Compare commits
569
Commits
contact-dev
...
handle
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
21879e8ab1 | ||
|
|
19b8c440ca | ||
|
|
2b076d0664 | ||
|
|
3551442f61 | ||
|
|
9a9087e20b | ||
|
|
c3771b3352 | ||
|
|
51a75893f7 | ||
|
|
35bbdc75c9 | ||
|
|
9bee2fcac8 | ||
|
|
f1304374e0 | ||
|
|
1136a2f283 | ||
|
|
baf6ba5d66 | ||
|
|
3fb7697ffb | ||
|
|
4f3bc873cc | ||
|
|
cf90e56850 | ||
|
|
7a6caccf99 | ||
|
|
f319ddef60 | ||
|
|
8f4c1dbe79 | ||
|
|
1e838ff45e | ||
|
|
b96db37ab8 | ||
|
|
79834fa003 | ||
|
|
25a1f0b3c6 | ||
|
|
6bcd940840 | ||
|
|
93c07b5c1c | ||
|
|
90e77b9ca1 | ||
|
|
3bd439a3c4 | ||
|
|
5b825515f7 | ||
|
|
d4da37d89a | ||
|
|
deb8bc7ed3 | ||
|
|
982583068a | ||
|
|
899a96b769 | ||
|
|
b4bd2f7e63 | ||
|
|
9837922654 | ||
|
|
5ec2931690 | ||
|
|
911511ed1d | ||
|
|
d7e8d78ca4 | ||
|
|
bbc37c5236 | ||
|
|
4ca2e5cef2 | ||
|
|
c09c15c0b2 | ||
|
|
d6d3e30832 | ||
|
|
9129e51b86 | ||
|
|
0797adb30a | ||
|
|
3945247cf5 | ||
|
|
de6ac02a8d | ||
|
|
873a6aa84c | ||
|
|
1262d17e8b | ||
|
|
d6e1063c5e | ||
|
|
fe9bd03f4b | ||
|
|
7645bce2b5 | ||
|
|
7cb81d5916 | ||
|
|
128882200d | ||
|
|
3f4dd4db7f | ||
|
|
73dbd7446f | ||
|
|
7c1a0eb5e3 | ||
|
|
3183af1b3c | ||
|
|
ced884b231 | ||
|
|
afbd1a1ba5 | ||
|
|
72dc18cccb | ||
|
|
8e3674396f | ||
|
|
4c0c3f822a | ||
|
|
cba0739740 | ||
|
|
75f0ed1b67 | ||
|
|
8853f574da | ||
|
|
645b7ba0dc | ||
|
|
e90cff6413 | ||
|
|
449778485d | ||
|
|
59a033b3ea | ||
|
|
bf47bc9210 | ||
|
|
4eac35a79a | ||
|
|
dffee6b764 | ||
|
|
302be130d1 | ||
|
|
9d7696d803 | ||
|
|
1e0bb496e8 | ||
|
|
a954ed2046 | ||
|
|
6e814df8cd | ||
|
|
fe3a6cba80 | ||
|
|
8883f34f5d | ||
|
|
737d9032d7 | ||
|
|
4993d5e715 | ||
|
|
9148e14b6f | ||
|
|
e8c5dbd885 | ||
|
|
e561db6d0a | ||
|
|
40dbb933e7 | ||
|
|
81ee483d2a | ||
|
|
701f109c1b | ||
|
|
e250112b1b | ||
|
|
70af0843a6 | ||
|
|
9176c2b95f | ||
|
|
79afc9f006 | ||
|
|
6eb86d9fbb | ||
|
|
59f8bb30ef | ||
|
|
561b172a8b | ||
|
|
b8547cb430 | ||
|
|
caf98db468 | ||
|
|
aeeadfe5d0 | ||
|
|
29417aed77 | ||
|
|
20cd0b2a9f | ||
|
|
1f6abc2e0b | ||
|
|
293b5f78e8 | ||
|
|
a2bbf76926 | ||
|
|
109baa5448 | ||
|
|
2ebe3efde8 | ||
|
|
e6fb9d0ff9 | ||
|
|
6a167c938f | ||
|
|
7399d8a8e0 | ||
|
|
6ae591075c | ||
|
|
e49747c49b | ||
|
|
a24370a2ed | ||
|
|
9a28ca5e6b | ||
|
|
5a1d69837d | ||
|
|
7876439a7d | ||
|
|
64907e2ab1 | ||
|
|
ee3f9fe97b | ||
|
|
8007b5073f | ||
|
|
564e2ff58e | ||
|
|
780eaeda5a | ||
|
|
8a4bb61a2a | ||
|
|
ff4544771b | ||
|
|
6105a4e1fa | ||
|
|
255c0c77e0 | ||
|
|
759ca48add | ||
|
|
c214533826 | ||
|
|
199f3616b6 | ||
|
|
3b4825675b | ||
|
|
470698bb28 | ||
|
|
8b8abfb611 | ||
|
|
8989feda0d | ||
|
|
784b74e1b3 | ||
|
|
cea760b1e6 | ||
|
|
c232029d84 | ||
|
|
4b6e48e915 | ||
|
|
73efadce18 | ||
|
|
c9cf2ec345 | ||
|
|
7195af90b1 | ||
|
|
ba9de3252b | ||
|
|
9dc7331d9c | ||
|
|
d5d2cbba19 | ||
|
|
db92a8950b | ||
|
|
325929278d | ||
|
|
2464a9d1ca | ||
|
|
f6db201a39 | ||
|
|
def4df1313 | ||
|
|
ea6ab76762 | ||
|
|
b4efd401b8 | ||
|
|
c7bb0201c0 | ||
|
|
8a19254fc6 | ||
|
|
ff0b016126 | ||
|
|
88f90717b1 | ||
|
|
256995a053 | ||
|
|
941c6c2bac | ||
|
|
de235a0660 | ||
|
|
bee8df8b42 | ||
|
|
4e17193a11 | ||
|
|
b4dfb8660d | ||
|
|
c3ac1e2222 | ||
|
|
031f8ad04a | ||
|
|
2cb4f5fd65 | ||
|
|
9f708051da | ||
|
|
3a64973722 | ||
|
|
6cedf73dd5 | ||
|
|
bd6c2ab61a | ||
|
|
1c90b1fd4f | ||
|
|
41cc480ba8 | ||
|
|
b1fc0a039f | ||
|
|
a714c4e881 | ||
|
|
8d189be921 | ||
|
|
82b0035ba2 | ||
|
|
a8db9de5a3 | ||
|
|
c086d8362d | ||
|
|
cf78d5d9f5 | ||
|
|
447d2ccd52 | ||
|
|
323cd8a2ae | ||
|
|
cbb95d2a8e | ||
|
|
1767d82a92 | ||
|
|
4c33502069 | ||
|
|
a74eed1083 | ||
|
|
3de18c65ab | ||
|
|
8451125d53 | ||
|
|
d9c65990d2 | ||
|
|
c1a796c60f | ||
|
|
d7d0e802a0 | ||
|
|
dee95c1d72 | ||
|
|
e1b98c30ec | ||
|
|
5099277778 | ||
|
|
3a9a131967 | ||
|
|
4491140db5 | ||
|
|
17955e1140 | ||
|
|
33cbfac042 | ||
|
|
41d94a5528 | ||
|
|
a7382dd25e | ||
|
|
c83264e825 | ||
|
|
70a4d67169 | ||
|
|
89eb2213fc | ||
|
|
498d539f68 | ||
|
|
a7cdb86334 | ||
|
|
4259ecc48b | ||
|
|
1382f6c771 | ||
|
|
f4675033a9 | ||
|
|
1662cbb045 | ||
|
|
d0b1f760eb | ||
|
|
846c63d53e | ||
|
|
d703c8c7a4 | ||
|
|
2bac83dc34 | ||
|
|
e3c0420c09 | ||
|
|
e46a3dc294 | ||
|
|
7f2ee0b7c9 | ||
|
|
324a86d4e7 | ||
|
|
d7c3190a68 | ||
|
|
d98eb5b5a0 | ||
|
|
14e5114039 | ||
|
|
235ab39d4a | ||
|
|
55efebfa00 | ||
|
|
fc13ff8f6c | ||
|
|
08cf03fc7f | ||
|
|
3bb7ea788f | ||
|
|
f1146c13b9 | ||
|
|
81fc677483 | ||
|
|
28f9bc4dd7 | ||
|
|
1886e25382 | ||
|
|
e5cd8378dc | ||
|
|
be35149113 | ||
|
|
808560ba72 | ||
|
|
30164b2db9 | ||
|
|
feeebaacc1 | ||
|
|
ad46b5217f | ||
|
|
854b2c5ed8 | ||
|
|
de70ec68cf | ||
|
|
7c37e06cd5 | ||
|
|
0cdfebca48 | ||
|
|
78ddcfee78 | ||
|
|
a92dc14745 | ||
|
|
718204a3c3 | ||
|
|
569a756b11 | ||
|
|
56381a3706 | ||
|
|
645bf01441 | ||
|
|
4eaa589c1f | ||
|
|
6205ec2b12 | ||
|
|
027681ff54 | ||
|
|
4acd812daa | ||
|
|
a1024d3645 | ||
|
|
6df6f1f199 | ||
|
|
29d97f356e | ||
|
|
e91f98c2c1 | ||
|
|
af9695d8f2 | ||
|
|
f2f0b17d91 | ||
|
|
36f15e5784 | ||
|
|
db1cb03562 | ||
|
|
b0cfba73ff | ||
|
|
8ebcd5b6d3 | ||
|
|
5c1d4f24a3 | ||
|
|
cf4e79b0e5 | ||
|
|
d8a9621dd5 | ||
|
|
0c42c16022 | ||
|
|
acf8bdb43e | ||
|
|
81f936aad5 | ||
|
|
c99c7581d8 | ||
|
|
5faf1e83bb | ||
|
|
b0acea4560 | ||
|
|
540c21c9e5 | ||
|
|
33e507ccbc | ||
|
|
829af3b6d4 | ||
|
|
dc142f33b4 | ||
|
|
b9c143a3fe | ||
|
|
e15a3fabfc | ||
|
|
7249c9dd22 | ||
|
|
bb1f48cc06 | ||
|
|
bc13b805da | ||
|
|
b42f27fe48 | ||
|
|
ee59eb5cc0 | ||
|
|
6672424982 | ||
|
|
449ae5e8c3 | ||
|
|
7f962b0ee6 | ||
|
|
f0ca6327cc | ||
|
|
82b0b3c9e5 | ||
|
|
a130d17bc9 | ||
|
|
445e41bb77 | ||
|
|
6c17447045 | ||
|
|
ada0e37801 | ||
|
|
4cf617347f | ||
|
|
a854669092 | ||
|
|
77f2bcb3af | ||
|
|
e58ec7d6e9 | ||
|
|
7b5497868d | ||
|
|
f5e5f62194 | ||
|
|
8d6557fa59 | ||
|
|
2c7f088dc7 | ||
|
|
22a7948a1b | ||
|
|
2aa283d3ec | ||
|
|
a6d067bc86 | ||
|
|
9ddb323911 | ||
|
|
3fba6c6c64 | ||
|
|
2bbf2a757f | ||
|
|
970521a17a | ||
|
|
a42ef2644e | ||
|
|
4f69b9bca4 | ||
|
|
c9a11a7a5b | ||
|
|
5d6d96b5b1 | ||
|
|
48c1be8fb5 | ||
|
|
676a94dcc5 | ||
|
|
635026fc5f | ||
|
|
2a85a72d19 | ||
|
|
b3323ef6e4 | ||
|
|
345957aae2 | ||
|
|
ecf167ca37 | ||
|
|
ea8fd50995 | ||
|
|
24ed3a7fe2 | ||
|
|
7f6cbffd82 | ||
|
|
3cedb47e7c | ||
|
|
c24baff0b9 | ||
|
|
8bdd414658 | ||
|
|
d4b0014407 | ||
|
|
e822520d5d | ||
|
|
4c952181c9 | ||
|
|
6d4f7570ad | ||
|
|
f61629c5a5 | ||
|
|
b3fff9267a | ||
|
|
c253f00ddc | ||
|
|
cc43f03baa | ||
|
|
cd5a72fabe | ||
|
|
5d27d4c77f | ||
|
|
e8a7f2136a | ||
|
|
0432b1c47c | ||
|
|
167b591d01 | ||
|
|
75452f6e30 | ||
|
|
58bd809f87 | ||
|
|
708a8d92f8 | ||
|
|
f3add08ae3 | ||
|
|
96860ce2a6 | ||
|
|
cf530e9029 | ||
|
|
2f6871e449 | ||
|
|
8a2ef8aa36 | ||
|
|
f0bc536820 | ||
|
|
f052af3d6b | ||
|
|
a3be873907 | ||
|
|
d0c358ab48 | ||
|
|
982f7a1729 | ||
|
|
96ef25817c | ||
|
|
7f0e9c8801 | ||
|
|
f96f8af545 | ||
|
|
4edd730ce7 | ||
|
|
06955c17d9 | ||
|
|
06a8b35570 | ||
|
|
92ff8c744f | ||
|
|
c269b1ea54 | ||
|
|
cc70734bc0 | ||
|
|
013eace8a6 | ||
|
|
8237b9212d | ||
|
|
009837f4c8 | ||
|
|
b991cb755e | ||
|
|
5e3359a805 | ||
|
|
df0c066e43 | ||
|
|
8d01267e28 | ||
|
|
8130e46a06 | ||
|
|
b82b7dc1a2 | ||
|
|
bb055a83c1 | ||
|
|
93225fa096 | ||
|
|
95c7b8b692 | ||
|
|
dddfd64c04 | ||
|
|
3a03d25d8a | ||
|
|
644e0540b1 | ||
|
|
4cbc97ae6b | ||
|
|
00cccf157f | ||
|
|
da8efca267 | ||
|
|
347d5f3861 | ||
|
|
4a022b3393 | ||
|
|
db8304e311 | ||
|
|
cf49036582 | ||
|
|
69b9e48cd6 | ||
|
|
c786caef28 | ||
|
|
4abe31b237 | ||
|
|
2c723d8a21 | ||
|
|
9a742299b5 | ||
|
|
2b2b141281 | ||
|
|
e554d15416 | ||
|
|
1e19cc58d4 | ||
|
|
937390c63b | ||
|
|
74f8617a9e | ||
|
|
77ee552475 | ||
|
|
efa4308b0c | ||
|
|
84caff9dd6 | ||
|
|
0d663eb13f | ||
|
|
c1261461c5 | ||
|
|
256e513b02 | ||
|
|
9bf8f03d47 | ||
|
|
45716da3e8 | ||
|
|
093be3733b | ||
|
|
7c6e4c48ae | ||
|
|
ac36c05f4b | ||
|
|
065c7dfd2b | ||
|
|
e8d76b6887 | ||
|
|
f69981012a | ||
|
|
2ebbe59aee | ||
|
|
bd7218a2e4 | ||
|
|
8726340bc1 | ||
|
|
f0de5ade98 | ||
|
|
77b88173b4 | ||
|
|
bff6755a36 | ||
|
|
b914196334 | ||
|
|
1b484707ab | ||
|
|
72a520df8b | ||
|
|
e44d7cdea7 | ||
|
|
423edcc540 | ||
|
|
9e71343031 | ||
|
|
02194f6ecb | ||
|
|
09b0b3eacc | ||
|
|
fce85e66a9 | ||
|
|
6d5381cdd2 | ||
|
|
8bbf7a87c2 | ||
|
|
432d290af5 | ||
|
|
a2ffe892c8 | ||
|
|
ab8e18be26 | ||
|
|
84b49f507a | ||
|
|
7aa36f82d9 | ||
|
|
5032ec9d7d | ||
|
|
1c655cbdc5 | ||
|
|
170ebdc372 | ||
|
|
b2c45912f7 | ||
|
|
b758c68930 | ||
|
|
5067891393 | ||
|
|
6fd27950ed | ||
|
|
297877bbef | ||
|
|
f0e9b0b55f | ||
|
|
69bfdf44c7 | ||
|
|
acd07bc6bd | ||
|
|
6a21cb7eba | ||
|
|
ce0d89397b | ||
|
|
c2cc36e559 | ||
|
|
305124eaaf | ||
|
|
e30950f349 | ||
|
|
254ade218b | ||
|
|
8d78dcaf9e | ||
|
|
a69e1c69ef | ||
|
|
4bafc17358 | ||
|
|
dfcb153e52 | ||
|
|
eea4386fcf | ||
|
|
22653aaf6e | ||
|
|
c6a3ccba0b | ||
|
|
755206a2d3 | ||
|
|
43dd9549f4 | ||
|
|
ebc27b9511 | ||
|
|
1c17415be3 | ||
|
|
eaed96dae0 | ||
|
|
da07b29b6d | ||
|
|
0942a818ca | ||
|
|
959b07ce39 | ||
|
|
ddb518df90 | ||
|
|
84575c6423 | ||
|
|
5e6727225b | ||
|
|
5c8dae8e8e | ||
|
|
aa9886365f | ||
|
|
38e48d89b1 | ||
|
|
64e2b26824 | ||
|
|
3137379e1d | ||
|
|
901a85abf2 | ||
|
|
aaf861460e | ||
|
|
19500f3c0b | ||
|
|
3f359156ed | ||
|
|
67372245c4 | ||
|
|
074f28ccba | ||
|
|
76cbcfd3be | ||
|
|
48a170c57d | ||
|
|
782b0266f2 | ||
|
|
7bd7f08fe9 | ||
|
|
c2dc013de5 | ||
|
|
208f36f354 | ||
|
|
3a4fe0bfe7 | ||
|
|
4230779792 | ||
|
|
7a4bd3fb51 | ||
|
|
9e0f9cabc0 | ||
|
|
b8a5c6e1a6 | ||
|
|
d168ea86ec | ||
|
|
60b4414fd9 | ||
|
|
59ec6ace17 | ||
|
|
521b044d61 | ||
|
|
852da98c50 | ||
|
|
03904a8bb0 | ||
|
|
3cf792a66b | ||
|
|
6bdaa12c88 | ||
|
|
6787428ae8 | ||
|
|
68a9a070a5 | ||
|
|
12927b36f0 | ||
|
|
43533b51d5 | ||
|
|
cfbedc494a | ||
|
|
1b1d9ca272 | ||
|
|
3388132bc3 | ||
|
|
1dedc55a42 | ||
|
|
fd6ac545fa | ||
|
|
736f0aca8a | ||
|
|
cdc9127ed6 | ||
|
|
cdbca8beb2 | ||
|
|
bffd75c0da | ||
|
|
1b5ae7461b | ||
|
|
b48574391e | ||
|
|
cd6919ce29 | ||
|
|
15f7f9dd1a | ||
|
|
2305d501db | ||
|
|
e125207781 | ||
|
|
8701290a72 | ||
|
|
35e3930fd7 | ||
|
|
f5cf13076b | ||
|
|
2bb6c55d66 | ||
|
|
08085843db | ||
|
|
3123099784 | ||
|
|
4e3df5a144 | ||
|
|
6baa0e29db | ||
|
|
612b7aa4f7 | ||
|
|
80702006f2 | ||
|
|
6ac7f61224 | ||
|
|
098063f588 | ||
|
|
c76b58fb12 | ||
|
|
4849471dc2 | ||
|
|
4c57ba72a6 | ||
|
|
0a44db4850 | ||
|
|
04691f4c16 | ||
|
|
3e1aec8bf8 | ||
|
|
ab71be1272 | ||
|
|
d7352fbfd4 | ||
|
|
ab7028ed7e | ||
|
|
793dd5e4c2 | ||
|
|
3920872a08 | ||
|
|
94fd002fab | ||
|
|
282e5b1a3d | ||
|
|
f49f007eda | ||
|
|
a2943f213f | ||
|
|
9c35bfbfda | ||
|
|
e488fc158d | ||
|
|
1d194da30d | ||
|
|
77d3c64a0d | ||
|
|
cd0ef98f79 | ||
|
|
fcb853fd6c | ||
|
|
5416209e9d | ||
|
|
448a395e5b | ||
|
|
baacaa9726 | ||
|
|
6fa0fb9efd | ||
|
|
f5580dd673 | ||
|
|
4d7c1c959f | ||
|
|
3c4e2a65a6 | ||
|
|
3c53fbf767 | ||
|
|
68b0c3c55f | ||
|
|
3fb8003f06 | ||
|
|
830eebd35e | ||
|
|
e36aaf91ed | ||
|
|
29e2b929f4 | ||
|
|
932b7dfa81 | ||
|
|
36464a6ea5 | ||
|
|
5c88b180e9 | ||
|
|
b9e6521123 | ||
|
|
1f564b2674 | ||
|
|
53e85b8bf4 | ||
|
|
2a797169aa | ||
|
|
98f7556b21 | ||
|
|
e185360c24 | ||
|
|
66cff6eeb4 | ||
|
|
a400c72ab6 | ||
|
|
27b920d975 | ||
|
|
058ad32dd9 | ||
|
|
c0476063a2 | ||
|
|
53f203ee79 | ||
|
|
85f8b9b07f | ||
|
|
336b82fafe | ||
|
|
222945b705 | ||
|
|
4d7e19e5e7 | ||
|
|
87d20a162c | ||
|
|
8e1b422b61 | ||
|
|
965d8f7d4b | ||
|
|
470479f17a | ||
|
|
fe8bd7c1bd | ||
|
|
9314475e22 | ||
|
|
f5687330c7 |
@@ -1,61 +0,0 @@
|
||||
# Configuration for probot-stale - https://github.com/probot/stale
|
||||
|
||||
# Number of days of inactivity before an Issue or Pull Request becomes stale
|
||||
daysUntilStale: 30
|
||||
|
||||
# Number of days of inactivity before an Issue or Pull Request with the stale
|
||||
# label is closed. Set to false to disable. If disabled, issues still need to
|
||||
# be closed manually, but will remain marked as stale.
|
||||
daysUntilClose: 7
|
||||
|
||||
# Only issues or pull requests with all of these labels are check if stale.
|
||||
# Defaults to `[]` (disabled)
|
||||
onlyLabels: []
|
||||
|
||||
# Issues or Pull Requests with these labels will never be considered stale. Set
|
||||
# to `[]` to disable
|
||||
exemptLabels:
|
||||
- bug
|
||||
- WIP
|
||||
- ready-for-review
|
||||
- in-review
|
||||
- in-next
|
||||
|
||||
# Set to true to ignore issues in a project (defaults to false)
|
||||
exemptProjects: false
|
||||
|
||||
# Set to true to ignore issues in a milestone (defaults to false)
|
||||
exemptMilestones: false
|
||||
|
||||
# Set to true to ignore issues with an assignee (defaults to false)
|
||||
exemptAssignees: false
|
||||
|
||||
# Label to use when marking an issue as stale
|
||||
staleLabel: stale
|
||||
|
||||
# Comment to post when marking an issue as stale. Set to `false` to disable
|
||||
markComment: >
|
||||
:warning: This issue or PR 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.
|
||||
|
||||
# Comment to post when closing a stale issue. Set to `false` to disable
|
||||
closeComment: false
|
||||
|
||||
# Limit the number of actions per hour, from 1-30. Default is 30
|
||||
limitPerRun: 30
|
||||
|
||||
# Limit to only `issues` or `pulls`
|
||||
# only: issues
|
||||
|
||||
# Optionally, specify configuration settings that are specific to just 'issues' or 'pulls':
|
||||
# pulls:
|
||||
# daysUntilStale: 30
|
||||
# markComment: >
|
||||
# This pull request has been automatically marked as stale because it has not had
|
||||
# recent activity. It will be closed if no further activity occurs. Thank you
|
||||
# for your contributions.
|
||||
|
||||
# issues:
|
||||
# exemptLabels:
|
||||
# - confirmed
|
||||
@@ -0,0 +1,31 @@
|
||||
# This workflow warns and then closes issues and PRs that have had no activity for a specified amount of time.
|
||||
# For more information, see: https://github.com/actions/stale
|
||||
name: Mark stale issues and pull requests
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: '0 0 * * *'
|
||||
|
||||
jobs:
|
||||
stale:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
issues: write
|
||||
pull-requests: write
|
||||
actions: write
|
||||
|
||||
steps:
|
||||
- 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.'
|
||||
stale-pr-message: ':warning: This PR 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.'
|
||||
days-before-stale: 30
|
||||
days-before-close: 7
|
||||
stale-issue-label: 'stale'
|
||||
stale-pr-label: 'stale'
|
||||
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"
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
# Object and library files
|
||||
*.o
|
||||
*.o.tmp
|
||||
/libmfem.*
|
||||
/miniapps/common/libmfem-common.*
|
||||
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
|
||||
Version 4.7.1 (development)
|
||||
===========================
|
||||
- Refactored ALGOIM cut integration rules. The interface is unified with
|
||||
the interface for moment based cut integration rules.
|
||||
|
||||
Discretization improvements
|
||||
---------------------------
|
||||
@@ -18,6 +20,8 @@ Discretization improvements
|
||||
|
||||
- Added support for boundary constraints to the hybridization class.
|
||||
|
||||
- Added support for external boundary submeshes with nonconformal mesh adaptation.
|
||||
|
||||
Meshing improvements
|
||||
--------------------
|
||||
- The ExodusII reader now handles pyramid and wedge element types. Mixed meshes
|
||||
@@ -50,8 +54,15 @@ GPU computing
|
||||
or by explicitly calling `KernelReporter::Enable`. Users can then add
|
||||
specializations for these kernels to achieve higher performance.
|
||||
|
||||
- Element assembly kernels have been added for low-order refined to
|
||||
high-order transfer operators. New kernels can be offloaded as device
|
||||
kernels. Example usage may be found in lor-transfer.cpp under miniapps/tools.
|
||||
|
||||
Miscellaneous
|
||||
-------------
|
||||
- Added support for SUNDIALS v7. See the section "API changes" for some small
|
||||
changes related to this new version.
|
||||
|
||||
- Refactored the `ARKStepSolver` class (ARKODE interface) to use
|
||||
`TimeDependentOperator::Mult` only when the associated ODE operator is
|
||||
expressed in explicit form (i.e., `TimeDependentOperator::isExplicit()`),
|
||||
@@ -64,10 +75,27 @@ 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.
|
||||
|
||||
API changes
|
||||
-----------
|
||||
- API change: in class GridFunction, 'fec' was renamed to 'fec_owned'.
|
||||
|
||||
- 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
|
||||
`sunbooleantype`, respectively, which MFEM defines when using SUNDIALS < v6
|
||||
where these types were not defined.
|
||||
* The SUNDIALS macro `SUNLS_SUCCESS` and some other `*_SUCCESS` macros were
|
||||
removed and replaced by `SUN_SUCCESS` in v7, so to avoid tedious checks for
|
||||
SUNDIALS versions, MFEM now defines and uses the constant `SUN_SUCCESS` when
|
||||
using SUNDIALS < v7.
|
||||
* The constants `SUN_PREC_*`, introduced by SUNDIALS v6 are now introduced by
|
||||
MFEM when using SUNDIALS < v6 to avoid tedious version checks.
|
||||
|
||||
|
||||
Version 4.7, released on May 7, 2024
|
||||
====================================
|
||||
@@ -154,6 +182,15 @@ New and updated examples and miniapps
|
||||
- Added two new example codes: 38 and 39/39p described above. Substantially
|
||||
updated Example 18/18p.
|
||||
|
||||
- Added ODE solvers selection routines. This creates a uniformity across examples,
|
||||
miniapps and other executables in regard to ODE(time-integrator) selection.
|
||||
|
||||
- Added new mechanism for retrieving and setting state vectors in ODE solvers.
|
||||
This is relevant for AB/AM and gen-alpha solvers.
|
||||
|
||||
- Added ODEsolver/ODEsolver2 unit tests to verify order of convergence and
|
||||
read/write functionality.
|
||||
|
||||
Miscellaneous
|
||||
-------------
|
||||
- Updated the Doxygen documentation style, which now requires Doxygen version
|
||||
|
||||
+4
-1
@@ -340,7 +340,10 @@ if (MFEM_USE_SUNDIALS)
|
||||
if (MFEM_USE_HIP)
|
||||
list(APPEND SUNDIALS_COMPONENTS NVector_Hip)
|
||||
endif()
|
||||
find_package(SUNDIALS REQUIRED ${SUNDIALS_COMPONENTS})
|
||||
# The Core component was added in SUNDIALS v7, so we treat it as optional in
|
||||
# order to support older versions.
|
||||
find_package(SUNDIALS REQUIRED ${SUNDIALS_COMPONENTS}
|
||||
OPTIONAL_COMPONENTS Core)
|
||||
endif()
|
||||
|
||||
# SuperLU_DIST can only be enabled in parallel
|
||||
|
||||
@@ -502,10 +502,14 @@ MFEM_USE_CODIPACK = YES/NO
|
||||
MFEM_USE_ALGOIM = YES/NO
|
||||
Enable the usage of Algoim - a collection of high-order accurate numerical
|
||||
methods and C++ algorithms for working with implicitly-defined geometry and
|
||||
level set methods. The Algoim library requires the Blitz++ library. The MFEM
|
||||
provides interface to Algoim v1. Thus, to check out the specific state use:
|
||||
level set methods, see https://algoim.github.io. MFEM provides interface to
|
||||
Algoim v1. To check out the specific Algoim state use:
|
||||
https://github.com/algoim/algoim
|
||||
git checkout 9c9ca0ef094d8ab0390ed36367a1151b459bbe0a
|
||||
https://algoim.github.io
|
||||
The Algoim library requires the Blitz++ library. To use the latest state of
|
||||
Blitz++ that has been tested with MFEM, use:
|
||||
https://github.com/blitzpp/blitz
|
||||
git checkout f24a250a43dff88c31ad92916da828b7ea9a98b7
|
||||
|
||||
MFEM_USE_ADFORWARD = YES/NO
|
||||
Enable forward mode for AD packages. This option is valid
|
||||
|
||||
@@ -31,4 +31,5 @@ mfem_find_package(SUNDIALS SUNDIALS SUNDIALS_DIR
|
||||
ADD_COMPONENT CVODE "include" cvode/cvode.h "lib" sundials_cvode
|
||||
ADD_COMPONENT CVODES "include" cvodes/cvodes.h "lib" sundials_cvodes
|
||||
ADD_COMPONENT ARKODE "include" arkode/arkode.h "lib" sundials_arkode
|
||||
ADD_COMPONENT KINSOL "include" kinsol/kinsol.h "lib" sundials_kinsol)
|
||||
ADD_COMPONENT KINSOL "include" kinsol/kinsol.h "lib" sundials_kinsol
|
||||
ADD_COMPONENT Core "include" sundials/sundials_core.h "lib" sundials_core)
|
||||
|
||||
+10
-1
@@ -289,6 +289,13 @@ endif
|
||||
ifeq ($(MFEM_USE_HIP),YES)
|
||||
SUNDIALS_LIB += -lsundials_nvechip
|
||||
endif
|
||||
SUNDIALS_CORE_PAT = $(subst\
|
||||
@MFEM_DIR@,$(MFEM_DIR),$(SUNDIALS_DIR))/lib*/libsundials_core.*
|
||||
ifeq ($(MFEM_USE_SUNDIALS),YES)
|
||||
ifneq ($(wildcard $(SUNDIALS_CORE_PAT)),)
|
||||
SUNDIALS_LIB += -lsundials_core
|
||||
endif
|
||||
endif
|
||||
# If SUNDIALS was built with KLU:
|
||||
# MFEM_USE_SUITESPARSE = YES
|
||||
|
||||
@@ -533,8 +540,10 @@ ifdef GOTCHA_DIR
|
||||
endif
|
||||
|
||||
# BLITZ library configuration
|
||||
BLITZ_DIR = @MFEM_DIR@/../blitz
|
||||
# BLITZ_DIR must be the custom installation folder (-DCMAKE_INSTALL_PREFIX).
|
||||
BLITZ_DIR = @MFEM_DIR@/../blitz/install
|
||||
BLITZ_OPT = -I$(BLITZ_DIR)/include
|
||||
# On intel machines, use /lib64 instead of /lib.
|
||||
BLITZ_LIB = $(XLINKER)-rpath,$(BLITZ_DIR)/lib -L$(BLITZ_DIR)/lib -lblitz
|
||||
|
||||
# ALGOIM library configuration
|
||||
|
||||
+11
-37
@@ -3,14 +3,14 @@
|
||||
// Compile with: make ex10
|
||||
//
|
||||
// Sample runs:
|
||||
// ex10 -m ../data/beam-quad.mesh -s 3 -r 2 -o 2 -dt 3
|
||||
// ex10 -m ../data/beam-tri.mesh -s 3 -r 2 -o 2 -dt 3
|
||||
// ex10 -m ../data/beam-hex.mesh -s 2 -r 1 -o 2 -dt 3
|
||||
// ex10 -m ../data/beam-tet.mesh -s 2 -r 1 -o 2 -dt 3
|
||||
// ex10 -m ../data/beam-wedge.mesh -s 2 -r 1 -o 2 -dt 3
|
||||
// ex10 -m ../data/beam-quad.mesh -s 14 -r 2 -o 2 -dt 0.03 -vs 20
|
||||
// ex10 -m ../data/beam-hex.mesh -s 14 -r 1 -o 2 -dt 0.05 -vs 20
|
||||
// ex10 -m ../data/beam-quad-amr.mesh -s 3 -r 2 -o 2 -dt 3
|
||||
// ex10 -m ../data/beam-quad.mesh -s 23 -r 2 -o 2 -dt 3
|
||||
// ex10 -m ../data/beam-tri.mesh -s 23 -r 2 -o 2 -dt 3
|
||||
// ex10 -m ../data/beam-hex.mesh -s 22 -r 1 -o 2 -dt 3
|
||||
// ex10 -m ../data/beam-tet.mesh -s 22 -r 1 -o 2 -dt 3
|
||||
// ex10 -m ../data/beam-wedge.mesh -s 22 -r 1 -o 2 -dt 3
|
||||
// ex10 -m ../data/beam-quad.mesh -s 4 -r 2 -o 2 -dt 0.03 -vs 20
|
||||
// ex10 -m ../data/beam-hex.mesh -s 4 -r 1 -o 2 -dt 0.05 -vs 20
|
||||
// ex10 -m ../data/beam-quad-amr.mesh -s 23 -r 2 -o 2 -dt 3
|
||||
//
|
||||
// Description: This examples solves a time dependent nonlinear elasticity
|
||||
// problem of the form dv/dt = H(x) + S v, dx/dt = v, where H is a
|
||||
@@ -160,7 +160,7 @@ int main(int argc, char *argv[])
|
||||
const char *mesh_file = "../data/beam-quad.mesh";
|
||||
int ref_levels = 2;
|
||||
int order = 2;
|
||||
int ode_solver_type = 3;
|
||||
int ode_solver_type = 23;
|
||||
real_t t_final = 300.0;
|
||||
real_t dt = 3.0;
|
||||
real_t visc = 1e-2;
|
||||
@@ -177,11 +177,7 @@ int main(int argc, char *argv[])
|
||||
args.AddOption(&order, "-o", "--order",
|
||||
"Order (degree) of the finite elements.");
|
||||
args.AddOption(&ode_solver_type, "-s", "--ode-solver",
|
||||
"ODE solver: 1 - Backward Euler, 2 - SDIRK2, 3 - SDIRK3,\n\t"
|
||||
" 11 - Forward Euler, 12 - RK2,\n\t"
|
||||
" 13 - RK3 SSP, 14 - RK4."
|
||||
" 22 - Implicit Midpoint Method,\n\t"
|
||||
" 23 - SDIRK23 (A-stable), 24 - SDIRK34");
|
||||
ODESolver::Types.c_str());
|
||||
args.AddOption(&t_final, "-tf", "--t-final",
|
||||
"Final time; start time is 0.");
|
||||
args.AddOption(&dt, "-dt", "--time-step",
|
||||
@@ -213,28 +209,7 @@ int main(int argc, char *argv[])
|
||||
// 3. Define the ODE solver used for time integration. Several implicit
|
||||
// singly diagonal implicit Runge-Kutta (SDIRK) methods, as well as
|
||||
// explicit Runge-Kutta methods are available.
|
||||
ODESolver *ode_solver;
|
||||
switch (ode_solver_type)
|
||||
{
|
||||
// Implicit L-stable methods
|
||||
case 1: ode_solver = new BackwardEulerSolver; break;
|
||||
case 2: ode_solver = new SDIRK23Solver(2); break;
|
||||
case 3: ode_solver = new SDIRK33Solver; break;
|
||||
// Explicit methods
|
||||
case 11: ode_solver = new ForwardEulerSolver; break;
|
||||
case 12: ode_solver = new RK2Solver(0.5); break; // midpoint method
|
||||
case 13: ode_solver = new RK3SSPSolver; break;
|
||||
case 14: ode_solver = new RK4Solver; break;
|
||||
case 15: ode_solver = new GeneralizedAlphaSolver(0.5); break;
|
||||
// Implicit A-stable methods (not L-stable)
|
||||
case 22: ode_solver = new ImplicitMidpointSolver; break;
|
||||
case 23: ode_solver = new SDIRK23Solver; break;
|
||||
case 24: ode_solver = new SDIRK34Solver; break;
|
||||
default:
|
||||
cout << "Unknown ODE solver type: " << ode_solver_type << '\n';
|
||||
delete mesh;
|
||||
return 3;
|
||||
}
|
||||
unique_ptr<ODESolver> ode_solver = ODESolver::Select(ode_solver_type);
|
||||
|
||||
// 4. Refine the mesh to increase the resolution. In this example we do
|
||||
// 'ref_levels' of uniform refinement, where 'ref_levels' is a
|
||||
@@ -371,7 +346,6 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
|
||||
// 10. Free the used memory.
|
||||
delete ode_solver;
|
||||
delete mesh;
|
||||
|
||||
return 0;
|
||||
|
||||
+11
-40
@@ -3,14 +3,14 @@
|
||||
// Compile with: make ex10p
|
||||
//
|
||||
// Sample runs:
|
||||
// mpirun -np 4 ex10p -m ../data/beam-quad.mesh -s 3 -rs 2 -dt 3
|
||||
// mpirun -np 4 ex10p -m ../data/beam-tri.mesh -s 3 -rs 2 -dt 3
|
||||
// mpirun -np 4 ex10p -m ../data/beam-hex.mesh -s 2 -rs 1 -dt 3
|
||||
// mpirun -np 4 ex10p -m ../data/beam-tet.mesh -s 2 -rs 1 -dt 3
|
||||
// mpirun -np 4 ex10p -m ../data/beam-wedge.mesh -s 2 -rs 1 -dt 3
|
||||
// mpirun -np 4 ex10p -m ../data/beam-quad.mesh -s 14 -rs 2 -dt 0.03 -vs 20
|
||||
// mpirun -np 4 ex10p -m ../data/beam-hex.mesh -s 14 -rs 1 -dt 0.05 -vs 20
|
||||
// mpirun -np 4 ex10p -m ../data/beam-quad-amr.mesh -s 3 -rs 2 -dt 3
|
||||
// mpirun -np 4 ex10p -m ../data/beam-quad.mesh -s 23 -rs 2 -dt 3
|
||||
// mpirun -np 4 ex10p -m ../data/beam-tri.mesh -s 23 -rs 2 -dt 3
|
||||
// mpirun -np 4 ex10p -m ../data/beam-hex.mesh -s 22 -rs 1 -dt 3
|
||||
// mpirun -np 4 ex10p -m ../data/beam-tet.mesh -s 22 -rs 1 -dt 3
|
||||
// mpirun -np 4 ex10p -m ../data/beam-wedge.mesh -s 22 -rs 1 -dt 3
|
||||
// mpirun -np 4 ex10p -m ../data/beam-quad.mesh -s 4 -rs 2 -dt 0.03 -vs 20
|
||||
// mpirun -np 4 ex10p -m ../data/beam-hex.mesh -s 4 -rs 1 -dt 0.05 -vs 20
|
||||
// mpirun -np 4 ex10p -m ../data/beam-quad-amr.mesh -s 23 -rs 2 -dt 3
|
||||
//
|
||||
// Description: This examples solves a time dependent nonlinear elasticity
|
||||
// problem of the form dv/dt = H(x) + S v, dx/dt = v, where H is a
|
||||
@@ -172,7 +172,7 @@ int main(int argc, char *argv[])
|
||||
int ser_ref_levels = 2;
|
||||
int par_ref_levels = 0;
|
||||
int order = 2;
|
||||
int ode_solver_type = 3;
|
||||
int ode_solver_type = 23;
|
||||
real_t t_final = 300.0;
|
||||
real_t dt = 3.0;
|
||||
real_t visc = 1e-2;
|
||||
@@ -192,11 +192,7 @@ int main(int argc, char *argv[])
|
||||
args.AddOption(&order, "-o", "--order",
|
||||
"Order (degree) of the finite elements.");
|
||||
args.AddOption(&ode_solver_type, "-s", "--ode-solver",
|
||||
"ODE solver: 1 - Backward Euler, 2 - SDIRK2, 3 - SDIRK3,\n\t"
|
||||
" 11 - Forward Euler, 12 - RK2,\n\t"
|
||||
" 13 - RK3 SSP, 14 - RK4."
|
||||
" 22 - Implicit Midpoint Method,\n\t"
|
||||
" 23 - SDIRK23 (A-stable), 24 - SDIRK34");
|
||||
ODESolver::Types.c_str());
|
||||
args.AddOption(&t_final, "-tf", "--t-final",
|
||||
"Final time; start time is 0.");
|
||||
args.AddOption(&dt, "-dt", "--time-step",
|
||||
@@ -238,31 +234,7 @@ int main(int argc, char *argv[])
|
||||
// 4. Define the ODE solver used for time integration. Several implicit
|
||||
// singly diagonal implicit Runge-Kutta (SDIRK) methods, as well as
|
||||
// explicit Runge-Kutta methods are available.
|
||||
ODESolver *ode_solver;
|
||||
switch (ode_solver_type)
|
||||
{
|
||||
// Implicit L-stable methods
|
||||
case 1: ode_solver = new BackwardEulerSolver; break;
|
||||
case 2: ode_solver = new SDIRK23Solver(2); break;
|
||||
case 3: ode_solver = new SDIRK33Solver; break;
|
||||
// Explicit methods
|
||||
case 11: ode_solver = new ForwardEulerSolver; break;
|
||||
case 12: ode_solver = new RK2Solver(0.5); break; // midpoint method
|
||||
case 13: ode_solver = new RK3SSPSolver; break;
|
||||
case 14: ode_solver = new RK4Solver; break;
|
||||
case 15: ode_solver = new GeneralizedAlphaSolver(0.5); break;
|
||||
// Implicit A-stable methods (not L-stable)
|
||||
case 22: ode_solver = new ImplicitMidpointSolver; break;
|
||||
case 23: ode_solver = new SDIRK23Solver; break;
|
||||
case 24: ode_solver = new SDIRK34Solver; break;
|
||||
default:
|
||||
if (myid == 0)
|
||||
{
|
||||
cout << "Unknown ODE solver type: " << ode_solver_type << '\n';
|
||||
}
|
||||
delete mesh;
|
||||
return 3;
|
||||
}
|
||||
unique_ptr<ODESolver> ode_solver = ODESolver::Select(ode_solver_type);
|
||||
|
||||
// 5. Refine the mesh in serial to increase the resolution. In this example
|
||||
// we do 'ser_ref_levels' of uniform refinement, where 'ser_ref_levels' is
|
||||
@@ -433,7 +405,6 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
|
||||
// 12. Free the used memory.
|
||||
delete ode_solver;
|
||||
delete pmesh;
|
||||
|
||||
return 0;
|
||||
|
||||
+9
-30
@@ -5,10 +5,10 @@
|
||||
// Sample runs: ex16
|
||||
// ex16 -m ../data/inline-tri.mesh
|
||||
// ex16 -m ../data/disc-nurbs.mesh -tf 2
|
||||
// ex16 -s 1 -a 0.0 -k 1.0
|
||||
// ex16 -s 2 -a 1.0 -k 0.0
|
||||
// ex16 -s 3 -a 0.5 -k 0.5 -o 4
|
||||
// ex16 -s 14 -dt 1.0e-4 -tf 4.0e-2 -vs 40
|
||||
// ex16 -s 21 -a 0.0 -k 1.0
|
||||
// ex16 -s 22 -a 1.0 -k 0.0
|
||||
// ex16 -s 23 -a 0.5 -k 0.5 -o 4
|
||||
// ex16 -s 4 -dt 1.0e-4 -tf 4.0e-2 -vs 40
|
||||
// ex16 -m ../data/fichera-q2.mesh
|
||||
// ex16 -m ../data/fichera-mixed.mesh
|
||||
// ex16 -m ../data/escher.mesh
|
||||
@@ -95,11 +95,13 @@ int main(int argc, char *argv[])
|
||||
const char *mesh_file = "../data/star.mesh";
|
||||
int ref_levels = 2;
|
||||
int order = 2;
|
||||
int ode_solver_type = 3;
|
||||
|
||||
int ode_solver_type = 23; // SDIRK33Solver
|
||||
real_t t_final = 0.5;
|
||||
real_t dt = 1.0e-2;
|
||||
real_t alpha = 1.0e-2;
|
||||
real_t kappa = 0.5;
|
||||
|
||||
bool visualization = true;
|
||||
bool visit = false;
|
||||
int vis_steps = 5;
|
||||
@@ -115,8 +117,7 @@ int main(int argc, char *argv[])
|
||||
args.AddOption(&order, "-o", "--order",
|
||||
"Order (degree) of the finite elements.");
|
||||
args.AddOption(&ode_solver_type, "-s", "--ode-solver",
|
||||
"ODE solver: 1 - Backward Euler, 2 - SDIRK2, 3 - SDIRK3,\n\t"
|
||||
"\t 11 - Forward Euler, 12 - RK2, 13 - RK3 SSP, 14 - RK4.");
|
||||
ODESolver::Types.c_str());
|
||||
args.AddOption(&t_final, "-tf", "--t-final",
|
||||
"Final time; start time is 0.");
|
||||
args.AddOption(&dt, "-dt", "--time-step",
|
||||
@@ -149,28 +150,7 @@ int main(int argc, char *argv[])
|
||||
// 3. Define the ODE solver used for time integration. Several implicit
|
||||
// singly diagonal implicit Runge-Kutta (SDIRK) methods, as well as
|
||||
// explicit Runge-Kutta methods are available.
|
||||
ODESolver *ode_solver;
|
||||
switch (ode_solver_type)
|
||||
{
|
||||
// Implicit L-stable methods
|
||||
case 1: ode_solver = new BackwardEulerSolver; break;
|
||||
case 2: ode_solver = new SDIRK23Solver(2); break;
|
||||
case 3: ode_solver = new SDIRK33Solver; break;
|
||||
// Explicit methods
|
||||
case 11: ode_solver = new ForwardEulerSolver; break;
|
||||
case 12: ode_solver = new RK2Solver(0.5); break; // midpoint method
|
||||
case 13: ode_solver = new RK3SSPSolver; break;
|
||||
case 14: ode_solver = new RK4Solver; break;
|
||||
case 15: ode_solver = new GeneralizedAlphaSolver(0.5); break;
|
||||
// Implicit A-stable methods (not L-stable)
|
||||
case 22: ode_solver = new ImplicitMidpointSolver; break;
|
||||
case 23: ode_solver = new SDIRK23Solver; break;
|
||||
case 24: ode_solver = new SDIRK34Solver; break;
|
||||
default:
|
||||
cout << "Unknown ODE solver type: " << ode_solver_type << '\n';
|
||||
delete mesh;
|
||||
return 3;
|
||||
}
|
||||
unique_ptr<ODESolver> ode_solver = ODESolver::Select(ode_solver_type);
|
||||
|
||||
// 4. Refine the mesh to increase the resolution. In this example we do
|
||||
// 'ref_levels' of uniform refinement, where 'ref_levels' is a
|
||||
@@ -287,7 +267,6 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
|
||||
// 10. Free the used memory.
|
||||
delete ode_solver;
|
||||
delete mesh;
|
||||
|
||||
return 0;
|
||||
|
||||
+9
-30
@@ -5,10 +5,10 @@
|
||||
// Sample runs: mpirun -np 4 ex16p
|
||||
// mpirun -np 4 ex16p -m ../data/inline-tri.mesh
|
||||
// mpirun -np 4 ex16p -m ../data/disc-nurbs.mesh -tf 2
|
||||
// mpirun -np 4 ex16p -s 1 -a 0.0 -k 1.0
|
||||
// mpirun -np 4 ex16p -s 2 -a 1.0 -k 0.0
|
||||
// mpirun -np 8 ex16p -s 3 -a 0.5 -k 0.5 -o 4
|
||||
// mpirun -np 4 ex16p -s 14 -dt 1.0e-4 -tf 4.0e-2 -vs 40
|
||||
// mpirun -np 4 ex16p -s 21 -a 0.0 -k 1.0
|
||||
// mpirun -np 4 ex16p -s 22 -a 1.0 -k 0.0
|
||||
// mpirun -np 8 ex16p -s 23 -a 0.5 -k 0.5 -o 4
|
||||
// mpirun -np 4 ex16p -s 4 -dt 1.0e-4 -tf 4.0e-2 -vs 40
|
||||
// mpirun -np 16 ex16p -m ../data/fichera-q2.mesh
|
||||
// mpirun -np 16 ex16p -m ../data/fichera-mixed.mesh
|
||||
// mpirun -np 16 ex16p -m ../data/escher-p2.mesh
|
||||
@@ -104,11 +104,13 @@ int main(int argc, char *argv[])
|
||||
int ser_ref_levels = 2;
|
||||
int par_ref_levels = 1;
|
||||
int order = 2;
|
||||
int ode_solver_type = 3;
|
||||
|
||||
int ode_solver_type = 23; // SDIRK33Solver
|
||||
real_t t_final = 0.5;
|
||||
real_t dt = 1.0e-2;
|
||||
real_t alpha = 1.0e-2;
|
||||
real_t kappa = 0.5;
|
||||
|
||||
bool visualization = true;
|
||||
bool visit = false;
|
||||
int vis_steps = 5;
|
||||
@@ -127,8 +129,7 @@ int main(int argc, char *argv[])
|
||||
args.AddOption(&order, "-o", "--order",
|
||||
"Order (degree) of the finite elements.");
|
||||
args.AddOption(&ode_solver_type, "-s", "--ode-solver",
|
||||
"ODE solver: 1 - Backward Euler, 2 - SDIRK2, 3 - SDIRK3,\n\t"
|
||||
"\t 11 - Forward Euler, 12 - RK2, 13 - RK3 SSP, 14 - RK4.");
|
||||
ODESolver::Types.c_str());
|
||||
args.AddOption(&t_final, "-tf", "--t-final",
|
||||
"Final time; start time is 0.");
|
||||
args.AddOption(&dt, "-dt", "--time-step",
|
||||
@@ -169,28 +170,7 @@ int main(int argc, char *argv[])
|
||||
// 4. Define the ODE solver used for time integration. Several implicit
|
||||
// singly diagonal implicit Runge-Kutta (SDIRK) methods, as well as
|
||||
// explicit Runge-Kutta methods are available.
|
||||
ODESolver *ode_solver;
|
||||
switch (ode_solver_type)
|
||||
{
|
||||
// Implicit L-stable methods
|
||||
case 1: ode_solver = new BackwardEulerSolver; break;
|
||||
case 2: ode_solver = new SDIRK23Solver(2); break;
|
||||
case 3: ode_solver = new SDIRK33Solver; break;
|
||||
// Explicit methods
|
||||
case 11: ode_solver = new ForwardEulerSolver; break;
|
||||
case 12: ode_solver = new RK2Solver(0.5); break; // midpoint method
|
||||
case 13: ode_solver = new RK3SSPSolver; break;
|
||||
case 14: ode_solver = new RK4Solver; break;
|
||||
case 15: ode_solver = new GeneralizedAlphaSolver(0.5); break;
|
||||
// Implicit A-stable methods (not L-stable)
|
||||
case 22: ode_solver = new ImplicitMidpointSolver; break;
|
||||
case 23: ode_solver = new SDIRK23Solver; break;
|
||||
case 24: ode_solver = new SDIRK34Solver; break;
|
||||
default:
|
||||
cout << "Unknown ODE solver type: " << ode_solver_type << '\n';
|
||||
delete mesh;
|
||||
return 3;
|
||||
}
|
||||
unique_ptr<ODESolver> ode_solver = ODESolver::Select(ode_solver_type);
|
||||
|
||||
// 5. Refine the mesh in serial to increase the resolution. In this example
|
||||
// we do 'ser_ref_levels' of uniform refinement, where 'ser_ref_levels' is
|
||||
@@ -376,7 +356,6 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
|
||||
// 12. Free the used memory.
|
||||
delete ode_solver;
|
||||
delete pmesh;
|
||||
|
||||
return 0;
|
||||
|
||||
+2
-17
@@ -90,8 +90,7 @@ int main(int argc, char *argv[])
|
||||
args.AddOption(&order, "-o", "--order",
|
||||
"Order (degree) of the finite elements.");
|
||||
args.AddOption(&ode_solver_type, "-s", "--ode-solver",
|
||||
"ODE solver: 1 - Forward Euler,\n\t"
|
||||
" 2 - RK2 SSP, 3 - RK3 SSP, 4 - RK4, 6 - RK6.");
|
||||
ODESolver::ExplicitTypes.c_str());
|
||||
args.AddOption(&t_final, "-tf", "--t-final", "Final time; start time is 0.");
|
||||
args.AddOption(&dt, "-dt", "--time-step",
|
||||
"Time step. Positive number skips CFL timestep calculation.");
|
||||
@@ -125,18 +124,7 @@ int main(int argc, char *argv[])
|
||||
|
||||
// 3. Define the ODE solver used for time integration. Several explicit
|
||||
// Runge-Kutta methods are available.
|
||||
ODESolver *ode_solver = NULL;
|
||||
switch (ode_solver_type)
|
||||
{
|
||||
case 1: ode_solver = new ForwardEulerSolver; break;
|
||||
case 2: ode_solver = new RK2Solver(1.0); break;
|
||||
case 3: ode_solver = new RK3SSPSolver; break;
|
||||
case 4: ode_solver = new RK4Solver; break;
|
||||
case 6: ode_solver = new RK6Solver; break;
|
||||
default:
|
||||
cout << "Unknown ODE solver type: " << ode_solver_type << '\n';
|
||||
return 3;
|
||||
}
|
||||
unique_ptr<ODESolver> ode_solver = ODESolver::SelectExplicit(ode_solver_type);
|
||||
|
||||
// 4. Define the discontinuous DG finite element space of the given
|
||||
// polynomial order on the refined mesh.
|
||||
@@ -304,8 +292,5 @@ int main(int argc, char *argv[])
|
||||
const real_t error = sol.ComputeLpError(2, u0);
|
||||
cout << "Solution error: " << error << endl;
|
||||
|
||||
// Free the used memory.
|
||||
delete ode_solver;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
+2
-17
@@ -99,8 +99,7 @@ int main(int argc, char *argv[])
|
||||
args.AddOption(&order, "-o", "--order",
|
||||
"Order (degree) of the finite elements.");
|
||||
args.AddOption(&ode_solver_type, "-s", "--ode-solver",
|
||||
"ODE solver: 1 - Forward Euler,\n\t"
|
||||
" 2 - RK2 SSP, 3 - RK3 SSP, 4 - RK4, 6 - RK6.");
|
||||
ODESolver::ExplicitTypes.c_str());
|
||||
args.AddOption(&t_final, "-tf", "--t-final", "Final time; start time is 0.");
|
||||
args.AddOption(&dt, "-dt", "--time-step",
|
||||
"Time step. Positive number skips CFL timestep calculation.");
|
||||
@@ -148,18 +147,7 @@ int main(int argc, char *argv[])
|
||||
|
||||
// 3. Define the ODE solver used for time integration. Several explicit
|
||||
// Runge-Kutta methods are available.
|
||||
ODESolver *ode_solver = NULL;
|
||||
switch (ode_solver_type)
|
||||
{
|
||||
case 1: ode_solver = new ForwardEulerSolver; break;
|
||||
case 2: ode_solver = new RK2Solver(1.0); break;
|
||||
case 3: ode_solver = new RK3SSPSolver; break;
|
||||
case 4: ode_solver = new RK4Solver; break;
|
||||
case 6: ode_solver = new RK6Solver; break;
|
||||
default:
|
||||
cout << "Unknown ODE solver type: " << ode_solver_type << '\n';
|
||||
return 3;
|
||||
}
|
||||
unique_ptr<ODESolver> ode_solver = ODESolver::SelectExplicit(ode_solver_type);
|
||||
|
||||
// 4. Define the discontinuous DG finite element space of the given
|
||||
// polynomial order on the refined mesh.
|
||||
@@ -360,8 +348,5 @@ int main(int argc, char *argv[])
|
||||
cout << "Solution error: " << error << endl;
|
||||
}
|
||||
|
||||
// Free the used memory.
|
||||
delete ode_solver;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
+2
-29
@@ -201,9 +201,7 @@ int main(int argc, char *argv[])
|
||||
args.AddOption(&order, "-o", "--order",
|
||||
"Order (degree) of the finite elements.");
|
||||
args.AddOption(&ode_solver_type, "-s", "--ode-solver",
|
||||
"ODE solver: [0--10] - GeneralizedAlpha(0.1 * s),\n\t"
|
||||
"\t 11 - Average Acceleration, 12 - Linear Acceleration\n"
|
||||
"\t 13 - CentralDifference, 14 - FoxGoodwin");
|
||||
SecondOrderODESolver::Types.c_str());
|
||||
args.AddOption(&t_final, "-tf", "--t-final",
|
||||
"Final time; start time is 0.");
|
||||
args.AddOption(&dt, "-dt", "--time-step",
|
||||
@@ -238,32 +236,7 @@ int main(int argc, char *argv[])
|
||||
|
||||
// 3. Define the ODE solver used for time integration. Several second order
|
||||
// time integrators are available.
|
||||
SecondOrderODESolver *ode_solver;
|
||||
switch (ode_solver_type)
|
||||
{
|
||||
// Implicit methods
|
||||
case 0: ode_solver = new GeneralizedAlpha2Solver(0.0); break;
|
||||
case 1: ode_solver = new GeneralizedAlpha2Solver(0.1); break;
|
||||
case 2: ode_solver = new GeneralizedAlpha2Solver(0.2); break;
|
||||
case 3: ode_solver = new GeneralizedAlpha2Solver(0.3); break;
|
||||
case 4: ode_solver = new GeneralizedAlpha2Solver(0.4); break;
|
||||
case 5: ode_solver = new GeneralizedAlpha2Solver(0.5); break;
|
||||
case 6: ode_solver = new GeneralizedAlpha2Solver(0.6); break;
|
||||
case 7: ode_solver = new GeneralizedAlpha2Solver(0.7); break;
|
||||
case 8: ode_solver = new GeneralizedAlpha2Solver(0.8); break;
|
||||
case 9: ode_solver = new GeneralizedAlpha2Solver(0.9); break;
|
||||
case 10: ode_solver = new GeneralizedAlpha2Solver(1.0); break;
|
||||
|
||||
case 11: ode_solver = new AverageAccelerationSolver(); break;
|
||||
case 12: ode_solver = new LinearAccelerationSolver(); break;
|
||||
case 13: ode_solver = new CentralDifferenceSolver(); break;
|
||||
case 14: ode_solver = new FoxGoodwinSolver(); break;
|
||||
|
||||
default:
|
||||
cout << "Unknown ODE solver type: " << ode_solver_type << '\n';
|
||||
delete mesh;
|
||||
return 3;
|
||||
}
|
||||
SecondOrderODESolver *ode_solver= SecondOrderODESolver::Select(ode_solver_type);
|
||||
|
||||
// 4. Refine the mesh to increase the resolution. In this example we do
|
||||
// 'ref_levels' of uniform refinement, where 'ref_levels' is a
|
||||
|
||||
+115
-81
@@ -3,18 +3,18 @@
|
||||
// Compile with: make ex38
|
||||
//
|
||||
// Sample runs:
|
||||
// (since all sample runs require LAPACK, the * symbol is used to exclude them
|
||||
// from the automatically generated internal MFEM tests).
|
||||
// (since all sample runs require LAPACK or ALGOIM, the * symbol is used to
|
||||
// exclude them from the automatically generated internal MFEM tests).
|
||||
// * ex38
|
||||
// * ex38 -i volumetric1d
|
||||
// * ex38 -i surface2d
|
||||
// * ex38 -i surface2d -o 4 -r 5
|
||||
// * ex38 -i surface2d -o 4 -r 5 -m 1
|
||||
// * ex38 -i volumetric2d
|
||||
// * ex38 -i volumetric2d -o 4 -r 5
|
||||
// * ex38 -i volumetric2d -o 4 -r 5 -m 1
|
||||
// * ex38 -i surface3d
|
||||
// * ex38 -i surface3d -o 4 -r 5
|
||||
// * ex38 -i surface3d -o 3 -r 4 -m 1
|
||||
// * ex38 -i volumetric3d
|
||||
// * ex38 -i volumetric3d -o 4 -r 5
|
||||
// * ex38 -i volumetric3d -o 3 -r 4 -m 1
|
||||
//
|
||||
// Description: This example code demonstrates the use of MFEM to integrate
|
||||
// functions over implicit interfaces and subdomains bounded by
|
||||
@@ -71,7 +71,7 @@ real_t integrand(const Vector& X)
|
||||
switch (itype)
|
||||
{
|
||||
case IntegrationType::Volumetric1D:
|
||||
return 1.;
|
||||
return pow(X(0), 2.);
|
||||
case IntegrationType::Surface2D:
|
||||
return 3. * pow(X(0), 2.) - pow(X(1), 2.);
|
||||
case IntegrationType::Volumetric2D:
|
||||
@@ -91,7 +91,7 @@ real_t Surface()
|
||||
switch (itype)
|
||||
{
|
||||
case IntegrationType::Volumetric1D:
|
||||
return 1.;
|
||||
return .3025;
|
||||
case IntegrationType::Surface2D:
|
||||
return 2. * M_PI;
|
||||
case IntegrationType::Volumetric2D:
|
||||
@@ -111,7 +111,7 @@ real_t Volume()
|
||||
switch (itype)
|
||||
{
|
||||
case IntegrationType::Volumetric1D:
|
||||
return .55;
|
||||
return pow(.55, 3.) / 3.;
|
||||
case IntegrationType::Surface2D:
|
||||
return NAN;
|
||||
case IntegrationType::Volumetric2D:
|
||||
@@ -125,7 +125,6 @@ real_t Volume()
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef MFEM_USE_LAPACK
|
||||
/**
|
||||
@brief Class for surface IntegrationRule
|
||||
|
||||
@@ -135,11 +134,14 @@ real_t Volume()
|
||||
class SIntegrationRule : public IntegrationRule
|
||||
{
|
||||
protected:
|
||||
/// @brief Space Dimension of the IntegrationRule
|
||||
/// method 0 is moments-based, 1 is Algoim.
|
||||
int method, ir_order, ls_order;
|
||||
Coefficient &level_set;
|
||||
/// Space Dimension of the IntegrationRule
|
||||
int dim;
|
||||
/// @brief Column-wise matrix of the quadtrature weights
|
||||
/// Column-wise matrix of the quadtrature weights
|
||||
DenseMatrix Weights;
|
||||
/// @brief Column-wise matrix of the transformation weights of the normal
|
||||
/// Column-wise matrix of the transformation weights of the normal
|
||||
DenseMatrix SurfaceWeights;
|
||||
|
||||
public:
|
||||
@@ -153,15 +155,21 @@ public:
|
||||
@param [in] lsOrder Polynomial degree for approx of level-set function
|
||||
@param [in] mesh Pointer to the mesh that is used
|
||||
*/
|
||||
SIntegrationRule(int Order, Coefficient& LvlSet, int lsOrder, Mesh* mesh)
|
||||
SIntegrationRule(int method_, int Order,
|
||||
Coefficient& LvlSet, int lsOrder, Mesh* mesh)
|
||||
: method(method_), ir_order(Order), ls_order(lsOrder),
|
||||
level_set(LvlSet), dim(mesh->Dimension())
|
||||
{
|
||||
dim = mesh->Dimension();
|
||||
// Nothing gets pre-computed for Algoim.
|
||||
if (method == 1) { return; }
|
||||
|
||||
#ifdef MFEM_USE_LAPACK
|
||||
MomentFittingIntRules mf_ir(ir_order, level_set, ls_order);
|
||||
|
||||
IsoparametricTransformation Tr;
|
||||
MomentFittingIntRules MFIRs(Order, LvlSet, lsOrder);
|
||||
mesh->GetElementTransformation(0, &Tr);
|
||||
IntegrationRule ir;
|
||||
MFIRs.GetSurfaceIntegrationRule(Tr, ir);
|
||||
mf_ir.GetSurfaceIntegrationRule(Tr, ir);
|
||||
if (dim >1)
|
||||
{
|
||||
Weights.SetSize(ir.GetNPoints(), mesh->GetNE());
|
||||
@@ -172,7 +180,7 @@ public:
|
||||
}
|
||||
SurfaceWeights.SetSize(ir.GetNPoints(), mesh->GetNE());
|
||||
Vector w;
|
||||
MFIRs.GetSurfaceWeights(Tr, ir, w);
|
||||
mf_ir.GetSurfaceWeights(Tr, ir, w);
|
||||
SurfaceWeights.SetCol(0, w);
|
||||
SetSize(ir.GetNPoints());
|
||||
|
||||
@@ -198,8 +206,8 @@ public:
|
||||
for (int elem = 1; elem < mesh->GetNE(); elem++)
|
||||
{
|
||||
mesh->GetElementTransformation(elem, &Tr);
|
||||
MFIRs.GetSurfaceIntegrationRule(Tr, ir);
|
||||
MFIRs.GetSurfaceWeights(Tr, ir, w);
|
||||
mf_ir.GetSurfaceIntegrationRule(Tr, ir);
|
||||
mf_ir.GetSurfaceWeights(Tr, ir, w);
|
||||
SurfaceWeights.SetCol(elem, w);
|
||||
|
||||
for (int ip = 0; ip < GetNPoints(); ip++)
|
||||
@@ -215,48 +223,48 @@ public:
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
MFEM_ABORT("Moment-fitting requires MFEM to be built with LAPACK!");
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
@brief Set the weights for the given element and multiply them with the
|
||||
transformation of the interface
|
||||
*/
|
||||
void SetElementinclSurfaceWeight(int Element)
|
||||
void SetElementAndSurfaceWeight(ElementTransformation &Tr)
|
||||
{
|
||||
if (dim == 1)
|
||||
if (method == 1)
|
||||
{
|
||||
IntegrationPoint &intp = IntPoint(0);
|
||||
intp.x = Weights(0, Element);
|
||||
intp.weight = Weights(1, Element);
|
||||
cout << intp.x << " " << Element << endl;
|
||||
}
|
||||
else
|
||||
#ifdef MFEM_USE_ALGOIM
|
||||
AlgoimIntegrationRules a_ir(ir_order, level_set, ls_order);
|
||||
a_ir.GetSurfaceIntegrationRule(Tr, *this);
|
||||
Vector w;
|
||||
a_ir.GetSurfaceWeights(Tr, *this, w);
|
||||
for (int ip = 0; ip < GetNPoints(); ip++)
|
||||
{
|
||||
IntegrationPoint &intp = IntPoint(ip);
|
||||
intp.weight = Weights(ip, Element) * SurfaceWeights(ip, Element);
|
||||
IntPoint(ip).weight *= w(ip);
|
||||
}
|
||||
}
|
||||
return;
|
||||
#else
|
||||
MFEM_ABORT("MFEM is not built with Algoim support!");
|
||||
#endif
|
||||
}
|
||||
|
||||
/// @brief Set the weights for the given element
|
||||
void SetElement(int Element)
|
||||
{
|
||||
if (dim == 1)
|
||||
{
|
||||
IntegrationPoint &intp = IntPoint(0);
|
||||
intp.x = Weights(0, Element);
|
||||
intp.weight = Weights(1, Element);
|
||||
IntPoint(0).x = Weights(0, Tr.ElementNo);
|
||||
IntPoint(0).weight = Weights(1, Tr.ElementNo);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int ip = 0; ip < GetNPoints(); ip++)
|
||||
{
|
||||
IntegrationPoint &intp = IntPoint(ip);
|
||||
intp.weight = Weights(ip, Element);
|
||||
IntPoint(ip).weight = Weights(ip, Tr.ElementNo) *
|
||||
SurfaceWeights(ip, Tr.ElementNo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief Destructor of SIntegrationRule
|
||||
~SIntegrationRule() {}
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -268,9 +276,12 @@ public:
|
||||
class CIntegrationRule : public IntegrationRule
|
||||
{
|
||||
protected:
|
||||
/// @brief Space Dimension of the IntegrationRule
|
||||
/// method 0 is moments-based, 1 is Algoim.
|
||||
int method, ir_order, ls_order;
|
||||
Coefficient &level_set;
|
||||
/// Space Dimension of the IntegrationRule
|
||||
int dim;
|
||||
/// @brief Column-wise matrix of the quadtrature weights
|
||||
/// Column-wise matrix of the quadtrature positions and weights.
|
||||
DenseMatrix Weights;
|
||||
|
||||
public:
|
||||
@@ -284,15 +295,21 @@ public:
|
||||
@param [in] lsOrder Polynomial degree for approx of level-set function
|
||||
@param [in] mesh Pointer to the mesh that is used
|
||||
*/
|
||||
CIntegrationRule(int Order, Coefficient& LvlSet, int lsOrder, Mesh* mesh)
|
||||
CIntegrationRule(int method_, int Order,
|
||||
Coefficient &LvlSet, int lsOrder, Mesh *mesh)
|
||||
: method(method_), ir_order(Order), ls_order(lsOrder),
|
||||
level_set(LvlSet), dim(mesh->Dimension())
|
||||
{
|
||||
dim = mesh->Dimension();
|
||||
// Nothing gets pre-computed for Algoim.
|
||||
if (method == 1) { return; }
|
||||
|
||||
#ifdef MFEM_USE_LAPACK
|
||||
MomentFittingIntRules mf_ir(ir_order, level_set, ls_order);
|
||||
|
||||
IsoparametricTransformation Tr;
|
||||
MomentFittingIntRules MFIRs(Order, LvlSet, lsOrder);
|
||||
mesh->GetElementTransformation(0, &Tr);
|
||||
IntegrationRule ir;
|
||||
MFIRs.GetVolumeIntegrationRule(Tr, ir);
|
||||
mf_ir.GetVolumeIntegrationRule(Tr, ir);
|
||||
if (dim > 1)
|
||||
{
|
||||
Weights.SetSize(ir.GetNPoints(), mesh->GetNE());
|
||||
@@ -324,9 +341,9 @@ public:
|
||||
for (int elem = 1; elem < mesh->GetNE(); elem++)
|
||||
{
|
||||
mesh->GetElementTransformation(elem, &Tr);
|
||||
MFIRs.GetVolumeIntegrationRule(Tr, ir);
|
||||
mf_ir.GetVolumeIntegrationRule(Tr, ir);
|
||||
|
||||
for (int ip = 0; ip < GetNPoints(); ip++)
|
||||
for (int ip = 0; ip < ir.GetNPoints(); ip++)
|
||||
{
|
||||
if (dim > 1)
|
||||
{
|
||||
@@ -339,29 +356,39 @@ public:
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
MFEM_ABORT("Moment-fitting requires MFEM to be built with LAPACK!");
|
||||
#endif
|
||||
}
|
||||
|
||||
/// @brief Set the weights for the given element
|
||||
void SetElement(int Element)
|
||||
void SetElement(ElementTransformation &Tr)
|
||||
{
|
||||
if (dim == 1)
|
||||
for (int ip = 0; ip < GetNPoints(); ip++)
|
||||
{
|
||||
IntegrationPoint &intp = IntPoint(ip);
|
||||
intp.x = Weights(2 * ip, Element);
|
||||
intp.weight = Weights(2 * ip + 1, Element);
|
||||
}
|
||||
else
|
||||
for (int ip = 0; ip < GetNPoints(); ip++)
|
||||
{
|
||||
IntegrationPoint &intp = IntPoint(ip);
|
||||
intp.weight = Weights(ip, Element);
|
||||
}
|
||||
}
|
||||
if (method == 1)
|
||||
{
|
||||
#ifdef MFEM_USE_ALGOIM
|
||||
AlgoimIntegrationRules a_ir(ir_order, level_set, ls_order);
|
||||
a_ir.GetVolumeIntegrationRule(Tr, *this);
|
||||
return;
|
||||
#else
|
||||
MFEM_ABORT("MFEM is not built with Algoim support!");
|
||||
#endif
|
||||
}
|
||||
|
||||
/// @brief Destructor of CIntegrationRule
|
||||
~CIntegrationRule() {}
|
||||
for (int ip = 0; ip < GetNPoints(); ip++)
|
||||
{
|
||||
IntegrationPoint &intp = IntPoint(ip);
|
||||
if (dim == 1)
|
||||
{
|
||||
intp.x = Weights(2 * ip, Tr.ElementNo);
|
||||
intp.weight = Weights(2 * ip + 1, Tr.ElementNo);
|
||||
}
|
||||
else { intp.weight = Weights(ip, Tr.ElementNo); }
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
@brief Class for surface linearform integrator
|
||||
|
||||
@@ -418,7 +445,7 @@ public:
|
||||
elvect = 0.;
|
||||
|
||||
// Update the surface integration rule for the current element
|
||||
SIntRule->SetElementinclSurfaceWeight(Tr.ElementNo);
|
||||
SIntRule->SetElementAndSurfaceWeight(Tr);
|
||||
|
||||
for (int ip = 0; ip < SIntRule->GetNPoints(); ip++)
|
||||
{
|
||||
@@ -428,6 +455,8 @@ public:
|
||||
add(elvect, SIntRule->IntPoint(ip).weight * val, shape, elvect);
|
||||
}
|
||||
}
|
||||
|
||||
using LinearFormIntegrator::AssembleRHSElementVect;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -486,7 +515,7 @@ public:
|
||||
elvect = 0.;
|
||||
|
||||
// Update the subdomain integration rule
|
||||
CIntRule->SetElement(Tr.ElementNo);
|
||||
CIntRule->SetElement(Tr);
|
||||
|
||||
for (int ip = 0; ip < CIntRule->GetNPoints(); ip++)
|
||||
{
|
||||
@@ -497,18 +526,17 @@ public:
|
||||
add(elvect, CIntRule->IntPoint(ip).weight * val, shape, elvect);
|
||||
}
|
||||
}
|
||||
|
||||
using LinearFormIntegrator::AssembleRHSElementVect;
|
||||
};
|
||||
#endif // MFEM_USE_LAPACK
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
#ifndef MFEM_USE_LAPACK
|
||||
cout << "MFEM must be built with LAPACK for this example." << endl;
|
||||
return MFEM_SKIP_RETURN_VALUE;
|
||||
#else
|
||||
#if defined(MFEM_USE_LAPACK) || defined(MFEM_USE_ALGOIM)
|
||||
// 1. Parse he command-line options.
|
||||
int ref_levels = 3;
|
||||
int order = 2;
|
||||
int method = 0;
|
||||
const char *inttype = "surface2d";
|
||||
bool visualization = true;
|
||||
itype = IntegrationType::Surface2D;
|
||||
@@ -516,6 +544,8 @@ int main(int argc, char *argv[])
|
||||
OptionsParser args(argc, argv);
|
||||
args.AddOption(&order, "-o", "--order", "Order of quadrature rule");
|
||||
args.AddOption(&ref_levels, "-r", "--refine", "Number of meh refinements");
|
||||
args.AddOption(&method, "-m", "--method",
|
||||
"Cut integration method: 0 for moments-based, 1 for Algoim.");
|
||||
args.AddOption(&inttype, "-i", "--integrationtype",
|
||||
"IntegrationType to demonstrate");
|
||||
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
|
||||
@@ -550,7 +580,7 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
|
||||
// 2. Construct and refine the mesh.
|
||||
Mesh *mesh;
|
||||
Mesh *mesh = nullptr;
|
||||
if (itype == IntegrationType::Volumetric1D)
|
||||
{
|
||||
mesh = new Mesh("../data/inline-segment.mesh");
|
||||
@@ -598,13 +628,14 @@ int main(int argc, char *argv[])
|
||||
// 5. Define the necessary Integration rules on element 0.
|
||||
IsoparametricTransformation Tr;
|
||||
mesh->GetElementTransformation(0, &Tr);
|
||||
SIntegrationRule* sir = new SIntegrationRule(order, levelset, 2, mesh);
|
||||
SIntegrationRule* sir = new SIntegrationRule(method, order,
|
||||
levelset, 2, mesh);
|
||||
CIntegrationRule* cir = NULL;
|
||||
if (itype == IntegrationType::Volumetric1D
|
||||
|| itype == IntegrationType::Volumetric2D
|
||||
|| itype == IntegrationType::Volumetric3D)
|
||||
{
|
||||
cir = new CIntegrationRule(order, levelset, 2, mesh);
|
||||
cir = new CIntegrationRule(method, order, levelset, 2, mesh);
|
||||
}
|
||||
|
||||
// 6. Define and assemble the linear forms on the finite element space.
|
||||
@@ -647,11 +678,11 @@ int main(int argc, char *argv[])
|
||||
cout << "Number of div free basis functions: " << nbasis << endl;
|
||||
cout << "Number of quadrature points: " << ir.GetNPoints() << endl;
|
||||
}
|
||||
cout << scientific << setprecision(2);
|
||||
cout << scientific << setprecision(10);
|
||||
cout << "============================================" << endl;
|
||||
cout << "Computed value of surface integral: " << surface.Sum() << endl;
|
||||
cout << "True value of surface integral: " << Surface() << endl;
|
||||
cout << "Absolute Error (Surface): ";
|
||||
cout << "Absolute Error (Surface): ";
|
||||
cout << abs(surface.Sum() - Surface()) << endl;
|
||||
cout << "Relative Error (Surface): ";
|
||||
cout << abs(surface.Sum() - Surface()) / Surface() << endl;
|
||||
@@ -662,7 +693,7 @@ int main(int argc, char *argv[])
|
||||
cout << "--------------------------------------------" << endl;
|
||||
cout << "Computed value of volume integral: " << volume.Sum() << endl;
|
||||
cout << "True value of volume integral: " << Volume() << endl;
|
||||
cout << "Absolute Error (Volume): ";
|
||||
cout << "Absolute Error (Volume): ";
|
||||
cout << abs(volume.Sum() - Volume()) << endl;
|
||||
cout << "Relative Error (Volume): ";
|
||||
cout << abs(volume.Sum() - Volume()) / Volume() << endl;
|
||||
@@ -691,5 +722,8 @@ int main(int argc, char *argv[])
|
||||
delete fespace;
|
||||
delete mesh;
|
||||
return EXIT_SUCCESS;
|
||||
#endif //MFEM_USE_LAPACK
|
||||
#else
|
||||
cout << "MFEM must be built with LAPACK or ALGOIM for this example." << endl;
|
||||
return MFEM_SKIP_RETURN_VALUE;
|
||||
#endif // MFEM_USE_LAPACK
|
||||
}
|
||||
|
||||
+3
-30
@@ -9,7 +9,7 @@
|
||||
// ex9 -m ../data/periodic-square.mesh -p 1 -r 2 -dt 0.005 -tf 9
|
||||
// ex9 -m ../data/periodic-hexagon.mesh -p 1 -r 2 -dt 0.005 -tf 9
|
||||
// ex9 -m ../data/amr-quad.mesh -p 1 -r 2 -dt 0.002 -tf 9
|
||||
// ex9 -m ../data/amr-quad.mesh -p 1 -r 2 -dt 0.02 -s 13 -tf 9
|
||||
// ex9 -m ../data/amr-quad.mesh -p 1 -r 2 -dt 0.02 -s 23 -tf 9
|
||||
// ex9 -m ../data/star-q3.mesh -p 1 -r 2 -dt 0.005 -tf 9
|
||||
// ex9 -m ../data/star-mixed.mesh -p 1 -r 2 -dt 0.005 -tf 9
|
||||
// ex9 -m ../data/disc-nurbs.mesh -p 1 -r 3 -dt 0.005 -tf 9
|
||||
@@ -182,12 +182,7 @@ int main(int argc, char *argv[])
|
||||
args.AddOption(&device_config, "-d", "--device",
|
||||
"Device configuration string, see Device::Configure().");
|
||||
args.AddOption(&ode_solver_type, "-s", "--ode-solver",
|
||||
"ODE solver: 1 - Forward Euler,\n\t"
|
||||
" 2 - RK2 SSP, 3 - RK3 SSP, 4 - RK4, 6 - RK6,\n\t"
|
||||
" 11 - Backward Euler,\n\t"
|
||||
" 12 - SDIRK23 (L-stable), 13 - SDIRK33,\n\t"
|
||||
" 22 - Implicit Midpoint Method,\n\t"
|
||||
" 23 - SDIRK23 (A-stable), 24 - SDIRK34");
|
||||
ODESolver::Types.c_str());
|
||||
args.AddOption(&t_final, "-tf", "--t-final",
|
||||
"Final time; start time is 0.");
|
||||
args.AddOption(&dt, "-dt", "--time-step",
|
||||
@@ -224,28 +219,7 @@ int main(int argc, char *argv[])
|
||||
|
||||
// 3. Define the ODE solver used for time integration. Several explicit
|
||||
// Runge-Kutta methods are available.
|
||||
ODESolver *ode_solver = NULL;
|
||||
switch (ode_solver_type)
|
||||
{
|
||||
// Explicit methods
|
||||
case 1: ode_solver = new ForwardEulerSolver; break;
|
||||
case 2: ode_solver = new RK2Solver(1.0); break;
|
||||
case 3: ode_solver = new RK3SSPSolver; break;
|
||||
case 4: ode_solver = new RK4Solver; break;
|
||||
case 6: ode_solver = new RK6Solver; break;
|
||||
// Implicit (L-stable) methods
|
||||
case 11: ode_solver = new BackwardEulerSolver; break;
|
||||
case 12: ode_solver = new SDIRK23Solver(2); break;
|
||||
case 13: ode_solver = new SDIRK33Solver; break;
|
||||
// Implicit A-stable methods (not L-stable)
|
||||
case 22: ode_solver = new ImplicitMidpointSolver; break;
|
||||
case 23: ode_solver = new SDIRK23Solver; break;
|
||||
case 24: ode_solver = new SDIRK34Solver; break;
|
||||
|
||||
default:
|
||||
cout << "Unknown ODE solver type: " << ode_solver_type << '\n';
|
||||
return 3;
|
||||
}
|
||||
unique_ptr<ODESolver> ode_solver = ODESolver::Select(ode_solver_type);
|
||||
|
||||
// 4. Refine the mesh to increase the resolution. In this example we do
|
||||
// 'ref_levels' of uniform refinement, where 'ref_levels' is a
|
||||
@@ -440,7 +414,6 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
|
||||
// 10. Free the used memory.
|
||||
delete ode_solver;
|
||||
delete pd;
|
||||
delete dc;
|
||||
|
||||
|
||||
+3
-33
@@ -9,7 +9,7 @@
|
||||
// mpirun -np 4 ex9p -m ../data/periodic-square.mesh -p 1 -dt 0.005 -tf 9
|
||||
// mpirun -np 4 ex9p -m ../data/periodic-hexagon.mesh -p 1 -dt 0.005 -tf 9
|
||||
// mpirun -np 4 ex9p -m ../data/amr-quad.mesh -p 1 -rp 1 -dt 0.002 -tf 9
|
||||
// mpirun -np 4 ex9p -m ../data/amr-quad.mesh -p 1 -rp 1 -dt 0.02 -s 13 -tf 9
|
||||
// mpirun -np 4 ex9p -m ../data/amr-quad.mesh -p 1 -rp 1 -dt 0.02 -s 23 -tf 9
|
||||
// mpirun -np 4 ex9p -m ../data/star-q3.mesh -p 1 -rp 1 -dt 0.004 -tf 9
|
||||
// mpirun -np 4 ex9p -m ../data/star-mixed.mesh -p 1 -rp 1 -dt 0.004 -tf 9
|
||||
// mpirun -np 4 ex9p -m ../data/disc-nurbs.mesh -p 1 -rp 1 -dt 0.005 -tf 9
|
||||
@@ -285,12 +285,7 @@ int main(int argc, char *argv[])
|
||||
args.AddOption(&device_config, "-d", "--device",
|
||||
"Device configuration string, see Device::Configure().");
|
||||
args.AddOption(&ode_solver_type, "-s", "--ode-solver",
|
||||
"ODE solver: 1 - Forward Euler,\n\t"
|
||||
" 2 - RK2 SSP, 3 - RK3 SSP, 4 - RK4, 6 - RK6,\n\t"
|
||||
" 11 - Backward Euler,\n\t"
|
||||
" 12 - SDIRK23 (L-stable), 13 - SDIRK33,\n\t"
|
||||
" 22 - Implicit Midpoint Method,\n\t"
|
||||
" 23 - SDIRK23 (A-stable), 24 - SDIRK34");
|
||||
ODESolver::Types.c_str());
|
||||
args.AddOption(&t_final, "-tf", "--t-final",
|
||||
"Final time; start time is 0.");
|
||||
args.AddOption(&dt, "-dt", "--time-step",
|
||||
@@ -338,31 +333,7 @@ int main(int argc, char *argv[])
|
||||
|
||||
// 4. Define the ODE solver used for time integration. Several explicit
|
||||
// Runge-Kutta methods are available.
|
||||
ODESolver *ode_solver = NULL;
|
||||
switch (ode_solver_type)
|
||||
{
|
||||
// Explicit methods
|
||||
case 1: ode_solver = new ForwardEulerSolver; break;
|
||||
case 2: ode_solver = new RK2Solver(1.0); break;
|
||||
case 3: ode_solver = new RK3SSPSolver; break;
|
||||
case 4: ode_solver = new RK4Solver; break;
|
||||
case 6: ode_solver = new RK6Solver; break;
|
||||
// Implicit (L-stable) methods
|
||||
case 11: ode_solver = new BackwardEulerSolver; break;
|
||||
case 12: ode_solver = new SDIRK23Solver(2); break;
|
||||
case 13: ode_solver = new SDIRK33Solver; break;
|
||||
// Implicit A-stable methods (not L-stable)
|
||||
case 22: ode_solver = new ImplicitMidpointSolver; break;
|
||||
case 23: ode_solver = new SDIRK23Solver; break;
|
||||
case 24: ode_solver = new SDIRK34Solver; break;
|
||||
default:
|
||||
if (Mpi::Root())
|
||||
{
|
||||
cout << "Unknown ODE solver type: " << ode_solver_type << '\n';
|
||||
}
|
||||
delete mesh;
|
||||
return 3;
|
||||
}
|
||||
unique_ptr<ODESolver> ode_solver = ODESolver::Select(ode_solver_type);
|
||||
|
||||
// 5. Refine the mesh in serial to increase the resolution. In this example
|
||||
// we do 'ser_ref_levels' of uniform refinement, where 'ser_ref_levels' is
|
||||
@@ -642,7 +613,6 @@ int main(int argc, char *argv[])
|
||||
delete m;
|
||||
delete fes;
|
||||
delete pmesh;
|
||||
delete ode_solver;
|
||||
delete pd;
|
||||
#ifdef MFEM_USE_ADIOS2
|
||||
if (adios2)
|
||||
|
||||
@@ -486,7 +486,11 @@ int main(int argc, char *argv[])
|
||||
arkode = new ARKStepSolver(ARKStepSolver::IMPLICIT);
|
||||
arkode->Init(*oper);
|
||||
arkode->SetSStolerances(reltol, abstol);
|
||||
#if MFEM_SUNDIALS_VERSION < 70100
|
||||
ARKStepSetNonlinConvCoef(arkode->GetMem(), arkode_eps_nonlin);
|
||||
#else
|
||||
ARKodeSetNonlinConvCoef(arkode->GetMem(), arkode_eps_nonlin);
|
||||
#endif
|
||||
arkode->SetMaxStep(dt);
|
||||
if (ode_solver_type == 15)
|
||||
{
|
||||
|
||||
@@ -541,7 +541,11 @@ int main(int argc, char *argv[])
|
||||
arkode = new ARKStepSolver(MPI_COMM_WORLD, ARKStepSolver::IMPLICIT);
|
||||
arkode->Init(*oper);
|
||||
arkode->SetSStolerances(reltol, abstol);
|
||||
#if MFEM_SUNDIALS_VERSION < 70100
|
||||
ARKStepSetNonlinConvCoef(arkode->GetMem(), arkode_eps_nonlin);
|
||||
#else
|
||||
ARKodeSetNonlinConvCoef(arkode->GetMem(), arkode_eps_nonlin);
|
||||
#endif
|
||||
arkode->SetMaxStep(dt);
|
||||
if (ode_solver_type == 15)
|
||||
{
|
||||
|
||||
@@ -447,7 +447,7 @@ ConductionOperator::ConductionOperator(FiniteElementSpace &fes,
|
||||
const Vector &u,
|
||||
const Type &ode_expression_type)
|
||||
: TimeDependentOperator(fes.GetTrueVSize(), 0.0, ode_expression_type),
|
||||
fespace(fes), alpha(alpha), kappa(kappa), M(&fespace), z(height)
|
||||
fespace(fes), M(&fespace), alpha(alpha), kappa(kappa), z(height)
|
||||
{
|
||||
// specify a relative tolerance for all solves with MFEM integrators
|
||||
const real_t rel_tol = 1e-8;
|
||||
@@ -522,7 +522,7 @@ int ConductionOperator::SUNImplicitSetup(const Vector &u, const Vector &fu,
|
||||
T = std::unique_ptr<SparseMatrix>(Add(1.0, Mmat, gam, Kmat));
|
||||
T_solver.SetOperator(*T);
|
||||
*jcur = SUNTRUE; // this should eventually only be set true if K(u) is used
|
||||
return SUNLS_SUCCESS;
|
||||
return SUN_SUCCESS;
|
||||
}
|
||||
|
||||
int ConductionOperator::SUNImplicitSolve(const Vector &r, Vector &dk,
|
||||
@@ -544,7 +544,7 @@ int ConductionOperator::SUNImplicitSolve(const Vector &r, Vector &dk,
|
||||
}
|
||||
if (T_solver.GetConverged())
|
||||
{
|
||||
return SUNLS_SUCCESS;
|
||||
return SUN_SUCCESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -555,7 +555,7 @@ int ConductionOperator::SUNImplicitSolve(const Vector &r, Vector &dk,
|
||||
int ConductionOperator::SUNMassSetup()
|
||||
{
|
||||
// Do nothing b/c mass solver was setup in constructor.
|
||||
return SUNLS_SUCCESS;
|
||||
return SUN_SUCCESS;
|
||||
}
|
||||
|
||||
int ConductionOperator::SUNMassSolve(const Vector &b, Vector &x, real_t tol)
|
||||
@@ -565,7 +565,7 @@ int ConductionOperator::SUNMassSolve(const Vector &b, Vector &x, real_t tol)
|
||||
M_solver.Mult(b, x);
|
||||
if (M_solver.GetConverged())
|
||||
{
|
||||
return SUNLS_SUCCESS;
|
||||
return SUN_SUCCESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -577,6 +577,6 @@ int ConductionOperator::SUNMassMult(const Vector &x, Vector &v)
|
||||
{
|
||||
// Compute M x.
|
||||
Mmat.Mult(x, v);
|
||||
return SUNLS_SUCCESS;
|
||||
return SUN_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
@@ -499,7 +499,7 @@ ConductionOperator::ConductionOperator(ParFiniteElementSpace &fes,
|
||||
const Vector &u,
|
||||
const Type &ode_expression_type)
|
||||
: TimeDependentOperator(fes.GetTrueVSize(), 0.0, ode_expression_type),
|
||||
fespace(fes), alpha(alpha), kappa(kappa), M(&fespace),
|
||||
fespace(fes), M(&fespace), alpha(alpha), kappa(kappa),
|
||||
M_solver(fes.GetComm()), T_solver(fes.GetComm()), z(height)
|
||||
{
|
||||
// specify a relative tolerance for all solves with MFEM integrators
|
||||
@@ -576,7 +576,7 @@ int ConductionOperator::SUNImplicitSetup(const Vector &u, const Vector &fu,
|
||||
T = std::unique_ptr<HypreParMatrix>(Add(1.0, Mmat, gam, Kmat));
|
||||
T_solver.SetOperator(*T);
|
||||
*jcur = SUNTRUE; // this should eventually only be set true if K(u) is used
|
||||
return SUNLS_SUCCESS;
|
||||
return SUN_SUCCESS;
|
||||
}
|
||||
|
||||
int ConductionOperator::SUNImplicitSolve(const Vector &r, Vector &dk,
|
||||
@@ -598,7 +598,7 @@ int ConductionOperator::SUNImplicitSolve(const Vector &r, Vector &dk,
|
||||
}
|
||||
if (T_solver.GetConverged())
|
||||
{
|
||||
return SUNLS_SUCCESS;
|
||||
return SUN_SUCCESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -609,7 +609,7 @@ int ConductionOperator::SUNImplicitSolve(const Vector &r, Vector &dk,
|
||||
int ConductionOperator::SUNMassSetup()
|
||||
{
|
||||
// Do nothing b/c mass solver was setup in constructor.
|
||||
return SUNLS_SUCCESS;
|
||||
return SUN_SUCCESS;
|
||||
}
|
||||
|
||||
int ConductionOperator::SUNMassSolve(const Vector &b, Vector &x, real_t tol)
|
||||
@@ -619,7 +619,7 @@ int ConductionOperator::SUNMassSolve(const Vector &b, Vector &x, real_t tol)
|
||||
M_solver.Mult(b, x);
|
||||
if (M_solver.GetConverged())
|
||||
{
|
||||
return SUNLS_SUCCESS;
|
||||
return SUN_SUCCESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -631,5 +631,5 @@ int ConductionOperator::SUNMassMult(const Vector &x, Vector &v)
|
||||
{
|
||||
// Compute M x.
|
||||
Mmat.Mult(x, v);
|
||||
return SUNLS_SUCCESS;
|
||||
return SUN_SUCCESS;
|
||||
}
|
||||
|
||||
+249
-26
@@ -289,9 +289,10 @@ void BilinearForm::ComputeElementMatrix(int i, DenseMatrix &elmat) const
|
||||
return;
|
||||
}
|
||||
|
||||
const FiniteElement &fe = *fes->GetFE(i);
|
||||
|
||||
if (domain_integs.Size())
|
||||
{
|
||||
const FiniteElement &fe = *fes->GetFE(i);
|
||||
ElementTransformation *eltrans = fes->GetElementTransformation(i);
|
||||
domain_integs[0]->AssembleElementMatrix(fe, *eltrans, elmat);
|
||||
for (int k = 1; k < domain_integs.Size(); k++)
|
||||
@@ -302,17 +303,18 @@ void BilinearForm::ComputeElementMatrix(int i, DenseMatrix &elmat) const
|
||||
}
|
||||
else
|
||||
{
|
||||
fes->GetElementVDofs(i, vdofs);
|
||||
elmat.SetSize(vdofs.Size());
|
||||
const int ndof = fe.GetDof() * fes->GetVDim();
|
||||
elmat.SetSize(ndof);
|
||||
elmat = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
void BilinearForm::ComputeBdrElementMatrix(int i, DenseMatrix &elmat) const
|
||||
{
|
||||
const FiniteElement &be = *fes->GetBE(i);
|
||||
|
||||
if (boundary_integs.Size())
|
||||
{
|
||||
const FiniteElement &be = *fes->GetBE(i);
|
||||
ElementTransformation *eltrans = fes->GetBdrElementTransformation(i);
|
||||
boundary_integs[0]->AssembleElementMatrix(be, *eltrans, elmat);
|
||||
for (int k = 1; k < boundary_integs.Size(); k++)
|
||||
@@ -323,8 +325,8 @@ void BilinearForm::ComputeBdrElementMatrix(int i, DenseMatrix &elmat) const
|
||||
}
|
||||
else
|
||||
{
|
||||
fes->GetBdrElementVDofs(i, vdofs);
|
||||
elmat.SetSize(vdofs.Size());
|
||||
const int ndof = be.GetDof() * fes->GetVDim();
|
||||
elmat.SetSize(ndof);
|
||||
elmat = 0.0;
|
||||
}
|
||||
}
|
||||
@@ -1429,32 +1431,50 @@ void MixedBilinearForm::GetBlocks(Array2D<SparseMatrix *> &blocks) const
|
||||
mat->GetBlocks(blocks);
|
||||
}
|
||||
|
||||
void MixedBilinearForm::AddDomainIntegrator (BilinearFormIntegrator * bfi)
|
||||
void MixedBilinearForm::AddDomainIntegrator(BilinearFormIntegrator *bfi)
|
||||
{
|
||||
domain_integs.Append (bfi);
|
||||
domain_integs.Append(bfi);
|
||||
domain_integs_marker.Append(NULL); // NULL marker means apply everywhere
|
||||
}
|
||||
|
||||
void MixedBilinearForm::AddDomainIntegrator (BilinearFormIntegrator * bfi,
|
||||
Array<int> &elem_marker)
|
||||
void MixedBilinearForm::AddDomainIntegrator(BilinearFormIntegrator *bfi,
|
||||
Array<int> &elem_marker)
|
||||
{
|
||||
domain_integs.Append (bfi);
|
||||
domain_integs.Append(bfi);
|
||||
domain_integs_marker.Append(&elem_marker);
|
||||
}
|
||||
|
||||
void MixedBilinearForm::AddBoundaryIntegrator (BilinearFormIntegrator * bfi)
|
||||
void MixedBilinearForm::AddBoundaryIntegrator(BilinearFormIntegrator *bfi)
|
||||
{
|
||||
boundary_integs.Append (bfi);
|
||||
boundary_integs.Append(bfi);
|
||||
boundary_integs_marker.Append(NULL); // NULL marker means apply everywhere
|
||||
}
|
||||
|
||||
void MixedBilinearForm::AddBoundaryIntegrator (BilinearFormIntegrator * bfi,
|
||||
Array<int> &bdr_marker)
|
||||
void MixedBilinearForm::AddBoundaryIntegrator(BilinearFormIntegrator *bfi,
|
||||
Array<int> &bdr_marker)
|
||||
{
|
||||
boundary_integs.Append (bfi);
|
||||
boundary_integs.Append(bfi);
|
||||
boundary_integs_marker.Append(&bdr_marker);
|
||||
}
|
||||
|
||||
void MixedBilinearForm::AddInteriorFaceIntegrator(BilinearFormIntegrator *bfi)
|
||||
{
|
||||
interior_face_integs.Append(bfi);
|
||||
}
|
||||
|
||||
void MixedBilinearForm::AddBdrFaceIntegrator(BilinearFormIntegrator *bfi)
|
||||
{
|
||||
boundary_face_integs.Append(bfi);
|
||||
boundary_face_integs_marker.Append(NULL); // NULL marker means apply everywhere
|
||||
}
|
||||
|
||||
void MixedBilinearForm::AddBdrFaceIntegrator(BilinearFormIntegrator *bfi,
|
||||
Array<int> &bdr_marker)
|
||||
{
|
||||
boundary_face_integs.Append(bfi);
|
||||
boundary_face_integs_marker.Append(&bdr_marker);
|
||||
}
|
||||
|
||||
void MixedBilinearForm::AddTraceFaceIntegrator (BilinearFormIntegrator * bfi)
|
||||
{
|
||||
trace_face_integs.Append (bfi);
|
||||
@@ -1587,6 +1607,108 @@ void MixedBilinearForm::Assemble(int skip_zeros)
|
||||
}
|
||||
}
|
||||
|
||||
if (interior_face_integs.Size())
|
||||
{
|
||||
FaceElementTransformations *ftr;
|
||||
Array<int> trial_vdofs2, test_vdofs2;
|
||||
const FiniteElement *trial_fe1, *trial_fe2, *test_fe1, *test_fe2;
|
||||
|
||||
int nfaces = mesh->GetNumFaces();
|
||||
for (int i = 0; i < nfaces; i++)
|
||||
{
|
||||
ftr = mesh->GetInteriorFaceTransformations(i);
|
||||
if (ftr != NULL)
|
||||
{
|
||||
trial_fes->GetElementVDofs(ftr->Elem1No, trial_vdofs);
|
||||
test_fes->GetElementVDofs(ftr->Elem1No, test_vdofs);
|
||||
trial_fe1 = trial_fes->GetFE(ftr->Elem1No);
|
||||
test_fe1 = test_fes->GetFE(ftr->Elem1No);
|
||||
if (ftr->Elem2No >= 0)
|
||||
{
|
||||
trial_fes->GetElementVDofs(ftr->Elem2No, trial_vdofs2);
|
||||
test_fes->GetElementVDofs(ftr->Elem2No, test_vdofs2);
|
||||
trial_vdofs.Append(trial_vdofs2);
|
||||
test_vdofs.Append(test_vdofs2);
|
||||
trial_fe2 = trial_fes->GetFE(ftr->Elem2No);
|
||||
test_fe2 = test_fes->GetFE(ftr->Elem2No);
|
||||
}
|
||||
else
|
||||
{
|
||||
// The test_fe2 object is really a dummy and not used on the
|
||||
// boundaries, but we can't dereference a NULL pointer, and we don't
|
||||
// want to actually make a fake element.
|
||||
trial_fe2 = trial_fe1;
|
||||
test_fe2 = test_fe1;
|
||||
}
|
||||
for (int k = 0; k < interior_face_integs.Size(); k++)
|
||||
{
|
||||
interior_face_integs[k]->AssembleFaceMatrix(*trial_fe1, *test_fe1, *trial_fe2,
|
||||
*test_fe2,
|
||||
*ftr, elemmat);
|
||||
mat->AddSubMatrix(test_vdofs, trial_vdofs, elemmat, skip_zeros);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (boundary_face_integs.Size())
|
||||
{
|
||||
FaceElementTransformations *ftr;
|
||||
Array<int> tr_vdofs2, te_vdofs2;
|
||||
const FiniteElement *trial_fe1, *trial_fe2, *test_fe1, *test_fe2;
|
||||
|
||||
// Which boundary attributes need to be processed?
|
||||
Array<int> bdr_attr_marker(mesh->bdr_attributes.Size() ?
|
||||
mesh->bdr_attributes.Max() : 0);
|
||||
bdr_attr_marker = 0;
|
||||
for (int k = 0; k < boundary_face_integs.Size(); k++)
|
||||
{
|
||||
if (boundary_face_integs_marker[k] == NULL)
|
||||
{
|
||||
bdr_attr_marker = 1;
|
||||
break;
|
||||
}
|
||||
Array<int> &bdr_marker = *boundary_face_integs_marker[k];
|
||||
MFEM_ASSERT(bdr_marker.Size() == bdr_attr_marker.Size(),
|
||||
"invalid boundary marker for boundary face integrator #"
|
||||
<< k << ", counting from zero");
|
||||
for (int i = 0; i < bdr_attr_marker.Size(); i++)
|
||||
{
|
||||
bdr_attr_marker[i] |= bdr_marker[i];
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < trial_fes -> GetNBE(); i++)
|
||||
{
|
||||
const int bdr_attr = mesh->GetBdrAttribute(i);
|
||||
if (bdr_attr_marker[bdr_attr-1] == 0) { continue; }
|
||||
|
||||
ftr = mesh -> GetBdrFaceTransformations (i);
|
||||
if (ftr != NULL)
|
||||
{
|
||||
trial_fes->GetElementVDofs(ftr->Elem1No, trial_vdofs);
|
||||
test_fes->GetElementVDofs(ftr->Elem1No, test_vdofs);
|
||||
trial_fe1 = trial_fes->GetFE(ftr->Elem1No);
|
||||
test_fe1 = test_fes->GetFE(ftr->Elem1No);
|
||||
// The test_fe2 object is really a dummy and not used on the
|
||||
// boundaries, but we can't dereference a NULL pointer, and we don't
|
||||
// want to actually make a fake element.
|
||||
trial_fe2 = trial_fe1;
|
||||
test_fe2 = test_fe1;
|
||||
for (int k = 0; k < boundary_face_integs.Size(); k++)
|
||||
{
|
||||
if (boundary_face_integs_marker[k] &&
|
||||
(*boundary_face_integs_marker[k])[bdr_attr-1] == 0) { continue; }
|
||||
|
||||
boundary_face_integs[k]->AssembleFaceMatrix(*trial_fe1, *test_fe1, *trial_fe2,
|
||||
*test_fe2,
|
||||
*ftr, elemmat);
|
||||
mat->AddSubMatrix(test_vdofs, trial_vdofs, elemmat, skip_zeros);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (trace_face_integs.Size())
|
||||
{
|
||||
FaceElementTransformations *ftr;
|
||||
@@ -1767,10 +1889,11 @@ void MixedBilinearForm::ConformingAssemble()
|
||||
|
||||
void MixedBilinearForm::ComputeElementMatrix(int i, DenseMatrix &elmat) const
|
||||
{
|
||||
const FiniteElement &trial_fe = *trial_fes->GetFE(i);
|
||||
const FiniteElement &test_fe = *test_fes->GetFE(i);
|
||||
|
||||
if (domain_integs.Size())
|
||||
{
|
||||
const FiniteElement &trial_fe = *trial_fes->GetFE(i);
|
||||
const FiniteElement &test_fe = *test_fes->GetFE(i);
|
||||
ElementTransformation *eltrans = test_fes->GetElementTransformation(i);
|
||||
domain_integs[0]->AssembleElementMatrix2(trial_fe, test_fe, *eltrans,
|
||||
elmat);
|
||||
@@ -1783,19 +1906,21 @@ void MixedBilinearForm::ComputeElementMatrix(int i, DenseMatrix &elmat) const
|
||||
}
|
||||
else
|
||||
{
|
||||
trial_fes->GetElementVDofs(i, trial_vdofs);
|
||||
test_fes->GetElementVDofs(i, test_vdofs);
|
||||
elmat.SetSize(test_vdofs.Size(), trial_vdofs.Size());
|
||||
const int tr_dofs = trial_fe.GetDof() * trial_fes->GetVDim();
|
||||
const int te_dofs = test_fe.GetDof() * test_fes->GetVDim();
|
||||
|
||||
elmat.SetSize(te_dofs, tr_dofs);
|
||||
elmat = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
void MixedBilinearForm::ComputeBdrElementMatrix(int i, DenseMatrix &elmat) const
|
||||
{
|
||||
const FiniteElement &trial_be = *trial_fes->GetBE(i);
|
||||
const FiniteElement &test_be = *test_fes->GetBE(i);
|
||||
|
||||
if (boundary_integs.Size())
|
||||
{
|
||||
const FiniteElement &trial_be = *trial_fes->GetBE(i);
|
||||
const FiniteElement &test_be = *test_fes->GetBE(i);
|
||||
ElementTransformation *eltrans = test_fes->GetBdrElementTransformation(i);
|
||||
boundary_integs[0]->AssembleElementMatrix2(trial_be, test_be, *eltrans,
|
||||
elmat);
|
||||
@@ -1808,9 +1933,103 @@ void MixedBilinearForm::ComputeBdrElementMatrix(int i, DenseMatrix &elmat) const
|
||||
}
|
||||
else
|
||||
{
|
||||
trial_fes->GetBdrElementVDofs(i, trial_vdofs);
|
||||
test_fes->GetBdrElementVDofs(i, test_vdofs);
|
||||
elmat.SetSize(test_vdofs.Size(), trial_vdofs.Size());
|
||||
const int tr_dofs = trial_be.GetDof() * trial_fes->GetVDim();
|
||||
const int te_dofs = test_be.GetDof() * test_fes->GetVDim();
|
||||
|
||||
elmat.SetSize(te_dofs, tr_dofs);
|
||||
elmat = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
void MixedBilinearForm::ComputeFaceMatrix(int i, DenseMatrix &elmat) const
|
||||
{
|
||||
FaceElementTransformations *ftr;
|
||||
Mesh *mesh = test_fes -> GetMesh();
|
||||
ftr = mesh->GetFaceElementTransformations(i);
|
||||
MFEM_ASSERT(ftr, "No associated face transformations.");
|
||||
|
||||
const FiniteElement *trial_fe1, *trial_fe2, *test_fe1, *test_fe2;
|
||||
|
||||
trial_fe1 = trial_fes->GetFE(ftr->Elem1No);
|
||||
test_fe1 = test_fes->GetFE(ftr->Elem1No);
|
||||
if (ftr->Elem2No >= 0)
|
||||
{
|
||||
trial_fe2 = trial_fes->GetFE(ftr->Elem2No);
|
||||
test_fe2 = test_fes->GetFE(ftr->Elem2No);
|
||||
}
|
||||
else
|
||||
{
|
||||
// The test_fe2 object is really a dummy and not used on the
|
||||
// boundaries, but we can't dereference a NULL pointer, and we don't
|
||||
// want to actually make a fake element.
|
||||
trial_fe2 = trial_fe1;
|
||||
test_fe2 = test_fe1;
|
||||
}
|
||||
|
||||
if (interior_face_integs.Size())
|
||||
{
|
||||
interior_face_integs[0]->AssembleFaceMatrix(*trial_fe1, *test_fe1, *trial_fe2,
|
||||
*test_fe2,
|
||||
*ftr, elmat);
|
||||
for (int k = 1; k < interior_face_integs.Size(); k++)
|
||||
{
|
||||
interior_face_integs[k]->AssembleFaceMatrix(*trial_fe1, *test_fe1, *trial_fe2,
|
||||
*test_fe2,
|
||||
*ftr, elemmat);
|
||||
elmat += elemmat;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int tr_dofs = trial_fe1->GetDof() * trial_fes->GetVDim();
|
||||
int te_dofs = test_fe1->GetDof() * test_fes->GetVDim();
|
||||
if (ftr->Elem2No >= 0)
|
||||
{
|
||||
tr_dofs += trial_fe2->GetDof() * trial_fes->GetVDim();
|
||||
te_dofs += test_fe2->GetDof() * test_fes->GetVDim();
|
||||
}
|
||||
|
||||
elmat.SetSize(te_dofs, tr_dofs);
|
||||
elmat = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
void MixedBilinearForm::ComputeBdrFaceMatrix(int i, DenseMatrix &elmat) const
|
||||
{
|
||||
FaceElementTransformations *ftr;
|
||||
Mesh *mesh = test_fes -> GetMesh();
|
||||
ftr = mesh->GetBdrFaceTransformations(i);
|
||||
MFEM_ASSERT(ftr, "No associated boundary face.");
|
||||
|
||||
const FiniteElement *trial_fe1, *trial_fe2, *test_fe1, *test_fe2;
|
||||
|
||||
trial_fe1 = trial_fes->GetFE(ftr->Elem1No);
|
||||
test_fe1 = test_fes->GetFE(ftr->Elem1No);
|
||||
// The test_fe2 object is really a dummy and not used on the
|
||||
// boundaries, but we can't dereference a NULL pointer, and we don't
|
||||
// want to actually make a fake element.
|
||||
trial_fe2 = trial_fe1;
|
||||
test_fe2 = test_fe1;
|
||||
|
||||
if (boundary_face_integs.Size())
|
||||
{
|
||||
boundary_face_integs[0]->AssembleFaceMatrix(*trial_fe1, *test_fe1, *trial_fe2,
|
||||
*test_fe2,
|
||||
*ftr, elmat);
|
||||
for (int k = 1; k < boundary_face_integs.Size(); k++)
|
||||
{
|
||||
boundary_face_integs[k]->AssembleFaceMatrix(*trial_fe1, *test_fe1, *trial_fe2,
|
||||
*test_fe2,
|
||||
*ftr, elemmat);
|
||||
elmat += elemmat;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const int tr_dofs = trial_fe1->GetDof() * trial_fes->GetVDim();
|
||||
const int te_dofs = test_fe1->GetDof() * test_fes->GetVDim();
|
||||
|
||||
elmat.SetSize(te_dofs, tr_dofs);
|
||||
elmat = 0.0;
|
||||
}
|
||||
}
|
||||
@@ -2114,6 +2333,10 @@ MixedBilinearForm::~MixedBilinearForm()
|
||||
for (i = 0; i < domain_integs.Size(); i++) { delete domain_integs[i]; }
|
||||
for (i = 0; i < boundary_integs.Size(); i++)
|
||||
{ delete boundary_integs[i]; }
|
||||
for (i = 0; i < interior_face_integs.Size(); i++)
|
||||
{ delete interior_face_integs[i]; }
|
||||
for (i = 0; i < boundary_face_integs.Size(); i++)
|
||||
{ delete boundary_face_integs[i]; }
|
||||
for (i = 0; i < trace_face_integs.Size(); i++)
|
||||
{ delete trace_face_integs[i]; }
|
||||
for (i = 0; i < boundary_trace_face_integs.Size(); i++)
|
||||
|
||||
@@ -772,6 +772,14 @@ protected:
|
||||
/// Entries are not owned.
|
||||
Array<Array<int>*> boundary_integs_marker;
|
||||
|
||||
/// Interior face integrators.
|
||||
Array<BilinearFormIntegrator*> interior_face_integs;
|
||||
|
||||
/// Boundary face integrators.
|
||||
Array<BilinearFormIntegrator*> boundary_face_integs;
|
||||
/// Entries are not owned.
|
||||
Array<Array<int>*> boundary_face_integs_marker;
|
||||
|
||||
/// Trace face (skeleton) integrators.
|
||||
Array<BilinearFormIntegrator*> trace_face_integs;
|
||||
|
||||
@@ -893,6 +901,16 @@ public:
|
||||
void AddBoundaryIntegrator(BilinearFormIntegrator * bfi,
|
||||
Array<int> &bdr_marker);
|
||||
|
||||
/// Adds an interior face integrator. Assumes ownership of @a bfi.
|
||||
void AddInteriorFaceIntegrator(BilinearFormIntegrator *bfi);
|
||||
|
||||
/// Adds a boundary face integrator. Assumes ownership of @a bfi.
|
||||
void AddBdrFaceIntegrator(BilinearFormIntegrator *bfi);
|
||||
|
||||
/// Adds a boundary face integrator. Assumes ownership of @a bfi.
|
||||
void AddBdrFaceIntegrator(BilinearFormIntegrator *bfi,
|
||||
Array<int> &bdr_marker);
|
||||
|
||||
/** @brief Add a trace face integrator. Assumes ownership of @a bfi.
|
||||
|
||||
This type of integrator assembles terms over all faces of the mesh using
|
||||
@@ -923,6 +941,16 @@ public:
|
||||
corresponding pointer (to Array<int>) will be NULL. */
|
||||
Array<Array<int>*> *GetBBFI_Marker() { return &boundary_integs_marker; }
|
||||
|
||||
/// Access all integrators added with AddInteriorFaceIntegrator().
|
||||
Array<BilinearFormIntegrator*> *GetFBFI() { return &interior_face_integs; }
|
||||
|
||||
/// Access all integrators added with AddBdrFaceIntegrator().
|
||||
Array<BilinearFormIntegrator*> *GetBFBFI() { return &boundary_face_integs; }
|
||||
/** @brief Access all boundary markers added with AddBdrFaceIntegrator().
|
||||
If no marker was specified when the integrator was added, the
|
||||
corresponding pointer (to Array<int>) will be NULL. */
|
||||
Array<Array<int>*> *GetBFBFI_Marker() { return &boundary_face_integs_marker; }
|
||||
|
||||
/// Access all integrators added with AddTraceFaceIntegrator().
|
||||
Array<BilinearFormIntegrator*> *GetTFBFI() { return &trace_face_integs; }
|
||||
|
||||
@@ -988,6 +1016,13 @@ public:
|
||||
/** @note The boundary attribute markers of the integrators are ignored. */
|
||||
void ComputeBdrTraceFaceMatrix(int i, DenseMatrix &elmat) const;
|
||||
|
||||
/// Compute the face matrix of the given face element
|
||||
void ComputeFaceMatrix(int i, DenseMatrix &elmat) const;
|
||||
|
||||
/// Compute the boundary face matrix of the given boundary element
|
||||
/** @note The boundary attribute markers of the integrators are ignored. */
|
||||
void ComputeBdrFaceMatrix(int i, DenseMatrix &elmat) const;
|
||||
|
||||
/// Assemble the given element matrix
|
||||
/** The element matrix @a elmat is assembled for the element @a i, i.e.
|
||||
added to the system matrix. The flag @a skip_zeros skips the zero
|
||||
|
||||
+209
-6
@@ -170,6 +170,16 @@ void BilinearFormIntegrator::AssembleFaceMatrix(
|
||||
" is not implemented for this class.");
|
||||
}
|
||||
|
||||
void BilinearFormIntegrator::AssembleFaceMatrix(
|
||||
const FiniteElement &trial_fe1, const FiniteElement &test_fe1,
|
||||
const FiniteElement &trial_fe2, const FiniteElement &test_fe2,
|
||||
FaceElementTransformations &Trans,
|
||||
DenseMatrix &elmat)
|
||||
{
|
||||
MFEM_ABORT("AssembleFaceMatrix (mixed form) is not implemented for this"
|
||||
" Integrator class.");
|
||||
}
|
||||
|
||||
void BilinearFormIntegrator::AssembleFaceMatrix(
|
||||
const FiniteElement &trial_face_fe, const FiniteElement &test_fe1,
|
||||
const FiniteElement &test_fe2, FaceElementTransformations &Trans,
|
||||
@@ -223,28 +233,38 @@ void TransposeIntegrator::SetIntRule(const IntegrationRule *ir)
|
||||
bfi->SetIntRule(ir);
|
||||
}
|
||||
|
||||
void TransposeIntegrator::AssembleElementMatrix (
|
||||
void TransposeIntegrator::AssembleElementMatrix(
|
||||
const FiniteElement &el, ElementTransformation &Trans, DenseMatrix &elmat)
|
||||
{
|
||||
bfi -> AssembleElementMatrix (el, Trans, bfi_elmat);
|
||||
bfi->AssembleElementMatrix(el, Trans, bfi_elmat);
|
||||
// elmat = bfi_elmat^t
|
||||
elmat.Transpose (bfi_elmat);
|
||||
}
|
||||
|
||||
void TransposeIntegrator::AssembleElementMatrix2 (
|
||||
void TransposeIntegrator::AssembleElementMatrix2(
|
||||
const FiniteElement &trial_fe, const FiniteElement &test_fe,
|
||||
ElementTransformation &Trans, DenseMatrix &elmat)
|
||||
{
|
||||
bfi -> AssembleElementMatrix2 (test_fe, trial_fe, Trans, bfi_elmat);
|
||||
bfi->AssembleElementMatrix2(test_fe, trial_fe, Trans, bfi_elmat);
|
||||
// elmat = bfi_elmat^t
|
||||
elmat.Transpose (bfi_elmat);
|
||||
}
|
||||
|
||||
void TransposeIntegrator::AssembleFaceMatrix (
|
||||
void TransposeIntegrator::AssembleFaceMatrix(
|
||||
const FiniteElement &el1, const FiniteElement &el2,
|
||||
FaceElementTransformations &Trans, DenseMatrix &elmat)
|
||||
{
|
||||
bfi -> AssembleFaceMatrix (el1, el2, Trans, bfi_elmat);
|
||||
bfi->AssembleFaceMatrix(el1, el2, Trans, bfi_elmat);
|
||||
// elmat = bfi_elmat^t
|
||||
elmat.Transpose (bfi_elmat);
|
||||
}
|
||||
|
||||
void TransposeIntegrator::AssembleFaceMatrix(
|
||||
const FiniteElement &tr_el1, const FiniteElement &te_el1,
|
||||
const FiniteElement &tr_el2, const FiniteElement &te_el2,
|
||||
FaceElementTransformations &Trans, DenseMatrix &elmat)
|
||||
{
|
||||
bfi->AssembleFaceMatrix(te_el1, tr_el1, te_el2, tr_el2, Trans, bfi_elmat);
|
||||
// elmat = bfi_elmat^t
|
||||
elmat.Transpose (bfi_elmat);
|
||||
}
|
||||
@@ -835,6 +855,34 @@ const IntegrationRule &GradientIntegrator::GetRule(const FiniteElement
|
||||
}
|
||||
|
||||
|
||||
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 )
|
||||
@@ -1290,6 +1338,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,
|
||||
@@ -3498,6 +3557,150 @@ void DGTraceIntegrator::AssembleFaceMatrix(const FiniteElement &el1,
|
||||
}
|
||||
}
|
||||
|
||||
void DGTraceIntegrator::AssembleFaceMatrix(const FiniteElement &trial_fe1,
|
||||
const FiniteElement &test_fe1,
|
||||
const FiniteElement &trial_fe2,
|
||||
const FiniteElement &test_fe2,
|
||||
FaceElementTransformations &Trans,
|
||||
DenseMatrix &elmat)
|
||||
{
|
||||
int tr_ndof1, te_ndof1, tr_ndof2, te_ndof2;
|
||||
|
||||
real_t un, a, b, w;
|
||||
|
||||
dim = test_fe1.GetDim();
|
||||
tr_ndof1 = trial_fe1.GetDof();
|
||||
te_ndof1 = test_fe1.GetDof();
|
||||
Vector vu(dim), nor(dim);
|
||||
|
||||
if (Trans.Elem2No >= 0)
|
||||
{
|
||||
tr_ndof2 = trial_fe2.GetDof();
|
||||
te_ndof2 = test_fe2.GetDof();
|
||||
}
|
||||
else
|
||||
{
|
||||
tr_ndof2 = 0;
|
||||
te_ndof2 = 0;
|
||||
}
|
||||
|
||||
tr_shape1.SetSize(tr_ndof1);
|
||||
te_shape1.SetSize(te_ndof1);
|
||||
tr_shape2.SetSize(tr_ndof2);
|
||||
te_shape2.SetSize(te_ndof2);
|
||||
elmat.SetSize(te_ndof1 + te_ndof2, tr_ndof1 + tr_ndof2);
|
||||
elmat = 0.0;
|
||||
|
||||
const IntegrationRule *ir = IntRule;
|
||||
if (ir == NULL)
|
||||
{
|
||||
int order;
|
||||
// Assuming order(u)==order(mesh)
|
||||
if (Trans.Elem2No >= 0)
|
||||
order = (min(Trans.Elem1->OrderW(), Trans.Elem2->OrderW()) +
|
||||
max(trial_fe1.GetOrder(), trial_fe2.GetOrder()) +
|
||||
max(test_fe1.GetOrder(), test_fe2.GetOrder()));
|
||||
else
|
||||
{
|
||||
order = Trans.Elem1->OrderW() + trial_fe1.GetOrder() + test_fe1.GetOrder();
|
||||
}
|
||||
if (trial_fe1.Space() == FunctionSpace::Pk)
|
||||
{
|
||||
order++;
|
||||
}
|
||||
ir = &IntRules.Get(Trans.FaceGeom, order);
|
||||
}
|
||||
|
||||
for (int p = 0; p < ir->GetNPoints(); p++)
|
||||
{
|
||||
const IntegrationPoint &ip = ir->IntPoint(p);
|
||||
IntegrationPoint eip1, eip2;
|
||||
Trans.Loc1.Transform(ip, eip1);
|
||||
Trans.Elem1->SetIntPoint(&eip1);
|
||||
if (tr_ndof2 && te_ndof2)
|
||||
{
|
||||
Trans.Loc2.Transform(ip, eip2);
|
||||
Trans.Elem2->SetIntPoint(&eip2);
|
||||
}
|
||||
trial_fe1.CalcPhysShape(*Trans.Elem1, tr_shape1);
|
||||
test_fe1.CalcPhysShape(*Trans.Elem1, te_shape1);
|
||||
|
||||
Trans.Face->SetIntPoint(&ip);
|
||||
|
||||
u->Eval(vu, *Trans.Elem1, eip1);
|
||||
|
||||
if (dim == 1)
|
||||
{
|
||||
nor(0) = 2*eip1.x - 1.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
CalcOrtho(Trans.Face->Jacobian(), nor);
|
||||
}
|
||||
|
||||
un = vu * nor;
|
||||
a = 0.5 * alpha * un;
|
||||
b = beta * fabs(un);
|
||||
// note: if |alpha/2|==|beta| then |a|==|b|, i.e. (a==b) or (a==-b)
|
||||
// and therefore two blocks in the element matrix contribution
|
||||
// (from the current quadrature point) are 0
|
||||
|
||||
if (rho)
|
||||
{
|
||||
real_t rho_p;
|
||||
if (un >= 0.0 && tr_ndof2 && te_ndof2)
|
||||
{
|
||||
Trans.Elem2->SetIntPoint(&eip2);
|
||||
rho_p = rho->Eval(*Trans.Elem2, eip2);
|
||||
}
|
||||
else
|
||||
{
|
||||
rho_p = rho->Eval(*Trans.Elem1, eip1);
|
||||
}
|
||||
a *= rho_p;
|
||||
b *= rho_p;
|
||||
}
|
||||
|
||||
w = ip.weight * (a+b);
|
||||
if (w != 0.0)
|
||||
{
|
||||
for (int i = 0; i < te_ndof1; i++)
|
||||
for (int j = 0; j < tr_ndof1; j++)
|
||||
{
|
||||
elmat(i, j) += w * te_shape1(i) * tr_shape1(j);
|
||||
}
|
||||
}
|
||||
|
||||
if (tr_ndof2 && te_ndof2)
|
||||
{
|
||||
trial_fe2.CalcPhysShape(*Trans.Elem2, tr_shape2);
|
||||
test_fe2.CalcPhysShape(*Trans.Elem2, te_shape2);
|
||||
|
||||
if (w != 0.0)
|
||||
for (int i = 0; i < te_ndof2; i++)
|
||||
for (int j = 0; j < tr_ndof1; j++)
|
||||
{
|
||||
elmat(te_ndof1+i, j) -= w * te_shape2(i) * tr_shape1(j);
|
||||
}
|
||||
|
||||
w = ip.weight * (b-a);
|
||||
if (w != 0.0)
|
||||
{
|
||||
for (int i = 0; i < te_ndof2; i++)
|
||||
for (int j = 0; j < tr_ndof2; j++)
|
||||
{
|
||||
elmat(te_ndof1+i, tr_ndof1+j) += w * te_shape2(i) * tr_shape2(j);
|
||||
}
|
||||
|
||||
for (int i = 0; i < te_ndof1; i++)
|
||||
for (int j = 0; j < tr_ndof2; j++)
|
||||
{
|
||||
elmat(i, tr_ndof1+j) -= w * te_shape1(i) * tr_shape2(j);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const IntegrationRule &DGTraceIntegrator::GetRule(
|
||||
Geometry::Type geom, int order, FaceElementTransformations &T)
|
||||
|
||||
+66
-25
@@ -159,6 +159,13 @@ public:
|
||||
FaceElementTransformations &Trans,
|
||||
DenseMatrix &elmat);
|
||||
|
||||
virtual void AssembleFaceMatrix(const FiniteElement &trial_fe1,
|
||||
const FiniteElement &test_fe1,
|
||||
const FiniteElement &trial_fe2,
|
||||
const FiniteElement &test_fe2,
|
||||
FaceElementTransformations &Trans,
|
||||
DenseMatrix &elmat);
|
||||
|
||||
/** Abstract method used for assembling TraceFaceIntegrators in a
|
||||
MixedBilinearForm. */
|
||||
virtual void AssembleFaceMatrix(const FiniteElement &trial_face_fe,
|
||||
@@ -335,6 +342,13 @@ public:
|
||||
FaceElementTransformations &Trans,
|
||||
DenseMatrix &elmat) override;
|
||||
|
||||
void AssembleFaceMatrix(const FiniteElement &trial_fe1,
|
||||
const FiniteElement &test_fe1,
|
||||
const FiniteElement &trial_fe2,
|
||||
const FiniteElement &test_fe2,
|
||||
FaceElementTransformations &Trans,
|
||||
DenseMatrix &elmat) override;
|
||||
|
||||
void AssemblePA(const FiniteElementSpace& fes) override
|
||||
{
|
||||
bfi->AssemblePA(fes);
|
||||
@@ -2142,7 +2156,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;
|
||||
@@ -2220,26 +2234,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. */
|
||||
@@ -2342,15 +2346,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. */
|
||||
@@ -3232,6 +3234,7 @@ protected:
|
||||
|
||||
private:
|
||||
Vector shape1, shape2;
|
||||
Vector tr_shape1, te_shape1, tr_shape2, te_shape2;
|
||||
|
||||
public:
|
||||
/// Construct integrator with $\rho = 1$, $\beta = \alpha/2$.
|
||||
@@ -3252,6 +3255,13 @@ public:
|
||||
FaceElementTransformations &Trans,
|
||||
DenseMatrix &elmat) override;
|
||||
|
||||
void AssembleFaceMatrix(const FiniteElement &trial_fe1,
|
||||
const FiniteElement &test_fe1,
|
||||
const FiniteElement &trial_fe2,
|
||||
const FiniteElement &test_fe2,
|
||||
FaceElementTransformations &Trans,
|
||||
DenseMatrix &elmat) override;
|
||||
|
||||
void AssemblePAInteriorFaces(const FiniteElementSpace &fes) override;
|
||||
|
||||
void AssemblePABoundaryFaces(const FiniteElementSpace &fes) override;
|
||||
@@ -3700,14 +3710,37 @@ private:
|
||||
the range space. Otherwise, a dof projection matrix is constructed. */
|
||||
class IdentityInterpolator : public DiscreteInterpolator
|
||||
{
|
||||
protected:
|
||||
const int vdim;
|
||||
|
||||
public:
|
||||
IdentityInterpolator(): dofquad_fe(NULL) { }
|
||||
/** @brief Construct an identity interpolator.
|
||||
|
||||
@param[in] vdim_ Vector dimension (number of components) in the domain
|
||||
and range FE spaces.
|
||||
*/
|
||||
IdentityInterpolator(int vdim_ = 1) : vdim(vdim_) { }
|
||||
|
||||
void AssembleElementMatrix2(const FiniteElement &dom_fe,
|
||||
const FiniteElement &ran_fe,
|
||||
ElementTransformation &Trans,
|
||||
DenseMatrix &elmat) override
|
||||
{ ran_fe.Project(dom_fe, Trans, elmat); }
|
||||
{
|
||||
if (vdim == 1)
|
||||
{
|
||||
ran_fe.Project(dom_fe, Trans, elmat);
|
||||
return;
|
||||
}
|
||||
DenseMatrix elmat_block;
|
||||
ran_fe.Project(dom_fe, Trans, elmat_block);
|
||||
elmat.SetSize(vdim*elmat_block.Height(), vdim*elmat_block.Width());
|
||||
elmat = 0_r;
|
||||
for (int i = 0; i < vdim; i++)
|
||||
{
|
||||
elmat.SetSubMatrix(i*elmat_block.Height(), i*elmat_block.Width(),
|
||||
elmat_block);
|
||||
}
|
||||
}
|
||||
|
||||
using BilinearFormIntegrator::AssemblePA;
|
||||
void AssemblePA(const FiniteElementSpace &trial_fes,
|
||||
@@ -3716,11 +3749,9 @@ public:
|
||||
void AddMultPA(const Vector &x, Vector &y) const override;
|
||||
void AddMultTransposePA(const Vector &x, Vector &y) const override;
|
||||
|
||||
virtual ~IdentityInterpolator() { delete dofquad_fe; }
|
||||
|
||||
private:
|
||||
/// 1D finite element that generates and owns the 1D DofToQuad maps below
|
||||
FiniteElement *dofquad_fe;
|
||||
std::unique_ptr<FiniteElement> dofquad_fe;
|
||||
|
||||
const DofToQuad *maps_C_C; // one-d map with Lobatto rows, Lobatto columns
|
||||
const DofToQuad *maps_O_C; // one-d map with Legendre rows, Lobatto columns
|
||||
@@ -3730,6 +3761,16 @@ private:
|
||||
};
|
||||
|
||||
|
||||
/** @brief Class identical to IdentityInterpolator with the exception that it
|
||||
requires the vector dimension (number of components) to be specified during
|
||||
construction. */
|
||||
class VectorIdentityInterpolator : public IdentityInterpolator
|
||||
{
|
||||
public:
|
||||
VectorIdentityInterpolator(int vdim_) : IdentityInterpolator(vdim_) { }
|
||||
};
|
||||
|
||||
|
||||
/** Class for constructing the (local) discrete curl matrix which can be used
|
||||
as an integrator in a DiscreteLinearOperator object to assemble the global
|
||||
discrete curl matrix. */
|
||||
|
||||
@@ -798,6 +798,12 @@ public:
|
||||
/// Sets coefficient in the vector.
|
||||
void Set(int i, Coefficient *c, bool own=true);
|
||||
|
||||
/// Set ownership of the i'th coefficient
|
||||
void SetOwnership(int i, bool own) { ownCoeff[i] = own; }
|
||||
|
||||
/// Get ownership of the i'th coefficient
|
||||
bool GetOwnership(int i) const { return ownCoeff[i]; }
|
||||
|
||||
/// Evaluates i'th component of the vector of coefficients and returns the
|
||||
/// value.
|
||||
real_t Eval(int i, ElementTransformation &T, const IntegrationPoint &ip)
|
||||
@@ -1320,6 +1326,12 @@ public:
|
||||
can be overridden with the @a own parameter. */
|
||||
void Set(int i, int j, Coefficient * c, bool own=true);
|
||||
|
||||
/// Set ownership of the coefficient at (i,j) in the matrix
|
||||
void SetOwnership(int i, int j, bool own) { ownCoeff[i*width+j] = own; }
|
||||
|
||||
/// Get ownership of the coefficient at (i,j) in the matrix
|
||||
bool GetOwnership(int i, int j) const { return ownCoeff[i*width+j]; }
|
||||
|
||||
using MatrixCoefficient::Eval;
|
||||
|
||||
/// Evaluate coefficient located at (i,j) in the matrix using integration
|
||||
@@ -1360,6 +1372,12 @@ public:
|
||||
can be overridden with the @a own parameter. */
|
||||
void Set(int i, VectorCoefficient * c, bool own=true);
|
||||
|
||||
/// Set ownership of the i'th coefficient
|
||||
void SetOwnership(int i, bool own) { ownCoeff[i] = own; }
|
||||
|
||||
/// Get ownership of the i'th coefficient
|
||||
bool GetOwnership(int i) const { return ownCoeff[i]; }
|
||||
|
||||
using MatrixCoefficient::Eval;
|
||||
|
||||
/// Evaluate coefficient located at the i-th row of the matrix using integration
|
||||
|
||||
+1
-1
@@ -1245,7 +1245,7 @@ ParSesquilinearForm::FormLinearSystem(const Array<int> &ess_tdof_list,
|
||||
hypre_ParCSRMatrix *Aih = *Ah;
|
||||
Ah->HypreReadWrite();
|
||||
const int *d_ess_tdof_list =
|
||||
ess_tdof_list.GetMemory().Read(GetHypreMemoryClass(), n);
|
||||
ess_tdof_list.GetMemory().Read(GetHypreForallMemoryClass(), n);
|
||||
HYPRE_Int *d_diag_i = Aih->diag->i;
|
||||
real_t *d_diag_data = Aih->diag->data;
|
||||
mfem::hypre_forall(n, [=] MFEM_HOST_DEVICE (int k)
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -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(),
|
||||
|
||||
@@ -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. */
|
||||
|
||||
+8
-6
@@ -37,7 +37,7 @@ FindPointsGSLIB::FindPointsGSLIB()
|
||||
: mesh(NULL),
|
||||
fec_map_lin(NULL),
|
||||
fdata2D(NULL), fdata3D(NULL), cr(NULL), gsl_comm(NULL),
|
||||
dim(-1), points_cnt(0), setupflag(false), default_interp_value(0),
|
||||
dim(-1), points_cnt(-1), setupflag(false), default_interp_value(0),
|
||||
avgtype(AvgType::ARITHMETIC), bdr_tol(1e-8)
|
||||
{
|
||||
mesh_split.SetSize(4);
|
||||
@@ -55,7 +55,7 @@ FindPointsGSLIB::FindPointsGSLIB()
|
||||
gsl_comm = new gslib::comm;
|
||||
cr = new gslib::crystal;
|
||||
#ifdef MFEM_USE_MPI
|
||||
int initialized;
|
||||
int initialized = 0;
|
||||
MPI_Initialized(&initialized);
|
||||
if (!initialized) { MPI_Init(NULL, NULL); }
|
||||
MPI_Comm comm = MPI_COMM_WORLD;
|
||||
@@ -85,7 +85,7 @@ FindPointsGSLIB::FindPointsGSLIB(MPI_Comm comm_)
|
||||
: mesh(NULL),
|
||||
fec_map_lin(NULL),
|
||||
fdata2D(NULL), fdata3D(NULL), cr(NULL), gsl_comm(NULL),
|
||||
dim(-1), points_cnt(0), setupflag(false), default_interp_value(0),
|
||||
dim(-1), points_cnt(-1), setupflag(false), default_interp_value(0),
|
||||
avgtype(AvgType::ARITHMETIC), bdr_tol(1e-8)
|
||||
{
|
||||
mesh_split.SetSize(4);
|
||||
@@ -307,6 +307,7 @@ void FindPointsGSLIB::FreeData()
|
||||
}
|
||||
if (fec_map_lin) { delete fec_map_lin; fec_map_lin = NULL; }
|
||||
setupflag = false;
|
||||
points_cnt = -1;
|
||||
}
|
||||
|
||||
void FindPointsGSLIB::SetupSplitMeshes()
|
||||
@@ -897,7 +898,8 @@ void FindPointsGSLIB::Interpolate(const GridFunction &field_in,
|
||||
int gf_order_h1 = std::max(gf_order, 1); // H1 should be at least order 1
|
||||
H1_FECollection fec(gf_order_h1, dim);
|
||||
const int ncomp = field_in.FESpace()->GetVDim();
|
||||
FiniteElementSpace fes(mesh, &fec, ncomp);
|
||||
FiniteElementSpace fes(mesh, &fec, ncomp,
|
||||
field_in.FESpace()->GetOrdering());
|
||||
GridFunction field_in_h1(&fes);
|
||||
|
||||
if (avgtype == AvgType::ARITHMETIC)
|
||||
@@ -927,7 +929,7 @@ void FindPointsGSLIB::Interpolate(const GridFunction &field_in,
|
||||
{
|
||||
for (int i = 0; i < indl2.Size(); i++)
|
||||
{
|
||||
int idx = field_in.FESpace()->GetOrdering() == Ordering::byNODES ?
|
||||
int idx = field_in_h1.FESpace()->GetOrdering() == Ordering::byNODES?
|
||||
indl2[i] + j*points_cnt:
|
||||
indl2[i]*ncomp + j;
|
||||
field_out(idx) = field_out_l2(idx);
|
||||
@@ -1172,7 +1174,7 @@ void FindPointsGSLIB::DistributePointInfoToOwningMPIRanks(
|
||||
Array<unsigned int> &recv_elem, Vector &recv_ref,
|
||||
Array<unsigned int> &recv_code)
|
||||
{
|
||||
MFEM_VERIFY(points_cnt,
|
||||
MFEM_VERIFY(points_cnt >= 0,
|
||||
"Invalid size. Please make sure to call FindPoints method "
|
||||
"before calling this function.");
|
||||
|
||||
|
||||
@@ -16,7 +16,6 @@ namespace mfem
|
||||
|
||||
// PA Diffusion Integrator
|
||||
|
||||
DiffusionIntegrator::Kernels DiffusionIntegrator::kernels;
|
||||
DiffusionIntegrator::Kernels::Kernels()
|
||||
{
|
||||
// 2D
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -1819,10 +1819,12 @@ void IdentityInterpolator::AssemblePA(const FiniteElementSpace &trial_fes,
|
||||
|
||||
MFEM_VERIFY(trial_el->GetOrder() == test_el->GetOrder(), "");
|
||||
|
||||
MFEM_VERIFY(vdim == 1, "vdim != 1 with PA is not supported yet!");
|
||||
|
||||
ne = trial_fes.GetNE();
|
||||
|
||||
const int order = trial_el->GetOrder();
|
||||
dofquad_fe = new H1_SegmentElement(order);
|
||||
dofquad_fe.reset(new H1_SegmentElement(order));
|
||||
mfem::QuadratureFunctions1D qf1d;
|
||||
mfem::IntegrationRule closed_ir;
|
||||
closed_ir.SetSize(order + 1);
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
MassIntegrator::Kernels MassIntegrator::kernels;
|
||||
MassIntegrator::Kernels::Kernels()
|
||||
{
|
||||
// 2D
|
||||
|
||||
+1
-1
@@ -1908,7 +1908,7 @@ IntegrationRule& NURBSMeshRules::GetElementRule(const int elem,
|
||||
}
|
||||
}
|
||||
|
||||
npd[d] = el[d].size() / 2;
|
||||
npd[d] = static_cast<int>(el[d].size() / 2);
|
||||
np *= npd[d];
|
||||
}
|
||||
|
||||
|
||||
+240
-22
@@ -31,6 +31,172 @@ void CutIntegrationRules::SetLevelSetProjectionOrder(int order)
|
||||
lsOrder = order;
|
||||
}
|
||||
|
||||
#ifdef MFEM_USE_ALGOIM
|
||||
void AlgoimIntegrationRules::GetSurfaceIntegrationRule(ElementTransformation
|
||||
&Tr,
|
||||
IntegrationRule &result)
|
||||
{
|
||||
GenerateLSVector(Tr,LvlSet);
|
||||
|
||||
const int dim=pe->GetDim();
|
||||
int np1d=CutIntegrationRules::Order/2+1;
|
||||
if (dim==2)
|
||||
{
|
||||
LevelSet2D ls(pe,lsvec);
|
||||
auto q = Algoim::quadGen<2>(ls,Algoim::BoundingBox<real_t,2>(0.0,1.0),
|
||||
2, -1, np1d);
|
||||
result.SetSize(q.nodes.size());
|
||||
result.SetOrder(CutIntegrationRules::Order);
|
||||
for (size_t i=0; i<q.nodes.size(); i++)
|
||||
{
|
||||
IntegrationPoint& ip=result.IntPoint(i);
|
||||
ip.Set2w(q.nodes[i].x(0),q.nodes[i].x(1),q.nodes[i].w);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LevelSet3D ls(pe,lsvec);
|
||||
auto q = Algoim::quadGen<3>(ls,Algoim::BoundingBox<real_t,3>(0.0,1.0),
|
||||
3, -1, np1d);
|
||||
|
||||
result.SetSize(q.nodes.size());
|
||||
result.SetOrder(CutIntegrationRules::Order);
|
||||
for (size_t i=0; i<q.nodes.size(); i++)
|
||||
{
|
||||
IntegrationPoint& ip=result.IntPoint(i);
|
||||
ip.Set(q.nodes[i].x(0),q.nodes[i].x(1),q.nodes[i].x(2),q.nodes[i].w);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void AlgoimIntegrationRules::GetVolumeIntegrationRule(ElementTransformation &Tr,
|
||||
IntegrationRule &result,
|
||||
const IntegrationRule *sir)
|
||||
{
|
||||
GenerateLSVector(Tr,LvlSet);
|
||||
|
||||
const int dim=pe->GetDim();
|
||||
int np1d=CutIntegrationRules::Order/2+1;
|
||||
if (dim==2)
|
||||
{
|
||||
LevelSet2D ls(pe,lsvec);
|
||||
auto q = Algoim::quadGen<2>(ls,Algoim::BoundingBox<real_t,2>(0.0,1.0),
|
||||
-1, -1, np1d);
|
||||
result.SetSize(q.nodes.size());
|
||||
result.SetOrder(CutIntegrationRules::Order);
|
||||
for (size_t i=0; i<q.nodes.size(); i++)
|
||||
{
|
||||
IntegrationPoint& ip=result.IntPoint(i);
|
||||
ip.Set2w(q.nodes[i].x(0),q.nodes[i].x(1),q.nodes[i].w);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LevelSet3D ls(pe,lsvec);
|
||||
auto q = Algoim::quadGen<3>(ls,Algoim::BoundingBox<real_t,3>(0.0,1.0),
|
||||
-1, -1, np1d);
|
||||
|
||||
result.SetSize(q.nodes.size());
|
||||
result.SetOrder(CutIntegrationRules::Order);
|
||||
for (size_t i=0; i<q.nodes.size(); i++)
|
||||
{
|
||||
IntegrationPoint& ip=result.IntPoint(i);
|
||||
ip.Set(q.nodes[i].x(0),q.nodes[i].x(1),q.nodes[i].x(2),q.nodes[i].w);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void AlgoimIntegrationRules::GetSurfaceWeights(ElementTransformation &Tr,
|
||||
const IntegrationRule &sir,
|
||||
Vector &weights)
|
||||
{
|
||||
GenerateLSVector(Tr,LvlSet);
|
||||
|
||||
DenseMatrix bmat; // gradients of the shape functions in isoparametric space
|
||||
DenseMatrix pmat; // gradients of the shape functions in physical space
|
||||
Vector inormal; // normal to the level set in isoparametric space
|
||||
Vector tnormal; // normal to the level set in physical space
|
||||
bmat.SetSize(pe->GetDof(),pe->GetDim());
|
||||
pmat.SetSize(pe->GetDof(),pe->GetDim());
|
||||
inormal.SetSize(pe->GetDim());
|
||||
tnormal.SetSize(pe->GetDim());
|
||||
|
||||
weights.SetSize(sir.GetNPoints());
|
||||
|
||||
for (int j = 0; j < sir.GetNPoints(); j++)
|
||||
{
|
||||
const IntegrationPoint &ip = sir.IntPoint(j);
|
||||
Tr.SetIntPoint(&ip);
|
||||
pe->CalcDShape(ip,bmat);
|
||||
Mult(bmat, Tr.InverseJacobian(), pmat);
|
||||
// compute the normal to the LS in isoparametric space
|
||||
bmat.MultTranspose(lsvec,inormal);
|
||||
// compute the normal to the LS in physical space
|
||||
pmat.MultTranspose(lsvec,tnormal);
|
||||
weights[j]= tnormal.Norml2() / inormal.Norml2();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void AlgoimIntegrationRules::GenerateLSVector(ElementTransformation &Tr,
|
||||
Coefficient* lvlset)
|
||||
{
|
||||
//check if the coefficient is already projected
|
||||
if (currentElementNo==Tr.ElementNo)
|
||||
{
|
||||
if (currentLvlSet==lvlset)
|
||||
{
|
||||
if (currentGeometry==Tr.GetGeometryType())
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
currentElementNo=Tr.ElementNo;
|
||||
|
||||
if (currentGeometry!=Tr.GetGeometryType())
|
||||
{
|
||||
delete le;
|
||||
delete pe;
|
||||
currentGeometry=Tr.GetGeometryType();
|
||||
if (Tr.GetGeometryType()==Geometry::Type::SQUARE)
|
||||
{
|
||||
pe=new H1Pos_QuadrilateralElement(lsOrder);
|
||||
le=new H1_QuadrilateralElement(lsOrder);
|
||||
}
|
||||
else if (Tr.GetGeometryType()==Geometry::Type::CUBE)
|
||||
{
|
||||
pe=new H1Pos_HexahedronElement(lsOrder);
|
||||
le=new H1_HexahedronElement(lsOrder);
|
||||
}
|
||||
else
|
||||
{
|
||||
MFEM_ABORT("Currently MFEM + Algoim supports only quads and hexes.");
|
||||
}
|
||||
|
||||
T.SetSize(pe->GetDof());
|
||||
pe->Project(*le,Tr,T);
|
||||
//The transformation matrix depends only on the geometry for change of basis
|
||||
}
|
||||
|
||||
currentLvlSet=lvlset;
|
||||
const IntegrationRule &ir=le->GetNodes();
|
||||
lsvec.SetSize(ir.GetNPoints());
|
||||
lsfun.SetSize(ir.GetNPoints());
|
||||
for (int i=0; i<ir.GetNPoints(); i++)
|
||||
{
|
||||
const IntegrationPoint &ip = ir.IntPoint(i);
|
||||
Tr.SetIntPoint(&ip);
|
||||
lsfun(i)=lvlset->Eval(Tr,ip);
|
||||
}
|
||||
T.Mult(lsfun,lsvec);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef MFEM_USE_LAPACK
|
||||
|
||||
void MomentFittingIntRules::InitSurface(int order, Coefficient& levelset,
|
||||
@@ -175,6 +341,7 @@ void MomentFittingIntRules::ComputeFaceWeights(ElementTransformation& Tr)
|
||||
local_mesh.GetElementTransformation(0, &faceTrafo);
|
||||
|
||||
// The 3D face integrals are computed as 2D volumetric integrals.
|
||||
// The 2D face integrals are computed as 1D volumetric integrals.
|
||||
MomentFittingIntRules FaceRules(Order, *LvlSet, lsOrder);
|
||||
IntegrationRule FaceRule;
|
||||
FaceRules.GetVolumeIntegrationRule(faceTrafo, FaceRule);
|
||||
@@ -254,8 +421,56 @@ void MomentFittingIntRules::ComputeSurfaceWeights1D(ElementTransformation& Tr)
|
||||
}
|
||||
}
|
||||
|
||||
void MomentFittingIntRules::ComputeVolumeWeights1D(ElementTransformation& Tr,
|
||||
const IntegrationRule* sir)
|
||||
double bisect(ElementTransformation &Tr, Coefficient *LvlSet)
|
||||
{
|
||||
IntegrationPoint intp;
|
||||
|
||||
IntegrationPoint ip0;
|
||||
ip0.x = 0.;
|
||||
IntegrationPoint ip1;
|
||||
ip1.x = 1.;
|
||||
Tr.SetIntPoint(&ip0);
|
||||
if (LvlSet->Eval(Tr, ip0) * LvlSet->Eval(Tr, ip1) < 0.)
|
||||
{
|
||||
IntegrationPoint ip2;
|
||||
ip2.x = .5;
|
||||
while (LvlSet->Eval(Tr, ip2) > 1e-12
|
||||
|| LvlSet->Eval(Tr, ip2) < -1e-12)
|
||||
{
|
||||
if (LvlSet->Eval(Tr, ip0) * LvlSet->Eval(Tr, ip2) < 0.)
|
||||
{
|
||||
ip1.x = ip2.x;
|
||||
}
|
||||
else
|
||||
{
|
||||
ip0.x = ip2.x;
|
||||
}
|
||||
|
||||
ip2.x = (ip1.x + ip0.x) / 2.;
|
||||
}
|
||||
intp.x = ip2.x;
|
||||
intp.weight = 1. / Tr.Weight();
|
||||
}
|
||||
else if (LvlSet->Eval(Tr, ip0) > 0. && LvlSet->Eval(Tr, ip1) <= 1e-12)
|
||||
{
|
||||
intp.x = 1.;
|
||||
intp.weight = 1. / Tr.Weight();
|
||||
}
|
||||
else if (LvlSet->Eval(Tr, ip1) > 0. && LvlSet->Eval(Tr, ip0) <= 1e-12)
|
||||
{
|
||||
intp.x = 0.;
|
||||
intp.weight = 1. / Tr.Weight();
|
||||
}
|
||||
else
|
||||
{
|
||||
intp.x = .5;
|
||||
intp.weight = 0.;
|
||||
}
|
||||
|
||||
return intp.x;
|
||||
}
|
||||
|
||||
void MomentFittingIntRules::ComputeVolumeWeights1D(ElementTransformation& Tr)
|
||||
{
|
||||
IntegrationRules irs(0, Quadrature1D::GaussLegendre);
|
||||
IntegrationRule ir2 = irs.Get(Geometry::SEGMENT, ir.GetOrder());
|
||||
@@ -271,7 +486,7 @@ void MomentFittingIntRules::ComputeVolumeWeights1D(ElementTransformation& Tr,
|
||||
real_t length;
|
||||
if (LvlSet->Eval(Tr, ip0) > 0.)
|
||||
{
|
||||
length = sir->IntPoint(0).x;
|
||||
length = bisect(Tr, LvlSet);
|
||||
for (int ip = 0; ip < ir.GetNPoints(); ip++)
|
||||
{
|
||||
IntegrationPoint &intp = ir.IntPoint(ip);
|
||||
@@ -281,11 +496,11 @@ void MomentFittingIntRules::ComputeVolumeWeights1D(ElementTransformation& Tr,
|
||||
}
|
||||
else
|
||||
{
|
||||
length = 1. - sir->IntPoint(0).x;
|
||||
length = 1. - bisect(Tr, LvlSet);
|
||||
for (int ip = 0; ip < ir.GetNPoints(); ip++)
|
||||
{
|
||||
IntegrationPoint &intp = ir.IntPoint(ip);
|
||||
intp.x = sir->IntPoint(ip).x + ir2.IntPoint(ip).x * length;
|
||||
intp.x = bisect(Tr, LvlSet) + ir2.IntPoint(ip).x * length;
|
||||
intp.weight = ir2.IntPoint(ip).weight * length;
|
||||
}
|
||||
}
|
||||
@@ -1491,26 +1706,29 @@ void MomentFittingIntRules::GetVolumeIntegrationRule(ElementTransformation& Tr,
|
||||
}
|
||||
|
||||
IntegrationRule SIR;
|
||||
if (sir == NULL)
|
||||
{
|
||||
Order++;
|
||||
GetSurfaceIntegrationRule(Tr, SIR);
|
||||
Order--;
|
||||
}
|
||||
else if ((sir->GetOrder() - 1) != ir.GetOrder())
|
||||
{
|
||||
Order++;
|
||||
GetSurfaceIntegrationRule(Tr, SIR);
|
||||
Order--;
|
||||
}
|
||||
else
|
||||
{
|
||||
SIR = *sir;
|
||||
}
|
||||
|
||||
if (Tr.GetDimension() == 1)
|
||||
{
|
||||
ComputeVolumeWeights1D(Tr, &SIR);
|
||||
Clear();
|
||||
InitVolume(Order, *LvlSet, lsOrder, Tr);
|
||||
}
|
||||
else if (sir == NULL)
|
||||
{
|
||||
Order++;
|
||||
GetSurfaceIntegrationRule(Tr, SIR);
|
||||
Order--;
|
||||
}
|
||||
else if (sir->GetOrder() - 1 != ir.GetOrder())
|
||||
{
|
||||
Order++;
|
||||
GetSurfaceIntegrationRule(Tr, SIR);
|
||||
Order--;
|
||||
}
|
||||
else { SIR = *sir; }
|
||||
|
||||
if (Tr.GetDimension() == 1)
|
||||
{
|
||||
ComputeVolumeWeights1D(Tr);
|
||||
}
|
||||
else if (Tr.GetDimension() == 2)
|
||||
{
|
||||
|
||||
+354
-3
@@ -18,6 +18,16 @@
|
||||
#include "eltrans.hpp"
|
||||
#include "coefficient.hpp"
|
||||
|
||||
|
||||
#ifdef MFEM_USE_ALGOIM
|
||||
#ifdef MFEM_HAVE_GCC_PRAGMA_DIAGNOSTIC
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||
#endif
|
||||
#include <algoim_quad.hpp>
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
/**
|
||||
@@ -116,6 +126,349 @@ public:
|
||||
virtual ~CutIntegrationRules() {}
|
||||
};
|
||||
|
||||
#ifdef MFEM_USE_ALGOIM
|
||||
// define templated element bases
|
||||
namespace TmplPoly_1D
|
||||
{
|
||||
|
||||
/// Templated version of CalcBinomTerms
|
||||
template<typename float_type>
|
||||
void CalcBinomTerms(const int p, const float_type x, const float_type y,
|
||||
float_type* u)
|
||||
{
|
||||
if (p == 0)
|
||||
{
|
||||
u[0] = float_type(1.);
|
||||
}
|
||||
else
|
||||
{
|
||||
int i;
|
||||
const int *b = Poly_1D::Binom(p);
|
||||
float_type z = x;
|
||||
for (i = 1; i < p; i++)
|
||||
{
|
||||
u[i] = b[i]*z;
|
||||
z *= x;
|
||||
}
|
||||
u[p] = z;
|
||||
z = y;
|
||||
for (i--; i > 0; i--)
|
||||
{
|
||||
u[i] *= z;
|
||||
z *= y;
|
||||
}
|
||||
u[0] = z;
|
||||
}
|
||||
}
|
||||
|
||||
/// Templated version of CalcBinomTerms
|
||||
template<typename float_type>
|
||||
void CalcBinomTerms(const int p, const float_type x, const float_type y,
|
||||
float_type* u, float_type* d)
|
||||
{
|
||||
if (p == 0)
|
||||
{
|
||||
u[0] = float_type(1.);
|
||||
d[0] = float_type(0.);
|
||||
}
|
||||
else
|
||||
{
|
||||
int i;
|
||||
const int *b = Poly_1D::Binom(p);
|
||||
const float_type xpy = x + y, ptx = p*x;
|
||||
float_type z = float_type(1.);
|
||||
|
||||
for (i = 1; i < p; i++)
|
||||
{
|
||||
d[i] = b[i]*z*(i*xpy - ptx);
|
||||
z *= x;
|
||||
u[i] = b[i]*z;
|
||||
}
|
||||
d[p] = p*z;
|
||||
u[p] = z*x;
|
||||
z = float_type(1.);
|
||||
for (i--; i > 0; i--)
|
||||
{
|
||||
d[i] *= z;
|
||||
z *= y;
|
||||
u[i] *= z;
|
||||
}
|
||||
d[0] = -p*z;
|
||||
u[0] = z*y;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// Templated evaluation of Bernstein basis
|
||||
template <typename float_type>
|
||||
void CalcBernstein(const int p, const float_type x, float_type *u)
|
||||
{
|
||||
CalcBinomTerms(p, x, 1. - x, u);
|
||||
}
|
||||
|
||||
|
||||
/// Templated evaluation of Bernstein basis
|
||||
template <typename float_type>
|
||||
void CalcBernstein(const int p, const float_type x,
|
||||
float_type *u, float_type *d)
|
||||
{
|
||||
CalcBinomTerms(p, x, 1. - x, u, d);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
class AlgoimIntegrationRules : public CutIntegrationRules
|
||||
{
|
||||
public:
|
||||
|
||||
/** @brief Constructor to set up the generated cut IntegrationRules.
|
||||
|
||||
@param [in] order Order of the constructed IntegrationRule.
|
||||
@param [in] lvlset Coefficient whose zero level set specifies the cut.
|
||||
@param [in] lsO Polynomial degree for projecting the level-set
|
||||
Coefficient to a GridFunction, which is used to
|
||||
compute gradients and normals. */
|
||||
AlgoimIntegrationRules(int order, Coefficient &lvlset, int lsO = 2)
|
||||
: CutIntegrationRules(order, lvlset, lsO)
|
||||
{
|
||||
pe=nullptr;
|
||||
le=nullptr;
|
||||
currentLvlSet=nullptr;
|
||||
currentGeometry=Geometry::Type::INVALID;
|
||||
currentElementNo = -1;
|
||||
}
|
||||
|
||||
virtual ~AlgoimIntegrationRules()
|
||||
{
|
||||
delete pe;
|
||||
delete le;
|
||||
}
|
||||
|
||||
virtual void SetOrder(int order) override
|
||||
{
|
||||
MFEM_VERIFY(order > 0, "Invalid input");
|
||||
Order = order;
|
||||
delete pe;
|
||||
delete le;
|
||||
pe=nullptr;
|
||||
le=nullptr;
|
||||
currentLvlSet=nullptr;
|
||||
currentGeometry=Geometry::Type::INVALID;
|
||||
currentElementNo=-1;
|
||||
}
|
||||
|
||||
virtual void SetLevelSetProjectionOrder(int order) override
|
||||
{
|
||||
MFEM_VERIFY(order > 0, "Invalid input");
|
||||
lsOrder = order;
|
||||
delete pe;
|
||||
delete le;
|
||||
pe=nullptr;
|
||||
le=nullptr;
|
||||
currentLvlSet=nullptr;
|
||||
currentGeometry=Geometry::Type::INVALID;
|
||||
currentElementNo=-1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
@brief Construct a cut-surface IntegrationRule.
|
||||
|
||||
Construct an IntegrationRule to integrate on the surface given by the
|
||||
already specified level set function, for the element given by @a Tr.
|
||||
|
||||
@param [in] Tr Specifies the IntegrationRule's associated mesh element.
|
||||
@param [out] result IntegrationRule on the cut-surface
|
||||
*/
|
||||
virtual
|
||||
void GetSurfaceIntegrationRule(ElementTransformation &Tr,
|
||||
IntegrationRule &result) override;
|
||||
|
||||
/**
|
||||
@brief Construct a cut-volume IntegrationRule.
|
||||
|
||||
Construct an IntegrationRule to integrate in the subdomain given by the
|
||||
positive values of the already specified level set function, for the element
|
||||
given by @a Tr.
|
||||
|
||||
@param [in] Tr Specifies the IntegrationRule's associated mesh element.
|
||||
@param [out] result IntegrationRule for the cut-volume
|
||||
@param [in] sir Corresponding IntegrationRule for the surface, which can
|
||||
be used to avoid computations.
|
||||
*/
|
||||
virtual
|
||||
void GetVolumeIntegrationRule(ElementTransformation &Tr,
|
||||
IntegrationRule &result,
|
||||
const IntegrationRule *sir = nullptr) override;
|
||||
|
||||
|
||||
/**
|
||||
@brief Compute transformation quadrature weights for surface integration.
|
||||
|
||||
Compute the transformation weights for integration over the cut-surface in
|
||||
reference space.
|
||||
|
||||
@param [in] Tr Specifies the IntegrationRule's associated element.
|
||||
@param [in] sir IntegrationRule defining the IntegrationPoints
|
||||
@param [out] weights Vector containing the transformation weights.
|
||||
*/
|
||||
virtual
|
||||
void GetSurfaceWeights(ElementTransformation &Tr,
|
||||
const IntegrationRule &sir,
|
||||
Vector &weights) override;
|
||||
|
||||
private:
|
||||
|
||||
/// projects the lvlset coefficient onto the lsvec,
|
||||
/// i.e., represent the level-set using Bernstein bases
|
||||
void GenerateLSVector(ElementTransformation &Tr, Coefficient* lvlset);
|
||||
|
||||
|
||||
/// Lagrange finite element used for converting coefficients to positive basis
|
||||
FiniteElement* le;
|
||||
PositiveTensorFiniteElement *pe;
|
||||
DenseMatrix T; //Projection matrix from nodal basis to positive basis
|
||||
Vector lsvec; // level-set in Bernstein basis
|
||||
Vector lsfun; // level-set in nodal basis
|
||||
Geometry::Type currentGeometry; // the current element geometry
|
||||
Coefficient* currentLvlSet; //the current level-set coefficient
|
||||
int currentElementNo; //the current element No
|
||||
|
||||
/// 3D level-set function object required by Algoim.
|
||||
struct LevelSet3D
|
||||
{
|
||||
/// Constructor for 3D level-set function object required by Algoim.
|
||||
LevelSet3D(PositiveTensorFiniteElement* el_, Vector& lsfun_)
|
||||
: el(el_), lsfun(lsfun_) { }
|
||||
|
||||
/// Returns the value of the LSF for point x.
|
||||
template<typename T>
|
||||
T operator() (const blitz::TinyVector<T,3>& x) const
|
||||
{
|
||||
int el_order=el->GetOrder();
|
||||
T u1[el_order+1];
|
||||
T u2[el_order+1];
|
||||
T u3[el_order+1];
|
||||
TmplPoly_1D::CalcBernstein(el_order, x[0], u1);
|
||||
TmplPoly_1D::CalcBernstein(el_order, x[1], u2);
|
||||
TmplPoly_1D::CalcBernstein(el_order, x[2], u3);
|
||||
|
||||
const Array<int>& dof_map=el->GetDofMap();
|
||||
|
||||
T res=T(0.0);
|
||||
for (int oo = 0, kk = 0; kk <= el_order; kk++)
|
||||
for (int jj = 0; jj <= el_order; jj++)
|
||||
for (int ii = 0; ii <= el_order; ii++)
|
||||
{
|
||||
res=res-u1[ii]*u2[jj]*u3[kk]*lsfun(dof_map[oo++]);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/// Returns the gradients of the LSF for point x.
|
||||
template<typename T>
|
||||
blitz::TinyVector<T,3> grad(const blitz::TinyVector<T,3>& x) const
|
||||
{
|
||||
int el_order=el->GetOrder();
|
||||
T u1[el_order+1];
|
||||
T u2[el_order+1];
|
||||
T u3[el_order+1];
|
||||
T d1[el_order+1];
|
||||
T d2[el_order+1];
|
||||
T d3[el_order+1];
|
||||
|
||||
TmplPoly_1D::CalcBernstein(el_order,x[0], u1, d1);
|
||||
TmplPoly_1D::CalcBernstein(el_order,x[1], u2, d2);
|
||||
TmplPoly_1D::CalcBernstein(el_order,x[2], u3, d3);
|
||||
|
||||
blitz::TinyVector<T,3> res(T(0.0),T(0.0),T(0.0));
|
||||
|
||||
const Array<int>& dof_map=el->GetDofMap();
|
||||
|
||||
for (int oo = 0, kk = 0; kk <= el_order; kk++)
|
||||
for (int jj = 0; jj <= el_order; jj++)
|
||||
for (int ii = 0; ii <= el_order; ii++)
|
||||
{
|
||||
res[0]=res[0]-d1[ii]*u2[jj]*u3[kk]*lsfun(dof_map[oo]);
|
||||
res[1]=res[1]-u1[ii]*d2[jj]*u3[kk]*lsfun(dof_map[oo]);
|
||||
res[2]=res[2]-u1[ii]*u2[jj]*d3[kk]*lsfun(dof_map[oo]);
|
||||
oo++;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
private:
|
||||
PositiveTensorFiniteElement* el;
|
||||
Vector& lsfun;
|
||||
};
|
||||
|
||||
/// 2D level-set function object required by Algoim.
|
||||
struct LevelSet2D
|
||||
{
|
||||
/// Constructor for 2D level-set function object required by Algoim.
|
||||
LevelSet2D(PositiveTensorFiniteElement* el_, Vector& lsfun_)
|
||||
:el(el_), lsfun(lsfun_) { }
|
||||
|
||||
/// Returns the value of the LSF for point x.
|
||||
template<typename T>
|
||||
T operator() (const blitz::TinyVector<T,2>& x) const
|
||||
{
|
||||
int el_order=el->GetOrder();
|
||||
T u1[el_order+1];
|
||||
T u2[el_order+1];
|
||||
TmplPoly_1D::CalcBernstein(el_order, x[0], u1);
|
||||
TmplPoly_1D::CalcBernstein(el_order, x[1], u2);
|
||||
|
||||
const Array<int>& dof_map=el->GetDofMap();
|
||||
|
||||
T res=T(0.0);
|
||||
|
||||
for (int oo = 0, jj = 0; jj <= el_order; jj++)
|
||||
for (int ii = 0; ii <= el_order; ii++)
|
||||
{
|
||||
res=res-u1[ii]*u2[jj]*lsfun(dof_map[oo++]);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/// Returns the gradients of the LSF for point x.
|
||||
template<typename T>
|
||||
blitz::TinyVector<T,2> grad(const blitz::TinyVector<T,2>& x) const
|
||||
{
|
||||
int el_order=el->GetOrder();
|
||||
T u1[el_order+1];
|
||||
T u2[el_order+1];
|
||||
T d1[el_order+1];
|
||||
T d2[el_order+1];
|
||||
|
||||
TmplPoly_1D::CalcBernstein(el_order,x[0], u1, d1);
|
||||
TmplPoly_1D::CalcBernstein(el_order,x[1], u2, d2);
|
||||
|
||||
blitz::TinyVector<T,2> res(T(0.0),T(0.0));
|
||||
|
||||
const Array<int>& dof_map=el->GetDofMap();
|
||||
|
||||
for (int oo = 0, jj = 0; jj <= el_order; jj++)
|
||||
for (int ii = 0; ii <= el_order; ii++)
|
||||
{
|
||||
res[0]=res[0]-(d1[ii]*u2[jj])*lsfun(dof_map[oo]);
|
||||
res[1]=res[1]-(u1[ii]*d2[jj])*lsfun(dof_map[oo]);
|
||||
oo++;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
PositiveTensorFiniteElement* el;
|
||||
Vector& lsfun;
|
||||
};
|
||||
};
|
||||
#endif //MFEM_USE_ALGOIM
|
||||
|
||||
#ifdef MFEM_USE_LAPACK
|
||||
|
||||
/**
|
||||
@@ -212,10 +565,8 @@ protected:
|
||||
rule.
|
||||
|
||||
@param [in] Tr ElementTransformation of the current element
|
||||
@param [in] sir corresponding IntegrationRule on surface
|
||||
*/
|
||||
void ComputeVolumeWeights1D(ElementTransformation& Tr,
|
||||
const IntegrationRule* sir);
|
||||
void ComputeVolumeWeights1D(ElementTransformation& Tr);
|
||||
|
||||
/**
|
||||
@brief Compute 2D quadrature weights
|
||||
|
||||
+13
-7
@@ -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.
|
||||
@@ -162,7 +162,7 @@ public:
|
||||
{
|
||||
std::tuple<Params...> param_tuple(PARAMS...);
|
||||
Kernels::Get().table[param_tuple] =
|
||||
Kernels:: template Kernel<PARAMS...>();
|
||||
Kernels:: template Kernel<PARAMS..., OptParams{}...>();
|
||||
};
|
||||
// Version with optional parameters
|
||||
template <OptParams... OPT_PARAMS>
|
||||
@@ -176,6 +176,12 @@ public:
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
/// Return the dispatch map table
|
||||
static const TableType &GetDispatchTable()
|
||||
{
|
||||
return Kernels::Get().table;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
+1
-1
@@ -676,7 +676,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
|
||||
|
||||
+7
-13
@@ -242,13 +242,13 @@ void BatchedLOR_AMS::FormGradientMatrix()
|
||||
template <typename T>
|
||||
static inline const T *HypreRead(const Memory<T> &mem)
|
||||
{
|
||||
return mem.Read(GetHypreMemoryClass(), mem.Capacity());
|
||||
return mem.Read(GetHypreForallMemoryClass(), mem.Capacity());
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static inline T *HypreWrite(Memory<T> &mem)
|
||||
{
|
||||
return mem.Write(GetHypreMemoryClass(), mem.Capacity());
|
||||
return mem.Write(GetHypreForallMemoryClass(), mem.Capacity());
|
||||
}
|
||||
|
||||
void BatchedLOR_AMS::FormCoordinateVectors(const Vector &X_vert)
|
||||
@@ -278,10 +278,7 @@ void BatchedLOR_AMS::FormCoordinateVectors(const Vector &X_vert)
|
||||
const int sdim = vert_fes.GetMesh()->SpaceDimension();
|
||||
const int ntdofs = R->Height();
|
||||
|
||||
const MemoryClass mc = GetHypreMemoryClass();
|
||||
bool dev = (mc == MemoryClass::DEVICE);
|
||||
|
||||
xyz_tvec = new Vector(ntdofs*sdim);
|
||||
xyz_tvec = new Vector(ntdofs*sdim, GetHypreMemoryType());
|
||||
|
||||
auto xyz_tv = Reshape(HypreWrite(xyz_tvec->GetMemory()), ntdofs, sdim);
|
||||
const auto xyz_e =
|
||||
@@ -304,15 +301,12 @@ void BatchedLOR_AMS::FormCoordinateVectors(const Vector &X_vert)
|
||||
// Make x, y, z HypreParVectors point to T-vector data
|
||||
HYPRE_BigInt glob_size = vert_fes.GlobalTrueVSize();
|
||||
HYPRE_BigInt *cols = vert_fes.GetTrueDofOffsets();
|
||||
|
||||
real_t *d_x_ptr = xyz_tv + 0*ntdofs;
|
||||
x = new HypreParVector(vert_fes.GetComm(), glob_size, d_x_ptr, cols, dev);
|
||||
real_t *d_y_ptr = xyz_tv + 1*ntdofs;
|
||||
y = new HypreParVector(vert_fes.GetComm(), glob_size, d_y_ptr, cols, dev);
|
||||
MPI_Comm comm = vert_fes.GetComm();
|
||||
x = new HypreParVector(comm, glob_size, *xyz_tvec, 0*ntdofs, cols);
|
||||
y = new HypreParVector(comm, glob_size, *xyz_tvec, 1*ntdofs, cols);
|
||||
if (sdim == 3)
|
||||
{
|
||||
real_t *d_z_ptr = xyz_tv + 2*ntdofs;
|
||||
z = new HypreParVector(vert_fes.GetComm(), glob_size, d_z_ptr, cols, dev);
|
||||
z = new HypreParVector(comm, glob_size, *xyz_tvec, 2*ntdofs, cols);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
+1
-1
@@ -16,7 +16,7 @@
|
||||
#include "bilinearform.hpp"
|
||||
|
||||
#include "../linalg/operator.hpp"
|
||||
#include "../linalg/handle.hpp"
|
||||
#include "../linalg/op_handle.hpp"
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
+7
-7
@@ -1984,7 +1984,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 +2074,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 +2833,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 +2893,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 +3119,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 +3240,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 +3252,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());
|
||||
|
||||
+33
-26
@@ -982,70 +982,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 +1054,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
|
||||
|
||||
+21
-5
@@ -434,13 +434,29 @@ public:
|
||||
/// be used for ASCII output.
|
||||
void Save(const char *fname, int precision=16) const override;
|
||||
|
||||
/// Returns a GridFunction on MPI rank @a save_rank that does not have any
|
||||
/// duplication of vertices/nodes at processor boundaries.
|
||||
/// serial_mesh is obtained using ParMesh::GetSerialMesh(save_rank).
|
||||
/// Note that the @ save_rank argument must match for the
|
||||
/// ParMesh::GetSerialMesh and GetSerialGridFunction method.
|
||||
/// @brief Returns a GridFunction on MPI rank @a save_rank that does not have
|
||||
/// any duplication of vertices/nodes at processor boundaries.
|
||||
///
|
||||
/// The @a serial_mesh is obtained using ParMesh::GetSerialMesh. Note that
|
||||
/// the @a save_rank must be the same as that used in ParMesh::GetSerialMesh.
|
||||
///
|
||||
/// @note The returned GridFunction will own the newly created
|
||||
/// FiniteElementCollection and FiniteElementSpace objects.
|
||||
GridFunction GetSerialGridFunction(int save_rank, Mesh &serial_mesh) const;
|
||||
|
||||
/// @brief Returns a GridFunction on MPI rank @a save_rank that does not have
|
||||
/// any duplication of vertices/nodes at processor boundaries.
|
||||
///
|
||||
/// The given @a serial_fes must be defined on the mesh returned by
|
||||
/// ParMesh::GetSerialMesh (with @a save_rank ranks), for example using the
|
||||
/// space belonging to the GridFunction obtained from @ref
|
||||
/// ParGridFunction::GetSerialGridFunction(int,Mesh &) const.
|
||||
///
|
||||
/// @note The returned GridFunction does not assume ownership of @a
|
||||
/// serial_fes.
|
||||
GridFunction GetSerialGridFunction(
|
||||
int save_rank, FiniteElementSpace &serial_fes) const;
|
||||
|
||||
/// Write the serial GridFunction a single file (written using MPI rank 0).
|
||||
/// The given @a precision will be used for ASCII output.
|
||||
void SaveAsSerial(const char *fname, int precision=16, int save_rank=0) const;
|
||||
|
||||
+229
-9
@@ -43,12 +43,13 @@ static void Derivatives1D(const int NE,
|
||||
const int q1d)
|
||||
{
|
||||
MFEM_CONTRACT_VAR(b_);
|
||||
const int SDIM = GRAD_PHYS ? sdim : 1;
|
||||
const auto g = Reshape(g_, q1d, d1d);
|
||||
const auto j = Reshape(j_, q1d, sdim, NE);
|
||||
const auto j = Reshape(j_, q1d, SDIM, NE);
|
||||
const auto x = Reshape(x_, d1d, vdim, NE);
|
||||
auto y = Q_LAYOUT == QVectorLayout::byNODES ?
|
||||
Reshape(y_, q1d, vdim, sdim, NE):
|
||||
Reshape(y_, vdim, sdim, q1d, NE);
|
||||
Reshape(y_, q1d, vdim, SDIM, NE):
|
||||
Reshape(y_, vdim, SDIM, q1d, NE);
|
||||
|
||||
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
|
||||
{
|
||||
@@ -63,8 +64,8 @@ static void Derivatives1D(const int NE,
|
||||
}
|
||||
if (GRAD_PHYS)
|
||||
{
|
||||
if (sdim == 1) { du[0] /= j(q, 0, e); }
|
||||
else if (sdim == 2)
|
||||
if (SDIM == 1) { du[0] /= j(q, 0, e); }
|
||||
else if (SDIM == 2)
|
||||
{
|
||||
const real_t Jloc[2] = {j(q,0,e), j(q,1,e)};
|
||||
real_t Jinv[3];
|
||||
@@ -74,7 +75,7 @@ static void Derivatives1D(const int NE,
|
||||
du[0] = U;
|
||||
du[1] = V;
|
||||
}
|
||||
else // sdim == 3
|
||||
else // SDIM == 3
|
||||
{
|
||||
const real_t Jloc[3] = {j(q,0,e), j(q,1,e), j(q,2,e)};
|
||||
real_t Jinv[3];
|
||||
@@ -87,7 +88,7 @@ static void Derivatives1D(const int NE,
|
||||
du[2] = W;
|
||||
}
|
||||
}
|
||||
for (int d = 0; d < sdim; ++d)
|
||||
for (int d = 0; d < SDIM; ++d)
|
||||
{
|
||||
if (Q_LAYOUT == QVectorLayout::byVDIM) { y(c, d, q, e) = du[d]; }
|
||||
if (Q_LAYOUT == QVectorLayout::byNODES) { y(q, c, d, e) = du[d]; }
|
||||
@@ -372,14 +373,222 @@ static void Derivatives3D(const int NE,
|
||||
});
|
||||
}
|
||||
|
||||
template<QVectorLayout Q_LAYOUT, bool GRAD_PHYS>
|
||||
static void CollocatedDerivatives1D(const int NE,
|
||||
const real_t *g_,
|
||||
const real_t *j_,
|
||||
const real_t *x_,
|
||||
real_t *y_,
|
||||
const int sdim,
|
||||
const int vdim,
|
||||
const int d1d)
|
||||
{
|
||||
Derivatives1D<Q_LAYOUT, GRAD_PHYS>(
|
||||
NE, nullptr, g_, j_, x_, y_, sdim, vdim, d1d, d1d);
|
||||
}
|
||||
|
||||
// Template compute kernel for derivatives in 2D: tensor product version.
|
||||
template<QVectorLayout Q_LAYOUT, bool GRAD_PHYS,
|
||||
int T_VDIM = 0, int T_D1D = 0,
|
||||
int T_NBZ = 1>
|
||||
static void CollocatedDerivatives2D(const int NE,
|
||||
const real_t *g_,
|
||||
const real_t *j_,
|
||||
const real_t *x_,
|
||||
real_t *y_,
|
||||
const int sdim = 2,
|
||||
const int vdim = 0,
|
||||
const int d1d = 0)
|
||||
{
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int VDIM = T_VDIM ? T_VDIM : vdim;
|
||||
const int SDIM = GRAD_PHYS ? sdim : 2;
|
||||
static constexpr int NBZ = T_NBZ ? T_NBZ : 1;
|
||||
|
||||
const auto g = Reshape(g_, D1D, D1D);
|
||||
const auto j = Reshape(j_, D1D, D1D, SDIM, 2, NE);
|
||||
const auto x = Reshape(x_, D1D, D1D, VDIM, NE);
|
||||
auto y = Q_LAYOUT == QVectorLayout:: byNODES ?
|
||||
Reshape(y_, D1D, D1D, VDIM, SDIM, NE):
|
||||
Reshape(y_, VDIM, SDIM, D1D, D1D, NE);
|
||||
|
||||
mfem::forall_2D_batch(NE, D1D, D1D, NBZ, [=] MFEM_HOST_DEVICE (int e)
|
||||
{
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int VDIM = T_VDIM ? T_VDIM : vdim;
|
||||
constexpr int MD1 = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
|
||||
|
||||
const int tidz = MFEM_THREAD_ID(z);
|
||||
|
||||
MFEM_SHARED real_t XY[NBZ][MD1*MD1];
|
||||
DeviceTensor<2> X((real_t*)(XY+tidz), D1D, D1D);
|
||||
|
||||
for (int c = 0; c < VDIM; ++c)
|
||||
{
|
||||
kernels::internal::LoadX<MD1,NBZ>(e,D1D,c,x,XY);
|
||||
MFEM_FOREACH_THREAD(dy,y,D1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(dx,x,D1D)
|
||||
{
|
||||
real_t u = 0.0;
|
||||
real_t v = 0.0;
|
||||
real_t w = 0.0;
|
||||
for (int dxy = 0; dxy < D1D; ++dxy)
|
||||
{
|
||||
u += X(dxy, dy) * g(dx,dxy);
|
||||
v += X(dx, dxy) * g(dy,dxy);
|
||||
}
|
||||
|
||||
if (GRAD_PHYS)
|
||||
{
|
||||
if (SDIM == 2)
|
||||
{
|
||||
real_t Jloc[4], Jinv[4];
|
||||
Jloc[0] = j(dx,dy,0,0,e);
|
||||
Jloc[1] = j(dx,dy,1,0,e);
|
||||
Jloc[2] = j(dx,dy,0,1,e);
|
||||
Jloc[3] = j(dx,dy,1,1,e);
|
||||
kernels::CalcInverse<2>(Jloc, Jinv);
|
||||
const real_t U = Jinv[0]*u + Jinv[1]*v;
|
||||
const real_t V = Jinv[2]*u + Jinv[3]*v;
|
||||
u = U;
|
||||
v = V;
|
||||
}
|
||||
else
|
||||
{
|
||||
real_t Jloc[6], Jinv[6];
|
||||
Jloc[0] = j(dx,dy,0,0,e);
|
||||
Jloc[1] = j(dx,dy,1,0,e);
|
||||
Jloc[2] = j(dx,dy,2,0,e);
|
||||
Jloc[3] = j(dx,dy,0,1,e);
|
||||
Jloc[4] = j(dx,dy,1,1,e);
|
||||
Jloc[5] = j(dx,dy,2,1,e);
|
||||
kernels::CalcLeftInverse<3,2>(Jloc, Jinv);
|
||||
const real_t U = Jinv[0]*u + Jinv[1]*v;
|
||||
const real_t V = Jinv[2]*u + Jinv[3]*v;
|
||||
const real_t W = Jinv[4]*u + Jinv[5]*v;
|
||||
u = U;
|
||||
v = V;
|
||||
w = W;
|
||||
}
|
||||
}
|
||||
|
||||
if (Q_LAYOUT == QVectorLayout::byVDIM)
|
||||
{
|
||||
y(c,0,dx,dy,e) = u;
|
||||
y(c,1,dx,dy,e) = v;
|
||||
if (SDIM == 3) { y(c,2,dx,dy,e) = w; }
|
||||
}
|
||||
if (Q_LAYOUT == QVectorLayout::byNODES)
|
||||
{
|
||||
y(dx,dy,c,0,e) = u;
|
||||
y(dx,dy,c,1,e) = v;
|
||||
if (SDIM == 3) { y(dx,dy,c,2,e) = w; }
|
||||
}
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Template compute kernel for derivatives in 3D: tensor product version.
|
||||
template<QVectorLayout Q_LAYOUT, bool GRAD_PHYS,
|
||||
int T_VDIM = 0, int T_D1D = 0>
|
||||
static void CollocatedDerivatives3D(const int NE,
|
||||
const real_t *g_,
|
||||
const real_t *j_,
|
||||
const real_t *x_,
|
||||
real_t *y_,
|
||||
const int sdim = 3,
|
||||
const int vdim = 0,
|
||||
const int d1d = 0)
|
||||
{
|
||||
MFEM_VERIFY(sdim == 3, "");
|
||||
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int VDIM = T_VDIM ? T_VDIM : vdim;
|
||||
|
||||
const auto g = Reshape(g_, D1D, D1D);
|
||||
const auto j = Reshape(j_, D1D, D1D, D1D, 3, 3, NE);
|
||||
const auto x = Reshape(x_, D1D, D1D, D1D, VDIM, NE);
|
||||
auto y = Q_LAYOUT == QVectorLayout:: byNODES ?
|
||||
Reshape(y_, D1D, D1D, D1D, VDIM, 3, NE):
|
||||
Reshape(y_, VDIM, 3, D1D, D1D, D1D, NE);
|
||||
|
||||
mfem::forall_3D(NE, D1D, D1D, D1D, [=] MFEM_HOST_DEVICE (int e)
|
||||
{
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int VDIM = T_VDIM ? T_VDIM : vdim;
|
||||
constexpr int MD1 = T_D1D ? T_D1D : DofQuadLimits::MAX_INTERP_1D;
|
||||
|
||||
MFEM_SHARED real_t uvw[MD1*MD1*MD1];
|
||||
DeviceTensor<3> X(uvw, D1D, D1D, D1D);
|
||||
|
||||
for (int c = 0; c < VDIM; ++c)
|
||||
{
|
||||
kernels::internal::LoadX(e,D1D,c,x,X);
|
||||
MFEM_FOREACH_THREAD(dz,z,D1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(dy,y,D1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(dx,x,D1D)
|
||||
{
|
||||
real_t u = 0.0;
|
||||
real_t v = 0.0;
|
||||
real_t w = 0.0;
|
||||
for (int dxyz = 0; dxyz < D1D; ++dxyz)
|
||||
{
|
||||
u += X(dxyz, dy, dz) * g(dx,dxyz);
|
||||
v += X(dx, dxyz, dz) * g(dy,dxyz);
|
||||
w += X(dx, dy, dxyz) * g(dz,dxyz);
|
||||
}
|
||||
|
||||
if (GRAD_PHYS)
|
||||
{
|
||||
real_t Jloc[9], Jinv[9];
|
||||
for (int col = 0; col < 3; col++)
|
||||
{
|
||||
for (int row = 0; row < 3; row++)
|
||||
{
|
||||
Jloc[row+3*col] = j(dx,dy,dz,row,col,e);
|
||||
}
|
||||
}
|
||||
kernels::CalcInverse<3>(Jloc, Jinv);
|
||||
const real_t U = Jinv[0]*u + Jinv[1]*v + Jinv[2]*w;
|
||||
const real_t V = Jinv[3]*u + Jinv[4]*v + Jinv[5]*w;
|
||||
const real_t W = Jinv[6]*u + Jinv[7]*v + Jinv[8]*w;
|
||||
u = U; v = V; w = W;
|
||||
}
|
||||
if (Q_LAYOUT == QVectorLayout::byVDIM)
|
||||
{
|
||||
y(c,0,dx,dy,dz,e) = u;
|
||||
y(c,1,dx,dy,dz,e) = v;
|
||||
y(c,2,dx,dy,dz,e) = w;
|
||||
}
|
||||
if (Q_LAYOUT == QVectorLayout::byNODES)
|
||||
{
|
||||
y(dx,dy,dz,c,0,e) = u;
|
||||
y(dx,dy,dz,c,1,e) = v;
|
||||
y(dx,dy,dz,c,2,e) = w;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace quadrature_interpolator
|
||||
|
||||
} // namespace internal
|
||||
|
||||
/// @cond Suppress_Doxygen_warnings
|
||||
|
||||
template<int DIM, QVectorLayout Q_LAYOUT, bool GRAD_PHYS,
|
||||
int VDIM, int D1D, int Q1D, int NBZ>
|
||||
template<int DIM, QVectorLayout Q_LAYOUT, bool GRAD_PHYS, int VDIM, int D1D,
|
||||
int Q1D, int NBZ>
|
||||
QuadratureInterpolator::GradKernelType
|
||||
QuadratureInterpolator::GradKernels::Kernel()
|
||||
{
|
||||
@@ -389,6 +598,17 @@ QuadratureInterpolator::GradKernels::Kernel()
|
||||
else { MFEM_ABORT(""); }
|
||||
}
|
||||
|
||||
template<int DIM, QVectorLayout Q_LAYOUT, bool GRAD_PHYS, int VDIM, int D1D,
|
||||
int NBZ>
|
||||
QuadratureInterpolator::CollocatedGradKernelType
|
||||
QuadratureInterpolator::CollocatedGradKernels::Kernel()
|
||||
{
|
||||
if (DIM == 1) { return internal::quadrature_interpolator::CollocatedDerivatives1D<Q_LAYOUT, GRAD_PHYS>; }
|
||||
else if (DIM == 2) { return internal::quadrature_interpolator::CollocatedDerivatives2D<Q_LAYOUT, GRAD_PHYS, VDIM, D1D, NBZ>; }
|
||||
else if (DIM == 3) { return internal::quadrature_interpolator::CollocatedDerivatives3D<Q_LAYOUT, GRAD_PHYS, VDIM, D1D>; }
|
||||
else { MFEM_ABORT(""); }
|
||||
}
|
||||
|
||||
/// @endcond
|
||||
|
||||
} // namespace mfem
|
||||
|
||||
@@ -23,50 +23,73 @@ template <bool P>
|
||||
void InitGradByNodesKernels()
|
||||
{
|
||||
using k = QuadratureInterpolator::GradKernels;
|
||||
constexpr auto L = QVectorLayout::byNODES;
|
||||
// 2D
|
||||
k::Specialization<2,QVectorLayout::byNODES,P,1,3,3>::template Opt<16>::Add();
|
||||
k::Specialization<2,QVectorLayout::byNODES,P,1,3,4>::template Opt<16>::Add();
|
||||
k::Specialization<2,QVectorLayout::byNODES,P,1,4,3>::template Opt<16>::Add();
|
||||
k::Specialization<2,QVectorLayout::byNODES,P,1,4,4>::template Opt<16>::Add();
|
||||
k::Specialization<2,L,P,1,3,3>::template Opt<16>::Add();
|
||||
k::Specialization<2,L,P,1,3,4>::template Opt<16>::Add();
|
||||
k::Specialization<2,L,P,1,4,3>::template Opt<16>::Add();
|
||||
k::Specialization<2,L,P,1,4,4>::template Opt<16>::Add();
|
||||
|
||||
k::Specialization<2,QVectorLayout::byNODES,P,2,2,2>::template Opt<16>::Add();
|
||||
k::Specialization<2,QVectorLayout::byNODES,P,2,2,3>::template Opt<8>::Add();
|
||||
k::Specialization<2,QVectorLayout::byNODES,P,2,2,4>::template Opt<4>::Add();
|
||||
k::Specialization<2,QVectorLayout::byNODES,P,2,2,5>::template Opt<4>::Add();
|
||||
k::Specialization<2,QVectorLayout::byNODES,P,2,2,6>::template Opt<2>::Add();
|
||||
k::Specialization<2,L,P,2,2,2>::template Opt<16>::Add();
|
||||
k::Specialization<2,L,P,2,2,3>::template Opt<8>::Add();
|
||||
k::Specialization<2,L,P,2,2,4>::template Opt<4>::Add();
|
||||
k::Specialization<2,L,P,2,2,5>::template Opt<4>::Add();
|
||||
k::Specialization<2,L,P,2,2,6>::template Opt<2>::Add();
|
||||
|
||||
k::Specialization<2,QVectorLayout::byNODES,P,2,3,3>::template Opt<2>::Add();
|
||||
k::Specialization<2,QVectorLayout::byNODES,P,2,3,4>::template Opt<4>::Add();
|
||||
k::Specialization<2,QVectorLayout::byNODES,P,2,4,3>::template Opt<4>::Add();
|
||||
k::Specialization<2,QVectorLayout::byNODES,P,2,3,6>::template Opt<2>::Add();
|
||||
k::Specialization<2,L,P,2,3,3>::template Opt<2>::Add();
|
||||
k::Specialization<2,L,P,2,3,4>::template Opt<4>::Add();
|
||||
k::Specialization<2,L,P,2,4,3>::template Opt<4>::Add();
|
||||
k::Specialization<2,L,P,2,3,6>::template Opt<2>::Add();
|
||||
|
||||
k::Specialization<2,QVectorLayout::byNODES,P,2,4,4>::template Opt<2>::Add();
|
||||
k::Specialization<2,QVectorLayout::byNODES,P,2,4,5>::template Opt<2>::Add();
|
||||
k::Specialization<2,QVectorLayout::byNODES,P,2,4,6>::template Opt<2>::Add();
|
||||
k::Specialization<2,QVectorLayout::byNODES,P,2,4,7>::template Opt<2>::Add();
|
||||
k::Specialization<2,L,P,2,4,4>::template Opt<2>::Add();
|
||||
k::Specialization<2,L,P,2,4,5>::template Opt<2>::Add();
|
||||
k::Specialization<2,L,P,2,4,6>::template Opt<2>::Add();
|
||||
k::Specialization<2,L,P,2,4,7>::template Opt<2>::Add();
|
||||
|
||||
k::Specialization<2,QVectorLayout::byNODES,P,2,5,6>::template Opt<2>::Add();
|
||||
k::Specialization<2,L,P,2,5,6>::template Opt<2>::Add();
|
||||
// 3D
|
||||
k::Specialization<3,QVectorLayout::byNODES,P,1,2,4>::template Opt<1>::Add();
|
||||
k::Specialization<3,QVectorLayout::byNODES,P,1,3,3>::template Opt<1>::Add();
|
||||
k::Specialization<3,QVectorLayout::byNODES,P,1,3,4>::template Opt<1>::Add();
|
||||
k::Specialization<3,QVectorLayout::byNODES,P,1,3,6>::template Opt<1>::Add();
|
||||
k::Specialization<3,QVectorLayout::byNODES,P,1,4,4>::template Opt<1>::Add();
|
||||
k::Specialization<3,QVectorLayout::byNODES,P,1,4,8>::template Opt<1>::Add();
|
||||
k::Specialization<3,L,P,1,2,4>::Add();
|
||||
k::Specialization<3,L,P,1,3,3>::Add();
|
||||
k::Specialization<3,L,P,1,3,4>::Add();
|
||||
k::Specialization<3,L,P,1,3,6>::Add();
|
||||
k::Specialization<3,L,P,1,4,4>::Add();
|
||||
k::Specialization<3,L,P,1,4,8>::Add();
|
||||
|
||||
k::Specialization<3,QVectorLayout::byNODES,P,3,2,3>::template Opt<1>::Add();
|
||||
k::Specialization<3,QVectorLayout::byNODES,P,3,2,4>::template Opt<1>::Add();
|
||||
k::Specialization<3,QVectorLayout::byNODES,P,3,2,5>::template Opt<1>::Add();
|
||||
k::Specialization<3,QVectorLayout::byNODES,P,3,2,6>::template Opt<1>::Add();
|
||||
k::Specialization<3,L,P,3,2,3>::Add();
|
||||
k::Specialization<3,L,P,3,2,4>::Add();
|
||||
k::Specialization<3,L,P,3,2,5>::Add();
|
||||
k::Specialization<3,L,P,3,2,6>::Add();
|
||||
|
||||
k::Specialization<3,QVectorLayout::byNODES,P,3,3,3>::template Opt<1>::Add();
|
||||
k::Specialization<3,QVectorLayout::byNODES,P,3,3,4>::template Opt<1>::Add();
|
||||
k::Specialization<3,QVectorLayout::byNODES,P,3,3,5>::template Opt<1>::Add();
|
||||
k::Specialization<3,QVectorLayout::byNODES,P,3,3,6>::template Opt<1>::Add();
|
||||
k::Specialization<3,QVectorLayout::byNODES,P,3,4,4>::template Opt<1>::Add();
|
||||
k::Specialization<3,QVectorLayout::byNODES,P,3,4,6>::template Opt<1>::Add();
|
||||
k::Specialization<3,QVectorLayout::byNODES,P,3,4,7>::template Opt<1>::Add();
|
||||
k::Specialization<3,QVectorLayout::byNODES,P,3,4,8>::template Opt<1>::Add();
|
||||
k::Specialization<3,L,P,3,3,3>::Add();
|
||||
k::Specialization<3,L,P,3,3,4>::Add();
|
||||
k::Specialization<3,L,P,3,3,5>::Add();
|
||||
k::Specialization<3,L,P,3,3,6>::Add();
|
||||
k::Specialization<3,L,P,3,4,4>::Add();
|
||||
k::Specialization<3,L,P,3,4,6>::Add();
|
||||
k::Specialization<3,L,P,3,4,7>::Add();
|
||||
k::Specialization<3,L,P,3,4,8>::Add();
|
||||
|
||||
using k2 = QuadratureInterpolator::CollocatedGradKernels;
|
||||
|
||||
// 2D
|
||||
k2::Specialization<2,L,P,1,2>::template Opt<16>::Add();
|
||||
k2::Specialization<2,L,P,1,3>::template Opt<16>::Add();
|
||||
k2::Specialization<2,L,P,1,4>::template Opt<16>::Add();
|
||||
k2::Specialization<2,L,P,2,2>::template Opt<16>::Add();
|
||||
k2::Specialization<2,L,P,2,3>::template Opt<4>::Add();
|
||||
k2::Specialization<2,L,P,2,4>::template Opt<2>::Add();
|
||||
|
||||
k2::Specialization<3,L,P,1,2>::Add();
|
||||
k2::Specialization<3,L,P,1,3>::Add();
|
||||
k2::Specialization<3,L,P,1,4>::Add();
|
||||
|
||||
k2::Specialization<3,L,P,2,2>::Add();
|
||||
k2::Specialization<3,L,P,2,3>::Add();
|
||||
k2::Specialization<3,L,P,2,4>::Add();
|
||||
|
||||
k2::Specialization<3,L,P,3,2>::Add();
|
||||
k2::Specialization<3,L,P,3,3>::Add();
|
||||
k2::Specialization<3,L,P,3,4>::Add();
|
||||
}
|
||||
|
||||
template void InitGradByNodesKernels<true>();
|
||||
|
||||
@@ -23,22 +23,46 @@ template <bool P>
|
||||
void InitGradByVDimKernels()
|
||||
{
|
||||
using k = QuadratureInterpolator::GradKernels;
|
||||
constexpr auto L = QVectorLayout::byVDIM;
|
||||
// 2D
|
||||
k::Specialization<2,QVectorLayout::byVDIM,P,1,3,4>::template Opt<8>::Add();
|
||||
k::Specialization<2,QVectorLayout::byVDIM,P,1,4,6>::template Opt<4>::Add();
|
||||
k::Specialization<2,QVectorLayout::byVDIM,P,1,5,8>::template Opt<2>::Add();
|
||||
k::Specialization<2,L,P,1,3,4>::template Opt<8>::Add();
|
||||
k::Specialization<2,L,P,1,4,6>::template Opt<4>::Add();
|
||||
k::Specialization<2,L,P,1,5,8>::template Opt<2>::Add();
|
||||
|
||||
k::Specialization<2,QVectorLayout::byVDIM,P,2,3,3>::template Opt<8>::Add();
|
||||
k::Specialization<2,QVectorLayout::byVDIM,P,2,3,4>::template Opt<8>::Add();
|
||||
k::Specialization<2,QVectorLayout::byVDIM,P,2,4,6>::template Opt<4>::Add();
|
||||
k::Specialization<2,QVectorLayout::byVDIM,P,2,5,8>::template Opt<2>::Add();
|
||||
k::Specialization<2,L,P,2,3,3>::template Opt<8>::Add();
|
||||
k::Specialization<2,L,P,2,3,4>::template Opt<8>::Add();
|
||||
k::Specialization<2,L,P,2,4,6>::template Opt<4>::Add();
|
||||
k::Specialization<2,L,P,2,5,8>::template Opt<2>::Add();
|
||||
// 3D
|
||||
k::Specialization<3,QVectorLayout::byVDIM,P,1,3,4>::template Opt<1>::Add();
|
||||
k::Specialization<3,QVectorLayout::byVDIM,P,1,4,6>::template Opt<1>::Add();
|
||||
k::Specialization<3,QVectorLayout::byVDIM,P,1,5,8>::template Opt<1>::Add();
|
||||
k::Specialization<3,QVectorLayout::byVDIM,P,3,3,4>::template Opt<1>::Add();
|
||||
k::Specialization<3,QVectorLayout::byVDIM,P,3,4,6>::template Opt<1>::Add();
|
||||
k::Specialization<3,QVectorLayout::byVDIM,P,3,5,8>::template Opt<1>::Add();
|
||||
k::Specialization<3,L,P,1,3,4>::Add();
|
||||
k::Specialization<3,L,P,1,4,6>::Add();
|
||||
k::Specialization<3,L,P,1,5,8>::Add();
|
||||
k::Specialization<3,L,P,3,3,4>::Add();
|
||||
k::Specialization<3,L,P,3,4,6>::Add();
|
||||
k::Specialization<3,L,P,3,5,8>::Add();
|
||||
|
||||
using k2 = QuadratureInterpolator::CollocatedGradKernels;
|
||||
// 2D
|
||||
k2::Specialization<2,L,P,1,2>::template Opt<16>::Add();
|
||||
k2::Specialization<2,L,P,1,3>::template Opt<16>::Add();
|
||||
k2::Specialization<2,L,P,1,4>::template Opt<16>::Add();
|
||||
|
||||
k2::Specialization<2,L,P,2,2>::template Opt<16>::Add();
|
||||
k2::Specialization<2,L,P,2,3>::template Opt<4>::Add();
|
||||
k2::Specialization<2,L,P,2,4>::template Opt<2>::Add();
|
||||
|
||||
// 3D
|
||||
k2::Specialization<3,L,P,1,2>::Add();
|
||||
k2::Specialization<3,L,P,1,3>::Add();
|
||||
k2::Specialization<3,L,P,1,4>::Add();
|
||||
|
||||
k2::Specialization<3,L,P,2,2>::Add();
|
||||
k2::Specialization<3,L,P,2,3>::Add();
|
||||
k2::Specialization<3,L,P,2,4>::Add();
|
||||
|
||||
k2::Specialization<3,L,P,3,2>::Add();
|
||||
k2::Specialization<3,L,P,3,3>::Add();
|
||||
k2::Specialization<3,L,P,3,4>::Add();
|
||||
}
|
||||
|
||||
template void InitGradByVDimKernels<true>();
|
||||
|
||||
+55
-24
@@ -30,26 +30,27 @@ void InitEvalKernels();
|
||||
void InitDetKernels();
|
||||
template <bool P> void InitGradByNodesKernels();
|
||||
template <bool P> void InitGradByVDimKernels();
|
||||
}
|
||||
}
|
||||
|
||||
QuadratureInterpolator::Kernels QuadratureInterpolator::kernels;
|
||||
QuadratureInterpolator::Kernels::Kernels()
|
||||
struct Kernels
|
||||
{
|
||||
using namespace internal::quadrature_interpolator;
|
||||
Kernels()
|
||||
{
|
||||
using namespace internal::quadrature_interpolator;
|
||||
|
||||
InitEvalByNodesKernels();
|
||||
InitEvalByVDimKernels();
|
||||
// Non-phys grad kernels
|
||||
InitGradByNodesKernels<false>();
|
||||
InitGradByVDimKernels<false>();
|
||||
// Phys grad kernels
|
||||
InitGradByNodesKernels<true>();
|
||||
InitGradByVDimKernels<true>();
|
||||
// Determinants
|
||||
InitDetKernels();
|
||||
// Non-tensor
|
||||
InitEvalKernels();
|
||||
InitEvalByNodesKernels();
|
||||
InitEvalByVDimKernels();
|
||||
// Non-phys grad kernels
|
||||
InitGradByNodesKernels<false>();
|
||||
InitGradByVDimKernels<false>();
|
||||
// Phys grad kernels
|
||||
InitGradByNodesKernels<true>();
|
||||
InitGradByVDimKernels<true>();
|
||||
// Determinants
|
||||
InitDetKernels();
|
||||
// Non-tensor
|
||||
InitEvalKernels();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
QuadratureInterpolator::QuadratureInterpolator(const FiniteElementSpace &fes,
|
||||
@@ -61,6 +62,8 @@ QuadratureInterpolator::QuadratureInterpolator(const FiniteElementSpace &fes,
|
||||
q_layout(QVectorLayout::byNODES),
|
||||
use_tensor_products(UsesTensorBasis(fes))
|
||||
{
|
||||
static internal::quadrature_interpolator::Kernels kernels;
|
||||
|
||||
d_buffer.UseDevice(true);
|
||||
if (fespace->GetNE() == 0) { return; }
|
||||
const FiniteElement *fe = fespace->GetFE(0);
|
||||
@@ -600,34 +603,55 @@ void QuadratureInterpolator::Determinants(const Vector &e_vec,
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
using namespace internal::quadrature_interpolator;
|
||||
|
||||
using EvalKernel = QuadratureInterpolator::EvalKernelType;
|
||||
using TensorEvalKernel = QuadratureInterpolator::TensorEvalKernelType;
|
||||
using GradKernel = QuadratureInterpolator::GradKernelType;
|
||||
using CollocatedGradKernel = QuadratureInterpolator::CollocatedGradKernelType;
|
||||
|
||||
template <QVectorLayout Q_LAYOUT>
|
||||
TensorEvalKernel FallbackTensorEvalKernel(int DIM)
|
||||
{
|
||||
if (DIM == 1) { return internal::quadrature_interpolator::Values1D<Q_LAYOUT>; }
|
||||
else if (DIM == 2) { return internal::quadrature_interpolator::Values2D<Q_LAYOUT>; }
|
||||
else if (DIM == 3) { return internal::quadrature_interpolator::Values3D<Q_LAYOUT>; }
|
||||
if (DIM == 1) { return Values1D<Q_LAYOUT>; }
|
||||
else if (DIM == 2) { return Values2D<Q_LAYOUT>; }
|
||||
else if (DIM == 3) { return Values3D<Q_LAYOUT>; }
|
||||
else { MFEM_ABORT(""); }
|
||||
}
|
||||
|
||||
template<QVectorLayout Q_LAYOUT, bool GRAD_PHYS>
|
||||
GradKernel GetGradKernel(int DIM)
|
||||
{
|
||||
if (DIM == 1) { return internal::quadrature_interpolator::Derivatives1D<Q_LAYOUT, GRAD_PHYS>; }
|
||||
else if (DIM == 2) { return internal::quadrature_interpolator::Derivatives2D<Q_LAYOUT, GRAD_PHYS>; }
|
||||
else if (DIM == 3) { return internal::quadrature_interpolator::Derivatives3D<Q_LAYOUT, GRAD_PHYS>; }
|
||||
if (DIM == 1) { return Derivatives1D<Q_LAYOUT, GRAD_PHYS>; }
|
||||
else if (DIM == 2) { return Derivatives2D<Q_LAYOUT, GRAD_PHYS>; }
|
||||
else if (DIM == 3) { return Derivatives3D<Q_LAYOUT, GRAD_PHYS>; }
|
||||
else { MFEM_ABORT(""); }
|
||||
}
|
||||
|
||||
|
||||
template<QVectorLayout Q_LAYOUT>
|
||||
GradKernel GetGradKernel(int DIM, bool GRAD_PHYS)
|
||||
{
|
||||
if (GRAD_PHYS) { return GetGradKernel<Q_LAYOUT, true>(DIM); }
|
||||
else { return GetGradKernel<Q_LAYOUT, false>(DIM); }
|
||||
}
|
||||
|
||||
template<QVectorLayout Q_LAYOUT, bool GRAD_PHYS>
|
||||
CollocatedGradKernel GetCollocatedGradKernel(int DIM)
|
||||
{
|
||||
if (DIM == 1) { return CollocatedDerivatives1D<Q_LAYOUT, GRAD_PHYS>; }
|
||||
else if (DIM == 2) { return CollocatedDerivatives2D<Q_LAYOUT, GRAD_PHYS>; }
|
||||
else if (DIM == 3) { return CollocatedDerivatives3D<Q_LAYOUT, GRAD_PHYS>; }
|
||||
else { MFEM_ABORT(""); }
|
||||
}
|
||||
|
||||
template<QVectorLayout Q_LAYOUT>
|
||||
CollocatedGradKernel GetCollocatedGradKernel(int DIM, bool GRAD_PHYS)
|
||||
{
|
||||
if (GRAD_PHYS) { return GetCollocatedGradKernel<Q_LAYOUT, true>(DIM); }
|
||||
else { return GetCollocatedGradKernel<Q_LAYOUT, false>(DIM); }
|
||||
}
|
||||
} // namespace
|
||||
|
||||
template <int DIM, int VDIM, int ND, int NQ>
|
||||
@@ -673,6 +697,13 @@ GradKernel QuadratureInterpolator::GradKernels::Fallback(
|
||||
else { return GetGradKernel<QVectorLayout::byVDIM>(DIM, GRAD_PHYS); }
|
||||
}
|
||||
|
||||
CollocatedGradKernel QuadratureInterpolator::CollocatedGradKernels::Fallback(
|
||||
int DIM, QVectorLayout Q_LAYOUT, bool GRAD_PHYS, int, int)
|
||||
{
|
||||
if (Q_LAYOUT == QVectorLayout::byNODES) { return GetCollocatedGradKernel<QVectorLayout::byNODES>(DIM, GRAD_PHYS); }
|
||||
else { return GetCollocatedGradKernel<QVectorLayout::byVDIM>(DIM, GRAD_PHYS); }
|
||||
}
|
||||
|
||||
/// @endcond
|
||||
|
||||
namespace internal
|
||||
|
||||
@@ -138,6 +138,10 @@ public:
|
||||
using GradKernelType = void(*)(const int, const real_t *, const real_t *,
|
||||
const real_t *, const real_t *, real_t *,
|
||||
const int, const int, const int, const int);
|
||||
using CollocatedGradKernelType = void(*)(const int, const real_t *,
|
||||
const real_t *, const real_t *,
|
||||
real_t *, const int, const int,
|
||||
const int);
|
||||
using DetKernelType = void(*)(const int NE, const real_t *, const real_t *,
|
||||
const real_t *, real_t *, const int, const int,
|
||||
Vector *);
|
||||
@@ -152,8 +156,8 @@ public:
|
||||
(int, QVectorLayout, bool, int, int, int), (int));
|
||||
MFEM_REGISTER_KERNELS(DetKernels, DetKernelType, (int, int, int, int));
|
||||
MFEM_REGISTER_KERNELS(EvalKernels, EvalKernelType, (int, int, int, int));
|
||||
|
||||
static struct Kernels { Kernels(); } kernels;
|
||||
MFEM_REGISTER_KERNELS(CollocatedGradKernels, CollocatedGradKernelType,
|
||||
(int, QVectorLayout, bool, int, int), (int));
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
+1
-1
@@ -1631,7 +1631,7 @@ void InterpolationManager::LinearizeInterpolatorMapIntoVector()
|
||||
const FiniteElement *trace_fe =
|
||||
fes.GetTraceElement(0, fes.GetMesh()->GetFaceGeometry(0));
|
||||
const int face_dofs = trace_fe->GetDof();
|
||||
const int nc_size = interp_map.size();
|
||||
const int nc_size = static_cast<int>(interp_map.size());
|
||||
MFEM_VERIFY(nc_cpt==nc_size, "Unexpected number of interpolators.");
|
||||
interpolators.SetSize(face_dofs*face_dofs*nc_size);
|
||||
auto d_interp = Reshape(interpolators.HostWrite(),face_dofs,face_dofs,nc_size);
|
||||
|
||||
+21
-8
@@ -1926,7 +1926,6 @@ void DiscreteAdaptTC::SetDiscreteTargetBase(const GridFunction &tspec_)
|
||||
{
|
||||
const int vdim = tspec_.FESpace()->GetVDim(),
|
||||
ndof = tspec_.FESpace()->GetNDofs();
|
||||
|
||||
ncomp += vdim;
|
||||
|
||||
// need to append data to tspec
|
||||
@@ -1950,7 +1949,7 @@ void DiscreteAdaptTC::SetTspecAtIndex(int idx, const GridFunction &tspec_)
|
||||
{
|
||||
const int vdim = tspec_.FESpace()->GetVDim(),
|
||||
ndof = tspec_.FESpace()->GetNDofs();
|
||||
MFEM_VERIFY(ndof == tspec.Size()/ncomp, "Inconsistency in SetTargetSpec.");
|
||||
MFEM_VERIFY(ndof == tspec.Size()/ncomp, "Inconsistency in SetTspecAtIndex.");
|
||||
|
||||
const auto tspec__d = tspec_.Read();
|
||||
auto tspec_d = tspec.ReadWrite();
|
||||
@@ -2698,16 +2697,18 @@ void DiscreteAdaptTC::ComputeElementTargetsGradient(const IntegrationRule &ir,
|
||||
Jtrcomp.Clear();
|
||||
}
|
||||
|
||||
void DiscreteAdaptTC:: UpdateGradientTargetSpecification(const Vector &x,
|
||||
const real_t dx,
|
||||
bool reuse_flag,
|
||||
int x_ordering)
|
||||
void DiscreteAdaptTC::
|
||||
UpdateGradientTargetSpecification(const Vector &x, real_t dx,
|
||||
bool reuse_flag, int x_ordering)
|
||||
{
|
||||
if (reuse_flag && good_tspec_grad) { return; }
|
||||
|
||||
const int dim = tspec_fesv->GetFE(0)->GetDim(),
|
||||
cnt = x.Size()/dim;
|
||||
|
||||
MFEM_VERIFY(tspec_fesv->GetVSize() / ncomp == cnt,
|
||||
"FD with discrete adaptivity assume mesh_order = field_order.");
|
||||
|
||||
tspec_pert1h.SetSize(x.Size()*ncomp);
|
||||
|
||||
Vector TSpecTemp;
|
||||
@@ -2734,16 +2735,18 @@ void DiscreteAdaptTC:: UpdateGradientTargetSpecification(const Vector &x,
|
||||
}
|
||||
|
||||
void DiscreteAdaptTC::
|
||||
UpdateHessianTargetSpecification(const Vector &x,real_t dx,
|
||||
UpdateHessianTargetSpecification(const Vector &x, real_t dx,
|
||||
bool reuse_flag, int x_ordering)
|
||||
{
|
||||
|
||||
if (reuse_flag && good_tspec_hess) { return; }
|
||||
|
||||
const int dim = tspec_fesv->GetFE(0)->GetDim(),
|
||||
cnt = x.Size()/dim,
|
||||
totmix = 1+2*(dim-2);
|
||||
|
||||
MFEM_VERIFY(tspec_fesv->GetVSize() / ncomp == cnt,
|
||||
"FD with discrete adaptivity assume mesh_order = field_order.");
|
||||
|
||||
tspec_pert2h.SetSize(cnt*dim*ncomp);
|
||||
tspec_pertmix.SetSize(cnt*totmix*ncomp);
|
||||
|
||||
@@ -2909,6 +2912,11 @@ void TMOP_Integrator::EnableAdaptiveLimiting(const GridFunction &z0,
|
||||
Coefficient &coeff,
|
||||
AdaptivityEvaluator &ae)
|
||||
{
|
||||
const char* gf_fe_name = z0.FESpace()->FEColl()->Name();
|
||||
const char* mesh_fe_name =
|
||||
z0.FESpace()->GetMesh()->GetNodalFESpace()->FEColl()->Name();
|
||||
MFEM_VERIFY(strcmp(gf_fe_name, mesh_fe_name) == 0,
|
||||
"Incompatible FE spaces for the adaptive limiting field.");
|
||||
adapt_lim_gf0 = &z0;
|
||||
delete adapt_lim_gf;
|
||||
adapt_lim_gf = new GridFunction(z0);
|
||||
@@ -2926,6 +2934,11 @@ void TMOP_Integrator::EnableAdaptiveLimiting(const ParGridFunction &z0,
|
||||
Coefficient &coeff,
|
||||
AdaptivityEvaluator &ae)
|
||||
{
|
||||
const char* gf_fe_name = z0.FESpace()->FEColl()->Name();
|
||||
const char* mesh_fe_name =
|
||||
z0.FESpace()->GetMesh()->GetNodalFESpace()->FEColl()->Name();
|
||||
MFEM_VERIFY(strcmp(gf_fe_name, mesh_fe_name) == 0,
|
||||
"Incompatible FE spaces for the adaptive limiting field.");
|
||||
adapt_lim_gf0 = &z0;
|
||||
adapt_lim_pgf0 = &z0;
|
||||
delete adapt_lim_gf;
|
||||
|
||||
+69
-11
@@ -118,7 +118,7 @@ void AdvectorCG::ComputeAtNewPositionScalar(const Vector &new_nodes,
|
||||
h_min = std::min(h_min, m->GetElementSize(i));
|
||||
}
|
||||
real_t v_max = 0.0;
|
||||
const int s = new_field.Size();
|
||||
const int s = u.Size()/m->Dimension();
|
||||
|
||||
u.HostReadWrite();
|
||||
for (int i = 0; i < s; i++)
|
||||
@@ -181,7 +181,7 @@ void AdvectorCG::ComputeAtNewPositionScalar(const Vector &new_nodes,
|
||||
|
||||
// Trim the overshoots and undershoots.
|
||||
new_field.HostReadWrite();
|
||||
for (int i = 0; i < s; i++)
|
||||
for (int i = 0; i < new_field.Size(); i++)
|
||||
{
|
||||
if (new_field(i) < glob_minv) { new_field(i) = glob_minv; }
|
||||
if (new_field(i) > glob_maxv) { new_field(i) = glob_maxv; }
|
||||
@@ -348,8 +348,10 @@ void InterpolatorFP::SetInitialField(const Vector &init_nodes,
|
||||
{
|
||||
nodes0 = init_nodes;
|
||||
Mesh *m = mesh;
|
||||
FiniteElementSpace *f = fes;
|
||||
#ifdef MFEM_USE_MPI
|
||||
if (pmesh) { m = pmesh; }
|
||||
if (pfes) { f = pfes; }
|
||||
#endif
|
||||
m->SetNodes(nodes0);
|
||||
|
||||
@@ -363,14 +365,9 @@ void InterpolatorFP::SetInitialField(const Vector &init_nodes,
|
||||
delete finder;
|
||||
}
|
||||
|
||||
FiniteElementSpace *f = fes;
|
||||
#ifdef MFEM_USE_MPI
|
||||
if (pfes)
|
||||
{
|
||||
f = pfes;
|
||||
finder = new FindPointsGSLIB(pfes->GetComm());
|
||||
}
|
||||
else { finder = new FindPointsGSLIB(); }
|
||||
if (pfes) { finder = new FindPointsGSLIB(pfes->GetComm()); }
|
||||
else { finder = new FindPointsGSLIB(); }
|
||||
#else
|
||||
finder = new FindPointsGSLIB();
|
||||
#endif
|
||||
@@ -378,13 +375,74 @@ void InterpolatorFP::SetInitialField(const Vector &init_nodes,
|
||||
|
||||
field0_gf.SetSpace(f);
|
||||
field0_gf = init_field;
|
||||
|
||||
// Check if the mesh nodes and the field nodes coincide.
|
||||
const bool nodes_mismatch = init_nodes.Size() / m->Dimension() !=
|
||||
field0_gf.Size() / f->GetVDim();
|
||||
if (nodes_mismatch)
|
||||
{
|
||||
delete fes_field_nodes;
|
||||
fes_field_nodes = new FiniteElementSpace(m, f->FEColl(), m->Dimension());
|
||||
}
|
||||
}
|
||||
|
||||
void InterpolatorFP::ComputeAtNewPosition(const Vector &new_nodes,
|
||||
Vector &new_field,
|
||||
int new_nodes_ordering)
|
||||
{
|
||||
finder->Interpolate(new_nodes, field0_gf, new_field, new_nodes_ordering);
|
||||
// Get physical node locations corresponding to field0_gf
|
||||
if (fes_field_nodes)
|
||||
{
|
||||
Vector mapped_nodes;
|
||||
GetFieldNodesPosition(new_nodes, mapped_nodes);
|
||||
finder->Interpolate(mapped_nodes, field0_gf, new_field,
|
||||
fes_field_nodes->GetOrdering());
|
||||
}
|
||||
else
|
||||
{
|
||||
finder->Interpolate(new_nodes, field0_gf, new_field, new_nodes_ordering);
|
||||
}
|
||||
}
|
||||
|
||||
void InterpolatorFP::GetFieldNodesPosition(const Vector &mesh_nodes,
|
||||
Vector &nodes_pos) const
|
||||
{
|
||||
MFEM_VERIFY(fes_field_nodes, "InterpolatorFP: fes_field_nodes is not set.");
|
||||
|
||||
Mesh *m = fes_field_nodes->GetMesh();
|
||||
const int nelem = fes_field_nodes->GetNE();
|
||||
const int n_f_nodes = fes_field_nodes->GetNDofs();
|
||||
const int dim = m->Dimension();
|
||||
if (nelem == 0) { return; }
|
||||
Array<int> dofs;
|
||||
Vector e_xyz;
|
||||
nodes_pos.SetSize(n_f_nodes*dim);
|
||||
const FiniteElementSpace *mesh_fes = m->GetNodalFESpace();
|
||||
|
||||
for (int e = 0; e < nelem; e++)
|
||||
{
|
||||
mesh_fes->GetElementVDofs(e, dofs);
|
||||
int n_mdofs = dofs.Size()/dim;
|
||||
mesh_nodes.GetSubVector(dofs, e_xyz); //e_xyz is ordered by nodes here
|
||||
const FiniteElement *mfe = mesh_fes->GetFE(e);
|
||||
Vector shape(n_mdofs);
|
||||
|
||||
auto ir = fes_field_nodes->GetFE(e)->GetNodes();
|
||||
const int n_gf_pts = ir.GetNPoints();
|
||||
Vector gf_xyz(n_gf_pts*dim);
|
||||
for (int q = 0; q < n_gf_pts; q++)
|
||||
{
|
||||
IntegrationPoint ip = ir.IntPoint(q);
|
||||
mfe->CalcShape(ip, shape);
|
||||
for (int d = 0; d < dim; d++)
|
||||
{
|
||||
Vector x(e_xyz.GetData() + d*n_mdofs, n_mdofs);
|
||||
gf_xyz(d*n_gf_pts + q) = x*shape; // order by nodes
|
||||
}
|
||||
}
|
||||
fes_field_nodes->GetElementVDofs(e, dofs);
|
||||
nodes_pos.SetSubVector(dofs, gf_xyz);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -437,7 +495,7 @@ real_t TMOPNewtonSolver::ComputeScalingFactor(const Vector &x,
|
||||
// Check for convergence
|
||||
if (init_fit_max_err < surf_fit_max_err_limit)
|
||||
{
|
||||
if (print_options.iterations)
|
||||
if (print_options.iterations || print_options.warnings)
|
||||
{
|
||||
mfem::out << "TMOPNewtonSolver converged "
|
||||
"based on the surface fitting error.\n";
|
||||
|
||||
+8
-1
@@ -58,8 +58,14 @@ private:
|
||||
Vector nodes0;
|
||||
GridFunction field0_gf;
|
||||
FindPointsGSLIB *finder;
|
||||
// FE space for the nodes of the solution GridFunction.
|
||||
FiniteElementSpace *fes_field_nodes;
|
||||
|
||||
void GetFieldNodesPosition(const Vector &mesh_nodes,
|
||||
Vector &nodes_pos) const;
|
||||
|
||||
public:
|
||||
InterpolatorFP() : finder(NULL) { }
|
||||
InterpolatorFP() : finder(NULL), fes_field_nodes(NULL) { }
|
||||
|
||||
void SetInitialField(const Vector &init_nodes,
|
||||
const Vector &init_field) override;
|
||||
@@ -77,6 +83,7 @@ public:
|
||||
{
|
||||
finder->FreeData();
|
||||
delete finder;
|
||||
delete fes_field_nodes;
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
+916
-40
File diff suppressed because it is too large
Load Diff
+156
-19
@@ -40,6 +40,10 @@ protected:
|
||||
OperatorHandle fw_t_oper; ///< Forward true-dof operator
|
||||
OperatorHandle bw_t_oper; ///< Backward true-dof operator
|
||||
|
||||
bool use_ea;
|
||||
|
||||
MemoryType d_mt;
|
||||
|
||||
#ifdef MFEM_USE_MPI
|
||||
bool parallel;
|
||||
#endif
|
||||
@@ -59,14 +63,23 @@ protected:
|
||||
|
||||
public:
|
||||
/** Construct a transfer algorithm between the domain, @a dom_fes_, and
|
||||
range, @a ran_fes_, FE spaces. */
|
||||
GridTransfer(FiniteElementSpace &dom_fes_, FiniteElementSpace &ran_fes_);
|
||||
range, @a ran_fes_, FE spaces, d_mt_ will specify memory space for
|
||||
large data structures */
|
||||
GridTransfer(FiniteElementSpace &dom_fes_,
|
||||
FiniteElementSpace &ran_fes_);
|
||||
|
||||
/// Virtual destructor
|
||||
virtual ~GridTransfer() { }
|
||||
|
||||
/** Uses device friendly element assembly versions for L2Projection
|
||||
transfers, L2, H1 FEM spaces currently supported */
|
||||
void UseEA(bool use_ea_) { use_ea = use_ea_;}
|
||||
|
||||
/** Set memory type for large data structures */
|
||||
void SetMemType(MemoryType d_mt_) {d_mt = d_mt_;}
|
||||
|
||||
/** @brief Set the desired Operator::Type for the construction of all
|
||||
operators defined by the underlying transfer algorithm. */
|
||||
operators defined by the underlying transfer algorithm. */
|
||||
/** The default value is Operator::ANY_TYPE which typically corresponds to a
|
||||
matrix-free operator representation. Note that derived classes are not
|
||||
required to support this setting and can ignore it. */
|
||||
@@ -169,7 +182,8 @@ public:
|
||||
smaller than the number of coarse dofs. */
|
||||
class L2ProjectionGridTransfer : public GridTransfer
|
||||
{
|
||||
protected:
|
||||
// Must be public due to host device lambdas
|
||||
public:
|
||||
/** Abstract class representing projection operator between a high-order
|
||||
finite element space on a coarse mesh, and a low-order finite element
|
||||
space on a refined mesh (LOR). We assume that the low-order space,
|
||||
@@ -194,10 +208,13 @@ protected:
|
||||
const FiniteElementSpace& fes_ho;
|
||||
const FiniteElementSpace& fes_lor;
|
||||
|
||||
MemoryType d_mt;
|
||||
Array<int> offsets;
|
||||
Table ho2lor;
|
||||
|
||||
L2Projection(const FiniteElementSpace& fes_ho_,
|
||||
const FiniteElementSpace& fes_lor_);
|
||||
const FiniteElementSpace& fes_lor_,
|
||||
MemoryType d_mt_ = Device::GetHostMemoryType());
|
||||
|
||||
void BuildHo2Lor(int nel_ho, int nel_lor,
|
||||
const CoarseFineTransformations& cf_tr);
|
||||
@@ -207,6 +224,50 @@ protected:
|
||||
ElementTransformation* tr_lor,
|
||||
IntegrationPointTransformation& ip_tr,
|
||||
DenseMatrix& M_mixed_el) const;
|
||||
|
||||
void ElemMixedMass(Geometry::Type geom, const FiniteElement& fe_ho,
|
||||
const FiniteElement& fe_lor,
|
||||
ElementTransformation* el_tr,
|
||||
IntegrationPointTransformation& ip_tr,
|
||||
DenseMatrix& B_L, DenseMatrix& B_H) const;
|
||||
public:
|
||||
/* Returns the Mixed Mass M_LH via device element assembly by building the
|
||||
basis functions and data at the quadrature points. */
|
||||
void MixedMassEA(const FiniteElementSpace& fes_ho_,
|
||||
const FiniteElementSpace& fes_lor_,
|
||||
Vector &M_LH,
|
||||
MemoryType d_mt_ = Device::GetHostMemoryType());
|
||||
};
|
||||
|
||||
// Class below must be public as we now have device code
|
||||
public:
|
||||
class H1SpaceMixedMassOperator : public Operator
|
||||
{
|
||||
protected:
|
||||
const FiniteElementSpace* fes_ho;
|
||||
const FiniteElementSpace* fes_lor;
|
||||
Table* ho2lor;
|
||||
Vector* M_LH_ea;
|
||||
public:
|
||||
H1SpaceMixedMassOperator(const FiniteElementSpace* fes_ho_,
|
||||
const FiniteElementSpace* fes_lor_,
|
||||
Table* ho2lor_, Vector* M_LH_ea_);
|
||||
void Mult(const Vector& x, Vector& y) const;
|
||||
void MultTranspose(const Vector& x, Vector& y) const;
|
||||
};
|
||||
|
||||
class H1SpaceLumpedMassOperator : public Operator
|
||||
{
|
||||
protected:
|
||||
const FiniteElementSpace* fes_ho;
|
||||
const FiniteElementSpace* fes_lor;
|
||||
Vector* ML_inv; // inverse of lumped M_L
|
||||
public:
|
||||
H1SpaceLumpedMassOperator(const FiniteElementSpace* fes_ho_,
|
||||
const FiniteElementSpace* fes_lor_,
|
||||
Vector& ML_inv_);
|
||||
void Mult(const Vector& x, Vector& y) const;
|
||||
void MultTranspose(const Vector& x, Vector& y) const;
|
||||
};
|
||||
|
||||
/** Class for projection operator between a L2 high-order finite element
|
||||
@@ -214,17 +275,24 @@ protected:
|
||||
refined mesh (LOR). */
|
||||
class L2ProjectionL2Space : public L2Projection
|
||||
{
|
||||
// The restriction and prolongation operators are represented as dense
|
||||
// elementwise matrices (of potentially different sizes, because of mixed
|
||||
// meshes or p-refinement). The matrix entries are stored in the R and P
|
||||
// arrays. The entries of the i'th high-order element are stored at the
|
||||
// index given by offsets[i].
|
||||
/// The restriction and prolongation operators are represented as dense
|
||||
/// elementwise matrices (of potentially different sizes, because of mixed
|
||||
/// meshes or p-refinement). The matrix entries are stored in the R and P
|
||||
/// arrays. The entries of the i'th high-order element are stored at the
|
||||
/// index given by offsets[i].
|
||||
mutable Array<real_t> R, P;
|
||||
Array<int> offsets;
|
||||
|
||||
const bool use_ea;
|
||||
|
||||
public:
|
||||
L2ProjectionL2Space(const FiniteElementSpace& fes_ho_,
|
||||
const FiniteElementSpace& fes_lor_);
|
||||
const FiniteElementSpace& fes_lor_,
|
||||
const bool use_ea_,
|
||||
MemoryType d_mt_ = Device::GetHostMemoryType());
|
||||
|
||||
/*Same as above but assembles and stores R_ea, P_ea */
|
||||
void EAL2ProjectionL2Space();
|
||||
|
||||
/// Maps <tt>x</tt>, primal field coefficients defined on a coarse mesh
|
||||
/// with a higher order L2 finite element space, to <tt>y</tt>, primal
|
||||
/// field coefficients defined on a refined mesh with a low order L2
|
||||
@@ -232,6 +300,10 @@ protected:
|
||||
/// the coarse mesh. Coefficients are computed through minimization of L2
|
||||
/// error between the fields.
|
||||
void Mult(const Vector& x, Vector& y) const override;
|
||||
|
||||
/// Perform mult on the device (same as above)
|
||||
void EAMult(const Vector& x, Vector& y) const;
|
||||
|
||||
/// Maps <tt>x</tt>, dual field coefficients defined on a refined mesh
|
||||
/// with a low order L2 finite element space, to <tt>y</tt>, dual field
|
||||
/// coefficients defined on a coarse mesh with a higher order L2 finite
|
||||
@@ -240,6 +312,9 @@ protected:
|
||||
/// error between the primal fields. Note, if the <tt>x</tt>-coefficients
|
||||
/// come from ProlongateTranspose, then mass is conserved.
|
||||
void MultTranspose(const Vector& x, Vector& y) const override;
|
||||
|
||||
void EAMultTranspose(const Vector& x, Vector& y) const;
|
||||
|
||||
/// Maps <tt>x</tt>, primal field coefficients defined on a refined mesh
|
||||
/// with a low order L2 finite element space, to <tt>y</tt>, primal field
|
||||
/// coefficients defined on a coarse mesh with a higher order L2 finite
|
||||
@@ -248,6 +323,9 @@ protected:
|
||||
/// left-inverse prolongation operation. This functionality is also
|
||||
/// provided as an Operator by L2Prolongation.
|
||||
void Prolongate(const Vector& x, Vector& y) const override;
|
||||
|
||||
void EAProlongate(const Vector& x, Vector& y) const;
|
||||
|
||||
/// Maps <tt>x</tt>, dual field coefficients defined on a coarse mesh with
|
||||
/// a higher order L2 finite element space, to <tt>y</tt>, dual field
|
||||
/// coefficients defined on a refined mesh with a low order L2 finite
|
||||
@@ -256,21 +334,46 @@ protected:
|
||||
/// conservative left-inverse prolongation operation. This functionality
|
||||
/// is also provided as an Operator by L2Prolongation.
|
||||
void ProlongateTranspose(const Vector& x, Vector& y) const override;
|
||||
|
||||
void EAProlongateTranspose(const Vector& x, Vector& y) const;
|
||||
|
||||
void SetRelTol(real_t p_rtol_) override { } ///< No-op.
|
||||
void SetAbsTol(real_t p_atol_) override { } ///< No-op.
|
||||
};
|
||||
|
||||
protected:
|
||||
|
||||
/// Class below must be public as we now have device code
|
||||
public:
|
||||
|
||||
/** Projection operator between a H1 high-order finite element space on a
|
||||
coarse mesh, and a H1 low-order finite element space on a refined mesh
|
||||
(LOR). */
|
||||
class L2ProjectionH1Space : public L2Projection
|
||||
{
|
||||
const bool use_ea;
|
||||
|
||||
public:
|
||||
L2ProjectionH1Space(const FiniteElementSpace &fes_ho_,
|
||||
const FiniteElementSpace &fes_lor_);
|
||||
const FiniteElementSpace &fes_lor_,
|
||||
const bool use_ea_,
|
||||
MemoryType d_mt_ = Device::GetHostMemoryType());
|
||||
#ifdef MFEM_USE_MPI
|
||||
L2ProjectionH1Space(const ParFiniteElementSpace &pfes_ho_,
|
||||
const ParFiniteElementSpace &pfes_lor_);
|
||||
const ParFiniteElementSpace &pfes_lor_,
|
||||
const bool use_ea_,
|
||||
MemoryType d_mt_ = Device::GetHostMemoryType());
|
||||
#endif
|
||||
/// Same as above but assembles action of R through 4 parts:
|
||||
/// ( ) inv( lumped(M_L) ), which is a diagonal matrix (essentially a vector)
|
||||
/// ( ) ElementRestrictionOperator for LOR space
|
||||
/// ( ) mixed mass matrix M_{LH}
|
||||
/// ( ) ElementRestrictionOperator for HO space
|
||||
void EAL2ProjectionH1Space();
|
||||
|
||||
#ifdef MFEM_USE_MPI
|
||||
void EAL2ProjectionH1Space(const ParFiniteElementSpace &pfes_ho_,
|
||||
const ParFiniteElementSpace &pfes_lor_);
|
||||
#endif
|
||||
/// Maps <tt>x</tt>, primal field coefficients defined on a coarse mesh
|
||||
/// with a higher order H1 finite element space, to <tt>y</tt>, primal
|
||||
@@ -279,6 +382,7 @@ protected:
|
||||
/// the coarse mesh. Coefficients are computed through minimization of L2
|
||||
/// error between the fields.
|
||||
void Mult(const Vector& x, Vector& y) const override;
|
||||
|
||||
/// Maps <tt>x</tt>, dual field coefficients defined on a refined mesh
|
||||
/// with a low order H1 finite element space, to <tt>y</tt>, dual field
|
||||
/// coefficients defined on a coarse mesh with a higher order H1 finite
|
||||
@@ -287,6 +391,7 @@ protected:
|
||||
/// error between the primal fields. Note, if the <tt>x</tt>-coefficients
|
||||
/// come from ProlongateTranspose, then mass is conserved.
|
||||
void MultTranspose(const Vector& x, Vector& y) const override;
|
||||
|
||||
/// Maps <tt>x</tt>, primal field coefficients defined on a refined mesh
|
||||
/// with a low order H1 finite element space, to <tt>y</tt>, primal field
|
||||
/// coefficients defined on a coarse mesh with a higher order H1 finite
|
||||
@@ -295,6 +400,7 @@ protected:
|
||||
/// left-inverse prolongation operation. This functionality is also
|
||||
/// provided as an Operator by L2Prolongation.
|
||||
void Prolongate(const Vector& x, Vector& y) const override;
|
||||
|
||||
/// Maps <tt>x</tt>, dual field coefficients defined on a coarse mesh with
|
||||
/// a higher order H1 finite element space, to <tt>y</tt>, dual field
|
||||
/// coefficients defined on a refined mesh with a low order H1 finite
|
||||
@@ -303,14 +409,22 @@ protected:
|
||||
/// conservative left-inverse prolongation operation. This functionality
|
||||
/// is also provided as an Operator by L2Prolongation.
|
||||
void ProlongateTranspose(const Vector& x, Vector& y) const override;
|
||||
|
||||
/// Returns the inverse of an on-rank lumped mass matrix
|
||||
void LumpedMassInverse(Vector& ML_inv) const;
|
||||
|
||||
void SetRelTol(real_t p_rtol_) override;
|
||||
void SetAbsTol(real_t p_atol_) override;
|
||||
|
||||
protected:
|
||||
/// Sets up the PCG solver (sets parameters, operator, and preconditioner)
|
||||
void SetupPCG();
|
||||
/// Computes on-rank R and M_LH matrices.
|
||||
|
||||
/// @brief Computes on-rank R and M_LH matrices. If true, computes mixed mass and/or
|
||||
/// inverse lumped mass matrix error when compared to device implementation.
|
||||
std::pair<std::unique_ptr<SparseMatrix>,
|
||||
std::unique_ptr<SparseMatrix>> ComputeSparseRAndM_LH();
|
||||
|
||||
/// @brief Recovers vector of tdofs given a vector of dofs and a finite
|
||||
/// element space
|
||||
void GetTDofs(const FiniteElementSpace& fes, const Vector& x, Vector& X) const;
|
||||
@@ -333,10 +447,8 @@ protected:
|
||||
void TDofsListByVDim(const FiniteElementSpace& fes,
|
||||
int vdim,
|
||||
Array<int>& vdofs_list) const;
|
||||
/// Returns the inverse of an on-rank lumped mass matrix
|
||||
void LumpedMassInverse(Vector& ML_inv) const;
|
||||
|
||||
/// @brief Computes sparsity pattern and initializes R matrix.
|
||||
///
|
||||
/// Based on BilinearForm::AllocMat(), except maps between coarse HO
|
||||
/// elements and refined LOR elements.
|
||||
std::unique_ptr<SparseMatrix> AllocR();
|
||||
@@ -346,10 +458,34 @@ protected:
|
||||
// The restriction operator is represented as an Operator R. The
|
||||
// prolongation operator is a dense matrix computed as the inverse of (R^T
|
||||
// M_L R), and hence, is not stored.
|
||||
// If element assembly is enabled
|
||||
std::unique_ptr<Operator> R;
|
||||
// Used to compute P = (RT*M_LH)^(-1) M_LH^T
|
||||
std::unique_ptr<Operator> M_LH;
|
||||
// Inverted operator in P = (RT*M_LH)^(-1) M_LH^T. Used to compute P via PCG.
|
||||
std::unique_ptr<Operator> RTxM_LH;
|
||||
// Lumped M_L inverse operator built via EA. Wrapped with restriction maps
|
||||
// to multiply with scalar TDof LOR vectors.
|
||||
std::unique_ptr<Operator> ML_inv_vea;
|
||||
// LDof Mixed mass operator built via EA. Wrapped with restrition maps to send
|
||||
// scalar LDof HO vectors to LDof LOR vectors.
|
||||
Operator *M_LH_local_op;
|
||||
|
||||
// Scalar finite element spaces for stored Tdof-to-and-from-LDof maps.
|
||||
std::unique_ptr<FiniteElementSpace> fes_ho_scalar;
|
||||
std::unique_ptr<FiniteElementSpace> fes_lor_scalar;
|
||||
// Element Assembled mixed mass
|
||||
Vector M_LH_ea;
|
||||
// Element Assembled lumped M_L inverse built via EA. Stores diagonal as a Ldof vector.
|
||||
Vector ML_inv_ea;
|
||||
|
||||
#ifdef MFEM_USE_MPI
|
||||
std::unique_ptr<ParFiniteElementSpace> pfes_ho_scalar;
|
||||
std::unique_ptr<ParFiniteElementSpace> pfes_lor_scalar;
|
||||
Vector RML_inv;
|
||||
#endif
|
||||
|
||||
friend class L2ProjectionL2Space;
|
||||
};
|
||||
|
||||
/** Mass-conservative prolongation operator going in the opposite direction
|
||||
@@ -379,7 +515,8 @@ protected:
|
||||
public:
|
||||
L2ProjectionGridTransfer(FiniteElementSpace &coarse_fes_,
|
||||
FiniteElementSpace &fine_fes_,
|
||||
bool force_l2_space_ = false)
|
||||
bool force_l2_space_ = false,
|
||||
MemoryType d_mt_ = Device::GetHostMemoryType()) //move to method
|
||||
: GridTransfer(coarse_fes_, fine_fes_),
|
||||
F(NULL), B(NULL), force_l2_space(force_l2_space_)
|
||||
{ }
|
||||
|
||||
@@ -45,6 +45,7 @@ list(APPEND HDRS
|
||||
gecko.hpp
|
||||
globals.hpp
|
||||
zstr.hpp
|
||||
handle.hpp
|
||||
hash.hpp
|
||||
isockstream.hpp
|
||||
kdtree.hpp
|
||||
|
||||
+1
-1
@@ -112,7 +112,7 @@ void Array<T>::PartialSum()
|
||||
|
||||
// Sum
|
||||
template <class T>
|
||||
T Array<T>::Sum()
|
||||
T Array<T>::Sum() const
|
||||
{
|
||||
T sum = static_cast<T>(0);
|
||||
for (int i = 0; i < size; i++)
|
||||
|
||||
+71
-10
@@ -23,6 +23,7 @@
|
||||
#include <cstring>
|
||||
#include <algorithm>
|
||||
#include <type_traits>
|
||||
#include <initializer_list>
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
@@ -52,10 +53,7 @@ protected:
|
||||
|
||||
inline void GrowSize(int minsize);
|
||||
|
||||
static inline void TypeAssert()
|
||||
{
|
||||
static_assert(std::is_trivial<T>::value, "type T must be trivial");
|
||||
}
|
||||
static_assert(std::is_trivial<T>::value, "type T must be trivial");
|
||||
|
||||
public:
|
||||
friend void Swap<T>(Array<T> &, Array<T> &);
|
||||
@@ -91,15 +89,20 @@ public:
|
||||
template <typename CT>
|
||||
inline Array(const Array<CT> &src);
|
||||
|
||||
/// Deep copy from a braced init-list of convertible type
|
||||
/// Construct an Array from a C-style array of static length
|
||||
template <typename CT, int N>
|
||||
explicit inline Array(const CT (&values)[N]);
|
||||
|
||||
/// Construct an Array from a braced initializer list of convertible type
|
||||
template <typename CT, typename std::enable_if<
|
||||
std::is_convertible<CT,T>::value,bool>::type = true>
|
||||
explicit inline Array(std::initializer_list<CT> values);
|
||||
|
||||
/// Move constructor ("steals" data from 'src')
|
||||
inline Array(Array<T> &&src) { Swap(src, *this); }
|
||||
|
||||
/// Destructor
|
||||
inline ~Array() { TypeAssert(); data.Delete(); }
|
||||
inline ~Array() { data.Delete(); }
|
||||
|
||||
/// Assignment operator: deep copy from 'src'.
|
||||
Array<T> &operator=(const Array<T> &src) { src.Copy(*this); return *this; }
|
||||
@@ -204,6 +207,8 @@ public:
|
||||
/// Delete the whole array.
|
||||
inline void DeleteAll();
|
||||
|
||||
/// Reduces the capacity of the array to exactly match the current size.
|
||||
inline void ShrinkToFit();
|
||||
|
||||
/// Create a copy of the internal array to the provided @a copy.
|
||||
inline void Copy(Array ©) const;
|
||||
@@ -221,6 +226,18 @@ public:
|
||||
/// Make this Array a reference to 'master'.
|
||||
inline void MakeRef(const Array &master);
|
||||
|
||||
/**
|
||||
* @brief Permute the array using the provided indices. Sorts the indices
|
||||
* variable in the process, thereby destroying the permutation. The rvalue
|
||||
* reference is to be used when this destruction is allowed, whilst the const
|
||||
* reference preserves at the cost of duplication.
|
||||
*
|
||||
* @param indices The indices of the ordering. data[i] = data[indices[i]].
|
||||
*/
|
||||
template <typename I>
|
||||
inline void Permute(I &&indices);
|
||||
template <typename I>
|
||||
inline void Permute(const I &indices) { Permute(I(indices)); }
|
||||
|
||||
/// Copy sub array starting from @a offset out to the provided @a sa.
|
||||
inline void GetSubArray(int offset, int sa_size, Array<T> &sa) const;
|
||||
@@ -269,17 +286,20 @@ public:
|
||||
void Unique()
|
||||
{
|
||||
T* end = std::unique((T*)data, data + size);
|
||||
SetSize(end - data);
|
||||
SetSize((int)(end - data));
|
||||
}
|
||||
|
||||
/// Return 1 if the array is sorted from lowest to highest. Otherwise return 0.
|
||||
int IsSorted() const;
|
||||
|
||||
/// Does the Array have Size zero.
|
||||
bool IsEmpty() const { return Size() == 0; }
|
||||
|
||||
/// Fill the entries of the array with the cumulative sum of the entries.
|
||||
void PartialSum();
|
||||
|
||||
/// Return the sum of all the array entries using the '+'' operator for class 'T'.
|
||||
T Sum();
|
||||
T Sum() const;
|
||||
|
||||
/// Set all entries of the array to the provided constant.
|
||||
inline void operator=(const T &a);
|
||||
@@ -492,6 +512,8 @@ public:
|
||||
BlockArray(int block_size = 16*1024);
|
||||
BlockArray(const BlockArray<T> &other); // deep copy
|
||||
BlockArray& operator=(const BlockArray&) = delete; // not supported
|
||||
BlockArray(BlockArray<T> &&other) = default;
|
||||
BlockArray& operator=(BlockArray<T> &&other) = default;
|
||||
~BlockArray() { Destroy(); }
|
||||
|
||||
/// Allocate and construct a new item in the array, return its index.
|
||||
@@ -613,6 +635,8 @@ public:
|
||||
|
||||
iterator begin() { return size ? iterator(this) : iterator(true); }
|
||||
iterator end() { return iterator(); }
|
||||
const_iterator begin() const { return cbegin(); }
|
||||
const_iterator end() const { return cend(); }
|
||||
|
||||
const_iterator cbegin() const
|
||||
{ return size ? const_iterator(this) : const_iterator(true); }
|
||||
@@ -668,10 +692,18 @@ inline Array<T>::Array(const Array<CT> &src)
|
||||
for (int i = 0; i < size; i++) { (*this)[i] = T(src[i]); }
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
template <typename CT, typename std::enable_if<
|
||||
std::is_convertible<CT,T>::value,bool>::type>
|
||||
inline Array<T>::Array(std::initializer_list<CT> values) : Array(values.size())
|
||||
{
|
||||
std::copy(values.begin(), values.end(), begin());
|
||||
}
|
||||
|
||||
template <typename T> template <typename CT, int N>
|
||||
inline Array<T>::Array(const CT (&values)[N]) : Array(N)
|
||||
{
|
||||
for (int i = 0; i < size; i++) { (*this)[i] = T(values[i]); }
|
||||
std::copy(values, values + N, begin());
|
||||
}
|
||||
|
||||
template <class T>
|
||||
@@ -685,6 +717,35 @@ inline void Array<T>::GrowSize(int minsize)
|
||||
data = p;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void Array<T>::ShrinkToFit()
|
||||
{
|
||||
if (Capacity() == size) { return; }
|
||||
Memory<T> p(size, data.GetMemoryType());
|
||||
p.CopyFrom(data, size);
|
||||
p.UseDevice(data.UseDevice());
|
||||
data.Delete();
|
||||
data = p;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
template <typename I>
|
||||
inline void Array<T>::Permute(I &&indices)
|
||||
{
|
||||
for (int i = 0; i < size; i++)
|
||||
{
|
||||
auto current = i;
|
||||
while (i != indices[current])
|
||||
{
|
||||
auto next = indices[current];
|
||||
std::swap(data[current], data[next]);
|
||||
indices[current] = current;
|
||||
current = next;
|
||||
}
|
||||
indices[current] = current;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T> template <typename CT>
|
||||
inline Array<T> &Array<T>::operator=(const Array<CT> &src)
|
||||
{
|
||||
@@ -840,7 +901,7 @@ inline int Array<T>::FindSorted(const T &el) const
|
||||
const T *begin = data, *end = begin + size;
|
||||
const T* first = std::lower_bound(begin, end, el);
|
||||
if (first == end || !(*first == el)) { return -1; }
|
||||
return first - begin;
|
||||
return (int)(first - begin);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
|
||||
@@ -64,7 +64,7 @@ public:
|
||||
ArraysByName(ArraysByName &&src) noexcept = default;
|
||||
|
||||
/// Return the number of named arrays in the container
|
||||
int Size() const { return data.size(); }
|
||||
int Size() const { return static_cast<int>(data.size()); }
|
||||
|
||||
/// Return an STL set of strings giving the names of the arrays
|
||||
inline std::set<std::string> GetNames() const;
|
||||
|
||||
@@ -431,8 +431,8 @@ struct VarMessage
|
||||
void Isend(int rank, MPI_Comm comm)
|
||||
{
|
||||
Encode(rank);
|
||||
MPI_Isend((void*) data.data(), data.length(), MPI_BYTE, rank, Tag, comm,
|
||||
&send_request);
|
||||
MPI_Isend((void*) data.data(), static_cast<int>(data.length()), MPI_BYTE, rank,
|
||||
Tag, comm, &send_request);
|
||||
}
|
||||
|
||||
/** @brief Non-blocking synchronous send to processor 'rank'.
|
||||
@@ -441,8 +441,8 @@ struct VarMessage
|
||||
void Issend(int rank, MPI_Comm comm)
|
||||
{
|
||||
Encode(rank);
|
||||
MPI_Issend((void*) data.data(), data.length(), MPI_BYTE, rank, Tag, comm,
|
||||
&send_request);
|
||||
MPI_Issend((void*) data.data(), static_cast<int>(data.length()), MPI_BYTE, rank,
|
||||
Tag, comm, &send_request);
|
||||
}
|
||||
|
||||
/// Helper to send all messages in a rank-to-message map container.
|
||||
@@ -538,7 +538,7 @@ struct VarMessage
|
||||
template<typename MapT>
|
||||
static void RecvAll(MapT& rank_msg, MPI_Comm comm)
|
||||
{
|
||||
int recv_left = rank_msg.size();
|
||||
int recv_left = static_cast<int>(rank_msg.size());
|
||||
while (recv_left > 0)
|
||||
{
|
||||
int rank, size;
|
||||
|
||||
+12
-1
@@ -150,6 +150,9 @@ Device::Device()
|
||||
|
||||
Device::~Device()
|
||||
{
|
||||
#ifdef MFEM_USE_MPI
|
||||
Hypre::Finalize();
|
||||
#endif
|
||||
if ( device_env && !destroy_mm) { return; }
|
||||
if (!device_env && destroy_mm && !mem_host_env)
|
||||
{
|
||||
@@ -255,7 +258,15 @@ void Device::Configure(const std::string &device, const int device_id)
|
||||
destroy_mm = true;
|
||||
|
||||
#ifdef MFEM_USE_MPI
|
||||
Hypre::InitDevice();
|
||||
#if defined(HYPRE_USING_GPU) && (MFEM_HYPRE_VERSION >= 23100)
|
||||
// Skip the call to Hypre::InitDevice() if HYPRE is not initialized, e.g.
|
||||
// * if running a serial code
|
||||
// * if running with the environment variable MFEM_DEVICE set.
|
||||
if (HYPRE_Initialized())
|
||||
{
|
||||
Hypre::InitDevice();
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -838,6 +838,16 @@ inline void hypre_forall(int N, lambda &&body)
|
||||
#endif
|
||||
}
|
||||
|
||||
// Return the most general MemoryClass that can be used with mfem::hypre_forall
|
||||
// kernels. The returned MemoryClass is the same as the one returned by
|
||||
// GerHypreMemoryClass() except when hypre is configured to use UVM, in which
|
||||
// case this function returns MemoryClass::HOST or MemoryClass::DEVICE depending
|
||||
// on the result of HypreUsingGPU().
|
||||
inline MemoryClass GetHypreForallMemoryClass()
|
||||
{
|
||||
return HypreUsingGPU() ? MemoryClass::DEVICE : MemoryClass::HOST;
|
||||
}
|
||||
|
||||
#endif // MFEM_USE_MPI
|
||||
|
||||
} // namespace mfem
|
||||
|
||||
@@ -9,12 +9,17 @@
|
||||
// terms of the BSD-3 license. We welcome feedback and contributions, see file
|
||||
// CONTRIBUTING.md for details.
|
||||
|
||||
#ifdef _WIN32
|
||||
// Turn off CRT deprecation warnings for getenv
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
#endif
|
||||
|
||||
#include "../config/config.hpp"
|
||||
#include "globals.hpp"
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
#include <cstdlib> // getenv
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
@@ -71,4 +76,8 @@ void SetGlobalMPI_Comm(MPI_Comm comm)
|
||||
|
||||
#endif
|
||||
|
||||
const char* getenv(const char* name)
|
||||
{
|
||||
return ::getenv(name);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -107,6 +107,8 @@ void SetGlobalMPI_Comm(MPI_Comm comm);
|
||||
|
||||
#endif
|
||||
|
||||
const char* getenv(const char* name);
|
||||
|
||||
} // namespace mfem
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,200 @@
|
||||
// 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_HANDLE_HPP
|
||||
#define MFEM_HANDLE_HPP
|
||||
|
||||
#include "../config/config.hpp"
|
||||
#include <memory>
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
/// @brief A smart pointer class that may represent either shared ownership, or
|
||||
/// a non-owning borrow.
|
||||
///
|
||||
/// A Handle may either be owning or non-owning. Non-owning Handle%s point to
|
||||
/// externally owned data; it is the responsibility of the user both to ensure
|
||||
/// that the data remains valid as long as the Handle is alive and to delete the
|
||||
/// pointer when it is no longer needed. Owning Handle%s use <a
|
||||
/// href="https://en.cppreference.com/w/cpp/memory/shared_ptr">
|
||||
/// std::shared_ptr</a> to implement reference counting. The underlying data
|
||||
/// will be valid as long as there is at least one live copy. When the last
|
||||
/// Handle is destroyed, the pointer is deleted.
|
||||
///
|
||||
/// Both types of Handle%s can be copied, moved, stored in standard containers,
|
||||
/// etc.
|
||||
///
|
||||
/// A non-owning Handle may assume ownership over its data, but an owning Handle
|
||||
/// cannot release ownership over its data.
|
||||
///
|
||||
/// It is an invariant of this class that **at most** one of the data members
|
||||
/// @a not_owned and @a owned will be non-null.
|
||||
template <typename T>
|
||||
class Handle
|
||||
{
|
||||
/// If this is a non-owning handle, @a not_owned will point to the data.
|
||||
T *not_owned = nullptr;
|
||||
|
||||
/// If this is an owning handle, @a owned will point to the data.
|
||||
std::shared_ptr<T> owned = nullptr;
|
||||
|
||||
/// @brief Types @a Handle<T> and @a %Handle\<U\> are friends to allow
|
||||
/// construction of one from another when @a T and @a U are convertible
|
||||
/// types.
|
||||
template <typename U> friend class Handle;
|
||||
|
||||
public:
|
||||
/// Create an empty (null) Handle.
|
||||
Handle() = default;
|
||||
|
||||
/// @brief Create a Handle pointing to @a t.
|
||||
///
|
||||
/// If @a take_ownership is true, then the Handle assumes ownership over the
|
||||
/// pointer, and it should not be deleted externally. Otherwise, the Handle
|
||||
/// will be non-owning, and it is the user's responsibility to ensure the
|
||||
/// correct lifetime of @a t.
|
||||
Handle(T *t, bool take_ownership)
|
||||
{
|
||||
if (take_ownership) { owned.reset(t); }
|
||||
else { not_owned = t; }
|
||||
}
|
||||
|
||||
/// Create a Handle from a std::shared_ptr (sharing ownership with @a t).
|
||||
Handle(const std::shared_ptr<T> &t) : owned(t) { }
|
||||
|
||||
/// @brief Copy constructor.
|
||||
///
|
||||
/// Copying an owning Handle results in another owning handle. Copying a
|
||||
/// non-owning handle results in a non-owning handle.
|
||||
Handle(const Handle &other) = default;
|
||||
|
||||
/// Move constructor (see Handle(const Handle&)).
|
||||
Handle(Handle &&other) = default;
|
||||
|
||||
/// @brief Constructs a copy of @a u, where type @a U is convertible to @a T.
|
||||
///
|
||||
/// This allows the construction of Handle<Base> from Handle<Derived>.
|
||||
template <typename U>
|
||||
Handle(const Handle<U> &u) : not_owned(u.not_owned), owned(u.owned) { }
|
||||
|
||||
/// @brief Move-constructs from @a u, where type @a U is convertible to @a T.
|
||||
///
|
||||
/// See @ref Handle(const Handle<U>&).
|
||||
template <typename U>
|
||||
Handle(Handle<U> &&u) : not_owned(u.not_owned), owned(u.owned) { }
|
||||
|
||||
/// Destructor. If the Handle is owning, decrement the reference count.
|
||||
~Handle() = default;
|
||||
|
||||
/// Copy assignment (see Handle(const Handle&)).
|
||||
Handle &operator=(const Handle &other) = default;
|
||||
|
||||
/// Move assignment (see Handle(const Handle&)).
|
||||
Handle &operator=(Handle &&other) = default;
|
||||
|
||||
/// Returns the contained pointer (may be null).
|
||||
T *Get() const
|
||||
{
|
||||
if (not_owned) { return not_owned; }
|
||||
else { return owned.get(); }
|
||||
}
|
||||
|
||||
/// @brief If the Handle is owning, return a copy of the underlying shared
|
||||
/// pointer.
|
||||
///
|
||||
/// @warning If the Handle is non-owning (even if non-null), this will return
|
||||
/// and empty (null) shared pointer.
|
||||
std::shared_ptr<T> GetSharedPtr() const { return owned; }
|
||||
|
||||
/// Dereference operator. The Handle must be non-null.
|
||||
T &operator*() const { return *Get(); }
|
||||
|
||||
/// Member access (arrow) operator. The Handle must be non-null.
|
||||
T *operator->() const { return Get(); }
|
||||
|
||||
/// @brief Returns true if the Handle is owning, false if it is non-owning.
|
||||
///
|
||||
/// Returns false if the Handle is null (empty).
|
||||
bool IsOwner() const { return owned; }
|
||||
|
||||
/// Returns true if the Handle is non-null.
|
||||
explicit operator bool() const { return not_owned || owned; }
|
||||
|
||||
/// @brief Assume owernship of the data.
|
||||
///
|
||||
/// If the Handle is already owning, this does nothing.
|
||||
void MakeOwner()
|
||||
{
|
||||
if (owned) { return; }
|
||||
owned.reset(not_owned);
|
||||
not_owned = nullptr;
|
||||
}
|
||||
|
||||
/// @brief Reset the Handle to be empty.
|
||||
///
|
||||
/// If the Handle is owning, this will decrement the reference count.
|
||||
void Reset()
|
||||
{
|
||||
owned.reset();
|
||||
not_owned = nullptr;
|
||||
}
|
||||
|
||||
/// @brief Reset the Handle to point to @a t.
|
||||
///
|
||||
/// The Handle may assume ownership of the pointer according to @a
|
||||
/// take_ownership (see @ref Handle(T*, bool)).
|
||||
void Reset(T *t, bool take_ownership)
|
||||
{
|
||||
if (take_ownership)
|
||||
{
|
||||
owned.reset(t);
|
||||
not_owned = nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
owned.reset();
|
||||
not_owned = t;
|
||||
}
|
||||
}
|
||||
|
||||
/// Reset the Handle to share ownership with @a t.
|
||||
void Reset(const std::shared_ptr<T> &t)
|
||||
{
|
||||
owned = t;
|
||||
not_owned = nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
/// @brief Return a new owning Handle, where the pointed-to object is a new
|
||||
/// object constructed using the given arguments.
|
||||
///
|
||||
/// This is analogous to <a
|
||||
/// href="https://en.cppreference.com/w/cpp/memory/shared_ptr/make_shared">
|
||||
/// std::make_shared</a>.
|
||||
template <typename T, typename... Args>
|
||||
Handle<T> MakeOwning(Args&&... args)
|
||||
{
|
||||
T *t = new T(std::forward<Args>(args)...);
|
||||
return Handle<T>(t, true);
|
||||
}
|
||||
|
||||
/// Return a new owning Handle pointing to @a t.
|
||||
template <typename T>
|
||||
Handle<T> Owning(T *t) { return Handle<T>(t, true); }
|
||||
|
||||
/// Return a new non-owning Handle pointing to @a t.
|
||||
template <typename T>
|
||||
Handle<T> NonOwning(T *t) { return Handle<T>(t, false); }
|
||||
|
||||
} // namespace mfem
|
||||
|
||||
#endif
|
||||
@@ -87,7 +87,7 @@ int isockstream::establish()
|
||||
#if defined(__APPLE__)
|
||||
if (bind(sfd, (const struct sockaddr *)rp->ai_addr, rp->ai_addrlen) < 0)
|
||||
#else
|
||||
if (bind(sfd, rp->ai_addr, rp->ai_addrlen) < 0)
|
||||
if (bind(sfd, rp->ai_addr, static_cast<socklen_t>(rp->ai_addrlen)) < 0)
|
||||
#endif
|
||||
{
|
||||
mfem::err << "isockstream::establish(): bind() failed!" << std::endl;
|
||||
|
||||
+58
-10
@@ -408,8 +408,26 @@ class UvmHostMemorySpace : public HostMemorySpace
|
||||
{
|
||||
public:
|
||||
UvmHostMemorySpace(): HostMemorySpace() { }
|
||||
void Alloc(void **ptr, size_t bytes) override { CuMallocManaged(ptr, bytes == 0 ? 8 : bytes); }
|
||||
void Dealloc(void *ptr) override { CuMemFree(ptr); }
|
||||
|
||||
void Alloc(void **ptr, size_t bytes) override
|
||||
{
|
||||
#ifdef MFEM_USE_CUDA
|
||||
CuMallocManaged(ptr, bytes == 0 ? 8 : bytes);
|
||||
#endif
|
||||
#ifdef MFEM_USE_HIP
|
||||
HipMallocManaged(ptr, bytes == 0 ? 8 : bytes);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Dealloc(void *ptr) override
|
||||
{
|
||||
#ifdef MFEM_USE_CUDA
|
||||
CuMemFree(ptr);
|
||||
#endif
|
||||
#ifdef MFEM_USE_HIP
|
||||
HipMemFree(ptr);
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
/// The 'No' device memory space
|
||||
@@ -504,6 +522,25 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
class UvmHipMemorySpace : public DeviceMemorySpace
|
||||
{
|
||||
public:
|
||||
void Alloc(Memory &base) { base.d_ptr = base.h_ptr; }
|
||||
void Dealloc(Memory&) { }
|
||||
void *HtoD(void *dst, const void *src, size_t bytes)
|
||||
{
|
||||
if (dst == src) { MFEM_STREAM_SYNC; return dst; }
|
||||
return HipMemcpyHtoD(dst, src, bytes);
|
||||
}
|
||||
void *DtoD(void* dst, const void* src, size_t bytes)
|
||||
{ return HipMemcpyDtoD(dst, src, bytes); }
|
||||
void *DtoH(void *dst, const void *src, size_t bytes)
|
||||
{
|
||||
if (dst == src) { MFEM_STREAM_SYNC; return dst; }
|
||||
return HipMemcpyDtoH(dst, src, bytes);
|
||||
}
|
||||
};
|
||||
|
||||
/// The MMU device memory space
|
||||
class MmuDeviceMemorySpace : public DeviceMemorySpace
|
||||
{
|
||||
@@ -661,7 +698,15 @@ public:
|
||||
|
||||
// Filling the device memory backends, shifting with the device size
|
||||
constexpr int shift = DeviceMemoryType;
|
||||
#if defined(MFEM_USE_CUDA)
|
||||
device[static_cast<int>(MT::MANAGED)-shift] = new UvmCudaMemorySpace();
|
||||
#elif defined(MFEM_USE_HIP)
|
||||
device[static_cast<int>(MT::MANAGED)-shift] = new UvmHipMemorySpace();
|
||||
#else
|
||||
// this re-creates the original behavior, but should this be nullptr instead?
|
||||
device[static_cast<int>(MT::MANAGED)-shift] = new UvmCudaMemorySpace();
|
||||
#endif
|
||||
|
||||
// All other devices controllers are delayed
|
||||
device[static_cast<int>(MemoryType::DEVICE)-shift] = nullptr;
|
||||
device[static_cast<int>(MT::DEVICE_DEBUG)-shift] = nullptr;
|
||||
@@ -1193,8 +1238,9 @@ void MemoryManager::Copy_(void *dst_h_ptr, const void *src_h_ptr,
|
||||
{
|
||||
if (dst_h_ptr != src_d_ptr && bytes != 0)
|
||||
{
|
||||
internal::Memory &src_d_base = maps->memories.at(src_h_ptr);
|
||||
MemoryType src_d_mt = src_d_base.d_mt;
|
||||
MemoryType src_d_mt = (src_flags & Mem::ALIAS) ?
|
||||
maps->aliases.at(src_h_ptr).mem->d_mt :
|
||||
maps->memories.at(src_h_ptr).d_mt;
|
||||
ctrl->Device(src_d_mt)->DtoH(dst_h_ptr, src_d_ptr, bytes);
|
||||
}
|
||||
}
|
||||
@@ -1254,9 +1300,10 @@ void MemoryManager::CopyToHost_(void *dest_h_ptr, const void *src_h_ptr,
|
||||
const void *src_d_ptr = (src_flags & Mem::ALIAS) ?
|
||||
mm.GetAliasDevicePtr(src_h_ptr, bytes, false) :
|
||||
mm.GetDevicePtr(src_h_ptr, bytes, false);
|
||||
const internal::Memory &base = maps->memories.at(dest_h_ptr);
|
||||
const MemoryType d_mt = base.d_mt;
|
||||
ctrl->Device(d_mt)->DtoH(dest_h_ptr, src_d_ptr, bytes);
|
||||
MemoryType src_d_mt = (src_flags & Mem::ALIAS) ?
|
||||
maps->aliases.at(src_h_ptr).mem->d_mt :
|
||||
maps->memories.at(src_h_ptr).d_mt;
|
||||
ctrl->Device(src_d_mt)->DtoH(dest_h_ptr, src_d_ptr, bytes);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1283,9 +1330,10 @@ void MemoryManager::CopyFromHost_(void *dest_h_ptr, const void *src_h_ptr,
|
||||
void *dest_d_ptr = (dest_flags & Mem::ALIAS) ?
|
||||
mm.GetAliasDevicePtr(dest_h_ptr, bytes, false) :
|
||||
mm.GetDevicePtr(dest_h_ptr, bytes, false);
|
||||
const internal::Memory &base = maps->memories.at(dest_h_ptr);
|
||||
const MemoryType d_mt = base.d_mt;
|
||||
ctrl->Device(d_mt)->HtoD(dest_d_ptr, src_h_ptr, bytes);
|
||||
MemoryType dest_d_mt = (dest_flags & Mem::ALIAS) ?
|
||||
maps->aliases.at(dest_h_ptr).mem->d_mt :
|
||||
maps->memories.at(dest_h_ptr).d_mt;
|
||||
ctrl->Device(dest_d_mt)->HtoD(dest_d_ptr, src_h_ptr, bytes);
|
||||
}
|
||||
dest_flags = dest_flags &
|
||||
~(dest_on_host ? Mem::VALID_DEVICE : Mem::VALID_HOST);
|
||||
|
||||
+13
-48
@@ -15,80 +15,45 @@
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
IntegerSet::IntegerSet(IntegerSet &s)
|
||||
: me(s.me.Size())
|
||||
int IntegerSet::PickRandomElement() const
|
||||
{
|
||||
for (int i = 0; i < me.Size(); i++)
|
||||
{
|
||||
me[i] = s.me[i];
|
||||
}
|
||||
}
|
||||
|
||||
IntegerSet& IntegerSet::operator=(const IntegerSet &s)
|
||||
{
|
||||
me.SetSize(s.me.Size());
|
||||
for (int i = 0; i < me.Size(); i++)
|
||||
{
|
||||
me[i] = s.me[i];
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
int IntegerSet::operator== (IntegerSet &s)
|
||||
{
|
||||
if (me.Size() != s.me.Size())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (int i = 0; i < me.Size(); i++)
|
||||
if (me[i] != s.me[i])
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int IntegerSet::PickRandomElement()
|
||||
{
|
||||
int i, size = me.Size();
|
||||
int i, size = Size();
|
||||
unsigned int seed = 0;
|
||||
|
||||
for (i = 0; i < size; i++)
|
||||
{
|
||||
seed += me[i];
|
||||
seed += data[i];
|
||||
}
|
||||
|
||||
srand(seed);
|
||||
|
||||
return me[rand()/(RAND_MAX/size)];
|
||||
return data[rand()/(RAND_MAX/size)];
|
||||
}
|
||||
|
||||
void IntegerSet::Recreate(const int n, const int *p)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
me.SetSize(n);
|
||||
SetSize(n);
|
||||
|
||||
for (i = 0; i < n; i++)
|
||||
{
|
||||
me[i] = p[i];
|
||||
data[i] = p[i];
|
||||
}
|
||||
|
||||
me.Sort();
|
||||
Sort();
|
||||
|
||||
for (j = 0, i = 1; i < n; i++)
|
||||
if (me[i] != me[j])
|
||||
if (data[i] != data[j])
|
||||
{
|
||||
me[++j] = me[i];
|
||||
data[++j] = data[i];
|
||||
}
|
||||
|
||||
me.SetSize(j+1);
|
||||
SetSize(j+1);
|
||||
}
|
||||
|
||||
|
||||
int ListOfIntegerSets::Insert(IntegerSet &s)
|
||||
int ListOfIntegerSets::Insert(const IntegerSet &s)
|
||||
{
|
||||
for (int i = 0; i < TheList.Size(); i++)
|
||||
if (*TheList[i] == s)
|
||||
@@ -101,7 +66,7 @@ int ListOfIntegerSets::Insert(IntegerSet &s)
|
||||
return TheList.Size()-1;
|
||||
}
|
||||
|
||||
int ListOfIntegerSets::Lookup(IntegerSet &s)
|
||||
int ListOfIntegerSets::Lookup(const IntegerSet &s) const
|
||||
{
|
||||
for (int i = 0; i < TheList.Size(); i++)
|
||||
if (*TheList[i] == s)
|
||||
@@ -113,7 +78,7 @@ int ListOfIntegerSets::Lookup(IntegerSet &s)
|
||||
return -1;
|
||||
}
|
||||
|
||||
void ListOfIntegerSets::AsTable(Table & t)
|
||||
void ListOfIntegerSets::AsTable(Table & t) const
|
||||
{
|
||||
int i;
|
||||
|
||||
|
||||
+17
-29
@@ -20,38 +20,26 @@ namespace mfem
|
||||
{
|
||||
|
||||
/// A set of integers
|
||||
class IntegerSet
|
||||
class IntegerSet : public Array<int>
|
||||
{
|
||||
private:
|
||||
Array<int> me;
|
||||
|
||||
public:
|
||||
/// Create an empty set.
|
||||
IntegerSet() { }
|
||||
|
||||
/// Create a copy of set 's'.
|
||||
IntegerSet(IntegerSet &s);
|
||||
using Array<int>::Array; ///< Inherit all Array constructors.
|
||||
// MSVC fails to recognize that rule of zero applies after using base class
|
||||
// constructors.
|
||||
IntegerSet() = default; ///< Default construct and empty set.
|
||||
IntegerSet(const IntegerSet &) = default; ///< Copy constructor.
|
||||
IntegerSet(IntegerSet &&) = default; ///< Move constructor.
|
||||
IntegerSet& operator=(const IntegerSet &) = default; ///< Copy assignment.
|
||||
IntegerSet& operator=(IntegerSet &&) = default; ///< Move assignment.
|
||||
|
||||
/// Create an integer set from C-array 'p' of 'n' integers.
|
||||
IntegerSet(const int n, const int *p) { Recreate(n, p); }
|
||||
|
||||
/// Return the size of the set.
|
||||
int Size() { return me.Size(); }
|
||||
|
||||
/// Return a reference to the sorted array of all the set entries.
|
||||
operator Array<int>& () { return me; }
|
||||
|
||||
/// Return the value of the lowest element of the set.
|
||||
int PickElement() { return me[0]; }
|
||||
int PickElement() const { return data[0]; }
|
||||
|
||||
/// Return the value of a random element of the set.
|
||||
int PickRandomElement();
|
||||
|
||||
/// Create a copy of set 's'.
|
||||
IntegerSet& operator=(const IntegerSet &s);
|
||||
|
||||
/// Return 1 if the sets are equal and 0 otherwise.
|
||||
int operator==(IntegerSet &s);
|
||||
int PickRandomElement() const;
|
||||
|
||||
/** @brief Create an integer set from C-array 'p' of 'n' integers.
|
||||
Overwrites any existing set data. */
|
||||
@@ -67,25 +55,25 @@ private:
|
||||
public:
|
||||
|
||||
/// Return the number of integer sets in the list.
|
||||
int Size() { return TheList.Size(); }
|
||||
int Size() const { return TheList.Size(); }
|
||||
|
||||
/// Return the value of the first element of the ith set.
|
||||
int PickElementInSet(int i) { return TheList[i]->PickElement(); }
|
||||
int PickElementInSet(int i) const { return TheList[i]->PickElement(); }
|
||||
|
||||
/// Return a random value from the ith set in the list.
|
||||
int PickRandomElementInSet(int i) { return TheList[i]->PickRandomElement(); }
|
||||
int PickRandomElementInSet(int i) const { return TheList[i]->PickRandomElement(); }
|
||||
|
||||
/** @brief Check to see if set 's' is in the list. If not append it to the
|
||||
end of the list. Returns the index of the list where set 's' can be
|
||||
found. */
|
||||
int Insert(IntegerSet &s);
|
||||
int Insert(const IntegerSet &s);
|
||||
|
||||
/** Return the index of the list where set 's' can be found. Returns -1 if
|
||||
not found. */
|
||||
int Lookup(IntegerSet &s);
|
||||
int Lookup(const IntegerSet &s) const;
|
||||
|
||||
/// Write the list of sets into table 't'.
|
||||
void AsTable(Table &t);
|
||||
void AsTable(Table &t) const;
|
||||
|
||||
~ListOfIntegerSets();
|
||||
};
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
// CONTRIBUTING.md for details.
|
||||
|
||||
#ifdef _WIN32
|
||||
// Turn off CRT deprecation warnings for strerror (VS 2013)
|
||||
// Turn off CRT deprecation warnings for strerror
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
#endif
|
||||
|
||||
@@ -30,13 +30,13 @@
|
||||
#include <ws2tcpip.h>
|
||||
#ifdef _MSC_VER
|
||||
typedef int ssize_t;
|
||||
typedef int socklen_t;
|
||||
// Link with ws2_32.lib
|
||||
#pragma comment(lib, "ws2_32.lib")
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef MFEM_USE_GNUTLS
|
||||
#include <cstdlib> // getenv
|
||||
#ifndef MFEM_USE_GNUTLS_X509
|
||||
#include <gnutls/openpgp.h>
|
||||
#endif
|
||||
@@ -146,7 +146,8 @@ int socketbuf::open(const char hostname[], int port)
|
||||
}
|
||||
#endif
|
||||
|
||||
if (connect(socket_descriptor, rp->ai_addr, rp->ai_addrlen) < 0)
|
||||
if (connect(socket_descriptor, rp->ai_addr,
|
||||
static_cast<socklen_t>(rp->ai_addrlen)) < 0)
|
||||
{
|
||||
closesocket(socket_descriptor);
|
||||
socket_descriptor = -2;
|
||||
|
||||
@@ -24,7 +24,7 @@ list(APPEND SRCS
|
||||
constraints.cpp
|
||||
densemat.cpp
|
||||
symmat.cpp
|
||||
handle.cpp
|
||||
op_handle.cpp
|
||||
matrix.cpp
|
||||
ode.cpp
|
||||
operator.cpp
|
||||
@@ -51,7 +51,7 @@ list(APPEND HDRS
|
||||
dinvariants.hpp
|
||||
symmat.hpp
|
||||
dtensor.hpp
|
||||
handle.hpp
|
||||
op_handle.hpp
|
||||
invariants.hpp
|
||||
kernels.hpp
|
||||
lapack.hpp
|
||||
|
||||
@@ -52,9 +52,9 @@ BatchedLinAlg &BatchedLinAlg::Instance()
|
||||
}
|
||||
|
||||
void BatchedLinAlg::AddMult(const DenseTensor &A, const Vector &x, Vector &y,
|
||||
real_t alpha, real_t beta)
|
||||
real_t alpha, real_t beta, Op op)
|
||||
{
|
||||
Get(Instance().active_backend).AddMult(A, x, y, alpha, beta);
|
||||
Get(Instance().active_backend).AddMult(A, x, y, alpha, beta, op);
|
||||
}
|
||||
|
||||
void BatchedLinAlg::Mult(const DenseTensor &A, const Vector &x, Vector &y)
|
||||
@@ -62,6 +62,12 @@ void BatchedLinAlg::Mult(const DenseTensor &A, const Vector &x, Vector &y)
|
||||
Get(Instance().active_backend).Mult(A, x, y);
|
||||
}
|
||||
|
||||
void BatchedLinAlg::MultTranspose(const DenseTensor &A, const Vector &x,
|
||||
Vector &y)
|
||||
{
|
||||
Get(Instance().active_backend).MultTranspose(A, x, y);
|
||||
}
|
||||
|
||||
void BatchedLinAlg::Invert(DenseTensor &A)
|
||||
{
|
||||
Get(Instance().active_backend).Invert(A);
|
||||
@@ -107,4 +113,10 @@ void BatchedLinAlgBase::Mult(const DenseTensor &A, const Vector &x,
|
||||
AddMult(A, x, y, 1.0, 0.0);
|
||||
}
|
||||
|
||||
void BatchedLinAlgBase::MultTranspose(const DenseTensor &A, const Vector &x,
|
||||
Vector &y) const
|
||||
{
|
||||
AddMult(A, x, y, 1.0, 0.0, Op::T);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -48,6 +48,14 @@ public:
|
||||
/// Counter for the number of backends.
|
||||
NUM_BACKENDS
|
||||
};
|
||||
|
||||
/// Operation type (transposed or not transposed)
|
||||
enum Op
|
||||
{
|
||||
N, ///< Not transposed.
|
||||
T ///< Transposed.
|
||||
};
|
||||
|
||||
private:
|
||||
/// All available backends. Unavailble backends will be nullptr.
|
||||
std::array<std::unique_ptr<class BatchedLinAlgBase>,
|
||||
@@ -58,15 +66,19 @@ private:
|
||||
/// Return the singleton instance.
|
||||
static BatchedLinAlg &Instance();
|
||||
public:
|
||||
/// @brief Computes $y = \alpha A x + \beta y$.
|
||||
/// @brief Computes $y = \alpha A^{op} x + \beta y$.
|
||||
///
|
||||
/// $A^{op}$ is either $A$ or $A^T$ depending on the value of @a op.
|
||||
/// $A$ is a block diagonal matrix, represented by the DenseTensor @a A with
|
||||
/// shape (m, n, n_mat). $x$ has shape (n, k, n_mat), and $y$ has shape
|
||||
/// (m, k, n_mat).
|
||||
/// shape (m, n, n_mat). $x$ has shape (tr?m:n, k, n_mat), and $y$ has shape
|
||||
/// (tr?n:m, k, n_mat), where 'tr' is true in the transposed case.
|
||||
static void AddMult(const DenseTensor &A, const Vector &x, Vector &y,
|
||||
real_t alpha = 1.0, real_t beta = 1.0);
|
||||
/// Computes $y = A x$ (e.g. by calling @ref AddMult "AddMult(A,x,y,1,0)").
|
||||
real_t alpha = 1.0, real_t beta = 1.0,
|
||||
Op op = Op::N);
|
||||
/// Computes $y = A x$ (e.g. by calling @ref AddMult "AddMult(A,x,y,1,0,Op::N)").
|
||||
static void Mult(const DenseTensor &A, const Vector &x, Vector &y);
|
||||
/// Computes $y = A^T x$ (e.g. by calling @ref AddMult "AddMult(A,x,y,1,0,Op::T)").
|
||||
static void MultTranspose(const DenseTensor &A, const Vector &x, Vector &y);
|
||||
/// @brief Replaces the block diagonal matrix $A$ with its inverse $A^{-1}$.
|
||||
///
|
||||
/// $A$ is represented by the DenseTensor @a A with shape (m, m, n_mat).
|
||||
@@ -109,11 +121,16 @@ public:
|
||||
class BatchedLinAlgBase
|
||||
{
|
||||
public:
|
||||
using Op = BatchedLinAlg::Op;
|
||||
/// See BatchedLinAlg::AddMult.
|
||||
virtual void AddMult(const DenseTensor &A, const Vector &x, Vector &y,
|
||||
real_t alpha = 1.0, real_t beta = 1.0) const = 0;
|
||||
real_t alpha = 1.0, real_t beta = 1.0,
|
||||
Op op = Op::N) const = 0;
|
||||
/// See BatchedLinAlg::Mult.
|
||||
virtual void Mult(const DenseTensor &A, const Vector &x, Vector &y) const;
|
||||
/// See BatchedLinAlg::MultTranspose.
|
||||
virtual void MultTranspose(const DenseTensor &A, const Vector &x,
|
||||
Vector &y) const;
|
||||
/// See BatchedLinAlg::Invert.
|
||||
virtual void Invert(DenseTensor &A) const = 0;
|
||||
/// See BatchedLinAlg::LUFactor.
|
||||
|
||||
+14
-10
@@ -82,23 +82,27 @@ void GPUBlas::DisableAtomics()
|
||||
}
|
||||
|
||||
void GPUBlasBatchedLinAlg::AddMult(const DenseTensor &A, const Vector &x,
|
||||
Vector &y, real_t alpha, real_t beta) const
|
||||
Vector &y, real_t alpha, real_t beta,
|
||||
Op op) const
|
||||
{
|
||||
const int m = A.SizeI();
|
||||
const int n = A.SizeJ();
|
||||
const bool tr = (op == Op::T);
|
||||
|
||||
const int m = tr ? A.SizeJ() : A.SizeI();
|
||||
const int n = tr ? A.SizeI() : A.SizeJ();
|
||||
const int n_mat = A.SizeK();
|
||||
const int k = x.Size() / n / n_mat;
|
||||
|
||||
auto d_A = mfem::Reshape(A.Read(), m, n, n_mat);
|
||||
auto d_x = mfem::Reshape(x.Read(), n, k, n_mat);
|
||||
auto d_y = mfem::Reshape(beta == 0.0 ? y.Write() : y.ReadWrite(), m, k, n_mat);
|
||||
auto d_A = A.Read();
|
||||
auto d_x = x.Read(); // Shape: (n, k, n_mat)
|
||||
auto d_y = beta == 0.0 ? y.Write() : y.ReadWrite(); // Shape (m, k, n_mat)
|
||||
|
||||
const auto op = MFEM_CU_or_HIP(BLAS_OP_N);
|
||||
const auto op_A = tr ? MFEM_CU_or_HIP(BLAS_OP_T) : MFEM_CU_or_HIP(BLAS_OP_N);
|
||||
const auto op_B = MFEM_CU_or_HIP(BLAS_OP_N);
|
||||
|
||||
const blasStatus_t status = MFEM_GPUBLAS_PREFIX(gemmStridedBatched)(
|
||||
GPUBlas::Handle(), op, op, m, k, n, &alpha,
|
||||
d_A, m, m*n, d_x, n, n*k, &beta, d_y, m, m*k,
|
||||
n_mat);
|
||||
GPUBlas::Handle(), op_A, op_B, m, k, n,
|
||||
&alpha, d_A, m, m*n, d_x, n, n*k, &beta, d_y,
|
||||
m, m*k, n_mat);
|
||||
MFEM_VERIFY(status == MFEM_BLAS_SUCCESS, "GPU BLAS error.");
|
||||
}
|
||||
|
||||
|
||||
@@ -57,7 +57,8 @@ class GPUBlasBatchedLinAlg : public BatchedLinAlgBase
|
||||
{
|
||||
public:
|
||||
void AddMult(const DenseTensor &A, const Vector &x, Vector &y,
|
||||
real_t alpha = 1.0, real_t beta = 1.0) const override;
|
||||
real_t alpha = 1.0, real_t beta = 1.0,
|
||||
Op op = Op::N) const override;
|
||||
void Invert(DenseTensor &A) const override;
|
||||
void LUFactor(DenseTensor &A, Array<int> &P) const override;
|
||||
void LUSolve(const DenseTensor &LU, const Array<int> &P,
|
||||
|
||||
@@ -54,19 +54,24 @@ magma_queue_t Magma::Queue()
|
||||
}
|
||||
|
||||
void MagmaBatchedLinAlg::AddMult(const DenseTensor &A, const Vector &x,
|
||||
Vector &y, real_t alpha, real_t beta) const
|
||||
Vector &y, real_t alpha, real_t beta,
|
||||
Op op) const
|
||||
{
|
||||
const int m = A.SizeI();
|
||||
const int n = A.SizeJ();
|
||||
const bool tr = (op == Op::T);
|
||||
|
||||
const int m = tr ? A.SizeJ() : A.SizeI();
|
||||
const int n = tr ? A.SizeI() : A.SizeJ();
|
||||
const int n_mat = A.SizeK();
|
||||
const int k = x.Size() / n / n_mat;
|
||||
|
||||
auto d_A = mfem::Reshape(A.Read(), m, n, n_mat);
|
||||
auto d_x = mfem::Reshape(x.Read(), n, k, n_mat);
|
||||
auto d_y = mfem::Reshape(beta == 0.0 ? y.Write() : y.ReadWrite(), m, k, n_mat);
|
||||
auto d_A = A.Read();
|
||||
auto d_x = x.Read(); // Shape (n, k, n_mat);
|
||||
auto d_y = beta == 0.0 ? y.Write() : y.ReadWrite(); // Shape (m, k, n_mat);
|
||||
|
||||
magma_trans_t magma_op = tr ? MagmaNoTrans : MagmaTrans;
|
||||
|
||||
MFEM_MAGMABLAS_PREFIX(gemm_batched_strided)(
|
||||
MagmaNoTrans, MagmaNoTrans, m, k, n, alpha, d_A, m, m*n, d_x, n, n*k,
|
||||
magma_op, MagmaNoTrans, m, k, n, alpha, d_A, m, m*n, d_x, n, n*k,
|
||||
beta, d_y, m, m*k, n_mat, Magma::Queue());
|
||||
}
|
||||
|
||||
|
||||
@@ -25,7 +25,8 @@ class MagmaBatchedLinAlg : public BatchedLinAlgBase
|
||||
{
|
||||
public:
|
||||
void AddMult(const DenseTensor &A, const Vector &x, Vector &y,
|
||||
real_t alpha = 1.0, real_t beta = 1.0) const override;
|
||||
real_t alpha = 1.0, real_t beta = 1.0,
|
||||
Op op = Op::N) const override;
|
||||
void Invert(DenseTensor &A) const override;
|
||||
void LUFactor(DenseTensor &A, Array<int> &P) const override;
|
||||
void LUSolve(const DenseTensor &A, const Array<int> &P,
|
||||
|
||||
+110
-17
@@ -18,22 +18,37 @@ namespace mfem
|
||||
{
|
||||
|
||||
void NativeBatchedLinAlg::AddMult(const DenseTensor &A, const Vector &x,
|
||||
Vector &y, real_t alpha, real_t beta) const
|
||||
Vector &y, real_t alpha, real_t beta,
|
||||
Op op) const
|
||||
{
|
||||
const bool tr = (op == Op::T);
|
||||
|
||||
const int m = A.SizeI();
|
||||
const int n = A.SizeJ();
|
||||
const int n_mat = A.SizeK();
|
||||
const int k = x.Size() / n / n_mat;
|
||||
const int k = x.Size() / (tr ? m : n) / n_mat;
|
||||
|
||||
auto d_A = mfem::Reshape(A.Read(), m, n, n_mat);
|
||||
auto d_x = mfem::Reshape(x.Read(), n, k, n_mat);
|
||||
auto d_y = mfem::Reshape(beta == 0.0 ? y.Write() : y.ReadWrite(), m, k, n_mat);
|
||||
auto d_A = Reshape(A.Read(), m, n, n_mat);
|
||||
auto d_x = Reshape(x.Read(), (tr ? m : n), k, n_mat);
|
||||
auto d_y = Reshape(beta == 0.0 ? y.Write() : y.ReadWrite(),
|
||||
(tr ? n : m), k, n_mat);
|
||||
|
||||
mfem::forall(n_mat, [=] MFEM_HOST_DEVICE (int i)
|
||||
if (tr)
|
||||
{
|
||||
kernels::AddMult(m, k, n, &d_A(0,0,i), &d_x(0,0,i), &d_y(0,0,i),
|
||||
alpha, beta);
|
||||
});
|
||||
mfem::forall(n_mat, [=] MFEM_HOST_DEVICE (int i)
|
||||
{
|
||||
kernels::AddMultAtB(m, n, k, &d_A(0,0,i), &d_x(0,0,i), &d_y(0,0,i),
|
||||
alpha, beta);
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
mfem::forall(n_mat, [=] MFEM_HOST_DEVICE (int i)
|
||||
{
|
||||
kernels::AddMult(m, k, n, &d_A(0,0,i), &d_x(0,0,i), &d_y(0,0,i),
|
||||
alpha, beta);
|
||||
});
|
||||
}
|
||||
|
||||
// Alternative approach, threading also over the second index. Which one is
|
||||
// better?
|
||||
@@ -48,7 +63,85 @@ void NativeBatchedLinAlg::AddMult(const DenseTensor &A, const Vector &x,
|
||||
|
||||
void NativeBatchedLinAlg::Invert(DenseTensor &A) const
|
||||
{
|
||||
MFEM_ABORT("");
|
||||
const int m = A.SizeI();
|
||||
const int NE = A.SizeK();
|
||||
DenseTensor LU = A;
|
||||
Array<int> P(m*NE);
|
||||
|
||||
LUFactor(LU, P);
|
||||
|
||||
auto data_all = Reshape(LU.Read(), m, m, NE);
|
||||
auto piv_all = Reshape(P.Read(), m, NE);
|
||||
auto inv_all = Reshape(A.Write(), m, m, NE);
|
||||
|
||||
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
|
||||
{
|
||||
// A^{-1} = U^{-1} L^{-1} P
|
||||
// X <- U^{-1} (set only the upper triangular part of X)
|
||||
real_t *X = &inv_all(0, 0, e);
|
||||
real_t *x = X;
|
||||
const real_t *data = &data_all(0, 0, e);
|
||||
const int *ipiv = &piv_all(0, e);
|
||||
|
||||
for (int k = 0; k < m; k++)
|
||||
{
|
||||
const real_t minus_x_k = -(x[k] = 1.0 / data[k + k * m]);
|
||||
for (int i = 0; i < k; i++)
|
||||
{
|
||||
x[i] = data[i + k * m] * minus_x_k;
|
||||
}
|
||||
for (int j = k - 1; j >= 0; j--)
|
||||
{
|
||||
const real_t x_j = (x[j] /= data[j + j * m]);
|
||||
for (int i = 0; i < j; i++)
|
||||
{
|
||||
x[i] -= data[i + j * m] * x_j;
|
||||
}
|
||||
}
|
||||
x += m;
|
||||
}
|
||||
|
||||
// X <- X L^{-1} (use input only from the upper triangular part of X)
|
||||
{
|
||||
int k = m - 1;
|
||||
for (int j = 0; j < k; j++)
|
||||
{
|
||||
const real_t minus_L_kj = -data[k + j * m];
|
||||
for (int i = 0; i <= j; i++)
|
||||
{
|
||||
X[i + j * m] += X[i + k * m] * minus_L_kj;
|
||||
}
|
||||
for (int i = j + 1; i < m; i++)
|
||||
{
|
||||
X[i + j * m] = X[i + k * m] * minus_L_kj;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int k = m - 2; k >= 0; k--)
|
||||
{
|
||||
for (int j = 0; j < k; j++)
|
||||
{
|
||||
const real_t L_kj = data[k + j * m];
|
||||
for (int i = 0; i < m; i++)
|
||||
{
|
||||
X[i + j * m] -= X[i + k * m] * L_kj;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// X <- X P
|
||||
for (int k = m - 1; k >= 0; k--)
|
||||
{
|
||||
const int piv_k = ipiv[k];
|
||||
if (k != piv_k)
|
||||
{
|
||||
for (int i = 0; i < m; i++)
|
||||
{
|
||||
kernels::internal::Swap(X[i + k * m], X[i + piv_k * m]);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void NativeBatchedLinAlg::LUFactor(DenseTensor &A, Array<int> &P) const
|
||||
@@ -58,8 +151,8 @@ void NativeBatchedLinAlg::LUFactor(DenseTensor &A, Array<int> &P) const
|
||||
const int NE = A.SizeK();
|
||||
P.SetSize(m*NE);
|
||||
|
||||
auto data_all = mfem::Reshape(A.ReadWrite(), m, m, NE);
|
||||
auto ipiv_all = mfem::Reshape(P.Write(), m, NE);
|
||||
auto data_all = Reshape(A.ReadWrite(), m, m, NE);
|
||||
auto ipiv_all = Reshape(P.Write(), m, NE);
|
||||
Array<bool> pivot_flag(1);
|
||||
pivot_flag[0] = true;
|
||||
bool *d_pivot_flag = pivot_flag.ReadWrite();
|
||||
@@ -87,12 +180,12 @@ void NativeBatchedLinAlg::LUFactor(DenseTensor &A, Array<int> &P) const
|
||||
// swap rows i and piv in both L and U parts
|
||||
for (int j = 0; j < m; j++)
|
||||
{
|
||||
mfem::kernels::internal::Swap<real_t>(data_all(i,j,e), data_all(piv,j,e));
|
||||
kernels::internal::Swap<real_t>(data_all(i,j,e), data_all(piv,j,e));
|
||||
}
|
||||
}
|
||||
} // pivot end
|
||||
|
||||
if (abs(data_all(i,i,e)) <= tol)
|
||||
if (std::abs(data_all(i,i,e)) <= tol)
|
||||
{
|
||||
d_pivot_flag[0] = false;
|
||||
}
|
||||
@@ -124,9 +217,9 @@ void NativeBatchedLinAlg::LUSolve(const DenseTensor &LU, const Array<int> &P,
|
||||
const int n_mat = LU.SizeK();
|
||||
const int n_rhs = x.Size() / m / n_mat;
|
||||
|
||||
auto d_LU = mfem::Reshape(LU.Read(), m, m, n_mat);
|
||||
auto d_P = mfem::Reshape(P.Read(), m, n_mat);
|
||||
auto d_x = mfem::Reshape(x.Write(), m, n_rhs, n_mat);
|
||||
auto d_LU = Reshape(LU.Read(), m, m, n_mat);
|
||||
auto d_P = Reshape(P.Read(), m, n_mat);
|
||||
auto d_x = Reshape(x.Write(), m, n_rhs, n_mat);
|
||||
|
||||
mfem::forall(n_mat * n_rhs, [=] MFEM_HOST_DEVICE (int idx)
|
||||
{
|
||||
|
||||
@@ -21,7 +21,7 @@ class NativeBatchedLinAlg : public BatchedLinAlgBase
|
||||
{
|
||||
public:
|
||||
void AddMult(const DenseTensor &A, const Vector &x, Vector &y,
|
||||
real_t alpha, real_t beta) const override;
|
||||
real_t alpha, real_t beta, Op op) const override;
|
||||
void Invert(DenseTensor &A) const override;
|
||||
void LUFactor(DenseTensor &A, Array<int> &P) const override;
|
||||
void LUSolve(const DenseTensor &LU, const Array<int> &P,
|
||||
|
||||
@@ -1174,6 +1174,31 @@ public:
|
||||
tdata.Wrap(ext_data, i*j*k, false);
|
||||
}
|
||||
|
||||
/// @brief Reset the DenseTensor to use the given external Memory @a mem and
|
||||
/// dimensions @a i, @a j, and @a k.
|
||||
///
|
||||
/// If @a own_mem is false, the DenseTensor will not own any of the pointers
|
||||
/// of @a mem.
|
||||
///
|
||||
/// Note that when @a own_mem is true, the @a mem object can be destroyed
|
||||
/// immediately by the caller but `mem.Delete()` should NOT be called since
|
||||
/// the DenseTensor object takes ownership of all pointers owned by @a mem.
|
||||
void NewMemoryAndSize(const Memory<real_t> &mem, int i, int j, int k,
|
||||
bool own_mem)
|
||||
{
|
||||
tdata.Delete();
|
||||
Mk.UseExternalData(NULL, i, j);
|
||||
nk = k;
|
||||
if (own_mem)
|
||||
{
|
||||
tdata = mem;
|
||||
}
|
||||
else
|
||||
{
|
||||
tdata.MakeAlias(mem, 0, i*j*k);
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets the tensor elements equal to constant c
|
||||
DenseTensor &operator=(real_t c);
|
||||
|
||||
|
||||
+67
-16
@@ -28,16 +28,23 @@ namespace mfem
|
||||
{
|
||||
|
||||
bool Hypre::configure_runtime_policy_from_mfem = true;
|
||||
Hypre::State Hypre::state = Hypre::State::UNINITIALIZED;
|
||||
|
||||
Hypre::Hypre()
|
||||
void Hypre::Init()
|
||||
{
|
||||
if (state != State::INITIALIZED)
|
||||
{
|
||||
#if MFEM_HYPRE_VERSION >= 21900
|
||||
// Initializing hypre
|
||||
HYPRE_Init();
|
||||
HYPRE_Init();
|
||||
#endif
|
||||
|
||||
// Global hypre options that we set by default
|
||||
SetDefaultOptions();
|
||||
SetDefaultOptions();
|
||||
// Apply the setting of 'configure_runtime_policy_from_mfem' according to
|
||||
// the current configuration of the mfem::Device (HYPRE >= 2.31.0):
|
||||
InitDevice();
|
||||
// Create the singleton Hypre object AFTER initializing HYPRE:
|
||||
Instance();
|
||||
}
|
||||
state = State::INITIALIZED;
|
||||
}
|
||||
|
||||
void Hypre::InitDevice()
|
||||
@@ -48,6 +55,8 @@ void Hypre::InitDevice()
|
||||
#if defined(HYPRE_USING_GPU) && (MFEM_HYPRE_VERSION >= 23100)
|
||||
if (configure_runtime_policy_from_mfem)
|
||||
{
|
||||
MFEM_VERIFY(HYPRE_Initialized(), "HYPRE must be initialized before"
|
||||
" calling Hypre::InitDevice()");
|
||||
if (Device::Allows(Backend::DEVICE_MASK & ~Backend::DEBUG_DEVICE))
|
||||
{
|
||||
HYPRE_SetMemoryLocation(HYPRE_MEMORY_DEVICE);
|
||||
@@ -65,14 +74,13 @@ void Hypre::InitDevice()
|
||||
|
||||
void Hypre::Finalize()
|
||||
{
|
||||
Hypre &hypre = Instance();
|
||||
if (!hypre.finalized)
|
||||
if (state != State::UNINITIALIZED)
|
||||
{
|
||||
#if MFEM_HYPRE_VERSION >= 21900
|
||||
HYPRE_Finalize();
|
||||
#endif
|
||||
hypre.finalized = true;
|
||||
}
|
||||
state = State::UNINITIALIZED;
|
||||
}
|
||||
|
||||
void Hypre::SetDefaultOptions()
|
||||
@@ -211,6 +219,24 @@ HypreParVector::HypreParVector(MPI_Comm comm, HYPRE_BigInt glob_size,
|
||||
own_ParVector = 1;
|
||||
}
|
||||
|
||||
HypreParVector::HypreParVector(MPI_Comm comm, HYPRE_BigInt glob_size,
|
||||
Vector &base, int offset, HYPRE_BigInt *col)
|
||||
: HypreParVector(comm, glob_size, nullptr, col, false)
|
||||
{
|
||||
MFEM_ASSERT(CanShallowCopy(base.GetMemory(), GetHypreMemoryClass()),
|
||||
"the MemoryTypes of 'base' are incompatible with Hypre!");
|
||||
MFEM_ASSERT(offset + size <= base.Size(),
|
||||
"the size of 'base' is too small!");
|
||||
|
||||
data.Delete();
|
||||
data.MakeAlias(base.GetMemory(), offset, size);
|
||||
hypre_Vector *x_loc = hypre_ParVectorLocalVector(x);
|
||||
hypre_VectorData(x_loc) = data.ReadWrite(GetHypreMemoryClass(), size);
|
||||
#ifdef HYPRE_USING_GPU
|
||||
hypre_VectorMemoryLocation(x_loc) = GetHypreMemoryLocation();
|
||||
#endif
|
||||
}
|
||||
|
||||
// Call the move constructor on the "compatible" temp vector
|
||||
HypreParVector::HypreParVector(const HypreParVector &y) : HypreParVector(
|
||||
y.CreateCompatibleVector())
|
||||
@@ -1580,14 +1606,12 @@ void HypreParMatrix::GetDiag(Vector &diag) const
|
||||
{
|
||||
const int size = Height();
|
||||
diag.SetSize(size);
|
||||
auto hypre_ml = GetHypreMemoryLocation();
|
||||
// Avoid using GetHypreMemoryClass() since it may be MemoryClass::MANAGED and
|
||||
// that may not play well with the memory types used by 'diag'.
|
||||
MemoryClass hypre_mc = (hypre_ml == HYPRE_MEMORY_HOST) ?
|
||||
MemoryClass::HOST : MemoryClass::DEVICE;
|
||||
MemoryClass hypre_mc = GetHypreForallMemoryClass();
|
||||
real_t *diag_hd = diag.GetMemory().Write(hypre_mc, size);
|
||||
#if MFEM_HYPRE_VERSION >= 21800
|
||||
MFEM_VERIFY(A->diag->memory_location == hypre_ml,
|
||||
MFEM_VERIFY(A->diag->memory_location == GetHypreMemoryLocation(),
|
||||
"unexpected HypreParMatrix memory location!");
|
||||
#endif
|
||||
const HYPRE_Int *A_diag_i = A->diag->i;
|
||||
@@ -2494,7 +2518,7 @@ void HypreParMatrix::EliminateBC(const Array<int> &ess_dofs,
|
||||
|
||||
const int n_ess_dofs = ess_dofs.Size();
|
||||
const auto ess_dofs_d = ess_dofs.GetMemory().Read(
|
||||
GetHypreMemoryClass(), n_ess_dofs);
|
||||
GetHypreForallMemoryClass(), n_ess_dofs);
|
||||
|
||||
// Start communication to figure out which columns need to be eliminated in
|
||||
// the off-diagonal block
|
||||
@@ -2777,6 +2801,33 @@ void HypreParMatrix::PrintHash(std::ostream &os) const
|
||||
os << "col map offd hash : " << hf.GetHash() << '\n';
|
||||
}
|
||||
|
||||
real_t HypreParMatrix::FNorm() const
|
||||
{
|
||||
real_t norm_fro = 0.0;
|
||||
if (A != NULL)
|
||||
#if MFEM_HYPRE_VERSION >= 21900
|
||||
{
|
||||
const int ierr = hypre_ParCSRMatrixNormFro(A, &norm_fro);
|
||||
MFEM_VERIFY(ierr == 0, "");
|
||||
}
|
||||
#else
|
||||
{
|
||||
// HYPRE_USING_GPU is not defined for
|
||||
// MFEM_HYPRE_VERSION < 22100 and so here it is
|
||||
// guaranteed that the matrix is in "host" memory
|
||||
Vector Avec_diag(A->diag->data, A->diag->num_nonzeros);
|
||||
real_t normsqr_fro = InnerProduct(Avec_diag, Avec_diag);
|
||||
Vector Avec_offd(A->offd->data, A->offd->num_nonzeros);
|
||||
normsqr_fro += InnerProduct(Avec_offd, Avec_offd);
|
||||
MPI_Allreduce(MPI_IN_PLACE, &normsqr_fro, 1, MPITypeMap<real_t>::mpi_type,
|
||||
MPI_SUM, hypre_ParCSRMatrixComm(A));
|
||||
norm_fro = sqrt(normsqr_fro);
|
||||
}
|
||||
#endif
|
||||
return norm_fro;
|
||||
}
|
||||
|
||||
|
||||
inline void delete_hypre_ParCSRMatrixColMapOffd(hypre_ParCSRMatrix *A)
|
||||
{
|
||||
HYPRE_BigInt *A_col_map_offd = hypre_ParCSRMatrixColMapOffd(A);
|
||||
@@ -5312,8 +5363,8 @@ void HypreBoomerAMG::SetAdvectiveOptions(int distanceR,
|
||||
int ns_down = 0, ns_up = 0, ns_coarse; // init to suppress gcc warnings
|
||||
if (distanceR > 0)
|
||||
{
|
||||
ns_down = prerelax.length();
|
||||
ns_up = postrelax.length();
|
||||
ns_down = static_cast<int>(prerelax.length());
|
||||
ns_up = static_cast<int>(postrelax.length());
|
||||
ns_coarse = 1;
|
||||
|
||||
// Array to store relaxation scheme and pass to Hypre
|
||||
|
||||
+36
-12
@@ -68,10 +68,11 @@ class Hypre
|
||||
public:
|
||||
/// @brief Initialize hypre by calling HYPRE_Init() and set default options.
|
||||
/// After calling Hypre::Init(), hypre will be finalized automatically at
|
||||
/// program exit.
|
||||
/// program exit. May be re-initialized after finalize.
|
||||
///
|
||||
/// Calling HYPRE_Finalize() manually is not compatible with this class.
|
||||
static void Init() { Instance(); }
|
||||
/// Calling HYPRE_Init() or HYPRE_Finalize() manually is only supported for
|
||||
/// HYPRE 2.29.0+
|
||||
static void Init();
|
||||
|
||||
/// @brief Configure HYPRE's compute and memory policy.
|
||||
///
|
||||
@@ -94,6 +95,9 @@ public:
|
||||
///
|
||||
/// Multiple calls to Hypre::Finalize() have no effect. This function can be
|
||||
/// called manually to more precisely control when hypre is finalized.
|
||||
///
|
||||
/// Calling HYPRE_Init() or HYPRE_Finalize() manually is only supported for
|
||||
/// HYPRE 2.29.0+
|
||||
static void Finalize();
|
||||
|
||||
/// @brief Use MFEM's device policy to configure HYPRE's device policy, true
|
||||
@@ -104,14 +108,20 @@ public:
|
||||
static bool configure_runtime_policy_from_mfem;
|
||||
|
||||
private:
|
||||
/// Calls HYPRE_Init() when the singleton is constructed.
|
||||
Hypre();
|
||||
/// Default constructor. Singleton object; private.
|
||||
Hypre() = default;
|
||||
|
||||
/// Copy constructor. Deleted.
|
||||
Hypre(Hypre&) = delete;
|
||||
|
||||
/// Move constructor. Deleted.
|
||||
Hypre(Hypre&&) = delete;
|
||||
|
||||
/// The singleton destructor (called at program exit) finalizes hypre.
|
||||
~Hypre() { Finalize(); }
|
||||
|
||||
/// Set the default hypre global options (mostly GPU-relevant).
|
||||
void SetDefaultOptions();
|
||||
static void SetDefaultOptions();
|
||||
|
||||
/// Create and return the Hypre singleton object.
|
||||
static Hypre &Instance()
|
||||
@@ -120,7 +130,10 @@ private:
|
||||
return hypre;
|
||||
}
|
||||
|
||||
bool finalized = false; ///< Has Hypre::Finalize() been called already?
|
||||
enum class State { UNINITIALIZED, INITIALIZED };
|
||||
|
||||
/// Tracks whether Hypre was initialized or finalized by this class.
|
||||
static State state;
|
||||
};
|
||||
|
||||
|
||||
@@ -247,6 +260,12 @@ public:
|
||||
allocated in the memory location HYPRE_MEMORY_DEVICE. */
|
||||
HypreParVector(MPI_Comm comm, HYPRE_BigInt glob_size, real_t *data_,
|
||||
HYPRE_BigInt *col, bool is_device_ptr = false);
|
||||
/** @brief Creates a vector that uses the data of the Vector @a base,
|
||||
starting at the given @a offset. */
|
||||
/** The @a base Vector must have memory types compatible with the MemoryClass
|
||||
returned by GetHypreMemoryClass(). */
|
||||
HypreParVector(MPI_Comm comm, HYPRE_BigInt glob_size, Vector &base,
|
||||
int offset, HYPRE_BigInt *col);
|
||||
/// Creates a deep copy of @a y
|
||||
HypreParVector(const HypreParVector &y);
|
||||
/// Move constructor for HypreParVector. "Steals" data from its argument.
|
||||
@@ -312,7 +331,8 @@ public:
|
||||
/// Sets the data of the Vector and the hypre_ParVector to @a data_.
|
||||
/** Must be used only for HypreParVector%s that do not own the data,
|
||||
e.g. created with the constructor:
|
||||
HypreParVector(MPI_Comm, HYPRE_BigInt, double *, HYPRE_BigInt *). */
|
||||
HypreParVector(MPI_Comm, HYPRE_BigInt, real_t *, HYPRE_BigInt *, bool).
|
||||
*/
|
||||
void SetData(real_t *data_);
|
||||
|
||||
/** @brief Prepare the HypreParVector for read access in hypre's device
|
||||
@@ -332,7 +352,7 @@ public:
|
||||
HYPRE_MEMORY_DEVICE. */
|
||||
/** This method must be used with HypreParVector%s that do not own the data,
|
||||
e.g. created with the constructor:
|
||||
HypreParVector(MPI_Comm, HYPRE_BigInt, double *, HYPRE_BigInt *).
|
||||
HypreParVector(MPI_Comm, HYPRE_BigInt, real_t *, HYPRE_BigInt *, bool).
|
||||
|
||||
The Memory @a mem must be accessible with the hypre MemoryClass defined
|
||||
by GetHypreMemoryClass(). */
|
||||
@@ -343,7 +363,7 @@ public:
|
||||
space, HYPRE_MEMORY_DEVICE. */
|
||||
/** This method must be used with HypreParVector%s that do not own the data,
|
||||
e.g. created with the constructor:
|
||||
HypreParVector(MPI_Comm, HYPRE_BigInt, double *, HYPRE_BigInt *).
|
||||
HypreParVector(MPI_Comm, HYPRE_BigInt, real_t *, HYPRE_BigInt *, bool).
|
||||
|
||||
The Memory @a mem must be accessible with the hypre MemoryClass defined
|
||||
by GetHypreMemoryClass(). */
|
||||
@@ -354,7 +374,7 @@ public:
|
||||
HYPRE_MEMORY_DEVICE. */
|
||||
/** This method must be used with HypreParVector%s that do not own the data,
|
||||
e.g. created with the constructor:
|
||||
HypreParVector(MPI_Comm, HYPRE_BigInt, double *, HYPRE_BigInt *).
|
||||
HypreParVector(MPI_Comm, HYPRE_BigInt, real_t *, HYPRE_BigInt *, bool).
|
||||
|
||||
The Memory @a mem must be accessible with the hypre MemoryClass defined
|
||||
by GetHypreMemoryClass(). */
|
||||
@@ -393,7 +413,7 @@ private:
|
||||
/// Auxiliary vectors for typecasting
|
||||
mutable HypreParVector *X, *Y;
|
||||
/** @brief Auxiliary buffers for the case when the input or output arrays in
|
||||
methods like Mult(double, const Vector &, double, Vector &) need to be
|
||||
methods like Mult(real_t, const Vector &, real_t, Vector &) need to be
|
||||
deep copied in order to be used by hypre. */
|
||||
mutable Memory<real_t> auxX, auxY;
|
||||
|
||||
@@ -938,6 +958,10 @@ public:
|
||||
without the need to save the whole matrix. */
|
||||
void PrintHash(std::ostream &out) const;
|
||||
|
||||
/// @brief Return the Frobenius norm of the matrix (or 0 if the underlying
|
||||
/// hypre matrix is NULL)
|
||||
real_t FNorm() const;
|
||||
|
||||
/// Calls hypre's destroy function
|
||||
virtual ~HypreParMatrix() { Destroy(); }
|
||||
|
||||
|
||||
+38
-14
@@ -402,6 +402,43 @@ void MultABt(const int Aheight, const int Awidth, const int Bheight,
|
||||
}
|
||||
}
|
||||
|
||||
/** @brief Compute C = alpha*At*B + beta*C.
|
||||
|
||||
Multiply the transpose of a matrix of size @a Aheight x @a Awidth and data
|
||||
@a Adata with a matrix of size @a Aheight x @a Bwidth and data @a Bdata. */
|
||||
template<typename TA, typename TB, typename TC>
|
||||
MFEM_HOST_DEVICE inline
|
||||
void AddMultAtB(const int Aheight, const int Awidth, const int Bwidth,
|
||||
const TA *Adata, const TB *Bdata, TC *Cdata, const TB alpha,
|
||||
const TA beta)
|
||||
{
|
||||
const int aw_x_bw = Awidth * Bwidth;
|
||||
|
||||
if (beta == 0.0)
|
||||
{
|
||||
for (int i = 0; i < aw_x_bw; i++) { Cdata[i] = 0.0; }
|
||||
}
|
||||
else if (beta != 1.0)
|
||||
{
|
||||
for (int i = 0; i < aw_x_bw; i++) { Cdata[i] *= beta; }
|
||||
}
|
||||
|
||||
TC *c = Cdata;
|
||||
for (int i = 0; i < Bwidth; ++i)
|
||||
{
|
||||
for (int j = 0; j < Awidth; ++j)
|
||||
{
|
||||
TC val = 0.0;
|
||||
for (int k = 0; k < Aheight; ++k)
|
||||
{
|
||||
val += alpha * Adata[j * Aheight + k] * Bdata[i * Aheight + k];
|
||||
}
|
||||
*c += val;
|
||||
c++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** @brief Multiply the transpose of a matrix of size @a Aheight x @a Awidth
|
||||
and data @a Adata with a matrix of size @a Aheight x @a Bwidth and data @a
|
||||
Bdata: At * B. Return the result in a matrix with data @a AtBdata. */
|
||||
@@ -410,20 +447,7 @@ MFEM_HOST_DEVICE inline
|
||||
void MultAtB(const int Aheight, const int Awidth, const int Bwidth,
|
||||
const TA *Adata, const TB *Bdata, TC *AtBdata)
|
||||
{
|
||||
TC *c = AtBdata;
|
||||
for (int i = 0; i < Bwidth; ++i)
|
||||
{
|
||||
for (int j = 0; j < Awidth; ++j)
|
||||
{
|
||||
TC val = 0.0;
|
||||
for (int k = 0; k < Aheight; ++k)
|
||||
{
|
||||
val += Adata[j * Aheight + k] * Bdata[i * Aheight + k];
|
||||
}
|
||||
*c = val;
|
||||
c++;
|
||||
}
|
||||
}
|
||||
AddMultAtB(Aheight, Awidth, Bwidth, Adata, Bdata, AtBdata, TB(1.0), TA(0.0));
|
||||
}
|
||||
|
||||
/// Given a matrix of size 2x1, 3x1, or 3x2, compute the left inverse.
|
||||
|
||||
+1
-1
@@ -28,7 +28,7 @@
|
||||
#include "symmat.hpp"
|
||||
#include "ode.hpp"
|
||||
#include "solvers.hpp"
|
||||
#include "handle.hpp"
|
||||
#include "op_handle.hpp"
|
||||
#include "invariants.hpp"
|
||||
#include "constraints.hpp"
|
||||
#include "auxiliary.hpp"
|
||||
|
||||
+315
-235
@@ -9,12 +9,155 @@
|
||||
// terms of the BSD-3 license. We welcome feedback and contributions, see file
|
||||
// CONTRIBUTING.md for details.
|
||||
|
||||
#include "../general/communication.hpp"
|
||||
#include "operator.hpp"
|
||||
#include "ode.hpp"
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
std::string ODESolver::ExplicitTypes =
|
||||
"\n\tExplicit solver: \n\t"
|
||||
" RK : 1 - Forward Euler, 2 - RK2(0.5), 3 - RK3 SSP, 4 - RK4, 6 - RK6,\n\t"
|
||||
" AB : 11 - AB1, 12 - AB2, 13 - AB3, 14 - AB4, 15 - AB5\n";
|
||||
|
||||
std::string ODESolver::ImplicitTypes =
|
||||
"\n\tImplicit solver: \n\t"
|
||||
" (L-Stab): 21 - Backward Euler, 22 - SDIRK23(2), 23 - SDIRK33,\n\t"
|
||||
" (A-Stab): 32 - Implicit Midpoint, 33 - SDIRK23, 34 - SDIRK34,\n\t"
|
||||
" GA : 40 -- 50 - Generalized-alpha,\n\t"
|
||||
" AM : 51 - AM1, 52 - AM2, 53 - AM3, 54 - AM4\n";
|
||||
|
||||
std::string ODESolver::Types = ODESolver::ExplicitTypes +
|
||||
ODESolver::ImplicitTypes;
|
||||
|
||||
std::unique_ptr<ODESolver> ODESolver::Select(int ode_solver_type)
|
||||
{
|
||||
if (ode_solver_type < 20)
|
||||
{
|
||||
return SelectExplicit(ode_solver_type);
|
||||
}
|
||||
else
|
||||
{
|
||||
return SelectImplicit(ode_solver_type);
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<ODESolver> ODESolver::SelectExplicit(int ode_solver_type)
|
||||
{
|
||||
using ode_ptr = std::unique_ptr<ODESolver>;
|
||||
switch (ode_solver_type)
|
||||
{
|
||||
// Explicit RK methods
|
||||
case 1: return ode_ptr(new ForwardEulerSolver);
|
||||
case 2: return ode_ptr(new RK2Solver(0.5)); // midpoint method
|
||||
case 3: return ode_ptr(new RK3SSPSolver);
|
||||
case 4: return ode_ptr(new RK4Solver);
|
||||
case 6: return ode_ptr(new RK6Solver);
|
||||
|
||||
// Explicit AB methods
|
||||
case 11: return ode_ptr(new AB1Solver);
|
||||
case 12: return ode_ptr(new AB2Solver);
|
||||
case 13: return ode_ptr(new AB3Solver);
|
||||
case 14: return ode_ptr(new AB4Solver);
|
||||
case 15: return ode_ptr(new AB5Solver);
|
||||
|
||||
default:
|
||||
MFEM_ABORT("Unknown ODE solver type: " << ode_solver_type);
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<ODESolver> ODESolver::SelectImplicit(int ode_solver_type)
|
||||
{
|
||||
using ode_ptr = std::unique_ptr<ODESolver>;
|
||||
switch (ode_solver_type)
|
||||
{
|
||||
// Implicit L-stable methods
|
||||
case 21: return ode_ptr(new BackwardEulerSolver);
|
||||
case 22: return ode_ptr(new SDIRK23Solver(2));
|
||||
case 23: return ode_ptr(new SDIRK33Solver);
|
||||
|
||||
// Implicit A-stable methods (not L-stable)
|
||||
case 32: return ode_ptr(new ImplicitMidpointSolver);
|
||||
case 33: return ode_ptr(new SDIRK23Solver);
|
||||
case 34: return ode_ptr(new SDIRK34Solver);
|
||||
|
||||
// Implicit generalized alpha
|
||||
case 40: return ode_ptr(new GeneralizedAlphaSolver(0.0));
|
||||
case 41: return ode_ptr(new GeneralizedAlphaSolver(0.1));
|
||||
case 42: return ode_ptr(new GeneralizedAlphaSolver(0.2));
|
||||
case 43: return ode_ptr(new GeneralizedAlphaSolver(0.3));
|
||||
case 44: return ode_ptr(new GeneralizedAlphaSolver(0.4));
|
||||
case 45: return ode_ptr(new GeneralizedAlphaSolver(0.5));
|
||||
case 46: return ode_ptr(new GeneralizedAlphaSolver(0.6));
|
||||
case 47: return ode_ptr(new GeneralizedAlphaSolver(0.7));
|
||||
case 48: return ode_ptr(new GeneralizedAlphaSolver(0.8));
|
||||
case 49: return ode_ptr(new GeneralizedAlphaSolver(0.9));
|
||||
case 50: return ode_ptr(new GeneralizedAlphaSolver(1.0));
|
||||
|
||||
// Implicit AM methods
|
||||
case 51: return ode_ptr(new AM1Solver);
|
||||
case 52: return ode_ptr(new AM2Solver);
|
||||
case 53: return ode_ptr(new AM3Solver);
|
||||
case 54: return ode_ptr(new AM4Solver);
|
||||
|
||||
default:
|
||||
MFEM_ABORT("Unknown ODE solver type: " << ode_solver_type );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ODEStateDataVector::SetSize( int vsize, MemoryType m_t)
|
||||
{
|
||||
mem_type = m_t;
|
||||
for (int i = 0; i < smax; i++)
|
||||
{
|
||||
idx[i] = smax - i - 1;
|
||||
data[i].SetSize(vsize, mem_type);
|
||||
}
|
||||
|
||||
ss = 0;
|
||||
}
|
||||
|
||||
const Vector &ODEStateDataVector::Get(int i) const
|
||||
{
|
||||
MFEM_ASSERT_INDEX_IN_RANGE(i,0,ss);
|
||||
return data[idx[i]];
|
||||
}
|
||||
|
||||
Vector &ODEStateDataVector::Get(int i)
|
||||
{
|
||||
MFEM_ASSERT_INDEX_IN_RANGE(i,0,ss);
|
||||
return data[idx[i]];
|
||||
}
|
||||
|
||||
void ODEStateDataVector::Get(int i, Vector &vec) const
|
||||
{
|
||||
MFEM_ASSERT_INDEX_IN_RANGE(i,0,ss);
|
||||
vec = data[idx[i]];
|
||||
}
|
||||
|
||||
void ODEStateDataVector::Set(int i, Vector &state)
|
||||
{
|
||||
MFEM_ASSERT_INDEX_IN_RANGE(i,0,smax);
|
||||
data[idx[i]] = state;
|
||||
}
|
||||
|
||||
void ODEStateDataVector::Append(Vector &state)
|
||||
{
|
||||
ShiftStages();
|
||||
data[idx[0]] = state;
|
||||
Increment();
|
||||
}
|
||||
|
||||
void ODEStateDataVector::Print(std::ostream &os) const
|
||||
{
|
||||
os << ss <<"/" <<smax<<std::endl;
|
||||
idx.Print(os);
|
||||
for (int i = 0; i < ss; i++) { data[idx[i]].Print(os); }
|
||||
}
|
||||
|
||||
|
||||
void ODESolver::Init(TimeDependentOperator &f_)
|
||||
{
|
||||
this->f = &f_;
|
||||
@@ -344,104 +487,65 @@ const real_t RK8Solver::c[] =
|
||||
};
|
||||
|
||||
|
||||
AdamsBashforthSolver::AdamsBashforthSolver(int s_, const real_t *a_)
|
||||
AdamsBashforthSolver::AdamsBashforthSolver(int s_, const real_t *a_):
|
||||
stages(s_), state(s_)
|
||||
{
|
||||
smax = std::min(s_,5);
|
||||
a = a_;
|
||||
k = new Vector[5];
|
||||
dt_ = -1.0;
|
||||
|
||||
if (smax <= 2)
|
||||
{
|
||||
RKsolver = new RK2Solver();
|
||||
}
|
||||
else if (smax == 3)
|
||||
{
|
||||
RKsolver = new RK3SSPSolver();
|
||||
}
|
||||
else
|
||||
{
|
||||
RKsolver = new RK4Solver();
|
||||
}
|
||||
}
|
||||
|
||||
void AdamsBashforthSolver::GetStateVector(int i, Vector &state)
|
||||
{
|
||||
MFEM_ASSERT( (i >= 0) && ( i < s ),
|
||||
" AdamsBashforthSolver::GetStateVector \n" <<
|
||||
" - Tried to get non-existent state "<<i);
|
||||
|
||||
state = k[idx[i]];
|
||||
}
|
||||
|
||||
const Vector &AdamsBashforthSolver::GetStateVector(int i)
|
||||
{
|
||||
MFEM_ASSERT( (i >= 0) && ( i < s ),
|
||||
" AdamsBashforthSolver::GetStateVector \n" <<
|
||||
" - Tried to get non-existent state "<<i);
|
||||
|
||||
return k[idx[i]];
|
||||
}
|
||||
|
||||
|
||||
void AdamsBashforthSolver::SetStateVector(int i, Vector &state)
|
||||
{
|
||||
MFEM_ASSERT( (i >= 0) && ( i < smax ),
|
||||
" AdamsBashforthSolver::SetStateVector \n" <<
|
||||
" - Tried to set non-existent state "<<i);
|
||||
k[idx[i]] = state;
|
||||
s = std::max(i,s);
|
||||
}
|
||||
|
||||
void AdamsBashforthSolver::Init(TimeDependentOperator &f_)
|
||||
{
|
||||
ODESolver::Init(f_);
|
||||
RKsolver->Init(f_);
|
||||
idx.SetSize(smax);
|
||||
for (int i = 0; i < smax; i++)
|
||||
{
|
||||
idx[i] = (smax-i)%smax;
|
||||
k[i].SetSize(f->Width());
|
||||
}
|
||||
s = 0;
|
||||
if (RKsolver) { RKsolver->Init(f_); }
|
||||
state.SetSize(f->Width(), mem_type);
|
||||
dt_ = -1.0;
|
||||
}
|
||||
|
||||
void AdamsBashforthSolver::Step(Vector &x, real_t &t, real_t &dt)
|
||||
{
|
||||
if ( (dt_ > 0.0) && (fabs(dt-dt_) >10*std::numeric_limits<real_t>::epsilon()))
|
||||
CheckTimestep(dt);
|
||||
|
||||
if (state.Size() >= stages -1)
|
||||
{
|
||||
s = 0;
|
||||
f->SetTime(t);
|
||||
f->Mult(x, state[0]);
|
||||
state.Increment();
|
||||
for (int i = 0; i < stages; i++)
|
||||
{
|
||||
x.Add(a[i]*dt, state[i]);
|
||||
}
|
||||
t += dt;
|
||||
}
|
||||
else
|
||||
{
|
||||
f->Mult(x,state[0]);
|
||||
RKsolver->Step(x,t,dt);
|
||||
state.Increment();
|
||||
}
|
||||
|
||||
state.ShiftStages();
|
||||
}
|
||||
|
||||
void AdamsBashforthSolver::CheckTimestep(real_t dt)
|
||||
{
|
||||
if (dt_ < 0.0)
|
||||
{
|
||||
dt_ = dt;
|
||||
return;
|
||||
}
|
||||
else if (fabs(dt-dt_) >10*std::numeric_limits<real_t>::epsilon())
|
||||
{
|
||||
state.Reset();
|
||||
dt_ = dt;
|
||||
|
||||
if (print())
|
||||
{
|
||||
mfem::out << "WARNING:" << std::endl;
|
||||
mfem::out << " - Time step changed" << std::endl;
|
||||
mfem::out << " - Purging Adams-Bashforth history" << std::endl;
|
||||
mfem::out << " - Purging time stepping history" << std::endl;
|
||||
mfem::out << " - Will run Runge-Kutta to rebuild history" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
s++;
|
||||
s = std::min(s, smax);
|
||||
if (s == smax)
|
||||
{
|
||||
f->SetTime(t);
|
||||
f->Mult(x, k[idx[0]]);
|
||||
for (int i = 0; i < s; i++)
|
||||
{
|
||||
x.Add(a[i]*dt, k[idx[i]]);
|
||||
}
|
||||
t += dt;
|
||||
}
|
||||
else
|
||||
{
|
||||
f->Mult(x,k[idx[0]]);
|
||||
RKsolver->Step(x,t,dt);
|
||||
}
|
||||
|
||||
// Shift the index
|
||||
for (int i = 0; i < smax; i++) { idx[i] = ++idx[i]%smax; }
|
||||
}
|
||||
|
||||
const real_t AB1Solver::a[] =
|
||||
@@ -455,110 +559,68 @@ const real_t AB4Solver::a[] =
|
||||
const real_t AB5Solver::a[] =
|
||||
{1901.0/720.0,-2774.0/720.0, 2616.0/720.0,-1274.0/720.0, 251.0/720.0};
|
||||
|
||||
AdamsMoultonSolver::AdamsMoultonSolver(int s_, const real_t *a_)
|
||||
|
||||
AdamsMoultonSolver::AdamsMoultonSolver(int s_, const real_t *a_):
|
||||
stages(s_), state(s_)
|
||||
{
|
||||
s = 0;
|
||||
smax = std::min(s_+1,5);
|
||||
a = a_;
|
||||
k = new Vector[5];
|
||||
dt_ = -1.0;
|
||||
|
||||
if (smax <= 3)
|
||||
{
|
||||
RKsolver = new SDIRK23Solver();
|
||||
}
|
||||
else
|
||||
{
|
||||
RKsolver = new SDIRK34Solver();
|
||||
}
|
||||
}
|
||||
|
||||
const Vector &AdamsMoultonSolver::GetStateVector(int i)
|
||||
{
|
||||
MFEM_ASSERT( (i >= 0) && ( i < s ),
|
||||
" AdamsMoultonSolver::GetStateVector \n" <<
|
||||
" - Tried to get non-existent state "<<i);
|
||||
return k[idx[i+1]];
|
||||
}
|
||||
|
||||
void AdamsMoultonSolver::GetStateVector(int i, Vector &state)
|
||||
{
|
||||
MFEM_ASSERT( (i >= 0) && ( i < s ),
|
||||
" AdamsMoultonSolver::GetStateVector \n" <<
|
||||
" - Tried to get non-existent state "<<i);
|
||||
state = k[idx[i+1]];
|
||||
}
|
||||
|
||||
void AdamsMoultonSolver::SetStateVector(int i, Vector &state)
|
||||
{
|
||||
MFEM_ASSERT( (i >= 0) && ( i < smax ),
|
||||
" AdamsMoultonSolver::SetStateVector \n" <<
|
||||
" - Tried to set non-existent state "<<i);
|
||||
k[idx[i+1]] = state;
|
||||
s = std::max(i,s);
|
||||
}
|
||||
|
||||
void AdamsMoultonSolver::Init(TimeDependentOperator &f_)
|
||||
{
|
||||
ODESolver::Init(f_);
|
||||
RKsolver->Init(f_);
|
||||
int n = f->Width();
|
||||
idx.SetSize(smax);
|
||||
for (int i = 0; i < smax; i++)
|
||||
{
|
||||
idx[i] = (smax-i)%smax;
|
||||
k[i].SetSize(n);
|
||||
}
|
||||
s = 0;
|
||||
if (RKsolver) { RKsolver->Init(f_); }
|
||||
state.SetSize(f->Width(), mem_type);
|
||||
dt_ = -1.0;
|
||||
}
|
||||
|
||||
void AdamsMoultonSolver::Step(Vector &x, real_t &t, real_t &dt)
|
||||
{
|
||||
if ( (dt_ > 0.0) && (fabs(dt-dt_) >10*std::numeric_limits<real_t>::epsilon()))
|
||||
if (dt_ < 0.0)
|
||||
{
|
||||
s = 0;
|
||||
dt_ = dt;
|
||||
}
|
||||
else if (fabs(dt-dt_) > 10*std::numeric_limits<real_t>::epsilon())
|
||||
{
|
||||
state.Reset();
|
||||
dt_ = dt;
|
||||
|
||||
if (print())
|
||||
{
|
||||
mfem::out << "WARNING:" << std::endl;
|
||||
mfem::out << " - Time step changed" << std::endl;
|
||||
mfem::out << " - Purging Adams-Moulton history" << std::endl;
|
||||
mfem::out << " - Purging time stepping history" << std::endl;
|
||||
mfem::out << " - Will run Runge-Kutta to rebuild history" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
if ((s == 0)&&(smax>1))
|
||||
if ((state.Size() == 0)&&(stages>1))
|
||||
{
|
||||
f->Mult(x,k[idx[1]]);
|
||||
f->Mult(x,state[0]);
|
||||
state.Increment();
|
||||
}
|
||||
s++;
|
||||
s = std::min(s, smax);
|
||||
|
||||
if (s >= smax-1)
|
||||
if (state.Size() >= stages )
|
||||
{
|
||||
f->SetTime(t);
|
||||
for (int i = 1; i < smax; i++)
|
||||
for (int i = 0; i < stages; i++)
|
||||
{
|
||||
x.Add(a[i]*dt, k[idx[i]]);
|
||||
x.Add(a[i+1]*dt, state[i]);
|
||||
}
|
||||
f->ImplicitSolve(a[0]*dt, x, k[idx[0]]);
|
||||
x.Add(a[0]*dt, k[idx[0]]);
|
||||
state.ShiftStages();
|
||||
f->ImplicitSolve(a[0]*dt, x, state[0]);
|
||||
x.Add(a[0]*dt, state[0]);
|
||||
t += dt;
|
||||
}
|
||||
else
|
||||
{
|
||||
state.ShiftStages();
|
||||
RKsolver->Step(x,t,dt);
|
||||
f->Mult(x,k[idx[0]]);
|
||||
f->Mult(x,state[0]);
|
||||
state.Increment();
|
||||
}
|
||||
|
||||
|
||||
// Shift the index
|
||||
for (int i = 0; i < smax; i++) { idx[i] = ++idx[i]%smax; }
|
||||
}
|
||||
|
||||
const real_t AM0Solver::a[] =
|
||||
{1.0};
|
||||
const real_t AM1Solver::a[] =
|
||||
{0.5, 0.5};
|
||||
const real_t AM2Solver::a[] =
|
||||
@@ -817,34 +879,7 @@ void GeneralizedAlphaSolver::Init(TimeDependentOperator &f_)
|
||||
ODESolver::Init(f_);
|
||||
k.SetSize(f->Width(), mem_type);
|
||||
y.SetSize(f->Width(), mem_type);
|
||||
xdot.SetSize(f->Width(), mem_type);
|
||||
xdot = 0.0;
|
||||
nstate = 0;
|
||||
}
|
||||
|
||||
const Vector &GeneralizedAlphaSolver::GetStateVector(int i)
|
||||
{
|
||||
MFEM_ASSERT( (i == 0) && (nstate == 1),
|
||||
"GeneralizedAlphaSolver::GetStateVector \n" <<
|
||||
" - Tried to get non-existent state "<<i);
|
||||
return xdot;
|
||||
}
|
||||
|
||||
void GeneralizedAlphaSolver::GetStateVector(int i, Vector &state)
|
||||
{
|
||||
MFEM_ASSERT( (i == 0) && (nstate == 1),
|
||||
"GeneralizedAlphaSolver::GetStateVector \n" <<
|
||||
" - Tried to get non-existent state "<<i);
|
||||
state = xdot;
|
||||
}
|
||||
|
||||
void GeneralizedAlphaSolver::SetStateVector(int i, Vector &state)
|
||||
{
|
||||
MFEM_ASSERT( (i == 0),
|
||||
"GeneralizedAlphaSolver::SetStateVector \n" <<
|
||||
" - Tried to set non-existent state "<<i);
|
||||
xdot = state;
|
||||
nstate = 1;
|
||||
state.SetSize(f->Width(), mem_type);
|
||||
}
|
||||
|
||||
void GeneralizedAlphaSolver::SetRhoInf(real_t rho_inf)
|
||||
@@ -884,17 +919,17 @@ void GeneralizedAlphaSolver::PrintProperties(std::ostream &os)
|
||||
}
|
||||
}
|
||||
|
||||
// This routine assumes xdot is initialized.
|
||||
// This routine state[0] represents xdot
|
||||
void GeneralizedAlphaSolver::Step(Vector &x, real_t &t, real_t &dt)
|
||||
{
|
||||
if (nstate == 0)
|
||||
if (state.Size() == 0)
|
||||
{
|
||||
f->Mult(x,xdot);
|
||||
nstate = 1;
|
||||
f->Mult(x,state[0]);
|
||||
state.Increment();
|
||||
}
|
||||
|
||||
// Set y = x + alpha_f*(1.0 - (gamma/alpha_m))*dt*xdot
|
||||
add(x, alpha_f*(1.0 - (gamma/alpha_m))*dt, xdot, y);
|
||||
add(x, alpha_f*(1.0 - (gamma/alpha_m))*dt, state[0], y);
|
||||
|
||||
// Solve k = f(y + dt_eff*k)
|
||||
real_t dt_eff = (gamma*alpha_f/alpha_m)*dt;
|
||||
@@ -902,11 +937,11 @@ void GeneralizedAlphaSolver::Step(Vector &x, real_t &t, real_t &dt)
|
||||
f->ImplicitSolve(dt_eff, y, k);
|
||||
|
||||
// Update x and xdot
|
||||
x.Add((1.0 - (gamma/alpha_m))*dt, xdot);
|
||||
x.Add((1.0 - (gamma/alpha_m))*dt, state[0]);
|
||||
x.Add( (gamma/alpha_m) *dt, k);
|
||||
|
||||
xdot *= (1.0-(1.0/alpha_m));
|
||||
xdot.Add((1.0/alpha_m),k);
|
||||
state[0] *= (1.0-(1.0/alpha_m));
|
||||
state[0].Add((1.0/alpha_m),k);
|
||||
|
||||
t += dt;
|
||||
}
|
||||
@@ -1017,18 +1052,75 @@ SIAVSolver::Step(Vector &q, Vector &p, real_t &t, real_t &dt)
|
||||
}
|
||||
}
|
||||
|
||||
std::string SecondOrderODESolver::Types =
|
||||
"ODE solver: \n\t"
|
||||
" [0--10] - GeneralizedAlpha(0.1 * s),\n\t"
|
||||
" 11 - Average Acceleration, 12 - Linear Acceleration\n\t"
|
||||
" 13 - CentralDifference, 14 - FoxGoodwin";
|
||||
|
||||
SecondOrderODESolver* SecondOrderODESolver::Select(int ode_solver_type)
|
||||
{
|
||||
SecondOrderODESolver* ode_solver = NULL;
|
||||
switch (ode_solver_type)
|
||||
{
|
||||
// Implicit methods
|
||||
case 0: ode_solver = new GeneralizedAlpha2Solver(0.0); break;
|
||||
case 1: ode_solver = new GeneralizedAlpha2Solver(0.1); break;
|
||||
case 2: ode_solver = new GeneralizedAlpha2Solver(0.2); break;
|
||||
case 3: ode_solver = new GeneralizedAlpha2Solver(0.3); break;
|
||||
case 4: ode_solver = new GeneralizedAlpha2Solver(0.4); break;
|
||||
case 5: ode_solver = new GeneralizedAlpha2Solver(0.5); break;
|
||||
case 6: ode_solver = new GeneralizedAlpha2Solver(0.6); break;
|
||||
case 7: ode_solver = new GeneralizedAlpha2Solver(0.7); break;
|
||||
case 8: ode_solver = new GeneralizedAlpha2Solver(0.8); break;
|
||||
case 9: ode_solver = new GeneralizedAlpha2Solver(0.9); break;
|
||||
case 10: ode_solver = new GeneralizedAlpha2Solver(1.0); break;
|
||||
|
||||
case 11: ode_solver = new AverageAccelerationSolver(); break;
|
||||
case 12: ode_solver = new LinearAccelerationSolver(); break;
|
||||
case 13: ode_solver = new CentralDifferenceSolver(); break;
|
||||
case 14: ode_solver = new FoxGoodwinSolver(); break;
|
||||
|
||||
default:
|
||||
MFEM_ABORT("Unknown ODE solver type: " << ode_solver_type);
|
||||
}
|
||||
return ode_solver;
|
||||
}
|
||||
|
||||
// In this routine state[0] represents d2xdt2
|
||||
void SecondOrderODESolver::EulerStep(Vector &x, Vector &dxdt, real_t &t,
|
||||
real_t &dt)
|
||||
{
|
||||
x.Add(dt, dxdt);
|
||||
|
||||
f->SetTime(t + dt);
|
||||
f->ImplicitSolve(0.5*dt*dt, dt, x, dxdt, state[0]);
|
||||
|
||||
x .Add(0.5*dt*dt, state[0]);
|
||||
dxdt.Add(dt, state[0]);
|
||||
t += dt;
|
||||
}
|
||||
|
||||
// In this routine state[0] represents d2xdt2
|
||||
void SecondOrderODESolver::MidPointStep(Vector &x, Vector &dxdt, real_t &t,
|
||||
real_t &dt)
|
||||
{
|
||||
x.Add(0.5*dt, dxdt);
|
||||
|
||||
f->SetTime(t + dt);
|
||||
f->ImplicitSolve(0.25*dt*dt, 0.5*dt, x, dxdt, state[0]);
|
||||
|
||||
x.Add(0.5*dt, dxdt);
|
||||
x.Add(0.5*dt*dt, state[0]);
|
||||
dxdt.Add(dt, state[0]);
|
||||
t += dt;
|
||||
}
|
||||
|
||||
void SecondOrderODESolver::Init(SecondOrderTimeDependentOperator &f_)
|
||||
{
|
||||
this->f = &f_;
|
||||
mem_type = GetMemoryType(f_.GetMemoryClass());
|
||||
}
|
||||
|
||||
void NewmarkSolver::Init(SecondOrderTimeDependentOperator &f_)
|
||||
{
|
||||
SecondOrderODESolver::Init(f_);
|
||||
d2xdt2.SetSize(f->Width());
|
||||
d2xdt2 = 0.0;
|
||||
first = true;
|
||||
state.SetSize(f->Width(), mem_type);
|
||||
}
|
||||
|
||||
void NewmarkSolver::PrintProperties(std::ostream &os)
|
||||
@@ -1060,6 +1152,7 @@ void NewmarkSolver::PrintProperties(std::ostream &os)
|
||||
}
|
||||
}
|
||||
|
||||
// In this routine state[0] represents d2xdt2
|
||||
void NewmarkSolver::Step(Vector &x, Vector &dxdt, real_t &t, real_t &dt)
|
||||
{
|
||||
real_t fac0 = 0.5 - beta;
|
||||
@@ -1068,60 +1161,38 @@ void NewmarkSolver::Step(Vector &x, Vector &dxdt, real_t &t, real_t &dt)
|
||||
real_t fac4 = gamma;
|
||||
|
||||
// In the first pass compute d2xdt2 directly from operator.
|
||||
if (first)
|
||||
if (state.Size() == 0)
|
||||
{
|
||||
f->Mult(x, dxdt, d2xdt2);
|
||||
first = false;
|
||||
if (no_mult)
|
||||
{
|
||||
MidPointStep(x, dxdt, t, dt);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
f->Mult(x, dxdt, state[0]);
|
||||
}
|
||||
}
|
||||
f->SetTime(t + dt);
|
||||
|
||||
x.Add(dt, dxdt);
|
||||
x.Add(fac0*dt*dt, d2xdt2);
|
||||
dxdt.Add(fac2*dt, d2xdt2);
|
||||
x.Add(fac0*dt*dt, state[0]);
|
||||
dxdt.Add(fac2*dt, state[0]);
|
||||
|
||||
f->SetTime(t + dt);
|
||||
f->ImplicitSolve(fac3*dt*dt, fac4*dt, x, dxdt, d2xdt2);
|
||||
f->ImplicitSolve(fac3*dt*dt, fac4*dt, x, dxdt, state[0]);
|
||||
|
||||
x .Add(fac3*dt*dt, d2xdt2);
|
||||
dxdt.Add(fac4*dt, d2xdt2);
|
||||
x .Add(fac3*dt*dt, state[0]);
|
||||
dxdt.Add(fac4*dt, state[0]);
|
||||
t += dt;
|
||||
}
|
||||
|
||||
void GeneralizedAlpha2Solver::Init(SecondOrderTimeDependentOperator &f_)
|
||||
{
|
||||
SecondOrderODESolver::Init(f_);
|
||||
xa.SetSize(f->Width());
|
||||
va.SetSize(f->Width());
|
||||
aa.SetSize(f->Width());
|
||||
d2xdt2.SetSize(f->Width());
|
||||
d2xdt2 = 0.0;
|
||||
nstate = 0;
|
||||
}
|
||||
|
||||
const Vector &GeneralizedAlpha2Solver::GetStateVector(int i)
|
||||
{
|
||||
MFEM_ASSERT( (i == 0) && (nstate == 1),
|
||||
"GeneralizedAlpha2Solver::GetStateVector \n" <<
|
||||
" - Tried to get non-existent state "<<i);
|
||||
return d2xdt2;
|
||||
}
|
||||
|
||||
|
||||
void GeneralizedAlpha2Solver::GetStateVector(int i, Vector &state)
|
||||
{
|
||||
MFEM_ASSERT( (i == 0) && (nstate == 1),
|
||||
"GeneralizedAlpha2Solver::GetStateVector \n" <<
|
||||
" - Tried to get non-existent state "<<i);
|
||||
state = d2xdt2;
|
||||
}
|
||||
|
||||
void GeneralizedAlpha2Solver::SetStateVector(int i, Vector &state)
|
||||
{
|
||||
MFEM_ASSERT( (i == 0),
|
||||
"GeneralizedAlpha2Solver::SetStateVector \n" <<
|
||||
" - Tried to set non-existent state "<<i);
|
||||
d2xdt2 = state;
|
||||
nstate = 1;
|
||||
xa.SetSize(f->Width(), mem_type);
|
||||
va.SetSize(f->Width(), mem_type);
|
||||
aa.SetSize(f->Width(), mem_type);
|
||||
}
|
||||
|
||||
void GeneralizedAlpha2Solver::PrintProperties(std::ostream &os)
|
||||
@@ -1153,6 +1224,7 @@ void GeneralizedAlpha2Solver::PrintProperties(std::ostream &os)
|
||||
}
|
||||
}
|
||||
|
||||
// In this routine state[0] represents d2xdt2
|
||||
void GeneralizedAlpha2Solver::Step(Vector &x, Vector &dxdt,
|
||||
real_t &t, real_t &dt)
|
||||
{
|
||||
@@ -1164,16 +1236,24 @@ void GeneralizedAlpha2Solver::Step(Vector &x, Vector &dxdt,
|
||||
real_t fac5 = alpha_m;
|
||||
|
||||
// In the first pass compute d2xdt2 directly from operator.
|
||||
if (nstate == 0)
|
||||
if (state.Size() == 0)
|
||||
{
|
||||
f->Mult(x, dxdt, d2xdt2);
|
||||
nstate = 1;
|
||||
if (no_mult)
|
||||
{
|
||||
MidPointStep(x, dxdt, t, dt);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
f->Mult(x, dxdt, state[0]);
|
||||
}
|
||||
state.Increment();
|
||||
}
|
||||
|
||||
// Predict alpha levels
|
||||
add(dxdt, fac0*dt, d2xdt2, va);
|
||||
add(dxdt, fac0*dt, state[0], va);
|
||||
add(x, fac1*dt, va, xa);
|
||||
add(dxdt, fac2*dt, d2xdt2, va);
|
||||
add(dxdt, fac2*dt, state[0], va);
|
||||
|
||||
// Solve alpha levels
|
||||
f->SetTime(t + dt);
|
||||
@@ -1190,8 +1270,8 @@ void GeneralizedAlpha2Solver::Step(Vector &x, Vector &dxdt,
|
||||
dxdt *= 1.0 - 1.0/fac1;
|
||||
dxdt.Add (1.0/fac1, va);
|
||||
|
||||
d2xdt2 *= 1.0 - 1.0/fac5;
|
||||
d2xdt2.Add (1.0/fac5, aa);
|
||||
state[0] *= 1.0 - 1.0/fac5;
|
||||
state[0].Add (1.0/fac5, aa);
|
||||
|
||||
t += dt;
|
||||
}
|
||||
|
||||
+319
-246
@@ -12,13 +12,99 @@
|
||||
#ifndef MFEM_ODE
|
||||
#define MFEM_ODE
|
||||
|
||||
#include "../general/communication.hpp"
|
||||
#include "../config/config.hpp"
|
||||
#include "operator.hpp"
|
||||
#include "../general/communication.hpp"
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
/// An interface for storing state of previous timesteps
|
||||
class ODEStateData
|
||||
{
|
||||
public:
|
||||
/// Get the maximum number of stored stages
|
||||
virtual int MaxSize() const = 0;
|
||||
|
||||
/// Get the current number of stored stages
|
||||
virtual int Size() const = 0;
|
||||
|
||||
/// Get the ith state vector
|
||||
virtual const Vector &Get(int i) const = 0;
|
||||
|
||||
/// Get the ith state vector - non-const version
|
||||
virtual Vector &Get(int i) = 0;
|
||||
|
||||
/// Get the ith state vector - with a copy
|
||||
virtual void Get(int i, Vector &vec) const = 0;
|
||||
|
||||
/// Set the ith state vector
|
||||
virtual void Set(int i, Vector &state) = 0;
|
||||
|
||||
/// Add state vector and increment state size
|
||||
virtual void Append(Vector &state) = 0;
|
||||
|
||||
/// Virtual destructor
|
||||
virtual ~ODEStateData() = default;
|
||||
};
|
||||
|
||||
/// An implementation of ODEStateData that stores states in an std::vector<Vector>
|
||||
class ODEStateDataVector : public ODEStateData
|
||||
{
|
||||
private:
|
||||
MemoryType mem_type;
|
||||
int ss, smax;
|
||||
std::vector<Vector> data;
|
||||
Array<int> idx;
|
||||
|
||||
public:
|
||||
ODEStateDataVector (int smax): smax(smax)
|
||||
{
|
||||
data.resize(smax);
|
||||
idx.SetSize(smax);
|
||||
ss = 0;
|
||||
};
|
||||
|
||||
/// Set the number of stages and the size of the vectors
|
||||
void SetSize(int vsize, MemoryType mem_type);
|
||||
|
||||
/// Shift the stage counter for the next timestep
|
||||
inline void ShiftStages()
|
||||
{
|
||||
for (int i = 0; i < smax; i++) { idx[i] = (++idx[i])%smax; }
|
||||
};
|
||||
|
||||
/// Increment the stage counter
|
||||
void Increment() { ss++; ss = std::min(ss,smax); };
|
||||
|
||||
/// Reset the stage counter
|
||||
void Reset() { ss = 0; };
|
||||
|
||||
/// Reference access to the ith vector.
|
||||
inline Vector & operator[](int i) { return data[idx[i]]; };
|
||||
|
||||
/// Const reference access to the ith vector.
|
||||
inline const Vector &operator[](int i) const { return data[idx[i]]; };
|
||||
|
||||
/// Print state data
|
||||
void Print(std::ostream &os = mfem::out) const ;
|
||||
|
||||
int MaxSize() const override { return smax; };
|
||||
|
||||
int Size() const override { return ss; };
|
||||
|
||||
const Vector &Get(int i) const override;
|
||||
Vector &Get(int i) override;
|
||||
void Get(int i, Vector &vec) const override;
|
||||
|
||||
void Set(int i, Vector &state) override;
|
||||
|
||||
void Append(Vector &state) override;
|
||||
};
|
||||
|
||||
|
||||
/// Abstract class for solving systems of ODEs: dx/dt = f(x,t)
|
||||
class ODESolver
|
||||
{
|
||||
@@ -92,26 +178,48 @@ public:
|
||||
while (t < tf) { Step(x, t, dt); }
|
||||
}
|
||||
|
||||
/// Function for getting and setting the state vectors
|
||||
virtual int GetMaxStateSize() { return 0; }
|
||||
virtual int GetStateSize() { return 0; }
|
||||
virtual const Vector &GetStateVector(int i)
|
||||
{
|
||||
mfem_error("ODESolver has no state vectors");
|
||||
Vector *s = NULL; return *s; // Make some compiler happy
|
||||
}
|
||||
virtual void GetStateVector(int i, Vector &state)
|
||||
{
|
||||
mfem_error("ODESolver has no state vectors");
|
||||
}
|
||||
virtual void SetStateVector(int i, Vector &state)
|
||||
{
|
||||
mfem_error("ODESolver has no state vectors");
|
||||
}
|
||||
/// Returns how many State vectors the ODE requires
|
||||
virtual int GetStateSize() { return 0; };
|
||||
|
||||
// Help info for ODESolver options
|
||||
static MFEM_EXPORT std::string ExplicitTypes;
|
||||
static MFEM_EXPORT std::string ImplicitTypes;
|
||||
static MFEM_EXPORT std::string Types;
|
||||
|
||||
/// Function for selecting the desired ODESolver (Explicit and Implicit)
|
||||
/// Returns an ODESolver pointer based on an type
|
||||
/// Caller gets ownership of the object and is responsible for its deletion
|
||||
static MFEM_EXPORT std::unique_ptr<ODESolver> Select(const int ode_solver_type);
|
||||
|
||||
/// Function for selecting the desired Explicit ODESolver
|
||||
/// Returns an ODESolver pointer based on an type
|
||||
/// Caller gets ownership of the object and is responsible for its deletion
|
||||
static MFEM_EXPORT std::unique_ptr<ODESolver> SelectExplicit(
|
||||
const int ode_solver_type);
|
||||
|
||||
/// Function for selecting the desired Implicit ODESolver
|
||||
/// Returns an ODESolver pointer based on an type
|
||||
/// Caller gets ownership of the object and is responsible for its deletion
|
||||
static MFEM_EXPORT std::unique_ptr<ODESolver> SelectImplicit(
|
||||
const int ode_solver_type);
|
||||
|
||||
virtual ~ODESolver() { }
|
||||
};
|
||||
|
||||
/// Abstract class for an ODESolver that has state history implemented as ODEStateData
|
||||
class ODESolverWithStates : public ODESolver
|
||||
{
|
||||
public:
|
||||
/// Returns the StateData
|
||||
virtual ODEStateData& GetState() = 0;
|
||||
|
||||
/// Returns the StateData
|
||||
virtual const ODEStateData& GetState() const = 0;
|
||||
|
||||
/// Returns how many State vectors the ODE requires
|
||||
virtual int GetStateSize() { return GetState().MaxSize(); };
|
||||
};
|
||||
|
||||
|
||||
/// The classical forward Euler method
|
||||
class ForwardEulerSolver : public ODESolver
|
||||
@@ -217,196 +325,13 @@ public:
|
||||
class RK8Solver : public ExplicitRKSolver
|
||||
{
|
||||
private:
|
||||
static const real_t a[66], b[12], c[11];
|
||||
static MFEM_EXPORT const real_t a[66], b[12], c[11];
|
||||
|
||||
public:
|
||||
RK8Solver() : ExplicitRKSolver(12, a, b, c) { }
|
||||
};
|
||||
|
||||
|
||||
/** An explicit Adams-Bashforth method. */
|
||||
class AdamsBashforthSolver : public ODESolver
|
||||
{
|
||||
private:
|
||||
int s, smax;
|
||||
const real_t *a;
|
||||
Vector *k;
|
||||
Array<int> idx;
|
||||
ODESolver *RKsolver;
|
||||
real_t dt_;
|
||||
|
||||
inline bool print()
|
||||
{
|
||||
#ifdef MFEM_USE_MPI
|
||||
return Mpi::IsInitialized() ? Mpi::Root() : true;
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
public:
|
||||
AdamsBashforthSolver(int s_, const real_t *a_);
|
||||
|
||||
void Init(TimeDependentOperator &f_) override;
|
||||
|
||||
void Step(Vector &x, real_t &t, real_t &dt) override;
|
||||
|
||||
int GetMaxStateSize() override { return smax; };
|
||||
int GetStateSize() override { return s; };
|
||||
const Vector &GetStateVector(int i) override;
|
||||
void GetStateVector(int i, Vector &state) override;
|
||||
void SetStateVector(int i, Vector &state) override;
|
||||
|
||||
~AdamsBashforthSolver()
|
||||
{
|
||||
if (RKsolver) { delete RKsolver; }
|
||||
delete [] k;
|
||||
}
|
||||
};
|
||||
|
||||
/** A 1-stage, 1st order AB method. */
|
||||
class AB1Solver : public AdamsBashforthSolver
|
||||
{
|
||||
private:
|
||||
static MFEM_EXPORT const real_t a[1];
|
||||
|
||||
public:
|
||||
AB1Solver() : AdamsBashforthSolver(1, a) { }
|
||||
};
|
||||
|
||||
/** A 2-stage, 2nd order AB method. */
|
||||
class AB2Solver : public AdamsBashforthSolver
|
||||
{
|
||||
private:
|
||||
static MFEM_EXPORT const real_t a[2];
|
||||
|
||||
public:
|
||||
AB2Solver() : AdamsBashforthSolver(2, a) { }
|
||||
};
|
||||
|
||||
/** A 3-stage, 3rd order AB method. */
|
||||
class AB3Solver : public AdamsBashforthSolver
|
||||
{
|
||||
private:
|
||||
static MFEM_EXPORT const real_t a[3];
|
||||
|
||||
public:
|
||||
AB3Solver() : AdamsBashforthSolver(3, a) { }
|
||||
};
|
||||
|
||||
/** A 4-stage, 4th order AB method. */
|
||||
class AB4Solver : public AdamsBashforthSolver
|
||||
{
|
||||
private:
|
||||
static MFEM_EXPORT const real_t a[4];
|
||||
|
||||
public:
|
||||
AB4Solver() : AdamsBashforthSolver(4, a) { }
|
||||
};
|
||||
|
||||
/** A 5-stage, 5th order AB method. */
|
||||
class AB5Solver : public AdamsBashforthSolver
|
||||
{
|
||||
private:
|
||||
static MFEM_EXPORT const real_t a[5];
|
||||
|
||||
public:
|
||||
AB5Solver() : AdamsBashforthSolver(5, a) { }
|
||||
};
|
||||
|
||||
|
||||
/** An implicit Adams-Moulton method. */
|
||||
class AdamsMoultonSolver : public ODESolver
|
||||
{
|
||||
private:
|
||||
int s, smax;
|
||||
const real_t *a;
|
||||
Vector *k;
|
||||
Array<int> idx;
|
||||
ODESolver *RKsolver;
|
||||
real_t dt_;
|
||||
|
||||
inline bool print()
|
||||
{
|
||||
#ifdef MFEM_USE_MPI
|
||||
return Mpi::IsInitialized() ? Mpi::Root() : true;
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
public:
|
||||
AdamsMoultonSolver(int s_, const real_t *a_);
|
||||
|
||||
void Init(TimeDependentOperator &f_) override;
|
||||
|
||||
void Step(Vector &x, real_t &t, real_t &dt) override;
|
||||
|
||||
int GetMaxStateSize() override { return smax-1; };
|
||||
int GetStateSize() override { return s-1; };
|
||||
const Vector &GetStateVector(int i) override;
|
||||
void GetStateVector(int i, Vector &state) override;
|
||||
void SetStateVector(int i, Vector &state) override;
|
||||
|
||||
~AdamsMoultonSolver()
|
||||
{
|
||||
if (RKsolver) { delete RKsolver; }
|
||||
delete [] k;
|
||||
};
|
||||
};
|
||||
|
||||
/** A 0-stage, 1st order AM method. */
|
||||
class AM0Solver : public AdamsMoultonSolver
|
||||
{
|
||||
private:
|
||||
static MFEM_EXPORT const real_t a[1];
|
||||
|
||||
public:
|
||||
AM0Solver() : AdamsMoultonSolver(0, a) { }
|
||||
};
|
||||
|
||||
|
||||
/** A 1-stage, 2nd order AM method. */
|
||||
class AM1Solver : public AdamsMoultonSolver
|
||||
{
|
||||
private:
|
||||
static MFEM_EXPORT const real_t a[2];
|
||||
|
||||
public:
|
||||
AM1Solver() : AdamsMoultonSolver(1, a) { }
|
||||
};
|
||||
|
||||
/** A 2-stage, 3rd order AM method. */
|
||||
class AM2Solver : public AdamsMoultonSolver
|
||||
{
|
||||
private:
|
||||
static MFEM_EXPORT const real_t a[3];
|
||||
|
||||
public:
|
||||
AM2Solver() : AdamsMoultonSolver(2, a) { }
|
||||
};
|
||||
|
||||
/** A 3-stage, 4th order AM method. */
|
||||
class AM3Solver : public AdamsMoultonSolver
|
||||
{
|
||||
private:
|
||||
static MFEM_EXPORT const real_t a[4];
|
||||
|
||||
public:
|
||||
AM3Solver() : AdamsMoultonSolver(3, a) { }
|
||||
};
|
||||
|
||||
/** A 4-stage, 5th order AM method. */
|
||||
class AM4Solver : public AdamsMoultonSolver
|
||||
{
|
||||
private:
|
||||
static MFEM_EXPORT const real_t a[5];
|
||||
|
||||
public:
|
||||
AM4Solver() : AdamsMoultonSolver(4, a) { }
|
||||
};
|
||||
|
||||
|
||||
/// Backward Euler ODE solver. L-stable.
|
||||
class BackwardEulerSolver : public ODESolver
|
||||
{
|
||||
@@ -527,31 +452,183 @@ public:
|
||||
/// Generalized-alpha ODE solver from "A generalized-α method for integrating
|
||||
/// the filtered Navier-Stokes equations with a stabilized finite element
|
||||
/// method" by K.E. Jansen, C.H. Whiting and G.M. Hulbert.
|
||||
class GeneralizedAlphaSolver : public ODESolver
|
||||
class GeneralizedAlphaSolver : public ODESolverWithStates
|
||||
{
|
||||
ODEStateDataVector state;
|
||||
|
||||
protected:
|
||||
mutable Vector xdot,k,y;
|
||||
|
||||
mutable Vector k,y;
|
||||
real_t alpha_f, alpha_m, gamma;
|
||||
int nstate;
|
||||
|
||||
void SetRhoInf(real_t rho_inf);
|
||||
void PrintProperties(std::ostream &out = mfem::out);
|
||||
void PrintProperties(std::ostream &os = mfem::out);
|
||||
public:
|
||||
|
||||
GeneralizedAlphaSolver(real_t rho = 1.0) { SetRhoInf(rho); };
|
||||
|
||||
GeneralizedAlphaSolver(real_t rho = 1.0) : state(1) { SetRhoInf(rho); };
|
||||
void Init(TimeDependentOperator &f_) override;
|
||||
|
||||
void Step(Vector &x, real_t &t, real_t &dt) override;
|
||||
|
||||
int GetMaxStateSize() override { return 1; };
|
||||
int GetStateSize() override { return nstate; };
|
||||
const Vector &GetStateVector(int i) override;
|
||||
void GetStateVector(int i, Vector &state) override;
|
||||
void SetStateVector(int i, Vector &state) override;
|
||||
ODEStateData& GetState() override { return state; }
|
||||
const ODEStateData& GetState() const override { return state; }
|
||||
};
|
||||
|
||||
|
||||
/** An explicit Adams-Bashforth method. */
|
||||
class AdamsBashforthSolver : public ODESolverWithStates
|
||||
{
|
||||
private:
|
||||
const real_t *a;
|
||||
const int stages;
|
||||
real_t dt_;
|
||||
ODEStateDataVector state;
|
||||
|
||||
protected:
|
||||
std::unique_ptr<ODESolver> RKsolver;
|
||||
|
||||
inline bool print()
|
||||
{
|
||||
#ifdef MFEM_USE_MPI
|
||||
return Mpi::IsInitialized() ? Mpi::Root() : true;
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
void CheckTimestep(real_t dt);
|
||||
|
||||
public:
|
||||
AdamsBashforthSolver(int s_, const real_t *a_);
|
||||
void Init(TimeDependentOperator &f_) override;
|
||||
void Step(Vector &x, real_t &t, real_t &dt) override;
|
||||
|
||||
ODEStateData& GetState() override { return state; }
|
||||
const ODEStateData& GetState() const override { return state; }
|
||||
};
|
||||
|
||||
/** A 1-stage, 1st order AB method. */
|
||||
class AB1Solver : public AdamsBashforthSolver
|
||||
{
|
||||
private:
|
||||
static MFEM_EXPORT const real_t a[1];
|
||||
|
||||
public:
|
||||
AB1Solver() : AdamsBashforthSolver(1, a) { }
|
||||
};
|
||||
|
||||
/** A 2-stage, 2nd order AB method. */
|
||||
class AB2Solver : public AdamsBashforthSolver
|
||||
{
|
||||
private:
|
||||
static MFEM_EXPORT const real_t a[2];
|
||||
|
||||
public:
|
||||
AB2Solver() : AdamsBashforthSolver(2, a) { RKsolver.reset(new RK2Solver()); }
|
||||
};
|
||||
|
||||
/** A 3-stage, 3rd order AB method. */
|
||||
class AB3Solver : public AdamsBashforthSolver
|
||||
{
|
||||
private:
|
||||
static MFEM_EXPORT const real_t a[3];
|
||||
|
||||
public:
|
||||
AB3Solver() : AdamsBashforthSolver(3, a) { RKsolver.reset(new RK3SSPSolver()); }
|
||||
};
|
||||
|
||||
/** A 4-stage, 4th order AB method. */
|
||||
class AB4Solver : public AdamsBashforthSolver
|
||||
{
|
||||
private:
|
||||
static MFEM_EXPORT const real_t a[4];
|
||||
|
||||
public:
|
||||
AB4Solver() : AdamsBashforthSolver(4, a) { RKsolver.reset(new RK4Solver()); }
|
||||
};
|
||||
|
||||
/** A 5-stage, 5th order AB method. */
|
||||
class AB5Solver : public AdamsBashforthSolver
|
||||
{
|
||||
private:
|
||||
static MFEM_EXPORT const real_t a[5];
|
||||
|
||||
public:
|
||||
AB5Solver() : AdamsBashforthSolver(5, a) { RKsolver.reset(new RK6Solver()); }
|
||||
};
|
||||
|
||||
|
||||
/** An implicit Adams-Moulton method. */
|
||||
class AdamsMoultonSolver : public ODESolverWithStates
|
||||
{
|
||||
private:
|
||||
const real_t *a;
|
||||
const int stages;
|
||||
real_t dt_;
|
||||
ODEStateDataVector state;
|
||||
|
||||
protected:
|
||||
std::unique_ptr<ODESolver> RKsolver;
|
||||
|
||||
inline bool print()
|
||||
{
|
||||
#ifdef MFEM_USE_MPI
|
||||
return Mpi::IsInitialized() ? Mpi::Root() : true;
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
void CheckTimestep(real_t dt);
|
||||
|
||||
public:
|
||||
AdamsMoultonSolver(int s_, const real_t *a_);
|
||||
void Init(TimeDependentOperator &f_) override;
|
||||
void Step(Vector &x, real_t &t, real_t &dt) override;
|
||||
|
||||
ODEStateData& GetState() override { return state; }
|
||||
const ODEStateData& GetState() const override { return state; }
|
||||
};
|
||||
|
||||
/** A 1-stage, 2nd order AM method. */
|
||||
class AM1Solver : public AdamsMoultonSolver
|
||||
{
|
||||
private:
|
||||
static MFEM_EXPORT const real_t a[2];
|
||||
|
||||
public:
|
||||
AM1Solver() : AdamsMoultonSolver(1, a) { RKsolver.reset(new SDIRK23Solver()); }
|
||||
};
|
||||
|
||||
/** A 2-stage, 3rd order AM method. */
|
||||
class AM2Solver : public AdamsMoultonSolver
|
||||
{
|
||||
private:
|
||||
static MFEM_EXPORT const real_t a[3];
|
||||
|
||||
public:
|
||||
AM2Solver() : AdamsMoultonSolver(2, a) { RKsolver.reset(new SDIRK23Solver()); }
|
||||
};
|
||||
|
||||
/** A 3-stage, 4th order AM method. */
|
||||
class AM3Solver : public AdamsMoultonSolver
|
||||
{
|
||||
private:
|
||||
static MFEM_EXPORT const real_t a[4];
|
||||
|
||||
public:
|
||||
AM3Solver() : AdamsMoultonSolver(3, a) { RKsolver.reset(new SDIRK23Solver()); }
|
||||
};
|
||||
|
||||
/** A 4-stage, 5th order AM method. */
|
||||
class AM4Solver : public AdamsMoultonSolver
|
||||
{
|
||||
private:
|
||||
static MFEM_EXPORT const real_t a[5];
|
||||
|
||||
public:
|
||||
AM4Solver() : AdamsMoultonSolver(4, a) { RKsolver.reset(new SDIRK34Solver()); }
|
||||
};
|
||||
|
||||
/// The SIASolver class is based on the Symplectic Integration Algorithm
|
||||
/// described in "A Symplectic Integration Algorithm for Separable Hamiltonian
|
||||
/// Functions" by J. Candy and W. Rozmus, Journal of Computational Physics,
|
||||
@@ -630,9 +707,10 @@ protected:
|
||||
/// Pointer to the associated TimeDependentOperator.
|
||||
SecondOrderTimeDependentOperator *f; // f(.,.,t) : R^n x R^n --> R^n
|
||||
MemoryType mem_type;
|
||||
ODEStateDataVector state;
|
||||
|
||||
public:
|
||||
SecondOrderODESolver() : f(NULL) { mem_type = MemoryType::HOST; }
|
||||
SecondOrderODESolver() : f(NULL), state(1) { mem_type = MemoryType::HOST; }
|
||||
|
||||
/// Associate a TimeDependentOperator with the ODE solver.
|
||||
/** This method has to be called:
|
||||
@@ -680,6 +758,8 @@ public:
|
||||
sequence, then the ODE solver must be re-initialized by calling Init()
|
||||
between the two Step() calls. */
|
||||
virtual void Step(Vector &x, Vector &dxdt, real_t &t, real_t &dt) = 0;
|
||||
void EulerStep(Vector &x, Vector &dxdt, real_t &t, real_t &dt);
|
||||
void MidPointStep(Vector &x, Vector &dxdt, real_t &t, real_t &dt);
|
||||
|
||||
/// Perform time integration from time @a t [in] to time @a tf [in].
|
||||
/** @param[in,out] x Approximate solution.
|
||||
@@ -705,22 +785,18 @@ public:
|
||||
while (t < tf) { Step(x, dxdt, t, dt); }
|
||||
}
|
||||
|
||||
/// Function for getting and setting the state vectors
|
||||
virtual int GetMaxStateSize() { return 0; };
|
||||
virtual int GetStateSize() { return 0; }
|
||||
virtual const Vector &GetStateVector(int i)
|
||||
{
|
||||
mfem_error("ODESolver has no state vectors");
|
||||
Vector *s = NULL; return *s; // Make some compiler happy
|
||||
}
|
||||
virtual void GetStateVector(int i, Vector &state)
|
||||
{
|
||||
mfem_error("ODESolver has no state vectors");
|
||||
}
|
||||
virtual void SetStateVector(int i, Vector &state)
|
||||
{
|
||||
mfem_error("ODESolver has no state vectors");
|
||||
}
|
||||
/// Functions for getting the state vectors
|
||||
ODEStateData& GetState() { return state; }
|
||||
const ODEStateData& GetState() const { return state; }
|
||||
|
||||
/// Returns how many State vectors the ODE requires
|
||||
int GetStateSize() { return GetState().MaxSize(); };
|
||||
|
||||
/// Help info for SecondOrderODESolver options
|
||||
static MFEM_EXPORT std::string Types;
|
||||
|
||||
/// Function selecting the desired SecondOrderODESolver
|
||||
static MFEM_EXPORT SecondOrderODESolver *Select(const int ode_solver_type);
|
||||
|
||||
virtual ~SecondOrderODESolver() { }
|
||||
};
|
||||
@@ -731,17 +807,18 @@ public:
|
||||
class NewmarkSolver : public SecondOrderODESolver
|
||||
{
|
||||
private:
|
||||
Vector d2xdt2;
|
||||
|
||||
real_t beta, gamma;
|
||||
bool first;
|
||||
bool no_mult;
|
||||
|
||||
public:
|
||||
NewmarkSolver(real_t beta_ = 0.25, real_t gamma_ = 0.5) { beta = beta_; gamma = gamma_; };
|
||||
NewmarkSolver(real_t beta_ = 0.25, real_t gamma_ = 0.5, bool no_mult_ = false)
|
||||
{
|
||||
beta = beta_;
|
||||
gamma = gamma_;
|
||||
no_mult = no_mult_;
|
||||
};
|
||||
|
||||
void PrintProperties(std::ostream &out = mfem::out);
|
||||
|
||||
void Init(SecondOrderTimeDependentOperator &f_) override;
|
||||
void PrintProperties(std::ostream &os = mfem::out);
|
||||
|
||||
void Step(Vector &x, Vector &dxdt, real_t &t, real_t &dt) override;
|
||||
};
|
||||
@@ -773,13 +850,14 @@ public:
|
||||
class GeneralizedAlpha2Solver : public SecondOrderODESolver
|
||||
{
|
||||
protected:
|
||||
Vector xa,va,aa,d2xdt2;
|
||||
Vector xa,va,aa;
|
||||
real_t alpha_f, alpha_m, beta, gamma;
|
||||
int nstate;
|
||||
bool no_mult;
|
||||
|
||||
public:
|
||||
GeneralizedAlpha2Solver(real_t rho_inf = 1.0)
|
||||
GeneralizedAlpha2Solver(real_t rho_inf = 1.0, bool no_mult_ = false)
|
||||
{
|
||||
no_mult = no_mult_;
|
||||
rho_inf = (rho_inf > 1.0) ? 1.0 : rho_inf;
|
||||
rho_inf = (rho_inf < 0.0) ? 0.0 : rho_inf;
|
||||
|
||||
@@ -789,17 +867,12 @@ public:
|
||||
gamma = 0.5 + alpha_m - alpha_f;
|
||||
};
|
||||
|
||||
void PrintProperties(std::ostream &out = mfem::out);
|
||||
void PrintProperties(std::ostream &os = mfem::out);
|
||||
|
||||
void Init(SecondOrderTimeDependentOperator &f_) override;
|
||||
|
||||
void Step(Vector &x, Vector &dxdt, real_t &t, real_t &dt) override;
|
||||
|
||||
int GetMaxStateSize() override { return 1; };
|
||||
int GetStateSize() override { return nstate; };
|
||||
const Vector &GetStateVector(int i) override;
|
||||
void GetStateVector(int i, Vector &state) override;
|
||||
void SetStateVector(int i, Vector &state) override;
|
||||
};
|
||||
|
||||
/// The classical midpoint method.
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
// terms of the BSD-3 license. We welcome feedback and contributions, see file
|
||||
// CONTRIBUTING.md for details.
|
||||
|
||||
#include "handle.hpp"
|
||||
#include "op_handle.hpp"
|
||||
#include "sparsemat.hpp"
|
||||
#ifdef MFEM_USE_MPI
|
||||
#include "petsc.hpp"
|
||||
@@ -17,8 +17,8 @@
|
||||
|
||||
// Make sure that hypre and PETSc use the same size indices.
|
||||
#if defined(MFEM_USE_MPI) && defined(MFEM_USE_PETSC)
|
||||
#if (defined(HYPRE_BIGINT) && !defined(PETSC_USE_64BIT_INDICES)) || \
|
||||
(!defined(HYPRE_BIGINT) && defined(PETSC_USE_64BIT_INDICES))
|
||||
#if ((defined(HYPRE_BIGINT) || defined(HYPRE_MIXEDINT)) && !defined(PETSC_USE_64BIT_INDICES)) || \
|
||||
(!defined(HYPRE_BIGINT) && !defined(HYPRE_MIXEDINT) && defined(PETSC_USE_64BIT_INDICES))
|
||||
#error HYPRE and PETSC do not use the same size integers!
|
||||
#endif
|
||||
#endif
|
||||
@@ -9,8 +9,8 @@
|
||||
// terms of the BSD-3 license. We welcome feedback and contributions, see file
|
||||
// CONTRIBUTING.md for details.
|
||||
|
||||
#ifndef MFEM_HANDLE_HPP
|
||||
#define MFEM_HANDLE_HPP
|
||||
#ifndef MFEM_OP_HANDLE_HPP
|
||||
#define MFEM_OP_HANDLE_HPP
|
||||
|
||||
#include "../config/config.hpp"
|
||||
#include "operator.hpp"
|
||||
+44
-63
@@ -183,8 +183,8 @@ Operator * Operator::SetupRAP(const Operator *Pi, const Operator *Po)
|
||||
{
|
||||
if (!IsIdentityProlongation(Po))
|
||||
{
|
||||
TransposeOperator * PoT = new TransposeOperator(Po);
|
||||
rap = new ProductOperator(PoT, this, true,false);
|
||||
rap = new ProductOperator(Owning(new TransposeOperator(Po)),
|
||||
NonOwning(this));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -365,11 +365,10 @@ void SecondOrderTimeDependentOperator::ImplicitSolve(const real_t dt0,
|
||||
mfem_error("SecondOrderTimeDependentOperator::ImplicitSolve() is not overridden!");
|
||||
}
|
||||
|
||||
SumOperator::SumOperator(const Operator *A, const real_t alpha,
|
||||
const Operator *B, const real_t beta,
|
||||
bool ownA, bool ownB)
|
||||
: Operator(A->Height(), A->Width()),
|
||||
A(A), B(B), alpha(alpha), beta(beta), ownA(ownA), ownB(ownB),
|
||||
SumOperator::SumOperator(Handle<const Operator> A_, const real_t alpha,
|
||||
Handle<const Operator> B_, const real_t beta)
|
||||
: Operator(A_->Height(), A_->Width()),
|
||||
A(A_), B(B_), alpha(alpha), beta(beta),
|
||||
z(A->Height())
|
||||
{
|
||||
MFEM_VERIFY(A->Width() == B->Width(),
|
||||
@@ -381,53 +380,43 @@ SumOperator::SumOperator(const Operator *A, const real_t alpha,
|
||||
<< "A->Height() = " << A->Height()
|
||||
<< ", B->Height() = " << B->Height() );
|
||||
|
||||
if (auto SolverA = dynamic_cast<const Solver*>(A.Get()))
|
||||
{
|
||||
const Solver* SolverA = dynamic_cast<const Solver*>(A);
|
||||
const Solver* SolverB = dynamic_cast<const Solver*>(B);
|
||||
if (SolverA)
|
||||
{
|
||||
MFEM_VERIFY(!(SolverA->iterative_mode),
|
||||
"Operator A of a SumOperator should not be in iterative mode");
|
||||
}
|
||||
if (SolverB)
|
||||
{
|
||||
MFEM_VERIFY(!(SolverB->iterative_mode),
|
||||
"Operator B of a SumOperator should not be in iterative mode");
|
||||
}
|
||||
MFEM_VERIFY(!(SolverA->iterative_mode),
|
||||
"Operator A of a SumOperator should not be in iterative mode");
|
||||
}
|
||||
if (auto SolverB = dynamic_cast<const Solver*>(B.Get()))
|
||||
{
|
||||
MFEM_VERIFY(!(SolverB->iterative_mode),
|
||||
"Operator B of a SumOperator should not be in iterative mode");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
SumOperator::~SumOperator()
|
||||
{
|
||||
if (ownA) { delete A; }
|
||||
if (ownB) { delete B; }
|
||||
}
|
||||
SumOperator::SumOperator(const Operator *A_, const real_t alpha,
|
||||
const Operator *B_, const real_t beta,
|
||||
bool own_A, bool own_B)
|
||||
: SumOperator({A_, own_A}, alpha, {B_, own_B}, beta) { }
|
||||
|
||||
ProductOperator::ProductOperator(const Operator *A, const Operator *B,
|
||||
bool ownA, bool ownB)
|
||||
: Operator(A->Height(), B->Width()),
|
||||
A(A), B(B), ownA(ownA), ownB(ownB), z(A->Width())
|
||||
|
||||
ProductOperator::ProductOperator(Handle<const Operator> A_,
|
||||
Handle<const Operator> B_)
|
||||
: Operator(A_->Height(), B_->Width()),
|
||||
A(A_), B(B_), z(A->Width())
|
||||
{
|
||||
MFEM_VERIFY(A->Width() == B->Height(),
|
||||
"incompatible Operators: A->Width() = " << A->Width()
|
||||
<< ", B->Height() = " << B->Height());
|
||||
|
||||
if (auto SolverB = dynamic_cast<const Solver*>(B.Get()))
|
||||
{
|
||||
const Solver* SolverB = dynamic_cast<const Solver*>(B);
|
||||
if (SolverB)
|
||||
{
|
||||
MFEM_VERIFY(!(SolverB->iterative_mode),
|
||||
"Operator B of a ProductOperator should not be in iterative mode");
|
||||
}
|
||||
MFEM_VERIFY(!(SolverB->iterative_mode),
|
||||
"Operator B of a ProductOperator should not be in iterative mode");
|
||||
}
|
||||
}
|
||||
|
||||
ProductOperator::~ProductOperator()
|
||||
{
|
||||
if (ownA) { delete A; }
|
||||
if (ownB) { delete B; }
|
||||
}
|
||||
ProductOperator::ProductOperator(const Operator *A_, const Operator *B_,
|
||||
bool own_A, bool own_B)
|
||||
: ProductOperator({A_, own_A}, {B_, own_B}) { }
|
||||
|
||||
|
||||
RAPOperator::RAPOperator(const Operator &Rt_, const Operator &A_,
|
||||
@@ -465,11 +454,9 @@ RAPOperator::RAPOperator(const Operator &Rt_, const Operator &A_,
|
||||
|
||||
|
||||
TripleProductOperator::TripleProductOperator(
|
||||
const Operator *A, const Operator *B, const Operator *C,
|
||||
bool ownA, bool ownB, bool ownC)
|
||||
: Operator(A->Height(), C->Width())
|
||||
, A(A), B(B), C(C)
|
||||
, ownA(ownA), ownB(ownB), ownC(ownC)
|
||||
Handle<const Operator> A_, Handle<const Operator> B_, Handle<const Operator> C_)
|
||||
: Operator(A_->Height(), C_->Width()),
|
||||
A(A_), B(B_), C(C_)
|
||||
{
|
||||
MFEM_VERIFY(A->Width() == B->Height(),
|
||||
"incompatible Operators: A->Width() = " << A->Width()
|
||||
@@ -478,20 +465,16 @@ TripleProductOperator::TripleProductOperator(
|
||||
"incompatible Operators: B->Width() = " << B->Width()
|
||||
<< ", C->Height() = " << C->Height());
|
||||
|
||||
if (auto SolverB = dynamic_cast<const Solver*>(B.Get()))
|
||||
{
|
||||
const Solver* SolverB = dynamic_cast<const Solver*>(B);
|
||||
if (SolverB)
|
||||
{
|
||||
MFEM_VERIFY(!(SolverB->iterative_mode),
|
||||
"Operator B of a TripleProductOperator should not be in iterative mode");
|
||||
}
|
||||
MFEM_VERIFY(!(SolverB->iterative_mode),
|
||||
"Operator B of a TripleProductOperator should not be in iterative mode");
|
||||
}
|
||||
|
||||
const Solver* SolverC = dynamic_cast<const Solver*>(C);
|
||||
if (SolverC)
|
||||
{
|
||||
MFEM_VERIFY(!(SolverC->iterative_mode),
|
||||
"Operator C of a TripleProductOperator should not be in iterative mode");
|
||||
}
|
||||
if (auto SolverC = dynamic_cast<const Solver*>(C.Get()))
|
||||
{
|
||||
MFEM_VERIFY(!(SolverC->iterative_mode),
|
||||
"Operator C of a TripleProductOperator should not be in iterative mode");
|
||||
}
|
||||
|
||||
mem_class = A->GetMemoryClass()*C->GetMemoryClass();
|
||||
@@ -500,12 +483,10 @@ TripleProductOperator::TripleProductOperator(
|
||||
t2.SetSize(B->Height(), mem_type);
|
||||
}
|
||||
|
||||
TripleProductOperator::~TripleProductOperator()
|
||||
{
|
||||
if (ownA) { delete A; }
|
||||
if (ownB) { delete B; }
|
||||
if (ownC) { delete C; }
|
||||
}
|
||||
TripleProductOperator::TripleProductOperator(
|
||||
const Operator *A_, const Operator *B_, const Operator *C_,
|
||||
bool own_A, bool own_B, bool own_C)
|
||||
: TripleProductOperator({A_, own_A}, {B_, own_B}, {C_, own_C}) { }
|
||||
|
||||
|
||||
ConstrainedOperator::ConstrainedOperator(Operator *A, const Array<int> &list,
|
||||
|
||||
+22
-21
@@ -13,6 +13,7 @@
|
||||
#define MFEM_OPERATOR
|
||||
|
||||
#include "vector.hpp"
|
||||
#include "../general/handle.hpp"
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
@@ -869,43 +870,42 @@ public:
|
||||
/// General linear combination operator: x -> a A(x) + b B(x).
|
||||
class SumOperator : public Operator
|
||||
{
|
||||
const Operator *A, *B;
|
||||
Handle<const Operator> A, B;
|
||||
const real_t alpha, beta;
|
||||
bool ownA, ownB;
|
||||
mutable Vector z;
|
||||
|
||||
public:
|
||||
SumOperator(
|
||||
const Operator *A, const real_t alpha,
|
||||
const Operator *B, const real_t beta,
|
||||
bool ownA, bool ownB);
|
||||
SumOperator(Handle<const Operator> A_, const real_t alpha,
|
||||
Handle<const Operator> B_, const real_t beta);
|
||||
|
||||
SumOperator(const Operator *A_, const real_t alpha,
|
||||
const Operator *B_, const real_t beta,
|
||||
bool own_A, bool own_B);
|
||||
|
||||
void Mult(const Vector &x, Vector &y) const override
|
||||
{ z.SetSize(A->Height()); A->Mult(x, z); B->Mult(x, y); add(alpha, z, beta, y, y); }
|
||||
|
||||
void MultTranspose(const Vector &x, Vector &y) const override
|
||||
{ z.SetSize(A->Width()); A->MultTranspose(x, z); B->MultTranspose(x, y); add(alpha, z, beta, y, y); }
|
||||
|
||||
virtual ~SumOperator();
|
||||
};
|
||||
|
||||
/// General product operator: x -> (A*B)(x) = A(B(x)).
|
||||
class ProductOperator : public Operator
|
||||
{
|
||||
const Operator *A, *B;
|
||||
bool ownA, ownB;
|
||||
Handle<const Operator> A, B;
|
||||
mutable Vector z;
|
||||
|
||||
public:
|
||||
ProductOperator(const Operator *A, const Operator *B, bool ownA, bool ownB);
|
||||
ProductOperator(Handle<const Operator> A_, Handle<const Operator> B_);
|
||||
|
||||
ProductOperator(const Operator *A_, const Operator *B_,
|
||||
bool own_A, bool own_B);
|
||||
|
||||
void Mult(const Vector &x, Vector &y) const override
|
||||
{ B->Mult(x, z); A->Mult(z, y); }
|
||||
|
||||
void MultTranspose(const Vector &x, Vector &y) const override
|
||||
{ A->MultTranspose(x, z); B->MultTranspose(z, y); }
|
||||
|
||||
virtual ~ProductOperator();
|
||||
};
|
||||
|
||||
|
||||
@@ -956,16 +956,19 @@ public:
|
||||
/// General triple product operator x -> A*B*C*x, with ownership of the factors.
|
||||
class TripleProductOperator : public Operator
|
||||
{
|
||||
const Operator *A;
|
||||
const Operator *B;
|
||||
const Operator *C;
|
||||
bool ownA, ownB, ownC;
|
||||
Handle<const Operator> A;
|
||||
Handle<const Operator> B;
|
||||
Handle<const Operator> C;
|
||||
mutable Vector t1, t2;
|
||||
MemoryClass mem_class;
|
||||
|
||||
public:
|
||||
TripleProductOperator(const Operator *A, const Operator *B,
|
||||
const Operator *C, bool ownA, bool ownB, bool ownC);
|
||||
TripleProductOperator(Handle<const Operator> A_, Handle<const Operator> B_,
|
||||
Handle<const Operator> C_);
|
||||
|
||||
TripleProductOperator(
|
||||
const Operator *A_, const Operator *B_, const Operator *C_,
|
||||
bool own_A, bool own_B, bool own_C);
|
||||
|
||||
MemoryClass GetMemoryClass() const override { return mem_class; }
|
||||
|
||||
@@ -974,8 +977,6 @@ public:
|
||||
|
||||
void MultTranspose(const Vector &x, Vector &y) const override
|
||||
{ A->MultTranspose(x, t2); B->MultTranspose(t2, t1); C->MultTranspose(t1, y); }
|
||||
|
||||
virtual ~TripleProductOperator();
|
||||
};
|
||||
|
||||
|
||||
|
||||
+3
-3
@@ -21,7 +21,7 @@
|
||||
|
||||
#include <limits>
|
||||
|
||||
#include "handle.hpp"
|
||||
#include "op_handle.hpp"
|
||||
#include "hypre.hpp"
|
||||
#include "ode.hpp"
|
||||
#include "../general/mem_manager.hpp"
|
||||
@@ -36,10 +36,10 @@
|
||||
#if defined(PETSC_USE_COMPLEX)
|
||||
#error "MFEM does not work with PETSc compiled with complex numbers support"
|
||||
#endif
|
||||
#if defined(PETSC_USE_64BIT_INDICES) && !defined(HYPRE_BIGINT)
|
||||
#if defined(PETSC_USE_64BIT_INDICES) && !defined(HYPRE_BIGINT) && !defined(HYPRE_MIXEDINT)
|
||||
#error "Mismatch between HYPRE (32bit) and PETSc (64bit) integer types"
|
||||
#endif
|
||||
#if !defined(PETSC_USE_64BIT_INDICES) && defined(HYPRE_BIGINT)
|
||||
#if !defined(PETSC_USE_64BIT_INDICES) && (defined(HYPRE_BIGINT) || defined(HYPRE_MIXEDINT))
|
||||
#error "Mismatch between HYPRE (64bit) and PETSc (32bit) integer types"
|
||||
#endif
|
||||
|
||||
|
||||
+12
-10
@@ -1919,7 +1919,8 @@ void NewtonSolver::Mult(const Vector &b, Vector &x) const
|
||||
print_options.first_and_last)
|
||||
{
|
||||
mfem::out << "Newton: Number of iterations: " << final_iter << '\n'
|
||||
<< " ||r|| = " << final_norm << '\n';
|
||||
<< " ||r|| = " << final_norm
|
||||
<< ", ||r||/||r_0|| = " << final_norm/norm0 << '\n';
|
||||
}
|
||||
if (!converged && (print_options.summary || print_options.warnings))
|
||||
{
|
||||
@@ -2141,7 +2142,8 @@ void LBFGSSolver::Mult(const Vector &b, Vector &x) const
|
||||
print_options.first_and_last)
|
||||
{
|
||||
mfem::out << "LBFGS: Number of iterations: " << final_iter << '\n'
|
||||
<< " ||r|| = " << final_norm << '\n';
|
||||
<< " ||r|| = " << final_norm
|
||||
<< ", ||r||/||r_0|| = " << final_norm/norm0 << '\n';
|
||||
}
|
||||
if (print_options.summary || (!converged && print_options.warnings))
|
||||
{
|
||||
@@ -2570,7 +2572,7 @@ struct WeightMinHeap
|
||||
for (; pos > 0 && w[c[(pos-1)/2]] > val; pos = (pos-1)/2)
|
||||
{
|
||||
c[pos] = c[(pos-1)/2];
|
||||
loc[c[(pos-1)/2]] = pos;
|
||||
loc[c[(pos-1)/2]] = static_cast<int>(pos);
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
@@ -2587,7 +2589,7 @@ struct WeightMinHeap
|
||||
if (w[c[tgt]] < val)
|
||||
{
|
||||
c[pos] = c[tgt];
|
||||
loc[c[tgt]] = pos;
|
||||
loc[c[tgt]] = static_cast<int>(pos);
|
||||
pos = tgt;
|
||||
}
|
||||
else
|
||||
@@ -2605,7 +2607,7 @@ struct WeightMinHeap
|
||||
size_t pos = c.size()-1;
|
||||
pos = percolate_up(pos, val);
|
||||
c[pos] = i;
|
||||
loc[i] = pos;
|
||||
loc[i] = static_cast<int>(pos);
|
||||
}
|
||||
|
||||
int pop()
|
||||
@@ -2615,13 +2617,13 @@ struct WeightMinHeap
|
||||
c.pop_back();
|
||||
// Mark as removed
|
||||
loc[i] = -1;
|
||||
if (c.empty()) { return i; }
|
||||
if (c.empty()) { return static_cast<int>(i); }
|
||||
real_t val = w[j];
|
||||
size_t pos = 0;
|
||||
pos = percolate_down(pos, val);
|
||||
c[pos] = j;
|
||||
loc[j] = pos;
|
||||
return i;
|
||||
loc[j] = static_cast<int>(pos);
|
||||
return static_cast<int>(i);
|
||||
}
|
||||
|
||||
void update(size_t i)
|
||||
@@ -2631,7 +2633,7 @@ struct WeightMinHeap
|
||||
pos = percolate_up(pos, val);
|
||||
pos = percolate_down(pos, val);
|
||||
c[pos] = i;
|
||||
loc[i] = pos;
|
||||
loc[i] = static_cast<int>(pos);
|
||||
}
|
||||
|
||||
bool picked(size_t i)
|
||||
@@ -2819,7 +2821,7 @@ void BlockILU::CreateBlockPattern(const SparseMatrix &A)
|
||||
unique_block_cols[iblock].insert(J[k] / block_size);
|
||||
}
|
||||
}
|
||||
nnz += unique_block_cols[iblock].size();
|
||||
nnz += static_cast<int>(unique_block_cols[iblock].size());
|
||||
}
|
||||
|
||||
if (reordering != Reordering::NONE)
|
||||
|
||||
+1
-1
@@ -14,7 +14,7 @@
|
||||
|
||||
#include "../config/config.hpp"
|
||||
#include "densemat.hpp"
|
||||
#include "handle.hpp"
|
||||
#include "op_handle.hpp"
|
||||
#include <memory>
|
||||
|
||||
#ifdef MFEM_USE_MPI
|
||||
|
||||
+133
-80
@@ -95,7 +95,7 @@ MFEM_DEPRECATED void* CVodeCreate(int lmm, SUNContext)
|
||||
|
||||
/// (DEPRECATED) Wrapper function for backwards compatibility with SUNDIALS
|
||||
/// version < 6
|
||||
MFEM_DEPRECATED void* ARKStepCreate(ARKRhsFn fe, ARKRhsFn fi, realtype t0,
|
||||
MFEM_DEPRECATED void* ARKStepCreate(ARKRhsFn fe, ARKRhsFn fi, sunrealtype t0,
|
||||
N_Vector y0, SUNContext)
|
||||
{
|
||||
return ARKStepCreate(fe, fi, t0, y0);
|
||||
@@ -127,7 +127,7 @@ MFEM_DEPRECATED N_Vector N_VNewEmpty_Parallel(MPI_Comm comm,
|
||||
/// (DEPRECATED) Wrapper function for backwards compatibility with SUNDIALS
|
||||
/// version < 6
|
||||
MFEM_DEPRECATED N_Vector SUN_Hip_OR_Cuda(N_VNewWithMemHelp)(sunindextype length,
|
||||
booleantype use_managed_mem,
|
||||
sunbooleantype use_managed_mem,
|
||||
SUNMemoryHelper helper,
|
||||
SUNContext)
|
||||
{
|
||||
@@ -157,6 +157,16 @@ MFEM_DEPRECATED N_Vector N_VMake_MPIPlusX(MPI_Comm comm, N_Vector local_vector,
|
||||
|
||||
#endif // SUNDIALS_VERSION_MAJOR < 6
|
||||
|
||||
#if MFEM_SUNDIALS_VERSION < 70100
|
||||
#define MFEM_ARKode(FUNC) ARKStep##FUNC
|
||||
#else
|
||||
#define MFEM_ARKode(FUNC) ARKode##FUNC
|
||||
#endif
|
||||
|
||||
// Macro STR(): expand the argument and add double quotes
|
||||
#define STR1(s) #s
|
||||
#define STR(s) STR1(s)
|
||||
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
@@ -187,11 +197,21 @@ SundialsMemHelper &Sundials::GetMemHelper()
|
||||
Sundials::Sundials()
|
||||
{
|
||||
#ifdef MFEM_USE_MPI
|
||||
MPI_Comm communicator = MPI_COMM_WORLD;
|
||||
int mpi_initialized = 0;
|
||||
MPI_Initialized(&mpi_initialized);
|
||||
MPI_Comm communicator = mpi_initialized ? MPI_COMM_WORLD : MPI_COMM_NULL;
|
||||
#if SUNDIALS_VERSION_MAJOR < 7
|
||||
int return_val = SUNContext_Create((void*) &communicator, &context);
|
||||
#else
|
||||
int return_val = SUNContext_Create(nullptr, &context);
|
||||
int return_val = SUNContext_Create(communicator, &context);
|
||||
#endif
|
||||
#else // #ifdef MFEM_USE_MPI
|
||||
#if SUNDIALS_VERSION_MAJOR < 7
|
||||
int return_val = SUNContext_Create(nullptr, &context);
|
||||
#else
|
||||
int return_val = SUNContext_Create((SUNComm)(0), &context);
|
||||
#endif
|
||||
#endif // #ifdef MFEM_USE_MPI
|
||||
MFEM_VERIFY(return_val == 0, "Call to SUNContext_Create failed");
|
||||
SundialsMemHelper actual_helper(context);
|
||||
memHelper = std::move(actual_helper);
|
||||
@@ -250,7 +270,11 @@ int SundialsMemHelper::SundialsMemHelper_Alloc(SUNMemoryHelper helper,
|
||||
#endif
|
||||
)
|
||||
{
|
||||
#if (SUNDIALS_VERSION_MAJOR < 7)
|
||||
SUNMemory sunmem = SUNMemoryNewEmpty();
|
||||
#else
|
||||
SUNMemory sunmem = SUNMemoryNewEmpty(helper->sunctx);
|
||||
#endif
|
||||
|
||||
sunmem->ptr = NULL;
|
||||
sunmem->own = SUNTRUE;
|
||||
@@ -631,7 +655,7 @@ static int LSFree(SUNLinearSolver LS)
|
||||
// ---------------------------------------------------------------------------
|
||||
// CVODE interface
|
||||
// ---------------------------------------------------------------------------
|
||||
int CVODESolver::RHS(realtype t, const N_Vector y, N_Vector ydot,
|
||||
int CVODESolver::RHS(sunrealtype t, const N_Vector y, N_Vector ydot,
|
||||
void *user_data)
|
||||
{
|
||||
// At this point the up-to-date data for N_Vector y and ydot is on the device.
|
||||
@@ -648,7 +672,8 @@ int CVODESolver::RHS(realtype t, const N_Vector y, N_Vector ydot,
|
||||
return (0);
|
||||
}
|
||||
|
||||
int CVODESolver::root(realtype t, N_Vector y, realtype *gout, void *user_data)
|
||||
int CVODESolver::root(sunrealtype t, N_Vector y, sunrealtype *gout,
|
||||
void *user_data)
|
||||
{
|
||||
CVODESolver *self = static_cast<CVODESolver*>(user_data);
|
||||
|
||||
@@ -668,8 +693,9 @@ void CVODESolver::SetRootFinder(int components, RootFunction func)
|
||||
MFEM_VERIFY(flag == CV_SUCCESS, "error in SetRootFinder()");
|
||||
}
|
||||
|
||||
int CVODESolver::LinSysSetup(realtype t, N_Vector y, N_Vector fy, SUNMatrix A,
|
||||
booleantype jok, booleantype *jcur, realtype gamma,
|
||||
int CVODESolver::LinSysSetup(sunrealtype t, N_Vector y, N_Vector fy,
|
||||
SUNMatrix A, sunbooleantype jok,
|
||||
sunbooleantype *jcur, sunrealtype gamma,
|
||||
void*, N_Vector, N_Vector, N_Vector)
|
||||
{
|
||||
// Get data from N_Vectors
|
||||
@@ -683,7 +709,7 @@ int CVODESolver::LinSysSetup(realtype t, N_Vector y, N_Vector fy, SUNMatrix A,
|
||||
}
|
||||
|
||||
int CVODESolver::LinSysSolve(SUNLinearSolver LS, SUNMatrix, N_Vector x,
|
||||
N_Vector b, realtype tol)
|
||||
N_Vector b, sunrealtype tol)
|
||||
{
|
||||
SundialsNVector mfem_x(x);
|
||||
const SundialsNVector mfem_b(b);
|
||||
@@ -859,7 +885,7 @@ void CVODESolver::UseSundialsLinearSolver()
|
||||
if (LSA != NULL) { SUNLinSolFree(LSA); LSA = NULL; }
|
||||
|
||||
// Create linear solver
|
||||
LSA = SUNLinSol_SPGMR(*Y, PREC_NONE, 0, Sundials::GetContext());
|
||||
LSA = SUNLinSol_SPGMR(*Y, SUN_PREC_NONE, 0, Sundials::GetContext());
|
||||
MFEM_VERIFY(LSA, "error in SUNLinSol_SPGMR()");
|
||||
|
||||
// Attach linear solver
|
||||
@@ -1150,7 +1176,7 @@ void CVODESSolver::UseSundialsLinearSolverB()
|
||||
if (LSB != NULL) { SUNLinSolFree(LSB); LSB = NULL; }
|
||||
|
||||
// Set default linear solver (Newton is the default Nonlinear Solver)
|
||||
LSB = SUNLinSol_SPGMR(*yB, PREC_NONE, 0, Sundials::GetContext());
|
||||
LSB = SUNLinSol_SPGMR(*yB, SUN_PREC_NONE, 0, Sundials::GetContext());
|
||||
MFEM_VERIFY(LSB, "error in SUNLinSol_SPGMR()");
|
||||
|
||||
/* Attach the matrix and linear solver */
|
||||
@@ -1158,11 +1184,11 @@ void CVODESSolver::UseSundialsLinearSolverB()
|
||||
MFEM_VERIFY(flag == CV_SUCCESS, "error in CVodeSetLinearSolverB()");
|
||||
}
|
||||
|
||||
int CVODESSolver::LinSysSetupB(realtype t, N_Vector y, N_Vector yB,
|
||||
int CVODESSolver::LinSysSetupB(sunrealtype t, N_Vector y, N_Vector yB,
|
||||
N_Vector fyB, SUNMatrix AB,
|
||||
booleantype jokB, booleantype *jcurB,
|
||||
realtype gammaB, void *user_data, N_Vector tmp1,
|
||||
N_Vector tmp2, N_Vector tmp3)
|
||||
sunbooleantype jokB, sunbooleantype *jcurB,
|
||||
sunrealtype gammaB, void *user_data,
|
||||
N_Vector tmp1, N_Vector tmp2, N_Vector tmp3)
|
||||
{
|
||||
// Get data from N_Vectors
|
||||
const SundialsNVector mfem_y(y);
|
||||
@@ -1178,7 +1204,7 @@ int CVODESSolver::LinSysSetupB(realtype t, N_Vector y, N_Vector yB,
|
||||
}
|
||||
|
||||
int CVODESSolver::LinSysSolveB(SUNLinearSolver LS, SUNMatrix AB, N_Vector yB,
|
||||
N_Vector Rb, realtype tol)
|
||||
N_Vector Rb, sunrealtype tol)
|
||||
{
|
||||
SundialsNVector mfem_yB(yB);
|
||||
const SundialsNVector mfem_Rb(Rb);
|
||||
@@ -1216,7 +1242,7 @@ void CVODESSolver::SetWFTolerances(EWTFunction func)
|
||||
|
||||
// CVODESSolver static functions
|
||||
|
||||
int CVODESSolver::RHSQ(realtype t, const N_Vector y, N_Vector qdot,
|
||||
int CVODESSolver::RHSQ(sunrealtype t, const N_Vector y, N_Vector qdot,
|
||||
void *user_data)
|
||||
{
|
||||
CVODESSolver *self = static_cast<CVODESSolver*>(user_data);
|
||||
@@ -1229,7 +1255,7 @@ int CVODESSolver::RHSQ(realtype t, const N_Vector y, N_Vector qdot,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CVODESSolver::RHSQB(realtype t, N_Vector y, N_Vector yB, N_Vector qBdot,
|
||||
int CVODESSolver::RHSQB(sunrealtype t, N_Vector y, N_Vector yB, N_Vector qBdot,
|
||||
void *user_dataB)
|
||||
{
|
||||
CVODESSolver *self = static_cast<CVODESSolver*>(user_dataB);
|
||||
@@ -1243,7 +1269,7 @@ int CVODESSolver::RHSQB(realtype t, N_Vector y, N_Vector yB, N_Vector qBdot,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CVODESSolver::RHSB(realtype t, N_Vector y, N_Vector yB, N_Vector yBdot,
|
||||
int CVODESSolver::RHSB(sunrealtype t, N_Vector y, N_Vector yB, N_Vector yBdot,
|
||||
void *user_dataB)
|
||||
{
|
||||
CVODESSolver *self = static_cast<CVODESSolver*>(user_dataB);
|
||||
@@ -1341,7 +1367,7 @@ CVODESSolver::~CVODESSolver()
|
||||
// ARKStep interface
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
int ARKStepSolver::RHS1(realtype t, const N_Vector y, N_Vector result,
|
||||
int ARKStepSolver::RHS1(sunrealtype t, const N_Vector y, N_Vector result,
|
||||
void *user_data)
|
||||
{
|
||||
// Get data from N_Vectors
|
||||
@@ -1373,7 +1399,7 @@ int ARKStepSolver::RHS1(realtype t, const N_Vector y, N_Vector result,
|
||||
return (0);
|
||||
}
|
||||
|
||||
int ARKStepSolver::RHS2(realtype t, const N_Vector y, N_Vector result,
|
||||
int ARKStepSolver::RHS2(sunrealtype t, const N_Vector y, N_Vector result,
|
||||
void *user_data)
|
||||
{
|
||||
// Get data from N_Vectors
|
||||
@@ -1399,9 +1425,9 @@ int ARKStepSolver::RHS2(realtype t, const N_Vector y, N_Vector result,
|
||||
return (0);
|
||||
}
|
||||
|
||||
int ARKStepSolver::LinSysSetup(realtype t, N_Vector y, N_Vector fy, SUNMatrix A,
|
||||
SUNMatrix, booleantype jok, booleantype *jcur,
|
||||
realtype gamma,
|
||||
int ARKStepSolver::LinSysSetup(sunrealtype t, N_Vector y, N_Vector fy,
|
||||
SUNMatrix A, SUNMatrix, sunbooleantype jok,
|
||||
sunbooleantype *jcur, sunrealtype gamma,
|
||||
void*, N_Vector, N_Vector, N_Vector)
|
||||
{
|
||||
// Get data from N_Vectors
|
||||
@@ -1419,7 +1445,7 @@ int ARKStepSolver::LinSysSetup(realtype t, N_Vector y, N_Vector fy, SUNMatrix A,
|
||||
}
|
||||
|
||||
int ARKStepSolver::LinSysSolve(SUNLinearSolver LS, SUNMatrix, N_Vector x,
|
||||
N_Vector b, realtype tol)
|
||||
N_Vector b, sunrealtype tol)
|
||||
{
|
||||
SundialsNVector mfem_x(x);
|
||||
const SundialsNVector mfem_b(b);
|
||||
@@ -1433,7 +1459,7 @@ int ARKStepSolver::LinSysSolve(SUNLinearSolver LS, SUNMatrix, N_Vector x,
|
||||
return (self->f->SUNImplicitSolve(mfem_b, mfem_x, tol));
|
||||
}
|
||||
|
||||
int ARKStepSolver::MassSysSetup(realtype t, SUNMatrix M,
|
||||
int ARKStepSolver::MassSysSetup(sunrealtype t, SUNMatrix M,
|
||||
void*, N_Vector, N_Vector, N_Vector)
|
||||
{
|
||||
ARKStepSolver *self = static_cast<ARKStepSolver*>(GET_CONTENT(M));
|
||||
@@ -1444,7 +1470,7 @@ int ARKStepSolver::MassSysSetup(realtype t, SUNMatrix M,
|
||||
}
|
||||
|
||||
int ARKStepSolver::MassSysSolve(SUNLinearSolver LS, SUNMatrix, N_Vector x,
|
||||
N_Vector b, realtype tol)
|
||||
N_Vector b, sunrealtype tol)
|
||||
{
|
||||
SundialsNVector mfem_x(x);
|
||||
const SundialsNVector mfem_b(b);
|
||||
@@ -1464,7 +1490,7 @@ int ARKStepSolver::MassMult1(SUNMatrix M, N_Vector x, N_Vector v)
|
||||
return (self->f->SUNMassMult(mfem_x, mfem_v));
|
||||
}
|
||||
|
||||
int ARKStepSolver::MassMult2(N_Vector x, N_Vector v, realtype t,
|
||||
int ARKStepSolver::MassMult2(N_Vector x, N_Vector v, sunrealtype t,
|
||||
void* mtimes_data)
|
||||
{
|
||||
const SundialsNVector mfem_x(x);
|
||||
@@ -1535,7 +1561,7 @@ void ARKStepSolver::Init(TimeDependentOperator &f_)
|
||||
// Free existing solver memory and re-create with new vector size
|
||||
if (resize)
|
||||
{
|
||||
ARKStepFree(&sundials_mem);
|
||||
MFEM_ARKode(Free)(&sundials_mem);
|
||||
sundials_mem = NULL;
|
||||
}
|
||||
}
|
||||
@@ -1573,12 +1599,15 @@ void ARKStepSolver::Init(TimeDependentOperator &f_)
|
||||
MFEM_VERIFY(sundials_mem, "error in ARKStepCreate()");
|
||||
|
||||
// Attach the ARKStepSolver as user-defined data
|
||||
flag = ARKStepSetUserData(sundials_mem, this);
|
||||
MFEM_VERIFY(flag == ARK_SUCCESS, "error in ARKStepSetUserData()");
|
||||
flag = MFEM_ARKode(SetUserData)(sundials_mem, this);
|
||||
MFEM_VERIFY(flag == ARK_SUCCESS,
|
||||
"error in " STR(MFEM_ARKode(SetUserData)) "()");
|
||||
|
||||
// Set default tolerances
|
||||
flag = ARKStepSStolerances(sundials_mem, default_rel_tol, default_abs_tol);
|
||||
MFEM_VERIFY(flag == ARK_SUCCESS, "error in ARKStepSetSStolerances()");
|
||||
flag = MFEM_ARKode(SStolerances)(sundials_mem, default_rel_tol,
|
||||
default_abs_tol);
|
||||
MFEM_VERIFY(flag == ARK_SUCCESS,
|
||||
"error in " STR(MFEM_ARKode(SStolerances)) "()");
|
||||
|
||||
// If implicit, attach MFEM linear solver by default
|
||||
if (use_implicit) { UseMFEMLinearSolver(); }
|
||||
@@ -1617,15 +1646,16 @@ void ARKStepSolver::Step(Vector &x, real_t &t, real_t &dt)
|
||||
|
||||
// Integrate the system
|
||||
double tout = t + dt;
|
||||
flag = ARKStepEvolve(sundials_mem, tout, *Y, &t, step_mode);
|
||||
MFEM_VERIFY(flag >= 0, "error in ARKStepEvolve()");
|
||||
flag = MFEM_ARKode(Evolve)(sundials_mem, tout, *Y, &t, step_mode);
|
||||
MFEM_VERIFY(flag >= 0, "error in " STR(MFEM_ARKode(Evolve)) "()");
|
||||
|
||||
// Make sure host is up to date
|
||||
Y->HostRead();
|
||||
|
||||
// Return the last incremental step size
|
||||
flag = ARKStepGetLastStep(sundials_mem, &dt);
|
||||
MFEM_VERIFY(flag == ARK_SUCCESS, "error in ARKStepGetLastStep()");
|
||||
flag = MFEM_ARKode(GetLastStep)(sundials_mem, &dt);
|
||||
MFEM_VERIFY(flag == ARK_SUCCESS,
|
||||
"error in " STR(MFEM_ARKode(GetLastStep)) "()");
|
||||
}
|
||||
|
||||
void ARKStepSolver::UseMFEMLinearSolver()
|
||||
@@ -1651,12 +1681,14 @@ void ARKStepSolver::UseMFEMLinearSolver()
|
||||
A->ops->destroy = MatDestroy;
|
||||
|
||||
// Attach the linear solver and matrix
|
||||
flag = ARKStepSetLinearSolver(sundials_mem, LSA, A);
|
||||
MFEM_VERIFY(flag == ARK_SUCCESS, "error in ARKStepSetLinearSolver()");
|
||||
flag = MFEM_ARKode(SetLinearSolver)(sundials_mem, LSA, A);
|
||||
MFEM_VERIFY(flag == ARK_SUCCESS,
|
||||
"error in " STR(MFEM_ARKode(SetLinearSolver)) "()");
|
||||
|
||||
// Set the linear system evaluation function
|
||||
flag = ARKStepSetLinSysFn(sundials_mem, ARKStepSolver::LinSysSetup);
|
||||
MFEM_VERIFY(flag == ARK_SUCCESS, "error in ARKStepSetLinSysFn()");
|
||||
flag = MFEM_ARKode(SetLinSysFn)(sundials_mem, ARKStepSolver::LinSysSetup);
|
||||
MFEM_VERIFY(flag == ARK_SUCCESS,
|
||||
"error in " STR(MFEM_ARKode(SetLinSysFn)) "()");
|
||||
}
|
||||
|
||||
void ARKStepSolver::UseSundialsLinearSolver()
|
||||
@@ -1666,12 +1698,13 @@ void ARKStepSolver::UseSundialsLinearSolver()
|
||||
if (LSA != NULL) { SUNLinSolFree(LSA); LSA = NULL; }
|
||||
|
||||
// Create linear solver
|
||||
LSA = SUNLinSol_SPGMR(*Y, PREC_NONE, 0, Sundials::GetContext());
|
||||
LSA = SUNLinSol_SPGMR(*Y, SUN_PREC_NONE, 0, Sundials::GetContext());
|
||||
MFEM_VERIFY(LSA, "error in SUNLinSol_SPGMR()");
|
||||
|
||||
// Attach linear solver
|
||||
flag = ARKStepSetLinearSolver(sundials_mem, LSA, NULL);
|
||||
MFEM_VERIFY(flag == ARK_SUCCESS, "error in ARKStepSetLinearSolver()");
|
||||
flag = MFEM_ARKode(SetLinearSolver)(sundials_mem, LSA, NULL);
|
||||
MFEM_VERIFY(flag == ARK_SUCCESS,
|
||||
"error in " STR(MFEM_ARKode(SetLinearSolver)) "()");
|
||||
}
|
||||
|
||||
void ARKStepSolver::UseMFEMMassLinearSolver(int tdep)
|
||||
@@ -1698,12 +1731,14 @@ void ARKStepSolver::UseMFEMMassLinearSolver(int tdep)
|
||||
M->ops->destroy = MatDestroy;
|
||||
|
||||
// Attach the linear solver and matrix
|
||||
flag = ARKStepSetMassLinearSolver(sundials_mem, LSM, M, tdep);
|
||||
MFEM_VERIFY(flag == ARK_SUCCESS, "error in ARKStepSetLinearSolver()");
|
||||
flag = MFEM_ARKode(SetMassLinearSolver)(sundials_mem, LSM, M, tdep);
|
||||
MFEM_VERIFY(flag == ARK_SUCCESS,
|
||||
"error in " STR(MFEM_ARKode(SetMassLinearSolver)) "()");
|
||||
|
||||
// Set the linear system function
|
||||
flag = ARKStepSetMassFn(sundials_mem, ARKStepSolver::MassSysSetup);
|
||||
MFEM_VERIFY(flag == ARK_SUCCESS, "error in ARKStepSetMassFn()");
|
||||
flag = MFEM_ARKode(SetMassFn)(sundials_mem, ARKStepSolver::MassSysSetup);
|
||||
MFEM_VERIFY(flag == ARK_SUCCESS,
|
||||
"error in " STR(MFEM_ARKode(SetMassFn)) "()");
|
||||
|
||||
// Check that the ODE is not expressed in EXPLICIT form
|
||||
MFEM_VERIFY(!f->isExplicit(), "ODE operator is expressed in EXPLICIT form")
|
||||
@@ -1716,17 +1751,19 @@ void ARKStepSolver::UseSundialsMassLinearSolver(int tdep)
|
||||
if (LSM != NULL) { SUNLinSolFree(LSM); LSM = NULL; }
|
||||
|
||||
// Create linear solver
|
||||
LSM = SUNLinSol_SPGMR(*Y, PREC_NONE, 0, Sundials::GetContext());
|
||||
LSM = SUNLinSol_SPGMR(*Y, SUN_PREC_NONE, 0, Sundials::GetContext());
|
||||
MFEM_VERIFY(LSM, "error in SUNLinSol_SPGMR()");
|
||||
|
||||
// Attach linear solver
|
||||
flag = ARKStepSetMassLinearSolver(sundials_mem, LSM, NULL, tdep);
|
||||
MFEM_VERIFY(flag == ARK_SUCCESS, "error in ARKStepSetMassLinearSolver()");
|
||||
flag = MFEM_ARKode(SetMassLinearSolver)(sundials_mem, LSM, NULL, tdep);
|
||||
MFEM_VERIFY(flag == ARK_SUCCESS,
|
||||
"error in " STR(MFEM_ARKode(SetMassLinearSolver)) "()");
|
||||
|
||||
// Attach matrix multiplication function
|
||||
flag = ARKStepSetMassTimes(sundials_mem, NULL, ARKStepSolver::MassMult2,
|
||||
this);
|
||||
MFEM_VERIFY(flag == ARK_SUCCESS, "error in ARKStepSetMassTimes()");
|
||||
flag = MFEM_ARKode(SetMassTimes)(sundials_mem, NULL,
|
||||
ARKStepSolver::MassMult2, this);
|
||||
MFEM_VERIFY(flag == ARK_SUCCESS,
|
||||
"error in " STR(MFEM_ARKode(SetMassTimes)) "()");
|
||||
|
||||
// Check that the ODE is not expressed in EXPLICIT form
|
||||
MFEM_VERIFY(!f->isExplicit(), "ODE operator is expressed in EXPLICIT form")
|
||||
@@ -1739,20 +1776,23 @@ void ARKStepSolver::SetStepMode(int itask)
|
||||
|
||||
void ARKStepSolver::SetSStolerances(double reltol, double abstol)
|
||||
{
|
||||
flag = ARKStepSStolerances(sundials_mem, reltol, abstol);
|
||||
MFEM_VERIFY(flag == ARK_SUCCESS, "error in ARKStepSStolerances()");
|
||||
flag = MFEM_ARKode(SStolerances)(sundials_mem, reltol, abstol);
|
||||
MFEM_VERIFY(flag == ARK_SUCCESS,
|
||||
"error in " STR(MFEM_ARKode(SStolerances)) "()");
|
||||
}
|
||||
|
||||
void ARKStepSolver::SetMaxStep(double dt_max)
|
||||
{
|
||||
flag = ARKStepSetMaxStep(sundials_mem, dt_max);
|
||||
MFEM_VERIFY(flag == ARK_SUCCESS, "error in ARKStepSetMaxStep()");
|
||||
flag = MFEM_ARKode(SetMaxStep)(sundials_mem, dt_max);
|
||||
MFEM_VERIFY(flag == ARK_SUCCESS,
|
||||
"error in " STR(MFEM_ARKode(SetMaxStep)) "()");
|
||||
}
|
||||
|
||||
void ARKStepSolver::SetOrder(int order)
|
||||
{
|
||||
flag = ARKStepSetOrder(sundials_mem, order);
|
||||
MFEM_VERIFY(flag == ARK_SUCCESS, "error in ARKStepSetOrder()");
|
||||
flag = MFEM_ARKode(SetOrder)(sundials_mem, order);
|
||||
MFEM_VERIFY(flag == ARK_SUCCESS,
|
||||
"error in " STR(MFEM_ARKode(SetOrder)) "()");
|
||||
}
|
||||
|
||||
void ARKStepSolver::SetERKTableNum(ARKODE_ERKTableID table_id)
|
||||
@@ -1776,8 +1816,9 @@ void ARKStepSolver::SetIMEXTableNum(ARKODE_ERKTableID etable_id,
|
||||
|
||||
void ARKStepSolver::SetFixedStep(double dt)
|
||||
{
|
||||
flag = ARKStepSetFixedStep(sundials_mem, dt);
|
||||
MFEM_VERIFY(flag == ARK_SUCCESS, "error in ARKStepSetFixedStep()");
|
||||
flag = MFEM_ARKode(SetFixedStep)(sundials_mem, dt);
|
||||
MFEM_VERIFY(flag == ARK_SUCCESS,
|
||||
"error in " STR(MFEM_ARKode(SetFixedStep)) "()");
|
||||
}
|
||||
|
||||
void ARKStepSolver::PrintInfo() const
|
||||
@@ -1799,18 +1840,19 @@ void ARKStepSolver::PrintInfo() const
|
||||
&netfails);
|
||||
MFEM_VERIFY(flag == ARK_SUCCESS, "error in ARKStepGetTimestepperStats()");
|
||||
|
||||
flag = ARKStepGetStepStats(sundials_mem,
|
||||
&nsteps,
|
||||
&hinused,
|
||||
&hlast,
|
||||
&hcur,
|
||||
&tcur);
|
||||
flag = MFEM_ARKode(GetStepStats)(sundials_mem,
|
||||
&nsteps,
|
||||
&hinused,
|
||||
&hlast,
|
||||
&hcur,
|
||||
&tcur);
|
||||
|
||||
// Get nonlinear solver stats
|
||||
flag = ARKStepGetNonlinSolvStats(sundials_mem,
|
||||
&nniters,
|
||||
&nncfails);
|
||||
MFEM_VERIFY(flag == ARK_SUCCESS, "error in ARKStepGetNonlinSolvStats()");
|
||||
flag = MFEM_ARKode(GetNonlinSolvStats)(sundials_mem,
|
||||
&nniters,
|
||||
&nncfails);
|
||||
MFEM_VERIFY(flag == ARK_SUCCESS,
|
||||
"error in " STR(MFEM_ARKode(GetNonlinSolvStats)) "()");
|
||||
|
||||
mfem::out <<
|
||||
"ARKStep:\n"
|
||||
@@ -1838,7 +1880,7 @@ ARKStepSolver::~ARKStepSolver()
|
||||
SUNMatDestroy(A);
|
||||
SUNLinSolFree(LSA);
|
||||
SUNNonlinSolFree(NLS);
|
||||
ARKStepFree(&sundials_mem);
|
||||
MFEM_ARKode(Free)(&sundials_mem);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -1861,7 +1903,7 @@ int KINSolver::Mult(const N_Vector u, N_Vector fu, void *user_data)
|
||||
|
||||
// Wrapper for computing Jacobian-vector products
|
||||
int KINSolver::GradientMult(N_Vector v, N_Vector Jv, N_Vector u,
|
||||
booleantype *new_u, void *user_data)
|
||||
sunbooleantype *new_u, void *user_data)
|
||||
{
|
||||
const SundialsNVector mfem_v(v);
|
||||
SundialsNVector mfem_Jv(Jv);
|
||||
@@ -1901,7 +1943,7 @@ int KINSolver::LinSysSetup(N_Vector u, N_Vector, SUNMatrix J,
|
||||
|
||||
// Wrapper for solving linear systems J u = b
|
||||
int KINSolver::LinSysSolve(SUNLinearSolver LS, SUNMatrix, N_Vector u,
|
||||
N_Vector b, realtype)
|
||||
N_Vector b, sunrealtype)
|
||||
{
|
||||
SundialsNVector mfem_u(u), mfem_b(b);
|
||||
KINSolver *self = static_cast<KINSolver*>(GET_CONTENT(LS));
|
||||
@@ -1960,7 +2002,11 @@ KINSolver::KINSolver(int strategy, bool oper_grad)
|
||||
f_scale = new SundialsNVector();
|
||||
|
||||
// Default abs_tol and print_level
|
||||
#if MFEM_SUNDIALS_VERSION < 70000
|
||||
abs_tol = pow(UNIT_ROUNDOFF, 1.0/3.0);
|
||||
#else
|
||||
abs_tol = pow(SUN_UNIT_ROUNDOFF, 1.0/3.0);
|
||||
#endif
|
||||
print_level = 0;
|
||||
}
|
||||
|
||||
@@ -1974,7 +2020,11 @@ KINSolver::KINSolver(MPI_Comm comm, int strategy, bool oper_grad)
|
||||
f_scale = new SundialsNVector(comm);
|
||||
|
||||
// Default abs_tol and print_level
|
||||
#if MFEM_SUNDIALS_VERSION < 70000
|
||||
abs_tol = pow(UNIT_ROUNDOFF, 1.0/3.0);
|
||||
#else
|
||||
abs_tol = pow(SUN_UNIT_ROUNDOFF, 1.0/3.0);
|
||||
#endif
|
||||
print_level = 0;
|
||||
}
|
||||
#endif
|
||||
@@ -2086,7 +2136,7 @@ void KINSolver::SetOperator(const Operator &op)
|
||||
if (A != NULL) { SUNMatDestroy(A); A = NULL; }
|
||||
if (LSA != NULL) { SUNLinSolFree(LSA); LSA = NULL; }
|
||||
|
||||
LSA = SUNLinSol_SPGMR(*Y, PREC_NONE, 0, Sundials::GetContext());
|
||||
LSA = SUNLinSol_SPGMR(*Y, SUN_PREC_NONE, 0, Sundials::GetContext());
|
||||
MFEM_VERIFY(LSA, "error in SUNLinSol_SPGMR()");
|
||||
|
||||
flag = KINSetLinearSolver(sundials_mem, LSA, NULL);
|
||||
@@ -2155,12 +2205,12 @@ void KINSolver::SetJFNKSolver(Solver &solver)
|
||||
if (LSA != NULL) { SUNLinSolFree(LSA); LSA = NULL; }
|
||||
|
||||
// Setup FGMRES
|
||||
LSA = SUNLinSol_SPFGMR(*Y, prec ? PREC_RIGHT : PREC_NONE, maxli,
|
||||
LSA = SUNLinSol_SPFGMR(*Y, prec ? SUN_PREC_RIGHT : SUN_PREC_NONE, maxli,
|
||||
Sundials::GetContext());
|
||||
MFEM_VERIFY(LSA, "error in SUNLinSol_SPFGMR()");
|
||||
|
||||
flag = SUNLinSol_SPFGMRSetMaxRestarts(LSA, maxlrs);
|
||||
MFEM_VERIFY(flag == SUNLS_SUCCESS, "error in SUNLinSol_SPFGMR()");
|
||||
MFEM_VERIFY(flag == SUN_SUCCESS, "error in SUNLinSol_SPFGMR()");
|
||||
|
||||
flag = KINSetLinearSolver(sundials_mem, LSA, NULL);
|
||||
MFEM_VERIFY(flag == KIN_SUCCESS, "error in KINSetLinearSolver()");
|
||||
@@ -2317,18 +2367,21 @@ void KINSolver::Mult(Vector &x,
|
||||
|
||||
if (rank == 0)
|
||||
{
|
||||
#if MFEM_SUNDIALS_VERSION < 70000
|
||||
flag = KINSetPrintLevel(sundials_mem, print_level);
|
||||
MFEM_VERIFY(flag == KIN_SUCCESS, "KINSetPrintLevel() failed!");
|
||||
#endif
|
||||
// NOTE: there is no KINSetPrintLevel in SUNDIALS v7!
|
||||
|
||||
#ifdef SUNDIALS_BUILD_WITH_MONITORING
|
||||
if (jfnk && print_level)
|
||||
{
|
||||
flag = SUNLinSolSetInfoFile_SPFGMR(LSA, stdout);
|
||||
MFEM_VERIFY(flag == SUNLS_SUCCESS,
|
||||
MFEM_VERIFY(flag == SUN_SUCCESS,
|
||||
"error in SUNLinSolSetInfoFile_SPFGMR()");
|
||||
|
||||
flag = SUNLinSolSetPrintLevel_SPFGMR(LSA, 1);
|
||||
MFEM_VERIFY(flag == SUNLS_SUCCESS,
|
||||
MFEM_VERIFY(flag == SUN_SUCCESS,
|
||||
"error in SUNLinSolSetPrintLevel_SPFGMR()");
|
||||
}
|
||||
#endif
|
||||
|
||||
+65
-31
@@ -54,6 +54,10 @@
|
||||
|
||||
#include <functional>
|
||||
|
||||
#define MFEM_SUNDIALS_VERSION \
|
||||
(SUNDIALS_VERSION_MAJOR*10000 + SUNDIALS_VERSION_MINOR*100 + \
|
||||
SUNDIALS_VERSION_PATCH)
|
||||
|
||||
#if (SUNDIALS_VERSION_MAJOR < 6)
|
||||
|
||||
/// (DEPRECATED) Map SUNDIALS version >= 6 datatypes and constants to
|
||||
@@ -68,13 +72,30 @@ constexpr ARKODE_ERKTableID ARKODE_FEHLBERG_13_7_8 = FEHLBERG_13_7_8;
|
||||
/// arbitrary type for more compact backwards compatibility
|
||||
using SUNContext = void*;
|
||||
|
||||
/// 'sunrealtype' was first introduced in v6.0.0
|
||||
typedef realtype sunrealtype;
|
||||
/// 'sunbooleantype' was first introduced in v6.0.0
|
||||
typedef booleantype sunbooleantype;
|
||||
|
||||
/// New constant names introduced in v6.0.0
|
||||
enum { SUN_PREC_NONE, SUN_PREC_LEFT, SUN_PREC_RIGHT, SUN_PREC_BOTH };
|
||||
|
||||
// KIN_ORTH_MGS was introduced in SUNDIALS v6; here, we define it just so that
|
||||
// it can be used as the default option in the second parameter of
|
||||
// KINSolver::EnableAndersonAcc -- the actual value of the parameter will be
|
||||
// ignored when using SUNDIALS < v6.
|
||||
#define KIN_ORTH_MGS 0
|
||||
|
||||
#endif // SUNDIALS_VERSION_MAJOR < 6
|
||||
#endif // #if SUNDIALS_VERSION_MAJOR < 6
|
||||
|
||||
#if (SUNDIALS_VERSION_MAJOR < 7)
|
||||
|
||||
/** @brief The enum constant SUN_SUCCESS was added in v7 as a replacement of
|
||||
various *_SUCCESS macros that were removed in v7. */
|
||||
enum { SUN_SUCCESS = 0 };
|
||||
|
||||
#endif // #if SUNDIALS_VERSION_MAJOR < 7
|
||||
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
@@ -244,7 +265,14 @@ public:
|
||||
|
||||
#ifdef MFEM_USE_MPI
|
||||
/// Returns the MPI communicator for the internal N_Vector x.
|
||||
inline MPI_Comm GetComm() const { return *static_cast<MPI_Comm*>(N_VGetCommunicator(x)); }
|
||||
inline MPI_Comm GetComm() const
|
||||
{
|
||||
#if SUNDIALS_VERSION_MAJOR < 7
|
||||
return *static_cast<MPI_Comm*>(N_VGetCommunicator(x));
|
||||
#else
|
||||
return N_VGetCommunicator(x);
|
||||
#endif
|
||||
}
|
||||
|
||||
/// Returns the MPI global length for the internal N_Vector x.
|
||||
inline long GlobalSize() const { return N_VGetLength(x); }
|
||||
@@ -396,24 +424,26 @@ protected:
|
||||
int root_components; /// Number of components in gout
|
||||
|
||||
/// Wrapper to compute the ODE rhs function.
|
||||
static int RHS(realtype t, const N_Vector y, N_Vector ydot, void *user_data);
|
||||
static int RHS(sunrealtype t, const N_Vector y, N_Vector ydot,
|
||||
void *user_data);
|
||||
|
||||
/// Setup the linear system $ A x = b $.
|
||||
static int LinSysSetup(realtype t, N_Vector y, N_Vector fy, SUNMatrix A,
|
||||
booleantype jok, booleantype *jcur,
|
||||
realtype gamma, void *user_data, N_Vector tmp1,
|
||||
static int LinSysSetup(sunrealtype t, N_Vector y, N_Vector fy, SUNMatrix A,
|
||||
sunbooleantype jok, sunbooleantype *jcur,
|
||||
sunrealtype gamma, void *user_data, N_Vector tmp1,
|
||||
N_Vector tmp2, N_Vector tmp3);
|
||||
|
||||
/// Solve the linear system $ A x = b $.
|
||||
static int LinSysSolve(SUNLinearSolver LS, SUNMatrix A, N_Vector x,
|
||||
N_Vector b, realtype tol);
|
||||
N_Vector b, sunrealtype tol);
|
||||
|
||||
/// Prototype to define root finding for CVODE
|
||||
static int root(realtype t, N_Vector y, realtype *gout, void *user_data);
|
||||
static int root(sunrealtype t, N_Vector y, sunrealtype *gout,
|
||||
void *user_data);
|
||||
|
||||
/// Typedef for root finding functions
|
||||
typedef std::function<int(realtype t, Vector y, Vector gout, CVODESolver *)>
|
||||
RootFunction;
|
||||
typedef std::function<int(sunrealtype t, Vector y, Vector gout,
|
||||
CVODESolver *)> RootFunction;
|
||||
|
||||
/// A class member to facilitate pointing to a user-specified root function
|
||||
RootFunction root_func;
|
||||
@@ -421,7 +451,8 @@ protected:
|
||||
/// Typedef declaration for error weight functions
|
||||
typedef std::function<int(Vector y, Vector w, CVODESolver*)> EWTFunction;
|
||||
|
||||
/// A class member to facilitate pointing to a user-specified error weight function
|
||||
/** @brief A class member to facilitate pointing to a user-specified error
|
||||
weight function */
|
||||
EWTFunction ewt_func;
|
||||
|
||||
public:
|
||||
@@ -455,7 +486,7 @@ public:
|
||||
@note If this method is called a second time with a different problem
|
||||
size, then any non-default user-set options will be lost and will need
|
||||
to be set again. */
|
||||
void Init(TimeDependentOperator &f_);
|
||||
void Init(TimeDependentOperator &f_) override;
|
||||
|
||||
/// Integrate the ODE with CVODE using the specified step mode.
|
||||
/** @param[in,out] x On output, the solution vector at the requested output
|
||||
@@ -531,14 +562,15 @@ protected:
|
||||
int indexB; ///< backward problem index
|
||||
|
||||
/// Wrapper to compute the ODE RHS Quadrature function.
|
||||
static int RHSQ(realtype t, const N_Vector y, N_Vector qdot, void *user_data);
|
||||
static int RHSQ(sunrealtype t, const N_Vector y, N_Vector qdot,
|
||||
void *user_data);
|
||||
|
||||
/// Wrapper to compute the ODE RHS backward function.
|
||||
static int RHSB(realtype t, N_Vector y,
|
||||
static int RHSB(sunrealtype t, N_Vector y,
|
||||
N_Vector yB, N_Vector yBdot, void *user_dataB);
|
||||
|
||||
/// Wrapper to compute the ODE RHS Backwards Quadrature function.
|
||||
static int RHSQB(realtype t, N_Vector y, N_Vector yB,
|
||||
static int RHSQB(sunrealtype t, N_Vector y, N_Vector yB,
|
||||
N_Vector qBdot, void *user_dataB);
|
||||
|
||||
/// Error control function
|
||||
@@ -654,15 +686,15 @@ public:
|
||||
void SetSVtolerancesB(double reltol, Vector abstol);
|
||||
|
||||
/// Setup the linear system A x = b
|
||||
static int LinSysSetupB(realtype t, N_Vector y, N_Vector yB, N_Vector fyB,
|
||||
static int LinSysSetupB(sunrealtype t, N_Vector y, N_Vector yB, N_Vector fyB,
|
||||
SUNMatrix A,
|
||||
booleantype jok, booleantype *jcur,
|
||||
realtype gamma, void *user_data, N_Vector tmp1,
|
||||
sunbooleantype jok, sunbooleantype *jcur,
|
||||
sunrealtype gamma, void *user_data, N_Vector tmp1,
|
||||
N_Vector tmp2, N_Vector tmp3);
|
||||
|
||||
/// Solve the linear system A x = b
|
||||
static int LinSysSolveB(SUNLinearSolver LS, SUNMatrix A, N_Vector x,
|
||||
N_Vector b, realtype tol);
|
||||
N_Vector b, sunrealtype tol);
|
||||
|
||||
|
||||
/// Destroy the associated CVODES memory and SUNDIALS objects.
|
||||
@@ -695,33 +727,35 @@ protected:
|
||||
RHS1 is explicit RHS and RHS2 the implicit RHS for IMEX integration. When
|
||||
purely implicit or explicit only RHS1 is used. */
|
||||
///@{
|
||||
static int RHS1(realtype t, const N_Vector y, N_Vector ydot, void *user_data);
|
||||
static int RHS2(realtype t, const N_Vector y, N_Vector ydot, void *user_data);
|
||||
static int RHS1(sunrealtype t, const N_Vector y, N_Vector ydot,
|
||||
void *user_data);
|
||||
static int RHS2(sunrealtype t, const N_Vector y, N_Vector ydot,
|
||||
void *user_data);
|
||||
///@}
|
||||
|
||||
/// Setup the linear system $ A x = b $.
|
||||
static int LinSysSetup(realtype t, N_Vector y, N_Vector fy, SUNMatrix A,
|
||||
SUNMatrix M, booleantype jok, booleantype *jcur,
|
||||
realtype gamma, void *user_data, N_Vector tmp1,
|
||||
static int LinSysSetup(sunrealtype t, N_Vector y, N_Vector fy, SUNMatrix A,
|
||||
SUNMatrix M, sunbooleantype jok, sunbooleantype *jcur,
|
||||
sunrealtype gamma, void *user_data, N_Vector tmp1,
|
||||
N_Vector tmp2, N_Vector tmp3);
|
||||
|
||||
/// Solve the linear system $ A x = b $.
|
||||
static int LinSysSolve(SUNLinearSolver LS, SUNMatrix A, N_Vector x,
|
||||
N_Vector b, realtype tol);
|
||||
N_Vector b, sunrealtype tol);
|
||||
|
||||
/// Setup the linear system $ M x = b $.
|
||||
static int MassSysSetup(realtype t, SUNMatrix M, void *user_data,
|
||||
static int MassSysSetup(sunrealtype t, SUNMatrix M, void *user_data,
|
||||
N_Vector tmp1, N_Vector tmp2, N_Vector tmp3);
|
||||
|
||||
/// Solve the linear system $ M x = b $.
|
||||
static int MassSysSolve(SUNLinearSolver LS, SUNMatrix M, N_Vector x,
|
||||
N_Vector b, realtype tol);
|
||||
N_Vector b, sunrealtype tol);
|
||||
|
||||
/// Compute the matrix-vector product $ v = M x $.
|
||||
static int MassMult1(SUNMatrix M, N_Vector x, N_Vector v);
|
||||
|
||||
/// Compute the matrix-vector product $v = M_t x $ at time t.
|
||||
static int MassMult2(N_Vector x, N_Vector v, realtype t,
|
||||
static int MassMult2(N_Vector x, N_Vector v, sunrealtype t,
|
||||
void* mtimes_data);
|
||||
|
||||
public:
|
||||
@@ -757,7 +791,7 @@ public:
|
||||
@note If this method is called a second time with a different problem
|
||||
size, then any non-default user-set options will be lost and will need
|
||||
to be set again. */
|
||||
void Init(TimeDependentOperator &f_);
|
||||
void Init(TimeDependentOperator &f_) override;
|
||||
|
||||
/// Integrate the ODE with ARKode using the specified step mode.
|
||||
/**
|
||||
@@ -871,7 +905,7 @@ protected:
|
||||
|
||||
/// Wrapper to compute the Jacobian-vector product $ J(u) v = Jv $.
|
||||
static int GradientMult(N_Vector v, N_Vector Jv, N_Vector u,
|
||||
booleantype *new_u, void *user_data);
|
||||
sunbooleantype *new_u, void *user_data);
|
||||
|
||||
/// Setup the linear system $ J u = b $.
|
||||
static int LinSysSetup(N_Vector u, N_Vector fu, SUNMatrix J,
|
||||
@@ -879,7 +913,7 @@ protected:
|
||||
|
||||
/// Solve the linear system $ J u = b $.
|
||||
static int LinSysSolve(SUNLinearSolver LS, SUNMatrix J, N_Vector u,
|
||||
N_Vector b, realtype tol);
|
||||
N_Vector b, sunrealtype tol);
|
||||
|
||||
/// Setup the preconditioner.
|
||||
static int PrecSetup(N_Vector uu,
|
||||
|
||||
+11
-3
@@ -24,6 +24,8 @@
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
#include <limits>
|
||||
#include <type_traits>
|
||||
#include <initializer_list>
|
||||
#if defined(_MSC_VER) && (_MSC_VER < 1800)
|
||||
#include <float.h>
|
||||
#define isfinite _finite
|
||||
@@ -119,10 +121,16 @@ public:
|
||||
Vector(int size_, MemoryType h_mt, MemoryType d_mt)
|
||||
: data(size_, h_mt, d_mt), size(size_) { }
|
||||
|
||||
/// Create a vector from a statically sized C-style array of convertible type
|
||||
template <typename CT, int N>
|
||||
explicit Vector(const CT (&values)[N]) : Vector(N)
|
||||
{ std::copy(values, values + N, begin()); }
|
||||
|
||||
/// Create a vector using a braced initializer list
|
||||
template <int N, typename T = real_t>
|
||||
explicit Vector(const T (&values)[N]) : Vector(N)
|
||||
{ std::copy(values, values + N, GetData()); }
|
||||
template <typename CT, typename std::enable_if<
|
||||
std::is_convertible<CT,real_t>::value,bool>::type = true>
|
||||
explicit Vector(std::initializer_list<CT> values) : Vector(values.size())
|
||||
{ std::copy(values.begin(), values.end(), begin()); }
|
||||
|
||||
/// Enable execution of Vector operations using the mfem::Device.
|
||||
/** The default is to use Backend::CPU (serial execution on each MPI rank),
|
||||
|
||||
+8
-4
@@ -32,6 +32,7 @@ set(SRCS
|
||||
vtk.cpp
|
||||
wedge.cpp
|
||||
submesh/submesh.cpp
|
||||
submesh/ncsubmesh.cpp
|
||||
submesh/submesh_utils.cpp
|
||||
submesh/transfermap.cpp
|
||||
)
|
||||
@@ -58,6 +59,7 @@ set(HDRS
|
||||
vertex.hpp
|
||||
vtk.hpp
|
||||
wedge.hpp
|
||||
submesh/ncsubmesh.hpp
|
||||
submesh/submesh.hpp
|
||||
submesh/submesh_utils.hpp
|
||||
submesh/transfer_category.hpp
|
||||
@@ -68,15 +70,17 @@ if (MFEM_USE_MPI)
|
||||
list(APPEND SRCS
|
||||
pmesh.cpp
|
||||
pncmesh.cpp
|
||||
submesh/ptransfermap.cpp
|
||||
submesh/psubmesh.cpp)
|
||||
submesh/pncsubmesh.cpp
|
||||
submesh/psubmesh.cpp
|
||||
submesh/ptransfermap.cpp)
|
||||
# If this list (HDRS -> HEADERS) is used for install, we probably want the
|
||||
# headers added all the time.
|
||||
list(APPEND HDRS
|
||||
pmesh.hpp
|
||||
pncmesh.hpp
|
||||
submesh/ptransfermap.hpp
|
||||
submesh/psubmesh.hpp)
|
||||
submesh/pncsubmesh.hpp
|
||||
submesh/psubmesh.hpp
|
||||
submesh/ptransfermap.hpp)
|
||||
endif()
|
||||
|
||||
if (MFEM_USE_PUMI)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user