Compare commits
622
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cf1c58ee1c | ||
|
|
02579a1d23 | ||
|
|
66d9ead7b1 | ||
|
|
da351da0e3 | ||
|
|
fba3262eb9 | ||
|
|
b9d950aa9a | ||
|
|
bc0153079a | ||
|
|
2ebe366a38 | ||
|
|
2e3edffa1b | ||
|
|
291c9bce21 | ||
|
|
a6a31ff1f7 | ||
|
|
b5e67a7ee6 | ||
|
|
4fc694b72d | ||
|
|
d47b4349a6 | ||
|
|
c5542b8b28 | ||
|
|
acbf109a23 | ||
|
|
8e5c8e0148 | ||
|
|
f95a285c3f | ||
|
|
25b98cc8ab | ||
|
|
f23de626fe | ||
|
|
2035b22945 | ||
|
|
ac31d70c95 | ||
|
|
d37b743d71 | ||
|
|
77dc5cff7b | ||
|
|
88d182e6c5 | ||
|
|
2e2f30b9df | ||
|
|
5ad603eba1 | ||
|
|
aedf61d97e | ||
|
|
2e77bdde72 | ||
|
|
2fb67e5cb5 | ||
|
|
19f30e814d | ||
|
|
c0867ca009 | ||
|
|
b8fb0faba9 | ||
|
|
7fe7c9ef2a | ||
|
|
8fa61fa729 | ||
|
|
ffc7c2429c | ||
|
|
947a0d7393 | ||
|
|
89caa3ac6d | ||
|
|
0e5adc7a7c | ||
|
|
69fbae732d | ||
|
|
8600da6132 | ||
|
|
79c20c20ce | ||
|
|
a37cdb880c | ||
|
|
29603ec34e | ||
|
|
ff9892579d | ||
|
|
73708f6583 | ||
|
|
4d4696e4bd | ||
|
|
5beb289dc8 | ||
|
|
6a9b3b5433 | ||
|
|
a5f437cf40 | ||
|
|
464c44689a | ||
|
|
709f7c8405 | ||
|
|
a2ee2da080 | ||
|
|
b74430bfce | ||
|
|
b682477fd4 | ||
|
|
b3745da37e | ||
|
|
046a93babc | ||
|
|
d007267e90 | ||
|
|
67bfd4b188 | ||
|
|
2bf967ae3e | ||
|
|
67b1d10200 | ||
|
|
e381583f07 | ||
|
|
ecca887d3f | ||
|
|
890df6291d | ||
|
|
79e7d8b431 | ||
|
|
2c31ce6ace | ||
|
|
a7042fc866 | ||
|
|
23f1b902e5 | ||
|
|
f18c31f9c9 | ||
|
|
4584142974 | ||
|
|
9529062888 | ||
|
|
5c7fb27a42 | ||
|
|
8f7953389a | ||
|
|
afcca4036c | ||
|
|
cf44dca835 | ||
|
|
60be5ca073 | ||
|
|
42bf788749 | ||
|
|
2ac34161ea | ||
|
|
8eee277b98 | ||
|
|
d4b8975a86 | ||
|
|
ff0ea61aad | ||
|
|
ce649af7e3 | ||
|
|
1395b526b2 | ||
|
|
2fd40f22bf | ||
|
|
0913a510d2 | ||
|
|
c80186ceca | ||
|
|
b89295dec7 | ||
|
|
08c3a12b9e | ||
|
|
e99e753e96 | ||
|
|
47f69b7b2b | ||
|
|
408bec38d4 | ||
|
|
de9171ceb5 | ||
|
|
555fe133a0 | ||
|
|
28e7d2301d | ||
|
|
e9b52d4556 | ||
|
|
7cdbe94131 | ||
|
|
ee26296db2 | ||
|
|
743ba622dd | ||
|
|
4482235f80 | ||
|
|
6d81b467c2 | ||
|
|
89c8ff0281 | ||
|
|
6fd19e578e | ||
|
|
6dd0d056f4 | ||
|
|
a3f0f89512 | ||
|
|
8c0cdd51c2 | ||
|
|
21eed0fdf3 | ||
|
|
d063a4a02e | ||
|
|
8a9ca13855 | ||
|
|
f2f96b1737 | ||
|
|
7357444a84 | ||
|
|
0a704c61ba | ||
|
|
86ec2bfa8d | ||
|
|
d1ffbfb046 | ||
|
|
15107fac43 | ||
|
|
664dfa2f62 | ||
|
|
91378528ab | ||
|
|
67579a973c | ||
|
|
bb2ae08dd8 | ||
|
|
a3e9ea0a66 | ||
|
|
6b5db0c503 | ||
|
|
7284dc092f | ||
|
|
ba0f9bba88 | ||
|
|
c1ca14ffd6 | ||
|
|
584e5e6aeb | ||
|
|
5199786617 | ||
|
|
a2557a37b2 | ||
|
|
c8798d22bd | ||
|
|
2cb2fcd61c | ||
|
|
e922ec6de6 | ||
|
|
15fcaa5fde | ||
|
|
b5a9129c90 | ||
|
|
71b056fd5d | ||
|
|
3358309208 | ||
|
|
921997412b | ||
|
|
b8108379d7 | ||
|
|
a0d8349dda | ||
|
|
0788205d88 | ||
|
|
80891b26a3 | ||
|
|
c5f703a30b | ||
|
|
07189adb6d | ||
|
|
64c8725594 | ||
|
|
b57486e027 | ||
|
|
5e0140e877 | ||
|
|
b5888d4b0f | ||
|
|
cda97a67bf | ||
|
|
c7722ef0f8 | ||
|
|
181b5d5641 | ||
|
|
d651672f16 | ||
|
|
25568d690f | ||
|
|
062217b9a9 | ||
|
|
4115a9ad5d | ||
|
|
c157638b00 | ||
|
|
b5ceaca56c | ||
|
|
329cfb998c | ||
|
|
1ccb31fde6 | ||
|
|
1a0246734b | ||
|
|
a8cb5babce | ||
|
|
65ad6dcde4 | ||
|
|
d17320661b | ||
|
|
ebddeb7597 | ||
|
|
89bfa3eda4 | ||
|
|
cff7444f0a | ||
|
|
a279b4592b | ||
|
|
40b61f789e | ||
|
|
82bd2cbf4c | ||
|
|
d4d479ca7b | ||
|
|
0933014721 | ||
|
|
fc8477a265 | ||
|
|
c9e63c6292 | ||
|
|
05442e17dc | ||
|
|
27235c38ef | ||
|
|
5fc6ae6201 | ||
|
|
315065b727 | ||
|
|
51adfe2785 | ||
|
|
8519f3432f | ||
|
|
cda099923d | ||
|
|
454a96e3b7 | ||
|
|
7c6af8cab8 | ||
|
|
397abc4190 | ||
|
|
680ccf0f2d | ||
|
|
e42f2cc32e | ||
|
|
e4c0b956e8 | ||
|
|
135dfa983a | ||
|
|
1844c93b14 | ||
|
|
1d1443cb1a | ||
|
|
a15866e212 | ||
|
|
9baadbe00e | ||
|
|
4222287b02 | ||
|
|
d46c2cd5a7 | ||
|
|
5a2d286e0c | ||
|
|
d15f9136c5 | ||
|
|
5d50d96a7b | ||
|
|
edf209a78c | ||
|
|
eb1a95acfd | ||
|
|
bee28f59f5 | ||
|
|
4d94ce5ac8 | ||
|
|
a0f5bd4e44 | ||
|
|
84a101a745 | ||
|
|
cbad53d9f9 | ||
|
|
bebdead740 | ||
|
|
1a5207f856 | ||
|
|
be82bb8e6b | ||
|
|
0c7fee782f | ||
|
|
0ba4fdc591 | ||
|
|
300af9c231 | ||
|
|
4a4b0062f8 | ||
|
|
aee4575404 | ||
|
|
7bec37fe5b | ||
|
|
834205ac04 | ||
|
|
37a7e5466b | ||
|
|
be168f4b78 | ||
|
|
99af756462 | ||
|
|
7f87b66763 | ||
|
|
d68a188884 | ||
|
|
df8b9928f8 | ||
|
|
3ad69e8e65 | ||
|
|
8d19530dbb | ||
|
|
809087f0c8 | ||
|
|
057e25657e | ||
|
|
05c8569587 | ||
|
|
6432ff4d87 | ||
|
|
94fb0f94c5 | ||
|
|
f986b2022b | ||
|
|
8806eec449 | ||
|
|
c1779a49cb | ||
|
|
472f2b83d2 | ||
|
|
d4d1eadb1a | ||
|
|
1a10217ba4 | ||
|
|
65921a4dda | ||
|
|
1cf0ffbe03 | ||
|
|
32432c2c19 | ||
|
|
c34e4b34f4 | ||
|
|
2fc92344bc | ||
|
|
3e1a24c35c | ||
|
|
aeacd50a40 | ||
|
|
edc138ebd5 | ||
|
|
134af6f08f | ||
|
|
c2ed725739 | ||
|
|
971eb7bb5f | ||
|
|
c4dc57ffd2 | ||
|
|
89f7d276ef | ||
|
|
cddbd24df3 | ||
|
|
39714f039a | ||
|
|
e42147f3a7 | ||
|
|
79c1749e81 | ||
|
|
62dc04c5ca | ||
|
|
fa101bcb05 | ||
|
|
1eb679b9e1 | ||
|
|
c770c80bf7 | ||
|
|
100de86cfa | ||
|
|
7d2e402a08 | ||
|
|
c0dab30375 | ||
|
|
fdd1c6c8b4 | ||
|
|
74caaf1c36 | ||
|
|
d70cb175e7 | ||
|
|
7c62434ef3 | ||
|
|
e18279782d | ||
|
|
90c13f0634 | ||
|
|
21889e22e4 | ||
|
|
b9a3d1fffe | ||
|
|
b77c106d72 | ||
|
|
994cdacff4 | ||
|
|
c52da3dd57 | ||
|
|
7c9f9b262d | ||
|
|
a759f32692 | ||
|
|
79b2967464 | ||
|
|
d6aab14ec1 | ||
|
|
69302c3ce7 | ||
|
|
75e5bb2a7f | ||
|
|
56eef31eb8 | ||
|
|
abe702f5b8 | ||
|
|
c6521a189c | ||
|
|
8a5b30ff71 | ||
|
|
a9eb6ecc1a | ||
|
|
530cd440d8 | ||
|
|
98d96e5c99 | ||
|
|
f121373467 | ||
|
|
428f051e1c | ||
|
|
117069efd4 | ||
|
|
bc441dab14 | ||
|
|
d919149e5f | ||
|
|
1ee6e88934 | ||
|
|
b4e7aecafe | ||
|
|
448b2b1b2d | ||
|
|
ce7c02b1b1 | ||
|
|
45613102e9 | ||
|
|
3776e6b2c2 | ||
|
|
838a8a3dd3 | ||
|
|
f3227ebe89 | ||
|
|
411a706e24 | ||
|
|
76905b7496 | ||
|
|
2ab8692165 | ||
|
|
28aa4ebe26 | ||
|
|
d5a143ce0a | ||
|
|
6a9058665e | ||
|
|
ef160a3fd0 | ||
|
|
1d9865c681 | ||
|
|
a003249bc6 | ||
|
|
2e987d7744 | ||
|
|
f280f02493 | ||
|
|
1cb8697ad1 | ||
|
|
bae1d521ec | ||
|
|
1b76a2ee5e | ||
|
|
5d2f112d1e | ||
|
|
a35c335bd7 | ||
|
|
5848987cf7 | ||
|
|
2aa15a7ef0 | ||
|
|
7417766c5e | ||
|
|
22aae443b9 | ||
|
|
9ef9f3c271 | ||
|
|
037031bae6 | ||
|
|
fc13314a10 | ||
|
|
f0a5e74bab | ||
|
|
cfeb3e51b6 | ||
|
|
6afb81b41c | ||
|
|
91199ccb6c | ||
|
|
e034066a09 | ||
|
|
9ac053ce28 | ||
|
|
5946cd62fd | ||
|
|
72bfdbc906 | ||
|
|
a93c20c5ad | ||
|
|
2103b7ea8c | ||
|
|
c2deaeed46 | ||
|
|
3883d47caa | ||
|
|
65193feefb | ||
|
|
fb41dc55a8 | ||
|
|
e07747c246 | ||
|
|
75e6cfc574 | ||
|
|
575c63a564 | ||
|
|
40fefd264e | ||
|
|
340f0b8d51 | ||
|
|
c2d4f28f87 | ||
|
|
3418bd94d3 | ||
|
|
e92d16f165 | ||
|
|
78e758bbbb | ||
|
|
6ea9dc4113 | ||
|
|
f1e73e4d2f | ||
|
|
9d87ea3ee0 | ||
|
|
1c39ef9958 | ||
|
|
3e2de8dfbe | ||
|
|
04d34e4de1 | ||
|
|
912e4c6001 | ||
|
|
54ed63d76e | ||
|
|
04ef6d2187 | ||
|
|
2d3eb3dc97 | ||
|
|
24a12cb57d | ||
|
|
e383bb979e | ||
|
|
5c06c96c31 | ||
|
|
2a46b2893a | ||
|
|
78de80e89a | ||
|
|
49f8aa209e | ||
|
|
8d26195d4d | ||
|
|
4dfc90a462 | ||
|
|
20747046bd | ||
|
|
124af9ad61 | ||
|
|
24527b8a59 | ||
|
|
9f4bf49945 | ||
|
|
7c4986546b | ||
|
|
84a2de8dec | ||
|
|
b5e65b187d | ||
|
|
3b57334da0 | ||
|
|
acf49d4035 | ||
|
|
864677cdcb | ||
|
|
ba91fb564b | ||
|
|
d9d674b82e | ||
|
|
c17092c5c7 | ||
|
|
e7fb674fa3 | ||
|
|
2c81fdc849 | ||
|
|
c5726ea7a9 | ||
|
|
adcc8a53b8 | ||
|
|
f9167a6752 | ||
|
|
b3d4f575b1 | ||
|
|
a5d4a999fa | ||
|
|
d1e9849dfa | ||
|
|
f204a664c0 | ||
|
|
86043d6f87 | ||
|
|
66036bf6a3 | ||
|
|
fa81db96ba | ||
|
|
3e1bb914c5 | ||
|
|
0ca88cb295 | ||
|
|
2419e6211e | ||
|
|
7f4cce4a0a | ||
|
|
4016cceb6a | ||
|
|
c4336e8c6c | ||
|
|
228e4e5564 | ||
|
|
4794f058cf | ||
|
|
041310858e | ||
|
|
1a6a3ac5d7 | ||
|
|
d22c68dbd8 | ||
|
|
c068471192 | ||
|
|
502ad09e67 | ||
|
|
e2963ad817 | ||
|
|
a389cd5257 | ||
|
|
6d0b9d81c2 | ||
|
|
06daad4e03 | ||
|
|
8009bcb192 | ||
|
|
c82b9b33fc | ||
|
|
886b04a5f3 | ||
|
|
07b5787f5b | ||
|
|
c4cd39a785 | ||
|
|
a7be74494c | ||
|
|
525a083a78 | ||
|
|
5a4190c392 | ||
|
|
e4ba44bcb7 | ||
|
|
5a494f1bbf | ||
|
|
9067e0b5ce | ||
|
|
93dcb69132 | ||
|
|
b9de68ea8c | ||
|
|
311accf5eb | ||
|
|
ad61527aff | ||
|
|
661f6a1268 | ||
|
|
e75f24ff76 | ||
|
|
72a1d09920 | ||
|
|
03be75de97 | ||
|
|
ec77e3988a | ||
|
|
ccadddc9f5 | ||
|
|
8adb531554 | ||
|
|
11f3d34963 | ||
|
|
f561f1d069 | ||
|
|
6376dc1bb9 | ||
|
|
1bcd411837 | ||
|
|
26a242252d | ||
|
|
87981b9e37 | ||
|
|
c9aae953f0 | ||
|
|
31ed77c025 | ||
|
|
a124640f43 | ||
|
|
9ca0124b99 | ||
|
|
29d17b7174 | ||
|
|
ceab44d9fd | ||
|
|
d8d5adb62b | ||
|
|
aad2c99e48 | ||
|
|
5630c8aefc | ||
|
|
80cf146882 | ||
|
|
c6c2381171 | ||
|
|
c7e8d7f99a | ||
|
|
1b8d520eb9 | ||
|
|
d2af3ac8f4 | ||
|
|
eda2e7b798 | ||
|
|
594528e224 | ||
|
|
8a5a0d038c | ||
|
|
3331d6d9b6 | ||
|
|
47241bd101 | ||
|
|
c3572785df | ||
|
|
43a6e4c059 | ||
|
|
0800b05355 | ||
|
|
789255ed1e | ||
|
|
b4c0a9aa6d | ||
|
|
6fc1871d63 | ||
|
|
2a29eb3d2d | ||
|
|
81e3a246de | ||
|
|
629eb3a3d7 | ||
|
|
fbd8279072 | ||
|
|
cf24c2aa83 | ||
|
|
a3aa9cf16f | ||
|
|
c2b8a82f80 | ||
|
|
b297b3a9de | ||
|
|
9a2ea3696e | ||
|
|
53deb75f8b | ||
|
|
f565bf1713 | ||
|
|
14db96ad56 | ||
|
|
a0fc494c8d | ||
|
|
66290dcc0b | ||
|
|
f10fa85cb7 | ||
|
|
ae42201eb8 | ||
|
|
c9a57881d2 | ||
|
|
db3114f372 | ||
|
|
9255047c9c | ||
|
|
42feb99ddc | ||
|
|
8db4ef625b | ||
|
|
f40c4ae90d | ||
|
|
8672527898 | ||
|
|
261c252e28 | ||
|
|
6a09060d1a | ||
|
|
fbf9839a3e | ||
|
|
0f390f131b | ||
|
|
d78c9eb624 | ||
|
|
94d401b0b2 | ||
|
|
f24c43c396 | ||
|
|
605ed8b8a2 | ||
|
|
de4c7baa4d | ||
|
|
e21949b16b | ||
|
|
ddc27a60df | ||
|
|
36e3062378 | ||
|
|
102d4ad3f8 | ||
|
|
3ef4611c1f | ||
|
|
b81b023ea5 | ||
|
|
35938b691a | ||
|
|
ada5c8f4e9 | ||
|
|
16fede3622 | ||
|
|
ebdfac0dd7 | ||
|
|
a89d24843f | ||
|
|
05f18737a0 | ||
|
|
b06b1c0006 | ||
|
|
6b8865705e | ||
|
|
ebcb6cc603 | ||
|
|
dee6d806dd | ||
|
|
0b5be406aa | ||
|
|
83a6c88345 | ||
|
|
10e5ac4403 | ||
|
|
f645886ada | ||
|
|
2a974948a6 | ||
|
|
e8e6b1b159 | ||
|
|
d52d1fea0a | ||
|
|
c2e028c916 | ||
|
|
0560039149 | ||
|
|
c18c204279 | ||
|
|
80a4407f74 | ||
|
|
a4a5f784ab | ||
|
|
bf7194ec2b | ||
|
|
6e1204897a | ||
|
|
8d3c5ee11c | ||
|
|
b8da9d0448 | ||
|
|
431d3ea432 | ||
|
|
5ddc41f07e | ||
|
|
8d4b3657aa | ||
|
|
ebbd6dee0c | ||
|
|
e58f42e0b9 | ||
|
|
d585f60011 | ||
|
|
39c661388e | ||
|
|
f1eb3267bb | ||
|
|
0cde0fd1bb | ||
|
|
57483a1921 | ||
|
|
60b82f2fe4 | ||
|
|
1eab3a2193 | ||
|
|
8becbfbb7d | ||
|
|
2ae4b1914a | ||
|
|
813e99a41b | ||
|
|
15af16215a | ||
|
|
bc76844900 | ||
|
|
8f0d944b26 | ||
|
|
ea283d2ac7 | ||
|
|
242b2c4f91 | ||
|
|
4b1ca0b0f2 | ||
|
|
15deef3206 | ||
|
|
abc7074b3a | ||
|
|
18c0719ba2 | ||
|
|
21fe9724d5 | ||
|
|
7f17342db3 | ||
|
|
2a54d86f7b | ||
|
|
1414918b17 | ||
|
|
8facb48485 | ||
|
|
cc8cebaa99 | ||
|
|
de262c4134 | ||
|
|
c0c3618627 | ||
|
|
e1c2bf47d5 | ||
|
|
5403f28eca | ||
|
|
f5cd5b4117 | ||
|
|
ea655cb10a | ||
|
|
2d46bbd94f | ||
|
|
7e8812bc07 | ||
|
|
9cc92e72c2 | ||
|
|
30f8b1d876 | ||
|
|
7c6b6cc6b7 | ||
|
|
820ececea0 | ||
|
|
b113b19cd6 | ||
|
|
7885381cd8 | ||
|
|
6286897c16 | ||
|
|
c779c2ec8d | ||
|
|
a5391d125f | ||
|
|
550904ab55 | ||
|
|
d1bd5c6d95 | ||
|
|
7f63fba18c | ||
|
|
5ac9aa4a47 | ||
|
|
11b8330ae3 | ||
|
|
58ca949331 | ||
|
|
4c27a6c252 | ||
|
|
25b23be5e8 | ||
|
|
05151e52eb | ||
|
|
d27e88109d | ||
|
|
e9a5bf3c8f | ||
|
|
b58e1e09d3 | ||
|
|
2b89bfb934 | ||
|
|
abdb76f9a5 | ||
|
|
2efb0f4933 | ||
|
|
523bb28c54 | ||
|
|
7c913a1672 | ||
|
|
04debcf761 | ||
|
|
01d6b73b7c | ||
|
|
ba68679bee | ||
|
|
71822e6469 | ||
|
|
09302f4cb0 | ||
|
|
40e3d14449 | ||
|
|
f5469f73b7 | ||
|
|
8b1df3016d | ||
|
|
1bfce790ae | ||
|
|
e39b7498fc | ||
|
|
838cc607b6 | ||
|
|
fddc4fb9e1 | ||
|
|
06a49e3e42 | ||
|
|
5577701da0 | ||
|
|
10b486fe47 | ||
|
|
a0d1e57794 | ||
|
|
d370ba7ff3 | ||
|
|
99338fd4de | ||
|
|
d7573ec13b | ||
|
|
555dec9d2c | ||
|
|
cee9e87fde | ||
|
|
2380adc193 | ||
|
|
57397e0373 | ||
|
|
5f0b9d52ff | ||
|
|
cd36c676eb | ||
|
|
901a2143b7 | ||
|
|
780f383762 | ||
|
|
77a58cd1ab | ||
|
|
debdaff7b2 | ||
|
|
161163a160 | ||
|
|
913c80e05f | ||
|
|
1afe29794a | ||
|
|
b03e51fdac | ||
|
|
12c9aa6207 | ||
|
|
08353d2c4f | ||
|
|
a96b9f873b | ||
|
|
6723095508 | ||
|
|
6dd313d466 | ||
|
|
73c91489de | ||
|
|
5845a45d5b | ||
|
|
f09e08bb8f | ||
|
|
4b1709a418 | ||
|
|
5429f7af4a | ||
|
|
c9accc9abe | ||
|
|
331111c3d3 | ||
|
|
d93891f6c1 |
@@ -1,7 +1,6 @@
|
||||
name: "Docker"
|
||||
|
||||
on:
|
||||
|
||||
# Always have a base image ready to go - this is a nightly build
|
||||
schedule:
|
||||
- cron: 0 3 * * *
|
||||
@@ -26,7 +25,6 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
|
||||
# Dockerfiles to build, a matrix supports future expanded builds
|
||||
container: [["config/docker/Dockerfile.base", "ghcr.io/mfem/mfem-ubuntu-base"],
|
||||
["config/docker/Dockerfile", "ghcr.io/mfem/mfem-ubuntu"]]
|
||||
@@ -34,15 +32,20 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
name: Build
|
||||
steps:
|
||||
- name: Run Actions Cleaner
|
||||
uses: easimon/maximize-build-space@v8
|
||||
with:
|
||||
overprovision-lvm: 'true'
|
||||
remove-dotnet: 'true'
|
||||
remove-android: 'true'
|
||||
remove-haskell: 'true'
|
||||
remove-codeql: 'true'
|
||||
remove-docker-images: 'true'
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Make Space For Build
|
||||
run: |
|
||||
sudo rm -rf /usr/share/dotnet
|
||||
sudo rm -rf /opt/ghc
|
||||
|
||||
# It's easier to reference named variables than indexes of the matrix
|
||||
# It's easier to reference named variables than indexes of the matrix
|
||||
- name: Set Environment
|
||||
env:
|
||||
dockerfile: ${{ matrix.container[0] }}
|
||||
@@ -65,13 +65,16 @@ jobs:
|
||||
# - Add a new combination.
|
||||
# 'build-system: cmake' and 'hypre-target: int64'
|
||||
#
|
||||
# note: we will gather coverage info for any non-debug run except the
|
||||
# Note: we will gather coverage info for any non-debug run except the
|
||||
# CMake build.
|
||||
include:
|
||||
- target: dbg
|
||||
codecov: NO
|
||||
- target: opt
|
||||
codecov: YES
|
||||
- os: ubuntu-latest
|
||||
target: dbg
|
||||
config-opts: 'CPPFLAGS+=-Og'
|
||||
- os: windows-latest
|
||||
codecov: NO
|
||||
- os: windows-latest
|
||||
@@ -98,181 +101,189 @@ jobs:
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
steps:
|
||||
# This external action allows to interrupt a workflow already running on
|
||||
# the same branch to save resource
|
||||
- name: Cancel Previous Runs
|
||||
uses: styfle/cancel-workflow-action@0.11.0
|
||||
with:
|
||||
access_token: ${{ github.token }}
|
||||
# This external action allows to interrupt a workflow already running on
|
||||
# the same branch to save resources.
|
||||
- name: Cancel Previous Runs
|
||||
uses: styfle/cancel-workflow-action@0.11.0
|
||||
with:
|
||||
access_token: ${{ github.token }}
|
||||
|
||||
# Checkout MFEM in "mfem" subdirectory. Final path:
|
||||
# /home/runner/work/mfem/mfem/mfem
|
||||
# Note: Done now to access "install-hypre" and "install-metis" actions.
|
||||
- name: checkout mfem
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
path: ${{ env.MFEM_TOP_DIR }}
|
||||
# Fetch the complete history for codecov to access commits ID
|
||||
fetch-depth: 0
|
||||
# Fix 'No space left on device' errors for Ubuntu builds.
|
||||
- name: Run Actions Cleaner
|
||||
if: matrix.os == 'ubuntu-latest'
|
||||
uses: easimon/maximize-build-space@v8
|
||||
with:
|
||||
overprovision-lvm: 'true'
|
||||
remove-android: 'true'
|
||||
|
||||
# Only get MPI if defined for the job.
|
||||
# TODO: It would be nice to have only one step, e.g. with a dedicated
|
||||
# action, but I (@adrienbernede) don't see how at the moment.
|
||||
- name: get MPI (Linux)
|
||||
if: matrix.mpi == 'par' && matrix.os == 'ubuntu-latest'
|
||||
run: |
|
||||
sudo apt-get install mpich libmpich-dev
|
||||
# Checkout MFEM in "mfem" subdirectory. Final path:
|
||||
# /home/runner/work/mfem/mfem/mfem
|
||||
# Note: Done now to access "install-hypre" and "install-metis" actions.
|
||||
- name: checkout mfem
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
path: ${{ env.MFEM_TOP_DIR }}
|
||||
# Fetch the complete history for codecov to access commits ID
|
||||
fetch-depth: 0
|
||||
|
||||
- name: get lcov (Linux)
|
||||
if: matrix.codecov == 'YES' && matrix.os == 'ubuntu-latest'
|
||||
run: |
|
||||
sudo apt-get install lcov
|
||||
# Only get MPI if defined for the job.
|
||||
# TODO: It would be nice to have only one step, e.g. with a dedicated
|
||||
# action, but I (@adrienbernede) don't see how at the moment.
|
||||
- name: get MPI (Linux)
|
||||
if: matrix.mpi == 'par' && matrix.os == 'ubuntu-latest'
|
||||
run: |
|
||||
sudo apt-get install mpich libmpich-dev
|
||||
|
||||
# Keep the following section in case we need it again in the future,
|
||||
# see: https://github.com/mfem/mfem/pull/3385#discussion_r1058013032
|
||||
# - name: Set up Homebrew
|
||||
# if: ( matrix.mpi == 'par' || matrix.codecov == 'YES' ) && matrix.os == 'macos-latest'
|
||||
# uses: Homebrew/actions/setup-homebrew@master
|
||||
- name: get lcov (Linux)
|
||||
if: matrix.codecov == 'YES' && matrix.os == 'ubuntu-latest'
|
||||
run: |
|
||||
sudo apt-get install lcov
|
||||
|
||||
- name: get MPI (MacOS)
|
||||
if: matrix.mpi == 'par' && matrix.os == 'macos-latest'
|
||||
run: |
|
||||
export HOMEBREW_NO_INSTALL_CLEANUP=1
|
||||
brew install openmpi
|
||||
# Keep the following section in case we need it again in the future,
|
||||
# see: https://github.com/mfem/mfem/pull/3385#discussion_r1058013032
|
||||
# - name: Set up Homebrew
|
||||
# if: ( matrix.mpi == 'par' || matrix.codecov == 'YES' ) && matrix.os == 'macos-latest'
|
||||
# uses: Homebrew/actions/setup-homebrew@master
|
||||
|
||||
- name: get lcov (MacOS)
|
||||
if: matrix.codecov == 'YES' && matrix.os == 'macos-latest'
|
||||
run: |
|
||||
export HOMEBREW_NO_INSTALL_CLEANUP=1
|
||||
brew install lcov
|
||||
- name: get MPI (MacOS)
|
||||
if: matrix.mpi == 'par' && matrix.os == 'macos-latest'
|
||||
run: |
|
||||
export HOMEBREW_NO_INSTALL_CLEANUP=1
|
||||
brew install openmpi
|
||||
|
||||
- name: get MPI (Windows)
|
||||
if: matrix.mpi == 'par' && matrix.os == 'windows-latest'
|
||||
uses: mpi4py/setup-mpi@v1.1.4
|
||||
- name: get lcov (MacOS)
|
||||
if: matrix.codecov == 'YES' && matrix.os == 'macos-latest'
|
||||
run: |
|
||||
export HOMEBREW_NO_INSTALL_CLEANUP=1
|
||||
brew install lcov
|
||||
|
||||
# Get Hypre through cache, or build it.
|
||||
# Install will only run on cache miss.
|
||||
- name: cache hypre
|
||||
id: hypre-cache
|
||||
if: matrix.mpi == 'par'
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: ${{ env.HYPRE_TOP_DIR }}
|
||||
key: ${{ runner.os }}-build-${{ env.HYPRE_TOP_DIR }}-${{ matrix.hypre-target }}-v2.2
|
||||
- name: get MPI (Windows)
|
||||
if: matrix.mpi == 'par' && matrix.os == 'windows-latest'
|
||||
uses: mpi4py/setup-mpi@v1.1.4
|
||||
|
||||
- name: get hypre
|
||||
if: matrix.mpi == 'par' && steps.hypre-cache.outputs.cache-hit != 'true' && matrix.os != 'windows-latest'
|
||||
uses: mfem/github-actions/build-hypre@v2.4
|
||||
with:
|
||||
archive: ${{ env.HYPRE_ARCHIVE }}
|
||||
dir: ${{ env.HYPRE_TOP_DIR }}
|
||||
target: ${{ matrix.hypre-target }}
|
||||
build-system: make
|
||||
# Get Hypre through cache, or build it.
|
||||
# Install will only run on cache miss.
|
||||
- name: cache hypre
|
||||
id: hypre-cache
|
||||
if: matrix.mpi == 'par'
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: ${{ env.HYPRE_TOP_DIR }}
|
||||
key: ${{ runner.os }}-build-${{ env.HYPRE_TOP_DIR }}-${{ matrix.hypre-target }}-v2.2
|
||||
|
||||
- name: get hypre (Windows)
|
||||
if: matrix.mpi == 'par' && steps.hypre-cache.outputs.cache-hit != 'true' && matrix.os == 'windows-latest'
|
||||
uses: mfem/github-actions/build-hypre@v2.4
|
||||
with:
|
||||
archive: ${{ env.HYPRE_ARCHIVE }}
|
||||
dir: ${{ env.HYPRE_TOP_DIR }}
|
||||
target: ${{ matrix.hypre-target }}
|
||||
build-system: cmake
|
||||
- name: get hypre
|
||||
if: matrix.mpi == 'par' && steps.hypre-cache.outputs.cache-hit != 'true' && matrix.os != 'windows-latest'
|
||||
uses: mfem/github-actions/build-hypre@v2.4
|
||||
with:
|
||||
archive: ${{ env.HYPRE_ARCHIVE }}
|
||||
dir: ${{ env.HYPRE_TOP_DIR }}
|
||||
target: ${{ matrix.hypre-target }}
|
||||
build-system: make
|
||||
|
||||
# Get Metis through cache, or build it.
|
||||
# Install will only run on cache miss.
|
||||
- name: cache metis
|
||||
id: metis-cache
|
||||
if: matrix.mpi == 'par' && matrix.os != 'windows-latest'
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: ${{ env.METIS_TOP_DIR }}
|
||||
key: ${{ runner.os }}-build-${{ env.METIS_TOP_DIR }}-v2.2
|
||||
- name: get hypre (Windows)
|
||||
if: matrix.mpi == 'par' && steps.hypre-cache.outputs.cache-hit != 'true' && matrix.os == 'windows-latest'
|
||||
uses: mfem/github-actions/build-hypre@v2.4
|
||||
with:
|
||||
archive: ${{ env.HYPRE_ARCHIVE }}
|
||||
dir: ${{ env.HYPRE_TOP_DIR }}
|
||||
target: ${{ matrix.hypre-target }}
|
||||
build-system: cmake
|
||||
|
||||
- name: install metis
|
||||
if: matrix.mpi == 'par' && matrix.os != 'windows-latest' && steps.metis-cache.outputs.cache-hit != 'true'
|
||||
uses: mfem/github-actions/build-metis@v2.4
|
||||
with:
|
||||
archive: ${{ env.METIS_ARCHIVE }}
|
||||
dir: ${{ env.METIS_TOP_DIR }}
|
||||
# Get Metis through cache, or build it.
|
||||
# Install will only run on cache miss.
|
||||
- name: cache metis
|
||||
id: metis-cache
|
||||
if: matrix.mpi == 'par' && matrix.os != 'windows-latest'
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: ${{ env.METIS_TOP_DIR }}
|
||||
key: ${{ runner.os }}-build-${{ env.METIS_TOP_DIR }}-v2.2
|
||||
|
||||
- name: cache vcpkg (Windows)
|
||||
id: vcpkg-cache
|
||||
if: matrix.os == 'windows-latest'
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: vcpkg_cache
|
||||
key: ${{ runner.os }}-${{ matrix.mpi }}-vcpkg-v1
|
||||
- name: install metis
|
||||
if: matrix.mpi == 'par' && matrix.os != 'windows-latest' && steps.metis-cache.outputs.cache-hit != 'true'
|
||||
uses: mfem/github-actions/build-metis@v2.4
|
||||
with:
|
||||
archive: ${{ env.METIS_ARCHIVE }}
|
||||
dir: ${{ env.METIS_TOP_DIR }}
|
||||
|
||||
- name: prepare vcpkg binary cache location (Windows)
|
||||
if: matrix.os == 'windows-latest' && steps.vcpkg-cache.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
mkdir -p vcpkg_cache
|
||||
- name: cache vcpkg (Windows)
|
||||
id: vcpkg-cache
|
||||
if: matrix.os == 'windows-latest'
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: vcpkg_cache
|
||||
key: ${{ runner.os }}-${{ matrix.mpi }}-vcpkg-v1
|
||||
|
||||
- name: install metis (Windows)
|
||||
if: matrix.mpi == 'par' && matrix.os == 'windows-latest'
|
||||
env:
|
||||
VCPKG_DEFAULT_BINARY_CACHE: ${{ github.workspace }}/vcpkg_cache
|
||||
run: |
|
||||
vcpkg install metis-mfem --triplet=x64-windows-static --overlay-ports=${{ env.MFEM_TOP_DIR }}/config/vcpkg/ports
|
||||
- name: prepare vcpkg binary cache location (Windows)
|
||||
if: matrix.os == 'windows-latest' && steps.vcpkg-cache.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
mkdir -p vcpkg_cache
|
||||
|
||||
# MFEM build and test
|
||||
- name: build
|
||||
uses: mfem/github-actions/build-mfem@v2.4
|
||||
env:
|
||||
VCPKG_DEFAULT_BINARY_CACHE: ${{ github.workspace }}/vcpkg_cache
|
||||
with:
|
||||
os: ${{ matrix.os }}
|
||||
target: ${{ matrix.target }}
|
||||
codecov: ${{ matrix.codecov }}
|
||||
mpi: ${{ matrix.mpi }}
|
||||
build-system: ${{ matrix.build-system }}
|
||||
hypre-dir: ${{ env.HYPRE_TOP_DIR }}
|
||||
metis-dir: ${{ env.METIS_TOP_DIR }}
|
||||
mfem-dir: ${{ env.MFEM_TOP_DIR }}
|
||||
config-options: ${{ matrix.config-opts }}
|
||||
library-only: ${{ matrix.target == 'dbg' }}
|
||||
- name: install metis (Windows)
|
||||
if: matrix.mpi == 'par' && matrix.os == 'windows-latest'
|
||||
env:
|
||||
VCPKG_DEFAULT_BINARY_CACHE: ${{ github.workspace }}/vcpkg_cache
|
||||
run: |
|
||||
vcpkg install metis-mfem --triplet=x64-windows-static --overlay-ports=${{ env.MFEM_TOP_DIR }}/config/vcpkg/ports
|
||||
|
||||
# Run checks (and only checks) on debug targets
|
||||
- name: checks
|
||||
if: matrix.build-system == 'make' && matrix.target == 'dbg'
|
||||
run: |
|
||||
cd ${{ env.MFEM_TOP_DIR }} && make check
|
||||
# MFEM build and test
|
||||
- name: build
|
||||
uses: mfem/github-actions/build-mfem@v2.4
|
||||
env:
|
||||
VCPKG_DEFAULT_BINARY_CACHE: ${{ github.workspace }}/vcpkg_cache
|
||||
with:
|
||||
os: ${{ matrix.os }}
|
||||
target: ${{ matrix.target }}
|
||||
codecov: ${{ matrix.codecov }}
|
||||
mpi: ${{ matrix.mpi }}
|
||||
build-system: ${{ matrix.build-system }}
|
||||
hypre-dir: ${{ env.HYPRE_TOP_DIR }}
|
||||
metis-dir: ${{ env.METIS_TOP_DIR }}
|
||||
mfem-dir: ${{ env.MFEM_TOP_DIR }}
|
||||
config-options: ${{ matrix.config-opts }}
|
||||
library-only: ${{ matrix.target == 'dbg' && matrix.os != 'ubuntu-latest' }}
|
||||
|
||||
# Note: 'tests' include the unit tests
|
||||
- name: tests
|
||||
if: matrix.build-system == 'make' && matrix.target == 'opt'
|
||||
run: |
|
||||
cd ${{ env.MFEM_TOP_DIR }} && make test
|
||||
# Run checks (and only checks) on debug targets
|
||||
- name: checks
|
||||
if: matrix.build-system == 'make' && matrix.target == 'dbg'
|
||||
run: |
|
||||
cd ${{ env.MFEM_TOP_DIR }} && make check
|
||||
|
||||
- name: cmake checks
|
||||
if: matrix.build-system == 'cmake' && matrix.target == 'dbg'
|
||||
run: |
|
||||
CTEST_CONFIG="Debug"
|
||||
cd ${{ env.MFEM_TOP_DIR }} && cmake --build build --target check --config ${CTEST_CONFIG}
|
||||
shell: bash
|
||||
# Note: 'tests' include the unit tests
|
||||
- name: tests
|
||||
if: matrix.build-system == 'make' && (matrix.target == 'opt' || matrix.os == 'ubuntu-latest')
|
||||
run: |
|
||||
cd ${{ env.MFEM_TOP_DIR }} && make test
|
||||
|
||||
- name: cmake unit tests (Ubuntu)
|
||||
if: matrix.build-system == 'cmake' && matrix.target == 'opt' && matrix.os == 'ubuntu-latest'
|
||||
run: |
|
||||
CTEST_CONFIG="Release"
|
||||
[[ ${{ matrix.target }} == 'dbg' ]] && CTEST_CONFIG="Debug"
|
||||
cd ${{ env.MFEM_TOP_DIR }}/build/tests/unit && ctest --output-on-failure -C ${CTEST_CONFIG}
|
||||
shell: bash
|
||||
- name: cmake checks
|
||||
if: matrix.build-system == 'cmake' && matrix.target == 'dbg'
|
||||
run: |
|
||||
CTEST_CONFIG="Debug"
|
||||
cd ${{ env.MFEM_TOP_DIR }} && cmake --build build --target check --config ${CTEST_CONFIG}
|
||||
shell: bash
|
||||
|
||||
- name: cmake tests
|
||||
if: matrix.build-system == 'cmake' && matrix.target == 'opt' && matrix.os != 'ubuntu-latest'
|
||||
run: |
|
||||
CTEST_CONFIG="Release"
|
||||
cd ${{ env.MFEM_TOP_DIR }}/build && \
|
||||
ctest --output-on-failure -C ${CTEST_CONFIG} || \
|
||||
ctest --rerun-failed --output-on-failure -C ${CTEST_CONFIG}
|
||||
shell: bash
|
||||
- name: cmake unit tests (Ubuntu)
|
||||
if: matrix.build-system == 'cmake' && matrix.target == 'opt' && matrix.os == 'ubuntu-latest'
|
||||
run: |
|
||||
CTEST_CONFIG="Release"
|
||||
[[ ${{ matrix.target }} == 'dbg' ]] && CTEST_CONFIG="Debug"
|
||||
cd ${{ env.MFEM_TOP_DIR }}/build/tests/unit && ctest --output-on-failure -C ${CTEST_CONFIG}
|
||||
shell: bash
|
||||
|
||||
# Code coverage (process and upload reports)
|
||||
- name: codecov
|
||||
if: matrix.codecov == 'YES'
|
||||
uses: mfem/github-actions/upload-coverage@v2.4
|
||||
with:
|
||||
name: ${{ matrix.os }}-${{ matrix.build-system }}-${{ matrix.target }}-${{ matrix.mpi }}-${{ matrix.hypre-target }}
|
||||
project_dir: ${{ env.MFEM_TOP_DIR }}
|
||||
directories: "fem general linalg mesh"
|
||||
- name: cmake tests
|
||||
if: matrix.build-system == 'cmake' && matrix.target == 'opt' && matrix.os != 'ubuntu-latest'
|
||||
run: |
|
||||
CTEST_CONFIG="Release"
|
||||
cd ${{ env.MFEM_TOP_DIR }}/build && \
|
||||
ctest --output-on-failure -C ${CTEST_CONFIG} || \
|
||||
ctest --rerun-failed --output-on-failure -C ${CTEST_CONFIG}
|
||||
shell: bash
|
||||
|
||||
# Code coverage (process and upload reports)
|
||||
- name: codecov
|
||||
if: matrix.codecov == 'YES'
|
||||
uses: mfem/github-actions/upload-coverage@v2.4
|
||||
with:
|
||||
name: ${{ matrix.os }}-${{ matrix.build-system }}-${{ matrix.target }}-${{ matrix.mpi }}-${{ matrix.hypre-target }}
|
||||
project_dir: ${{ env.MFEM_TOP_DIR }}
|
||||
directories: "fem general linalg mesh"
|
||||
|
||||
@@ -13,10 +13,10 @@ name: "Static Analysis"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "master", "next"]
|
||||
branches: ["master", "next"]
|
||||
pull_request:
|
||||
# The branches below must be a subset of the branches above
|
||||
branches: [ "master" ]
|
||||
branches: ["master"]
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
@@ -35,36 +35,35 @@ jobs:
|
||||
# Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v2
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||
# By default, queries listed here will override any specified in a config file.
|
||||
# Prefix the list here with "+" to use these queries and those in the config file.
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v2
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||
# By default, queries listed here will override any specified in a config file.
|
||||
# Prefix the list here with "+" to use these queries and those in the config file.
|
||||
|
||||
# Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
|
||||
# queries: security-extended,security-and-quality
|
||||
# Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
|
||||
# queries: security-extended,security-and-quality
|
||||
|
||||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||
# If this step fails, then you should remove it and run the build manually (see below)
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v2
|
||||
|
||||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||
# If this step fails, then you should remove it and run the build manually (see below)
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v2
|
||||
# ℹ️ Command-line programs to run using the OS shell.
|
||||
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
|
||||
|
||||
# ℹ️ Command-line programs to run using the OS shell.
|
||||
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
|
||||
# If the Autobuild fails above, remove it and uncomment the following three lines.
|
||||
# modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance.
|
||||
|
||||
# If the Autobuild fails above, remove it and uncomment the following three lines.
|
||||
# modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance.
|
||||
# - run: |
|
||||
# echo "Run, Build Application using script"
|
||||
# ./location_of_script_within_repo/buildscript.sh
|
||||
|
||||
# - run: |
|
||||
# echo "Run, Build Application using script"
|
||||
# ./location_of_script_within_repo/buildscript.sh
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v2
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v2
|
||||
|
||||
@@ -34,67 +34,67 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Cancel Previous Runs
|
||||
uses: styfle/cancel-workflow-action@0.11.0
|
||||
with:
|
||||
access_token: ${{ github.token }}
|
||||
- name: Cancel Previous Runs
|
||||
uses: styfle/cancel-workflow-action@0.11.0
|
||||
with:
|
||||
access_token: ${{ github.token }}
|
||||
|
||||
- name: checkout MFEM
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
path: mfem
|
||||
- name: checkout MFEM
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
path: mfem
|
||||
|
||||
- name: Get MPI (Linux)
|
||||
run: |
|
||||
sudo apt-get install mpich libmpich-dev
|
||||
- name: Get MPI (Linux)
|
||||
run: |
|
||||
sudo apt-get install mpich libmpich-dev
|
||||
|
||||
- name: Cache Hypre Install
|
||||
id: hypre-cache
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: ${{ env.HYPRE_TOP_DIR }}
|
||||
key: ${{ runner.os }}-build-${{ env.HYPRE_TOP_DIR }}-v2.2
|
||||
- name: Cache Hypre Install
|
||||
id: hypre-cache
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: ${{ env.HYPRE_TOP_DIR }}
|
||||
key: ${{ runner.os }}-build-${{ env.HYPRE_TOP_DIR }}-v2.2
|
||||
|
||||
- name: Get Hypre
|
||||
if: steps.hypre-cache.outputs.cache-hit != 'true'
|
||||
uses: mfem/github-actions/build-hypre@v2.4
|
||||
with:
|
||||
archive: ${{ env.HYPRE_ARCHIVE }}
|
||||
dir: ${{ env.HYPRE_TOP_DIR }}
|
||||
target: int32
|
||||
- name: Get Hypre
|
||||
if: steps.hypre-cache.outputs.cache-hit != 'true'
|
||||
uses: mfem/github-actions/build-hypre@v2.4
|
||||
with:
|
||||
archive: ${{ env.HYPRE_ARCHIVE }}
|
||||
dir: ${{ env.HYPRE_TOP_DIR }}
|
||||
target: int32
|
||||
|
||||
- name: Cache Metis Install
|
||||
id: metis-cache
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: ${{ env.METIS_TOP_DIR }}
|
||||
key: ${{ runner.os }}-build-${{ env.METIS_TOP_DIR }}-v2.2
|
||||
- name: Cache Metis Install
|
||||
id: metis-cache
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: ${{ env.METIS_TOP_DIR }}
|
||||
key: ${{ runner.os }}-build-${{ env.METIS_TOP_DIR }}-v2.2
|
||||
|
||||
- name: Install Metis
|
||||
if: steps.metis-cache.outputs.cache-hit != 'true'
|
||||
uses: mfem/github-actions/build-metis@v2.4
|
||||
with:
|
||||
archive: ${{ env.METIS_ARCHIVE }}
|
||||
dir: ${{ env.METIS_TOP_DIR }}
|
||||
- name: Install Metis
|
||||
if: steps.metis-cache.outputs.cache-hit != 'true'
|
||||
uses: mfem/github-actions/build-metis@v2.4
|
||||
with:
|
||||
archive: ${{ env.METIS_ARCHIVE }}
|
||||
dir: ${{ env.METIS_TOP_DIR }}
|
||||
|
||||
# MFEM build and test
|
||||
- name: build-mfem
|
||||
uses: mfem/github-actions/build-mfem@v2.4
|
||||
with:
|
||||
os: ${{ runner.os }}
|
||||
target: opt
|
||||
codecov: NO
|
||||
mpi: par
|
||||
build-system: make
|
||||
hypre-dir: ${{ env.HYPRE_TOP_DIR }}
|
||||
metis-dir: ${{ env.METIS_TOP_DIR }}
|
||||
mfem-dir: mfem
|
||||
# MFEM build and test
|
||||
- name: build-mfem
|
||||
uses: mfem/github-actions/build-mfem@v2.4
|
||||
with:
|
||||
os: ${{ runner.os }}
|
||||
target: opt
|
||||
codecov: NO
|
||||
mpi: par
|
||||
build-system: make
|
||||
hypre-dir: ${{ env.HYPRE_TOP_DIR }}
|
||||
metis-dir: ${{ env.METIS_TOP_DIR }}
|
||||
mfem-dir: mfem
|
||||
|
||||
- name: test (no clean)
|
||||
run: |
|
||||
cd mfem && make test-noclean
|
||||
- name: test (no clean)
|
||||
run: |
|
||||
cd mfem && make test-noclean
|
||||
|
||||
- name: gitignore
|
||||
run: |
|
||||
cd mfem/tests/scripts
|
||||
./runtest gitignore
|
||||
- name: gitignore
|
||||
run: |
|
||||
cd mfem/tests/scripts
|
||||
./runtest gitignore
|
||||
|
||||
@@ -27,44 +27,44 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Cancel Previous Runs
|
||||
uses: styfle/cancel-workflow-action@0.11.0
|
||||
with:
|
||||
access_token: ${{ github.token }}
|
||||
- name: Cancel Previous Runs
|
||||
uses: styfle/cancel-workflow-action@0.11.0
|
||||
with:
|
||||
access_token: ${{ github.token }}
|
||||
|
||||
- name: MFEM Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
path: mfem
|
||||
- name: MFEM Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
path: mfem
|
||||
|
||||
- name: MFEM Build
|
||||
uses: mfem/github-actions/build-mfem@v2.4
|
||||
with:
|
||||
os: ${{ runner.os }}
|
||||
target: opt
|
||||
mpi: seq
|
||||
hypre-dir: unused-hypre-dir
|
||||
metis-dir: unused-metis-dir
|
||||
mfem-dir: mfem
|
||||
build-system: make
|
||||
library-only: false
|
||||
config-options:
|
||||
CXX="clang++-14"
|
||||
CXXFLAGS="-g -O1 -std=c++11
|
||||
-fsanitize=address
|
||||
-fno-omit-frame-pointer
|
||||
-fsanitize-address-use-after-scope"
|
||||
- name: MFEM Build
|
||||
uses: mfem/github-actions/build-mfem@v2.4
|
||||
with:
|
||||
os: ${{ runner.os }}
|
||||
target: opt
|
||||
mpi: seq
|
||||
hypre-dir: unused-hypre-dir
|
||||
metis-dir: unused-metis-dir
|
||||
mfem-dir: mfem
|
||||
build-system: make
|
||||
library-only: false
|
||||
config-options:
|
||||
CXX="clang++-14"
|
||||
CXXFLAGS="-g -O1 -std=c++11
|
||||
-fsanitize=address
|
||||
-fno-omit-frame-pointer
|
||||
-fsanitize-address-use-after-scope"
|
||||
|
||||
- name: MFEM Info
|
||||
working-directory: mfem
|
||||
run: make info
|
||||
- name: MFEM Info
|
||||
working-directory: mfem
|
||||
run: make info
|
||||
|
||||
- name: MFEM Sanitize
|
||||
working-directory: mfem
|
||||
run:
|
||||
ASAN_OPTIONS="detect_leaks=1,
|
||||
strict_init_order=1,
|
||||
strict_string_checks=1,
|
||||
check_initialization_order=1,
|
||||
detect_stack_use_after_return=1"
|
||||
make test
|
||||
- name: MFEM Sanitize
|
||||
working-directory: mfem
|
||||
run:
|
||||
ASAN_OPTIONS="detect_leaks=1,
|
||||
strict_init_order=1,
|
||||
strict_string_checks=1,
|
||||
check_initialization_order=1,
|
||||
detect_stack_use_after_return=1"
|
||||
make test
|
||||
|
||||
@@ -33,49 +33,49 @@ jobs:
|
||||
(github.event_name == 'push' ||
|
||||
github.event.pull_request.head.repo.full_name != github.repository)
|
||||
steps:
|
||||
- name: Cancel Previous Runs
|
||||
uses: styfle/cancel-workflow-action@0.11.0
|
||||
with:
|
||||
access_token: ${{ github.token }}
|
||||
- name: Cancel Previous Runs
|
||||
uses: styfle/cancel-workflow-action@0.11.0
|
||||
with:
|
||||
access_token: ${{ github.token }}
|
||||
|
||||
- name: checkout mfem
|
||||
uses: actions/checkout@v3
|
||||
- name: checkout mfem
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: copyright check
|
||||
id: copyright
|
||||
run: |
|
||||
./config/githooks/pre-push --copyright
|
||||
- name: copyright check
|
||||
id: copyright
|
||||
run: |
|
||||
./config/githooks/pre-push --copyright
|
||||
|
||||
continue-on-error: true
|
||||
continue-on-error: true
|
||||
|
||||
- name: license check
|
||||
id: license
|
||||
run: |
|
||||
./config/githooks/pre-push --license
|
||||
continue-on-error: true
|
||||
- name: license check
|
||||
id: license
|
||||
run: |
|
||||
./config/githooks/pre-push --license
|
||||
continue-on-error: true
|
||||
|
||||
- name: release check
|
||||
id: release
|
||||
run: |
|
||||
./config/githooks/pre-push --release
|
||||
continue-on-error: true
|
||||
- name: release check
|
||||
id: release
|
||||
run: |
|
||||
./config/githooks/pre-push --release
|
||||
continue-on-error: true
|
||||
|
||||
- name: wrap-up
|
||||
if: |
|
||||
steps.copyright.outcome != 'success' ||
|
||||
steps.license.outcome != 'success' ||
|
||||
steps.release.outcome != 'success'
|
||||
run: |
|
||||
if [[ "${{ steps.copyright.outcome }}" != "success" ]]; then
|
||||
echo "copyright check failed, unroll log for details"
|
||||
fi
|
||||
if [[ "${{ steps.license.outcome }}" != "success" ]]; then
|
||||
echo "license check failed, unroll log for details"
|
||||
fi
|
||||
if [[ "${{ steps.release.outcome }}" != "success" ]]; then
|
||||
echo "release check failed, unroll log for details"
|
||||
fi
|
||||
exit 1
|
||||
- name: wrap-up
|
||||
if: |
|
||||
steps.copyright.outcome != 'success' ||
|
||||
steps.license.outcome != 'success' ||
|
||||
steps.release.outcome != 'success'
|
||||
run: |
|
||||
if [[ "${{ steps.copyright.outcome }}" != "success" ]]; then
|
||||
echo "copyright check failed, unroll log for details"
|
||||
fi
|
||||
if [[ "${{ steps.license.outcome }}" != "success" ]]; then
|
||||
echo "license check failed, unroll log for details"
|
||||
fi
|
||||
if [[ "${{ steps.release.outcome }}" != "success" ]]; then
|
||||
echo "release check failed, unroll log for details"
|
||||
fi
|
||||
exit 1
|
||||
|
||||
code-style:
|
||||
runs-on: ubuntu-latest
|
||||
@@ -83,16 +83,16 @@ jobs:
|
||||
(github.event_name == 'push' ||
|
||||
github.event.pull_request.head.repo.full_name != github.repository)
|
||||
steps:
|
||||
- name: checkout mfem
|
||||
uses: actions/checkout@v3
|
||||
- name: checkout mfem
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: get astyle
|
||||
run: |
|
||||
sudo apt-get install astyle
|
||||
- name: get astyle
|
||||
run: |
|
||||
sudo apt-get install astyle
|
||||
|
||||
- name: style check
|
||||
run: |
|
||||
./config/githooks/pre-push --style
|
||||
- name: style check
|
||||
run: |
|
||||
./config/githooks/pre-push --style
|
||||
|
||||
documentation:
|
||||
runs-on: ubuntu-latest
|
||||
@@ -100,22 +100,22 @@ jobs:
|
||||
(github.event_name == 'push' ||
|
||||
github.event.pull_request.head.repo.full_name != github.repository)
|
||||
steps:
|
||||
- name: checkout mfem
|
||||
uses: actions/checkout@v3
|
||||
- name: checkout mfem
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: get doxygen and graphviz
|
||||
run: |
|
||||
sudo apt-get install doxygen graphviz
|
||||
- name: get doxygen and graphviz
|
||||
run: |
|
||||
sudo apt-get install doxygen graphviz
|
||||
|
||||
- name: update doxygen config file
|
||||
run: |
|
||||
cd doc
|
||||
doxygen -u CodeDocumentation.conf.in
|
||||
- name: update doxygen config file
|
||||
run: |
|
||||
cd doc
|
||||
doxygen -u CodeDocumentation.conf.in
|
||||
|
||||
- name: build documentation
|
||||
run: |
|
||||
cd tests/scripts
|
||||
./runtest documentation
|
||||
- name: build documentation
|
||||
run: |
|
||||
cd tests/scripts
|
||||
./runtest documentation
|
||||
|
||||
branch-history:
|
||||
if: |
|
||||
@@ -125,16 +125,16 @@ jobs:
|
||||
github.event.pull_request.head.repo.full_name != github.repository)
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: checkout mfem
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: checkout mfem
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: branch-history
|
||||
run: |
|
||||
# We override origin to make sure we point to the main repo.
|
||||
# This is to have consistent test results on PRs from forks.
|
||||
git remote remove origin
|
||||
git remote add origin https://github.com/mfem/mfem.git
|
||||
git checkout -b gh-actions-branch-history
|
||||
./config/githooks/pre-push --history
|
||||
- name: branch-history
|
||||
run: |
|
||||
# We override origin to make sure we point to the main repo.
|
||||
# This is to have consistent test results on PRs from forks.
|
||||
git remote remove origin
|
||||
git remote add origin https://github.com/mfem/mfem.git
|
||||
git checkout -b gh-actions-branch-history
|
||||
./config/githooks/pre-push --history
|
||||
|
||||
+10
@@ -213,6 +213,7 @@ miniapps/meshing/twist
|
||||
miniapps/meshing/mesh-explorer
|
||||
miniapps/meshing/shaper
|
||||
miniapps/meshing/extruder
|
||||
miniapps/meshing/fit-node-position
|
||||
miniapps/meshing/trimmer
|
||||
miniapps/meshing/reflector
|
||||
miniapps/meshing/mesh-optimizer
|
||||
@@ -265,11 +266,15 @@ miniapps/navier/*_output
|
||||
miniapps/nurbs/nurbs_ex1
|
||||
miniapps/nurbs/nurbs_ex1p
|
||||
miniapps/nurbs/nurbs_ex11p
|
||||
miniapps/nurbs/nurbs_patch_ex1
|
||||
miniapps/nurbs/nurbs_curveint
|
||||
miniapps/nurbs/refined.mesh
|
||||
miniapps/nurbs/mesh.*
|
||||
miniapps/nurbs/sol.*
|
||||
miniapps/nurbs/mode_*
|
||||
miniapps/nurbs/Example1*
|
||||
miniapps/nurbs/sin-fit.mesh
|
||||
miniapps/nurbs/CurveInt
|
||||
|
||||
miniapps/performance/ex1
|
||||
miniapps/performance/ex1p
|
||||
@@ -292,9 +297,14 @@ miniapps/tools/display-basis
|
||||
miniapps/tools/load-dc
|
||||
miniapps/tools/convert-dc
|
||||
miniapps/tools/lor-transfer
|
||||
miniapps/tools/plor-transfer
|
||||
miniapps/tools/get-values
|
||||
miniapps/tools/check-tmop-metric
|
||||
miniapps/tools/tmop-metric-magnitude
|
||||
miniapps/tools/nodal-transfer
|
||||
miniapps/tools/ParaView
|
||||
miniapps/tools/gridfunc_*
|
||||
miniapps/tools/mesh_*
|
||||
|
||||
miniapps/toys/automata
|
||||
miniapps/toys/life
|
||||
|
||||
@@ -8,88 +8,138 @@
|
||||
https://mfem.org
|
||||
|
||||
|
||||
Version 4.5.3 (development)
|
||||
Version 4.6.1 (development)
|
||||
===========================
|
||||
|
||||
|
||||
Version 4.6, released on September 27, 2023
|
||||
===========================================
|
||||
|
||||
- MFEM is now available in Homebrew and can be installed on a Mac with just
|
||||
"brew install mfem". See https://formulae.brew.sh/formula/mfem.
|
||||
|
||||
Meshing improvements
|
||||
--------------------
|
||||
- Added asymptotically-balanced TMOP compound metrics 90, 94, 328, 338. A new
|
||||
tool, tmop-metric-magnitude, can be used to track how metrics change under
|
||||
geometric perturbations. See miniapps/tools.
|
||||
|
||||
- Several NURBS meshing improvements:
|
||||
* Support for free connectivity of NURBS patches allowing for more complex
|
||||
patch configurations such as C-meshes.
|
||||
* New methods to set and get attributes on NURBS patches and patch boundaries.
|
||||
* The edge to knot map for NURBS meshes can be determined automatically. It is
|
||||
no longer needed to specify this in the NURBS mesh.
|
||||
* Added curve interpolation method for NURBS.
|
||||
* See miniapps/nurbs for example meshes and miniapps.
|
||||
|
||||
Discretization improvements
|
||||
---------------------------
|
||||
- SubMesh and ParSubMesh have been extended to support the transfer of
|
||||
Nedelec and Raviart-Thomas finite element spaces.
|
||||
|
||||
- Added support for partial assembly on NURBS patches, and NURBS-patch sparse
|
||||
matrix assembly. Patch matrix assembly includes the option to use reduced
|
||||
approximate integration rules, computed by the newly implemented non-negative
|
||||
least-squares (NNLS) solver.
|
||||
|
||||
- Support for parallel transfer of H1 fields using the low-order refined (LOR)
|
||||
transfer operators in L2ProjectionGridTransfer
|
||||
|
||||
- Added KDTree class for 2D/3D set of points, which is then utilized in the new
|
||||
KDTreeNodalProjection class to project a function defined on an arbitrary set
|
||||
of points onto an MFEM grid function. This functionality is demonstrated in
|
||||
the nodal-transfer miniapp. The current implementation is serial only. Further
|
||||
extensions can include search in arbitrary dimensional spaces.
|
||||
|
||||
- Added support for p-refined meshes in GSLIB-FindPoints.
|
||||
|
||||
- Device kernels can now access device-specific DOF and quadrature limits using
|
||||
the DofQuadLimits structure, allowing increased limits when executing on CPU.
|
||||
The limits for the runtime selected device can be accessed in host code using
|
||||
DeviceDofQuadLimits::Get(). The global constants MAX_D1D and MAX_Q1D are no
|
||||
longer available.
|
||||
|
||||
- Face restriction operators for Nedelec and Raviart-Thomas finite element
|
||||
spaces are now supported through the ConformingFaceRestriction class.
|
||||
|
||||
- VectorFEBoundaryFluxLFIntegrator is now supported on device/GPU.
|
||||
|
||||
Linear and nonlinear solvers
|
||||
----------------------------
|
||||
- Updated the MUMPS interface to support multiple right-hand sides, block
|
||||
low-rank compression, builds using 64-bit integers, and other improvements.
|
||||
|
||||
- Added an interface to the MKL Pardiso sparse direct solver developed by Intel.
|
||||
The interface provides a serial (OpenMP shared memory) version of Pardiso for
|
||||
use with SparseMatrix. This complements the existing parallel (MPI distributed
|
||||
memory) version already available through the CPardiso MFEM integration.
|
||||
|
||||
- Added HIP support to the PETSc and SUNDIALS interfaces.
|
||||
|
||||
New and updated examples and miniapps
|
||||
-------------------------------------
|
||||
- Added a new example code, Example 36/36p, to demonstrate the solution of
|
||||
the obstacle problem with a new finite element method.
|
||||
|
||||
- Added a new miniapp, Mesh Quality, for evaluating mesh quality using size,
|
||||
skewness, and aspect-ratio computed from the Jacobian of the transformation.
|
||||
|
||||
- Added a new miniapp for interface and boundary fitting to implicit domains
|
||||
defined using level-set functions. See miniapps/meshing/pmesh-fitting.cpp
|
||||
- Added a new H(div) solver miniapp demonstrating the use of a matrix-free
|
||||
saddle-point solver methodology, suitable for high-order discretizations and
|
||||
for GPU acceleration. Examples illustrating the solution of Darcy and grad-div
|
||||
problems are included. See miniapps/hdiv-linear-solver.
|
||||
|
||||
- Added new Discontinuous Petrov-Galerkin (DPG) miniapp which includes serial
|
||||
and parallel examples for diffusion, convection-diffusion, acoustics and
|
||||
Maxwell equations. The miniapp includes new classes such as (Par)DPGWeakForm,
|
||||
(Par)ComplexDPGWeakForm and (Complex)BlockStaticCondensation. Three new
|
||||
integrators are added in support of DPG systems: TraceIntegrator,
|
||||
NormalTraceIntegrator and TangentTraceIntegrator.
|
||||
NormalTraceIntegrator and TangentTraceIntegrator. See miniapps/dpg.
|
||||
|
||||
- Added new SubMesh examples demonstrating source terms and boundary conditions
|
||||
transferred from SubMesh objects.
|
||||
- Added a new miniapp that implements the SPDE method for generating Gaussian
|
||||
random fields of Matern covariance. The resulting random field can be used,
|
||||
e.g., to model material uncertainties. See miniapps/spde.
|
||||
|
||||
- Added a new H(div) solvers miniapp in miniapps/hdiv-linear-solver,
|
||||
demonstrating the use of a matrix-free saddle-point solver methodology,
|
||||
suitable for high-order discretizations and for GPU acceleration. Examples
|
||||
illustrating the solution of Darcy and grad-div problems are included.
|
||||
- Added a new parallel LOR transfer miniapp, plor-transfer, which mirrors the
|
||||
functionality of the serial LOR transfer miniapp. See miniapps/tools.
|
||||
|
||||
- New serial miniapp, nodal-transfer, demonstrating the use of KDTree to map a
|
||||
parallel grid function to a different parallel partitioning of the same mesh.
|
||||
|
||||
- Added 3 additional TMOP miniapps in miniapps/meshing:
|
||||
* Mesh-Quality evaluates quality using size, skewness, and aspect-ratio
|
||||
computed from the Jacobian of the transformation.
|
||||
* Mesh-Fitting can be used for interface and boundary fitting to implicit
|
||||
domains defined using level-set functions.
|
||||
* Fit-Node-Position fits selected mesh nodes to specified positions, while
|
||||
maintaining overall mesh quality.
|
||||
|
||||
- Added 4 new example codes:
|
||||
* Example 34/34p solves a simple magnetostatic problem where source terms and
|
||||
boundary conditions are transferred with SubMesh objects.
|
||||
* Example 35p implements H1, H(curl) and H(div) variants of a damped harmonic
|
||||
oscillator with field transfer using SubMesh objects.
|
||||
* Example 36/36p demonstrates the solution of the obstacle problem with a new
|
||||
finite element method (proximal Galerkin).
|
||||
* Example 37/37p demonstrates topology optimization with MFEM.
|
||||
|
||||
- Added a random refinement option to the mesh-explorer miniapp to assist users
|
||||
in experimenting with nonconforming meshes.
|
||||
|
||||
- Moved the distance solver methods from miniapps/shifted to miniapps/common.
|
||||
|
||||
Meshing improvements
|
||||
--------------------
|
||||
- Added new methods in the Mesh class to set and get attributes on NURBS patches
|
||||
and patch boundaries.
|
||||
|
||||
- Added HIP support to the SUNDIALS interface.
|
||||
|
||||
- TMOP improvement: added asymptotically-balanced compound metrics 90, 94, 328,
|
||||
338. Added the tmop-metric-magnitude tool for tracking how metrics change
|
||||
under geometric perturbations.
|
||||
|
||||
Discretization improvements
|
||||
---------------------------
|
||||
- Face restriction operators for Nedelec and Raviart-Thomas finite element
|
||||
spaces are now supported through the ConformingFaceRestriction class.
|
||||
|
||||
- SubMesh and ParSubMesh have been extended to support the transfer of
|
||||
Nedelec and Raviart-Thomas finite element spaces.
|
||||
|
||||
- VectorFEBoundaryFluxLFIntegrator is now supported on device/GPU.
|
||||
|
||||
- Added support for p-refined meshes in FindPointsGSLIB.
|
||||
|
||||
Linear and nonlinear solvers
|
||||
----------------------------
|
||||
- Updated interface to MUMPS direct solver to support multiple right-hand
|
||||
sides, block low-rank compression, builds using 64-bit integers, and other
|
||||
improvements.
|
||||
|
||||
- Added an interface to the MKL Pardiso sparse direct solver developed by Intel.
|
||||
This interface provides a serial (OpenMP shared memory) version of Pardiso for
|
||||
use with SparseMatrix. This complements the existing parallel (MPI distributed
|
||||
memory) version already available through the CPardiso MFEM integration.
|
||||
|
||||
Integrations, testing and documentation
|
||||
---------------------------------------
|
||||
- Added an address sanitizer GitHub action for a serial build/test on Ubuntu,
|
||||
based on Clang/LLVM (https://clang.llvm.org/docs/AddressSanitizer.html).
|
||||
|
||||
Miscellaneous
|
||||
-------------
|
||||
- Improved lambda body debugging with the addition of mfem::forall functions.
|
||||
These functions can take the place of the MFEM_FORALL macros, which have been
|
||||
preserved for backwards compatibility.
|
||||
|
||||
- Added an address sanitizer GitHub action for a serial build/test on Ubuntu,
|
||||
based on Clang/LLVM (https://clang.llvm.org/docs/AddressSanitizer.html).
|
||||
|
||||
- Reorganized files for bilinear form, linear form, and nonlinear form integrators
|
||||
in the fem/integ/ subdirectory.
|
||||
|
||||
- FiniteElementSpace::GetFE has been updated to abort instead of returning NULL for
|
||||
an empty partition.
|
||||
|
||||
- Various other simplifications, extensions, and bugfixes in the code.
|
||||
|
||||
|
||||
Version 4.5.2, released on March 23, 2023
|
||||
=========================================
|
||||
|
||||
+2
-2
@@ -57,7 +57,7 @@ project(mfem NONE)
|
||||
# Current version of MFEM, see also `makefile`.
|
||||
# mfem_VERSION = (string)
|
||||
# MFEM_VERSION = (int) [automatically derived from mfem_VERSION]
|
||||
set(${PROJECT_NAME}_VERSION 4.5.3)
|
||||
set(${PROJECT_NAME}_VERSION 4.6.1)
|
||||
|
||||
# Prohibit in-source build
|
||||
if (${PROJECT_SOURCE_DIR} STREQUAL ${PROJECT_BINARY_DIR})
|
||||
@@ -138,7 +138,7 @@ if (MFEM_USE_CUDA)
|
||||
set(CUDA_FLAGS "-ccbin=${CMAKE_CXX_COMPILER} ${CUDA_FLAGS}")
|
||||
set(CMAKE_CUDA_HOST_LINK_LAUNCHER ${CMAKE_CXX_COMPILER})
|
||||
endif()
|
||||
set(CMAKE_CUDA_FLAGS ${CMAKE_CUDA_FLAGS} ${CUDA_FLAGS})
|
||||
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} ${CUDA_FLAGS}")
|
||||
set(CUSPARSE_FOUND TRUE)
|
||||
set(CUSPARSE_LIBRARIES "cusparse")
|
||||
set(CUBLAS_FOUND TRUE)
|
||||
|
||||
@@ -135,6 +135,7 @@ The MFEM source code has the following structure:
|
||||
│ ├── adjoint
|
||||
│ ├── autodiff
|
||||
│ ├── common
|
||||
│ ├── dpg
|
||||
│ ├── electromagnetics
|
||||
│ ├── gslib
|
||||
│ ├── hdiv-linear-solver
|
||||
@@ -148,6 +149,7 @@ The MFEM source code has the following structure:
|
||||
│ ├── performance
|
||||
│ ├── shifted
|
||||
│ ├── solvers
|
||||
│ ├── spde
|
||||
│ ├── tools
|
||||
│ └── toys
|
||||
└── tests
|
||||
|
||||
@@ -699,12 +699,15 @@ The specific libraries and their options are:
|
||||
PETSc has been cloned on the same level as mfem and hypre:
|
||||
./configure --download-fblaslapack=yes --download-scalapack=yes \
|
||||
--download-mumps=yes --download-suitesparse=yes \
|
||||
--with-hypre-dir=../hypre-2.10.0b/src/hypre \
|
||||
--with-hypre-dir=../hypre/src/hypre \
|
||||
--with-shared-libraries=0
|
||||
When building PETSc with HIP, one may need to add a flag like -std=c2x to
|
||||
CFLAGS to allow proper parsing of the hipsparse header under C.
|
||||
URL: https://www.mcs.anl.gov/petsc
|
||||
Options: PETSC_OPT, PETSC_LIB.
|
||||
Versions: PETSc >= 3.8.0 (PETSc build without CUDA)
|
||||
Versions: PETSc >= 3.8.0 (PETSc build without CUDA/HIP)
|
||||
PETSc >= 3.15.0 (PETSc built with CUDA)
|
||||
PETSc >= 3.19.0 (PETSc built with HIP, older versions may work too)
|
||||
|
||||
- SLEPc (optional), used when MFEM_USE_SLEPC = YES. SLEPc depends on PETSc and
|
||||
uses some of the PETSc options when compiled.
|
||||
|
||||
@@ -19,9 +19,7 @@ RUN apt-get update && \
|
||||
apt-get install -y libcurl4-openssl-dev libssl-dev
|
||||
|
||||
ENV PATH=$PATH:/opt/mfem-view/bin
|
||||
ENV LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/opt/mfem-view/lib:/opt/mfem-view/lib64
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
# The user will see the view on shell into the container
|
||||
WORKDIR /opt/mfem-view
|
||||
ENTRYPOINT ["/bin/bash"]
|
||||
|
||||
@@ -34,14 +34,14 @@ RUN cd /opt/mfem-env && \
|
||||
. /opt/spack/share/spack/setup-env.sh && \
|
||||
spack env activate . && \
|
||||
spack develop --path /code mfem@master+examples+miniapps && \
|
||||
spack add mfem@master+examples+miniapps # && \
|
||||
# spack install
|
||||
spack add mfem@master+examples+miniapps && \
|
||||
spack install
|
||||
|
||||
# ensure mfem always on various paths
|
||||
#RUN cd /opt/mfem-env && \
|
||||
# spack env activate --sh -d . >> /etc/profile.d/z10_spack_environment.sh
|
||||
RUN cd /opt/mfem-env && \
|
||||
spack env activate --sh -d . >> /etc/profile.d/z10_spack_environment.sh
|
||||
|
||||
# Present the software install when we shell in
|
||||
# The view is at /opt/mfem-env/.spack-env/view
|
||||
#WORKDIR /opt/software
|
||||
#ENTRYPOINT ["/bin/bash", "--rcfile", "/etc/profile", "-l", "-c"]
|
||||
WORKDIR /opt/software
|
||||
ENTRYPOINT ["/bin/bash", "--rcfile", "/etc/profile", "-l", "-c"]
|
||||
|
||||
+108
-46
@@ -7,21 +7,31 @@ You can use this image for a demo of using mfem! 🎉️
|
||||
Updated containers are built and deployed on merges to the main branch and releases.
|
||||
If you want to request a build on demand, you can [manually run the workflow](https://docs.github.com/en/actions/managing-workflow-runs/manually-running-a-workflow) thanks to the workflow dispatch event.
|
||||
|
||||
### Usage
|
||||
## Usage
|
||||
|
||||
Here is how to build the container. Note that we build so it belongs to the same
|
||||
namespace as the repository here. "ghcr.io" means "GitHub Container Registry" and
|
||||
We provide two containers, which you can either build or use directly from
|
||||
[GitHub packages](https://github.com/orgs/mfem/packages?repo_name=mfem).
|
||||
|
||||
- `ghcr.io/mfem/mfem-ubuntu-base`: a "build from scratch" for mfem
|
||||
- `ghcr.io/mfem/mfem-ubuntu`: a quick build that uses the base container
|
||||
|
||||
In the above, "ghcr.io" means "GitHub Container Registry" and
|
||||
is the [GitHub packages](https://github.com/features/packages) registry that supports
|
||||
Docker images and other OCI artifacts. From the root of the repository:
|
||||
Docker images and other OCI artifacts.
|
||||
|
||||
### Ubuntu
|
||||
|
||||
> Use or build this container for a multi-stage, slimmer base to develop on top of mfem
|
||||
|
||||
Note that this container is provided on GitHub packages [here](https://github.com/mfem/mfem/pkgs/container/mfem-ubuntu)
|
||||
so you don't need to build it. However, if you want to, you can do the following:
|
||||
|
||||
```bash
|
||||
$ docker build -f config/docker/Dockerfile -t ghcr.io/mfem/mfem-ubuntu .
|
||||
$ docker build -f config/docker/Dockerfile.base -t ghcr.io/mfem/mfem-ubuntu-base .
|
||||
```
|
||||
|
||||
### Shell Ubuntu
|
||||
|
||||
To shell into the container:
|
||||
Note that this will pull the base image. If you want to rebuild it, see [ubuntu base](#ubuntu-base)
|
||||
below. Once you have built (or prefer to pull) you can shell into the container as follows:
|
||||
|
||||
```bash
|
||||
$ docker run -it ghcr.io/mfem/mfem-ubuntu
|
||||
@@ -37,39 +47,13 @@ bin etc include lib libexec sbin share var
|
||||
- Examples are in share/mfem/examples
|
||||
- Examples are in share/mfem/miniapps
|
||||
|
||||
You can read more about interaction with these examples and miniapps below.
|
||||
|
||||
### Shell Ubuntu Base
|
||||
|
||||
To shell into the container:
|
||||
Using this container, if you want to develop a tool that _uses_ mfem, you can find the libraries / includes in:
|
||||
|
||||
```bash
|
||||
$ docker run -it ghcr.io/mfem/mfem-ubuntu-base bash
|
||||
```
|
||||
|
||||
Off the bat, you can see mfem libraries are in your path so you can jump into development:
|
||||
|
||||
```bash
|
||||
env | grep mfem
|
||||
```
|
||||
```bash
|
||||
PKG_CONFIG_PATH=/opt/mfem-env/.spack-env/view/lib/pkgconfig:/opt/mfem-env/.spack-env/view/share/pkgconfig:/opt/mfem-env/.spack-env/view/lib64/pkgconfig
|
||||
PWD=/opt/mfem-env
|
||||
MANPATH=/opt/mfem-env/.spack-env/view/share/man:/opt/mfem-env/.spack-env/view/man:
|
||||
CMAKE_PREFIX_PATH=/opt/mfem-env/.spack-env/view
|
||||
SPACK_ENV=/opt/mfem-env
|
||||
ACLOCAL_PATH=/opt/mfem-env/.spack-env/view/share/aclocal
|
||||
LD_LIBRARY_PATH=/opt/mfem-env/.spack-env/view/lib:/opt/mfem-env/.spack-env/view/lib64
|
||||
PATH=/opt/mfem-env/.spack-env/view/bin:/opt/view/bin:/opt/spack/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
|
||||
```
|
||||
|
||||
#### Examples and MiniApps
|
||||
|
||||
If you want to develop a tool that _uses_ mfem, you can find the built libraries in:
|
||||
|
||||
```
|
||||
$ ls /opt/mfem-env/.spack-env/view/
|
||||
bin etc include lib libexec sbin share var
|
||||
$ ls include/ | grep mfem
|
||||
mfem
|
||||
mfem-performance.hpp
|
||||
mfem.hpp
|
||||
```
|
||||
|
||||
And yes, this is the working directory when you shell into the container!
|
||||
@@ -79,6 +63,16 @@ You can find the examples here:
|
||||
```bash
|
||||
cd share/mfem/examples
|
||||
```
|
||||
|
||||
Try quickly setting the `LD_LIBRARY_PATH` so we can see the shared libraries
|
||||
we need:
|
||||
|
||||
```bash
|
||||
export LD_LIBRARY_PATH=/opt/mfem-view/lib:$LD_LIBRARY_PATH
|
||||
```
|
||||
|
||||
And then run:
|
||||
|
||||
```bash
|
||||
$ ./ex0
|
||||
Options used:
|
||||
@@ -97,7 +91,6 @@ Number of unknowns: 101
|
||||
Average reduction factor = 0.140201
|
||||
```
|
||||
|
||||
Try running a few, and look at the associated .cpp file for the source code!
|
||||
You can also explore the "mini apps," also in share/mfem, but under miniapps.
|
||||
|
||||
```bash
|
||||
@@ -130,18 +123,87 @@ Rule:
|
||||
Applying rule...done.
|
||||
```
|
||||
|
||||
Have fun!
|
||||
Have fun! As a reminder, this container is ideal for developing your own
|
||||
applications that might use mfem, or having a nice environment to test out
|
||||
examples.
|
||||
|
||||
|
||||
#### Your own App
|
||||
If you want to develop with your own code base
|
||||
(and mfem as is in the container) you can bind to somewhere else in the container (e.g., src)
|
||||
### Ubuntu Base
|
||||
|
||||
> Use this build for a development environment with spack and mfem
|
||||
|
||||
This container is also [provided on GitHub packages](https://github.com/mfem/mfem/pkgs/container/mfem-ubuntu-base),
|
||||
however you can build it locally too:
|
||||
|
||||
```bash
|
||||
$ docker run -it ghcr.io/mfem/mfem-ubuntu-base -v $PWD:/src bash
|
||||
$ docker build -f config/docker/Dockerfile.base -t ghcr.io/mfem/mfem-ubuntu-base .
|
||||
```
|
||||
|
||||
To shell into the container:
|
||||
|
||||
```bash
|
||||
$ docker run -it ghcr.io/mfem/mfem-ubuntu-base bash
|
||||
```
|
||||
|
||||
Change directory to the mfem environment, setup spack, and activate the environment:
|
||||
|
||||
```bash
|
||||
source /opt/spack/share/spack/setup-env.sh
|
||||
cd /opt/mfem-env/
|
||||
spack env activate .
|
||||
```
|
||||
|
||||
Note that this environment is installing to the view at `/opt/view`. Since the environment
|
||||
knows to install mfem from `/code` this means that you could make changes in the container (or bind
|
||||
`/code` to your container) and then update spack:
|
||||
|
||||
```bash
|
||||
# Note that concretization takes a hot minute!
|
||||
$ spack install
|
||||
```
|
||||
|
||||
And if you want to load mfem:
|
||||
|
||||
```bash
|
||||
$ spack load mfem
|
||||
$ env | grep mfem
|
||||
```
|
||||
|
||||
In this development container, you can find the examples and miniapps alongside
|
||||
mfem under `/code`:
|
||||
|
||||
```bash
|
||||
cd /code/examples
|
||||
```
|
||||
```bash
|
||||
$ ./ex0
|
||||
```
|
||||
```console
|
||||
Options used:
|
||||
--mesh ../data/star.mesh
|
||||
--order 1
|
||||
Number of unknowns: 101
|
||||
Iteration : 0 (B r, r) = 0.184259
|
||||
Iteration : 1 (B r, r) = 0.102754
|
||||
Iteration : 2 (B r, r) = 0.00558141
|
||||
Iteration : 3 (B r, r) = 1.5247e-05
|
||||
Iteration : 4 (B r, r) = 1.13807e-07
|
||||
Iteration : 5 (B r, r) = 6.27231e-09
|
||||
Iteration : 6 (B r, r) = 3.76268e-11
|
||||
Iteration : 7 (B r, r) = 6.07423e-13
|
||||
Iteration : 8 (B r, r) = 4.10615e-15
|
||||
Average reduction factor = 0.140201
|
||||
```
|
||||
|
||||
This container is likely ideal for someone that wants to develop mfem itself.
|
||||
For other use cases, we recommend using the slimmer image. As an example,
|
||||
if you want to develop with your own code base (and mfem as is in the container)
|
||||
you can bind to somewhere else in the container (e.g., src)
|
||||
|
||||
```bash
|
||||
$ docker run -it ghcr.io/mfem/mfem-ubuntu-base -v $PWD:/code bash
|
||||
```
|
||||
|
||||
In the above, we can pretend your project is in the present working directory (PWD) and we are
|
||||
binding to source. You can then use the mfem in the container for development, and if you
|
||||
want to distribute your library or app in a container, you can use the mfem container as the base.
|
||||
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
MFEM mesh v1.0
|
||||
|
||||
#
|
||||
# MFEM Geometry Types (see mesh/geom.hpp):
|
||||
#
|
||||
# POINT = 0
|
||||
# SEGMENT = 1
|
||||
# TRIANGLE = 2
|
||||
# SQUARE = 3
|
||||
# TETRAHEDRON = 4
|
||||
# CUBE = 5
|
||||
# PRISM = 6
|
||||
#
|
||||
|
||||
dimension
|
||||
1
|
||||
|
||||
elements
|
||||
4
|
||||
1 1 0 1
|
||||
1 1 1 2
|
||||
1 1 2 3
|
||||
1 1 3 4
|
||||
|
||||
boundary
|
||||
2
|
||||
1 0 0
|
||||
2 0 4
|
||||
|
||||
vertices
|
||||
5
|
||||
2
|
||||
0 0
|
||||
0.25 0.25
|
||||
0.50 0.50
|
||||
0.75 0.75
|
||||
1 1
|
||||
@@ -0,0 +1,37 @@
|
||||
MFEM mesh v1.0
|
||||
|
||||
#
|
||||
# MFEM Geometry Types (see mesh/geom.hpp):
|
||||
#
|
||||
# POINT = 0
|
||||
# SEGMENT = 1
|
||||
# TRIANGLE = 2
|
||||
# SQUARE = 3
|
||||
# TETRAHEDRON = 4
|
||||
# CUBE = 5
|
||||
# PRISM = 6
|
||||
#
|
||||
|
||||
dimension
|
||||
1
|
||||
|
||||
elements
|
||||
4
|
||||
1 1 0 1
|
||||
1 1 1 2
|
||||
1 1 2 3
|
||||
1 1 3 4
|
||||
|
||||
boundary
|
||||
2
|
||||
1 0 0
|
||||
2 0 4
|
||||
|
||||
vertices
|
||||
5
|
||||
3
|
||||
0 0 0
|
||||
0.25 0.25 0.25
|
||||
0.50 0.50 0.50
|
||||
0.75 0.75 0.75
|
||||
1 1 1
|
||||
@@ -38,7 +38,7 @@ PROJECT_NAME = "MFEM"
|
||||
# could be handy for archiving the generated documentation or if some version
|
||||
# control system is used.
|
||||
|
||||
PROJECT_NUMBER = v4.5.3
|
||||
PROJECT_NUMBER = v4.6.1
|
||||
|
||||
# Using the PROJECT_BRIEF tag one can provide an optional one line description
|
||||
# for a project that appears at the top of each page and should give viewer a
|
||||
|
||||
@@ -105,8 +105,13 @@ namespace mfem {
|
||||
* - <a class="el" href="ex32p_8cpp_source.html">Example 32p</a>: parallel anisotropic Maxwell eigensolver
|
||||
* - <a class="el" href="ex33_8cpp_source.html">Example 33</a>: nodal H1 FEM for the fractional Laplacian problem
|
||||
* - <a class="el" href="ex33p_8cpp_source.html">Example 33p</a>: parallel nodal H1 FEM for the fractional Laplacian problem
|
||||
* - <a class="el" href="ex34_8cpp_source.html">Example 34</a>: multi-domain magnetostatics
|
||||
* - <a class="el" href="ex34p_8cpp_source.html">Example 34p</a>: parallel multi-domain magnetostatics
|
||||
* - <a class="el" href="ex35p_8cpp_source.html">Example 35p</a>: parallel multi-domain damped harmonic oscillators
|
||||
* - <a class="el" href="ex36_8cpp_source.html">Example 36</a>: Proximal Galerkin FEM for the obstacle problem
|
||||
* - <a class="el" href="ex36p_8cpp_source.html">Example 36p</a>: parallel Proximal Galerkin FEM for the obstacle problem
|
||||
* - <a class="el" href="ex37_8cpp_source.html">Example 37</a>: Topology optimization
|
||||
* - <a class="el" href="ex37p_8cpp_source.html">Example 37p</a>: parallel topology optimization
|
||||
*
|
||||
* <H4>AmgX Examples</H4>
|
||||
* - Variants of Examples
|
||||
|
||||
@@ -42,6 +42,7 @@ list(APPEND ALL_EXE_SRCS
|
||||
ex33.cpp
|
||||
ex34.cpp
|
||||
ex36.cpp
|
||||
ex37.cpp
|
||||
)
|
||||
|
||||
if (MFEM_USE_MPI)
|
||||
@@ -82,6 +83,7 @@ if (MFEM_USE_MPI)
|
||||
ex34p.cpp
|
||||
ex35p.cpp
|
||||
ex36p.cpp
|
||||
ex37p.cpp
|
||||
)
|
||||
endif()
|
||||
|
||||
@@ -107,6 +109,8 @@ if (MFEM_ENABLE_TESTING)
|
||||
list(APPEND THIS_TEST_OPTIONS "-e" "1")
|
||||
elseif(${TEST_NAME} MATCHES "ex27p*")
|
||||
list(APPEND THIS_TEST_OPTIONS "-dg")
|
||||
elseif(${TEST_NAME} MATCHES "ex37p*")
|
||||
list(APPEND THIS_TEST_OPTIONS "-mi" "3")
|
||||
endif()
|
||||
|
||||
if (NOT (${TEST_NAME} MATCHES ".*p$"))
|
||||
|
||||
+1
-1
@@ -22,7 +22,7 @@ using namespace mfem;
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
// 1. Parse command line options.
|
||||
const char *mesh_file = "../data/star.mesh";
|
||||
string mesh_file = "../data/star.mesh";
|
||||
int order = 1;
|
||||
|
||||
OptionsParser args(argc, argv);
|
||||
|
||||
+1
-1
@@ -26,7 +26,7 @@ int main(int argc, char *argv[])
|
||||
Hypre::Init();
|
||||
|
||||
// 2. Parse command line options.
|
||||
const char *mesh_file = "../data/star.mesh";
|
||||
string mesh_file = "../data/star.mesh";
|
||||
int order = 1;
|
||||
|
||||
OptionsParser args(argc, argv);
|
||||
|
||||
@@ -100,6 +100,21 @@ int main(int argc, char *argv[])
|
||||
Device device(device_config);
|
||||
if (myid == 0) { device.Print(); }
|
||||
|
||||
if (mfem::Device::Allows(mfem::Backend::DEVICE_MASK))
|
||||
{
|
||||
HYPRE_SetMemoryLocation(HYPRE_MEMORY_DEVICE);
|
||||
HYPRE_SetExecutionPolicy(HYPRE_EXEC_DEVICE);
|
||||
HYPRE_DeviceInitialize();
|
||||
}
|
||||
else
|
||||
{
|
||||
HYPRE_SetMemoryLocation(HYPRE_MEMORY_HOST);
|
||||
HYPRE_SetExecutionPolicy(HYPRE_EXEC_HOST);
|
||||
}
|
||||
|
||||
auto loc = mfem::GetHypreMemoryLocation();
|
||||
auto exec = mfem::GetHypreExecutionPolicy();
|
||||
|
||||
// 4. Read the (serial) mesh from the given mesh file on all processors. We
|
||||
// can handle triangular, quadrilateral, tetrahedral, hexahedral, surface
|
||||
// and volume meshes with the same code.
|
||||
|
||||
+24
-25
@@ -267,9 +267,9 @@ int main(int argc, char *argv[])
|
||||
<< "window_geometry 400 0 400 350" << flush;
|
||||
}
|
||||
|
||||
// 7. Define a parallel finite element space on the full mesh. Here we
|
||||
// use the H(curl) finite elements for the vector potential and H(div)
|
||||
// for the current density.
|
||||
// 7. Define a parallel finite element space on the full mesh. Here we use
|
||||
// the H(curl) finite elements for the vector potential and H(div) for the
|
||||
// current density.
|
||||
ND_FECollection fec_nd(order, dim);
|
||||
RT_FECollection fec_rt(order - 1, dim);
|
||||
FiniteElementSpace fespace_nd(&mesh, &fec_nd);
|
||||
@@ -292,10 +292,10 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
|
||||
// 8. Determine the list of true (i.e. parallel conforming) essential
|
||||
// boundary dofs. In this example, the boundary conditions are defined
|
||||
// by marking all the boundary attributes except for those on a symmetry
|
||||
// plane as essential (Dirichlet) and converting them to a list of
|
||||
// true dofs.
|
||||
// boundary dofs. In this example, the boundary conditions are defined by
|
||||
// marking all the boundary attributes except for those on a symmetry
|
||||
// plane as essential (Dirichlet) and converting them to a list of true
|
||||
// dofs.
|
||||
Array<int> ess_tdof_list;
|
||||
Array<int> ess_bdr;
|
||||
if (mesh.bdr_attributes.Size())
|
||||
@@ -324,14 +324,13 @@ int main(int argc, char *argv[])
|
||||
GridFunction x(&fespace_nd);
|
||||
x = 0.0;
|
||||
|
||||
// 11. Set up the parallel bilinear form corresponding to the EM
|
||||
// diffusion operator curl muinv curl + delta I, by adding the
|
||||
// curl-curl and the mass domain integrators. For standard
|
||||
// magnetostatics equations choose delta << 1. Larger values of
|
||||
// delta should make the linear system easier to solve at the
|
||||
// expense of resembling a diffusive quasistatic magnetic field.
|
||||
// A reasonable balance must be found whenever the mesh or problem
|
||||
// setup is altered.
|
||||
// 11. Set up the parallel bilinear form corresponding to the EM diffusion
|
||||
// operator curl muinv curl + delta I, by adding the curl-curl and the
|
||||
// mass domain integrators. For standard magnetostatics equations choose
|
||||
// delta << 1. Larger values of delta should make the linear system
|
||||
// easier to solve at the expense of resembling a diffusive quasistatic
|
||||
// magnetic field. A reasonable balance must be found whenever the mesh
|
||||
// or problem setup is altered.
|
||||
ConstantCoefficient muinv(1.0);
|
||||
ConstantCoefficient delta(delta_const);
|
||||
BilinearForm a(&fespace_nd);
|
||||
@@ -423,8 +422,8 @@ int main(int argc, char *argv[])
|
||||
GridFunction dx(&fespace_rt);
|
||||
curl.Mult(x, dx);
|
||||
|
||||
// 18. Save the curl of the solution in parallel. This output can
|
||||
// be viewed later using GLVis: "glvis -np <np> -m mesh -g dsol".
|
||||
// 18. Save the curl of the solution in parallel. This output can be viewed
|
||||
// later using GLVis: "glvis -np <np> -m mesh -g dsol".
|
||||
{
|
||||
ostringstream dsol_name;
|
||||
dsol_name << "dsol.gf";
|
||||
@@ -456,18 +455,18 @@ void ComputeCurrentDensityOnSubMesh(int order,
|
||||
const Array<int> &jn_zero_attr,
|
||||
GridFunction &j_cond)
|
||||
{
|
||||
// Exract the finite element space and mesh on which j_cond is defined
|
||||
// Extract the finite element space and mesh on which j_cond is defined
|
||||
FiniteElementSpace &fes_cond_rt = *j_cond.FESpace();
|
||||
Mesh &mesh_cond = *fes_cond_rt.GetMesh();
|
||||
int dim = mesh_cond.Dimension();
|
||||
|
||||
// Define a parallel finite element space on the SubMesh. Here we use the
|
||||
// H1 finite elements for the electrostatic potential.
|
||||
// Define a parallel finite element space on the SubMesh. Here we use the H1
|
||||
// finite elements for the electrostatic potential.
|
||||
H1_FECollection fec_h1(order, dim);
|
||||
FiniteElementSpace fes_cond_h1(&mesh_cond, &fec_h1);
|
||||
|
||||
// Define the conductivity coefficient and the boundaries associated with
|
||||
// the fixed potentials phi0 and phi1 which will drive the current.
|
||||
// Define the conductivity coefficient and the boundaries associated with the
|
||||
// fixed potentials phi0 and phi1 which will drive the current.
|
||||
ConstantCoefficient sigmaCoef(1.0);
|
||||
Array<int> ess_bdr_phi(mesh_cond.bdr_attributes.Max());
|
||||
Array<int> ess_bdr_j(mesh_cond.bdr_attributes.Max());
|
||||
@@ -578,9 +577,9 @@ void ComputeCurrentDensityOnSubMesh(int order,
|
||||
<< "window_geometry 0 0 400 350" << flush;
|
||||
}
|
||||
|
||||
// Solve for the current density J = -sigma Grad phi with boundary
|
||||
// conditions J.n = 0 on the walls of the conductor but not on the
|
||||
// ports where phi=0 and phi=1.
|
||||
// Solve for the current density J = -sigma Grad phi with boundary conditions
|
||||
// J.n = 0 on the walls of the conductor but not on the ports where phi=0 and
|
||||
// phi=1.
|
||||
|
||||
// J will be computed in H(div) so we need an RT mass matrix
|
||||
BilinearForm m_rt(&fes_cond_rt);
|
||||
|
||||
+16
-17
@@ -302,9 +302,9 @@ int main(int argc, char *argv[])
|
||||
<< "window_geometry 400 0 400 350" << flush;
|
||||
}
|
||||
|
||||
// 8. Define a parallel finite element space on the full mesh. Here we
|
||||
// use the H(curl) finite elements for the vector potential and H(div)
|
||||
// for the current density.
|
||||
// 8. Define a parallel finite element space on the full mesh. Here we use
|
||||
// the H(curl) finite elements for the vector potential and H(div) for the
|
||||
// current density.
|
||||
ND_FECollection fec_nd(order, dim);
|
||||
RT_FECollection fec_rt(order - 1, dim);
|
||||
ParFiniteElementSpace fespace_nd(&pmesh, &fec_nd);
|
||||
@@ -360,14 +360,13 @@ int main(int argc, char *argv[])
|
||||
ParGridFunction x(&fespace_nd);
|
||||
x = 0.0;
|
||||
|
||||
// 12. Set up the parallel bilinear form corresponding to the EM
|
||||
// diffusion operator curl muinv curl + delta I, by adding the
|
||||
// curl-curl and the mass domain integrators. For standard
|
||||
// magnetostatics equations choose delta << 1. Larger values of
|
||||
// delta should make the linear system easier to solve at the
|
||||
// expense of resembling a diffusive quasistatic magnetic field.
|
||||
// A reasonable balance must be found whenever the mesh or problem
|
||||
// setup is altered.
|
||||
// 12. Set up the parallel bilinear form corresponding to the EM diffusion
|
||||
// operator curl muinv curl + delta I, by adding the curl-curl and the
|
||||
// mass domain integrators. For standard magnetostatics equations choose
|
||||
// delta << 1. Larger values of delta should make the linear system
|
||||
// easier to solve at the expense of resembling a diffusive quasistatic
|
||||
// magnetic field. A reasonable balance must be found whenever the mesh
|
||||
// or problem setup is altered.
|
||||
ConstantCoefficient muinv(1.0);
|
||||
ConstantCoefficient delta(delta_const);
|
||||
ParBilinearForm a(&fespace_nd);
|
||||
@@ -504,7 +503,7 @@ void ComputeCurrentDensityOnSubMesh(int order,
|
||||
const Array<int> &jn_zero_attr,
|
||||
ParGridFunction &j_cond)
|
||||
{
|
||||
// Exract the finite element space and mesh on which j_cond is defined
|
||||
// Extract the finite element space and mesh on which j_cond is defined
|
||||
ParFiniteElementSpace &fes_cond_rt = *j_cond.ParFESpace();
|
||||
ParMesh &pmesh_cond = *fes_cond_rt.GetParMesh();
|
||||
int myid = fes_cond_rt.GetMyRank();
|
||||
@@ -515,8 +514,8 @@ void ComputeCurrentDensityOnSubMesh(int order,
|
||||
H1_FECollection fec_h1(order, dim);
|
||||
ParFiniteElementSpace fes_cond_h1(&pmesh_cond, &fec_h1);
|
||||
|
||||
// Define the conductivity coefficient and the boundaries associated with
|
||||
// the fixed potentials phi0 and phi1 which will drive the current.
|
||||
// Define the conductivity coefficient and the boundaries associated with the
|
||||
// fixed potentials phi0 and phi1 which will drive the current.
|
||||
ConstantCoefficient sigmaCoef(1.0);
|
||||
Array<int> ess_bdr_phi(pmesh_cond.bdr_attributes.Max());
|
||||
Array<int> ess_bdr_j(pmesh_cond.bdr_attributes.Max());
|
||||
@@ -599,9 +598,9 @@ void ComputeCurrentDensityOnSubMesh(int order,
|
||||
<< "window_geometry 0 0 400 350" << flush;
|
||||
}
|
||||
|
||||
// Solve for the current density J = -sigma Grad phi with boundary
|
||||
// conditions J.n = 0 on the walls of the conductor but not on the
|
||||
// ports where phi=0 and phi=1.
|
||||
// Solve for the current density J = -sigma Grad phi with boundary conditions
|
||||
// J.n = 0 on the walls of the conductor but not on the ports where phi=0 and
|
||||
// phi=1.
|
||||
|
||||
// J will be computed in H(div) so we need an RT mass matrix
|
||||
ParBilinearForm m_rt(&fes_cond_rt);
|
||||
|
||||
+22
-25
@@ -35,10 +35,10 @@
|
||||
// conductivity, sigma = c. The user can specify these constants
|
||||
// using either set of names.
|
||||
//
|
||||
// This example demonstrates how to transfer fields computed on
|
||||
// a boundary generated SubMesh to the full mesh and apply them
|
||||
// as boundary conditions. The default mesh and corresponding
|
||||
// boundary attriburtes were chosen to verify proper behavior on
|
||||
// This example demonstrates how to transfer fields computed on a
|
||||
// boundary generated SubMesh to the full mesh and apply them as
|
||||
// boundary conditions. The default mesh and corresponding
|
||||
// boundary attributes were chosen to verify proper behavior on
|
||||
// both triangular and quadrilateral faces of tetrahedral,
|
||||
// wedge-shaped, and hexahedral elements.
|
||||
//
|
||||
@@ -420,7 +420,6 @@ int main(int argc, char *argv[])
|
||||
//
|
||||
// 2) A vector H(Div) field
|
||||
// -Grad(a Div) - omega^2 b + i omega c
|
||||
//
|
||||
ParBilinearForm pcOp(&fespace);
|
||||
if (pa) { pcOp.SetAssemblyLevel(AssemblyLevel::PARTIAL); }
|
||||
switch (prob)
|
||||
@@ -445,8 +444,8 @@ int main(int argc, char *argv[])
|
||||
pcOp.Assemble();
|
||||
|
||||
// 14b. Define and apply a parallel FGMRES solver for AU=B with a block
|
||||
// diagonal preconditioner based on the appropriate multigrid
|
||||
// preconditioner from hypre.
|
||||
// diagonal preconditioner based on the appropriate multigrid
|
||||
// preconditioner from hypre.
|
||||
Array<int> blockTrueOffsets;
|
||||
blockTrueOffsets.SetSize(3);
|
||||
blockTrueOffsets[0] = 0;
|
||||
@@ -609,10 +608,9 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
|
||||
/**
|
||||
Solves the eigenvalue problem -Div(Grad x) = lambda x with
|
||||
homogeneous Dirichlet boundary conditions on the boundary of the
|
||||
domain. Returns mode number "mode" (counting from zero) in the
|
||||
ParGridFunction "x".
|
||||
Solves the eigenvalue problem -Div(Grad x) = lambda x with homogeneous
|
||||
Dirichlet boundary conditions on the boundary of the domain. Returns mode
|
||||
number "mode" (counting from zero) in the ParGridFunction "x".
|
||||
*/
|
||||
void ScalarWaveGuide(int mode, ParGridFunction &x)
|
||||
{
|
||||
@@ -667,10 +665,10 @@ void ScalarWaveGuide(int mode, ParGridFunction &x)
|
||||
}
|
||||
|
||||
/**
|
||||
Solves the eigenvalue problem -Curl(Curl x) = lambda x with
|
||||
homogeneous Dirichlet boundary conditions, on the tangential
|
||||
component of x, on the boundary of the domain. Returns mode number
|
||||
"mode" (counting from zero) in the ParGridFunction "x".
|
||||
Solves the eigenvalue problem -Curl(Curl x) = lambda x with homogeneous
|
||||
Dirichlet boundary conditions, on the tangential component of x, on the
|
||||
boundary of the domain. Returns mode number "mode" (counting from zero) in
|
||||
the ParGridFunction "x".
|
||||
*/
|
||||
void VectorWaveGuide(int mode, ParGridFunction &x)
|
||||
{
|
||||
@@ -723,13 +721,12 @@ void VectorWaveGuide(int mode, ParGridFunction &x)
|
||||
}
|
||||
|
||||
/**
|
||||
Solves the eigenvalue problem -Div(Grad x) = lambda x with
|
||||
homogeneous Neumann boundary conditions on the boundary of the
|
||||
domain. Returns mode number "mode" (counting from zero) in the
|
||||
ParGridFunction "x_l2". Note that mode 0 is a constant field so
|
||||
higher mode numbers are often more interesting. The eigenmode is
|
||||
solved using continuous H1 basis of the appropriate order and then
|
||||
projected onto the L2 basis and returned.
|
||||
Solves the eigenvalue problem -Div(Grad x) = lambda x with homogeneous
|
||||
Neumann boundary conditions on the boundary of the domain. Returns mode
|
||||
number "mode" (counting from zero) in the ParGridFunction "x_l2". Note that
|
||||
mode 0 is a constant field so higher mode numbers are often more
|
||||
interesting. The eigenmode is solved using continuous H1 basis of the
|
||||
appropriate order and then projected onto the L2 basis and returned.
|
||||
*/
|
||||
void PseudoScalarWaveGuide(int mode, ParGridFunction &x_l2)
|
||||
{
|
||||
@@ -791,9 +788,9 @@ void PseudoScalarWaveGuide(int mode, ParGridFunction &x_l2)
|
||||
delete M;
|
||||
}
|
||||
|
||||
// Compute eigenmode "mode" of either a Dirichlet or Neumann Laplacian
|
||||
// or of a Dirichlet curl curl operator based on the problem type and
|
||||
// dimension of the domain.
|
||||
// Compute eigenmode "mode" of either a Dirichlet or Neumann Laplacian or of a
|
||||
// Dirichlet curl curl operator based on the problem type and dimension of the
|
||||
// domain.
|
||||
void SetPortBC(int prob, int dim, int mode, ParGridFunction &port_bc)
|
||||
{
|
||||
switch (prob)
|
||||
|
||||
+3
-7
@@ -1,12 +1,10 @@
|
||||
// MFEM Example 36
|
||||
//
|
||||
//
|
||||
// Compile with: make ex36
|
||||
//
|
||||
// Sample runs: ex36 -o 2
|
||||
// ex36 -o 2 -r 4
|
||||
//
|
||||
//
|
||||
// Description: This example code demonstrates the use of MFEM to solve the
|
||||
// bound-constrained energy minimization problem
|
||||
//
|
||||
@@ -28,12 +26,10 @@
|
||||
// order solutions to variation inequality problems and
|
||||
// showcases how to set up and solve nonlinear mixed methods.
|
||||
//
|
||||
//
|
||||
// [1] Keith, B. and Surowiec, T. (2023) Proximal Galerkin: A structure-
|
||||
// preserving finite element method for pointwise bound constraints.
|
||||
// arXiv:2307.12444 [math.NA]
|
||||
|
||||
|
||||
#include "mfem.hpp"
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
@@ -63,7 +59,7 @@ public:
|
||||
class ExponentialGridFunctionCoefficient : public Coefficient
|
||||
{
|
||||
protected:
|
||||
GridFunction *u; // grid function
|
||||
GridFunction *u;
|
||||
Coefficient *obstacle;
|
||||
double min_val;
|
||||
double max_val;
|
||||
@@ -88,7 +84,7 @@ int main(int argc, char *argv[])
|
||||
|
||||
OptionsParser args(argc, argv);
|
||||
args.AddOption(&order, "-o", "--order",
|
||||
"Finite element order (polynomial degree)");
|
||||
"Finite element order (polynomial degree).");
|
||||
args.AddOption(&ref_levels, "-r", "--refs",
|
||||
"Number of h-refinements.");
|
||||
args.AddOption(&max_it, "-mi", "--max-it",
|
||||
@@ -198,7 +194,7 @@ int main(int argc, char *argv[])
|
||||
u_gf.ProjectCoefficient(IC_coef);
|
||||
u_old_gf = u_gf;
|
||||
|
||||
// 9. Initialize the slack variable ψₕ = exp(uₕ)
|
||||
// 9. Initialize the slack variable ψₕ = ln(uₕ)
|
||||
LogarithmGridFunctionCoefficient ln_u(u_gf, obstacle);
|
||||
psi_gf.ProjectCoefficient(ln_u);
|
||||
psi_old_gf = psi_gf;
|
||||
|
||||
+3
-8
@@ -1,12 +1,10 @@
|
||||
// MFEM Example 36 - Parallel Version
|
||||
//
|
||||
// MFEM Example 36 - Parallel Version
|
||||
//
|
||||
// Compile with: make ex36p
|
||||
//
|
||||
// Sample runs: mpirun -np 4 ex36p -o 2
|
||||
// mpirun -np 4 ex36p -o 2 -r 4
|
||||
//
|
||||
//
|
||||
// Description: This example code demonstrates the use of MFEM to solve the
|
||||
// bound-constrained energy minimization problem
|
||||
//
|
||||
@@ -28,12 +26,10 @@
|
||||
// order solutions to variation inequality problems and
|
||||
// showcases how to set up and solve nonlinear mixed methods.
|
||||
//
|
||||
//
|
||||
// [1] Keith, B. and Surowiec, T. (2023) Proximal Galerkin: A structure-
|
||||
// preserving finite element method for pointwise bound constraints.
|
||||
// arXiv:2307.12444 [math.NA]
|
||||
|
||||
|
||||
#include "mfem.hpp"
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
@@ -63,7 +59,7 @@ public:
|
||||
class ExponentialGridFunctionCoefficient : public Coefficient
|
||||
{
|
||||
protected:
|
||||
GridFunction *u; // grid function
|
||||
GridFunction *u;
|
||||
Coefficient *obstacle;
|
||||
double min_val;
|
||||
double max_val;
|
||||
@@ -220,7 +216,6 @@ int main(int argc, char *argv[])
|
||||
u_old_gf = 0.0;
|
||||
psi_old_gf = 0.0;
|
||||
|
||||
|
||||
// 8. Define the function coefficients for the solution and use them to
|
||||
// initialize the initial guess
|
||||
FunctionCoefficient exact_coef(exact_solution_obstacle);
|
||||
@@ -231,7 +226,7 @@ int main(int argc, char *argv[])
|
||||
u_gf.ProjectCoefficient(IC_coef);
|
||||
u_old_gf = u_gf;
|
||||
|
||||
// 9. Initialize the slack variable ψₕ = exp(uₕ)
|
||||
// 9. Initialize the slack variable ψₕ = ln(uₕ)
|
||||
LogarithmGridFunctionCoefficient ln_u(u_gf, obstacle);
|
||||
psi_gf.ProjectCoefficient(ln_u);
|
||||
psi_old_gf = psi_gf;
|
||||
|
||||
@@ -0,0 +1,466 @@
|
||||
// MFEM Example 37
|
||||
//
|
||||
// Compile with: make ex37
|
||||
//
|
||||
// Sample runs:
|
||||
// ex37 -alpha 10
|
||||
// ex37 -alpha 10 -pv
|
||||
// ex37 -lambda 0.1 -mu 0.1
|
||||
// ex37 -o 2 -alpha 5.0 -mi 50 -vf 0.4 -ntol 1e-5
|
||||
// ex37 -r 6 -o 1 -alpha 25.0 -epsilon 0.02 -mi 50 -ntol 1e-5
|
||||
//
|
||||
// Description: This example code demonstrates the use of MFEM to solve a
|
||||
// density-filtered [3] topology optimization problem. The
|
||||
// objective is to minimize the compliance
|
||||
//
|
||||
// minimize ∫_Ω f⋅u dx over u ∈ [H¹(Ω)]² and ρ ∈ L¹(Ω)
|
||||
//
|
||||
// subject to
|
||||
//
|
||||
// -Div(r(ρ̃)Cε(u)) = f in Ω + BCs
|
||||
// -ϵ²Δρ̃ + ρ̃ = ρ in Ω + Neumann BCs
|
||||
// 0 ≤ ρ ≤ 1 in Ω
|
||||
// ∫_Ω ρ dx = θ vol(Ω)
|
||||
//
|
||||
// Here, r(ρ̃) = ρ₀ + ρ̃³ (1-ρ₀) is the solid isotropic material
|
||||
// penalization (SIMP) law, C is the elasticity tensor for an
|
||||
// isotropic linearly elastic material, ϵ > 0 is the design
|
||||
// length scale, and 0 < θ < 1 is the volume fraction.
|
||||
//
|
||||
// The problem is discretized and gradients are computing using
|
||||
// finite elements [1]. The design is optimized using an entropic
|
||||
// mirror descent algorithm introduced by Keith and Surowiec [2]
|
||||
// that is tailored to the bound constraint 0 ≤ ρ ≤ 1.
|
||||
//
|
||||
// This example highlights the ability of MFEM to deliver high-
|
||||
// order solutions to inverse design problems and showcases how
|
||||
// to set up and solve PDE-constrained optimization problems
|
||||
// using the so-called reduced space approach.
|
||||
//
|
||||
// [1] Andreassen, E., Clausen, A., Schevenels, M., Lazarov, B. S., & Sigmund, O.
|
||||
// (2011). Efficient topology optimization in MATLAB using 88 lines of
|
||||
// code. Structural and Multidisciplinary Optimization, 43(1), 1-16.
|
||||
// [2] Keith, B. and Surowiec, T. (2023) Proximal Galerkin: A structure-
|
||||
// preserving finite element method for pointwise bound constraints.
|
||||
// arXiv:2307.12444 [math.NA]
|
||||
// [3] Lazarov, B. S., & Sigmund, O. (2011). Filters in topology optimization
|
||||
// based on Helmholtz‐type differential equations. International Journal
|
||||
// for Numerical Methods in Engineering, 86(6), 765-781.
|
||||
|
||||
#include "mfem.hpp"
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include "ex37.hpp"
|
||||
|
||||
using namespace std;
|
||||
using namespace mfem;
|
||||
|
||||
/**
|
||||
* @brief Bregman projection of ρ = sigmoid(ψ) onto the subspace
|
||||
* ∫_Ω ρ dx = θ vol(Ω) as follows:
|
||||
*
|
||||
* 1. Compute the root of the R → R function
|
||||
* f(c) = ∫_Ω sigmoid(ψ + c) dx - θ vol(Ω)
|
||||
* 2. Set ψ ← ψ + c.
|
||||
*
|
||||
* @param psi a GridFunction to be updated
|
||||
* @param target_volume θ vol(Ω)
|
||||
* @param tol Newton iteration tolerance
|
||||
* @param max_its Newton maximum iteration number
|
||||
* @return double Final volume, ∫_Ω sigmoid(ψ)
|
||||
*/
|
||||
double proj(GridFunction &psi, double target_volume, double tol=1e-12,
|
||||
int max_its=10)
|
||||
{
|
||||
MappedGridFunctionCoefficient sigmoid_psi(&psi, sigmoid);
|
||||
MappedGridFunctionCoefficient der_sigmoid_psi(&psi, der_sigmoid);
|
||||
|
||||
LinearForm int_sigmoid_psi(psi.FESpace());
|
||||
int_sigmoid_psi.AddDomainIntegrator(new DomainLFIntegrator(sigmoid_psi));
|
||||
LinearForm int_der_sigmoid_psi(psi.FESpace());
|
||||
int_der_sigmoid_psi.AddDomainIntegrator(new DomainLFIntegrator(
|
||||
der_sigmoid_psi));
|
||||
bool done = false;
|
||||
for (int k=0; k<max_its; k++) // Newton iteration
|
||||
{
|
||||
int_sigmoid_psi.Assemble(); // Recompute f(c) with updated ψ
|
||||
const double f = int_sigmoid_psi.Sum() - target_volume;
|
||||
|
||||
int_der_sigmoid_psi.Assemble(); // Recompute df(c) with updated ψ
|
||||
const double df = int_der_sigmoid_psi.Sum();
|
||||
|
||||
const double dc = -f/df;
|
||||
psi += dc;
|
||||
if (abs(dc) < tol) { done = true; break; }
|
||||
}
|
||||
if (!done)
|
||||
{
|
||||
mfem_warning("Projection reached maximum iteration without converging. "
|
||||
"Result may not be accurate.");
|
||||
}
|
||||
int_sigmoid_psi.Assemble();
|
||||
return int_sigmoid_psi.Sum();
|
||||
}
|
||||
|
||||
/**
|
||||
* ---------------------------------------------------------------
|
||||
* ALGORITHM PREAMBLE
|
||||
* ---------------------------------------------------------------
|
||||
*
|
||||
* The Lagrangian for this problem is
|
||||
*
|
||||
* L(u,ρ,ρ̃,w,w̃) = (f,u) - (r(ρ̃) C ε(u),ε(w)) + (f,w)
|
||||
* - (ϵ² ∇ρ̃,∇w̃) - (ρ̃,w̃) + (ρ,w̃)
|
||||
*
|
||||
* where
|
||||
*
|
||||
* r(ρ̃) = ρ₀ + ρ̃³ (1 - ρ₀) (SIMP rule)
|
||||
*
|
||||
* ε(u) = (∇u + ∇uᵀ)/2 (symmetric gradient)
|
||||
*
|
||||
* C e = λtr(e)I + 2μe (isotropic material)
|
||||
*
|
||||
* NOTE: The Lame parameters can be computed from Young's modulus E
|
||||
* and Poisson's ratio ν as follows:
|
||||
*
|
||||
* λ = E ν/((1+ν)(1-2ν)), μ = E/(2(1+ν))
|
||||
*
|
||||
* ---------------------------------------------------------------
|
||||
*
|
||||
* Discretization choices:
|
||||
*
|
||||
* u ∈ V ⊂ (H¹)ᵈ (order p)
|
||||
* ψ ∈ L² (order p - 1), ρ = sigmoid(ψ)
|
||||
* ρ̃ ∈ H¹ (order p)
|
||||
* w ∈ V (order p)
|
||||
* w̃ ∈ H¹ (order p)
|
||||
*
|
||||
* ---------------------------------------------------------------
|
||||
* ALGORITHM
|
||||
* ---------------------------------------------------------------
|
||||
*
|
||||
* Update ρ with projected mirror descent via the following algorithm.
|
||||
*
|
||||
* 1. Initialize ψ = inv_sigmoid(vol_fraction) so that ∫ sigmoid(ψ) = θ vol(Ω)
|
||||
*
|
||||
* While not converged:
|
||||
*
|
||||
* 2. Solve filter equation ∂_w̃ L = 0; i.e.,
|
||||
*
|
||||
* (ϵ² ∇ ρ̃, ∇ v ) + (ρ̃,v) = (ρ,v) ∀ v ∈ H¹.
|
||||
*
|
||||
* 3. Solve primal problem ∂_w L = 0; i.e.,
|
||||
*
|
||||
* (λ r(ρ̃) ∇⋅u, ∇⋅v) + (2 μ r(ρ̃) ε(u), ε(v)) = (f,v) ∀ v ∈ V.
|
||||
*
|
||||
* NB. The dual problem ∂_u L = 0 is the negative of the primal problem due to symmetry.
|
||||
*
|
||||
* 4. Solve for filtered gradient ∂_ρ̃ L = 0; i.e.,
|
||||
*
|
||||
* (ϵ² ∇ w̃ , ∇ v ) + (w̃ ,v) = (-r'(ρ̃) ( λ |∇⋅u|² + 2 μ |ε(u)|²),v) ∀ v ∈ H¹.
|
||||
*
|
||||
* 5. Project the gradient onto the discrete latent space; i.e., solve
|
||||
*
|
||||
* (G,v) = (w̃,v) ∀ v ∈ L².
|
||||
*
|
||||
* 6. Bregman proximal gradient update; i.e.,
|
||||
*
|
||||
* ψ ← ψ - αG + c,
|
||||
*
|
||||
* where α > 0 is a step size parameter and c ∈ R is a constant ensuring
|
||||
*
|
||||
* ∫_Ω sigmoid(ψ - αG + c) dx = θ vol(Ω).
|
||||
*
|
||||
* end
|
||||
*/
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
// 1. Parse command-line options.
|
||||
int ref_levels = 5;
|
||||
int order = 2;
|
||||
double alpha = 1.0;
|
||||
double epsilon = 0.01;
|
||||
double vol_fraction = 0.5;
|
||||
int max_it = 1e3;
|
||||
double itol = 1e-1;
|
||||
double ntol = 1e-4;
|
||||
double rho_min = 1e-6;
|
||||
double lambda = 1.0;
|
||||
double mu = 1.0;
|
||||
bool glvis_visualization = true;
|
||||
bool paraview_output = false;
|
||||
|
||||
OptionsParser args(argc, argv);
|
||||
args.AddOption(&ref_levels, "-r", "--refine",
|
||||
"Number of times to refine the mesh uniformly.");
|
||||
args.AddOption(&order, "-o", "--order",
|
||||
"Order (degree) of the finite elements.");
|
||||
args.AddOption(&alpha, "-alpha", "--alpha-step-length",
|
||||
"Step length for gradient descent.");
|
||||
args.AddOption(&epsilon, "-epsilon", "--epsilon-thickness",
|
||||
"Length scale for ρ.");
|
||||
args.AddOption(&max_it, "-mi", "--max-it",
|
||||
"Maximum number of gradient descent iterations.");
|
||||
args.AddOption(&ntol, "-ntol", "--rel-tol",
|
||||
"Normalized exit tolerance.");
|
||||
args.AddOption(&itol, "-itol", "--abs-tol",
|
||||
"Increment exit tolerance.");
|
||||
args.AddOption(&vol_fraction, "-vf", "--volume-fraction",
|
||||
"Volume fraction for the material density.");
|
||||
args.AddOption(&lambda, "-lambda", "--lambda",
|
||||
"Lamé constant λ.");
|
||||
args.AddOption(&mu, "-mu", "--mu",
|
||||
"Lamé constant μ.");
|
||||
args.AddOption(&rho_min, "-rmin", "--psi-min",
|
||||
"Minimum of density coefficient.");
|
||||
args.AddOption(&glvis_visualization, "-vis", "--visualization", "-no-vis",
|
||||
"--no-visualization",
|
||||
"Enable or disable GLVis visualization.");
|
||||
args.AddOption(¶view_output, "-pv", "--paraview", "-no-pv",
|
||||
"--no-paraview",
|
||||
"Enable or disable ParaView output.");
|
||||
args.Parse();
|
||||
if (!args.Good())
|
||||
{
|
||||
args.PrintUsage(mfem::out);
|
||||
return 1;
|
||||
}
|
||||
args.PrintOptions(mfem::out);
|
||||
|
||||
Mesh mesh = Mesh::MakeCartesian2D(3, 1, mfem::Element::Type::QUADRILATERAL,
|
||||
true, 3.0, 1.0);
|
||||
int dim = mesh.Dimension();
|
||||
|
||||
// 2. Set BCs.
|
||||
for (int i = 0; i<mesh.GetNBE(); i++)
|
||||
{
|
||||
Element * be = mesh.GetBdrElement(i);
|
||||
Array<int> vertices;
|
||||
be->GetVertices(vertices);
|
||||
|
||||
double * coords1 = mesh.GetVertex(vertices[0]);
|
||||
double * coords2 = mesh.GetVertex(vertices[1]);
|
||||
|
||||
Vector center(2);
|
||||
center(0) = 0.5*(coords1[0] + coords2[0]);
|
||||
center(1) = 0.5*(coords1[1] + coords2[1]);
|
||||
|
||||
if (abs(center(0) - 0.0) < 1e-10)
|
||||
{
|
||||
// the left edge
|
||||
be->SetAttribute(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
// all other boundaries
|
||||
be->SetAttribute(2);
|
||||
}
|
||||
}
|
||||
mesh.SetAttributes();
|
||||
|
||||
// 3. Refine the mesh.
|
||||
for (int lev = 0; lev < ref_levels; lev++)
|
||||
{
|
||||
mesh.UniformRefinement();
|
||||
}
|
||||
|
||||
// 4. Define the necessary finite element spaces on the mesh.
|
||||
H1_FECollection state_fec(order, dim); // space for u
|
||||
H1_FECollection filter_fec(order, dim); // space for ρ̃
|
||||
L2_FECollection control_fec(order-1, dim,
|
||||
BasisType::GaussLobatto); // space for ψ
|
||||
FiniteElementSpace state_fes(&mesh, &state_fec,dim);
|
||||
FiniteElementSpace filter_fes(&mesh, &filter_fec);
|
||||
FiniteElementSpace control_fes(&mesh, &control_fec);
|
||||
|
||||
int state_size = state_fes.GetTrueVSize();
|
||||
int control_size = control_fes.GetTrueVSize();
|
||||
int filter_size = filter_fes.GetTrueVSize();
|
||||
mfem::out << "Number of state unknowns: " << state_size << std::endl;
|
||||
mfem::out << "Number of filter unknowns: " << filter_size << std::endl;
|
||||
mfem::out << "Number of control unknowns: " << control_size << std::endl;
|
||||
|
||||
// 5. Set the initial guess for ρ.
|
||||
GridFunction u(&state_fes);
|
||||
GridFunction psi(&control_fes);
|
||||
GridFunction psi_old(&control_fes);
|
||||
GridFunction rho_filter(&filter_fes);
|
||||
u = 0.0;
|
||||
rho_filter = vol_fraction;
|
||||
psi = inv_sigmoid(vol_fraction);
|
||||
psi_old = inv_sigmoid(vol_fraction);
|
||||
|
||||
// ρ = sigmoid(ψ)
|
||||
MappedGridFunctionCoefficient rho(&psi, sigmoid);
|
||||
// Interpolation of ρ = sigmoid(ψ) in control fes (for ParaView output)
|
||||
GridFunction rho_gf(&control_fes);
|
||||
// ρ - ρ_old = sigmoid(ψ) - sigmoid(ψ_old)
|
||||
DiffMappedGridFunctionCoefficient succ_diff_rho(&psi, &psi_old, sigmoid);
|
||||
|
||||
// 6. Set-up the physics solver.
|
||||
int maxat = mesh.bdr_attributes.Max();
|
||||
Array<int> ess_bdr(maxat);
|
||||
ess_bdr = 0;
|
||||
ess_bdr[0] = 1;
|
||||
ConstantCoefficient one(1.0);
|
||||
ConstantCoefficient lambda_cf(lambda);
|
||||
ConstantCoefficient mu_cf(mu);
|
||||
LinearElasticitySolver * ElasticitySolver = new LinearElasticitySolver();
|
||||
ElasticitySolver->SetMesh(&mesh);
|
||||
ElasticitySolver->SetOrder(state_fec.GetOrder());
|
||||
ElasticitySolver->SetupFEM();
|
||||
Vector center(2); center(0) = 2.9; center(1) = 0.5;
|
||||
Vector force(2); force(0) = 0.0; force(1) = -1.0;
|
||||
double r = 0.05;
|
||||
VolumeForceCoefficient vforce_cf(r,center,force);
|
||||
ElasticitySolver->SetRHSCoefficient(&vforce_cf);
|
||||
ElasticitySolver->SetEssentialBoundary(ess_bdr);
|
||||
|
||||
// 7. Set-up the filter solver.
|
||||
ConstantCoefficient eps2_cf(epsilon*epsilon);
|
||||
DiffusionSolver * FilterSolver = new DiffusionSolver();
|
||||
FilterSolver->SetMesh(&mesh);
|
||||
FilterSolver->SetOrder(filter_fec.GetOrder());
|
||||
FilterSolver->SetDiffusionCoefficient(&eps2_cf);
|
||||
FilterSolver->SetMassCoefficient(&one);
|
||||
Array<int> ess_bdr_filter;
|
||||
if (mesh.bdr_attributes.Size())
|
||||
{
|
||||
ess_bdr_filter.SetSize(mesh.bdr_attributes.Max());
|
||||
ess_bdr_filter = 0;
|
||||
}
|
||||
FilterSolver->SetEssentialBoundary(ess_bdr_filter);
|
||||
FilterSolver->SetupFEM();
|
||||
|
||||
BilinearForm mass(&control_fes);
|
||||
mass.AddDomainIntegrator(new InverseIntegrator(new MassIntegrator(one)));
|
||||
mass.Assemble();
|
||||
SparseMatrix M;
|
||||
Array<int> empty;
|
||||
mass.FormSystemMatrix(empty,M);
|
||||
|
||||
// 8. Define the Lagrange multiplier and gradient functions.
|
||||
GridFunction grad(&control_fes);
|
||||
GridFunction w_filter(&filter_fes);
|
||||
|
||||
// 9. Define some tools for later.
|
||||
ConstantCoefficient zero(0.0);
|
||||
GridFunction onegf(&control_fes);
|
||||
onegf = 1.0;
|
||||
GridFunction zerogf(&control_fes);
|
||||
zerogf = 0.0;
|
||||
LinearForm vol_form(&control_fes);
|
||||
vol_form.AddDomainIntegrator(new DomainLFIntegrator(one));
|
||||
vol_form.Assemble();
|
||||
double domain_volume = vol_form(onegf);
|
||||
const double target_volume = domain_volume * vol_fraction;
|
||||
|
||||
// 10. Connect to GLVis. Prepare for VisIt output.
|
||||
char vishost[] = "localhost";
|
||||
int visport = 19916;
|
||||
socketstream sout_r;
|
||||
if (glvis_visualization)
|
||||
{
|
||||
sout_r.open(vishost, visport);
|
||||
sout_r.precision(8);
|
||||
}
|
||||
|
||||
mfem::ParaViewDataCollection paraview_dc("ex37", &mesh);
|
||||
if (paraview_output)
|
||||
{
|
||||
rho_gf.ProjectCoefficient(rho);
|
||||
paraview_dc.SetPrefixPath("ParaView");
|
||||
paraview_dc.SetLevelsOfDetail(order);
|
||||
paraview_dc.SetDataFormat(VTKFormat::BINARY);
|
||||
paraview_dc.SetHighOrderOutput(true);
|
||||
paraview_dc.SetCycle(0);
|
||||
paraview_dc.SetTime(0.0);
|
||||
paraview_dc.RegisterField("displacement",&u);
|
||||
paraview_dc.RegisterField("density",&rho_gf);
|
||||
paraview_dc.RegisterField("filtered_density",&rho_filter);
|
||||
paraview_dc.Save();
|
||||
}
|
||||
|
||||
// 11. Iterate:
|
||||
for (int k = 1; k <= max_it; k++)
|
||||
{
|
||||
if (k > 1) { alpha *= ((double) k) / ((double) k-1); }
|
||||
|
||||
mfem::out << "\nStep = " << k << std::endl;
|
||||
|
||||
// Step 1 - Filter solve
|
||||
// Solve (ϵ^2 ∇ ρ̃, ∇ v ) + (ρ̃,v) = (ρ,v)
|
||||
FilterSolver->SetRHSCoefficient(&rho);
|
||||
FilterSolver->Solve();
|
||||
rho_filter = *FilterSolver->GetFEMSolution();
|
||||
|
||||
// Step 2 - State solve
|
||||
// Solve (λ r(ρ̃) ∇⋅u, ∇⋅v) + (2 μ r(ρ̃) ε(u), ε(v)) = (f,v)
|
||||
SIMPInterpolationCoefficient SIMP_cf(&rho_filter,rho_min, 1.0);
|
||||
ProductCoefficient lambda_SIMP_cf(lambda_cf,SIMP_cf);
|
||||
ProductCoefficient mu_SIMP_cf(mu_cf,SIMP_cf);
|
||||
ElasticitySolver->SetLameCoefficients(&lambda_SIMP_cf,&mu_SIMP_cf);
|
||||
ElasticitySolver->Solve();
|
||||
u = *ElasticitySolver->GetFEMSolution();
|
||||
|
||||
// Step 3 - Adjoint filter solve
|
||||
// Solve (ϵ² ∇ w̃, ∇ v) + (w̃ ,v) = (-r'(ρ̃) ( λ |∇⋅u|² + 2 μ |ε(u)|²),v)
|
||||
StrainEnergyDensityCoefficient rhs_cf(&lambda_cf,&mu_cf,&u, &rho_filter,
|
||||
rho_min);
|
||||
FilterSolver->SetRHSCoefficient(&rhs_cf);
|
||||
FilterSolver->Solve();
|
||||
w_filter = *FilterSolver->GetFEMSolution();
|
||||
|
||||
// Step 4 - Compute gradient
|
||||
// Solve G = M⁻¹w̃
|
||||
GridFunctionCoefficient w_cf(&w_filter);
|
||||
LinearForm w_rhs(&control_fes);
|
||||
w_rhs.AddDomainIntegrator(new DomainLFIntegrator(w_cf));
|
||||
w_rhs.Assemble();
|
||||
M.Mult(w_rhs,grad);
|
||||
|
||||
// Step 5 - Update design variable ψ ← proj(ψ - αG)
|
||||
psi.Add(-alpha, grad);
|
||||
const double material_volume = proj(psi, target_volume);
|
||||
|
||||
// Compute ||ρ - ρ_old|| in control fes.
|
||||
double norm_increment = zerogf.ComputeL1Error(succ_diff_rho);
|
||||
double norm_reduced_gradient = norm_increment/alpha;
|
||||
psi_old = psi;
|
||||
|
||||
double compliance = (*(ElasticitySolver->GetLinearForm()))(u);
|
||||
mfem::out << "norm of the reduced gradient = " << norm_reduced_gradient <<
|
||||
std::endl;
|
||||
mfem::out << "norm of the increment = " << norm_increment << endl;
|
||||
mfem::out << "compliance = " << compliance << std::endl;
|
||||
mfem::out << "volume fraction = " << material_volume / domain_volume <<
|
||||
std::endl;
|
||||
|
||||
if (glvis_visualization)
|
||||
{
|
||||
GridFunction r_gf(&filter_fes);
|
||||
r_gf.ProjectCoefficient(SIMP_cf);
|
||||
sout_r << "solution\n" << mesh << r_gf
|
||||
<< "window_title 'Design density r(ρ̃)'" << flush;
|
||||
}
|
||||
|
||||
if (paraview_output)
|
||||
{
|
||||
rho_gf.ProjectCoefficient(rho);
|
||||
paraview_dc.SetCycle(k);
|
||||
paraview_dc.SetTime((double)k);
|
||||
paraview_dc.Save();
|
||||
}
|
||||
|
||||
if (norm_reduced_gradient < ntol && norm_increment < itol)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
delete ElasticitySolver;
|
||||
delete FilterSolver;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,748 @@
|
||||
// MFEM Example 37 - Serial/Parallel Shared Code
|
||||
|
||||
#include "mfem.hpp"
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <functional>
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
/// @brief Inverse sigmoid function
|
||||
double inv_sigmoid(double x)
|
||||
{
|
||||
double tol = 1e-12;
|
||||
x = std::min(std::max(tol,x),1.0-tol);
|
||||
return std::log(x/(1.0-x));
|
||||
}
|
||||
|
||||
/// @brief Sigmoid function
|
||||
double sigmoid(double x)
|
||||
{
|
||||
if (x >= 0)
|
||||
{
|
||||
return 1.0/(1.0+std::exp(-x));
|
||||
}
|
||||
else
|
||||
{
|
||||
return std::exp(x)/(1.0+std::exp(x));
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief Derivative of sigmoid function
|
||||
double der_sigmoid(double x)
|
||||
{
|
||||
double tmp = sigmoid(-x);
|
||||
return tmp - std::pow(tmp,2);
|
||||
}
|
||||
|
||||
/// @brief Returns f(u(x)) where u is a scalar GridFunction and f:R → R
|
||||
class MappedGridFunctionCoefficient : public GridFunctionCoefficient
|
||||
{
|
||||
protected:
|
||||
std::function<double(const double)> fun; // f:R → R
|
||||
public:
|
||||
MappedGridFunctionCoefficient()
|
||||
:GridFunctionCoefficient(),
|
||||
fun([](double x) {return x;}) {}
|
||||
MappedGridFunctionCoefficient(const GridFunction *gf,
|
||||
std::function<double(const double)> fun_,
|
||||
int comp=1)
|
||||
:GridFunctionCoefficient(gf, comp),
|
||||
fun(fun_) {}
|
||||
|
||||
|
||||
virtual double Eval(ElementTransformation &T,
|
||||
const IntegrationPoint &ip)
|
||||
{
|
||||
return fun(GridFunctionCoefficient::Eval(T, ip));
|
||||
}
|
||||
void SetFunction(std::function<double(const double)> fun_) { fun = fun_; }
|
||||
};
|
||||
|
||||
|
||||
/// @brief Returns f(u(x)) - f(v(x)) where u, v are scalar GridFunctions and f:R → R
|
||||
class DiffMappedGridFunctionCoefficient : public GridFunctionCoefficient
|
||||
{
|
||||
protected:
|
||||
const GridFunction *OtherGridF;
|
||||
GridFunctionCoefficient OtherGridF_cf;
|
||||
std::function<double(const double)> fun; // f:R → R
|
||||
public:
|
||||
DiffMappedGridFunctionCoefficient()
|
||||
:GridFunctionCoefficient(),
|
||||
OtherGridF(nullptr),
|
||||
OtherGridF_cf(),
|
||||
fun([](double x) {return x;}) {}
|
||||
DiffMappedGridFunctionCoefficient(const GridFunction *gf,
|
||||
const GridFunction *other_gf,
|
||||
std::function<double(const double)> fun_,
|
||||
int comp=1)
|
||||
:GridFunctionCoefficient(gf, comp),
|
||||
OtherGridF(other_gf),
|
||||
OtherGridF_cf(OtherGridF),
|
||||
fun(fun_) {}
|
||||
|
||||
virtual double Eval(ElementTransformation &T,
|
||||
const IntegrationPoint &ip)
|
||||
{
|
||||
const double value1 = fun(GridFunctionCoefficient::Eval(T, ip));
|
||||
const double value2 = fun(OtherGridF_cf.Eval(T, ip));
|
||||
return value1 - value2;
|
||||
}
|
||||
void SetFunction(std::function<double(const double)> fun_) { fun = fun_; }
|
||||
};
|
||||
|
||||
/// @brief Solid isotropic material penalization (SIMP) coefficient
|
||||
class SIMPInterpolationCoefficient : public Coefficient
|
||||
{
|
||||
protected:
|
||||
GridFunction *rho_filter;
|
||||
double min_val;
|
||||
double max_val;
|
||||
double exponent;
|
||||
|
||||
public:
|
||||
SIMPInterpolationCoefficient(GridFunction *rho_filter_, double min_val_= 1e-6,
|
||||
double max_val_ = 1.0, double exponent_ = 3)
|
||||
: rho_filter(rho_filter_), min_val(min_val_), max_val(max_val_),
|
||||
exponent(exponent_) { }
|
||||
|
||||
virtual double Eval(ElementTransformation &T, const IntegrationPoint &ip)
|
||||
{
|
||||
double val = rho_filter->GetValue(T, ip);
|
||||
double coeff = min_val + pow(val,exponent)*(max_val-min_val);
|
||||
return coeff;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/// @brief Strain energy density coefficient
|
||||
class StrainEnergyDensityCoefficient : public Coefficient
|
||||
{
|
||||
protected:
|
||||
Coefficient * lambda=nullptr;
|
||||
Coefficient * mu=nullptr;
|
||||
GridFunction *u = nullptr; // displacement
|
||||
GridFunction *rho_filter = nullptr; // filter density
|
||||
DenseMatrix grad; // auxiliary matrix, used in Eval
|
||||
double exponent;
|
||||
double rho_min;
|
||||
|
||||
public:
|
||||
StrainEnergyDensityCoefficient(Coefficient *lambda_, Coefficient *mu_,
|
||||
GridFunction * u_, GridFunction * rho_filter_, double rho_min_=1e-6,
|
||||
double exponent_ = 3.0)
|
||||
: lambda(lambda_), mu(mu_), u(u_), rho_filter(rho_filter_),
|
||||
exponent(exponent_), rho_min(rho_min_)
|
||||
{
|
||||
MFEM_ASSERT(rho_min_ >= 0.0, "rho_min must be >= 0");
|
||||
MFEM_ASSERT(rho_min_ < 1.0, "rho_min must be > 1");
|
||||
MFEM_ASSERT(u, "displacement field is not set");
|
||||
MFEM_ASSERT(rho_filter, "density field is not set");
|
||||
}
|
||||
|
||||
virtual double Eval(ElementTransformation &T, const IntegrationPoint &ip)
|
||||
{
|
||||
double L = lambda->Eval(T, ip);
|
||||
double M = mu->Eval(T, ip);
|
||||
u->GetVectorGradient(T, grad);
|
||||
double div_u = grad.Trace();
|
||||
double density = L*div_u*div_u;
|
||||
int dim = T.GetSpaceDim();
|
||||
for (int i=0; i<dim; i++)
|
||||
{
|
||||
for (int j=0; j<dim; j++)
|
||||
{
|
||||
density += M*grad(i,j)*(grad(i,j)+grad(j,i));
|
||||
}
|
||||
}
|
||||
double val = rho_filter->GetValue(T,ip);
|
||||
|
||||
return -exponent * pow(val, exponent-1.0) * (1-rho_min) * density;
|
||||
}
|
||||
};
|
||||
|
||||
/// @brief Volumetric force for linear elasticity
|
||||
class VolumeForceCoefficient : public VectorCoefficient
|
||||
{
|
||||
private:
|
||||
double r;
|
||||
Vector center;
|
||||
Vector force;
|
||||
public:
|
||||
VolumeForceCoefficient(double r_,Vector & center_, Vector & force_) :
|
||||
VectorCoefficient(center_.Size()), r(r_), center(center_), force(force_) { }
|
||||
|
||||
using VectorCoefficient::Eval;
|
||||
|
||||
virtual void Eval(Vector &V, ElementTransformation &T,
|
||||
const IntegrationPoint &ip)
|
||||
{
|
||||
Vector xx; xx.SetSize(T.GetDimension());
|
||||
T.Transform(ip,xx);
|
||||
for (int i=0; i<xx.Size(); i++)
|
||||
{
|
||||
xx[i]=xx[i]-center[i];
|
||||
}
|
||||
|
||||
double cr=xx.Norml2();
|
||||
V.SetSize(T.GetDimension());
|
||||
if (cr <= r)
|
||||
{
|
||||
V = force;
|
||||
}
|
||||
else
|
||||
{
|
||||
V = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
void Set(double r_,Vector & center_, Vector & force_)
|
||||
{
|
||||
r=r_;
|
||||
center = center_;
|
||||
force = force_;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Class for solving Poisson's equation:
|
||||
*
|
||||
* - ∇ ⋅(κ ∇ u) = f in Ω
|
||||
*
|
||||
*/
|
||||
class DiffusionSolver
|
||||
{
|
||||
private:
|
||||
Mesh * mesh = nullptr;
|
||||
int order = 1;
|
||||
// diffusion coefficient
|
||||
Coefficient * diffcf = nullptr;
|
||||
// mass coefficient
|
||||
Coefficient * masscf = nullptr;
|
||||
Coefficient * rhscf = nullptr;
|
||||
Coefficient * essbdr_cf = nullptr;
|
||||
Coefficient * neumann_cf = nullptr;
|
||||
VectorCoefficient * gradient_cf = nullptr;
|
||||
|
||||
// FEM solver
|
||||
int dim;
|
||||
FiniteElementCollection * fec = nullptr;
|
||||
FiniteElementSpace * fes = nullptr;
|
||||
Array<int> ess_bdr;
|
||||
Array<int> neumann_bdr;
|
||||
GridFunction * u = nullptr;
|
||||
LinearForm * b = nullptr;
|
||||
bool parallel;
|
||||
#ifdef MFEM_USE_MPI
|
||||
ParMesh * pmesh = nullptr;
|
||||
ParFiniteElementSpace * pfes = nullptr;
|
||||
#endif
|
||||
|
||||
public:
|
||||
DiffusionSolver() { }
|
||||
DiffusionSolver(Mesh * mesh_, int order_, Coefficient * diffcf_,
|
||||
Coefficient * cf_);
|
||||
|
||||
void SetMesh(Mesh * mesh_)
|
||||
{
|
||||
mesh = mesh_;
|
||||
parallel = false;
|
||||
#ifdef MFEM_USE_MPI
|
||||
pmesh = dynamic_cast<ParMesh *>(mesh);
|
||||
if (pmesh) { parallel = true; }
|
||||
#endif
|
||||
}
|
||||
void SetOrder(int order_) { order = order_ ; }
|
||||
void SetDiffusionCoefficient(Coefficient * diffcf_) { diffcf = diffcf_; }
|
||||
void SetMassCoefficient(Coefficient * masscf_) { masscf = masscf_; }
|
||||
void SetRHSCoefficient(Coefficient * rhscf_) { rhscf = rhscf_; }
|
||||
void SetEssentialBoundary(const Array<int> & ess_bdr_) { ess_bdr = ess_bdr_;};
|
||||
void SetNeumannBoundary(const Array<int> & neumann_bdr_) { neumann_bdr = neumann_bdr_;};
|
||||
void SetNeumannData(Coefficient * neumann_cf_) {neumann_cf = neumann_cf_;}
|
||||
void SetEssBdrData(Coefficient * essbdr_cf_) {essbdr_cf = essbdr_cf_;}
|
||||
void SetGradientData(VectorCoefficient * gradient_cf_) {gradient_cf = gradient_cf_;}
|
||||
|
||||
void ResetFEM();
|
||||
void SetupFEM();
|
||||
|
||||
void Solve();
|
||||
GridFunction * GetFEMSolution();
|
||||
LinearForm * GetLinearForm() {return b;}
|
||||
#ifdef MFEM_USE_MPI
|
||||
ParGridFunction * GetParFEMSolution();
|
||||
ParLinearForm * GetParLinearForm()
|
||||
{
|
||||
if (parallel)
|
||||
{
|
||||
return dynamic_cast<ParLinearForm *>(b);
|
||||
}
|
||||
else
|
||||
{
|
||||
MFEM_ABORT("Wrong code path. Call GetLinearForm");
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
~DiffusionSolver();
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Class for solving linear elasticity:
|
||||
*
|
||||
* -∇ ⋅ σ(u) = f in Ω + BCs
|
||||
*
|
||||
* where
|
||||
*
|
||||
* σ(u) = λ ∇⋅u I + μ (∇ u + ∇uᵀ)
|
||||
*
|
||||
*/
|
||||
class LinearElasticitySolver
|
||||
{
|
||||
private:
|
||||
Mesh * mesh = nullptr;
|
||||
int order = 1;
|
||||
Coefficient * lambda_cf = nullptr;
|
||||
Coefficient * mu_cf = nullptr;
|
||||
VectorCoefficient * essbdr_cf = nullptr;
|
||||
VectorCoefficient * rhs_cf = nullptr;
|
||||
|
||||
// FEM solver
|
||||
int dim;
|
||||
FiniteElementCollection * fec = nullptr;
|
||||
FiniteElementSpace * fes = nullptr;
|
||||
Array<int> ess_bdr;
|
||||
Array<int> neumann_bdr;
|
||||
GridFunction * u = nullptr;
|
||||
LinearForm * b = nullptr;
|
||||
bool parallel;
|
||||
#ifdef MFEM_USE_MPI
|
||||
ParMesh * pmesh = nullptr;
|
||||
ParFiniteElementSpace * pfes = nullptr;
|
||||
#endif
|
||||
|
||||
public:
|
||||
LinearElasticitySolver() { }
|
||||
LinearElasticitySolver(Mesh * mesh_, int order_,
|
||||
Coefficient * lambda_cf_, Coefficient * mu_cf_);
|
||||
|
||||
void SetMesh(Mesh * mesh_)
|
||||
{
|
||||
mesh = mesh_;
|
||||
parallel = false;
|
||||
#ifdef MFEM_USE_MPI
|
||||
pmesh = dynamic_cast<ParMesh *>(mesh);
|
||||
if (pmesh) { parallel = true; }
|
||||
#endif
|
||||
}
|
||||
void SetOrder(int order_) { order = order_ ; }
|
||||
void SetLameCoefficients(Coefficient * lambda_cf_, Coefficient * mu_cf_) { lambda_cf = lambda_cf_; mu_cf = mu_cf_; }
|
||||
void SetRHSCoefficient(VectorCoefficient * rhs_cf_) { rhs_cf = rhs_cf_; }
|
||||
void SetEssentialBoundary(const Array<int> & ess_bdr_) { ess_bdr = ess_bdr_;};
|
||||
void SetNeumannBoundary(const Array<int> & neumann_bdr_) { neumann_bdr = neumann_bdr_;};
|
||||
void SetEssBdrData(VectorCoefficient * essbdr_cf_) {essbdr_cf = essbdr_cf_;}
|
||||
|
||||
void ResetFEM();
|
||||
void SetupFEM();
|
||||
|
||||
void Solve();
|
||||
GridFunction * GetFEMSolution();
|
||||
LinearForm * GetLinearForm() {return b;}
|
||||
#ifdef MFEM_USE_MPI
|
||||
ParGridFunction * GetParFEMSolution();
|
||||
ParLinearForm * GetParLinearForm()
|
||||
{
|
||||
if (parallel)
|
||||
{
|
||||
return dynamic_cast<ParLinearForm *>(b);
|
||||
}
|
||||
else
|
||||
{
|
||||
MFEM_ABORT("Wrong code path. Call GetLinearForm");
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
~LinearElasticitySolver();
|
||||
|
||||
};
|
||||
|
||||
|
||||
// Poisson solver
|
||||
|
||||
DiffusionSolver::DiffusionSolver(Mesh * mesh_, int order_,
|
||||
Coefficient * diffcf_, Coefficient * rhscf_)
|
||||
: mesh(mesh_), order(order_), diffcf(diffcf_), rhscf(rhscf_)
|
||||
{
|
||||
|
||||
#ifdef MFEM_USE_MPI
|
||||
pmesh = dynamic_cast<ParMesh *>(mesh);
|
||||
if (pmesh) { parallel = true; }
|
||||
#endif
|
||||
|
||||
SetupFEM();
|
||||
}
|
||||
|
||||
void DiffusionSolver::SetupFEM()
|
||||
{
|
||||
dim = mesh->Dimension();
|
||||
fec = new H1_FECollection(order, dim);
|
||||
|
||||
#ifdef MFEM_USE_MPI
|
||||
if (parallel)
|
||||
{
|
||||
pfes = new ParFiniteElementSpace(pmesh, fec);
|
||||
u = new ParGridFunction(pfes);
|
||||
b = new ParLinearForm(pfes);
|
||||
}
|
||||
else
|
||||
{
|
||||
fes = new FiniteElementSpace(mesh, fec);
|
||||
u = new GridFunction(fes);
|
||||
b = new LinearForm(fes);
|
||||
}
|
||||
#else
|
||||
fes = new FiniteElementSpace(mesh, fec);
|
||||
u = new GridFunction(fes);
|
||||
b = new LinearForm(fes);
|
||||
#endif
|
||||
*u=0.0;
|
||||
|
||||
if (!ess_bdr.Size())
|
||||
{
|
||||
if (mesh->bdr_attributes.Size())
|
||||
{
|
||||
ess_bdr.SetSize(mesh->bdr_attributes.Max());
|
||||
ess_bdr = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DiffusionSolver::Solve()
|
||||
{
|
||||
OperatorPtr A;
|
||||
Vector B, X;
|
||||
Array<int> ess_tdof_list;
|
||||
|
||||
#ifdef MFEM_USE_MPI
|
||||
if (parallel)
|
||||
{
|
||||
pfes->GetEssentialTrueDofs(ess_bdr,ess_tdof_list);
|
||||
}
|
||||
else
|
||||
{
|
||||
fes->GetEssentialTrueDofs(ess_bdr,ess_tdof_list);
|
||||
}
|
||||
#else
|
||||
fes->GetEssentialTrueDofs(ess_bdr,ess_tdof_list);
|
||||
#endif
|
||||
*u=0.0;
|
||||
if (b)
|
||||
{
|
||||
delete b;
|
||||
#ifdef MFEM_USE_MPI
|
||||
if (parallel)
|
||||
{
|
||||
b = new ParLinearForm(pfes);
|
||||
}
|
||||
else
|
||||
{
|
||||
b = new LinearForm(fes);
|
||||
}
|
||||
#else
|
||||
b = new LinearForm(fes);
|
||||
#endif
|
||||
}
|
||||
if (rhscf)
|
||||
{
|
||||
b->AddDomainIntegrator(new DomainLFIntegrator(*rhscf));
|
||||
}
|
||||
if (neumann_cf)
|
||||
{
|
||||
MFEM_VERIFY(neumann_bdr.Size(), "neumann_bdr attributes not provided");
|
||||
b->AddBoundaryIntegrator(new BoundaryLFIntegrator(*neumann_cf),neumann_bdr);
|
||||
}
|
||||
else if (gradient_cf)
|
||||
{
|
||||
MFEM_VERIFY(neumann_bdr.Size(), "neumann_bdr attributes not provided");
|
||||
b->AddBoundaryIntegrator(new BoundaryNormalLFIntegrator(*gradient_cf),
|
||||
neumann_bdr);
|
||||
}
|
||||
|
||||
b->Assemble();
|
||||
|
||||
BilinearForm * a = nullptr;
|
||||
|
||||
#ifdef MFEM_USE_MPI
|
||||
if (parallel)
|
||||
{
|
||||
a = new ParBilinearForm(pfes);
|
||||
}
|
||||
else
|
||||
{
|
||||
a = new BilinearForm(fes);
|
||||
}
|
||||
#else
|
||||
a = new BilinearForm(fes);
|
||||
#endif
|
||||
a->AddDomainIntegrator(new DiffusionIntegrator(*diffcf));
|
||||
if (masscf)
|
||||
{
|
||||
a->AddDomainIntegrator(new MassIntegrator(*masscf));
|
||||
}
|
||||
a->Assemble();
|
||||
if (essbdr_cf)
|
||||
{
|
||||
u->ProjectBdrCoefficient(*essbdr_cf,ess_bdr);
|
||||
}
|
||||
a->FormLinearSystem(ess_tdof_list, *u, *b, A, X, B);
|
||||
|
||||
CGSolver * cg = nullptr;
|
||||
Solver * M = nullptr;
|
||||
#ifdef MFEM_USE_MPI
|
||||
if (parallel)
|
||||
{
|
||||
M = new HypreBoomerAMG;
|
||||
dynamic_cast<HypreBoomerAMG*>(M)->SetPrintLevel(0);
|
||||
cg = new CGSolver(pmesh->GetComm());
|
||||
}
|
||||
else
|
||||
{
|
||||
M = new GSSmoother((SparseMatrix&)(*A));
|
||||
cg = new CGSolver;
|
||||
}
|
||||
#else
|
||||
M = new GSSmoother((SparseMatrix&)(*A));
|
||||
cg = new CGSolver;
|
||||
#endif
|
||||
cg->SetRelTol(1e-12);
|
||||
cg->SetMaxIter(10000);
|
||||
cg->SetPrintLevel(0);
|
||||
cg->SetPreconditioner(*M);
|
||||
cg->SetOperator(*A);
|
||||
cg->Mult(B, X);
|
||||
delete M;
|
||||
delete cg;
|
||||
a->RecoverFEMSolution(X, *b, *u);
|
||||
delete a;
|
||||
}
|
||||
|
||||
GridFunction * DiffusionSolver::GetFEMSolution()
|
||||
{
|
||||
return u;
|
||||
}
|
||||
|
||||
#ifdef MFEM_USE_MPI
|
||||
ParGridFunction * DiffusionSolver::GetParFEMSolution()
|
||||
{
|
||||
if (parallel)
|
||||
{
|
||||
return dynamic_cast<ParGridFunction*>(u);
|
||||
}
|
||||
else
|
||||
{
|
||||
MFEM_ABORT("Wrong code path. Call GetFEMSolution");
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
DiffusionSolver::~DiffusionSolver()
|
||||
{
|
||||
delete u; u = nullptr;
|
||||
delete fes; fes = nullptr;
|
||||
#ifdef MFEM_USE_MPI
|
||||
delete pfes; pfes=nullptr;
|
||||
#endif
|
||||
delete fec; fec = nullptr;
|
||||
delete b;
|
||||
}
|
||||
|
||||
|
||||
// Elasticity solver
|
||||
|
||||
LinearElasticitySolver::LinearElasticitySolver(Mesh * mesh_, int order_,
|
||||
Coefficient * lambda_cf_, Coefficient * mu_cf_)
|
||||
: mesh(mesh_), order(order_), lambda_cf(lambda_cf_), mu_cf(mu_cf_)
|
||||
{
|
||||
#ifdef MFEM_USE_MPI
|
||||
pmesh = dynamic_cast<ParMesh *>(mesh);
|
||||
if (pmesh) { parallel = true; }
|
||||
#endif
|
||||
SetupFEM();
|
||||
}
|
||||
|
||||
void LinearElasticitySolver::SetupFEM()
|
||||
{
|
||||
dim = mesh->Dimension();
|
||||
fec = new H1_FECollection(order, dim,BasisType::Positive);
|
||||
|
||||
#ifdef MFEM_USE_MPI
|
||||
if (parallel)
|
||||
{
|
||||
pfes = new ParFiniteElementSpace(pmesh, fec, dim);
|
||||
u = new ParGridFunction(pfes);
|
||||
b = new ParLinearForm(pfes);
|
||||
}
|
||||
else
|
||||
{
|
||||
fes = new FiniteElementSpace(mesh, fec,dim);
|
||||
u = new GridFunction(fes);
|
||||
b = new LinearForm(fes);
|
||||
}
|
||||
#else
|
||||
fes = new FiniteElementSpace(mesh, fec, dim);
|
||||
u = new GridFunction(fes);
|
||||
b = new LinearForm(fes);
|
||||
#endif
|
||||
*u=0.0;
|
||||
|
||||
if (!ess_bdr.Size())
|
||||
{
|
||||
if (mesh->bdr_attributes.Size())
|
||||
{
|
||||
ess_bdr.SetSize(mesh->bdr_attributes.Max());
|
||||
ess_bdr = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LinearElasticitySolver::Solve()
|
||||
{
|
||||
GridFunction * x = nullptr;
|
||||
OperatorPtr A;
|
||||
Vector B, X;
|
||||
Array<int> ess_tdof_list;
|
||||
|
||||
#ifdef MFEM_USE_MPI
|
||||
if (parallel)
|
||||
{
|
||||
x = new ParGridFunction(pfes);
|
||||
pfes->GetEssentialTrueDofs(ess_bdr,ess_tdof_list);
|
||||
}
|
||||
else
|
||||
{
|
||||
x = new GridFunction(fes);
|
||||
fes->GetEssentialTrueDofs(ess_bdr,ess_tdof_list);
|
||||
}
|
||||
#else
|
||||
x = new GridFunction(fes);
|
||||
fes->GetEssentialTrueDofs(ess_bdr,ess_tdof_list);
|
||||
#endif
|
||||
*u=0.0;
|
||||
if (b)
|
||||
{
|
||||
delete b;
|
||||
#ifdef MFEM_USE_MPI
|
||||
if (parallel)
|
||||
{
|
||||
b = new ParLinearForm(pfes);
|
||||
}
|
||||
else
|
||||
{
|
||||
b = new LinearForm(fes);
|
||||
}
|
||||
#else
|
||||
b = new LinearForm(fes);
|
||||
#endif
|
||||
}
|
||||
if (rhs_cf)
|
||||
{
|
||||
b->AddDomainIntegrator(new VectorDomainLFIntegrator(*rhs_cf));
|
||||
}
|
||||
|
||||
b->Assemble();
|
||||
|
||||
*x = 0.0;
|
||||
|
||||
BilinearForm * a = nullptr;
|
||||
|
||||
#ifdef MFEM_USE_MPI
|
||||
if (parallel)
|
||||
{
|
||||
a = new ParBilinearForm(pfes);
|
||||
}
|
||||
else
|
||||
{
|
||||
a = new BilinearForm(fes);
|
||||
}
|
||||
#else
|
||||
a = new BilinearForm(fes);
|
||||
#endif
|
||||
a->AddDomainIntegrator(new ElasticityIntegrator(*lambda_cf, *mu_cf));
|
||||
a->Assemble();
|
||||
if (essbdr_cf)
|
||||
{
|
||||
u->ProjectBdrCoefficient(*essbdr_cf,ess_bdr);
|
||||
}
|
||||
a->FormLinearSystem(ess_tdof_list, *x, *b, A, X, B);
|
||||
|
||||
CGSolver * cg = nullptr;
|
||||
Solver * M = nullptr;
|
||||
#ifdef MFEM_USE_MPI
|
||||
if (parallel)
|
||||
{
|
||||
M = new HypreBoomerAMG;
|
||||
dynamic_cast<HypreBoomerAMG*>(M)->SetPrintLevel(0);
|
||||
cg = new CGSolver(pmesh->GetComm());
|
||||
}
|
||||
else
|
||||
{
|
||||
M = new GSSmoother((SparseMatrix&)(*A));
|
||||
cg = new CGSolver;
|
||||
}
|
||||
#else
|
||||
M = new GSSmoother((SparseMatrix&)(*A));
|
||||
cg = new CGSolver;
|
||||
#endif
|
||||
cg->SetRelTol(1e-10);
|
||||
cg->SetMaxIter(10000);
|
||||
cg->SetPrintLevel(0);
|
||||
cg->SetPreconditioner(*M);
|
||||
cg->SetOperator(*A);
|
||||
cg->Mult(B, X);
|
||||
delete M;
|
||||
delete cg;
|
||||
a->RecoverFEMSolution(X, *b, *x);
|
||||
*u+=*x;
|
||||
delete a;
|
||||
delete x;
|
||||
}
|
||||
|
||||
GridFunction * LinearElasticitySolver::GetFEMSolution()
|
||||
{
|
||||
return u;
|
||||
}
|
||||
|
||||
#ifdef MFEM_USE_MPI
|
||||
ParGridFunction * LinearElasticitySolver::GetParFEMSolution()
|
||||
{
|
||||
if (parallel)
|
||||
{
|
||||
return dynamic_cast<ParGridFunction*>(u);
|
||||
}
|
||||
else
|
||||
{
|
||||
MFEM_ABORT("Wrong code path. Call GetFEMSolution");
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
LinearElasticitySolver::~LinearElasticitySolver()
|
||||
{
|
||||
delete u; u = nullptr;
|
||||
delete fes; fes = nullptr;
|
||||
#ifdef MFEM_USE_MPI
|
||||
delete pfes; pfes=nullptr;
|
||||
#endif
|
||||
delete fec; fec = nullptr;
|
||||
delete b;
|
||||
}
|
||||
|
||||
} // namespace mfem
|
||||
|
||||
@@ -0,0 +1,497 @@
|
||||
// MFEM Example 37 - Parallel Version
|
||||
//
|
||||
// Compile with: make ex37p
|
||||
//
|
||||
// Sample runs:
|
||||
// mpirun -np 4 ex37p -alpha 10 -pv
|
||||
// mpirun -np 4 ex37p -lambda 0.1 -mu 0.1
|
||||
// mpirun -np 4 ex37p -o 2 -alpha 5.0 -mi 50 -vf 0.4 -ntol 1e-5
|
||||
// mpirun -np 4 ex37p -r 6 -o 2 -alpha 10.0 -epsilon 0.02 -mi 50 -ntol 1e-5
|
||||
//
|
||||
// Description: This example code demonstrates the use of MFEM to solve a
|
||||
// density-filtered [3] topology optimization problem. The
|
||||
// objective is to minimize the compliance
|
||||
//
|
||||
// minimize ∫_Ω f⋅u dx over u ∈ [H¹(Ω)]² and ρ ∈ L¹(Ω)
|
||||
//
|
||||
// subject to
|
||||
//
|
||||
// -Div(r(ρ̃)Cε(u)) = f in Ω + BCs
|
||||
// -ϵ²Δρ̃ + ρ̃ = ρ in Ω + Neumann BCs
|
||||
// 0 ≤ ρ ≤ 1 in Ω
|
||||
// ∫_Ω ρ dx = θ vol(Ω)
|
||||
//
|
||||
// Here, r(ρ̃) = ρ₀ + ρ̃³ (1-ρ₀) is the solid isotropic material
|
||||
// penalization (SIMP) law, C is the elasticity tensor for an
|
||||
// isotropic linearly elastic material, ϵ > 0 is the design
|
||||
// length scale, and 0 < θ < 1 is the volume fraction.
|
||||
//
|
||||
// The problem is discretized and gradients are computing using
|
||||
// finite elements [1]. The design is optimized using an entropic
|
||||
// mirror descent algorithm introduced by Keith and Surowiec [2]
|
||||
// that is tailored to the bound constraint 0 ≤ ρ ≤ 1.
|
||||
//
|
||||
// This example highlights the ability of MFEM to deliver high-
|
||||
// order solutions to inverse design problems and showcases how
|
||||
// to set up and solve PDE-constrained optimization problems
|
||||
// using the so-called reduced space approach.
|
||||
//
|
||||
// [1] Andreassen, E., Clausen, A., Schevenels, M., Lazarov, B. S., & Sigmund, O.
|
||||
// (2011). Efficient topology optimization in MATLAB using 88 lines of
|
||||
// code. Structural and Multidisciplinary Optimization, 43(1), 1-16.
|
||||
// [2] Keith, B. and Surowiec, T. (2023) Proximal Galerkin: A structure-
|
||||
// preserving finite element method for pointwise bound constraints.
|
||||
// arXiv:2307.12444 [math.NA]
|
||||
// [3] Lazarov, B. S., & Sigmund, O. (2011). Filters in topology optimization
|
||||
// based on Helmholtz‐type differential equations. International Journal
|
||||
// for Numerical Methods in Engineering, 86(6), 765-781.
|
||||
|
||||
#include "mfem.hpp"
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include "ex37.hpp"
|
||||
|
||||
using namespace std;
|
||||
using namespace mfem;
|
||||
|
||||
/**
|
||||
* @brief Bregman projection of ρ = sigmoid(ψ) onto the subspace
|
||||
* ∫_Ω ρ dx = θ vol(Ω) as follows:
|
||||
*
|
||||
* 1. Compute the root of the R → R function
|
||||
* f(c) = ∫_Ω sigmoid(ψ + c) dx - θ vol(Ω)
|
||||
* 2. Set ψ ← ψ + c.
|
||||
*
|
||||
* @param psi a GridFunction to be updated
|
||||
* @param target_volume θ vol(Ω)
|
||||
* @param tol Newton iteration tolerance
|
||||
* @param max_its Newton maximum iteration number
|
||||
* @return double Final volume, ∫_Ω sigmoid(ψ)
|
||||
*/
|
||||
double proj(ParGridFunction &psi, double target_volume, double tol=1e-12,
|
||||
int max_its=10)
|
||||
{
|
||||
MappedGridFunctionCoefficient sigmoid_psi(&psi, sigmoid);
|
||||
MappedGridFunctionCoefficient der_sigmoid_psi(&psi, der_sigmoid);
|
||||
|
||||
ParLinearForm int_sigmoid_psi(psi.ParFESpace());
|
||||
int_sigmoid_psi.AddDomainIntegrator(new DomainLFIntegrator(sigmoid_psi));
|
||||
ParLinearForm int_der_sigmoid_psi(psi.ParFESpace());
|
||||
int_der_sigmoid_psi.AddDomainIntegrator(new DomainLFIntegrator(
|
||||
der_sigmoid_psi));
|
||||
bool done = false;
|
||||
for (int k=0; k<max_its; k++) // Newton iteration
|
||||
{
|
||||
int_sigmoid_psi.Assemble(); // Recompute f(c) with updated ψ
|
||||
double f = int_sigmoid_psi.Sum();
|
||||
MPI_Allreduce(MPI_IN_PLACE, &f, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);
|
||||
f -= target_volume;
|
||||
|
||||
int_der_sigmoid_psi.Assemble(); // Recompute df(c) with updated ψ
|
||||
double df = int_der_sigmoid_psi.Sum();
|
||||
MPI_Allreduce(MPI_IN_PLACE, &df, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);
|
||||
|
||||
const double dc = -f/df;
|
||||
psi += dc;
|
||||
if (abs(dc) < tol) { done = true; break; }
|
||||
}
|
||||
if (!done)
|
||||
{
|
||||
mfem_warning("Projection reached maximum iteration without converging. "
|
||||
"Result may not be accurate.");
|
||||
}
|
||||
int_sigmoid_psi.Assemble();
|
||||
double material_volume = int_sigmoid_psi.Sum();
|
||||
MPI_Allreduce(MPI_IN_PLACE, &material_volume, 1, MPI_DOUBLE, MPI_SUM,
|
||||
MPI_COMM_WORLD);
|
||||
return material_volume;
|
||||
}
|
||||
|
||||
/**
|
||||
* ---------------------------------------------------------------
|
||||
* ALGORITHM PREAMBLE
|
||||
* ---------------------------------------------------------------
|
||||
*
|
||||
* The Lagrangian for this problem is
|
||||
*
|
||||
* L(u,ρ,ρ̃,w,w̃) = (f,u) - (r(ρ̃) C ε(u),ε(w)) + (f,w)
|
||||
* - (ϵ² ∇ρ̃,∇w̃) - (ρ̃,w̃) + (ρ,w̃)
|
||||
*
|
||||
* where
|
||||
*
|
||||
* r(ρ̃) = ρ₀ + ρ̃³ (1 - ρ₀) (SIMP rule)
|
||||
*
|
||||
* ε(u) = (∇u + ∇uᵀ)/2 (symmetric gradient)
|
||||
*
|
||||
* C e = λtr(e)I + 2μe (isotropic material)
|
||||
*
|
||||
* NOTE: The Lame parameters can be computed from Young's modulus E
|
||||
* and Poisson's ratio ν as follows:
|
||||
*
|
||||
* λ = E ν/((1+ν)(1-2ν)), μ = E/(2(1+ν))
|
||||
*
|
||||
* ---------------------------------------------------------------
|
||||
*
|
||||
* Discretization choices:
|
||||
*
|
||||
* u ∈ V ⊂ (H¹)ᵈ (order p)
|
||||
* ψ ∈ L² (order p - 1), ρ = sigmoid(ψ)
|
||||
* ρ̃ ∈ H¹ (order p)
|
||||
* w ∈ V (order p)
|
||||
* w̃ ∈ H¹ (order p)
|
||||
*
|
||||
* ---------------------------------------------------------------
|
||||
* ALGORITHM
|
||||
* ---------------------------------------------------------------
|
||||
*
|
||||
* Update ρ with projected mirror descent via the following algorithm.
|
||||
*
|
||||
* 1. Initialize ψ = inv_sigmoid(vol_fraction) so that ∫ sigmoid(ψ) = θ vol(Ω)
|
||||
*
|
||||
* While not converged:
|
||||
*
|
||||
* 2. Solve filter equation ∂_w̃ L = 0; i.e.,
|
||||
*
|
||||
* (ϵ² ∇ ρ̃, ∇ v ) + (ρ̃,v) = (ρ,v) ∀ v ∈ H¹.
|
||||
*
|
||||
* 3. Solve primal problem ∂_w L = 0; i.e.,
|
||||
*
|
||||
* (λ r(ρ̃) ∇⋅u, ∇⋅v) + (2 μ r(ρ̃) ε(u), ε(v)) = (f,v) ∀ v ∈ V.
|
||||
*
|
||||
* NB. The dual problem ∂_u L = 0 is the negative of the primal problem due to symmetry.
|
||||
*
|
||||
* 4. Solve for filtered gradient ∂_ρ̃ L = 0; i.e.,
|
||||
*
|
||||
* (ϵ² ∇ w̃ , ∇ v ) + (w̃ ,v) = (-r'(ρ̃) ( λ |∇⋅u|² + 2 μ |ε(u)|²),v) ∀ v ∈ H¹.
|
||||
*
|
||||
* 5. Project the gradient onto the discrete latent space; i.e., solve
|
||||
*
|
||||
* (G,v) = (w̃,v) ∀ v ∈ L².
|
||||
*
|
||||
* 6. Bregman proximal gradient update; i.e.,
|
||||
*
|
||||
* ψ ← ψ - αG + c,
|
||||
*
|
||||
* where α > 0 is a step size parameter and c ∈ R is a constant ensuring
|
||||
*
|
||||
* ∫_Ω sigmoid(ψ - αG + c) dx = θ vol(Ω).
|
||||
*
|
||||
* end
|
||||
*/
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
// 0. Initialize MPI and HYPRE.
|
||||
Mpi::Init();
|
||||
int num_procs = Mpi::WorldSize();
|
||||
int myid = Mpi::WorldRank();
|
||||
Hypre::Init();
|
||||
|
||||
// 1. Parse command-line options.
|
||||
int ref_levels = 5;
|
||||
int order = 2;
|
||||
double alpha = 1.0;
|
||||
double epsilon = 0.01;
|
||||
double vol_fraction = 0.5;
|
||||
int max_it = 1e3;
|
||||
double itol = 1e-1;
|
||||
double ntol = 1e-4;
|
||||
double rho_min = 1e-6;
|
||||
double lambda = 1.0;
|
||||
double mu = 1.0;
|
||||
bool glvis_visualization = true;
|
||||
bool paraview_output = false;
|
||||
|
||||
OptionsParser args(argc, argv);
|
||||
args.AddOption(&ref_levels, "-r", "--refine",
|
||||
"Number of times to refine the mesh uniformly.");
|
||||
args.AddOption(&order, "-o", "--order",
|
||||
"Order (degree) of the finite elements.");
|
||||
args.AddOption(&alpha, "-alpha", "--alpha-step-length",
|
||||
"Step length for gradient descent.");
|
||||
args.AddOption(&epsilon, "-epsilon", "--epsilon-thickness",
|
||||
"Length scale for ρ.");
|
||||
args.AddOption(&max_it, "-mi", "--max-it",
|
||||
"Maximum number of gradient descent iterations.");
|
||||
args.AddOption(&ntol, "-ntol", "--rel-tol",
|
||||
"Normalized exit tolerance.");
|
||||
args.AddOption(&itol, "-itol", "--abs-tol",
|
||||
"Increment exit tolerance.");
|
||||
args.AddOption(&vol_fraction, "-vf", "--volume-fraction",
|
||||
"Volume fraction for the material density.");
|
||||
args.AddOption(&lambda, "-lambda", "--lambda",
|
||||
"Lamé constant λ.");
|
||||
args.AddOption(&mu, "-mu", "--mu",
|
||||
"Lamé constant μ.");
|
||||
args.AddOption(&rho_min, "-rmin", "--psi-min",
|
||||
"Minimum of density coefficient.");
|
||||
args.AddOption(&glvis_visualization, "-vis", "--visualization", "-no-vis",
|
||||
"--no-visualization",
|
||||
"Enable or disable GLVis visualization.");
|
||||
args.AddOption(¶view_output, "-pv", "--paraview", "-no-pv",
|
||||
"--no-paraview",
|
||||
"Enable or disable ParaView output.");
|
||||
args.Parse();
|
||||
if (!args.Good())
|
||||
{
|
||||
if (myid == 0)
|
||||
{
|
||||
args.PrintUsage(cout);
|
||||
}
|
||||
MPI_Finalize();
|
||||
return 1;
|
||||
}
|
||||
if (myid == 0)
|
||||
{
|
||||
mfem::out << num_procs << " number of process created.\n";
|
||||
args.PrintOptions(cout);
|
||||
}
|
||||
|
||||
Mesh mesh = Mesh::MakeCartesian2D(3, 1, mfem::Element::Type::QUADRILATERAL,
|
||||
true, 3.0, 1.0);
|
||||
int dim = mesh.Dimension();
|
||||
|
||||
// 2. Set BCs.
|
||||
for (int i = 0; i<mesh.GetNBE(); i++)
|
||||
{
|
||||
Element * be = mesh.GetBdrElement(i);
|
||||
Array<int> vertices;
|
||||
be->GetVertices(vertices);
|
||||
|
||||
double * coords1 = mesh.GetVertex(vertices[0]);
|
||||
double * coords2 = mesh.GetVertex(vertices[1]);
|
||||
|
||||
Vector center(2);
|
||||
center(0) = 0.5*(coords1[0] + coords2[0]);
|
||||
center(1) = 0.5*(coords1[1] + coords2[1]);
|
||||
|
||||
if (abs(center(0) - 0.0) < 1e-10)
|
||||
{
|
||||
// the left edge
|
||||
be->SetAttribute(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
// all other boundaries
|
||||
be->SetAttribute(2);
|
||||
}
|
||||
}
|
||||
mesh.SetAttributes();
|
||||
|
||||
// 3. Refine the mesh.
|
||||
for (int lev = 0; lev < ref_levels; lev++)
|
||||
{
|
||||
mesh.UniformRefinement();
|
||||
}
|
||||
|
||||
ParMesh pmesh(MPI_COMM_WORLD, mesh);
|
||||
mesh.Clear();
|
||||
|
||||
// 4. Define the necessary finite element spaces on the mesh.
|
||||
H1_FECollection state_fec(order, dim); // space for u
|
||||
H1_FECollection filter_fec(order, dim); // space for ρ̃
|
||||
L2_FECollection control_fec(order-1, dim,
|
||||
BasisType::GaussLobatto); // space for ψ
|
||||
ParFiniteElementSpace state_fes(&pmesh, &state_fec,dim);
|
||||
ParFiniteElementSpace filter_fes(&pmesh, &filter_fec);
|
||||
ParFiniteElementSpace control_fes(&pmesh, &control_fec);
|
||||
|
||||
HYPRE_BigInt state_size = state_fes.GlobalTrueVSize();
|
||||
HYPRE_BigInt control_size = control_fes.GlobalTrueVSize();
|
||||
HYPRE_BigInt filter_size = filter_fes.GlobalTrueVSize();
|
||||
if (myid==0)
|
||||
{
|
||||
cout << "Number of state unknowns: " << state_size << endl;
|
||||
cout << "Number of filter unknowns: " << filter_size << endl;
|
||||
cout << "Number of control unknowns: " << control_size << endl;
|
||||
}
|
||||
|
||||
// 5. Set the initial guess for ρ.
|
||||
ParGridFunction u(&state_fes);
|
||||
ParGridFunction psi(&control_fes);
|
||||
ParGridFunction psi_old(&control_fes);
|
||||
ParGridFunction rho_filter(&filter_fes);
|
||||
u = 0.0;
|
||||
rho_filter = vol_fraction;
|
||||
psi = inv_sigmoid(vol_fraction);
|
||||
psi_old = inv_sigmoid(vol_fraction);
|
||||
|
||||
// ρ = sigmoid(ψ)
|
||||
MappedGridFunctionCoefficient rho(&psi, sigmoid);
|
||||
// Interpolation of ρ = sigmoid(ψ) in control fes (for ParaView output)
|
||||
ParGridFunction rho_gf(&control_fes);
|
||||
// ρ - ρ_old = sigmoid(ψ) - sigmoid(ψ_old)
|
||||
DiffMappedGridFunctionCoefficient succ_diff_rho(&psi, &psi_old, sigmoid);
|
||||
|
||||
// 6. Set-up the physics solver.
|
||||
int maxat = pmesh.bdr_attributes.Max();
|
||||
Array<int> ess_bdr(maxat);
|
||||
ess_bdr = 0;
|
||||
ess_bdr[0] = 1;
|
||||
ConstantCoefficient one(1.0);
|
||||
ConstantCoefficient lambda_cf(lambda);
|
||||
ConstantCoefficient mu_cf(mu);
|
||||
LinearElasticitySolver * ElasticitySolver = new LinearElasticitySolver();
|
||||
ElasticitySolver->SetMesh(&pmesh);
|
||||
ElasticitySolver->SetOrder(state_fec.GetOrder());
|
||||
ElasticitySolver->SetupFEM();
|
||||
Vector center(2); center(0) = 2.9; center(1) = 0.5;
|
||||
Vector force(2); force(0) = 0.0; force(1) = -1.0;
|
||||
double r = 0.05;
|
||||
VolumeForceCoefficient vforce_cf(r,center,force);
|
||||
ElasticitySolver->SetRHSCoefficient(&vforce_cf);
|
||||
ElasticitySolver->SetEssentialBoundary(ess_bdr);
|
||||
|
||||
// 7. Set-up the filter solver.
|
||||
ConstantCoefficient eps2_cf(epsilon*epsilon);
|
||||
DiffusionSolver * FilterSolver = new DiffusionSolver();
|
||||
FilterSolver->SetMesh(&pmesh);
|
||||
FilterSolver->SetOrder(filter_fec.GetOrder());
|
||||
FilterSolver->SetDiffusionCoefficient(&eps2_cf);
|
||||
FilterSolver->SetMassCoefficient(&one);
|
||||
Array<int> ess_bdr_filter;
|
||||
if (pmesh.bdr_attributes.Size())
|
||||
{
|
||||
ess_bdr_filter.SetSize(pmesh.bdr_attributes.Max());
|
||||
ess_bdr_filter = 0;
|
||||
}
|
||||
FilterSolver->SetEssentialBoundary(ess_bdr_filter);
|
||||
FilterSolver->SetupFEM();
|
||||
|
||||
ParBilinearForm mass(&control_fes);
|
||||
mass.AddDomainIntegrator(new InverseIntegrator(new MassIntegrator(one)));
|
||||
mass.Assemble();
|
||||
HypreParMatrix M;
|
||||
Array<int> empty;
|
||||
mass.FormSystemMatrix(empty,M);
|
||||
|
||||
// 8. Define the Lagrange multiplier and gradient functions.
|
||||
ParGridFunction grad(&control_fes);
|
||||
ParGridFunction w_filter(&filter_fes);
|
||||
|
||||
// 9. Define some tools for later.
|
||||
ConstantCoefficient zero(0.0);
|
||||
ParGridFunction onegf(&control_fes);
|
||||
onegf = 1.0;
|
||||
ParGridFunction zerogf(&control_fes);
|
||||
zerogf = 0.0;
|
||||
ParLinearForm vol_form(&control_fes);
|
||||
vol_form.AddDomainIntegrator(new DomainLFIntegrator(one));
|
||||
vol_form.Assemble();
|
||||
double domain_volume = vol_form(onegf);
|
||||
const double target_volume = domain_volume * vol_fraction;
|
||||
|
||||
// 10. Connect to GLVis. Prepare for VisIt output.
|
||||
char vishost[] = "localhost";
|
||||
int visport = 19916;
|
||||
socketstream sout_r;
|
||||
if (glvis_visualization)
|
||||
{
|
||||
sout_r.open(vishost, visport);
|
||||
sout_r.precision(8);
|
||||
}
|
||||
|
||||
mfem::ParaViewDataCollection paraview_dc("ex37p", &pmesh);
|
||||
if (paraview_output)
|
||||
{
|
||||
rho_gf.ProjectCoefficient(rho);
|
||||
paraview_dc.SetPrefixPath("ParaView");
|
||||
paraview_dc.SetLevelsOfDetail(order);
|
||||
paraview_dc.SetDataFormat(VTKFormat::BINARY);
|
||||
paraview_dc.SetHighOrderOutput(true);
|
||||
paraview_dc.SetCycle(0);
|
||||
paraview_dc.SetTime(0.0);
|
||||
paraview_dc.RegisterField("displacement",&u);
|
||||
paraview_dc.RegisterField("density",&rho_gf);
|
||||
paraview_dc.RegisterField("filtered_density",&rho_filter);
|
||||
paraview_dc.Save();
|
||||
}
|
||||
|
||||
// 11. Iterate:
|
||||
for (int k = 1; k <= max_it; k++)
|
||||
{
|
||||
if (k > 1) { alpha *= ((double) k) / ((double) k-1); }
|
||||
|
||||
if (myid == 0)
|
||||
{
|
||||
cout << "\nStep = " << k << endl;
|
||||
}
|
||||
|
||||
// Step 1 - Filter solve
|
||||
// Solve (ϵ^2 ∇ ρ̃, ∇ v ) + (ρ̃,v) = (ρ,v)
|
||||
FilterSolver->SetRHSCoefficient(&rho);
|
||||
FilterSolver->Solve();
|
||||
rho_filter = *FilterSolver->GetFEMSolution();
|
||||
|
||||
// Step 2 - State solve
|
||||
// Solve (λ r(ρ̃) ∇⋅u, ∇⋅v) + (2 μ r(ρ̃) ε(u), ε(v)) = (f,v)
|
||||
SIMPInterpolationCoefficient SIMP_cf(&rho_filter,rho_min, 1.0);
|
||||
ProductCoefficient lambda_SIMP_cf(lambda_cf,SIMP_cf);
|
||||
ProductCoefficient mu_SIMP_cf(mu_cf,SIMP_cf);
|
||||
ElasticitySolver->SetLameCoefficients(&lambda_SIMP_cf,&mu_SIMP_cf);
|
||||
ElasticitySolver->Solve();
|
||||
u = *ElasticitySolver->GetFEMSolution();
|
||||
|
||||
// Step 3 - Adjoint filter solve
|
||||
// Solve (ϵ² ∇ w̃, ∇ v) + (w̃ ,v) = (-r'(ρ̃) ( λ |∇⋅u|² + 2 μ |ε(u)|²),v)
|
||||
StrainEnergyDensityCoefficient rhs_cf(&lambda_cf,&mu_cf,&u, &rho_filter,
|
||||
rho_min);
|
||||
FilterSolver->SetRHSCoefficient(&rhs_cf);
|
||||
FilterSolver->Solve();
|
||||
w_filter = *FilterSolver->GetFEMSolution();
|
||||
|
||||
// Step 4 - Compute gradient
|
||||
// Solve G = M⁻¹w̃
|
||||
GridFunctionCoefficient w_cf(&w_filter);
|
||||
ParLinearForm w_rhs(&control_fes);
|
||||
w_rhs.AddDomainIntegrator(new DomainLFIntegrator(w_cf));
|
||||
w_rhs.Assemble();
|
||||
M.Mult(w_rhs,grad);
|
||||
|
||||
// Step 5 - Update design variable ψ ← proj(ψ - αG)
|
||||
psi.Add(-alpha, grad);
|
||||
const double material_volume = proj(psi, target_volume);
|
||||
|
||||
// Compute ||ρ - ρ_old|| in control fes.
|
||||
double norm_increment = zerogf.ComputeL1Error(succ_diff_rho);
|
||||
double norm_reduced_gradient = norm_increment/alpha;
|
||||
psi_old = psi;
|
||||
|
||||
double compliance = (*(ElasticitySolver->GetLinearForm()))(u);
|
||||
MPI_Allreduce(MPI_IN_PLACE,&compliance,1,MPI_DOUBLE,MPI_SUM,MPI_COMM_WORLD);
|
||||
if (myid == 0)
|
||||
{
|
||||
mfem::out << "norm of the reduced gradient = " << norm_reduced_gradient << endl;
|
||||
mfem::out << "norm of the increment = " << norm_increment << endl;
|
||||
mfem::out << "compliance = " << compliance << endl;
|
||||
mfem::out << "volume fraction = " << material_volume / domain_volume << endl;
|
||||
}
|
||||
|
||||
if (glvis_visualization)
|
||||
{
|
||||
ParGridFunction r_gf(&filter_fes);
|
||||
r_gf.ProjectCoefficient(SIMP_cf);
|
||||
sout_r << "parallel " << num_procs << " " << myid << "\n";
|
||||
sout_r << "solution\n" << pmesh << r_gf
|
||||
<< "window_title 'Design density r(ρ̃)'" << flush;
|
||||
}
|
||||
|
||||
if (paraview_output)
|
||||
{
|
||||
rho_gf.ProjectCoefficient(rho);
|
||||
paraview_dc.SetCycle(k);
|
||||
paraview_dc.SetTime((double)k);
|
||||
paraview_dc.Save();
|
||||
}
|
||||
|
||||
if (norm_reduced_gradient < ntol && norm_increment < itol)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
delete ElasticitySolver;
|
||||
delete FilterSolver;
|
||||
|
||||
return 0;
|
||||
}
|
||||
+9
-2
@@ -23,10 +23,11 @@ MFEM_LIB_FILE = mfem_is_not_built
|
||||
|
||||
SEQ_EXAMPLES = ex0 ex1 ex2 ex3 ex4 ex5 ex6 ex7 ex8 ex9 ex10 ex14 ex15 ex16 \
|
||||
ex17 ex18 ex19 ex20 ex21 ex22 ex23 ex24 ex25 ex26 ex27 ex28 ex29 ex30 \
|
||||
ex31 ex33 ex34 ex36
|
||||
ex31 ex33 ex34 ex36 ex37
|
||||
PAR_EXAMPLES = ex0p ex1p ex2p ex3p ex4p ex5p ex6p ex7p ex8p ex9p ex10p ex11p \
|
||||
ex12p ex13p ex14p ex15p ex16p ex17p ex18p ex19p ex20p ex21p ex22p ex24p \
|
||||
ex25p ex26p ex27p ex28p ex29p ex30p ex31p ex32p ex33p ex34p ex35p ex36p
|
||||
ex25p ex26p ex27p ex28p ex29p ex30p ex31p ex32p ex33p ex34p ex35p ex36p \
|
||||
ex37p
|
||||
SEQ_DEVICE_EXAMPLES = ex1 ex3 ex4 ex5 ex6 ex9 ex22 ex24 ex25 ex26 ex34
|
||||
PAR_DEVICE_EXAMPLES = ex1p ex2p ex3p ex4p ex5p ex6p ex7p ex9p ex13p ex22p \
|
||||
ex24p ex25p ex26p ex34p ex35p
|
||||
@@ -92,10 +93,12 @@ $(SUBDIRS_TPRINT):
|
||||
# Additional dependencies
|
||||
ex18: $(SRC)ex18.hpp
|
||||
ex33: $(SRC)ex33.hpp
|
||||
ex37: $(SRC)ex37.hpp
|
||||
|
||||
ifeq ($(MFEM_USE_MPI),YES)
|
||||
ex18p: $(SRC)ex18.hpp
|
||||
ex33p: $(SRC)ex33.hpp
|
||||
ex37p: $(SRC)ex37.hpp
|
||||
endif
|
||||
|
||||
MFEM_TESTS = EXAMPLES
|
||||
@@ -139,6 +142,10 @@ ex27-test-seq: ex27
|
||||
@$(call mfem-test,$<,, Serial example,-dg)
|
||||
ex27p-test-par: ex27p
|
||||
@$(call mfem-test,$<, $(RUN_MPI), Parallel example,-dg)
|
||||
ex37-test-seq: ex37
|
||||
@$(call mfem-test,$<,, Serial example,-mi 3)
|
||||
ex37p-test-par: ex37p
|
||||
@$(call mfem-test,$<, $(RUN_MPI), Parallel example,-mi 3)
|
||||
# Testing: optional tests
|
||||
ifeq ($(MFEM_USE_STRUMPACK),YES)
|
||||
ex11p-test-strumpack: ex11p
|
||||
|
||||
@@ -24,13 +24,13 @@ if (MFEM_USE_MPI)
|
||||
ex10p.cpp
|
||||
)
|
||||
list(APPEND PETSC_RC_FILES
|
||||
rc_ex1p
|
||||
rc_ex2p
|
||||
rc_ex1p rc_ex1p_device rc_ex1p_deviceamg
|
||||
rc_ex2p rc_ex2p_bddc rc_ex2p_asm
|
||||
rc_ex3p rc_ex3p_bddc
|
||||
rc_ex4p rc_ex4p_bddc
|
||||
rc_ex5p_bddc rc_ex5p_fieldsplit
|
||||
rc_ex9p_expl rc_ex9p_impl
|
||||
rc_ex10p
|
||||
rc_ex9p_expl rc_ex9p_expl_device rc_ex9p_impl
|
||||
rc_ex10p rc_ex10p_mf rc_ex10p_mfop rc_ex10p_jfnk
|
||||
)
|
||||
endif()
|
||||
|
||||
@@ -39,7 +39,7 @@ if (MFEM_USE_SLEPC)
|
||||
ex11p.cpp
|
||||
)
|
||||
list(APPEND PETSC_RC_FILES
|
||||
rc_ex11p_lobpcg rc_ex11p_gd
|
||||
rc_ex11p_lobpcg rc_ex11p_lobpcg_device rc_ex11p_gd
|
||||
)
|
||||
endif()
|
||||
|
||||
@@ -74,7 +74,13 @@ add_mfem_examples(PETSC_EXAMPLES_SRCS ${PFX} copy_petsc_rc_files test_petsc)
|
||||
# Command line options for the tests.
|
||||
set(EX1_ARGS_W -m ../../data/amr-quad.mesh --usepetsc)
|
||||
set(EX1_ARGS_P -m ../../data/amr-quad.mesh --usepetsc --petscopts rc_ex1p)
|
||||
set(EX1_ARGS_CUDA -m ../../data/star.mesh --usepetsc --partial-assembly --device cuda --petscopts rc_ex1p_device)
|
||||
set(EX1_ARGS_CUDAAMG -m ../../data/star.mesh --usepetsc --device cuda --petscopts rc_ex1p_deviceamg)
|
||||
set(EX1_ARGS_HIP -m ../../data/star.mesh --usepetsc --partial-assembly --device hip --petscopts rc_ex1p_device)
|
||||
set(EX1_ARGS_HIPAMG -m ../../data/star.mesh --usepetsc --device hip --petscopts rc_ex1p_deviceamg)
|
||||
set(EX2_ARGS -m ../../data/beam-quad.mesh --usepetsc --petscopts rc_ex2p)
|
||||
set(EX2_ARGS_BDDC -m ../../data/beam-tri.mesh --usepetsc --nonoverlapping --petscopts rc_ex2p_bddc)
|
||||
set(EX2_ARGS_ASM -m ../../data/beam-quad.mesh --usepetsc --petscopts rc_ex2p_asm)
|
||||
set(EX3_ARGS -m ../../data/klein-bottle.mesh -o 2 -f 0.1 --usepetsc --petscopts rc_ex3p_bddc --nonoverlapping)
|
||||
set(EX4_ARGS -m ../../data/klein-bottle.mesh -o 2 --usepetsc --petscopts rc_ex4p_bddc --nonoverlapping)
|
||||
set(EX4_HYB_ARGS -m ../../data/klein-bottle.mesh -o 2 --usepetsc --petscopts rc_ex4p_bddc --nonoverlapping --hybridization)
|
||||
@@ -85,22 +91,46 @@ set(EX6_ARGS -m ../../data/amr-quad.mesh --usepetsc)
|
||||
set(EX6_NONOVL_ARGS -m ../../data/amr-quad.mesh --usepetsc --nonoverlapping)
|
||||
set(EX9_E_ARGS -m ../../data/periodic-hexagon.mesh --usepetsc --petscopts rc_ex9p_expl -dt 0.1)
|
||||
set(EX9_ES_ARGS -m ../../data/periodic-hexagon.mesh --usepetsc --petscopts rc_ex9p_expl --no-step)
|
||||
set(EX9_ES_ARGS_CUDA -m ../../data/periodic-hexagon.mesh --usepetsc --petscopts rc_ex9p_expl_device --no-step --partial-assembly --device cuda)
|
||||
set(EX9_ES_ARGS_HIP -m ../../data/periodic-hexagon.mesh --usepetsc --petscopts rc_ex9p_expl_device --no-step --partial-assembly --device hip)
|
||||
set(EX9_IS_ARGS -m ../../data/periodic-hexagon.mesh --usepetsc --petscopts rc_ex9p_impl --implicit -tf 0.5)
|
||||
set(EX10_ARGS -m ../../data/beam-quad.mesh --usepetsc --petscopts rc_ex10p -tf 30 -s 3 -rs 2 -dt 3)
|
||||
set(EX10_MF_ARGS -m ../../data/beam-quad.mesh --usepetsc --petscopts rc_ex10p_mf -tf 6 -s 3 -rs 0 -dt 3)
|
||||
set(EX10_MFOP_ARGS -m ../../data/beam-quad.mesh --usepetsc --petscopts rc_ex10p_mfop -tf 6 -s 3 -rs 0 -dt 3)
|
||||
set(EX10_JFNK_ARGS -m ../../data/beam-quad.mesh --usepetsc --petscopts rc_ex10p_jfnk --jfnk -tf 6 -s 3 -rs 0 -dt 3)
|
||||
if (MFEM_USE_SLEPC)
|
||||
set(EX11_ARGS_SINV -m ../../data/star.mesh --useslepc)
|
||||
set(EX11_ARGS_LOBPCG -m ../../data/star.mesh --useslepc --slepcopts rc_ex11p_lobpcg)
|
||||
set(EX11_ARGS_LOBPCG_CUDA -m ../../data/star.mesh --useslepc --slepcopts rc_ex11p_lobpcg_device --device cuda)
|
||||
set(EX11_ARGS_LOBPCG_HIP -m ../../data/star.mesh --useslepc --slepcopts rc_ex11p_lobpcg_device --device hip)
|
||||
set(EX11_ARGS_GD -m ../../data/star.mesh --useslepc --slepcopts rc_ex11p_gd)
|
||||
endif()
|
||||
|
||||
# Add the tests: one test per command-line-variable.
|
||||
if (MFEM_ENABLE_TESTING)
|
||||
set(TEST_OPTIONS_VARS
|
||||
EX1_ARGS_W EX1_ARGS_P EX2_ARGS EX3_ARGS EX4_ARGS EX4_HYB_ARGS
|
||||
EX5_BDDC_LB_ARGS EX5_BDDC_GB_ARGS EX5_FSPL_ARGS EX6_ARGS EX6_NONOVL_ARGS
|
||||
EX9_E_ARGS EX9_ES_ARGS EX9_IS_ARGS EX10_ARGS)
|
||||
EX1_ARGS_W EX1_ARGS_P EX2_ARGS EX2_ARGS_BDDC EX2_ARGS_ASM EX3_ARGS
|
||||
EX4_ARGS EX4_HYB_ARGS EX5_BDDC_LB_ARGS EX5_BDDC_GB_ARGS EX5_FSPL_ARGS
|
||||
EX6_ARGS EX6_NONOVL_ARGS EX9_E_ARGS EX9_ES_ARGS EX9_IS_ARGS EX10_ARGS
|
||||
EX10_MF_ARGS EX10_MFOP_ARGS EX10_JFNK_ARGS)
|
||||
if (MFEM_USE_SLEPC)
|
||||
list(APPEND TEST_OPTIONS_VARS EX11_ARGS_SINV EX11_ARGS_LOBPCG EX11_ARGS_GD)
|
||||
list(APPEND TEST_OPTIONS_VARS
|
||||
EX11_ARGS_SINV EX11_ARGS_LOBPCG EX11_ARGS_GD)
|
||||
endif()
|
||||
# CUDA/HIP tests
|
||||
if (MFEM_USE_CUDA)
|
||||
list(APPEND TEST_OPTIONS_VARS
|
||||
EX1_ARGS_CUDA EX1_ARGS_CUDAAMG EX9_ES_ARGS_CUDA)
|
||||
if (MFEM_USE_SLEPC)
|
||||
list(APPEND TEST_OPTIONS_VARS EX11_ARGS_LOBPCG_CUDA)
|
||||
endif()
|
||||
elseif (MFEM_USE_HIP)
|
||||
list(APPEND TEST_OPTIONS_VARS
|
||||
EX1_ARGS_HIP EX1_ARGS_HIPAMG EX9_ES_ARGS_HIP)
|
||||
if (MFEM_USE_SLEPC)
|
||||
# SLEPc does not support BVSVEC with HIP
|
||||
# list(APPEND TEST_OPTIONS_VARS EX11_ARGS_LOBPCG_HIP)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
foreach(TEST_OPTIONS_VAR ${TEST_OPTIONS_VARS})
|
||||
@@ -115,7 +145,7 @@ if (MFEM_ENABLE_TESTING)
|
||||
|
||||
# All PETSC tests are parallel.
|
||||
if (MFEM_USE_MPI)
|
||||
add_test(NAME ${TEST_NAME_FULL}_np=4
|
||||
add_test(NAME ${TEST_NAME_FULL}_np=${MFEM_MPI_NP}
|
||||
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP}
|
||||
${MPIEXEC_PREFLAGS}
|
||||
$<TARGET_FILE:${TEST_NAME}> ${TEST_OPTIONS}
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
// mpirun -np 4 ex1p -m ../../data/amr-quad.mesh --petscopts rc_ex1p
|
||||
//
|
||||
// Device sample runs:
|
||||
// mpirun -np 4 ex1p -pa -d cuda --petscopts rc_ex1p_cuda
|
||||
// mpirun -np 4 ex1p -pa -d cuda --petscopts rc_ex1p_device
|
||||
//
|
||||
// Description: This example code demonstrates the use of MFEM to define a
|
||||
// simple finite element discretization of the Laplace problem
|
||||
|
||||
+29
-9
@@ -66,7 +66,9 @@ include $(MFEM_TEST_MK)
|
||||
|
||||
# Testing: Parallel runs
|
||||
RUN_MPI = $(MFEM_MPIEXEC) $(MFEM_MPIEXEC_NP) $(MFEM_MPI_NP)
|
||||
TESTNAME = Parallel PETSc example
|
||||
TESTNAME = Parallel PETSc example
|
||||
TESTNAME_CUDA = Parallel CUDA PETSc example
|
||||
TESTNAME_HIP = Parallel HIP PETSc example
|
||||
%-test-par: %
|
||||
@$(call mfem-test,$<, $(RUN_MPI), $(TESTNAME))
|
||||
|
||||
@@ -74,8 +76,10 @@ TESTNAME = Parallel PETSc example
|
||||
# Testing PETSc execution options.
|
||||
EX1_ARGS_W := -m ../../data/amr-quad.mesh --usepetsc
|
||||
EX1_ARGS_P := -m ../../data/amr-quad.mesh --usepetsc --petscopts rc_ex1p
|
||||
EX1_ARGS_CUDA := -m ../../data/star.mesh --usepetsc --partial-assembly --device cuda --petscopts rc_ex1p_cuda
|
||||
EX1_ARGS_CUDAAMG := -m ../../data/star.mesh --usepetsc --device cuda --petscopts rc_ex1p_cudaamg
|
||||
EX1_ARGS_CUDA := -m ../../data/star.mesh --usepetsc --partial-assembly --device cuda --petscopts rc_ex1p_device
|
||||
EX1_ARGS_CUDAAMG := -m ../../data/star.mesh --usepetsc --device cuda --petscopts rc_ex1p_deviceamg
|
||||
EX1_ARGS_HIP := -m ../../data/star.mesh --usepetsc --partial-assembly --device hip --petscopts rc_ex1p_device
|
||||
EX1_ARGS_HIPAMG := -m ../../data/star.mesh --usepetsc --device hip --petscopts rc_ex1p_deviceamg
|
||||
EX2_ARGS := -m ../../data/beam-quad.mesh --usepetsc --petscopts rc_ex2p
|
||||
EX2_ARGS_BDDC := -m ../../data/beam-tri.mesh --usepetsc --nonoverlapping --petscopts rc_ex2p_bddc
|
||||
EX2_ARGS_ASM := -m ../../data/beam-quad.mesh --usepetsc --petscopts rc_ex2p_asm
|
||||
@@ -89,7 +93,8 @@ EX6_ARGS := -m ../../data/amr-quad.mesh --usepetsc
|
||||
EX6_NONOVL_ARGS := -m ../../data/amr-quad.mesh --usepetsc --nonoverlapping
|
||||
EX9_E_ARGS := -m ../../data/periodic-hexagon.mesh --usepetsc --petscopts rc_ex9p_expl -dt 0.1
|
||||
EX9_ES_ARGS := -m ../../data/periodic-hexagon.mesh --usepetsc --petscopts rc_ex9p_expl --no-step
|
||||
EX9_ES_ARGS_CUDA := -m ../../data/periodic-hexagon.mesh --usepetsc --petscopts rc_ex9p_expl_cuda --no-step --partial-assembly --device cuda
|
||||
EX9_ES_ARGS_CUDA := -m ../../data/periodic-hexagon.mesh --usepetsc --petscopts rc_ex9p_expl_device --no-step --partial-assembly --device cuda
|
||||
EX9_ES_ARGS_HIP := -m ../../data/periodic-hexagon.mesh --usepetsc --petscopts rc_ex9p_expl_device --no-step --partial-assembly --device hip
|
||||
EX9_IS_ARGS := -m ../../data/periodic-hexagon.mesh --usepetsc --petscopts rc_ex9p_impl --implicit -tf 0.5
|
||||
EX10_ARGS := -m ../../data/beam-quad.mesh --usepetsc --petscopts rc_ex10p -tf 30 -s 3 -rs 2 -dt 3
|
||||
EX10_MF_ARGS := -m ../../data/beam-quad.mesh --usepetsc --petscopts rc_ex10p_mf -tf 6 -s 3 -rs 0 -dt 3
|
||||
@@ -97,15 +102,20 @@ EX10_MFOP_ARGS := -m ../../data/beam-quad.mesh --usepetsc --petscopts rc_
|
||||
EX10_JFNK_ARGS := -m ../../data/beam-quad.mesh --usepetsc --petscopts rc_ex10p_jfnk --jfnk -tf 6 -s 3 -rs 0 -dt 3
|
||||
EX11_ARGS_SINV := -m ../../data/star.mesh --useslepc
|
||||
EX11_ARGS_LOBPCG := -m ../../data/star.mesh --useslepc --slepcopts rc_ex11p_lobpcg
|
||||
EX11_ARGS_LOBPCG_CUDA := -m ../../data/star.mesh --useslepc --slepcopts rc_ex11p_lobpcg_cuda --device cuda
|
||||
EX11_ARGS_LOBPCG_CUDA := -m ../../data/star.mesh --useslepc --slepcopts rc_ex11p_lobpcg_device --device cuda
|
||||
EX11_ARGS_LOBPCG_HIP := -m ../../data/star.mesh --useslepc --slepcopts rc_ex11p_lobpcg_device --device hip
|
||||
EX11_ARGS_GD := -m ../../data/star.mesh --useslepc --slepcopts rc_ex11p_gd
|
||||
|
||||
ex1p-test-par: ex1p
|
||||
@$(call mfem-test,$<, $(RUN_MPI), $(TESTNAME),$(EX1_ARGS_W))
|
||||
@$(call mfem-test,$<, $(RUN_MPI), $(TESTNAME),$(EX1_ARGS_P))
|
||||
ifeq ($(MFEM_USE_CUDA),YES)
|
||||
@$(call mfem-test,$<, $(RUN_MPI), $(TESTNAME),$(EX1_ARGS_CUDA))
|
||||
@$(call mfem-test,$<, $(RUN_MPI), $(TESTNAME),$(EX1_ARGS_CUDAAMG))
|
||||
@$(call mfem-test,$<, $(RUN_MPI), $(TESTNAME_CUDA),$(EX1_ARGS_CUDA))
|
||||
@$(call mfem-test,$<, $(RUN_MPI), $(TESTNAME_CUDA),$(EX1_ARGS_CUDAAMG))
|
||||
endif
|
||||
ifeq ($(MFEM_USE_HIP),YES)
|
||||
@$(call mfem-test,$<, $(RUN_MPI), $(TESTNAME_HIP),$(EX1_ARGS_HIP))
|
||||
@$(call mfem-test,$<, $(RUN_MPI), $(TESTNAME_HIP),$(EX1_ARGS_HIPAMG))
|
||||
endif
|
||||
ex2p-test-par: ex2p
|
||||
@$(call mfem-test,$<, $(RUN_MPI), $(TESTNAME),$(EX2_ARGS))
|
||||
@@ -128,7 +138,10 @@ ex9p-test-par: ex9p
|
||||
@$(call mfem-test,$<, $(RUN_MPI), $(TESTNAME),$(EX9_ES_ARGS))
|
||||
@$(call mfem-test,$<, $(RUN_MPI), $(TESTNAME),$(EX9_IS_ARGS))
|
||||
ifeq ($(MFEM_USE_CUDA),YES)
|
||||
@$(call mfem-test,$<, $(RUN_MPI), $(TESTNAME),$(EX9_ES_ARGS_CUDA))
|
||||
@$(call mfem-test,$<, $(RUN_MPI), $(TESTNAME_CUDA),$(EX9_ES_ARGS_CUDA))
|
||||
endif
|
||||
ifeq ($(MFEM_USE_HIP),YES)
|
||||
@$(call mfem-test,$<, $(RUN_MPI), $(TESTNAME_HIP),$(EX9_ES_ARGS_HIP))
|
||||
endif
|
||||
ex10p-test-par: ex10p
|
||||
@$(call mfem-test,$<, $(RUN_MPI), $(TESTNAME),$(EX10_ARGS))
|
||||
@@ -140,8 +153,12 @@ ex11p-test-par: ex11p
|
||||
@$(call mfem-test,$<, $(RUN_MPI), $(TESTNAME),$(EX11_ARGS_SINV))
|
||||
@$(call mfem-test,$<, $(RUN_MPI), $(TESTNAME),$(EX11_ARGS_LOBPCG))
|
||||
ifeq ($(MFEM_USE_CUDA),YES)
|
||||
@$(call mfem-test,$<, $(RUN_MPI), $(TESTNAME),$(EX11_ARGS_LOBPCG_CUDA))
|
||||
@$(call mfem-test,$<, $(RUN_MPI), $(TESTNAME_CUDA),$(EX11_ARGS_LOBPCG_CUDA))
|
||||
endif
|
||||
# SLEPc does not support BVSVEC with HIP
|
||||
#ifeq ($(MFEM_USE_HIP),YES)
|
||||
# @$(call mfem-test,$<, $(RUN_MPI), $(TESTNAME_HIP),$(EX11_ARGS_LOBPCG_HIP))
|
||||
#endif
|
||||
@$(call mfem-test,$<, $(RUN_MPI), $(TESTNAME),$(EX11_ARGS_GD))
|
||||
endif
|
||||
|
||||
@@ -156,6 +173,9 @@ clean: clean-build clean-exec
|
||||
clean-build:
|
||||
rm -f *.o *~ $(SEQ_EXAMPLES) $(PAR_EXAMPLES)
|
||||
rm -rf *.dSYM *.TVD.*breakpoints
|
||||
ifneq ($(SRC),)
|
||||
rm -f $(RC_FILES)
|
||||
endif
|
||||
|
||||
clean-exec:
|
||||
@rm -rf mesh.* sol.* sol_p.* sol_u.* Example5*
|
||||
|
||||
@@ -23,6 +23,7 @@ set(SRCS
|
||||
integ/bilininteg_diffusion_mf.cpp
|
||||
integ/bilininteg_diffusion_pa.cpp
|
||||
integ/bilininteg_diffusion_ea.cpp
|
||||
integ/bilininteg_diffusion_patch.cpp
|
||||
integ/bilininteg_divdiv_pa.cpp
|
||||
integ/bilininteg_gradient_pa.cpp
|
||||
integ/bilininteg_interp_pa.cpp
|
||||
@@ -87,6 +88,7 @@ set(SRCS
|
||||
ceed/solvers/algebraic.cpp
|
||||
ceed/solvers/full-assembly.cpp
|
||||
ceed/solvers/solvers-atpmg.cpp
|
||||
kdtree.cpp
|
||||
linearform.cpp
|
||||
linearform_ext.cpp
|
||||
lininteg.cpp
|
||||
@@ -198,6 +200,7 @@ set(HDRS
|
||||
ceed/solvers/algebraic.hpp
|
||||
ceed/solvers/full-assembly.hpp
|
||||
ceed/solvers/solvers-atpmg.hpp
|
||||
kdtree.hpp
|
||||
linearform.hpp
|
||||
linearform_ext.hpp
|
||||
lininteg.hpp
|
||||
|
||||
+48
-2
@@ -13,6 +13,7 @@
|
||||
|
||||
#include "fem.hpp"
|
||||
#include "../general/device.hpp"
|
||||
#include "../mesh/nurbs.hpp"
|
||||
#include <cmath>
|
||||
|
||||
namespace mfem
|
||||
@@ -421,11 +422,17 @@ void BilinearForm::Assemble(int skip_zeros)
|
||||
"invalid element marker for domain integrator #"
|
||||
<< k << ", counting from zero");
|
||||
}
|
||||
|
||||
if (domain_integs[k]->Patchwise())
|
||||
{
|
||||
MFEM_VERIFY(fes->GetNURBSext(), "Patchwise integration requires a "
|
||||
<< "NURBS FE space");
|
||||
}
|
||||
}
|
||||
|
||||
// Element-wise integration
|
||||
for (int i = 0; i < fes -> GetNE(); i++)
|
||||
{
|
||||
int elem_attr = fes->GetMesh()->GetAttribute(i);
|
||||
doftrans = fes->GetElementVDofs(i, vdofs);
|
||||
if (element_matrices)
|
||||
{
|
||||
@@ -433,11 +440,13 @@ void BilinearForm::Assemble(int skip_zeros)
|
||||
}
|
||||
else
|
||||
{
|
||||
const int elem_attr = fes->GetMesh()->GetAttribute(i);
|
||||
elmat.SetSize(0);
|
||||
for (int k = 0; k < domain_integs.Size(); k++)
|
||||
{
|
||||
if ( domain_integs_marker[k] == NULL ||
|
||||
if ((domain_integs_marker[k] == NULL ||
|
||||
(*(domain_integs_marker[k]))[elem_attr-1] == 1)
|
||||
&& !domain_integs[k]->Patchwise())
|
||||
{
|
||||
const FiniteElement &fe = *fes->GetFE(i);
|
||||
eltrans = fes->GetElementTransformation(i);
|
||||
@@ -479,6 +488,43 @@ void BilinearForm::Assemble(int skip_zeros)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Patch-wise integration
|
||||
if (fes->GetNURBSext())
|
||||
{
|
||||
for (int p=0; p<mesh->NURBSext->GetNP(); ++p)
|
||||
{
|
||||
bool vdofsSet = false;
|
||||
for (int k = 0; k < domain_integs.Size(); k++)
|
||||
{
|
||||
if (domain_integs[k]->Patchwise())
|
||||
{
|
||||
if (!vdofsSet)
|
||||
{
|
||||
fes->GetPatchVDofs(p, vdofs);
|
||||
vdofsSet = true;
|
||||
}
|
||||
|
||||
SparseMatrix* spmat = nullptr;
|
||||
domain_integs[k]->AssemblePatchMatrix(p, *fes, spmat);
|
||||
Array<int> cols;
|
||||
Vector srow;
|
||||
|
||||
for (int r=0; r<spmat->Height(); ++r)
|
||||
{
|
||||
spmat->GetRow(r, cols, srow);
|
||||
for (int i=0; i<cols.Size(); ++i)
|
||||
{
|
||||
cols[i] = vdofs[cols[i]];
|
||||
}
|
||||
mat->AddRow(vdofs[r], cols, srow);
|
||||
}
|
||||
|
||||
delete spmat;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (boundary_integs.Size())
|
||||
|
||||
@@ -254,6 +254,12 @@ public:
|
||||
/// Access all the integrators added with AddDomainIntegrator().
|
||||
Array<BilinearFormIntegrator*> *GetDBFI() { return &domain_integs; }
|
||||
|
||||
/// @brief Access all boundary markers added with AddDomainIntegrator().
|
||||
///
|
||||
/// If no marker was specified when the integrator was added, the
|
||||
/// corresponding pointer (to Array<int>) will be NULL. */
|
||||
Array<Array<int>*> *GetDBFI_Marker() { return &domain_integs_marker; }
|
||||
|
||||
/// Access all the integrators added with AddBoundaryIntegrator().
|
||||
Array<BilinearFormIntegrator*> *GetBBFI() { return &boundary_integs; }
|
||||
/** @brief Access all boundary markers added with AddBoundaryIntegrator().
|
||||
@@ -452,7 +458,7 @@ public:
|
||||
practice it is convenient to have it in transposed form for
|
||||
construction of RAP operators in matrix-free methods. */
|
||||
virtual const Operator *GetOutputRestrictionTranspose() const
|
||||
{ return GetOutputProlongation(); }
|
||||
{ return fes->GetRestrictionTransposeOperator(); }
|
||||
/// Get the output finite element space restriction matrix
|
||||
virtual const Operator *GetOutputRestriction() const
|
||||
{ return GetRestriction(); }
|
||||
|
||||
+166
-13
@@ -264,6 +264,14 @@ void PABilinearFormExtension::SetupRestrictionOperators(const L2FaceValues m)
|
||||
localX.SetSize(elem_restrict->Height(), Device::GetDeviceMemoryType());
|
||||
localY.SetSize(elem_restrict->Height(), Device::GetDeviceMemoryType());
|
||||
localY.UseDevice(true); // ensure 'localY = 0.0' is done on device
|
||||
|
||||
// Gather the attributes on the host from all the elements
|
||||
const Mesh &mesh = *trial_fes->GetMesh();
|
||||
elem_attributes.SetSize(mesh.GetNE());
|
||||
for (int i = 0; i < mesh.GetNE(); ++i)
|
||||
{
|
||||
elem_attributes[i] = mesh.GetAttribute(i);
|
||||
}
|
||||
}
|
||||
|
||||
// Construct face restriction operators only if the bilinear form has
|
||||
@@ -289,6 +297,46 @@ void PABilinearFormExtension::SetupRestrictionOperators(const L2FaceValues m)
|
||||
bdr_face_X.SetSize(bdr_face_restrict_lex->Height(), Device::GetMemoryType());
|
||||
bdr_face_Y.SetSize(bdr_face_restrict_lex->Height(), Device::GetMemoryType());
|
||||
bdr_face_Y.UseDevice(true); // ensure 'faceBoundY = 0.0' is done on device
|
||||
|
||||
const Mesh &mesh = *trial_fes->GetMesh();
|
||||
// See LinearFormExtension::Update for explanation of f_to_be logic.
|
||||
std::unordered_map<int,int> f_to_be;
|
||||
for (int i = 0; i < mesh.GetNBE(); ++i)
|
||||
{
|
||||
const int f = mesh.GetBdrElementEdgeIndex(i);
|
||||
f_to_be[f] = i;
|
||||
}
|
||||
const int nf_bdr = trial_fes->GetNFbyType(FaceType::Boundary);
|
||||
bdr_attributes.SetSize(nf_bdr);
|
||||
int f_ind = 0;
|
||||
int missing_bdr_elems = 0;
|
||||
for (int f = 0; f < mesh.GetNumFaces(); ++f)
|
||||
{
|
||||
if (!mesh.GetFaceInformation(f).IsOfFaceType(FaceType::Boundary))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
int attribute = 1; // default value
|
||||
if (f_to_be.find(f) != f_to_be.end())
|
||||
{
|
||||
const int be = f_to_be[f];
|
||||
attribute = mesh.GetBdrAttribute(be);
|
||||
}
|
||||
else
|
||||
{
|
||||
// If a boundary face does not correspond to the a boundary element,
|
||||
// we assign it the default attribute of 1. We also generate a
|
||||
// warning at runtime with the number of such missing elements.
|
||||
++missing_bdr_elems;
|
||||
}
|
||||
bdr_attributes[f_ind] = attribute;
|
||||
++f_ind;
|
||||
}
|
||||
if (missing_bdr_elems)
|
||||
{
|
||||
MFEM_WARNING("Missing " << missing_bdr_elems << " boundary elements "
|
||||
"for boundary faces.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -299,7 +347,16 @@ void PABilinearFormExtension::Assemble()
|
||||
Array<BilinearFormIntegrator*> &integrators = *a->GetDBFI();
|
||||
for (BilinearFormIntegrator *integ : integrators)
|
||||
{
|
||||
integ->AssemblePA(*a->FESpace());
|
||||
if (integ->Patchwise())
|
||||
{
|
||||
MFEM_VERIFY(a->FESpace()->GetNURBSext(),
|
||||
"Patchwise integration requires a NURBS FE space");
|
||||
integ->AssembleNURBSPA(*a->FESpace());
|
||||
}
|
||||
else
|
||||
{
|
||||
integ->AssemblePA(*a->FESpace());
|
||||
}
|
||||
}
|
||||
|
||||
Array<BilinearFormIntegrator*> &bdr_integrators = *a->GetBBFI();
|
||||
@@ -410,24 +467,52 @@ void PABilinearFormExtension::Mult(const Vector &x, Vector &y) const
|
||||
Array<BilinearFormIntegrator*> &integrators = *a->GetDBFI();
|
||||
|
||||
const int iSz = integrators.Size();
|
||||
if (DeviceCanUseCeed() || !elem_restrict)
|
||||
|
||||
bool allPatchwise = true;
|
||||
bool somePatchwise = false;
|
||||
|
||||
for (int i = 0; i < iSz; ++i)
|
||||
{
|
||||
if (integrators[i]->Patchwise())
|
||||
{
|
||||
somePatchwise = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
allPatchwise = false;
|
||||
}
|
||||
}
|
||||
|
||||
MFEM_VERIFY(!(somePatchwise && !allPatchwise),
|
||||
"All or none of the integrators should be patchwise");
|
||||
|
||||
if (DeviceCanUseCeed() || !elem_restrict || allPatchwise)
|
||||
{
|
||||
y.UseDevice(true); // typically this is a large vector, so store on device
|
||||
y = 0.0;
|
||||
for (int i = 0; i < iSz; ++i)
|
||||
{
|
||||
integrators[i]->AddMultPA(x, y);
|
||||
if (integrators[i]->Patchwise())
|
||||
{
|
||||
integrators[i]->AddMultNURBSPA(x, y);
|
||||
}
|
||||
else
|
||||
{
|
||||
integrators[i]->AddMultPA(x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (iSz)
|
||||
{
|
||||
Array<Array<int>*> &elem_markers = *a->GetDBFI_Marker();
|
||||
elem_restrict->Mult(x, localX);
|
||||
localY = 0.0;
|
||||
for (int i = 0; i < iSz; ++i)
|
||||
{
|
||||
integrators[i]->AddMultPA(localX, localY);
|
||||
AddMultWithMarkers(*integrators[i], localX, elem_markers[i], elem_attributes,
|
||||
false, localY);
|
||||
}
|
||||
elem_restrict->MultTranspose(localY, y);
|
||||
}
|
||||
@@ -460,17 +545,21 @@ void PABilinearFormExtension::Mult(const Vector &x, Vector &y) const
|
||||
const bool has_bdr_integs = (n_bdr_face_integs > 0 || n_bdr_integs > 0);
|
||||
if (bdr_face_restrict_lex && has_bdr_integs)
|
||||
{
|
||||
Array<Array<int>*> &bdr_markers = *a->GetBBFI_Marker();
|
||||
Array<Array<int>*> &bdr_face_markers = *a->GetBFBFI_Marker();
|
||||
bdr_face_restrict_lex->Mult(x, bdr_face_X);
|
||||
if (bdr_face_X.Size()>0)
|
||||
{
|
||||
bdr_face_Y = 0.0;
|
||||
for (int i = 0; i < n_bdr_integs; ++i)
|
||||
{
|
||||
bdr_integs[i]->AddMultPA(bdr_face_X, bdr_face_Y);
|
||||
AddMultWithMarkers(*bdr_integs[i], bdr_face_X, bdr_markers[i], bdr_attributes,
|
||||
false, bdr_face_Y);
|
||||
}
|
||||
for (int i = 0; i < n_bdr_face_integs; ++i)
|
||||
{
|
||||
bdr_face_integs[i]->AddMultPA(bdr_face_X, bdr_face_Y);
|
||||
AddMultWithMarkers(*bdr_face_integs[i], bdr_face_X, bdr_face_markers[i],
|
||||
bdr_attributes, false, bdr_face_Y);
|
||||
}
|
||||
bdr_face_restrict_lex->AddMultTransposeInPlace(bdr_face_Y, y);
|
||||
}
|
||||
@@ -483,11 +572,13 @@ void PABilinearFormExtension::MultTranspose(const Vector &x, Vector &y) const
|
||||
const int iSz = integrators.Size();
|
||||
if (elem_restrict)
|
||||
{
|
||||
Array<Array<int>*> &elem_markers = *a->GetDBFI_Marker();
|
||||
elem_restrict->Mult(x, localX);
|
||||
localY = 0.0;
|
||||
for (int i = 0; i < iSz; ++i)
|
||||
{
|
||||
integrators[i]->AddMultTransposePA(localX, localY);
|
||||
AddMultWithMarkers(*integrators[i], localX, elem_markers[i], elem_attributes,
|
||||
true, localY);
|
||||
}
|
||||
elem_restrict->MultTranspose(localY, y);
|
||||
}
|
||||
@@ -517,23 +608,85 @@ void PABilinearFormExtension::MultTranspose(const Vector &x, Vector &y) const
|
||||
}
|
||||
}
|
||||
|
||||
Array<BilinearFormIntegrator*> &bdrFaceIntegrators = *a->GetBFBFI();
|
||||
const int bFISz = bdrFaceIntegrators.Size();
|
||||
if (bdr_face_restrict_lex && bFISz>0)
|
||||
Array<BilinearFormIntegrator*> &bdr_integs = *a->GetBBFI();
|
||||
Array<BilinearFormIntegrator*> &bdr_face_integs = *a->GetBFBFI();
|
||||
const int n_bdr_integs = bdr_integs.Size();
|
||||
const int n_bdr_face_integs = bdr_face_integs.Size();
|
||||
const bool has_bdr_integs = (n_bdr_face_integs > 0 || n_bdr_integs > 0);
|
||||
if (bdr_face_restrict_lex && has_bdr_integs)
|
||||
{
|
||||
Array<Array<int>*> &bdr_markers = *a->GetBBFI_Marker();
|
||||
Array<Array<int>*> &bdr_face_markers = *a->GetBFBFI_Marker();
|
||||
|
||||
bdr_face_restrict_lex->Mult(x, bdr_face_X);
|
||||
if (bdr_face_X.Size()>0)
|
||||
if (bdr_face_X.Size() > 0)
|
||||
{
|
||||
bdr_face_Y = 0.0;
|
||||
for (int i = 0; i < bFISz; ++i)
|
||||
for (int i = 0; i < n_bdr_integs; ++i)
|
||||
{
|
||||
bdrFaceIntegrators[i]->AddMultTransposePA(bdr_face_X, bdr_face_Y);
|
||||
AddMultWithMarkers(*bdr_integs[i], bdr_face_X, bdr_markers[i], bdr_attributes,
|
||||
true, bdr_face_Y);
|
||||
}
|
||||
for (int i = 0; i < n_bdr_face_integs; ++i)
|
||||
{
|
||||
AddMultWithMarkers(*bdr_face_integs[i], bdr_face_X, bdr_face_markers[i],
|
||||
bdr_attributes, true, bdr_face_Y);
|
||||
}
|
||||
bdr_face_restrict_lex->AddMultTransposeInPlace(bdr_face_Y, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Compute kernels for PABilinearFormExtension::AddMultWithMarkers.
|
||||
// Cannot be in member function with non-public visibility.
|
||||
static void AddWithMarkers_(
|
||||
const int ne,
|
||||
const int nd,
|
||||
const Vector &x,
|
||||
const Array<int> &markers,
|
||||
const Array<int> &attributes,
|
||||
Vector &y)
|
||||
{
|
||||
const auto d_x = Reshape(x.Read(), nd, ne);
|
||||
const auto d_m = Reshape(markers.Read(), markers.Size());
|
||||
const auto d_attr = Reshape(attributes.Read(), ne);
|
||||
auto d_y = Reshape(y.ReadWrite(), nd, ne);
|
||||
mfem::forall(ne, [=] MFEM_HOST_DEVICE (int e)
|
||||
{
|
||||
const int attr = d_attr[e];
|
||||
if (d_m[attr - 1] == 0) { return; }
|
||||
for (int i = 0; i < nd; ++i)
|
||||
{
|
||||
d_y(i, e) += d_x(i, e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void PABilinearFormExtension::AddMultWithMarkers(
|
||||
const BilinearFormIntegrator &integ,
|
||||
const Vector &x,
|
||||
const Array<int> *markers,
|
||||
const Array<int> &attributes,
|
||||
const bool transpose,
|
||||
Vector &y) const
|
||||
{
|
||||
if (markers)
|
||||
{
|
||||
tmp_evec.SetSize(y.Size());
|
||||
tmp_evec = 0.0;
|
||||
if (transpose) { integ.AddMultTransposePA(x, tmp_evec); }
|
||||
else { integ.AddMultPA(x, tmp_evec); }
|
||||
const int ne = attributes.Size();
|
||||
const int nd = x.Size() / ne;
|
||||
AddWithMarkers_(ne, nd, tmp_evec, *markers, attributes, y);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (transpose) { integ.AddMultTransposePA(x, y); }
|
||||
else { integ.AddMultPA(x, y); }
|
||||
}
|
||||
}
|
||||
|
||||
// Data and methods for element-assembled bilinear forms
|
||||
EABilinearFormExtension::EABilinearFormExtension(BilinearForm *form)
|
||||
: PABilinearFormExtension(form),
|
||||
|
||||
@@ -68,6 +68,9 @@ class PABilinearFormExtension : public BilinearFormExtension
|
||||
{
|
||||
protected:
|
||||
const FiniteElementSpace *trial_fes, *test_fes; // Not owned
|
||||
/// Attributes of all mesh elements.
|
||||
Array<int> elem_attributes, bdr_attributes;
|
||||
mutable Vector tmp_evec; // Work array
|
||||
mutable Vector localX, localY;
|
||||
mutable Vector int_face_X, int_face_Y;
|
||||
mutable Vector bdr_face_X, bdr_face_Y;
|
||||
@@ -91,6 +94,25 @@ public:
|
||||
|
||||
protected:
|
||||
void SetupRestrictionOperators(const L2FaceValues m);
|
||||
|
||||
/// @brief Accumulate the action (or transpose) of the integrator on @a x
|
||||
/// into @a y, taking into account the (possibly null) @a markers array.
|
||||
///
|
||||
/// If @a markers is non-null, then only those elements or boundary elements
|
||||
/// whose attribute is marked in the markers array will be added to @a y.
|
||||
///
|
||||
/// @param integ The integrator (domain, boundary, or boundary face).
|
||||
/// @param x Input E-vector.
|
||||
/// @param markers Marked attributes (possibly null, meaning all attributes).
|
||||
/// @param attributes Array of element or boundary element attributes.
|
||||
/// @param transpose Compute the action or transpose of the integrator .
|
||||
/// @param y Output E-vector
|
||||
void AddMultWithMarkers(const BilinearFormIntegrator &integ,
|
||||
const Vector &x,
|
||||
const Array<int> *markers,
|
||||
const Array<int> &attributes,
|
||||
const bool transpose,
|
||||
Vector &y) const;
|
||||
};
|
||||
|
||||
/// Data and methods for element-assembled bilinear forms
|
||||
|
||||
+47
-10
@@ -26,6 +26,12 @@ void BilinearFormIntegrator::AssemblePA(const FiniteElementSpace&)
|
||||
" is not implemented for this class.");
|
||||
}
|
||||
|
||||
void BilinearFormIntegrator::AssembleNURBSPA(const FiniteElementSpace&)
|
||||
{
|
||||
mfem_error ("BilinearFormIntegrator::AssembleNURBSPA(fes)\n"
|
||||
" is not implemented for this class.");
|
||||
}
|
||||
|
||||
void BilinearFormIntegrator::AssemblePA(const FiniteElementSpace&,
|
||||
const FiniteElementSpace&)
|
||||
{
|
||||
@@ -92,7 +98,13 @@ void BilinearFormIntegrator::AssembleDiagonalPA_ADAt(const Vector &, Vector &)
|
||||
|
||||
void BilinearFormIntegrator::AddMultPA(const Vector &, Vector &) const
|
||||
{
|
||||
MFEM_ABORT("BilinearFormIntegrator::MultAssembled(...)\n"
|
||||
MFEM_ABORT("BilinearFormIntegrator:AddMultPA:(...)\n"
|
||||
" is not implemented for this class.");
|
||||
}
|
||||
|
||||
void BilinearFormIntegrator::AddMultNURBSPA(const Vector &, Vector &) const
|
||||
{
|
||||
MFEM_ABORT("BilinearFormIntegrator::AddMultNURBSPA(...)\n"
|
||||
" is not implemented for this class.");
|
||||
}
|
||||
|
||||
@@ -126,23 +138,30 @@ void BilinearFormIntegrator::AssembleDiagonalMF(Vector &)
|
||||
" is not implemented for this class.");
|
||||
}
|
||||
|
||||
void BilinearFormIntegrator::AssembleElementMatrix (
|
||||
void BilinearFormIntegrator::AssembleElementMatrix(
|
||||
const FiniteElement &el, ElementTransformation &Trans,
|
||||
DenseMatrix &elmat )
|
||||
DenseMatrix &elmat)
|
||||
{
|
||||
MFEM_ABORT("BilinearFormIntegrator::AssembleElementMatrix(...)\n"
|
||||
" is not implemented for this class.");
|
||||
}
|
||||
|
||||
void BilinearFormIntegrator::AssembleElementMatrix2 (
|
||||
void BilinearFormIntegrator::AssembleElementMatrix2(
|
||||
const FiniteElement &el1, const FiniteElement &el2,
|
||||
ElementTransformation &Trans, DenseMatrix &elmat )
|
||||
ElementTransformation &Trans, DenseMatrix &elmat)
|
||||
{
|
||||
MFEM_ABORT("BilinearFormIntegrator::AssembleElementMatrix2(...)\n"
|
||||
" is not implemented for this class.");
|
||||
}
|
||||
|
||||
void BilinearFormIntegrator::AssembleFaceMatrix (
|
||||
void BilinearFormIntegrator::AssemblePatchMatrix(
|
||||
const int patch, const FiniteElementSpace &fes, SparseMatrix*& smat)
|
||||
{
|
||||
mfem_error ("BilinearFormIntegrator::AssemblePatchMatrix(...)\n"
|
||||
" is not implemented for this class.");
|
||||
}
|
||||
|
||||
void BilinearFormIntegrator::AssembleFaceMatrix(
|
||||
const FiniteElement &el1, const FiniteElement &el2,
|
||||
FaceElementTransformations &Trans, DenseMatrix &elmat)
|
||||
{
|
||||
@@ -848,6 +867,19 @@ void DiffusionIntegrator::AssembleElementMatrix
|
||||
|
||||
const IntegrationRule *ir = IntRule ? IntRule : &GetRule(el, el);
|
||||
|
||||
const NURBSFiniteElement *NURBSFE =
|
||||
dynamic_cast<const NURBSFiniteElement *>(&el);
|
||||
|
||||
bool deleteRule = false;
|
||||
if (NURBSFE && patchRules)
|
||||
{
|
||||
const int patch = NURBSFE->GetPatch();
|
||||
const int* ijk = NURBSFE->GetIJK();
|
||||
Array<const KnotVector*>& kv = NURBSFE->KnotVectors();
|
||||
ir = &patchRules->GetElementRule(NURBSFE->GetElement(), patch, ijk, kv,
|
||||
deleteRule);
|
||||
}
|
||||
|
||||
elmat = 0.0;
|
||||
for (int i = 0; i < ir->GetNPoints(); i++)
|
||||
{
|
||||
@@ -882,6 +914,11 @@ void DiffusionIntegrator::AssembleElementMatrix
|
||||
AddMult_a_AAt(w, dshapedxt, elmat);
|
||||
}
|
||||
}
|
||||
|
||||
if (deleteRule)
|
||||
{
|
||||
delete ir;
|
||||
}
|
||||
}
|
||||
|
||||
void DiffusionIntegrator::AssembleElementMatrix2(
|
||||
@@ -2419,7 +2456,7 @@ void VectorFEMassIntegrator::AssembleElementMatrix(
|
||||
{
|
||||
int dof = el.GetDof();
|
||||
int spaceDim = Trans.GetSpaceDim();
|
||||
int vdim = std::max(spaceDim, el.GetVDim());
|
||||
int vdim = std::max(spaceDim, el.GetRangeDim());
|
||||
|
||||
double w;
|
||||
|
||||
@@ -2487,7 +2524,7 @@ void VectorFEMassIntegrator::AssembleElementMatrix2(
|
||||
{
|
||||
// assume test_fe is scalar FE and trial_fe is vector FE
|
||||
int spaceDim = Trans.GetSpaceDim();
|
||||
int vdim = std::max(spaceDim, trial_fe.GetVDim());
|
||||
int vdim = std::max(spaceDim, trial_fe.GetRangeDim());
|
||||
int trial_dof = trial_fe.GetDof();
|
||||
int test_dof = test_fe.GetDof();
|
||||
double w;
|
||||
@@ -2585,8 +2622,8 @@ void VectorFEMassIntegrator::AssembleElementMatrix2(
|
||||
{
|
||||
// assume both test_fe and trial_fe are vector FE
|
||||
int spaceDim = Trans.GetSpaceDim();
|
||||
int trial_vdim = std::max(spaceDim, trial_fe.GetVDim());
|
||||
int test_vdim = std::max(spaceDim, test_fe.GetVDim());
|
||||
int trial_vdim = std::max(spaceDim, trial_fe.GetRangeDim());
|
||||
int test_vdim = std::max(spaceDim, test_fe.GetRangeDim());
|
||||
int trial_dof = trial_fe.GetDof();
|
||||
int test_dof = test_fe.GetDof();
|
||||
double w;
|
||||
|
||||
+92
-23
@@ -20,17 +20,6 @@
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
// Local maximum size of dofs and quads in 1D
|
||||
constexpr int HCURL_MAX_D1D = 5;
|
||||
#ifdef MFEM_USE_HIP
|
||||
constexpr int HCURL_MAX_Q1D = 5;
|
||||
#else
|
||||
constexpr int HCURL_MAX_Q1D = 6;
|
||||
#endif
|
||||
|
||||
constexpr int HDIV_MAX_D1D = 5;
|
||||
constexpr int HDIV_MAX_Q1D = 6;
|
||||
|
||||
/// Abstract base class BilinearFormIntegrator
|
||||
class BilinearFormIntegrator : public NonlinearFormIntegrator
|
||||
{
|
||||
@@ -61,6 +50,11 @@ public:
|
||||
virtual void AssemblePA(const FiniteElementSpace &trial_fes,
|
||||
const FiniteElementSpace &test_fes);
|
||||
|
||||
/// Method defining partial assembly on NURBS patches.
|
||||
/** The result of the partial assembly is stored internally so that it can be
|
||||
used later in the method AddMultNURBSPA(). */
|
||||
virtual void AssembleNURBSPA(const FiniteElementSpace &fes);
|
||||
|
||||
virtual void AssemblePABoundary(const FiniteElementSpace &fes);
|
||||
|
||||
virtual void AssemblePAInteriorFaces(const FiniteElementSpace &fes);
|
||||
@@ -82,6 +76,9 @@ public:
|
||||
called. */
|
||||
virtual void AddMultPA(const Vector &x, Vector &y) const;
|
||||
|
||||
/// Method for partially assembled action on NURBS patches.
|
||||
virtual void AddMultNURBSPA(const Vector&x, Vector&y) const;
|
||||
|
||||
/// Method for partially assembled transposed action.
|
||||
/** Perform the transpose action of integrator on the input @a x and add the
|
||||
result to the output @a y. Both @a x and @a y are E-vectors, i.e. they
|
||||
@@ -148,6 +145,13 @@ public:
|
||||
ElementTransformation &Trans,
|
||||
DenseMatrix &elmat);
|
||||
|
||||
/** Given a particular NURBS patch, computes the patch matrix as a
|
||||
SparseMatrix @a smat.
|
||||
*/
|
||||
virtual void AssemblePatchMatrix(const int patch,
|
||||
const FiniteElementSpace &fes,
|
||||
SparseMatrix*& smat);
|
||||
|
||||
virtual void AssembleFaceMatrix(const FiniteElement &el1,
|
||||
const FiniteElement &el2,
|
||||
FaceElementTransformations &Trans,
|
||||
@@ -576,7 +580,7 @@ protected:
|
||||
|
||||
|
||||
inline virtual int GetTestVDim(const FiniteElement & test_fe)
|
||||
{ return std::max(space_dim, test_fe.GetVDim()); }
|
||||
{ return std::max(space_dim, test_fe.GetRangeDim()); }
|
||||
|
||||
inline virtual void CalcTestShape(const FiniteElement & test_fe,
|
||||
ElementTransformation &Trans,
|
||||
@@ -584,7 +588,7 @@ protected:
|
||||
{ test_fe.CalcVShape(Trans, shape); }
|
||||
|
||||
inline virtual int GetTrialVDim(const FiniteElement & trial_fe)
|
||||
{ return std::max(space_dim, trial_fe.GetVDim()); }
|
||||
{ return std::max(space_dim, trial_fe.GetRangeDim()); }
|
||||
|
||||
inline virtual void CalcTrialShape(const FiniteElement & trial_fe,
|
||||
ElementTransformation &Trans,
|
||||
@@ -674,7 +678,7 @@ protected:
|
||||
|
||||
|
||||
inline virtual int GetVDim(const FiniteElement & vector_fe)
|
||||
{ return std::max(space_dim, vector_fe.GetVDim()); }
|
||||
{ return std::max(space_dim, vector_fe.GetRangeDim()); }
|
||||
|
||||
inline virtual void CalcVShape(const FiniteElement & vector_fe,
|
||||
ElementTransformation &Trans,
|
||||
@@ -1101,7 +1105,7 @@ public:
|
||||
const FiniteElement & trial_fe,
|
||||
const FiniteElement & test_fe) const
|
||||
{
|
||||
return (trial_fe.GetVDim() == 3 &&
|
||||
return (trial_fe.GetRangeDim() == 3 &&
|
||||
trial_fe.GetRangeType() == mfem::FiniteElement::VECTOR &&
|
||||
test_fe.GetRangeType() == mfem::FiniteElement::SCALAR &&
|
||||
test_fe.GetDerivType() == mfem::FiniteElement::GRAD );
|
||||
@@ -1284,8 +1288,8 @@ public:
|
||||
const FiniteElement & trial_fe,
|
||||
const FiniteElement & test_fe) const
|
||||
{
|
||||
return (trial_fe.GetCurlDim() == 3 && trial_fe.GetVDim() == 3 &&
|
||||
test_fe.GetCurlDim() == 3 && test_fe.GetVDim() == 3 &&
|
||||
return (trial_fe.GetCurlDim() == 3 && trial_fe.GetRangeDim() == 3 &&
|
||||
test_fe.GetCurlDim() == 3 && test_fe.GetRangeDim() == 3 &&
|
||||
trial_fe.GetRangeType() == mfem::FiniteElement::VECTOR &&
|
||||
trial_fe.GetDerivType() == mfem::FiniteElement::CURL &&
|
||||
test_fe.GetRangeType() == mfem::FiniteElement::VECTOR &&
|
||||
@@ -1415,7 +1419,7 @@ public:
|
||||
const FiniteElement & trial_fe,
|
||||
const FiniteElement & test_fe) const
|
||||
{
|
||||
return (trial_fe.GetVDim() == 3 && test_fe.GetCurlDim() == 3 &&
|
||||
return (trial_fe.GetRangeDim() == 3 && test_fe.GetCurlDim() == 3 &&
|
||||
trial_fe.GetRangeType() == mfem::FiniteElement::VECTOR &&
|
||||
test_fe.GetRangeType() == mfem::FiniteElement::VECTOR &&
|
||||
test_fe.GetDerivType() == mfem::FiniteElement::CURL );
|
||||
@@ -1485,7 +1489,7 @@ public:
|
||||
const FiniteElement & trial_fe,
|
||||
const FiniteElement & test_fe) const
|
||||
{
|
||||
return (test_fe.GetVDim() == 3 &&
|
||||
return (test_fe.GetRangeDim() == 3 &&
|
||||
trial_fe.GetRangeType() == mfem::FiniteElement::SCALAR &&
|
||||
trial_fe.GetDerivType() == mfem::FiniteElement::GRAD &&
|
||||
test_fe.GetRangeType() == mfem::FiniteElement::VECTOR );
|
||||
@@ -1525,7 +1529,7 @@ public:
|
||||
const FiniteElement & trial_fe,
|
||||
const FiniteElement & test_fe) const
|
||||
{
|
||||
return (trial_fe.GetCurlDim() == 3 && test_fe.GetVDim() == 3 &&
|
||||
return (trial_fe.GetCurlDim() == 3 && test_fe.GetRangeDim() == 3 &&
|
||||
trial_fe.GetRangeType() == mfem::FiniteElement::VECTOR &&
|
||||
trial_fe.GetDerivType() == mfem::FiniteElement::CURL &&
|
||||
test_fe.GetRangeType() == mfem::FiniteElement::VECTOR );
|
||||
@@ -1896,7 +1900,7 @@ protected:
|
||||
const FiniteElement & trial_fe,
|
||||
const FiniteElement & test_fe) const
|
||||
{
|
||||
return (trial_fe.GetCurlDim() == 3 && test_fe.GetVDim() == 3 &&
|
||||
return (trial_fe.GetCurlDim() == 3 && test_fe.GetRangeDim() == 3 &&
|
||||
trial_fe.GetDerivType() == mfem::FiniteElement::CURL &&
|
||||
test_fe.GetRangeType() == mfem::FiniteElement::VECTOR );
|
||||
}
|
||||
@@ -1955,7 +1959,7 @@ protected:
|
||||
const FiniteElement & trial_fe,
|
||||
const FiniteElement & test_fe) const
|
||||
{
|
||||
return (trial_fe.GetVDim() == 3 && test_fe.GetCurlDim() == 3 &&
|
||||
return (trial_fe.GetRangeDim() == 3 && test_fe.GetCurlDim() == 3 &&
|
||||
trial_fe.GetRangeType() == mfem::FiniteElement::VECTOR &&
|
||||
test_fe.GetDerivType() == mfem::FiniteElement::CURL );
|
||||
}
|
||||
@@ -2111,6 +2115,59 @@ private:
|
||||
Vector pa_data;
|
||||
bool symmetric = true; ///< False if using a nonsymmetric matrix coefficient
|
||||
|
||||
// Data for NURBS patch PA
|
||||
|
||||
// Type for a variable-row-length 2D array, used for data related to 1D
|
||||
// quadrature rules in each dimension.
|
||||
typedef std::vector<std::vector<int>> IntArrayVar2D;
|
||||
|
||||
int numPatches = 0;
|
||||
static constexpr int numTypes = 2; // Number of rule types
|
||||
|
||||
// In the case integrationMode == Mode::PATCHWISE_REDUCED, an approximate
|
||||
// integration rule with sparse nonzero weights is computed by NNLSSolver,
|
||||
// for each 1D basis function on each patch, in each spatial dimension. For a
|
||||
// fixed 1D basis function b_i with DOF index i, in the tensor product basis
|
||||
// of patch p, the prescribed exact 1D rule is of the form
|
||||
// \sum_k a_{i,j,k} w_k for some integration points indexed by k, with
|
||||
// weights w_k and coefficients a_{i,j,k} depending on Q(x), an element
|
||||
// transformation, b_i, and b_j, for all 1D basis functions b_j whose support
|
||||
// overlaps that of b_i. Define the constraint matrix G = [g_{j,k}] with
|
||||
// g_{j,k} = a_{i,j,k} and the vector of exact weights w = [w_k]. A reduced
|
||||
// rule should have different weights w_r, many of them zero, and should
|
||||
// approximately satisfy Gw_r = Gw. A sparse approximate solution to this
|
||||
// underdetermined system is computed by NNLSSolver, and its data is stored
|
||||
// in the following members.
|
||||
|
||||
// For each patch p, spatial dimension d (total dim), and rule type t (total
|
||||
// numTypes), an std::vector<Vector> of reduced quadrature weights for all
|
||||
// basis functions is stored in reducedWeights[t + numTypes * (d + dim * p)],
|
||||
// reshaped as rw(t,d,p). Note that nd may vary with respect to the patch and
|
||||
// spatial dimension. Array reducedIDs is treated similarly.
|
||||
std::vector<std::vector<Vector>> reducedWeights;
|
||||
std::vector<IntArrayVar2D> reducedIDs;
|
||||
std::vector<Array<int>> pQ1D, pD1D;
|
||||
std::vector<std::vector<Array2D<double>>> pB, pG;
|
||||
std::vector<IntArrayVar2D> pminD, pmaxD, pminQ, pmaxQ, pminDD, pmaxDD;
|
||||
|
||||
std::vector<Array<const IntegrationRule*>> pir1d;
|
||||
|
||||
void SetupPatchPA(const int patch, Mesh *mesh, bool unitWeights=false);
|
||||
|
||||
void SetupPatchBasisData(Mesh *mesh, unsigned int patch);
|
||||
|
||||
/** Called by AssemblePatchMatrix for sparse matrix assembly on a NURBS patch
|
||||
with full 1D quadrature rules. */
|
||||
void AssemblePatchMatrix_fullQuadrature(const int patch,
|
||||
const FiniteElementSpace &fes,
|
||||
SparseMatrix*& smat);
|
||||
|
||||
/** Called by AssemblePatchMatrix for sparse matrix assembly on a NURBS patch
|
||||
with reduced 1D quadrature rules. */
|
||||
void AssemblePatchMatrix_reducedQuadrature(const int patch,
|
||||
const FiniteElementSpace &fes,
|
||||
SparseMatrix*& smat);
|
||||
|
||||
public:
|
||||
/// Construct a diffusion integrator with coefficient Q = 1
|
||||
DiffusionIntegrator(const IntegrationRule *ir = nullptr)
|
||||
@@ -2146,6 +2203,14 @@ public:
|
||||
ElementTransformation &Trans,
|
||||
DenseMatrix &elmat);
|
||||
|
||||
virtual void AssemblePatchMatrix(const int patch,
|
||||
const FiniteElementSpace &fes,
|
||||
SparseMatrix*& smat);
|
||||
|
||||
virtual void AssembleNURBSPA(const FiniteElementSpace &fes);
|
||||
|
||||
void AssemblePatchPA(const int patch, const FiniteElementSpace &fes);
|
||||
|
||||
/// Perform the local action of the BilinearFormIntegrator
|
||||
virtual void AssembleElementVector(const FiniteElement &el,
|
||||
ElementTransformation &Tr,
|
||||
@@ -2180,6 +2245,10 @@ public:
|
||||
|
||||
virtual void AddMultTransposePA(const Vector&, Vector&) const;
|
||||
|
||||
virtual void AddMultNURBSPA(const Vector&, Vector&) const;
|
||||
|
||||
void AddMultPatchPA(const int patch, const Vector &x, Vector &y) const;
|
||||
|
||||
static const IntegrationRule &GetRule(const FiniteElement &trial_fe,
|
||||
const FiniteElement &test_fe);
|
||||
|
||||
@@ -3371,7 +3440,7 @@ private:
|
||||
void cross_product(const Vector & x, const DenseMatrix & Y, DenseMatrix & Z)
|
||||
{
|
||||
int dim = x.Size();
|
||||
MFEM_VERIFY(Y.Width() == dim, "Size missmatch");
|
||||
MFEM_VERIFY(Y.Width() == dim, "Size mismatch");
|
||||
int dimc = dim == 3 ? dim : 1;
|
||||
int h = Y.Height();
|
||||
Z.SetSize(h,dimc);
|
||||
|
||||
+15
-3
@@ -1591,14 +1591,21 @@ void VectorQuadratureFunctionCoefficient::Eval(Vector &V,
|
||||
{
|
||||
QuadF.HostRead();
|
||||
|
||||
const int el_idx = QuadF.GetSpace()->GetEntityIndex(T);
|
||||
// Handle the case of "interior boundary elements" and FaceQuadratureSpace
|
||||
// with FaceType::Boundary.
|
||||
if (el_idx < 0) { V = 0.0; return; }
|
||||
|
||||
const int ip_idx = QuadF.GetSpace()->GetPermutedIndex(el_idx, ip.index);
|
||||
|
||||
if (index == 0 && vdim == QuadF.GetVDim())
|
||||
{
|
||||
QuadF.GetValues(T.ElementNo, ip.index, V);
|
||||
QuadF.GetValues(el_idx, ip_idx, V);
|
||||
}
|
||||
else
|
||||
{
|
||||
Vector temp;
|
||||
QuadF.GetValues(T.ElementNo, ip.index, temp);
|
||||
QuadF.GetValues(el_idx, ip_idx, temp);
|
||||
V.SetSize(vdim);
|
||||
for (int i = 0; i < vdim; i++)
|
||||
{
|
||||
@@ -1625,7 +1632,12 @@ double QuadratureFunctionCoefficient::Eval(ElementTransformation &T,
|
||||
{
|
||||
QuadF.HostRead();
|
||||
Vector temp(1);
|
||||
QuadF.GetValues(T.ElementNo, ip.index, temp);
|
||||
const int el_idx = QuadF.GetSpace()->GetEntityIndex(T);
|
||||
// Handle the case of "interior boundary elements" and FaceQuadratureSpace
|
||||
// with FaceType::Boundary.
|
||||
if (el_idx < 0) { return 0.0; }
|
||||
const int ip_idx = QuadF.GetSpace()->GetPermutedIndex(el_idx, ip.index);
|
||||
QuadF.GetValues(el_idx, ip_idx, temp);
|
||||
return temp[0];
|
||||
}
|
||||
|
||||
|
||||
+19
-16
@@ -1243,25 +1243,28 @@ ParSesquilinearForm::FormLinearSystem(const Array<int> &ess_tdof_list,
|
||||
HypreParMatrix * Ah;
|
||||
A_i.Get(Ah);
|
||||
hypre_ParCSRMatrix *Aih = *Ah;
|
||||
#if !defined(HYPRE_USING_GPU)
|
||||
ess_tdof_list.HostRead();
|
||||
for (int k = 0; k < n; k++)
|
||||
if (!HypreUsingGPU())
|
||||
{
|
||||
const int j = ess_tdof_list[k];
|
||||
Aih->diag->data[Aih->diag->i[j]] = 0.0;
|
||||
ess_tdof_list.HostRead();
|
||||
for (int k = 0; k < n; k++)
|
||||
{
|
||||
const int j = ess_tdof_list[k];
|
||||
Aih->diag->data[Aih->diag->i[j]] = 0.0;
|
||||
}
|
||||
}
|
||||
#else
|
||||
Ah->HypreReadWrite();
|
||||
const int *d_ess_tdof_list =
|
||||
ess_tdof_list.GetMemory().Read(MemoryClass::DEVICE, n);
|
||||
const int *d_diag_i = Aih->diag->i;
|
||||
double *d_diag_data = Aih->diag->data;
|
||||
MFEM_GPU_FORALL(k, n,
|
||||
else
|
||||
{
|
||||
const int j = d_ess_tdof_list[k];
|
||||
d_diag_data[d_diag_i[j]] = 0.0;
|
||||
});
|
||||
#endif
|
||||
Ah->HypreReadWrite();
|
||||
const int *d_ess_tdof_list =
|
||||
ess_tdof_list.GetMemory().Read(MemoryClass::DEVICE, n);
|
||||
const int *d_diag_i = Aih->diag->i;
|
||||
double *d_diag_data = Aih->diag->data;
|
||||
MFEM_GPU_FORALL(k, n,
|
||||
{
|
||||
const int j = d_ess_tdof_list[k];
|
||||
d_diag_data[d_diag_i[j]] = 0.0;
|
||||
});
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -922,7 +922,7 @@ void ParaViewDataCollection::Save()
|
||||
{
|
||||
const std::string &field_name = qfield.first;
|
||||
std::ofstream os(vtu_prefix + GenerateVTUFileName(field_name, myid));
|
||||
qfield.second->SaveVTU(os, pv_data_format, GetCompressionLevel());
|
||||
qfield.second->SaveVTU(os, pv_data_format, GetCompressionLevel(), field_name);
|
||||
}
|
||||
|
||||
// MPI rank 0 also creates a "PVTU" file that points to all of the separately
|
||||
|
||||
+4
-6
@@ -166,21 +166,19 @@ void DGMassInverse::DGMassCGIteration(const Vector &b_, Vector &u_) const
|
||||
b = b_.Read();
|
||||
}
|
||||
|
||||
constexpr int NB = Q1D ? Q1D : 1; // block size
|
||||
static constexpr int NB = Q1D ? Q1D : 1; // block size
|
||||
|
||||
mfem::forall_2D(NE, NB, NB, [=] MFEM_HOST_DEVICE (int e)
|
||||
{
|
||||
constexpr int NB = Q1D ? Q1D : 1; // redefine here for some compilers
|
||||
|
||||
// Perform change of basis if needed
|
||||
if (CHANGE_BASIS)
|
||||
{
|
||||
// Transform RHS
|
||||
DGMassBasis<DIM,D1D,MAX_D1D>(e, NE, q2d_Bt, b_orig, b2, d1d);
|
||||
DGMassBasis<DIM,D1D>(e, NE, q2d_Bt, b_orig, b2, d1d);
|
||||
if (IT_MODE)
|
||||
{
|
||||
// Transform initial guess
|
||||
DGMassBasis<DIM,D1D,MAX_D1D>(e, NE, d2q_B, u, u, d1d);
|
||||
DGMassBasis<DIM,D1D>(e, NE, d2q_B, u, u, d1d);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -257,7 +255,7 @@ void DGMassInverse::DGMassCGIteration(const Vector &b_, Vector &u_) const
|
||||
|
||||
if (CHANGE_BASIS)
|
||||
{
|
||||
DGMassBasis<DIM,D1D,MAX_D1D>(e, NE, q2d_B, u, u, d1d);
|
||||
DGMassBasis<DIM,D1D>(e, NE, q2d_B, u, u, d1d);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -172,7 +172,7 @@ double DGMassDot(const int e,
|
||||
return s_dot[0];
|
||||
}
|
||||
|
||||
template<int T_D1D = 0, int MAX_D1D = 0>
|
||||
template<int T_D1D = 0>
|
||||
MFEM_HOST_DEVICE inline
|
||||
void DGMassBasis2D(const int e,
|
||||
const int NE,
|
||||
@@ -181,7 +181,7 @@ void DGMassBasis2D(const int e,
|
||||
double *y_,
|
||||
const int d1d = 0)
|
||||
{
|
||||
constexpr int MD1 = T_D1D ? T_D1D : MAX_D1D;
|
||||
constexpr int MD1 = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
|
||||
const auto b = Reshape(b_, D1D, D1D);
|
||||
@@ -213,7 +213,7 @@ void DGMassBasis2D(const int e,
|
||||
MFEM_SYNC_THREAD;
|
||||
}
|
||||
|
||||
template<int T_D1D = 0, int MAX_D1D = 0>
|
||||
template<int T_D1D = 0>
|
||||
MFEM_HOST_DEVICE inline
|
||||
void DGMassBasis3D(const int e,
|
||||
const int NE,
|
||||
@@ -228,7 +228,7 @@ void DGMassBasis3D(const int e,
|
||||
const auto x = Reshape(x_, D1D, D1D, D1D, NE);
|
||||
auto y = Reshape(y_, D1D, D1D, D1D, NE);
|
||||
|
||||
constexpr int MD1 = T_D1D ? T_D1D : MAX_D1D;
|
||||
constexpr int MD1 = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
|
||||
|
||||
MFEM_SHARED double sB[MD1*MD1];
|
||||
MFEM_SHARED double sm0[MD1*MD1*MD1];
|
||||
@@ -260,7 +260,7 @@ void DGMassBasis3D(const int e,
|
||||
MFEM_SYNC_THREAD;
|
||||
}
|
||||
|
||||
template<int DIM, int T_D1D = 0, int MAX_D1D = 0>
|
||||
template<int DIM, int T_D1D = 0>
|
||||
MFEM_HOST_DEVICE inline
|
||||
void DGMassBasis(const int e,
|
||||
const int NE,
|
||||
@@ -271,11 +271,11 @@ void DGMassBasis(const int e,
|
||||
{
|
||||
if (DIM == 2)
|
||||
{
|
||||
DGMassBasis2D<T_D1D, MAX_D1D>(e, NE, b_, x_, y_, d1d);
|
||||
DGMassBasis2D<T_D1D>(e, NE, b_, x_, y_, d1d);
|
||||
}
|
||||
else if (DIM == 3)
|
||||
{
|
||||
DGMassBasis3D<T_D1D, MAX_D1D>(e, NE, b_, x_, y_, d1d);
|
||||
DGMassBasis3D<T_D1D>(e, NE, b_, x_, y_, d1d);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
+1
-1
@@ -125,7 +125,7 @@ public:
|
||||
DofTransformation objects are provided by the FiniteElementSpace which has
|
||||
access to the mesh and can therefore provide the face orientations. This is
|
||||
convenient when working with GridFunction, LinearForm, or BilinearForm
|
||||
obejcts or their parallel counterparts.
|
||||
objects or their parallel counterparts.
|
||||
|
||||
StatelessDofTransformation objects are provided by FiniteElement or
|
||||
FiniteElementCollection objects which do not have access to face
|
||||
|
||||
+1
-1
@@ -807,7 +807,7 @@ void NodalFiniteElement::Project(
|
||||
else
|
||||
{
|
||||
DenseMatrix vshape(fe.GetDof(), std::max(Trans.GetSpaceDim(),
|
||||
fe.GetVDim()));
|
||||
fe.GetRangeDim()));
|
||||
|
||||
I.SetSize(vshape.Width()*dof, fe.GetDof());
|
||||
for (int k = 0; k < dof; k++)
|
||||
|
||||
+7
-6
@@ -307,19 +307,20 @@ public:
|
||||
FiniteElement(int D, Geometry::Type G, int Do, int O,
|
||||
int F = FunctionSpace::Pk);
|
||||
|
||||
/// Returns the reference space dimension for the finite element
|
||||
/// Returns the reference space dimension for the finite element.
|
||||
int GetDim() const { return dim; }
|
||||
|
||||
/// Returns the vector dimension for vector-valued finite elements
|
||||
int GetVDim() const { return vdim; }
|
||||
/** @brief Returns the vector dimension for vector-valued finite elements,
|
||||
which is also the dimension of the interpolation operatrion. */
|
||||
int GetRangeDim() const { return vdim; }
|
||||
|
||||
/// Returns the dimension of the curl for vector-valued finite elements
|
||||
/// Returns the dimension of the curl for vector-valued finite elements.
|
||||
int GetCurlDim() const { return cdim; }
|
||||
|
||||
/// Returns the Geometry::Type of the reference element
|
||||
/// Returns the Geometry::Type of the reference element.
|
||||
Geometry::Type GetGeomType() const { return geom_type; }
|
||||
|
||||
/// Returns the number of degrees of freedom in the finite element
|
||||
/// Returns the number of degrees of freedom in the finite element.
|
||||
int GetDof() const { return dof; }
|
||||
|
||||
/** @brief Returns the order of the finite element. In the case of
|
||||
|
||||
+2
-2
@@ -1852,7 +1852,7 @@ void ND_R1D_SegmentElement::Project(const FiniteElement &fe,
|
||||
else
|
||||
{
|
||||
double vk[Geometry::MaxDim];
|
||||
DenseMatrix vshape(fe.GetDof(), fe.GetVDim());
|
||||
DenseMatrix vshape(fe.GetDof(), fe.GetRangeDim());
|
||||
|
||||
double * tk_ptr = const_cast<double*>(tk);
|
||||
|
||||
@@ -2293,7 +2293,7 @@ void ND_R2D_FiniteElement::Project(const FiniteElement &fe,
|
||||
else
|
||||
{
|
||||
double vk[Geometry::MaxDim];
|
||||
DenseMatrix vshape(fe.GetDof(), fe.GetVDim());
|
||||
DenseMatrix vshape(fe.GetDof(), fe.GetRangeDim());
|
||||
|
||||
double * tk_ptr = const_cast<double*>(tk);
|
||||
|
||||
|
||||
@@ -56,6 +56,10 @@ public:
|
||||
Vector &Weights () const { return weights; }
|
||||
/// Update the NURBSFiniteElement according to the currently set knot vectors
|
||||
virtual void SetOrder () const { }
|
||||
|
||||
/// Returns the indices (i,j) in 2D or (i,j,k) in 3D of this element in the
|
||||
/// tensor product ordering of the patch.
|
||||
const int* GetIJK() const { return ijk; }
|
||||
};
|
||||
|
||||
|
||||
|
||||
+4
-4
@@ -1486,7 +1486,7 @@ void RT_R1D_SegmentElement::Project(const FiniteElement &fe,
|
||||
else
|
||||
{
|
||||
double vk[Geometry::MaxDim];
|
||||
DenseMatrix vshape(fe.GetDof(), fe.GetVDim());
|
||||
DenseMatrix vshape(fe.GetDof(), fe.GetRangeDim());
|
||||
|
||||
double * nk_ptr = const_cast<double*>(nk);
|
||||
|
||||
@@ -1523,7 +1523,7 @@ void RT_R1D_SegmentElement::ProjectCurl(const FiniteElement &fe,
|
||||
ElementTransformation &Trans,
|
||||
DenseMatrix &curl) const
|
||||
{
|
||||
DenseMatrix curl_shape(fe.GetDof(), fe.GetVDim());
|
||||
DenseMatrix curl_shape(fe.GetDof(), fe.GetRangeDim());
|
||||
Vector curl_k(fe.GetDof());
|
||||
|
||||
double * nk_ptr = const_cast<double*>(nk);
|
||||
@@ -1849,7 +1849,7 @@ void RT_R2D_FiniteElement::Project(const FiniteElement &fe,
|
||||
else
|
||||
{
|
||||
double vk[Geometry::MaxDim];
|
||||
DenseMatrix vshape(fe.GetDof(), fe.GetVDim());
|
||||
DenseMatrix vshape(fe.GetDof(), fe.GetRangeDim());
|
||||
|
||||
double * nk_ptr = const_cast<double*>(nk);
|
||||
|
||||
@@ -1888,7 +1888,7 @@ void RT_R2D_FiniteElement::ProjectCurl(const FiniteElement &fe,
|
||||
ElementTransformation &Trans,
|
||||
DenseMatrix &curl) const
|
||||
{
|
||||
DenseMatrix curl_shape(fe.GetDof(), fe.GetVDim());
|
||||
DenseMatrix curl_shape(fe.GetDof(), fe.GetRangeDim());
|
||||
Vector curl_k(fe.GetDof());
|
||||
|
||||
double * nk_ptr = const_cast<double*>(nk);
|
||||
|
||||
+27
-17
@@ -87,6 +87,16 @@ int FiniteElementCollection::GetDerivMapType(int dim) const
|
||||
return FiniteElement::UNKNOWN_MAP_TYPE;
|
||||
}
|
||||
|
||||
int FiniteElementCollection::GetRangeDim(int dim) const
|
||||
{
|
||||
const FiniteElement *fe = FiniteElementForDim(dim);
|
||||
if (fe)
|
||||
{
|
||||
return fe->GetRangeDim();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int FiniteElementCollection::HasFaceDofs(Geometry::Type geom, int p) const
|
||||
{
|
||||
switch (geom)
|
||||
@@ -1713,7 +1723,7 @@ H1_FECollection::H1_FECollection(const int p, const int dim, const int btype)
|
||||
H1_Elements[Geometry::SEGMENT] = new H1_SegmentElement(p, btype);
|
||||
}
|
||||
|
||||
SegDofOrd[0] = new int[2*pm1];
|
||||
SegDofOrd[0] = (pm1 > 0) ? new int[2*pm1] : nullptr;
|
||||
SegDofOrd[1] = SegDofOrd[0] + pm1;
|
||||
for (int i = 0; i < pm1; i++)
|
||||
{
|
||||
@@ -1751,7 +1761,7 @@ H1_FECollection::H1_FECollection(const int p, const int dim, const int btype)
|
||||
|
||||
const int &TriDof = H1_dof[Geometry::TRIANGLE];
|
||||
const int &QuadDof = H1_dof[Geometry::SQUARE];
|
||||
TriDofOrd[0] = new int[6*TriDof];
|
||||
TriDofOrd[0] = (TriDof > 0) ? new int[6*TriDof] : nullptr;
|
||||
for (int i = 1; i < 6; i++)
|
||||
{
|
||||
TriDofOrd[i] = TriDofOrd[i-1] + TriDof;
|
||||
@@ -1772,7 +1782,7 @@ H1_FECollection::H1_FECollection(const int p, const int dim, const int btype)
|
||||
}
|
||||
}
|
||||
|
||||
QuadDofOrd[0] = new int[8*QuadDof];
|
||||
QuadDofOrd[0] = (QuadDof > 0) ? new int[8*QuadDof] : nullptr;
|
||||
for (int i = 1; i < 8; i++)
|
||||
{
|
||||
QuadDofOrd[i] = QuadDofOrd[i-1] + QuadDof;
|
||||
@@ -1855,7 +1865,7 @@ H1_FECollection::H1_FECollection(const int p, const int dim, const int btype)
|
||||
H1_Elements[Geometry::PYRAMID] = new LinearPyramidFiniteElement;
|
||||
|
||||
const int &TetDof = H1_dof[Geometry::TETRAHEDRON];
|
||||
TetDofOrd[0] = new int[24*TetDof];
|
||||
TetDofOrd[0] = (TetDof > 0) ? new int[24*TetDof] : nullptr;
|
||||
for (int i = 1; i < 24; i++)
|
||||
{
|
||||
TetDofOrd[i] = TetDofOrd[i-1] + TetDof;
|
||||
@@ -2127,7 +2137,7 @@ L2_FECollection::L2_FECollection(const int p, const int dim, const int btype,
|
||||
// No need to set the map_type for Tr_Elements.
|
||||
|
||||
const int pp1 = p + 1;
|
||||
SegDofOrd[0] = new int[2*pp1];
|
||||
SegDofOrd[0] = (pp1 > 0) ? new int[2*pp1] : nullptr;
|
||||
SegDofOrd[1] = SegDofOrd[0] + pp1;
|
||||
for (int i = 0; i <= p; i++)
|
||||
{
|
||||
@@ -2160,7 +2170,7 @@ L2_FECollection::L2_FECollection(const int p, const int dim, const int btype,
|
||||
}
|
||||
|
||||
const int TriDof = L2_Elements[Geometry::TRIANGLE]->GetDof();
|
||||
TriDofOrd[0] = new int[6*TriDof];
|
||||
TriDofOrd[0] = (TriDof > 0) ? new int[6*TriDof] : nullptr;
|
||||
for (int i = 1; i < 6; i++)
|
||||
{
|
||||
TriDofOrd[i] = TriDofOrd[i-1] + TriDof;
|
||||
@@ -2181,7 +2191,7 @@ L2_FECollection::L2_FECollection(const int p, const int dim, const int btype,
|
||||
}
|
||||
}
|
||||
const int QuadDof = L2_Elements[Geometry::SQUARE]->GetDof();
|
||||
OtherDofOrd = new int[QuadDof];
|
||||
OtherDofOrd = (QuadDof > 0) ? new int[QuadDof] : nullptr;
|
||||
for (int j = 0; j < QuadDof; j++)
|
||||
{
|
||||
OtherDofOrd[j] = j; // for Or == 0
|
||||
@@ -2225,7 +2235,7 @@ L2_FECollection::L2_FECollection(const int p, const int dim, const int btype,
|
||||
const int PriDof = L2_Elements[Geometry::PRISM]->GetDof();
|
||||
const int MaxDof = std::max(TetDof, std::max(PriDof, HexDof));
|
||||
|
||||
TetDofOrd[0] = new int[24*TetDof];
|
||||
TetDofOrd[0] = (TetDof > 0) ? new int[24*TetDof] : nullptr;
|
||||
for (int i = 1; i < 24; i++)
|
||||
{
|
||||
TetDofOrd[i] = TetDofOrd[i-1] + TetDof;
|
||||
@@ -2314,7 +2324,7 @@ L2_FECollection::L2_FECollection(const int p, const int dim, const int btype,
|
||||
}
|
||||
}
|
||||
}
|
||||
OtherDofOrd = new int[MaxDof];
|
||||
OtherDofOrd = (MaxDof > 0) ? new int[MaxDof] : nullptr;
|
||||
for (int j = 0; j < MaxDof; j++)
|
||||
{
|
||||
OtherDofOrd[j] = j; // for Or == 0
|
||||
@@ -2502,7 +2512,7 @@ void RT_FECollection::InitFaces(const int p, const int dim_,
|
||||
RT_Elements[Geometry::SEGMENT] = l2_seg;
|
||||
RT_dof[Geometry::SEGMENT] = pp1;
|
||||
|
||||
SegDofOrd[0] = new int[2*pp1];
|
||||
SegDofOrd[0] = (pp1 > 0) ? new int[2*pp1] : nullptr;
|
||||
SegDofOrd[1] = SegDofOrd[0] + pp1;
|
||||
for (int i = 0; i <= p; i++)
|
||||
{
|
||||
@@ -2523,7 +2533,7 @@ void RT_FECollection::InitFaces(const int p, const int dim_,
|
||||
RT_dof[Geometry::SQUARE] = pp1*pp1;
|
||||
|
||||
int TriDof = RT_dof[Geometry::TRIANGLE];
|
||||
TriDofOrd[0] = new int[6*TriDof];
|
||||
TriDofOrd[0] = (TriDof > 0) ? new int[6*TriDof] : nullptr;
|
||||
for (int i = 1; i < 6; i++)
|
||||
{
|
||||
TriDofOrd[i] = TriDofOrd[i-1] + TriDof;
|
||||
@@ -2553,7 +2563,7 @@ void RT_FECollection::InitFaces(const int p, const int dim_,
|
||||
}
|
||||
|
||||
int QuadDof = RT_dof[Geometry::SQUARE];
|
||||
QuadDofOrd[0] = new int[8*QuadDof];
|
||||
QuadDofOrd[0] = (QuadDof > 0) ? new int[8*QuadDof] : nullptr;
|
||||
for (int i = 1; i < 8; i++)
|
||||
{
|
||||
QuadDofOrd[i] = QuadDofOrd[i-1] + QuadDof;
|
||||
@@ -2749,7 +2759,7 @@ ND_FECollection::ND_FECollection(const int p, const int dim,
|
||||
ND_Elements[Geometry::SEGMENT] = new ND_SegmentElement(p, ob_type);
|
||||
ND_dof[Geometry::SEGMENT] = p;
|
||||
|
||||
SegDofOrd[0] = new int[2*p];
|
||||
SegDofOrd[0] = (p > 0) ? new int[2*p] : nullptr;
|
||||
SegDofOrd[1] = SegDofOrd[0] + p;
|
||||
for (int i = 0; i < p; i++)
|
||||
{
|
||||
@@ -2769,7 +2779,7 @@ ND_FECollection::ND_FECollection(const int p, const int dim,
|
||||
ND_dof[Geometry::TRIANGLE] = p*pm1;
|
||||
|
||||
int QuadDof = ND_dof[Geometry::SQUARE];
|
||||
QuadDofOrd[0] = new int[8*QuadDof];
|
||||
QuadDofOrd[0] = (QuadDof > 0) ? new int[8*QuadDof] : nullptr;
|
||||
for (int i = 1; i < 8; i++)
|
||||
{
|
||||
QuadDofOrd[i] = QuadDofOrd[i-1] + QuadDof;
|
||||
@@ -2813,7 +2823,7 @@ ND_FECollection::ND_FECollection(const int p, const int dim,
|
||||
}
|
||||
|
||||
int TriDof = ND_dof[Geometry::TRIANGLE];
|
||||
TriDofOrd[0] = new int[6*TriDof];
|
||||
TriDofOrd[0] = (TriDof > 0) ? new int[6*TriDof] : nullptr;
|
||||
for (int i = 1; i < 6; i++)
|
||||
{
|
||||
TriDofOrd[i] = TriDofOrd[i-1] + TriDof;
|
||||
@@ -3163,7 +3173,7 @@ ND_R2D_FECollection::ND_R2D_FECollection(const int p, const int dim,
|
||||
ob_type);
|
||||
ND_dof[Geometry::SEGMENT] = 2 * p - 1;
|
||||
|
||||
SegDofOrd[0] = new int[4 * p - 2];
|
||||
SegDofOrd[0] = (4*p > 2) ? new int[4 * p - 2] : nullptr;
|
||||
SegDofOrd[1] = SegDofOrd[0] + 2 * p - 1;
|
||||
for (int i = 0; i < p; i++)
|
||||
{
|
||||
@@ -3347,7 +3357,7 @@ void RT_R2D_FECollection::InitFaces(const int p, const int dim,
|
||||
RT_Elements[Geometry::SEGMENT] = l2_seg;
|
||||
RT_dof[Geometry::SEGMENT] = pp1;
|
||||
|
||||
SegDofOrd[0] = new int[2*pp1];
|
||||
SegDofOrd[0] = (pp1 > 0) ? new int[2*pp1] : nullptr;
|
||||
SegDofOrd[1] = SegDofOrd[0] + pp1;
|
||||
for (int i = 0; i <= p; i++)
|
||||
{
|
||||
|
||||
+347
-293
File diff suppressed because it is too large
Load Diff
@@ -26,6 +26,7 @@
|
||||
#include "bilininteg.hpp"
|
||||
#include "fespace.hpp"
|
||||
#include "gridfunc.hpp"
|
||||
#include "kdtree.hpp"
|
||||
#include "linearform.hpp"
|
||||
#include "nonlinearform.hpp"
|
||||
#include "bilinearform.hpp"
|
||||
|
||||
+70
-25
@@ -64,7 +64,7 @@ FiniteElementSpace::FiniteElementSpace()
|
||||
face_dof(NULL),
|
||||
NURBSext(NULL), own_ext(false),
|
||||
DoFTrans(0), VDoFTrans(vdim, ordering),
|
||||
cP(NULL), cR(NULL), cR_hp(NULL), cP_is_set(false),
|
||||
cP_is_set(false),
|
||||
Th(Operator::ANY_TYPE),
|
||||
sequence(0), mesh_sequence(0), orders_changed(false), relaxed_hp(false)
|
||||
{ }
|
||||
@@ -123,24 +123,24 @@ void FiniteElementSpace::CopyProlongationAndRestriction(
|
||||
|
||||
if (fes.GetConformingProlongation() != NULL)
|
||||
{
|
||||
if (perm) { cP = Mult(*perm_mat, *fes.GetConformingProlongation()); }
|
||||
else { cP = new SparseMatrix(*fes.GetConformingProlongation()); }
|
||||
if (perm) { cP.reset(Mult(*perm_mat, *fes.GetConformingProlongation())); }
|
||||
else { cP.reset(new SparseMatrix(*fes.GetConformingProlongation())); }
|
||||
cP_is_set = true;
|
||||
}
|
||||
else if (perm != NULL)
|
||||
{
|
||||
cP = perm_mat;
|
||||
cP.reset(perm_mat);
|
||||
cP_is_set = true;
|
||||
perm_mat = NULL;
|
||||
}
|
||||
if (fes.GetConformingRestriction() != NULL)
|
||||
{
|
||||
if (perm) { cR = Mult(*fes.GetConformingRestriction(), *perm_mat_tr); }
|
||||
else { cR = new SparseMatrix(*fes.GetConformingRestriction()); }
|
||||
if (perm) { cR.reset(Mult(*fes.GetConformingRestriction(), *perm_mat_tr)); }
|
||||
else { cR.reset(new SparseMatrix(*fes.GetConformingRestriction())); }
|
||||
}
|
||||
else if (perm != NULL)
|
||||
{
|
||||
cR = perm_mat_tr;
|
||||
cR.reset(perm_mat_tr);
|
||||
perm_mat_tr = NULL;
|
||||
}
|
||||
|
||||
@@ -309,6 +309,12 @@ FiniteElementSpace::GetBdrElementVDofs(int i, Array<int> &vdofs) const
|
||||
}
|
||||
}
|
||||
|
||||
void FiniteElementSpace::GetPatchVDofs(int i, Array<int> &vdofs) const
|
||||
{
|
||||
GetPatchDofs(i, vdofs);
|
||||
DofsToVDofs(vdofs);
|
||||
}
|
||||
|
||||
void FiniteElementSpace::GetFaceVDofs(int i, Array<int> &vdofs) const
|
||||
{
|
||||
GetFaceDofs(i, vdofs);
|
||||
@@ -954,7 +960,10 @@ void FiniteElementSpace::BuildConformingInterpolation() const
|
||||
|
||||
if (FEColl()->GetContType() == FiniteElementCollection::DISCONTINUOUS)
|
||||
{
|
||||
cP = cR = cR_hp = NULL; // will be treated as identities
|
||||
cP.reset();
|
||||
cR.reset();
|
||||
cR_hp.reset();
|
||||
R_transpose.reset();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1108,12 +1117,15 @@ void FiniteElementSpace::BuildConformingInterpolation() const
|
||||
// if all dofs are true dofs leave cP and cR NULL
|
||||
if (n_true_dofs == ndofs)
|
||||
{
|
||||
cP = cR = cR_hp = NULL; // will be treated as identities
|
||||
cP.reset();
|
||||
cR.reset();
|
||||
cR_hp.reset();
|
||||
R_transpose.reset();
|
||||
return;
|
||||
}
|
||||
|
||||
// create the conforming prolongation matrix cP
|
||||
cP = new SparseMatrix(ndofs, n_true_dofs);
|
||||
cP.reset(new SparseMatrix(ndofs, n_true_dofs));
|
||||
|
||||
// create the conforming restriction matrix cR
|
||||
int *cR_J;
|
||||
@@ -1127,12 +1139,19 @@ void FiniteElementSpace::BuildConformingInterpolation() const
|
||||
cR_A[i] = 1.0;
|
||||
}
|
||||
cR_I[n_true_dofs] = n_true_dofs;
|
||||
cR = new SparseMatrix(cR_I, cR_J, cR_A, n_true_dofs, ndofs);
|
||||
cR.reset(new SparseMatrix(cR_I, cR_J, cR_A, n_true_dofs, ndofs));
|
||||
}
|
||||
|
||||
// In var. order spaces, create the restriction matrix cR_hp which is similar
|
||||
// to cR, but has interpolation in the extra master edge/face DOFs.
|
||||
cR_hp = IsVariableOrder() ? new SparseMatrix(n_true_dofs, ndofs) : NULL;
|
||||
if (IsVariableOrder())
|
||||
{
|
||||
cR_hp.reset(new SparseMatrix(n_true_dofs, ndofs));
|
||||
}
|
||||
else
|
||||
{
|
||||
cR_hp.reset();
|
||||
}
|
||||
|
||||
Array<bool> finalized(ndofs);
|
||||
finalized = false;
|
||||
@@ -1250,21 +1269,28 @@ const SparseMatrix* FiniteElementSpace::GetConformingProlongation() const
|
||||
{
|
||||
if (Conforming()) { return NULL; }
|
||||
if (!cP_is_set) { BuildConformingInterpolation(); }
|
||||
return cP;
|
||||
return cP.get();
|
||||
}
|
||||
|
||||
const SparseMatrix* FiniteElementSpace::GetConformingRestriction() const
|
||||
{
|
||||
if (Conforming()) { return NULL; }
|
||||
if (!cP_is_set) { BuildConformingInterpolation(); }
|
||||
return cR;
|
||||
if (cR && !R_transpose) { R_transpose.reset(new TransposeOperator(*cR)); }
|
||||
return cR.get();
|
||||
}
|
||||
|
||||
const SparseMatrix* FiniteElementSpace::GetHpConformingRestriction() const
|
||||
{
|
||||
if (Conforming()) { return NULL; }
|
||||
if (!cP_is_set) { BuildConformingInterpolation(); }
|
||||
return IsVariableOrder() ? cR_hp : cR;
|
||||
return IsVariableOrder() ? cR_hp.get() : cR.get();
|
||||
}
|
||||
|
||||
const Operator *FiniteElementSpace::GetRestrictionTransposeOperator() const
|
||||
{
|
||||
GetRestrictionOperator(); // Ensure that R_transpose is built
|
||||
return R_transpose.get();
|
||||
}
|
||||
|
||||
int FiniteElementSpace::GetNConformingDofs() const
|
||||
@@ -2195,7 +2221,10 @@ void FiniteElementSpace::Constructor(Mesh *mesh_, NURBSExtension *NURBSext_,
|
||||
own_ext = 1;
|
||||
}
|
||||
UpdateNURBS();
|
||||
cP = cR = cR_hp = NULL;
|
||||
cP.reset();
|
||||
cR.reset();
|
||||
cR_hp.reset();
|
||||
R_transpose.reset();
|
||||
cP_is_set = false;
|
||||
|
||||
ConstructDoFTrans();
|
||||
@@ -2357,6 +2386,7 @@ void FiniteElementSpace::Construct()
|
||||
cR = NULL;
|
||||
cR_hp = NULL;
|
||||
cP_is_set = false;
|
||||
R_transpose = NULL;
|
||||
// 'Th' is initialized/destroyed before this method is called.
|
||||
|
||||
int dim = mesh->Dimension();
|
||||
@@ -2801,11 +2831,24 @@ FiniteElementSpace::GetElementDofs(int elem, Array<int> &dofs) const
|
||||
return DoFTrans[mesh->GetElementBaseGeometry(elem)];
|
||||
}
|
||||
|
||||
void FiniteElementSpace::GetPatchDofs(int patch, Array<int> &dofs) const
|
||||
{
|
||||
MFEM_ASSERT(NURBSext,
|
||||
"FiniteElementSpace::GetPatchDofs needs a NURBSExtension");
|
||||
NURBSext->GetPatchDofs(patch, dofs);
|
||||
}
|
||||
|
||||
const FiniteElement *FiniteElementSpace::GetFE(int i) const
|
||||
{
|
||||
if (i < 0 || !mesh->GetNE()) { return NULL; }
|
||||
MFEM_VERIFY(i < mesh->GetNE(),
|
||||
"Invalid element id " << i << ", maximum allowed " << mesh->GetNE()-1);
|
||||
if (i < 0 || i >= mesh->GetNE())
|
||||
{
|
||||
if (mesh->GetNE() == 0)
|
||||
{
|
||||
MFEM_ABORT("Empty MPI partitions are not permitted!");
|
||||
}
|
||||
MFEM_ABORT("Invalid element id:" << i << "; minimum allowed:" << 0 <<
|
||||
", maximum allowed:" << mesh->GetNE()-1);
|
||||
}
|
||||
|
||||
const FiniteElement *FE =
|
||||
fec->GetFE(mesh->GetElementGeometry(i), GetElementOrderImpl(i));
|
||||
@@ -3205,9 +3248,10 @@ FiniteElementSpace::~FiniteElementSpace()
|
||||
|
||||
void FiniteElementSpace::Destroy()
|
||||
{
|
||||
delete cR;
|
||||
delete cR_hp;
|
||||
delete cP;
|
||||
R_transpose.reset();
|
||||
cR.reset();
|
||||
cR_hp.reset();
|
||||
cP.reset();
|
||||
Th.Clear();
|
||||
L2E_nat.Clear();
|
||||
L2E_lex.Clear();
|
||||
@@ -3220,6 +3264,7 @@ void FiniteElementSpace::Destroy()
|
||||
{
|
||||
delete x.second;
|
||||
}
|
||||
L2F.clear();
|
||||
for (int i = 0; i < E2IFQ_array.Size(); i++)
|
||||
{
|
||||
delete E2IFQ_array[i];
|
||||
@@ -3319,14 +3364,14 @@ void FiniteElementSpace::GetTrueTransferOperator(
|
||||
switch (RP_case)
|
||||
{
|
||||
case 1:
|
||||
T.Reset(new ProductOperator(cR, T.Ptr(), false, owner));
|
||||
T.Reset(new ProductOperator(cR.get(), T.Ptr(), false, owner));
|
||||
break;
|
||||
case 2:
|
||||
T.Reset(new ProductOperator(T.Ptr(), coarse_P, owner, false));
|
||||
break;
|
||||
case 3:
|
||||
T.Reset(new TripleProductOperator(
|
||||
cR, T.Ptr(), coarse_P, false, owner, false));
|
||||
cR.get(), T.Ptr(), coarse_P, false, owner, false));
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -3444,7 +3489,7 @@ void FiniteElementSpace::Update(bool want_transform)
|
||||
if (cP && cR)
|
||||
{
|
||||
Th.SetOperatorOwner(false);
|
||||
Th.Reset(new TripleProductOperator(cP, cR, Th.Ptr(),
|
||||
Th.Reset(new TripleProductOperator(cP.get(), cR.get(), Th.Ptr(),
|
||||
false, false, true));
|
||||
}
|
||||
break;
|
||||
|
||||
+30
-11
@@ -214,7 +214,7 @@ class FaceQuadratureInterpolator;
|
||||
@par
|
||||
Clearly the notion of a @b vdof is relevant in each of the three contexts
|
||||
mentioned above so extra care must be taken whenever @b vdim != 1 to ensure
|
||||
that the @b edof, @b ldof, or @b tdof is being interpretted correctly.
|
||||
that the @b edof, @b ldof, or @b tdof is being interpreted correctly.
|
||||
*/
|
||||
class FiniteElementSpace
|
||||
{
|
||||
@@ -277,12 +277,14 @@ protected:
|
||||
/** Matrix representing the prolongation from the global conforming dofs to
|
||||
a set of intermediate partially conforming dofs, e.g. the dofs associated
|
||||
with a "cut" space on a non-conforming mesh. */
|
||||
mutable SparseMatrix *cP; // owned
|
||||
mutable std::unique_ptr<SparseMatrix> cP;
|
||||
/// Conforming restriction matrix such that cR.cP=I.
|
||||
mutable SparseMatrix *cR; // owned
|
||||
mutable std::unique_ptr<SparseMatrix> cR;
|
||||
/// A version of the conforming restriction matrix for variable-order spaces.
|
||||
mutable SparseMatrix *cR_hp; // owned
|
||||
mutable std::unique_ptr<SparseMatrix> cR_hp;
|
||||
mutable bool cP_is_set;
|
||||
/// Operator computing the action of the transpose of the restriction.
|
||||
mutable std::unique_ptr<Operator> R_transpose;
|
||||
|
||||
/// Transformation to apply to GridFunctions after space Update().
|
||||
OperatorHandle Th;
|
||||
@@ -592,10 +594,17 @@ public:
|
||||
{ return GetConformingProlongation(); }
|
||||
|
||||
/// Return an operator that performs the transpose of GetRestrictionOperator
|
||||
/** The returned operator is owned by the FiniteElementSpace. In serial this
|
||||
is the same as GetProlongationMatrix() */
|
||||
virtual const Operator *GetRestrictionTransposeOperator() const
|
||||
{ return GetConformingProlongation(); }
|
||||
/** The returned operator is owned by the FiniteElementSpace.
|
||||
|
||||
For a serial conforming space, this returns NULL, indicating the identity
|
||||
operator.
|
||||
|
||||
For a parallel conforming space, this will return a matrix-free
|
||||
(Device)ConformingProlongationOperator.
|
||||
|
||||
For a non-conforming mesh this will return a TransposeOperator wrapping
|
||||
the restriction matrix. */
|
||||
const Operator *GetRestrictionTransposeOperator() const;
|
||||
|
||||
/// An abstract operator that performs the same action as GetRestrictionMatrix
|
||||
/** In some cases this is an optimized matrix-free implementation. The
|
||||
@@ -811,6 +820,11 @@ public:
|
||||
virtual DofTransformation *GetBdrElementDofs(int bel,
|
||||
Array<int> &dofs) const;
|
||||
|
||||
/** @brief Returns indices of degrees of freedom for NURBS patch index
|
||||
@a patch. Cartesian ordering is used, for the tensor-product degrees of
|
||||
freedom. */
|
||||
void GetPatchDofs(int patch, Array<int> &dofs) const;
|
||||
|
||||
/// @brief Returns the indices of the degrees of freedom for the specified
|
||||
/// face, including the DOFs for the edges and the vertices of the face.
|
||||
///
|
||||
@@ -893,7 +907,7 @@ public:
|
||||
/// changed in the forward mappings by passing a value for @a ndofs which
|
||||
/// differs from that returned by GetNDofs().
|
||||
///
|
||||
/// @note Thse methods, with the exception of VDofToDof(), are designed to
|
||||
/// @note These methods, with the exception of VDofToDof(), are designed to
|
||||
/// produce the correctly encoded values when dof entries are negative,
|
||||
/// see @ref ldof for more on negative dof indices.
|
||||
///
|
||||
@@ -995,7 +1009,7 @@ public:
|
||||
|
||||
/// @brief Returns indices of degrees of freedom for the @a i'th element.
|
||||
/// The returned indices are offsets into an @ref ldof vector with @b vdim
|
||||
/// not necessarily equal to 1. The returned indexes are always ordered
|
||||
/// not necessarily equal to 1. The returned indices are always ordered
|
||||
/// byNODES, irrespective of whether the space is byNODES or byVDIM.
|
||||
/// See also GetElementDofs().
|
||||
///
|
||||
@@ -1024,6 +1038,9 @@ public:
|
||||
/// @note The returned object should NOT be deleted by the caller.
|
||||
DofTransformation *GetBdrElementVDofs(int i, Array<int> &vdofs) const;
|
||||
|
||||
/// Returns indices of degrees of freedom in @a vdofs for NURBS patch @a i.
|
||||
void GetPatchVDofs(int i, Array<int> &vdofs) const;
|
||||
|
||||
/// @brief Returns the indices of the degrees of freedom for the specified
|
||||
/// face, including the DOFs for the edges and the vertices of the face.
|
||||
///
|
||||
@@ -1107,7 +1124,9 @@ public:
|
||||
int GetLocalDofForDof(int i) const { return dof_ldof_array[i]; }
|
||||
|
||||
/** @brief Returns pointer to the FiniteElement in the FiniteElementCollection
|
||||
associated with i'th element in the mesh object. */
|
||||
associated with i'th element in the mesh object.
|
||||
Note: The method has been updated to abort instead of returning NULL for
|
||||
an empty partition. */
|
||||
virtual const FiniteElement *GetFE(int i) const;
|
||||
|
||||
/** @brief Returns pointer to the FiniteElement in the FiniteElementCollection
|
||||
|
||||
+3
-4
@@ -27,7 +27,6 @@
|
||||
#include <iostream>
|
||||
#include <algorithm>
|
||||
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
@@ -341,7 +340,7 @@ int GridFunction::VectorDim() const
|
||||
return fes->GetVDim();
|
||||
}
|
||||
return fes->GetVDim()*std::max(fes->GetMesh()->SpaceDimension(),
|
||||
fe->GetVDim());
|
||||
fe->GetRangeDim());
|
||||
}
|
||||
|
||||
int GridFunction::CurlDim() const
|
||||
@@ -1042,7 +1041,7 @@ void GridFunction::GetVectorValue(ElementTransformation &T,
|
||||
else
|
||||
{
|
||||
int spaceDim = fes->GetMesh()->SpaceDimension();
|
||||
int vdim = std::max(spaceDim, fe->GetVDim());
|
||||
int vdim = std::max(spaceDim, fe->GetRangeDim());
|
||||
DenseMatrix vshape(dof, vdim);
|
||||
fe->CalcVShape(T, vshape);
|
||||
val.SetSize(vdim);
|
||||
@@ -1094,7 +1093,7 @@ void GridFunction::GetVectorValues(ElementTransformation &T,
|
||||
else
|
||||
{
|
||||
int spaceDim = fes->GetMesh()->SpaceDimension();
|
||||
int vdim = std::max(spaceDim, FElem->GetVDim());
|
||||
int vdim = std::max(spaceDim, FElem->GetRangeDim());
|
||||
DenseMatrix vshape(dof, vdim);
|
||||
|
||||
vals.SetSize(vdim, nip);
|
||||
|
||||
+3
-3
@@ -1236,7 +1236,7 @@ void OversetFindPointsGSLIB::FindPoints(const Vector &point_pos,
|
||||
gsl_ref.SetSize(points_cnt * dim);
|
||||
gsl_dist.SetSize(points_cnt);
|
||||
|
||||
auto xvFill = [&](const double *xv_base[], unsigned xv_stride[], int dim)
|
||||
auto xvFill = [&](const double *xv_base[], unsigned xv_stride[])
|
||||
{
|
||||
for (int d = 0; d < dim; d++)
|
||||
{
|
||||
@@ -1256,7 +1256,7 @@ void OversetFindPointsGSLIB::FindPoints(const Vector &point_pos,
|
||||
{
|
||||
const double *xv_base[2];
|
||||
unsigned xv_stride[2];
|
||||
xvFill(xv_base, xv_stride, dim);
|
||||
xvFill(xv_base, xv_stride);
|
||||
findptsms_2(gsl_code.GetData(), sizeof(unsigned int),
|
||||
gsl_proc.GetData(), sizeof(unsigned int),
|
||||
gsl_elem.GetData(), sizeof(unsigned int),
|
||||
@@ -1270,7 +1270,7 @@ void OversetFindPointsGSLIB::FindPoints(const Vector &point_pos,
|
||||
{
|
||||
const double *xv_base[3];
|
||||
unsigned xv_stride[3];
|
||||
xvFill(xv_base, xv_stride, dim);
|
||||
xvFill(xv_base, xv_stride);
|
||||
findptsms_3(gsl_code.GetData(), sizeof(unsigned int),
|
||||
gsl_proc.GetData(), sizeof(unsigned int),
|
||||
gsl_elem.GetData(), sizeof(unsigned int),
|
||||
|
||||
@@ -28,8 +28,8 @@ static void EAConvectionAssemble1D(const int NE,
|
||||
{
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
MFEM_VERIFY(D1D <= MAX_D1D, "");
|
||||
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
|
||||
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
|
||||
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
|
||||
auto B = Reshape(b.Read(), Q1D, D1D);
|
||||
auto G = Reshape(g.Read(), Q1D, D1D);
|
||||
auto D = Reshape(padata.Read(), Q1D, NE);
|
||||
@@ -38,7 +38,7 @@ static void EAConvectionAssemble1D(const int NE,
|
||||
{
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : MAX_Q1D;
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
|
||||
double r_Gi[MQ1];
|
||||
double r_Bj[MQ1];
|
||||
for (int q = 0; q < Q1D; q++)
|
||||
@@ -80,8 +80,8 @@ static void EAConvectionAssemble2D(const int NE,
|
||||
{
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
MFEM_VERIFY(D1D <= MAX_D1D, "");
|
||||
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
|
||||
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
|
||||
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
|
||||
auto B = Reshape(b.Read(), Q1D, D1D);
|
||||
auto G = Reshape(g.Read(), Q1D, D1D);
|
||||
auto D = Reshape(padata.Read(), Q1D, Q1D, 2, NE);
|
||||
@@ -90,8 +90,8 @@ static void EAConvectionAssemble2D(const int NE,
|
||||
{
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
constexpr int MD1 = T_D1D ? T_D1D : MAX_D1D;
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : MAX_Q1D;
|
||||
constexpr int MD1 = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
|
||||
double r_B[MQ1][MD1];
|
||||
double r_G[MQ1][MD1];
|
||||
for (int d = 0; d < D1D; d++)
|
||||
@@ -157,8 +157,8 @@ static void EAConvectionAssemble3D(const int NE,
|
||||
{
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
MFEM_VERIFY(D1D <= MAX_D1D, "");
|
||||
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
|
||||
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
|
||||
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
|
||||
auto B = Reshape(b.Read(), Q1D, D1D);
|
||||
auto G = Reshape(g.Read(), Q1D, D1D);
|
||||
auto D = Reshape(padata.Read(), Q1D, Q1D, Q1D, 3, NE);
|
||||
@@ -167,8 +167,8 @@ static void EAConvectionAssemble3D(const int NE,
|
||||
{
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
constexpr int MD1 = T_D1D ? T_D1D : MAX_D1D;
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : MAX_Q1D;
|
||||
constexpr int MD1 = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
|
||||
double r_B[MQ1][MD1];
|
||||
double r_G[MQ1][MD1];
|
||||
for (int d = 0; d < D1D; d++)
|
||||
|
||||
@@ -203,8 +203,8 @@ void PAConvectionApply2D(const int ne,
|
||||
const int NE = ne;
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
MFEM_VERIFY(D1D <= MAX_D1D, "");
|
||||
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
|
||||
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
|
||||
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
|
||||
auto B = Reshape(b.Read(), Q1D, D1D);
|
||||
auto G = Reshape(g.Read(), Q1D, D1D);
|
||||
auto Bt = Reshape(bt.Read(), D1D, Q1D);
|
||||
@@ -216,8 +216,8 @@ void PAConvectionApply2D(const int ne,
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
// the following variables are evaluated at compile time
|
||||
constexpr int max_D1D = T_D1D ? T_D1D : MAX_D1D;
|
||||
constexpr int max_Q1D = T_Q1D ? T_Q1D : MAX_Q1D;
|
||||
constexpr int max_D1D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
|
||||
constexpr int max_Q1D = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
|
||||
|
||||
double u[max_D1D][max_D1D];
|
||||
for (int dy = 0; dy < D1D; ++dy)
|
||||
@@ -323,8 +323,8 @@ void SmemPAConvectionApply2D(const int ne,
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
constexpr int NBZ = T_NBZ ? T_NBZ : 1;
|
||||
MFEM_VERIFY(D1D <= MAX_D1D, "");
|
||||
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
|
||||
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
|
||||
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
|
||||
auto B = Reshape(b.Read(), Q1D, D1D);
|
||||
auto G = Reshape(g.Read(), Q1D, D1D);
|
||||
auto Bt = Reshape(bt.Read(), D1D, Q1D);
|
||||
@@ -338,8 +338,8 @@ void SmemPAConvectionApply2D(const int ne,
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
// the following variables are evaluated at compile time
|
||||
constexpr int NBZ = T_NBZ ? T_NBZ : 1;
|
||||
constexpr int max_D1D = T_D1D ? T_D1D : MAX_D1D;
|
||||
constexpr int max_Q1D = T_Q1D ? T_Q1D : MAX_Q1D;
|
||||
constexpr int max_D1D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
|
||||
constexpr int max_Q1D = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
|
||||
// constexpr int MDQ = (max_Q1D > max_D1D) ? max_Q1D : max_D1D;
|
||||
MFEM_SHARED double u[NBZ][max_D1D][max_D1D];
|
||||
MFEM_FOREACH_THREAD(dy,y,D1D)
|
||||
@@ -450,8 +450,8 @@ void PAConvectionApply3D(const int ne,
|
||||
const int NE = ne;
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
MFEM_VERIFY(D1D <= MAX_D1D, "");
|
||||
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
|
||||
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
|
||||
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
|
||||
auto B = Reshape(b.Read(), Q1D, D1D);
|
||||
auto G = Reshape(g.Read(), Q1D, D1D);
|
||||
auto Bt = Reshape(bt.Read(), D1D, Q1D);
|
||||
@@ -463,8 +463,8 @@ void PAConvectionApply3D(const int ne,
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
// the following variables are evaluated at compile time
|
||||
constexpr int max_D1D = T_D1D ? T_D1D : MAX_D1D;
|
||||
constexpr int max_Q1D = T_Q1D ? T_Q1D : MAX_Q1D;
|
||||
constexpr int max_D1D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
|
||||
constexpr int max_Q1D = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
|
||||
|
||||
double u[max_D1D][max_D1D][max_D1D];
|
||||
for (int dz = 0; dz < D1D; ++dz)
|
||||
@@ -631,8 +631,8 @@ void SmemPAConvectionApply3D(const int ne,
|
||||
const int NE = ne;
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
MFEM_VERIFY(D1D <= MAX_D1D, "");
|
||||
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
|
||||
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
|
||||
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
|
||||
auto B = Reshape(b.Read(), Q1D, D1D);
|
||||
auto G = Reshape(g.Read(), Q1D, D1D);
|
||||
auto Bt = Reshape(bt.Read(), D1D, Q1D);
|
||||
@@ -644,8 +644,8 @@ void SmemPAConvectionApply3D(const int ne,
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
// the following variables are evaluated at compile time
|
||||
constexpr int max_D1D = T_D1D ? T_D1D : MAX_D1D;
|
||||
constexpr int max_Q1D = T_Q1D ? T_Q1D : MAX_Q1D;
|
||||
constexpr int max_D1D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
|
||||
constexpr int max_Q1D = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
|
||||
constexpr int max_DQ = (max_Q1D > max_D1D) ? max_Q1D : max_D1D;
|
||||
MFEM_SHARED double sm0[max_DQ*max_DQ*max_DQ];
|
||||
MFEM_SHARED double sm1[max_DQ*max_DQ*max_DQ];
|
||||
@@ -835,8 +835,8 @@ void PAConvectionApplyT2D(const int ne,
|
||||
const int NE = ne;
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
MFEM_VERIFY(D1D <= MAX_D1D, "");
|
||||
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
|
||||
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
|
||||
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
|
||||
auto B = Reshape(b.Read(), Q1D, D1D);
|
||||
auto Bt = Reshape(bt.Read(), D1D, Q1D);
|
||||
auto Gt = Reshape(gt.Read(), D1D, Q1D);
|
||||
@@ -848,8 +848,8 @@ void PAConvectionApplyT2D(const int ne,
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
// the following variables are evaluated at compile time
|
||||
constexpr int max_D1D = T_D1D ? T_D1D : MAX_D1D;
|
||||
constexpr int max_Q1D = T_Q1D ? T_Q1D : MAX_Q1D;
|
||||
constexpr int max_D1D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
|
||||
constexpr int max_Q1D = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
|
||||
|
||||
double u[max_D1D][max_D1D];
|
||||
for (int dy = 0; dy < D1D; ++dy)
|
||||
@@ -951,8 +951,8 @@ void SmemPAConvectionApplyT2D(const int ne,
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
constexpr int NBZ = T_NBZ ? T_NBZ : 1;
|
||||
MFEM_VERIFY(D1D <= MAX_D1D, "");
|
||||
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
|
||||
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
|
||||
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
|
||||
auto B = Reshape(b.Read(), Q1D, D1D);
|
||||
auto Bt = Reshape(bt.Read(), D1D, Q1D);
|
||||
auto Gt = Reshape(gt.Read(), D1D, Q1D);
|
||||
@@ -966,8 +966,8 @@ void SmemPAConvectionApplyT2D(const int ne,
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
// the following variables are evaluated at compile time
|
||||
constexpr int NBZ = T_NBZ ? T_NBZ : 1;
|
||||
constexpr int max_D1D = T_D1D ? T_D1D : MAX_D1D;
|
||||
constexpr int max_Q1D = T_Q1D ? T_Q1D : MAX_Q1D;
|
||||
constexpr int max_D1D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
|
||||
constexpr int max_Q1D = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
|
||||
MFEM_SHARED double u[NBZ][max_D1D][max_D1D];
|
||||
MFEM_FOREACH_THREAD(dy,y,D1D)
|
||||
{
|
||||
@@ -1073,8 +1073,8 @@ void PAConvectionApplyT3D(const int ne,
|
||||
const int NE = ne;
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
MFEM_VERIFY(D1D <= MAX_D1D, "");
|
||||
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
|
||||
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
|
||||
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
|
||||
auto B = Reshape(b.Read(), Q1D, D1D);
|
||||
auto Bt = Reshape(bt.Read(), D1D, Q1D);
|
||||
auto Gt = Reshape(gt.Read(), D1D, Q1D);
|
||||
@@ -1086,8 +1086,8 @@ void PAConvectionApplyT3D(const int ne,
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
// the following variables are evaluated at compile time
|
||||
constexpr int max_D1D = T_D1D ? T_D1D : MAX_D1D;
|
||||
constexpr int max_Q1D = T_Q1D ? T_Q1D : MAX_Q1D;
|
||||
constexpr int max_D1D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
|
||||
constexpr int max_Q1D = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
|
||||
|
||||
double u[max_D1D][max_D1D][max_D1D];
|
||||
for (int dz = 0; dz < D1D; ++dz)
|
||||
@@ -1249,8 +1249,8 @@ void SmemPAConvectionApplyT3D(const int ne,
|
||||
const int NE = ne;
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
MFEM_VERIFY(D1D <= MAX_D1D, "");
|
||||
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
|
||||
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
|
||||
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
|
||||
auto B = Reshape(b.Read(), Q1D, D1D);
|
||||
auto Bt = Reshape(bt.Read(), D1D, Q1D);
|
||||
auto Gt = Reshape(gt.Read(), D1D, Q1D);
|
||||
@@ -1262,8 +1262,8 @@ void SmemPAConvectionApplyT3D(const int ne,
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
// the following variables are evaluated at compile time
|
||||
constexpr int max_D1D = T_D1D ? T_D1D : MAX_D1D;
|
||||
constexpr int max_Q1D = T_Q1D ? T_Q1D : MAX_Q1D;
|
||||
constexpr int max_D1D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
|
||||
constexpr int max_Q1D = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
|
||||
constexpr int max_DQ = (max_Q1D > max_D1D) ? max_Q1D : max_D1D;
|
||||
MFEM_SHARED double sm0[3*max_DQ*max_DQ*max_DQ];
|
||||
MFEM_SHARED double sm1[3*max_DQ*max_DQ*max_DQ];
|
||||
|
||||
@@ -83,8 +83,8 @@ static void EADGTraceAssemble2DInt(const int NF,
|
||||
{
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
MFEM_VERIFY(D1D <= MAX_D1D, "");
|
||||
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
|
||||
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
|
||||
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
|
||||
auto B = Reshape(basis.Read(), Q1D, D1D);
|
||||
auto D = Reshape(padata.Read(), Q1D, 2, 2, NF);
|
||||
auto A_int = Reshape(eadata_int.ReadWrite(), D1D, D1D, 2, NF);
|
||||
@@ -138,8 +138,8 @@ static void EADGTraceAssemble2DBdr(const int NF,
|
||||
{
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
MFEM_VERIFY(D1D <= MAX_D1D, "");
|
||||
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
|
||||
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
|
||||
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
|
||||
auto B = Reshape(basis.Read(), Q1D, D1D);
|
||||
auto D = Reshape(padata.Read(), Q1D, 2, 2, NF);
|
||||
auto A_bdr = Reshape(eadata_bdr.ReadWrite(), D1D, D1D, NF);
|
||||
@@ -181,8 +181,8 @@ static void EADGTraceAssemble3DInt(const int NF,
|
||||
{
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
MFEM_VERIFY(D1D <= MAX_D1D, "");
|
||||
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
|
||||
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
|
||||
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
|
||||
auto B = Reshape(basis.Read(), Q1D, D1D);
|
||||
auto D = Reshape(padata.Read(), Q1D, Q1D, 2, 2, NF);
|
||||
auto A_int = Reshape(eadata_int.ReadWrite(), D1D, D1D, D1D, D1D, 2, NF);
|
||||
@@ -191,8 +191,8 @@ static void EADGTraceAssemble3DInt(const int NF,
|
||||
{
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
constexpr int MD1 = T_D1D ? T_D1D : MAX_D1D;
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : MAX_Q1D;
|
||||
constexpr int MD1 = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
|
||||
double r_B[MQ1][MD1];
|
||||
for (int d = 0; d < D1D; d++)
|
||||
{
|
||||
@@ -278,8 +278,8 @@ static void EADGTraceAssemble3DBdr(const int NF,
|
||||
{
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
MFEM_VERIFY(D1D <= MAX_D1D, "");
|
||||
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
|
||||
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
|
||||
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
|
||||
auto B = Reshape(basis.Read(), Q1D, D1D);
|
||||
auto D = Reshape(padata.Read(), Q1D, Q1D, 2, 2, NF);
|
||||
auto A_bdr = Reshape(eadata_bdr.ReadWrite(), D1D, D1D, D1D, D1D, NF);
|
||||
@@ -287,8 +287,8 @@ static void EADGTraceAssemble3DBdr(const int NF,
|
||||
{
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
constexpr int MD1 = T_D1D ? T_D1D : MAX_D1D;
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : MAX_Q1D;
|
||||
constexpr int MD1 = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
|
||||
double r_B[MQ1][MD1];
|
||||
for (int d = 0; d < D1D; d++)
|
||||
{
|
||||
|
||||
@@ -258,8 +258,8 @@ void PADGTraceApply2D(const int NF,
|
||||
const int VDIM = 1;
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
MFEM_VERIFY(D1D <= MAX_D1D, "");
|
||||
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
|
||||
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
|
||||
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
|
||||
auto B = Reshape(b.Read(), Q1D, D1D);
|
||||
auto Bt = Reshape(bt.Read(), D1D, Q1D);
|
||||
auto op = Reshape(op_.Read(), Q1D, 2, 2, NF);
|
||||
@@ -272,8 +272,8 @@ void PADGTraceApply2D(const int NF,
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
// the following variables are evaluated at compile time
|
||||
constexpr int max_D1D = T_D1D ? T_D1D : MAX_D1D;
|
||||
constexpr int max_Q1D = T_Q1D ? T_Q1D : MAX_Q1D;
|
||||
constexpr int max_D1D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
|
||||
constexpr int max_Q1D = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
|
||||
double u0[max_D1D][VDIM];
|
||||
double u1[max_D1D][VDIM];
|
||||
for (int d = 0; d < D1D; d++)
|
||||
@@ -349,8 +349,8 @@ void PADGTraceApply3D(const int NF,
|
||||
const int VDIM = 1;
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
MFEM_VERIFY(D1D <= MAX_D1D, "");
|
||||
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
|
||||
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
|
||||
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
|
||||
auto B = Reshape(b.Read(), Q1D, D1D);
|
||||
auto Bt = Reshape(bt.Read(), D1D, Q1D);
|
||||
auto op = Reshape(op_.Read(), Q1D, Q1D, 2, 2, NF);
|
||||
@@ -363,8 +363,8 @@ void PADGTraceApply3D(const int NF,
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
// the following variables are evaluated at compile time
|
||||
constexpr int max_D1D = T_D1D ? T_D1D : MAX_D1D;
|
||||
constexpr int max_Q1D = T_Q1D ? T_Q1D : MAX_Q1D;
|
||||
constexpr int max_D1D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
|
||||
constexpr int max_Q1D = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
|
||||
double u0[max_D1D][max_D1D][VDIM];
|
||||
double u1[max_D1D][max_D1D][VDIM];
|
||||
for (int d1 = 0; d1 < D1D; d1++)
|
||||
@@ -494,8 +494,8 @@ void SmemPADGTraceApply3D(const int NF,
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
constexpr int NBZ = T_NBZ ? T_NBZ : 1;
|
||||
MFEM_VERIFY(D1D <= MAX_D1D, "");
|
||||
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
|
||||
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
|
||||
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
|
||||
auto B = Reshape(b.Read(), Q1D, D1D);
|
||||
auto Bt = Reshape(bt.Read(), D1D, Q1D);
|
||||
auto op = Reshape(op_.Read(), Q1D, Q1D, 2, 2, NF);
|
||||
@@ -509,8 +509,8 @@ void SmemPADGTraceApply3D(const int NF,
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
// the following variables are evaluated at compile time
|
||||
constexpr int NBZ = T_NBZ ? T_NBZ : 1;
|
||||
constexpr int max_D1D = T_D1D ? T_D1D : MAX_D1D;
|
||||
constexpr int max_Q1D = T_Q1D ? T_Q1D : MAX_Q1D;
|
||||
constexpr int max_D1D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
|
||||
constexpr int max_Q1D = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
|
||||
MFEM_SHARED double u0[NBZ][max_D1D][max_D1D];
|
||||
MFEM_SHARED double u1[NBZ][max_D1D][max_D1D];
|
||||
MFEM_FOREACH_THREAD(d1,x,D1D)
|
||||
@@ -659,8 +659,8 @@ void PADGTraceApplyTranspose2D(const int NF,
|
||||
const int VDIM = 1;
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
MFEM_VERIFY(D1D <= MAX_D1D, "");
|
||||
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
|
||||
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
|
||||
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
|
||||
auto B = Reshape(b.Read(), Q1D, D1D);
|
||||
auto Bt = Reshape(bt.Read(), D1D, Q1D);
|
||||
auto op = Reshape(op_.Read(), Q1D, 2, 2, NF);
|
||||
@@ -673,8 +673,8 @@ void PADGTraceApplyTranspose2D(const int NF,
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
// the following variables are evaluated at compile time
|
||||
constexpr int max_D1D = T_D1D ? T_D1D : MAX_D1D;
|
||||
constexpr int max_Q1D = T_Q1D ? T_Q1D : MAX_Q1D;
|
||||
constexpr int max_D1D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
|
||||
constexpr int max_Q1D = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
|
||||
double u0[max_D1D][VDIM];
|
||||
double u1[max_D1D][VDIM];
|
||||
for (int d = 0; d < D1D; d++)
|
||||
@@ -755,8 +755,8 @@ void PADGTraceApplyTranspose3D(const int NF,
|
||||
const int VDIM = 1;
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
MFEM_VERIFY(D1D <= MAX_D1D, "");
|
||||
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
|
||||
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
|
||||
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
|
||||
auto B = Reshape(b.Read(), Q1D, D1D);
|
||||
auto Bt = Reshape(bt.Read(), D1D, Q1D);
|
||||
auto op = Reshape(op_.Read(), Q1D, Q1D, 2, 2, NF);
|
||||
@@ -769,8 +769,8 @@ void PADGTraceApplyTranspose3D(const int NF,
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
// the following variables are evaluated at compile time
|
||||
constexpr int max_D1D = T_D1D ? T_D1D : MAX_D1D;
|
||||
constexpr int max_Q1D = T_Q1D ? T_Q1D : MAX_Q1D;
|
||||
constexpr int max_D1D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
|
||||
constexpr int max_Q1D = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
|
||||
double u0[max_D1D][max_D1D][VDIM];
|
||||
double u1[max_D1D][max_D1D][VDIM];
|
||||
for (int d1 = 0; d1 < D1D; d1++)
|
||||
@@ -911,8 +911,8 @@ void SmemPADGTraceApplyTranspose3D(const int NF,
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
constexpr int NBZ = T_NBZ ? T_NBZ : 1;
|
||||
MFEM_VERIFY(D1D <= MAX_D1D, "");
|
||||
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
|
||||
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
|
||||
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
|
||||
auto B = Reshape(b.Read(), Q1D, D1D);
|
||||
auto Bt = Reshape(bt.Read(), D1D, Q1D);
|
||||
auto op = Reshape(op_.Read(), Q1D, Q1D, 2, 2, NF);
|
||||
@@ -926,8 +926,8 @@ void SmemPADGTraceApplyTranspose3D(const int NF,
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
// the following variables are evaluated at compile time
|
||||
constexpr int NBZ = T_NBZ ? T_NBZ : 1;
|
||||
constexpr int max_D1D = T_D1D ? T_D1D : MAX_D1D;
|
||||
constexpr int max_Q1D = T_Q1D ? T_Q1D : MAX_Q1D;
|
||||
constexpr int max_D1D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
|
||||
constexpr int max_Q1D = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
|
||||
MFEM_SHARED double u0[NBZ][max_D1D][max_D1D];
|
||||
MFEM_SHARED double u1[NBZ][max_D1D][max_D1D];
|
||||
MFEM_FOREACH_THREAD(d1,x,D1D)
|
||||
|
||||
@@ -28,8 +28,8 @@ static void EADiffusionAssemble1D(const int NE,
|
||||
{
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
MFEM_VERIFY(D1D <= MAX_D1D, "");
|
||||
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
|
||||
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
|
||||
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
|
||||
auto G = Reshape(g.Read(), Q1D, D1D);
|
||||
auto D = Reshape(padata.Read(), Q1D, NE);
|
||||
auto A = Reshape(eadata.ReadWrite(), D1D, D1D, NE);
|
||||
@@ -37,7 +37,7 @@ static void EADiffusionAssemble1D(const int NE,
|
||||
{
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : MAX_Q1D;
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
|
||||
double r_Gi[MQ1];
|
||||
double r_Gj[MQ1];
|
||||
for (int q = 0; q < Q1D; q++)
|
||||
@@ -79,8 +79,8 @@ static void EADiffusionAssemble2D(const int NE,
|
||||
{
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
MFEM_VERIFY(D1D <= MAX_D1D, "");
|
||||
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
|
||||
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
|
||||
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
|
||||
auto B = Reshape(b.Read(), Q1D, D1D);
|
||||
auto G = Reshape(g.Read(), Q1D, D1D);
|
||||
auto D = Reshape(padata.Read(), Q1D, Q1D, 3, NE);
|
||||
@@ -89,8 +89,8 @@ static void EADiffusionAssemble2D(const int NE,
|
||||
{
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
constexpr int MD1 = T_D1D ? T_D1D : MAX_D1D;
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : MAX_Q1D;
|
||||
constexpr int MD1 = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
|
||||
double r_B[MQ1][MD1];
|
||||
double r_G[MQ1][MD1];
|
||||
for (int d = 0; d < D1D; d++)
|
||||
@@ -156,8 +156,8 @@ static void EADiffusionAssemble3D(const int NE,
|
||||
{
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
MFEM_VERIFY(D1D <= MAX_D1D, "");
|
||||
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
|
||||
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
|
||||
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
|
||||
auto B = Reshape(b.Read(), Q1D, D1D);
|
||||
auto G = Reshape(g.Read(), Q1D, D1D);
|
||||
auto D = Reshape(padata.Read(), Q1D, Q1D, Q1D, 6, NE);
|
||||
@@ -166,8 +166,8 @@ static void EADiffusionAssemble3D(const int NE,
|
||||
{
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
constexpr int MD1 = T_D1D ? T_D1D : MAX_D1D;
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : MAX_Q1D;
|
||||
constexpr int MD1 = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
|
||||
double r_B[MQ1][MD1];
|
||||
double r_G[MQ1][MD1];
|
||||
for (int d = 0; d < D1D; d++)
|
||||
|
||||
@@ -98,8 +98,8 @@ inline void PADiffusionDiagonal2D(const int NE,
|
||||
{
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
MFEM_VERIFY(D1D <= MAX_D1D, "");
|
||||
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
|
||||
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
|
||||
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
|
||||
auto B = Reshape(b.Read(), Q1D, D1D);
|
||||
auto G = Reshape(g.Read(), Q1D, D1D);
|
||||
// note the different shape for D, if this is a symmetric matrix we only
|
||||
@@ -110,8 +110,8 @@ inline void PADiffusionDiagonal2D(const int NE,
|
||||
{
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
constexpr int MD1 = T_D1D ? T_D1D : MAX_D1D;
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : MAX_Q1D;
|
||||
constexpr int MD1 = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
|
||||
// gradphi \cdot Q \gradphi has four terms
|
||||
double QD0[MQ1][MD1];
|
||||
double QD1[MQ1][MD1];
|
||||
@@ -165,10 +165,10 @@ inline void SmemPADiffusionDiagonal2D(const int NE,
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
constexpr int NBZ = T_NBZ ? T_NBZ : 1;
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : MAX_Q1D;
|
||||
constexpr int MD1 = T_D1D ? T_D1D : MAX_D1D;
|
||||
MFEM_VERIFY(D1D <= MD1, "");
|
||||
MFEM_VERIFY(Q1D <= MQ1, "");
|
||||
const int max_q1d = T_Q1D ? T_Q1D : DeviceDofQuadLimits::Get().MAX_Q1D;
|
||||
const int max_d1d = T_D1D ? T_D1D : DeviceDofQuadLimits::Get().MAX_D1D;
|
||||
MFEM_VERIFY(D1D <= max_d1d, "");
|
||||
MFEM_VERIFY(Q1D <= max_q1d, "");
|
||||
auto b = Reshape(b_.Read(), Q1D, D1D);
|
||||
auto g = Reshape(g_.Read(), Q1D, D1D);
|
||||
auto D = Reshape(d_.Read(), Q1D*Q1D, symmetric ? 3 : 4, NE);
|
||||
@@ -179,8 +179,8 @@ inline void SmemPADiffusionDiagonal2D(const int NE,
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
constexpr int NBZ = T_NBZ ? T_NBZ : 1;
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : MAX_Q1D;
|
||||
constexpr int MD1 = T_D1D ? T_D1D : MAX_D1D;
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
|
||||
constexpr int MD1 = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
|
||||
MFEM_SHARED double BG[2][MQ1*MD1];
|
||||
double (*B)[MD1] = (double (*)[MD1]) (BG+0);
|
||||
double (*G)[MD1] = (double (*)[MD1]) (BG+1);
|
||||
@@ -260,10 +260,10 @@ inline void PADiffusionDiagonal3D(const int NE,
|
||||
constexpr int DIM = 3;
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : MAX_Q1D;
|
||||
constexpr int MD1 = T_D1D ? T_D1D : MAX_D1D;
|
||||
MFEM_VERIFY(D1D <= MD1, "");
|
||||
MFEM_VERIFY(Q1D <= MQ1, "");
|
||||
const int max_q1d = T_Q1D ? T_Q1D : DeviceDofQuadLimits::Get().MAX_Q1D;
|
||||
const int max_d1d = T_D1D ? T_D1D : DeviceDofQuadLimits::Get().MAX_D1D;
|
||||
MFEM_VERIFY(D1D <= max_d1d, "");
|
||||
MFEM_VERIFY(Q1D <= max_q1d, "");
|
||||
auto B = Reshape(b.Read(), Q1D, D1D);
|
||||
auto G = Reshape(g.Read(), Q1D, D1D);
|
||||
auto Q = Reshape(d.Read(), Q1D*Q1D*Q1D, symmetric ? 6 : 9, NE);
|
||||
@@ -272,8 +272,8 @@ inline void PADiffusionDiagonal3D(const int NE,
|
||||
{
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
constexpr int MD1 = T_D1D ? T_D1D : MAX_D1D;
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : MAX_Q1D;
|
||||
constexpr int MD1 = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
|
||||
double QQD[MQ1][MQ1][MD1];
|
||||
double QDD[MQ1][MD1][MD1];
|
||||
for (int i = 0; i < DIM; ++i)
|
||||
@@ -361,10 +361,10 @@ inline void SmemPADiffusionDiagonal3D(const int NE,
|
||||
constexpr int DIM = 3;
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : MAX_Q1D;
|
||||
constexpr int MD1 = T_D1D ? T_D1D : MAX_D1D;
|
||||
MFEM_VERIFY(D1D <= MD1, "");
|
||||
MFEM_VERIFY(Q1D <= MQ1, "");
|
||||
const int max_q1d = T_Q1D ? T_Q1D : DeviceDofQuadLimits::Get().MAX_Q1D;
|
||||
const int max_d1d = T_D1D ? T_D1D : DeviceDofQuadLimits::Get().MAX_D1D;
|
||||
MFEM_VERIFY(D1D <= max_d1d, "");
|
||||
MFEM_VERIFY(Q1D <= max_q1d, "");
|
||||
auto b = Reshape(b_.Read(), Q1D, D1D);
|
||||
auto g = Reshape(g_.Read(), Q1D, D1D);
|
||||
auto D = Reshape(d_.Read(), Q1D*Q1D*Q1D, symmetric ? 6 : 9, NE);
|
||||
@@ -374,8 +374,8 @@ inline void SmemPADiffusionDiagonal3D(const int NE,
|
||||
const int tidz = MFEM_THREAD_ID(z);
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : MAX_Q1D;
|
||||
constexpr int MD1 = T_D1D ? T_D1D : MAX_D1D;
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
|
||||
constexpr int MD1 = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
|
||||
MFEM_SHARED double BG[2][MQ1*MD1];
|
||||
double (*B)[MD1] = (double (*)[MD1]) (BG+0);
|
||||
double (*G)[MD1] = (double (*)[MD1]) (BG+1);
|
||||
@@ -521,8 +521,8 @@ inline void PADiffusionApply2D(const int NE,
|
||||
{
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
MFEM_VERIFY(D1D <= MAX_D1D, "");
|
||||
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
|
||||
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
|
||||
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
|
||||
auto B = Reshape(b_.Read(), Q1D, D1D);
|
||||
auto G = Reshape(g_.Read(), Q1D, D1D);
|
||||
auto Bt = Reshape(bt_.Read(), D1D, Q1D);
|
||||
@@ -535,8 +535,8 @@ inline void PADiffusionApply2D(const int NE,
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
// the following variables are evaluated at compile time
|
||||
constexpr int max_D1D = T_D1D ? T_D1D : MAX_D1D;
|
||||
constexpr int max_Q1D = T_Q1D ? T_Q1D : MAX_Q1D;
|
||||
constexpr int max_D1D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
|
||||
constexpr int max_Q1D = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
|
||||
|
||||
double grad[max_Q1D][max_Q1D][2];
|
||||
for (int qy = 0; qy < Q1D; ++qy)
|
||||
@@ -642,10 +642,10 @@ inline void SmemPADiffusionApply2D(const int NE,
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
constexpr int NBZ = T_NBZ ? T_NBZ : 1;
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : MAX_Q1D;
|
||||
constexpr int MD1 = T_D1D ? T_D1D : MAX_D1D;
|
||||
MFEM_VERIFY(D1D <= MD1, "");
|
||||
MFEM_VERIFY(Q1D <= MQ1, "");
|
||||
const int max_q1d = T_Q1D ? T_Q1D : DeviceDofQuadLimits::Get().MAX_Q1D;
|
||||
const int max_d1d = T_D1D ? T_D1D : DeviceDofQuadLimits::Get().MAX_D1D;
|
||||
MFEM_VERIFY(D1D <= max_d1d, "");
|
||||
MFEM_VERIFY(Q1D <= max_q1d, "");
|
||||
auto b = Reshape(b_.Read(), Q1D, D1D);
|
||||
auto g = Reshape(g_.Read(), Q1D, D1D);
|
||||
auto D = Reshape(d_.Read(), Q1D*Q1D, symmetric ? 3 : 4, NE);
|
||||
@@ -657,8 +657,8 @@ inline void SmemPADiffusionApply2D(const int NE,
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
constexpr int NBZ = T_NBZ ? T_NBZ : 1;
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : MAX_Q1D;
|
||||
constexpr int MD1 = T_D1D ? T_D1D : MAX_D1D;
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
|
||||
constexpr int MD1 = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
|
||||
MFEM_SHARED double sBG[2][MQ1*MD1];
|
||||
double (*B)[MD1] = (double (*)[MD1]) (sBG+0);
|
||||
double (*G)[MD1] = (double (*)[MD1]) (sBG+1);
|
||||
@@ -800,8 +800,8 @@ inline void PADiffusionApply3D(const int NE,
|
||||
{
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
MFEM_VERIFY(D1D <= MAX_D1D, "");
|
||||
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
|
||||
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
|
||||
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
|
||||
auto B = Reshape(b.Read(), Q1D, D1D);
|
||||
auto G = Reshape(g.Read(), Q1D, D1D);
|
||||
auto Bt = Reshape(bt.Read(), D1D, Q1D);
|
||||
@@ -813,8 +813,8 @@ inline void PADiffusionApply3D(const int NE,
|
||||
{
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
constexpr int max_D1D = T_D1D ? T_D1D : MAX_D1D;
|
||||
constexpr int max_Q1D = T_Q1D ? T_Q1D : MAX_Q1D;
|
||||
constexpr int max_D1D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
|
||||
constexpr int max_Q1D = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
|
||||
double grad[max_Q1D][max_Q1D][max_Q1D][3];
|
||||
for (int qz = 0; qz < Q1D; ++qz)
|
||||
{
|
||||
@@ -992,10 +992,10 @@ inline void SmemPADiffusionApply3D(const int NE,
|
||||
{
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
constexpr int M1Q = T_Q1D ? T_Q1D : MAX_Q1D;
|
||||
constexpr int M1D = T_D1D ? T_D1D : MAX_D1D;
|
||||
MFEM_VERIFY(D1D <= M1D, "");
|
||||
MFEM_VERIFY(Q1D <= M1Q, "");
|
||||
const int max_q1d = T_Q1D ? T_Q1D : DeviceDofQuadLimits::Get().MAX_Q1D;
|
||||
const int max_d1d = T_D1D ? T_D1D : DeviceDofQuadLimits::Get().MAX_D1D;
|
||||
MFEM_VERIFY(D1D <= max_d1d, "");
|
||||
MFEM_VERIFY(Q1D <= max_q1d, "");
|
||||
auto b = Reshape(b_.Read(), Q1D, D1D);
|
||||
auto g = Reshape(g_.Read(), Q1D, D1D);
|
||||
auto d = Reshape(d_.Read(), Q1D, Q1D, Q1D, symmetric ? 6 : 9, NE);
|
||||
@@ -1005,8 +1005,8 @@ inline void SmemPADiffusionApply3D(const int NE,
|
||||
{
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : MAX_Q1D;
|
||||
constexpr int MD1 = T_D1D ? T_D1D : MAX_D1D;
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
|
||||
constexpr int MD1 = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
|
||||
constexpr int MDQ = (MQ1 > MD1) ? MQ1 : MD1;
|
||||
MFEM_SHARED double sBG[2][MQ1*MD1];
|
||||
double (*B)[MD1] = (double (*)[MD1]) (sBG+0);
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include "../bilininteg.hpp"
|
||||
#include "../gridfunc.hpp"
|
||||
#include "../qfunction.hpp"
|
||||
#include "../../mesh/nurbs.hpp"
|
||||
#include "../ceed/integrators/diffusion/diffusion.hpp"
|
||||
#include "bilininteg_diffusion_kernels.hpp"
|
||||
|
||||
@@ -74,6 +75,29 @@ void DiffusionIntegrator::AssemblePA(const FiniteElementSpace &fes)
|
||||
ir->GetWeights(), geom->J, coeff, pa_data);
|
||||
}
|
||||
|
||||
void DiffusionIntegrator::AssembleNURBSPA(const FiniteElementSpace &fes)
|
||||
{
|
||||
fespace = &fes;
|
||||
Mesh *mesh = fes.GetMesh();
|
||||
dim = mesh->Dimension();
|
||||
MFEM_VERIFY(3 == dim, "Only 3D so far");
|
||||
|
||||
numPatches = mesh->NURBSext->GetNP();
|
||||
for (int p=0; p<numPatches; ++p)
|
||||
{
|
||||
AssemblePatchPA(p, fes);
|
||||
}
|
||||
}
|
||||
|
||||
void DiffusionIntegrator::AssemblePatchPA(const int patch,
|
||||
const FiniteElementSpace &fes)
|
||||
{
|
||||
Mesh *mesh = fes.GetMesh();
|
||||
SetupPatchBasisData(mesh, patch);
|
||||
|
||||
SetupPatchPA(patch, mesh); // For full quadrature, unitWeights = false
|
||||
}
|
||||
|
||||
void DiffusionIntegrator::AssembleDiagonalPA(Vector &diag)
|
||||
{
|
||||
if (DeviceCanUseCeed())
|
||||
@@ -115,4 +139,221 @@ void DiffusionIntegrator::AddMultTransposePA(const Vector &x, Vector &y) const
|
||||
}
|
||||
}
|
||||
|
||||
// This version uses full 1D quadrature rules, taking into account the
|
||||
// minimum interaction between basis functions and integration points.
|
||||
void DiffusionIntegrator::AddMultPatchPA(const int patch, const Vector &x,
|
||||
Vector &y) const
|
||||
{
|
||||
MFEM_VERIFY(3 == dim, "Only 3D so far");
|
||||
|
||||
const Array<int>& Q1D = pQ1D[patch];
|
||||
const Array<int>& D1D = pD1D[patch];
|
||||
|
||||
const std::vector<Array2D<double>>& B = pB[patch];
|
||||
const std::vector<Array2D<double>>& G = pG[patch];
|
||||
|
||||
const IntArrayVar2D& minD = pminD[patch];
|
||||
const IntArrayVar2D& maxD = pmaxD[patch];
|
||||
const IntArrayVar2D& minQ = pminQ[patch];
|
||||
const IntArrayVar2D& maxQ = pmaxQ[patch];
|
||||
|
||||
auto X = Reshape(x.Read(), D1D[0], D1D[1], D1D[2]);
|
||||
auto Y = Reshape(y.ReadWrite(), D1D[0], D1D[1], D1D[2]);
|
||||
|
||||
const auto qd = Reshape(pa_data.Read(), Q1D[0]*Q1D[1]*Q1D[2],
|
||||
(symmetric ? 6 : 9));
|
||||
|
||||
// NOTE: the following is adapted from AssemblePatchMatrix_fullQuadrature
|
||||
std::vector<Array3D<double>> grad(dim);
|
||||
// TODO: Can an optimal order of dimensions be determined, for each patch?
|
||||
Array3D<double> gradXY(3, std::max(Q1D[0], D1D[0]), std::max(Q1D[1], D1D[1]));
|
||||
Array2D<double> gradX(3, std::max(Q1D[0], D1D[0]));
|
||||
|
||||
for (int d=0; d<dim; ++d)
|
||||
{
|
||||
grad[d].SetSize(Q1D[0], Q1D[1], Q1D[2]);
|
||||
|
||||
for (int qz = 0; qz < Q1D[2]; ++qz)
|
||||
{
|
||||
for (int qy = 0; qy < Q1D[1]; ++qy)
|
||||
{
|
||||
for (int qx = 0; qx < Q1D[0]; ++qx)
|
||||
{
|
||||
grad[d](qx,qy,qz) = 0.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int dz = 0; dz < D1D[2]; ++dz)
|
||||
{
|
||||
for (int qy = 0; qy < Q1D[1]; ++qy)
|
||||
{
|
||||
for (int qx = 0; qx < Q1D[0]; ++qx)
|
||||
{
|
||||
for (int d=0; d<dim; ++d)
|
||||
{
|
||||
gradXY(d,qx,qy) = 0.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int dy = 0; dy < D1D[1]; ++dy)
|
||||
{
|
||||
for (int qx = 0; qx < Q1D[0]; ++qx)
|
||||
{
|
||||
gradX(0,qx) = 0.0;
|
||||
gradX(1,qx) = 0.0;
|
||||
}
|
||||
for (int dx = 0; dx < D1D[0]; ++dx)
|
||||
{
|
||||
const double s = X(dx,dy,dz);
|
||||
for (int qx = minD[0][dx]; qx <= maxD[0][dx]; ++qx)
|
||||
{
|
||||
gradX(0,qx) += s * B[0](qx,dx);
|
||||
gradX(1,qx) += s * G[0](qx,dx);
|
||||
}
|
||||
}
|
||||
for (int qy = minD[1][dy]; qy <= maxD[1][dy]; ++qy)
|
||||
{
|
||||
const double wy = B[1](qy,dy);
|
||||
const double wDy = G[1](qy,dy);
|
||||
// This full range of qx values is generally necessary.
|
||||
for (int qx = 0; qx < Q1D[0]; ++qx)
|
||||
{
|
||||
const double wx = gradX(0,qx);
|
||||
const double wDx = gradX(1,qx);
|
||||
gradXY(0,qx,qy) += wDx * wy;
|
||||
gradXY(1,qx,qy) += wx * wDy;
|
||||
gradXY(2,qx,qy) += wx * wy;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int qz = minD[2][dz]; qz <= maxD[2][dz]; ++qz)
|
||||
{
|
||||
const double wz = B[2](qz,dz);
|
||||
const double wDz = G[2](qz,dz);
|
||||
for (int qy = 0; qy < Q1D[1]; ++qy)
|
||||
{
|
||||
for (int qx = 0; qx < Q1D[0]; ++qx)
|
||||
{
|
||||
grad[0](qx,qy,qz) += gradXY(0,qx,qy) * wz;
|
||||
grad[1](qx,qy,qz) += gradXY(1,qx,qy) * wz;
|
||||
grad[2](qx,qy,qz) += gradXY(2,qx,qy) * wDz;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int qz = 0; qz < Q1D[2]; ++qz)
|
||||
{
|
||||
for (int qy = 0; qy < Q1D[1]; ++qy)
|
||||
{
|
||||
for (int qx = 0; qx < Q1D[0]; ++qx)
|
||||
{
|
||||
const int q = qx + ((qy + (qz * Q1D[1])) * Q1D[0]);
|
||||
const double O00 = qd(q,0);
|
||||
const double O01 = qd(q,1);
|
||||
const double O02 = qd(q,2);
|
||||
const double O10 = symmetric ? O01 : qd(q,3);
|
||||
const double O11 = symmetric ? qd(q,3) : qd(q,4);
|
||||
const double O12 = symmetric ? qd(q,4) : qd(q,5);
|
||||
const double O20 = symmetric ? O02 : qd(q,6);
|
||||
const double O21 = symmetric ? O12 : qd(q,7);
|
||||
const double O22 = symmetric ? qd(q,5) : qd(q,8);
|
||||
|
||||
const double grad0 = grad[0](qx,qy,qz);
|
||||
const double grad1 = grad[1](qx,qy,qz);
|
||||
const double grad2 = grad[2](qx,qy,qz);
|
||||
|
||||
grad[0](qx,qy,qz) = (O00*grad0)+(O01*grad1)+(O02*grad2);
|
||||
grad[1](qx,qy,qz) = (O10*grad0)+(O11*grad1)+(O12*grad2);
|
||||
grad[2](qx,qy,qz) = (O20*grad0)+(O21*grad1)+(O22*grad2);
|
||||
} // qx
|
||||
} // qy
|
||||
} // qz
|
||||
|
||||
for (int qz = 0; qz < Q1D[2]; ++qz)
|
||||
{
|
||||
for (int dy = 0; dy < D1D[1]; ++dy)
|
||||
{
|
||||
for (int dx = 0; dx < D1D[0]; ++dx)
|
||||
{
|
||||
for (int d=0; d<3; ++d)
|
||||
{
|
||||
gradXY(d,dx,dy) = 0.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int qy = 0; qy < Q1D[1]; ++qy)
|
||||
{
|
||||
for (int dx = 0; dx < D1D[0]; ++dx)
|
||||
{
|
||||
for (int d=0; d<3; ++d)
|
||||
{
|
||||
gradX(d,dx) = 0.0;
|
||||
}
|
||||
}
|
||||
for (int qx = 0; qx < Q1D[0]; ++qx)
|
||||
{
|
||||
const double gX = grad[0](qx,qy,qz);
|
||||
const double gY = grad[1](qx,qy,qz);
|
||||
const double gZ = grad[2](qx,qy,qz);
|
||||
for (int dx = minQ[0][qx]; dx <= maxQ[0][qx]; ++dx)
|
||||
{
|
||||
const double wx = B[0](qx,dx);
|
||||
const double wDx = G[0](qx,dx);
|
||||
gradX(0,dx) += gX * wDx;
|
||||
gradX(1,dx) += gY * wx;
|
||||
gradX(2,dx) += gZ * wx;
|
||||
}
|
||||
}
|
||||
for (int dy = minQ[1][qy]; dy <= maxQ[1][qy]; ++dy)
|
||||
{
|
||||
const double wy = B[1](qy,dy);
|
||||
const double wDy = G[1](qy,dy);
|
||||
for (int dx = 0; dx < D1D[0]; ++dx)
|
||||
{
|
||||
gradXY(0,dx,dy) += gradX(0,dx) * wy;
|
||||
gradXY(1,dx,dy) += gradX(1,dx) * wDy;
|
||||
gradXY(2,dx,dy) += gradX(2,dx) * wy;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int dz = minQ[2][qz]; dz <= maxQ[2][qz]; ++dz)
|
||||
{
|
||||
const double wz = B[2](qz,dz);
|
||||
const double wDz = G[2](qz,dz);
|
||||
for (int dy = 0; dy < D1D[1]; ++dy)
|
||||
{
|
||||
for (int dx = 0; dx < D1D[0]; ++dx)
|
||||
{
|
||||
Y(dx,dy,dz) +=
|
||||
((gradXY(0,dx,dy) * wz) +
|
||||
(gradXY(1,dx,dy) * wz) +
|
||||
(gradXY(2,dx,dy) * wDz));
|
||||
}
|
||||
}
|
||||
} // dz
|
||||
} // qz
|
||||
}
|
||||
|
||||
void DiffusionIntegrator::AddMultNURBSPA(const Vector &x, Vector &y) const
|
||||
{
|
||||
Vector xp, yp;
|
||||
|
||||
for (int p=0; p<numPatches; ++p)
|
||||
{
|
||||
Array<int> vdofs;
|
||||
fespace->GetPatchVDofs(p, vdofs);
|
||||
|
||||
x.GetSubVector(vdofs, xp);
|
||||
yp.SetSize(vdofs.Size());
|
||||
yp = 0.0;
|
||||
|
||||
AddMultPatchPA(p, xp, yp);
|
||||
|
||||
y.AddElementVector(vdofs, yp);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace mfem
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -229,9 +229,9 @@ static void PAGradientApply2D(const int NE,
|
||||
const int TR_D1D = T_TR_D1D ? T_TR_D1D : tr_d1d;
|
||||
const int TE_D1D = T_TE_D1D ? T_TE_D1D : te_d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
MFEM_VERIFY(TR_D1D <= MAX_D1D, "");
|
||||
MFEM_VERIFY(TE_D1D <= MAX_D1D, "");
|
||||
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
|
||||
MFEM_VERIFY(TR_D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
|
||||
MFEM_VERIFY(TE_D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
|
||||
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
|
||||
auto B = Reshape(b.Read(), Q1D, TR_D1D);
|
||||
auto G = Reshape(g.Read(), Q1D, TR_D1D);
|
||||
auto Bt = Reshape(bt.Read(), TE_D1D, Q1D);
|
||||
@@ -245,8 +245,8 @@ static void PAGradientApply2D(const int NE,
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
const int VDIM = 2;
|
||||
// the following variables are evaluated at compile time
|
||||
constexpr int max_TE_D1D = T_TE_D1D ? T_TE_D1D : MAX_D1D;
|
||||
constexpr int max_Q1D = T_Q1D ? T_Q1D : MAX_Q1D;
|
||||
constexpr int max_TE_D1D = T_TE_D1D ? T_TE_D1D : DofQuadLimits::MAX_D1D;
|
||||
constexpr int max_Q1D = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
|
||||
|
||||
double grad[max_Q1D][max_Q1D][VDIM];
|
||||
for (int qy = 0; qy < Q1D; ++qy)
|
||||
@@ -359,9 +359,9 @@ static void PAGradientApply3D(const int NE,
|
||||
const int TR_D1D = T_TR_D1D ? T_TR_D1D : tr_d1d;
|
||||
const int TE_D1D = T_TE_D1D ? T_TE_D1D : te_d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
MFEM_VERIFY(TR_D1D <= MAX_D1D, "");
|
||||
MFEM_VERIFY(TE_D1D <= MAX_D1D, "");
|
||||
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
|
||||
MFEM_VERIFY(TR_D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
|
||||
MFEM_VERIFY(TE_D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
|
||||
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
|
||||
auto B = Reshape(b.Read(), Q1D, TR_D1D);
|
||||
auto G = Reshape(g.Read(), Q1D, TR_D1D);
|
||||
auto Bt = Reshape(bt.Read(), TE_D1D, Q1D);
|
||||
@@ -375,8 +375,8 @@ static void PAGradientApply3D(const int NE,
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
const int VDIM = 3;
|
||||
// the following variables are evaluated at compile time
|
||||
constexpr int max_TE_D1D = T_TE_D1D ? T_TE_D1D : MAX_D1D;
|
||||
constexpr int max_Q1D = T_Q1D ? T_Q1D : MAX_Q1D;
|
||||
constexpr int max_TE_D1D = T_TE_D1D ? T_TE_D1D : DofQuadLimits::MAX_D1D;
|
||||
constexpr int max_Q1D = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
|
||||
|
||||
double grad[max_Q1D][max_Q1D][max_Q1D][VDIM];
|
||||
for (int qz = 0; qz < Q1D; ++qz)
|
||||
@@ -555,11 +555,11 @@ static void SmemPAGradientApply3D(const int NE,
|
||||
const int TE_D1D = T_TE_D1D ? T_TE_D1D : te_d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
|
||||
MFEM_VERIFY(TR_D1D <= MAX_D1D, "");
|
||||
MFEM_VERIFY(TE_D1D <= MAX_D1D, "");
|
||||
MFEM_VERIFY(TR_D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
|
||||
MFEM_VERIFY(TE_D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
|
||||
MFEM_VERIFY(TR_D1D <= Q1D, "");
|
||||
MFEM_VERIFY(TE_D1D <= Q1D, "");
|
||||
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
|
||||
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
|
||||
|
||||
auto b = Reshape(b_.Read(), Q1D, TR_D1D);
|
||||
auto g = Reshape(g_.Read(), Q1D, TR_D1D);
|
||||
@@ -575,9 +575,9 @@ static void SmemPAGradientApply3D(const int NE,
|
||||
const int D1DR = T_TR_D1D ? T_TR_D1D : tr_d1d;
|
||||
const int D1DE = T_TE_D1D ? T_TE_D1D : te_d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : MAX_Q1D;
|
||||
constexpr int MD1R = T_TR_D1D ? T_TR_D1D : MAX_D1D;
|
||||
constexpr int MD1E = T_TE_D1D ? T_TE_D1D : MAX_D1D;
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
|
||||
constexpr int MD1R = T_TR_D1D ? T_TR_D1D : DofQuadLimits::MAX_D1D;
|
||||
constexpr int MD1E = T_TE_D1D ? T_TE_D1D : DofQuadLimits::MAX_D1D;
|
||||
constexpr int MD1 = MD1E > MD1R ? MD1E : MD1R;
|
||||
constexpr int MDQ = MQ1 > MD1 ? MQ1 : MD1;
|
||||
MFEM_SHARED double sBG[2][MQ1*MD1];
|
||||
|
||||
@@ -26,9 +26,6 @@ void PAHcurlMassAssembleDiagonal2D(const int D1D,
|
||||
const Vector &pa_data,
|
||||
Vector &diag)
|
||||
{
|
||||
constexpr static int VDIM = 2;
|
||||
constexpr static int MAX_Q1D = HCURL_MAX_Q1D;
|
||||
|
||||
auto Bo = Reshape(bo.Read(), Q1D, D1D-1);
|
||||
auto Bc = Reshape(bc.Read(), Q1D, D1D);
|
||||
auto op = Reshape(pa_data.Read(), Q1D, Q1D, symmetric ? 3 : 4, NE);
|
||||
@@ -36,6 +33,9 @@ void PAHcurlMassAssembleDiagonal2D(const int D1D,
|
||||
|
||||
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
|
||||
{
|
||||
constexpr static int VDIM = 2;
|
||||
constexpr static int MAX_Q1D = DofQuadLimits::HCURL_MAX_Q1D;
|
||||
|
||||
int osc = 0;
|
||||
|
||||
for (int c = 0; c < VDIM; ++c) // loop over x, y components
|
||||
@@ -83,11 +83,10 @@ void PAHcurlMassAssembleDiagonal3D(const int D1D,
|
||||
const Vector &pa_data,
|
||||
Vector &diag)
|
||||
{
|
||||
constexpr static int MAX_D1D = HCURL_MAX_D1D;
|
||||
constexpr static int MAX_Q1D = HCURL_MAX_Q1D;
|
||||
|
||||
MFEM_VERIFY(D1D <= MAX_D1D, "Error: D1D > MAX_D1D");
|
||||
MFEM_VERIFY(Q1D <= MAX_Q1D, "Error: Q1D > MAX_Q1D");
|
||||
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().HCURL_MAX_D1D,
|
||||
"Error: D1D > MAX_D1D");
|
||||
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().HCURL_MAX_Q1D,
|
||||
"Error: Q1D > MAX_Q1D");
|
||||
constexpr static int VDIM = 3;
|
||||
|
||||
auto Bo = Reshape(bo.Read(), Q1D, D1D-1);
|
||||
@@ -97,6 +96,8 @@ void PAHcurlMassAssembleDiagonal3D(const int D1D,
|
||||
|
||||
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
|
||||
{
|
||||
constexpr static int MAX_Q1D = DofQuadLimits::HCURL_MAX_Q1D;
|
||||
|
||||
int osc = 0;
|
||||
|
||||
for (int c = 0; c < VDIM; ++c) // loop over x, y, z components
|
||||
@@ -158,10 +159,6 @@ void PAHcurlMassApply2D(const int D1D,
|
||||
const Vector &x,
|
||||
Vector &y)
|
||||
{
|
||||
constexpr static int VDIM = 2;
|
||||
constexpr static int MAX_D1D = HCURL_MAX_D1D;
|
||||
constexpr static int MAX_Q1D = HCURL_MAX_Q1D;
|
||||
|
||||
auto Bo = Reshape(bo.Read(), Q1D, D1D-1);
|
||||
auto Bc = Reshape(bc.Read(), Q1D, D1D);
|
||||
auto Bot = Reshape(bot.Read(), D1D-1, Q1D);
|
||||
@@ -172,6 +169,10 @@ void PAHcurlMassApply2D(const int D1D,
|
||||
|
||||
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
|
||||
{
|
||||
constexpr static int VDIM = 2;
|
||||
constexpr static int MAX_D1D = DofQuadLimits::HCURL_MAX_D1D;
|
||||
constexpr static int MAX_Q1D = DofQuadLimits::HCURL_MAX_Q1D;
|
||||
|
||||
double mass[MAX_Q1D][MAX_Q1D][VDIM];
|
||||
|
||||
for (int qy = 0; qy < Q1D; ++qy)
|
||||
@@ -288,11 +289,10 @@ void PAHcurlMassApply3D(const int D1D,
|
||||
const Vector &x,
|
||||
Vector &y)
|
||||
{
|
||||
constexpr static int MAX_D1D = HCURL_MAX_D1D;
|
||||
constexpr static int MAX_Q1D = HCURL_MAX_Q1D;
|
||||
|
||||
MFEM_VERIFY(D1D <= MAX_D1D, "Error: D1D > MAX_D1D");
|
||||
MFEM_VERIFY(Q1D <= MAX_Q1D, "Error: Q1D > MAX_Q1D");
|
||||
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().HCURL_MAX_D1D,
|
||||
"Error: D1D > MAX_D1D");
|
||||
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().HCURL_MAX_Q1D,
|
||||
"Error: Q1D > MAX_Q1D");
|
||||
constexpr static int VDIM = 3;
|
||||
|
||||
auto Bo = Reshape(bo.Read(), Q1D, D1D-1);
|
||||
@@ -305,6 +305,9 @@ void PAHcurlMassApply3D(const int D1D,
|
||||
|
||||
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
|
||||
{
|
||||
constexpr static int MAX_D1D = DofQuadLimits::HCURL_MAX_D1D;
|
||||
constexpr static int MAX_Q1D = DofQuadLimits::HCURL_MAX_Q1D;
|
||||
|
||||
double mass[MAX_Q1D][MAX_Q1D][MAX_Q1D][VDIM];
|
||||
|
||||
for (int qz = 0; qz < Q1D; ++qz)
|
||||
@@ -604,9 +607,6 @@ void PACurlCurlAssembleDiagonal2D(const int D1D,
|
||||
const Vector &pa_data,
|
||||
Vector &diag)
|
||||
{
|
||||
constexpr static int VDIM = 2;
|
||||
constexpr static int MAX_Q1D = HCURL_MAX_Q1D;
|
||||
|
||||
auto Bo = Reshape(bo.Read(), Q1D, D1D-1);
|
||||
auto Gc = Reshape(gc.Read(), Q1D, D1D);
|
||||
auto op = Reshape(pa_data.Read(), Q1D, Q1D, NE);
|
||||
@@ -614,6 +614,9 @@ void PACurlCurlAssembleDiagonal2D(const int D1D,
|
||||
|
||||
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
|
||||
{
|
||||
constexpr static int VDIM = 2;
|
||||
constexpr static int MAX_Q1D = DofQuadLimits::HCURL_MAX_Q1D;
|
||||
|
||||
int osc = 0;
|
||||
|
||||
for (int c = 0; c < VDIM; ++c) // loop over x, y components
|
||||
@@ -661,9 +664,6 @@ void PACurlCurlApply2D(const int D1D,
|
||||
const Vector &x,
|
||||
Vector &y)
|
||||
{
|
||||
constexpr static int VDIM = 2;
|
||||
constexpr static int MAX_D1D = HCURL_MAX_D1D;
|
||||
constexpr static int MAX_Q1D = HCURL_MAX_Q1D;
|
||||
|
||||
auto Bo = Reshape(bo.Read(), Q1D, D1D-1);
|
||||
auto Bot = Reshape(bot.Read(), D1D-1, Q1D);
|
||||
@@ -675,6 +675,10 @@ void PACurlCurlApply2D(const int D1D,
|
||||
|
||||
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
|
||||
{
|
||||
constexpr static int VDIM = 2;
|
||||
constexpr static int MAX_D1D = DofQuadLimits::HCURL_MAX_D1D;
|
||||
constexpr static int MAX_Q1D = DofQuadLimits::HCURL_MAX_Q1D;
|
||||
|
||||
double curl[MAX_Q1D][MAX_Q1D];
|
||||
|
||||
// curl[qy][qx] will be computed as du_y/dx - du_x/dy
|
||||
@@ -824,9 +828,6 @@ void PAHcurlL2Apply2D(const int D1D,
|
||||
const Vector &x, // trial = H(curl)
|
||||
Vector &y) // test = L2 or H1
|
||||
{
|
||||
constexpr static int VDIM = 2;
|
||||
constexpr static int MAX_D1D = HCURL_MAX_D1D;
|
||||
constexpr static int MAX_Q1D = HCURL_MAX_Q1D;
|
||||
const int H1 = (D1Dtest == D1D);
|
||||
|
||||
MFEM_VERIFY(y.Size() == NE*D1Dtest*D1Dtest, "Test vector of wrong dimension");
|
||||
@@ -841,6 +842,10 @@ void PAHcurlL2Apply2D(const int D1D,
|
||||
|
||||
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
|
||||
{
|
||||
constexpr static int VDIM = 2;
|
||||
constexpr static int MAX_D1D = DofQuadLimits::HCURL_MAX_D1D;
|
||||
constexpr static int MAX_Q1D = DofQuadLimits::HCURL_MAX_Q1D;
|
||||
|
||||
double curl[MAX_Q1D][MAX_Q1D];
|
||||
|
||||
// curl[qy][qx] will be computed as du_y/dx - du_x/dy
|
||||
@@ -939,9 +944,6 @@ void PAHcurlL2ApplyTranspose2D(const int D1D,
|
||||
const Vector &x, // trial = H(curl)
|
||||
Vector &y) // test = L2 or H1
|
||||
{
|
||||
constexpr static int VDIM = 2;
|
||||
constexpr static int MAX_D1D = HCURL_MAX_D1D;
|
||||
constexpr static int MAX_Q1D = HCURL_MAX_Q1D;
|
||||
const int H1 = (D1Dtest == D1D);
|
||||
|
||||
MFEM_VERIFY(x.Size() == NE*D1Dtest*D1Dtest, "Test vector of wrong dimension");
|
||||
@@ -956,6 +958,10 @@ void PAHcurlL2ApplyTranspose2D(const int D1D,
|
||||
|
||||
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
|
||||
{
|
||||
constexpr static int VDIM = 2;
|
||||
constexpr static int MAX_D1D = DofQuadLimits::HCURL_MAX_D1D;
|
||||
constexpr static int MAX_Q1D = DofQuadLimits::HCURL_MAX_Q1D;
|
||||
|
||||
double mass[MAX_Q1D][MAX_Q1D];
|
||||
|
||||
// Zero-order term in L2 or H1 test space
|
||||
|
||||
@@ -59,8 +59,10 @@ inline void SmemPAHcurlMassAssembleDiagonal3D(const int d1d,
|
||||
const Vector &pa_data,
|
||||
Vector &diag)
|
||||
{
|
||||
MFEM_VERIFY(T_D1D || d1d <= HCURL_MAX_D1D, "Error: d1d > HCURL_MAX_D1D");
|
||||
MFEM_VERIFY(T_Q1D || q1d <= HCURL_MAX_Q1D, "Error: q1d > HCURL_MAX_Q1D");
|
||||
MFEM_VERIFY(T_D1D || d1d <= DeviceDofQuadLimits::Get().HCURL_MAX_D1D,
|
||||
"Error: d1d > HCURL_MAX_D1D");
|
||||
MFEM_VERIFY(T_Q1D || q1d <= DeviceDofQuadLimits::Get().HCURL_MAX_Q1D,
|
||||
"Error: q1d > HCURL_MAX_Q1D");
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
|
||||
@@ -72,8 +74,8 @@ inline void SmemPAHcurlMassAssembleDiagonal3D(const int d1d,
|
||||
mfem::forall_3D(NE, Q1D, Q1D, Q1D, [=] MFEM_HOST_DEVICE (int e)
|
||||
{
|
||||
constexpr int VDIM = 3;
|
||||
constexpr int MD1D = T_D1D ? T_D1D : HCURL_MAX_D1D;
|
||||
constexpr int MQ1D = T_Q1D ? T_Q1D : HCURL_MAX_Q1D;
|
||||
constexpr int MD1D = T_D1D ? T_D1D : DofQuadLimits::HCURL_MAX_D1D;
|
||||
constexpr int MQ1D = T_Q1D ? T_Q1D : DofQuadLimits::HCURL_MAX_Q1D;
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
|
||||
@@ -218,8 +220,10 @@ inline void SmemPAHcurlMassApply3D(const int d1d,
|
||||
const Vector &x,
|
||||
Vector &y)
|
||||
{
|
||||
MFEM_VERIFY(T_D1D || d1d <= HCURL_MAX_D1D, "Error: d1d > HCURL_MAX_D1D");
|
||||
MFEM_VERIFY(T_Q1D || q1d <= HCURL_MAX_Q1D, "Error: q1d > HCURL_MAX_Q1D");
|
||||
MFEM_VERIFY(T_D1D || d1d <= DeviceDofQuadLimits::Get().HCURL_MAX_D1D,
|
||||
"Error: d1d > HCURL_MAX_D1D");
|
||||
MFEM_VERIFY(T_Q1D || q1d <= DeviceDofQuadLimits::Get().HCURL_MAX_Q1D,
|
||||
"Error: q1d > HCURL_MAX_Q1D");
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
|
||||
@@ -234,8 +238,8 @@ inline void SmemPAHcurlMassApply3D(const int d1d,
|
||||
mfem::forall_3D(NE, Q1D, Q1D, Q1D, [=] MFEM_HOST_DEVICE (int e)
|
||||
{
|
||||
constexpr int VDIM = 3;
|
||||
constexpr int MD1D = T_D1D ? T_D1D : HCURL_MAX_D1D;
|
||||
constexpr int MQ1D = T_Q1D ? T_Q1D : HCURL_MAX_Q1D;
|
||||
constexpr int MD1D = T_D1D ? T_D1D : DofQuadLimits::HCURL_MAX_D1D;
|
||||
constexpr int MQ1D = T_Q1D ? T_Q1D : DofQuadLimits::HCURL_MAX_Q1D;
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
|
||||
@@ -441,8 +445,10 @@ inline void PACurlCurlAssembleDiagonal3D(const int d1d,
|
||||
const Vector &pa_data,
|
||||
Vector &diag)
|
||||
{
|
||||
MFEM_VERIFY(T_D1D || d1d <= HCURL_MAX_D1D, "Error: d1d > HCURL_MAX_D1D");
|
||||
MFEM_VERIFY(T_Q1D || q1d <= HCURL_MAX_Q1D, "Error: q1d > HCURL_MAX_Q1D");
|
||||
MFEM_VERIFY(T_D1D || d1d <= DeviceDofQuadLimits::Get().HCURL_MAX_D1D,
|
||||
"Error: d1d > HCURL_MAX_D1D");
|
||||
MFEM_VERIFY(T_Q1D || q1d <= DeviceDofQuadLimits::Get().HCURL_MAX_Q1D,
|
||||
"Error: q1d > HCURL_MAX_Q1D");
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
|
||||
@@ -476,8 +482,8 @@ inline void PACurlCurlAssembleDiagonal3D(const int d1d,
|
||||
// which may be non-symmetric depending on a possibly non-symmetric matrix coefficient.
|
||||
|
||||
constexpr int VDIM = 3;
|
||||
constexpr int MD1D = T_D1D ? T_D1D : HCURL_MAX_D1D;
|
||||
constexpr int MQ1D = T_Q1D ? T_Q1D : HCURL_MAX_Q1D;
|
||||
constexpr int MD1D = T_D1D ? T_D1D : DofQuadLimits::HCURL_MAX_D1D;
|
||||
constexpr int MQ1D = T_Q1D ? T_Q1D : DofQuadLimits::HCURL_MAX_Q1D;
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
|
||||
@@ -635,8 +641,10 @@ inline void SmemPACurlCurlAssembleDiagonal3D(const int d1d,
|
||||
const Vector &pa_data,
|
||||
Vector &diag)
|
||||
{
|
||||
MFEM_VERIFY(T_D1D || d1d <= HCURL_MAX_D1D, "Error: d1d > HCURL_MAX_D1D");
|
||||
MFEM_VERIFY(T_Q1D || q1d <= HCURL_MAX_Q1D, "Error: q1d > HCURL_MAX_Q1D");
|
||||
MFEM_VERIFY(T_D1D || d1d <= DeviceDofQuadLimits::Get().HCURL_MAX_D1D,
|
||||
"Error: d1d > HCURL_MAX_D1D");
|
||||
MFEM_VERIFY(T_Q1D || q1d <= DeviceDofQuadLimits::Get().HCURL_MAX_Q1D,
|
||||
"Error: q1d > HCURL_MAX_Q1D");
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
|
||||
@@ -667,8 +675,8 @@ inline void SmemPACurlCurlAssembleDiagonal3D(const int d1d,
|
||||
// If c = 2, \hat{\nabla}\times\hat{u} reduces to [(u_2)_{x_1}, -(u_2)_{x_0}, 0]
|
||||
|
||||
constexpr int VDIM = 3;
|
||||
constexpr int MD1D = T_D1D ? T_D1D : HCURL_MAX_D1D;
|
||||
constexpr int MQ1D = T_Q1D ? T_Q1D : HCURL_MAX_Q1D;
|
||||
constexpr int MD1D = T_D1D ? T_D1D : DofQuadLimits::HCURL_MAX_D1D;
|
||||
constexpr int MQ1D = T_Q1D ? T_Q1D : DofQuadLimits::HCURL_MAX_Q1D;
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
|
||||
@@ -848,8 +856,10 @@ inline void PACurlCurlApply3D(const int d1d,
|
||||
const Vector &x,
|
||||
Vector &y)
|
||||
{
|
||||
MFEM_VERIFY(T_D1D || d1d <= HCURL_MAX_D1D, "Error: d1d > HCURL_MAX_D1D");
|
||||
MFEM_VERIFY(T_Q1D || q1d <= HCURL_MAX_Q1D, "Error: q1d > HCURL_MAX_Q1D");
|
||||
MFEM_VERIFY(T_D1D || d1d <= DeviceDofQuadLimits::Get().HCURL_MAX_D1D,
|
||||
"Error: d1d > HCURL_MAX_D1D");
|
||||
MFEM_VERIFY(T_Q1D || q1d <= DeviceDofQuadLimits::Get().HCURL_MAX_Q1D,
|
||||
"Error: q1d > HCURL_MAX_Q1D");
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
|
||||
@@ -874,8 +884,8 @@ inline void PACurlCurlApply3D(const int d1d,
|
||||
// If c = 2, \hat{\nabla}\times\hat{u} reduces to [(u_2)_{x_1}, -(u_2)_{x_0}, 0]
|
||||
|
||||
constexpr int VDIM = 3;
|
||||
constexpr int MD1D = T_D1D ? T_D1D : HCURL_MAX_D1D;
|
||||
constexpr int MQ1D = T_Q1D ? T_Q1D : HCURL_MAX_Q1D;
|
||||
constexpr int MD1D = T_D1D ? T_D1D : DofQuadLimits::HCURL_MAX_D1D;
|
||||
constexpr int MQ1D = T_Q1D ? T_Q1D : DofQuadLimits::HCURL_MAX_Q1D;
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
|
||||
@@ -1369,8 +1379,10 @@ inline void SmemPACurlCurlApply3D(const int d1d,
|
||||
const Vector &x,
|
||||
Vector &y)
|
||||
{
|
||||
MFEM_VERIFY(T_D1D || d1d <= HCURL_MAX_D1D, "Error: d1d > HCURL_MAX_D1D");
|
||||
MFEM_VERIFY(T_Q1D || q1d <= HCURL_MAX_Q1D, "Error: q1d > HCURL_MAX_Q1D");
|
||||
MFEM_VERIFY(T_D1D || d1d <= DeviceDofQuadLimits::Get().HCURL_MAX_D1D,
|
||||
"Error: d1d > HCURL_MAX_D1D");
|
||||
MFEM_VERIFY(T_Q1D || q1d <= DeviceDofQuadLimits::Get().HCURL_MAX_Q1D,
|
||||
"Error: q1d > HCURL_MAX_Q1D");
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
|
||||
@@ -1392,8 +1404,8 @@ inline void SmemPACurlCurlApply3D(const int d1d,
|
||||
auto device_kernel = [=] MFEM_DEVICE (int e)
|
||||
{
|
||||
constexpr int VDIM = 3;
|
||||
constexpr int MD1D = T_D1D ? T_D1D : HCURL_MAX_D1D;
|
||||
constexpr int MQ1D = T_Q1D ? T_Q1D : HCURL_MAX_Q1D;
|
||||
constexpr int MD1D = T_D1D ? T_D1D : DofQuadLimits::HCURL_MAX_D1D;
|
||||
constexpr int MQ1D = T_Q1D ? T_Q1D : DofQuadLimits::HCURL_MAX_Q1D;
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
|
||||
@@ -1738,8 +1750,10 @@ inline void PAHcurlL2Apply3D(const int d1d,
|
||||
const Vector &x,
|
||||
Vector &y)
|
||||
{
|
||||
MFEM_VERIFY(T_D1D || d1d <= HCURL_MAX_D1D, "Error: d1d > HCURL_MAX_D1D");
|
||||
MFEM_VERIFY(T_Q1D || q1d <= HCURL_MAX_Q1D, "Error: q1d > HCURL_MAX_Q1D");
|
||||
MFEM_VERIFY(T_D1D || d1d <= DeviceDofQuadLimits::Get().HCURL_MAX_D1D,
|
||||
"Error: d1d > HCURL_MAX_D1D");
|
||||
MFEM_VERIFY(T_Q1D || q1d <= DeviceDofQuadLimits::Get().HCURL_MAX_Q1D,
|
||||
"Error: q1d > HCURL_MAX_Q1D");
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
|
||||
@@ -1764,8 +1778,8 @@ inline void PAHcurlL2Apply3D(const int d1d,
|
||||
// If c = 2, \hat{\nabla}\times\hat{u} reduces to [(u_2)_{x_1}, -(u_2)_{x_0}, 0]
|
||||
|
||||
constexpr int VDIM = 3;
|
||||
constexpr int MD1D = T_D1D ? T_D1D : HCURL_MAX_D1D;
|
||||
constexpr int MQ1D = T_Q1D ? T_Q1D : HCURL_MAX_Q1D;
|
||||
constexpr int MD1D = T_D1D ? T_D1D : DofQuadLimits::HCURL_MAX_D1D;
|
||||
constexpr int MQ1D = T_Q1D ? T_Q1D : DofQuadLimits::HCURL_MAX_Q1D;
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
|
||||
@@ -2107,8 +2121,10 @@ inline void SmemPAHcurlL2Apply3D(const int d1d,
|
||||
const Vector &x,
|
||||
Vector &y)
|
||||
{
|
||||
MFEM_VERIFY(T_D1D || d1d <= HCURL_MAX_D1D, "Error: d1d > HCURL_MAX_D1D");
|
||||
MFEM_VERIFY(T_Q1D || q1d <= HCURL_MAX_Q1D, "Error: q1d > HCURL_MAX_Q1D");
|
||||
MFEM_VERIFY(T_D1D || d1d <= DeviceDofQuadLimits::Get().HCURL_MAX_D1D,
|
||||
"Error: d1d > HCURL_MAX_D1D");
|
||||
MFEM_VERIFY(T_Q1D || q1d <= DeviceDofQuadLimits::Get().HCURL_MAX_Q1D,
|
||||
"Error: q1d > HCURL_MAX_Q1D");
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
|
||||
@@ -2123,8 +2139,8 @@ inline void SmemPAHcurlL2Apply3D(const int d1d,
|
||||
{
|
||||
constexpr int VDIM = 3;
|
||||
constexpr int maxCoeffDim = 9;
|
||||
constexpr int MD1D = T_D1D ? T_D1D : HCURL_MAX_D1D;
|
||||
constexpr int MQ1D = T_Q1D ? T_Q1D : HCURL_MAX_Q1D;
|
||||
constexpr int MD1D = T_D1D ? T_D1D : DofQuadLimits::HCURL_MAX_D1D;
|
||||
constexpr int MQ1D = T_Q1D ? T_Q1D : DofQuadLimits::HCURL_MAX_Q1D;
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
|
||||
@@ -2425,8 +2441,10 @@ inline void PAHcurlL2ApplyTranspose3D(const int d1d,
|
||||
Vector &y)
|
||||
{
|
||||
// See PAHcurlL2Apply3D for comments.
|
||||
MFEM_VERIFY(T_D1D || d1d <= HCURL_MAX_D1D, "Error: d1d > HCURL_MAX_D1D");
|
||||
MFEM_VERIFY(T_Q1D || q1d <= HCURL_MAX_Q1D, "Error: q1d > HCURL_MAX_Q1D");
|
||||
MFEM_VERIFY(T_D1D || d1d <= DeviceDofQuadLimits::Get().HCURL_MAX_D1D,
|
||||
"Error: d1d > HCURL_MAX_D1D");
|
||||
MFEM_VERIFY(T_Q1D || q1d <= DeviceDofQuadLimits::Get().HCURL_MAX_Q1D,
|
||||
"Error: q1d > HCURL_MAX_Q1D");
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
|
||||
@@ -2442,8 +2460,8 @@ inline void PAHcurlL2ApplyTranspose3D(const int d1d,
|
||||
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
|
||||
{
|
||||
constexpr int VDIM = 3;
|
||||
constexpr int MD1D = T_D1D ? T_D1D : HCURL_MAX_D1D;
|
||||
constexpr int MQ1D = T_Q1D ? T_Q1D : HCURL_MAX_Q1D;
|
||||
constexpr int MD1D = T_D1D ? T_D1D : DofQuadLimits::HCURL_MAX_D1D;
|
||||
constexpr int MQ1D = T_Q1D ? T_Q1D : DofQuadLimits::HCURL_MAX_Q1D;
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
|
||||
@@ -2791,8 +2809,10 @@ inline void SmemPAHcurlL2ApplyTranspose3D(const int d1d,
|
||||
const Vector &x,
|
||||
Vector &y)
|
||||
{
|
||||
MFEM_VERIFY(T_D1D || d1d <= HCURL_MAX_D1D, "Error: d1d > HCURL_MAX_D1D");
|
||||
MFEM_VERIFY(T_Q1D || q1d <= HCURL_MAX_Q1D, "Error: q1d > HCURL_MAX_Q1D");
|
||||
MFEM_VERIFY(T_D1D || d1d <= DeviceDofQuadLimits::Get().HCURL_MAX_D1D,
|
||||
"Error: d1d > HCURL_MAX_D1D");
|
||||
MFEM_VERIFY(T_Q1D || q1d <= DeviceDofQuadLimits::Get().HCURL_MAX_Q1D,
|
||||
"Error: q1d > HCURL_MAX_Q1D");
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
|
||||
@@ -2807,8 +2827,8 @@ inline void SmemPAHcurlL2ApplyTranspose3D(const int d1d,
|
||||
{
|
||||
constexpr int VDIM = 3;
|
||||
constexpr int maxCoeffDim = 9;
|
||||
constexpr int MD1D = T_D1D ? T_D1D : HCURL_MAX_D1D;
|
||||
constexpr int MQ1D = T_Q1D ? T_Q1D : HCURL_MAX_Q1D;
|
||||
constexpr int MD1D = T_D1D ? T_D1D : DofQuadLimits::HCURL_MAX_D1D;
|
||||
constexpr int MQ1D = T_Q1D ? T_Q1D : DofQuadLimits::HCURL_MAX_Q1D;
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
|
||||
|
||||
@@ -224,11 +224,10 @@ void PAHcurlHdivMassApply2D(const int D1D,
|
||||
const Vector &x_,
|
||||
Vector &y_)
|
||||
{
|
||||
constexpr static int MAX_D1D = HCURL_MAX_D1D;
|
||||
constexpr static int MAX_Q1D = HCURL_MAX_Q1D;
|
||||
|
||||
MFEM_VERIFY(D1D <= MAX_D1D, "Error: D1D > MAX_D1D");
|
||||
MFEM_VERIFY(Q1D <= MAX_Q1D, "Error: Q1D > MAX_Q1D");
|
||||
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().HCURL_MAX_D1D,
|
||||
"Error: D1D > MAX_D1D");
|
||||
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().HCURL_MAX_Q1D,
|
||||
"Error: Q1D > MAX_Q1D");
|
||||
constexpr static int VDIM = 2;
|
||||
|
||||
auto Bo = Reshape(Bo_.Read(), Q1D, D1D-1);
|
||||
@@ -244,6 +243,8 @@ void PAHcurlHdivMassApply2D(const int D1D,
|
||||
|
||||
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
|
||||
{
|
||||
constexpr static int MAX_Q1D = DofQuadLimits::HCURL_MAX_Q1D;
|
||||
|
||||
double mass[MAX_Q1D][MAX_Q1D][VDIM];
|
||||
|
||||
for (int qy = 0; qy < Q1D; ++qy)
|
||||
@@ -323,7 +324,7 @@ void PAHcurlHdivMassApply2D(const int D1D,
|
||||
|
||||
for (int qy = 0; qy < Q1D; ++qy)
|
||||
{
|
||||
double massX[HDIV_MAX_D1D];
|
||||
double massX[DofQuadLimits::HDIV_MAX_D1D];
|
||||
for (int dx = 0; dx < D1Dx; ++dx)
|
||||
{
|
||||
massX[dx] = 0.0;
|
||||
@@ -370,11 +371,10 @@ void PAHcurlHdivMassApply3D(const int D1D,
|
||||
const Vector &x_,
|
||||
Vector &y_)
|
||||
{
|
||||
constexpr static int MAX_D1D = HCURL_MAX_D1D;
|
||||
constexpr static int MAX_Q1D = HCURL_MAX_Q1D;
|
||||
|
||||
MFEM_VERIFY(D1D <= MAX_D1D, "Error: D1D > MAX_D1D");
|
||||
MFEM_VERIFY(Q1D <= MAX_Q1D, "Error: Q1D > MAX_Q1D");
|
||||
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().HCURL_MAX_D1D,
|
||||
"Error: D1D > MAX_D1D");
|
||||
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().HCURL_MAX_Q1D,
|
||||
"Error: Q1D > MAX_Q1D");
|
||||
constexpr static int VDIM = 3;
|
||||
|
||||
auto Bo = Reshape(Bo_.Read(), Q1D, D1D-1);
|
||||
@@ -395,6 +395,8 @@ void PAHcurlHdivMassApply3D(const int D1D,
|
||||
|
||||
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
|
||||
{
|
||||
constexpr static int MAX_Q1D = DofQuadLimits::HCURL_MAX_Q1D;
|
||||
|
||||
double mass[MAX_Q1D][MAX_Q1D][MAX_Q1D][VDIM];
|
||||
|
||||
for (int qz = 0; qz < Q1D; ++qz)
|
||||
@@ -507,7 +509,7 @@ void PAHcurlHdivMassApply3D(const int D1D,
|
||||
|
||||
for (int qz = 0; qz < Q1D; ++qz)
|
||||
{
|
||||
double massXY[HDIV_MAX_D1D][HDIV_MAX_D1D];
|
||||
double massXY[DofQuadLimits::HDIV_MAX_D1D][DofQuadLimits::HDIV_MAX_D1D];
|
||||
|
||||
osc = 0;
|
||||
for (int c = 0; c < VDIM; ++c) // loop over x, y, z test components
|
||||
@@ -528,7 +530,7 @@ void PAHcurlHdivMassApply3D(const int D1D,
|
||||
}
|
||||
for (int qy = 0; qy < Q1D; ++qy)
|
||||
{
|
||||
double massX[HDIV_MAX_D1D];
|
||||
double massX[DofQuadLimits::HDIV_MAX_D1D];
|
||||
for (int dx = 0; dx < D1Dx; ++dx)
|
||||
{
|
||||
massX[dx] = 0.0;
|
||||
|
||||
@@ -92,10 +92,12 @@ inline void PAHcurlHdivApply3D(const int d1d,
|
||||
const Vector &x,
|
||||
Vector &y)
|
||||
{
|
||||
MFEM_VERIFY(T_D1D || d1d <= HCURL_MAX_D1D, "Error: d1d > HCURL_MAX_D1D");
|
||||
MFEM_VERIFY(T_D1D_TEST ||
|
||||
d1dtest <= HCURL_MAX_D1D, "Error: d1dtest > HCURL_MAX_D1D");
|
||||
MFEM_VERIFY(T_Q1D || q1d <= HCURL_MAX_Q1D, "Error: q1d > HCURL_MAX_Q1D");
|
||||
MFEM_VERIFY(T_D1D || d1d <= DeviceDofQuadLimits::Get().HCURL_MAX_D1D,
|
||||
"Error: d1d > HCURL_MAX_D1D");
|
||||
MFEM_VERIFY(T_D1D_TEST || d1dtest <= DeviceDofQuadLimits::Get().HCURL_MAX_D1D,
|
||||
"Error: d1dtest > HCURL_MAX_D1D");
|
||||
MFEM_VERIFY(T_Q1D || q1d <= DeviceDofQuadLimits::Get().HCURL_MAX_Q1D,
|
||||
"Error: q1d > HCURL_MAX_Q1D");
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int D1Dtest = T_D1D_TEST ? T_D1D_TEST : d1dtest;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
@@ -120,8 +122,8 @@ inline void PAHcurlHdivApply3D(const int d1d,
|
||||
|
||||
constexpr int VDIM = 3;
|
||||
constexpr int MD1D = T_D1D ? T_D1D :
|
||||
HCURL_MAX_D1D; // Assuming HDIV_MAX_D1D <= HCURL_MAX_D1D
|
||||
constexpr int MQ1D = T_Q1D ? T_Q1D : HCURL_MAX_Q1D;
|
||||
DofQuadLimits::HCURL_MAX_D1D; // Assuming HDIV_MAX_D1D <= HCURL_MAX_D1D
|
||||
constexpr int MQ1D = T_Q1D ? T_Q1D : DofQuadLimits::HCURL_MAX_Q1D;
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int D1Dtest = T_D1D_TEST ? T_D1D_TEST : d1dtest;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
@@ -459,10 +461,12 @@ inline void PAHcurlHdivApplyTranspose3D(const int d1d,
|
||||
const Vector &x,
|
||||
Vector &y)
|
||||
{
|
||||
MFEM_VERIFY(T_D1D || d1d <= HCURL_MAX_D1D, "Error: d1d > HCURL_MAX_D1D");
|
||||
MFEM_VERIFY(T_D1D_TEST ||
|
||||
d1dtest <= HCURL_MAX_D1D, "Error: d1dtest > HCURL_MAX_D1D");
|
||||
MFEM_VERIFY(T_Q1D || q1d <= HCURL_MAX_Q1D, "Error: q1d > HCURL_MAX_Q1D");
|
||||
MFEM_VERIFY(T_D1D || d1d <= DeviceDofQuadLimits::Get().HCURL_MAX_D1D,
|
||||
"Error: d1d > HCURL_MAX_D1D");
|
||||
MFEM_VERIFY(T_D1D_TEST || d1dtest <= DeviceDofQuadLimits::Get().HCURL_MAX_D1D,
|
||||
"Error: d1dtest > HCURL_MAX_D1D");
|
||||
MFEM_VERIFY(T_Q1D || q1d <= DeviceDofQuadLimits::Get().HCURL_MAX_Q1D,
|
||||
"Error: q1d > HCURL_MAX_Q1D");
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int D1Dtest = T_D1D_TEST ? T_D1D_TEST : d1dtest;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
@@ -487,8 +491,8 @@ inline void PAHcurlHdivApplyTranspose3D(const int d1d,
|
||||
|
||||
constexpr int VDIM = 3;
|
||||
constexpr int MD1D = T_D1D ? T_D1D :
|
||||
HCURL_MAX_D1D; // Assuming HDIV_MAX_D1D <= HCURL_MAX_D1D
|
||||
constexpr int MQ1D = T_Q1D ? T_Q1D : HCURL_MAX_Q1D;
|
||||
DofQuadLimits::HCURL_MAX_D1D; // Assuming HDIV_MAX_D1D <= HCURL_MAX_D1D
|
||||
constexpr int MQ1D = T_Q1D ? T_Q1D : DofQuadLimits::HCURL_MAX_Q1D;
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int D1Dtest = T_D1D_TEST ? T_D1D_TEST : d1dtest;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
|
||||
@@ -176,9 +176,6 @@ void PAHdivMassAssembleDiagonal2D(const int D1D,
|
||||
const Vector &op_,
|
||||
Vector &diag_)
|
||||
{
|
||||
constexpr static int VDIM = 2;
|
||||
constexpr static int MAX_Q1D = HDIV_MAX_Q1D;
|
||||
|
||||
auto Bo = Reshape(Bo_.Read(), Q1D, D1D-1);
|
||||
auto Bc = Reshape(Bc_.Read(), Q1D, D1D);
|
||||
auto op = Reshape(op_.Read(), Q1D, Q1D, symmetric ? 3 : 4, NE);
|
||||
@@ -186,6 +183,9 @@ void PAHdivMassAssembleDiagonal2D(const int D1D,
|
||||
|
||||
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
|
||||
{
|
||||
constexpr static int VDIM = 2;
|
||||
constexpr static int MAX_Q1D = DofQuadLimits::HDIV_MAX_Q1D;
|
||||
|
||||
int osc = 0;
|
||||
|
||||
for (int c = 0; c < VDIM; ++c) // loop over x, y components
|
||||
@@ -232,8 +232,10 @@ void PAHdivMassAssembleDiagonal3D(const int D1D,
|
||||
const Vector &op_,
|
||||
Vector &diag_)
|
||||
{
|
||||
MFEM_VERIFY(D1D <= HDIV_MAX_D1D, "Error: D1D > HDIV_MAX_D1D");
|
||||
MFEM_VERIFY(Q1D <= HDIV_MAX_Q1D, "Error: Q1D > HDIV_MAX_Q1D");
|
||||
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().HDIV_MAX_D1D,
|
||||
"Error: D1D > HDIV_MAX_D1D");
|
||||
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().HDIV_MAX_Q1D,
|
||||
"Error: Q1D > HDIV_MAX_Q1D");
|
||||
constexpr static int VDIM = 3;
|
||||
|
||||
auto Bo = Reshape(Bo_.Read(), Q1D, D1D-1);
|
||||
@@ -254,7 +256,7 @@ void PAHdivMassAssembleDiagonal3D(const int D1D,
|
||||
const int opc = (c == 0) ? 0 : ((c == 1) ? (symmetric ? 3 : 4) :
|
||||
(symmetric ? 5 : 8));
|
||||
|
||||
double mass[HDIV_MAX_Q1D];
|
||||
double mass[DofQuadLimits::HDIV_MAX_Q1D];
|
||||
|
||||
for (int dz = 0; dz < D1Dz; ++dz)
|
||||
{
|
||||
@@ -347,10 +349,6 @@ void PAHdivMassApply2D(const int D1D,
|
||||
const Vector &x_,
|
||||
Vector &y_)
|
||||
{
|
||||
constexpr static int VDIM = 2;
|
||||
constexpr static int MAX_D1D = HDIV_MAX_D1D;
|
||||
constexpr static int MAX_Q1D = HDIV_MAX_Q1D;
|
||||
|
||||
auto Bo = Reshape(Bo_.Read(), Q1D, D1D-1);
|
||||
auto Bc = Reshape(Bc_.Read(), Q1D, D1D);
|
||||
auto Bot = Reshape(Bot_.Read(), D1D-1, Q1D);
|
||||
@@ -361,6 +359,10 @@ void PAHdivMassApply2D(const int D1D,
|
||||
|
||||
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
|
||||
{
|
||||
constexpr static int VDIM = 2;
|
||||
constexpr static int MAX_D1D = DofQuadLimits::HDIV_MAX_D1D;
|
||||
constexpr static int MAX_Q1D = DofQuadLimits::HDIV_MAX_Q1D;
|
||||
|
||||
double mass[MAX_Q1D][MAX_Q1D][VDIM];
|
||||
|
||||
for (int qy = 0; qy < Q1D; ++qy)
|
||||
@@ -478,8 +480,10 @@ void PAHdivMassApply3D(const int D1D,
|
||||
const Vector &x_,
|
||||
Vector &y_)
|
||||
{
|
||||
MFEM_VERIFY(D1D <= HDIV_MAX_D1D, "Error: D1D > HDIV_MAX_D1D");
|
||||
MFEM_VERIFY(Q1D <= HDIV_MAX_Q1D, "Error: Q1D > HDIV_MAX_Q1D");
|
||||
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().HDIV_MAX_D1D,
|
||||
"Error: D1D > HDIV_MAX_D1D");
|
||||
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().HDIV_MAX_Q1D,
|
||||
"Error: Q1D > HDIV_MAX_Q1D");
|
||||
constexpr static int VDIM = 3;
|
||||
|
||||
auto Bo = Reshape(Bo_.Read(), Q1D, D1D-1);
|
||||
@@ -492,7 +496,7 @@ void PAHdivMassApply3D(const int D1D,
|
||||
|
||||
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
|
||||
{
|
||||
double mass[HDIV_MAX_Q1D][HDIV_MAX_Q1D][HDIV_MAX_Q1D][VDIM];
|
||||
double mass[DofQuadLimits::HDIV_MAX_Q1D][DofQuadLimits::HDIV_MAX_Q1D][DofQuadLimits::HDIV_MAX_Q1D][VDIM];
|
||||
|
||||
for (int qz = 0; qz < Q1D; ++qz)
|
||||
{
|
||||
@@ -518,7 +522,7 @@ void PAHdivMassApply3D(const int D1D,
|
||||
|
||||
for (int dz = 0; dz < D1Dz; ++dz)
|
||||
{
|
||||
double massXY[HDIV_MAX_Q1D][HDIV_MAX_Q1D];
|
||||
double massXY[DofQuadLimits::HDIV_MAX_Q1D][DofQuadLimits::HDIV_MAX_Q1D];
|
||||
for (int qy = 0; qy < Q1D; ++qy)
|
||||
{
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
@@ -529,7 +533,7 @@ void PAHdivMassApply3D(const int D1D,
|
||||
|
||||
for (int dy = 0; dy < D1Dy; ++dy)
|
||||
{
|
||||
double massX[HDIV_MAX_Q1D];
|
||||
double massX[DofQuadLimits::HDIV_MAX_Q1D];
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
massX[qx] = 0.0;
|
||||
@@ -600,7 +604,7 @@ void PAHdivMassApply3D(const int D1D,
|
||||
|
||||
for (int qz = 0; qz < Q1D; ++qz)
|
||||
{
|
||||
double massXY[HDIV_MAX_D1D][HDIV_MAX_D1D];
|
||||
double massXY[DofQuadLimits::HDIV_MAX_D1D][DofQuadLimits::HDIV_MAX_D1D];
|
||||
|
||||
osc = 0;
|
||||
|
||||
@@ -619,7 +623,7 @@ void PAHdivMassApply3D(const int D1D,
|
||||
}
|
||||
for (int qy = 0; qy < Q1D; ++qy)
|
||||
{
|
||||
double massX[HDIV_MAX_D1D];
|
||||
double massX[DofQuadLimits::HDIV_MAX_D1D];
|
||||
for (int dx = 0; dx < D1Dx; ++dx)
|
||||
{
|
||||
massX[dx] = 0;
|
||||
@@ -730,9 +734,6 @@ void PADivDivAssembleDiagonal2D(const int D1D,
|
||||
const Vector &op_,
|
||||
Vector &diag_)
|
||||
{
|
||||
constexpr static int VDIM = 2;
|
||||
constexpr static int MAX_Q1D = HDIV_MAX_Q1D;
|
||||
|
||||
auto Bo = Reshape(Bo_.Read(), Q1D, D1D-1);
|
||||
auto Gc = Reshape(Gc_.Read(), Q1D, D1D);
|
||||
auto op = Reshape(op_.Read(), Q1D, Q1D, NE);
|
||||
@@ -740,6 +741,9 @@ void PADivDivAssembleDiagonal2D(const int D1D,
|
||||
|
||||
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
|
||||
{
|
||||
constexpr static int VDIM = 2;
|
||||
constexpr static int MAX_Q1D = DofQuadLimits::HDIV_MAX_Q1D;
|
||||
|
||||
int osc = 0;
|
||||
|
||||
for (int c = 0; c < VDIM; ++c) // loop over x, y components
|
||||
@@ -786,8 +790,10 @@ void PADivDivAssembleDiagonal3D(const int D1D,
|
||||
const Vector &op_,
|
||||
Vector &diag_)
|
||||
{
|
||||
MFEM_VERIFY(D1D <= HDIV_MAX_D1D, "Error: D1D > HDIV_MAX_D1D");
|
||||
MFEM_VERIFY(Q1D <= HDIV_MAX_Q1D, "Error: Q1D > HDIV_MAX_Q1D");
|
||||
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().HDIV_MAX_D1D,
|
||||
"Error: D1D > HDIV_MAX_D1D");
|
||||
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().HDIV_MAX_Q1D,
|
||||
"Error: Q1D > HDIV_MAX_Q1D");
|
||||
constexpr static int VDIM = 3;
|
||||
|
||||
auto Bo = Reshape(Bo_.Read(), Q1D, D1D-1);
|
||||
@@ -809,7 +815,7 @@ void PADivDivAssembleDiagonal3D(const int D1D,
|
||||
{
|
||||
for (int dy = 0; dy < D1Dy; ++dy)
|
||||
{
|
||||
double a[HDIV_MAX_Q1D];
|
||||
double a[DofQuadLimits::HDIV_MAX_Q1D];
|
||||
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
@@ -855,10 +861,6 @@ void PADivDivApply2D(const int D1D,
|
||||
const Vector &x_,
|
||||
Vector &y_)
|
||||
{
|
||||
constexpr static int VDIM = 2;
|
||||
constexpr static int MAX_D1D = HDIV_MAX_D1D;
|
||||
constexpr static int MAX_Q1D = HDIV_MAX_Q1D;
|
||||
|
||||
auto Bo = Reshape(Bo_.Read(), Q1D, D1D-1);
|
||||
auto Bot = Reshape(Bot_.Read(), D1D-1, Q1D);
|
||||
auto Gc = Reshape(Gc_.Read(), Q1D, D1D);
|
||||
@@ -869,6 +871,10 @@ void PADivDivApply2D(const int D1D,
|
||||
|
||||
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
|
||||
{
|
||||
constexpr static int VDIM = 2;
|
||||
constexpr static int MAX_D1D = DofQuadLimits::HDIV_MAX_D1D;
|
||||
constexpr static int MAX_Q1D = DofQuadLimits::HDIV_MAX_Q1D;
|
||||
|
||||
double div[MAX_Q1D][MAX_Q1D];
|
||||
|
||||
// div[qy][qx] will be computed as du_x/dx + du_y/dy
|
||||
@@ -974,8 +980,10 @@ void PADivDivApply3D(const int D1D,
|
||||
const Vector &x_,
|
||||
Vector &y_)
|
||||
{
|
||||
MFEM_VERIFY(D1D <= HDIV_MAX_D1D, "Error: D1D > HDIV_MAX_D1D");
|
||||
MFEM_VERIFY(Q1D <= HDIV_MAX_Q1D, "Error: Q1D > HDIV_MAX_Q1D");
|
||||
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().HDIV_MAX_D1D,
|
||||
"Error: D1D > HDIV_MAX_D1D");
|
||||
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().HDIV_MAX_Q1D,
|
||||
"Error: Q1D > HDIV_MAX_Q1D");
|
||||
constexpr static int VDIM = 3;
|
||||
|
||||
auto Bo = Reshape(Bo_.Read(), Q1D, D1D-1);
|
||||
@@ -988,7 +996,7 @@ void PADivDivApply3D(const int D1D,
|
||||
|
||||
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
|
||||
{
|
||||
double div[HDIV_MAX_Q1D][HDIV_MAX_Q1D][HDIV_MAX_Q1D];
|
||||
double div[DofQuadLimits::HDIV_MAX_Q1D][DofQuadLimits::HDIV_MAX_Q1D][DofQuadLimits::HDIV_MAX_Q1D];
|
||||
|
||||
for (int qz = 0; qz < Q1D; ++qz)
|
||||
{
|
||||
@@ -1011,7 +1019,7 @@ void PADivDivApply3D(const int D1D,
|
||||
|
||||
for (int dz = 0; dz < D1Dz; ++dz)
|
||||
{
|
||||
double aXY[HDIV_MAX_Q1D][HDIV_MAX_Q1D];
|
||||
double aXY[DofQuadLimits::HDIV_MAX_Q1D][DofQuadLimits::HDIV_MAX_Q1D];
|
||||
for (int qy = 0; qy < Q1D; ++qy)
|
||||
{
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
@@ -1022,7 +1030,7 @@ void PADivDivApply3D(const int D1D,
|
||||
|
||||
for (int dy = 0; dy < D1Dy; ++dy)
|
||||
{
|
||||
double aX[HDIV_MAX_Q1D];
|
||||
double aX[DofQuadLimits::HDIV_MAX_Q1D];
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
aX[qx] = 0.0;
|
||||
@@ -1078,7 +1086,7 @@ void PADivDivApply3D(const int D1D,
|
||||
|
||||
for (int qz = 0; qz < Q1D; ++qz)
|
||||
{
|
||||
double aXY[HDIV_MAX_D1D][HDIV_MAX_D1D];
|
||||
double aXY[DofQuadLimits::HDIV_MAX_D1D][DofQuadLimits::HDIV_MAX_D1D];
|
||||
|
||||
osc = 0;
|
||||
|
||||
@@ -1097,7 +1105,7 @@ void PADivDivApply3D(const int D1D,
|
||||
}
|
||||
for (int qy = 0; qy < Q1D; ++qy)
|
||||
{
|
||||
double aX[HDIV_MAX_D1D];
|
||||
double aX[DofQuadLimits::HDIV_MAX_D1D];
|
||||
for (int dx = 0; dx < D1Dx; ++dx)
|
||||
{
|
||||
aX[dx] = 0;
|
||||
@@ -1207,8 +1215,8 @@ void PAHdivL2AssembleDiagonal_ADAt_2D(const int D1D,
|
||||
// Compute row (rx,ry), assuming all contributions are from
|
||||
// a single element.
|
||||
|
||||
double row[2*HDIV_MAX_D1D*(HDIV_MAX_D1D-1)];
|
||||
double div[HDIV_MAX_Q1D][HDIV_MAX_Q1D];
|
||||
double row[2*DofQuadLimits::HDIV_MAX_D1D*(DofQuadLimits::HDIV_MAX_D1D-1)];
|
||||
double div[DofQuadLimits::HDIV_MAX_Q1D][DofQuadLimits::HDIV_MAX_Q1D];
|
||||
|
||||
for (int i=0; i<2*D1D*(D1D - 1); ++i)
|
||||
{
|
||||
@@ -1231,7 +1239,7 @@ void PAHdivL2AssembleDiagonal_ADAt_2D(const int D1D,
|
||||
const int D1Dy = (c == 1) ? D1D : D1D - 1;
|
||||
const int D1Dx = (c == 0) ? D1D : D1D - 1;
|
||||
|
||||
double aX[HDIV_MAX_D1D];
|
||||
double aX[DofQuadLimits::HDIV_MAX_D1D];
|
||||
for (int dx = 0; dx < D1Dx; ++dx)
|
||||
{
|
||||
aX[dx] = 0;
|
||||
@@ -1281,8 +1289,10 @@ void PAHdivL2AssembleDiagonal_ADAt_3D(const int D1D,
|
||||
const Vector &D_,
|
||||
Vector &diag_)
|
||||
{
|
||||
MFEM_VERIFY(D1D <= HDIV_MAX_D1D, "Error: D1D > HDIV_MAX_D1D");
|
||||
MFEM_VERIFY(Q1D <= HDIV_MAX_Q1D, "Error: Q1D > HDIV_MAX_Q1D");
|
||||
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().HDIV_MAX_D1D,
|
||||
"Error: D1D > HDIV_MAX_D1D");
|
||||
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().HDIV_MAX_Q1D,
|
||||
"Error: Q1D > HDIV_MAX_Q1D");
|
||||
constexpr static int VDIM = 3;
|
||||
|
||||
auto L2Bo = Reshape(L2Bo_.Read(), Q1D, L2D1D);
|
||||
@@ -1303,8 +1313,9 @@ void PAHdivL2AssembleDiagonal_ADAt_3D(const int D1D,
|
||||
// Compute row (rx,ry,rz), assuming all contributions are from
|
||||
// a single element.
|
||||
|
||||
double row[3*HDIV_MAX_D1D*(HDIV_MAX_D1D-1)*(HDIV_MAX_D1D-1)];
|
||||
double div[HDIV_MAX_Q1D][HDIV_MAX_Q1D][HDIV_MAX_Q1D];
|
||||
double row[3*DofQuadLimits::HDIV_MAX_D1D*(DofQuadLimits::HDIV_MAX_D1D-1)*
|
||||
(DofQuadLimits::HDIV_MAX_D1D-1)];
|
||||
double div[DofQuadLimits::HDIV_MAX_Q1D][DofQuadLimits::HDIV_MAX_Q1D][DofQuadLimits::HDIV_MAX_Q1D];
|
||||
|
||||
for (int i=0; i<3*D1D*(D1D - 1)*(D1D - 1); ++i)
|
||||
{
|
||||
@@ -1325,7 +1336,7 @@ void PAHdivL2AssembleDiagonal_ADAt_3D(const int D1D,
|
||||
|
||||
for (int qz = 0; qz < Q1D; ++qz)
|
||||
{
|
||||
double aXY[HDIV_MAX_D1D][HDIV_MAX_D1D];
|
||||
double aXY[DofQuadLimits::HDIV_MAX_D1D][DofQuadLimits::HDIV_MAX_D1D];
|
||||
|
||||
int osc = 0;
|
||||
for (int c = 0; c < VDIM; ++c) // loop over x, y, z components
|
||||
@@ -1343,7 +1354,7 @@ void PAHdivL2AssembleDiagonal_ADAt_3D(const int D1D,
|
||||
}
|
||||
for (int qy = 0; qy < Q1D; ++qy)
|
||||
{
|
||||
double aX[HDIV_MAX_D1D];
|
||||
double aX[DofQuadLimits::HDIV_MAX_D1D];
|
||||
for (int dx = 0; dx < D1Dx; ++dx)
|
||||
{
|
||||
aX[dx] = 0;
|
||||
@@ -1408,10 +1419,6 @@ void PAHdivL2Apply2D(const int D1D,
|
||||
const Vector &x_,
|
||||
Vector &y_)
|
||||
{
|
||||
constexpr static int VDIM = 2;
|
||||
constexpr static int MAX_D1D = HDIV_MAX_D1D;
|
||||
constexpr static int MAX_Q1D = HDIV_MAX_Q1D;
|
||||
|
||||
auto Bo = Reshape(Bo_.Read(), Q1D, D1D-1);
|
||||
auto Gc = Reshape(Gc_.Read(), Q1D, D1D);
|
||||
auto L2Bot = Reshape(L2Bot_.Read(), L2D1D, Q1D);
|
||||
@@ -1421,6 +1428,10 @@ void PAHdivL2Apply2D(const int D1D,
|
||||
|
||||
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
|
||||
{
|
||||
constexpr static int VDIM = 2;
|
||||
constexpr static int MAX_D1D = DofQuadLimits::HDIV_MAX_D1D;
|
||||
constexpr static int MAX_Q1D = DofQuadLimits::HDIV_MAX_Q1D;
|
||||
|
||||
double div[MAX_Q1D][MAX_Q1D];
|
||||
|
||||
for (int qy = 0; qy < Q1D; ++qy)
|
||||
@@ -1514,10 +1525,6 @@ void PAHdivL2ApplyTranspose2D(const int D1D,
|
||||
const Vector &x_,
|
||||
Vector &y_)
|
||||
{
|
||||
constexpr static int VDIM = 2;
|
||||
constexpr static int MAX_D1D = HDIV_MAX_D1D;
|
||||
constexpr static int MAX_Q1D = HDIV_MAX_Q1D;
|
||||
|
||||
auto L2Bo = Reshape(L2Bo_.Read(), Q1D, L2D1D);
|
||||
auto Gct = Reshape(Gct_.Read(), D1D, Q1D);
|
||||
auto Bot = Reshape(Bot_.Read(), D1D-1, Q1D);
|
||||
@@ -1527,6 +1534,10 @@ void PAHdivL2ApplyTranspose2D(const int D1D,
|
||||
|
||||
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
|
||||
{
|
||||
constexpr static int VDIM = 2;
|
||||
constexpr static int MAX_D1D = DofQuadLimits::HDIV_MAX_D1D;
|
||||
constexpr static int MAX_Q1D = DofQuadLimits::HDIV_MAX_Q1D;
|
||||
|
||||
double div[MAX_Q1D][MAX_Q1D];
|
||||
|
||||
for (int qy = 0; qy < Q1D; ++qy)
|
||||
@@ -1622,8 +1633,10 @@ void PAHdivL2Apply3D(const int D1D,
|
||||
const Vector &x_,
|
||||
Vector &y_)
|
||||
{
|
||||
MFEM_VERIFY(D1D <= HDIV_MAX_D1D, "Error: D1D > HDIV_MAX_D1D");
|
||||
MFEM_VERIFY(Q1D <= HDIV_MAX_Q1D, "Error: Q1D > HDIV_MAX_Q1D");
|
||||
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().HDIV_MAX_D1D,
|
||||
"Error: D1D > HDIV_MAX_D1D");
|
||||
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().HDIV_MAX_Q1D,
|
||||
"Error: Q1D > HDIV_MAX_Q1D");
|
||||
constexpr static int VDIM = 3;
|
||||
|
||||
auto Bo = Reshape(Bo_.Read(), Q1D, D1D-1);
|
||||
@@ -1635,7 +1648,7 @@ void PAHdivL2Apply3D(const int D1D,
|
||||
|
||||
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
|
||||
{
|
||||
double div[HDIV_MAX_Q1D][HDIV_MAX_Q1D][HDIV_MAX_Q1D];
|
||||
double div[DofQuadLimits::HDIV_MAX_Q1D][DofQuadLimits::HDIV_MAX_Q1D][DofQuadLimits::HDIV_MAX_Q1D];
|
||||
|
||||
for (int qz = 0; qz < Q1D; ++qz)
|
||||
{
|
||||
@@ -1658,7 +1671,7 @@ void PAHdivL2Apply3D(const int D1D,
|
||||
|
||||
for (int dz = 0; dz < D1Dz; ++dz)
|
||||
{
|
||||
double aXY[HDIV_MAX_Q1D][HDIV_MAX_Q1D];
|
||||
double aXY[DofQuadLimits::HDIV_MAX_Q1D][DofQuadLimits::HDIV_MAX_Q1D];
|
||||
for (int qy = 0; qy < Q1D; ++qy)
|
||||
{
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
@@ -1669,7 +1682,7 @@ void PAHdivL2Apply3D(const int D1D,
|
||||
|
||||
for (int dy = 0; dy < D1Dy; ++dy)
|
||||
{
|
||||
double aX[HDIV_MAX_Q1D];
|
||||
double aX[DofQuadLimits::HDIV_MAX_Q1D];
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
aX[qx] = 0.0;
|
||||
@@ -1724,7 +1737,7 @@ void PAHdivL2Apply3D(const int D1D,
|
||||
|
||||
for (int qz = 0; qz < Q1D; ++qz)
|
||||
{
|
||||
double aXY[HDIV_MAX_D1D][HDIV_MAX_D1D];
|
||||
double aXY[DofQuadLimits::HDIV_MAX_D1D][DofQuadLimits::HDIV_MAX_D1D];
|
||||
|
||||
for (int dy = 0; dy < L2D1D; ++dy)
|
||||
{
|
||||
@@ -1735,7 +1748,7 @@ void PAHdivL2Apply3D(const int D1D,
|
||||
}
|
||||
for (int qy = 0; qy < Q1D; ++qy)
|
||||
{
|
||||
double aX[HDIV_MAX_D1D];
|
||||
double aX[DofQuadLimits::HDIV_MAX_D1D];
|
||||
for (int dx = 0; dx < L2D1D; ++dx)
|
||||
{
|
||||
aX[dx] = 0;
|
||||
@@ -1783,8 +1796,10 @@ void PAHdivL2ApplyTranspose3D(const int D1D,
|
||||
const Vector &x_,
|
||||
Vector &y_)
|
||||
{
|
||||
MFEM_VERIFY(D1D <= HDIV_MAX_D1D, "Error: D1D > HDIV_MAX_D1D");
|
||||
MFEM_VERIFY(Q1D <= HDIV_MAX_Q1D, "Error: Q1D > HDIV_MAX_Q1D");
|
||||
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().HDIV_MAX_D1D,
|
||||
"Error: D1D > HDIV_MAX_D1D");
|
||||
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().HDIV_MAX_Q1D,
|
||||
"Error: Q1D > HDIV_MAX_Q1D");
|
||||
constexpr static int VDIM = 3;
|
||||
|
||||
auto L2Bo = Reshape(L2Bo_.Read(), Q1D, L2D1D);
|
||||
@@ -1796,7 +1811,7 @@ void PAHdivL2ApplyTranspose3D(const int D1D,
|
||||
|
||||
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
|
||||
{
|
||||
double div[HDIV_MAX_Q1D][HDIV_MAX_Q1D][HDIV_MAX_Q1D];
|
||||
double div[DofQuadLimits::HDIV_MAX_Q1D][DofQuadLimits::HDIV_MAX_Q1D][DofQuadLimits::HDIV_MAX_Q1D];
|
||||
|
||||
for (int qz = 0; qz < Q1D; ++qz)
|
||||
{
|
||||
@@ -1811,7 +1826,7 @@ void PAHdivL2ApplyTranspose3D(const int D1D,
|
||||
|
||||
for (int dz = 0; dz < L2D1D; ++dz)
|
||||
{
|
||||
double aXY[HDIV_MAX_Q1D][HDIV_MAX_Q1D];
|
||||
double aXY[DofQuadLimits::HDIV_MAX_Q1D][DofQuadLimits::HDIV_MAX_Q1D];
|
||||
for (int qy = 0; qy < Q1D; ++qy)
|
||||
{
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
@@ -1822,7 +1837,7 @@ void PAHdivL2ApplyTranspose3D(const int D1D,
|
||||
|
||||
for (int dy = 0; dy < L2D1D; ++dy)
|
||||
{
|
||||
double aX[HDIV_MAX_Q1D];
|
||||
double aX[DofQuadLimits::HDIV_MAX_Q1D];
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
aX[qx] = 0.0;
|
||||
@@ -1874,7 +1889,7 @@ void PAHdivL2ApplyTranspose3D(const int D1D,
|
||||
|
||||
for (int qz = 0; qz < Q1D; ++qz)
|
||||
{
|
||||
double aXY[HDIV_MAX_D1D][HDIV_MAX_D1D];
|
||||
double aXY[DofQuadLimits::HDIV_MAX_D1D][DofQuadLimits::HDIV_MAX_D1D];
|
||||
|
||||
int osc = 0;
|
||||
for (int c = 0; c < VDIM; ++c) // loop over x, y, z components
|
||||
@@ -1892,7 +1907,7 @@ void PAHdivL2ApplyTranspose3D(const int D1D,
|
||||
}
|
||||
for (int qy = 0; qy < Q1D; ++qy)
|
||||
{
|
||||
double aX[HDIV_MAX_D1D];
|
||||
double aX[DofQuadLimits::HDIV_MAX_D1D];
|
||||
for (int dx = 0; dx < D1Dx; ++dx)
|
||||
{
|
||||
aX[dx] = 0;
|
||||
|
||||
@@ -140,8 +140,8 @@ inline void SmemPAHdivMassApply2D(const int NE,
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : HDIV_MAX_Q1D;
|
||||
constexpr int MD1 = T_D1D ? T_D1D : HDIV_MAX_D1D;
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : DofQuadLimits::HDIV_MAX_Q1D;
|
||||
constexpr int MD1 = T_D1D ? T_D1D : DofQuadLimits::HDIV_MAX_D1D;
|
||||
constexpr int MDQ = (MQ1 > MD1) ? MQ1 : MD1;
|
||||
|
||||
MFEM_SHARED double smo[MQ1*(MD1-1)];
|
||||
@@ -310,8 +310,8 @@ inline void SmemPAHdivMassApply3D(const int NE,
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : HDIV_MAX_Q1D;
|
||||
constexpr int MD1 = T_D1D ? T_D1D : HDIV_MAX_D1D;
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : DofQuadLimits::HDIV_MAX_Q1D;
|
||||
constexpr int MD1 = T_D1D ? T_D1D : DofQuadLimits::HDIV_MAX_D1D;
|
||||
constexpr int MDQ = (MQ1 > MD1) ? MQ1 : MD1;
|
||||
|
||||
MFEM_SHARED double smo[MQ1*(MD1-1)];
|
||||
|
||||
@@ -34,11 +34,12 @@ static void PAHcurlApplyGradient2D(const int c_dofs1D,
|
||||
auto x = Reshape(x_.Read(), c_dofs1D, c_dofs1D, NE);
|
||||
auto y = Reshape(y_.ReadWrite(), 2 * c_dofs1D * o_dofs1D, NE);
|
||||
|
||||
constexpr static int MAX_D1D = HCURL_MAX_D1D;
|
||||
MFEM_VERIFY(c_dofs1D <= MAX_D1D && o_dofs1D <= c_dofs1D, "");
|
||||
MFEM_VERIFY(c_dofs1D <= DeviceDofQuadLimits::Get().MAX_D1D &&
|
||||
o_dofs1D <= c_dofs1D, "");
|
||||
|
||||
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
|
||||
{
|
||||
constexpr static int MAX_D1D = DofQuadLimits::HCURL_MAX_D1D;
|
||||
double w[MAX_D1D][MAX_D1D];
|
||||
|
||||
// horizontal part
|
||||
@@ -110,11 +111,12 @@ static void PAHcurlApplyGradient2DBId(const int c_dofs1D,
|
||||
auto x = Reshape(x_.Read(), c_dofs1D, c_dofs1D, NE);
|
||||
auto y = Reshape(y_.ReadWrite(), 2 * c_dofs1D * o_dofs1D, NE);
|
||||
|
||||
constexpr static int MAX_D1D = HCURL_MAX_D1D;
|
||||
MFEM_VERIFY(c_dofs1D <= MAX_D1D && o_dofs1D <= c_dofs1D, "");
|
||||
MFEM_VERIFY(c_dofs1D <= DeviceDofQuadLimits::Get().MAX_D1D &&
|
||||
o_dofs1D <= c_dofs1D, "");
|
||||
|
||||
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
|
||||
{
|
||||
constexpr static int MAX_D1D = DofQuadLimits::HCURL_MAX_D1D;
|
||||
double w[MAX_D1D][MAX_D1D];
|
||||
|
||||
// horizontal part
|
||||
@@ -178,11 +180,12 @@ static void PAHcurlApplyGradientTranspose2D(
|
||||
auto x = Reshape(x_.Read(), 2 * c_dofs1D * o_dofs1D, NE);
|
||||
auto y = Reshape(y_.ReadWrite(), c_dofs1D, c_dofs1D, NE);
|
||||
|
||||
constexpr static int MAX_D1D = HCURL_MAX_D1D;
|
||||
MFEM_VERIFY(c_dofs1D <= MAX_D1D && o_dofs1D <= c_dofs1D, "");
|
||||
MFEM_VERIFY(c_dofs1D <= DeviceDofQuadLimits::Get().HCURL_MAX_D1D &&
|
||||
o_dofs1D <= c_dofs1D, "");
|
||||
|
||||
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
|
||||
{
|
||||
constexpr static int MAX_D1D = DofQuadLimits::HCURL_MAX_D1D;
|
||||
double w[MAX_D1D][MAX_D1D];
|
||||
|
||||
// horizontal part (open x, closed y)
|
||||
@@ -253,11 +256,12 @@ static void PAHcurlApplyGradientTranspose2DBId(
|
||||
auto x = Reshape(x_.Read(), 2 * c_dofs1D * o_dofs1D, NE);
|
||||
auto y = Reshape(y_.ReadWrite(), c_dofs1D, c_dofs1D, NE);
|
||||
|
||||
constexpr static int MAX_D1D = HCURL_MAX_D1D;
|
||||
MFEM_VERIFY(c_dofs1D <= MAX_D1D && o_dofs1D <= c_dofs1D, "");
|
||||
MFEM_VERIFY(c_dofs1D <= DeviceDofQuadLimits::Get().HCURL_MAX_D1D &&
|
||||
o_dofs1D <= c_dofs1D, "");
|
||||
|
||||
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
|
||||
{
|
||||
constexpr static int MAX_D1D = DofQuadLimits::HCURL_MAX_D1D;
|
||||
double w[MAX_D1D][MAX_D1D];
|
||||
|
||||
// horizontal part (open x, closed y)
|
||||
@@ -324,11 +328,12 @@ static void PAHcurlApplyGradient3D(const int c_dofs1D,
|
||||
auto x = Reshape(x_.Read(), c_dofs1D, c_dofs1D, c_dofs1D, NE);
|
||||
auto y = Reshape(y_.ReadWrite(), (3 * c_dofs1D * c_dofs1D * o_dofs1D), NE);
|
||||
|
||||
constexpr static int MAX_D1D = HCURL_MAX_D1D;
|
||||
MFEM_VERIFY(c_dofs1D <= MAX_D1D && o_dofs1D <= c_dofs1D, "");
|
||||
MFEM_VERIFY(c_dofs1D <= DeviceDofQuadLimits::Get().HCURL_MAX_D1D &&
|
||||
o_dofs1D <= c_dofs1D, "");
|
||||
|
||||
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
|
||||
{
|
||||
constexpr static int MAX_D1D = DofQuadLimits::HCURL_MAX_D1D;
|
||||
double w1[MAX_D1D][MAX_D1D][MAX_D1D];
|
||||
double w2[MAX_D1D][MAX_D1D][MAX_D1D];
|
||||
|
||||
@@ -511,11 +516,13 @@ static void PAHcurlApplyGradient3DBId(const int c_dofs1D,
|
||||
auto x = Reshape(x_.Read(), c_dofs1D, c_dofs1D, c_dofs1D, NE);
|
||||
auto y = Reshape(y_.ReadWrite(), (3 * c_dofs1D * c_dofs1D * o_dofs1D), NE);
|
||||
|
||||
constexpr static int MAX_D1D = HCURL_MAX_D1D;
|
||||
MFEM_VERIFY(c_dofs1D <= MAX_D1D && o_dofs1D <= c_dofs1D, "");
|
||||
MFEM_VERIFY(c_dofs1D <= DeviceDofQuadLimits::Get().HCURL_MAX_D1D &&
|
||||
o_dofs1D <= c_dofs1D, "");
|
||||
|
||||
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
|
||||
{
|
||||
constexpr static int MAX_D1D = DofQuadLimits::HCURL_MAX_D1D;
|
||||
|
||||
double w1[MAX_D1D][MAX_D1D][MAX_D1D];
|
||||
double w2[MAX_D1D][MAX_D1D][MAX_D1D];
|
||||
|
||||
@@ -678,11 +685,12 @@ static void PAHcurlApplyGradientTranspose3D(
|
||||
auto x = Reshape(x_.Read(), (3 * c_dofs1D * c_dofs1D * o_dofs1D), NE);
|
||||
auto y = Reshape(y_.ReadWrite(), c_dofs1D, c_dofs1D, c_dofs1D, NE);
|
||||
|
||||
constexpr static int MAX_D1D = HCURL_MAX_D1D;
|
||||
MFEM_VERIFY(c_dofs1D <= MAX_D1D && o_dofs1D <= c_dofs1D, "");
|
||||
MFEM_VERIFY(c_dofs1D <= DeviceDofQuadLimits::Get().HCURL_MAX_D1D &&
|
||||
o_dofs1D <= c_dofs1D, "");
|
||||
|
||||
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
|
||||
{
|
||||
constexpr static int MAX_D1D = DofQuadLimits::HCURL_MAX_D1D;
|
||||
double w1[MAX_D1D][MAX_D1D][MAX_D1D];
|
||||
double w2[MAX_D1D][MAX_D1D][MAX_D1D];
|
||||
// ---
|
||||
@@ -863,11 +871,13 @@ static void PAHcurlApplyGradientTranspose3DBId(
|
||||
auto x = Reshape(x_.Read(), (3 * c_dofs1D * c_dofs1D * o_dofs1D), NE);
|
||||
auto y = Reshape(y_.ReadWrite(), c_dofs1D, c_dofs1D, c_dofs1D, NE);
|
||||
|
||||
constexpr static int MAX_D1D = HCURL_MAX_D1D;
|
||||
MFEM_VERIFY(c_dofs1D <= MAX_D1D && o_dofs1D <= c_dofs1D, "");
|
||||
MFEM_VERIFY(c_dofs1D <= DeviceDofQuadLimits::Get().HCURL_MAX_D1D &&
|
||||
o_dofs1D <= c_dofs1D, "");
|
||||
|
||||
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
|
||||
{
|
||||
constexpr static int MAX_D1D = DofQuadLimits::HCURL_MAX_D1D;
|
||||
|
||||
double w1[MAX_D1D][MAX_D1D][MAX_D1D];
|
||||
double w2[MAX_D1D][MAX_D1D][MAX_D1D];
|
||||
// ---
|
||||
@@ -1152,12 +1162,13 @@ static void PAHcurlVecH1IdentityApply2D(const int c_dofs1D,
|
||||
|
||||
auto vk = Reshape(pa_data.Read(), 2, (2 * c_dofs1D * o_dofs1D), NE);
|
||||
|
||||
constexpr static int MAX_D1D = HCURL_MAX_D1D;
|
||||
|
||||
MFEM_VERIFY(c_dofs1D <= MAX_D1D && o_dofs1D <= c_dofs1D, "");
|
||||
MFEM_VERIFY(c_dofs1D <= DeviceDofQuadLimits::Get().HCURL_MAX_D1D &&
|
||||
o_dofs1D <= c_dofs1D, "");
|
||||
|
||||
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
|
||||
{
|
||||
constexpr static int MAX_D1D = DofQuadLimits::HCURL_MAX_D1D;
|
||||
|
||||
double w[2][MAX_D1D][MAX_D1D];
|
||||
|
||||
// dofs that point parallel to x-axis (open in x, closed in y)
|
||||
@@ -1251,13 +1262,13 @@ static void PAHcurlVecH1IdentityApplyTranspose2D(const int c_dofs1D,
|
||||
|
||||
auto vk = Reshape(pa_data.Read(), 2, (2 * c_dofs1D * o_dofs1D), NE);
|
||||
|
||||
constexpr static int MAX_D1D = HCURL_MAX_D1D;
|
||||
//constexpr static int MAX_Q1D = HCURL_MAX_Q1D;
|
||||
|
||||
MFEM_VERIFY(c_dofs1D <= MAX_D1D && o_dofs1D <= c_dofs1D, "");
|
||||
MFEM_VERIFY(c_dofs1D <= DeviceDofQuadLimits::Get().HCURL_MAX_D1D &&
|
||||
o_dofs1D <= c_dofs1D, "");
|
||||
|
||||
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
|
||||
{
|
||||
constexpr static int MAX_D1D = DofQuadLimits::HCURL_MAX_D1D;
|
||||
|
||||
double w[2][MAX_D1D][MAX_D1D];
|
||||
|
||||
// dofs that point parallel to x-axis (open in x, closed in y)
|
||||
@@ -1360,12 +1371,13 @@ static void PAHcurlVecH1IdentityApply3D(const int c_dofs1D,
|
||||
|
||||
auto vk = Reshape(pa_data.Read(), 3, (3 * c_dofs1D * c_dofs1D * o_dofs1D),
|
||||
NE);
|
||||
|
||||
constexpr static int MAX_D1D = HCURL_MAX_D1D;
|
||||
MFEM_VERIFY(c_dofs1D <= MAX_D1D && o_dofs1D <= c_dofs1D, "");
|
||||
MFEM_VERIFY(c_dofs1D <= DeviceDofQuadLimits::Get().MAX_D1D &&
|
||||
o_dofs1D <= c_dofs1D, "");
|
||||
|
||||
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
|
||||
{
|
||||
constexpr static int MAX_D1D = DofQuadLimits::HCURL_MAX_D1D;
|
||||
|
||||
double w1[3][MAX_D1D][MAX_D1D][MAX_D1D];
|
||||
double w2[3][MAX_D1D][MAX_D1D][MAX_D1D];
|
||||
|
||||
@@ -1574,12 +1586,13 @@ static void PAHcurlVecH1IdentityApplyTranspose3D(const int c_dofs1D,
|
||||
auto vk = Reshape(pa_data.Read(), 3, (3 * c_dofs1D * c_dofs1D * o_dofs1D),
|
||||
NE);
|
||||
|
||||
constexpr static int MAX_D1D = HCURL_MAX_D1D;
|
||||
|
||||
MFEM_VERIFY(c_dofs1D <= MAX_D1D && o_dofs1D <= c_dofs1D, "");
|
||||
MFEM_VERIFY(c_dofs1D <= DeviceDofQuadLimits::Get().MAX_D1D &&
|
||||
o_dofs1D <= c_dofs1D, "");
|
||||
|
||||
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
|
||||
{
|
||||
constexpr static int MAX_D1D = DofQuadLimits::HCURL_MAX_D1D;
|
||||
|
||||
double w1[3][MAX_D1D][MAX_D1D][MAX_D1D];
|
||||
double w2[3][MAX_D1D][MAX_D1D][MAX_D1D];
|
||||
|
||||
|
||||
@@ -27,8 +27,8 @@ static void EAMassAssemble1D(const int NE,
|
||||
{
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
MFEM_VERIFY(D1D <= MAX_D1D, "");
|
||||
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
|
||||
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
|
||||
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
|
||||
auto B = Reshape(basis.Read(), Q1D, D1D);
|
||||
auto D = Reshape(padata.Read(), Q1D, NE);
|
||||
auto M = Reshape(eadata.ReadWrite(), D1D, D1D, NE);
|
||||
@@ -36,7 +36,7 @@ static void EAMassAssemble1D(const int NE,
|
||||
{
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : MAX_Q1D;
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
|
||||
double r_Bi[MQ1];
|
||||
double r_Bj[MQ1];
|
||||
for (int q = 0; q < Q1D; q++)
|
||||
@@ -77,8 +77,8 @@ static void EAMassAssemble2D(const int NE,
|
||||
{
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
MFEM_VERIFY(D1D <= MAX_D1D, "");
|
||||
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
|
||||
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
|
||||
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
|
||||
auto B = Reshape(basis.Read(), Q1D, D1D);
|
||||
auto D = Reshape(padata.Read(), Q1D, Q1D, NE);
|
||||
auto M = Reshape(eadata.ReadWrite(), D1D, D1D, D1D, D1D, NE);
|
||||
@@ -86,8 +86,8 @@ static void EAMassAssemble2D(const int NE,
|
||||
{
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
constexpr int MD1 = T_D1D ? T_D1D : MAX_D1D;
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : MAX_Q1D;
|
||||
constexpr int MD1 = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
|
||||
double r_B[MQ1][MD1];
|
||||
for (int d = 0; d < D1D; d++)
|
||||
{
|
||||
@@ -149,8 +149,8 @@ static void EAMassAssemble3D(const int NE,
|
||||
{
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
MFEM_VERIFY(D1D <= MAX_D1D, "");
|
||||
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
|
||||
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
|
||||
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
|
||||
auto B = Reshape(basis.Read(), Q1D, D1D);
|
||||
auto D = Reshape(padata.Read(), Q1D, Q1D, Q1D, NE);
|
||||
auto M = Reshape(eadata.ReadWrite(), D1D, D1D, D1D, D1D, D1D, D1D, NE);
|
||||
@@ -158,8 +158,8 @@ static void EAMassAssemble3D(const int NE,
|
||||
{
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
constexpr int MD1 = T_D1D ? T_D1D : MAX_D1D;
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : MAX_Q1D;
|
||||
constexpr int MD1 = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
|
||||
constexpr int DQ = T_D1D * T_Q1D;
|
||||
|
||||
// For quadratic and lower it's better to use registers but for higher-order you start to
|
||||
|
||||
@@ -25,8 +25,6 @@ static void PAMassAssembleDiagonal1D(const int NE,
|
||||
const int D1D,
|
||||
const int Q1D)
|
||||
{
|
||||
MFEM_VERIFY(D1D <= MAX_D1D, "");
|
||||
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
|
||||
auto B = Reshape(b.Read(), Q1D, D1D);
|
||||
auto D = Reshape(d.Read(), Q1D, NE);
|
||||
auto Y = Reshape(y.ReadWrite(), D1D, NE);
|
||||
@@ -34,7 +32,6 @@ static void PAMassAssembleDiagonal1D(const int NE,
|
||||
{
|
||||
for (int dx = 0; dx < D1D; ++dx)
|
||||
{
|
||||
Y(dx, e) = 0.0;
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
Y(dx, e) += B(qx, dx) * B(qx, dx) * D(qx, e);
|
||||
@@ -198,8 +195,7 @@ void PAMassApply1D_Element(const int e,
|
||||
auto X = ConstDeviceMatrix(x_, D1D, NE);
|
||||
auto Y = DeviceMatrix(y_, D1D, NE);
|
||||
|
||||
constexpr int max_Q1D = MAX_Q1D;
|
||||
double XQ[max_Q1D];
|
||||
double XQ[DofQuadLimits::MAX_Q1D];
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
XQ[qx] = 0.0;
|
||||
@@ -232,8 +228,8 @@ static void PAMassApply1D(const int NE,
|
||||
const int d1d = 0,
|
||||
const int q1d = 0)
|
||||
{
|
||||
MFEM_VERIFY(d1d <= MAX_D1D, "");
|
||||
MFEM_VERIFY(q1d <= MAX_Q1D, "");
|
||||
MFEM_VERIFY(d1d <= DeviceDofQuadLimits::Get().MAX_D1D, "");
|
||||
MFEM_VERIFY(q1d <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
|
||||
|
||||
const auto B = b_.Read();
|
||||
const auto Bt = bt_.Read();
|
||||
|
||||
@@ -42,8 +42,8 @@ inline void PAMassAssembleDiagonal2D(const int NE,
|
||||
{
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
MFEM_VERIFY(D1D <= MAX_D1D, "");
|
||||
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
|
||||
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
|
||||
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
|
||||
auto B = Reshape(b.Read(), Q1D, D1D);
|
||||
auto D = Reshape(d.Read(), Q1D, Q1D, NE);
|
||||
auto Y = Reshape(y.ReadWrite(), D1D, D1D, NE);
|
||||
@@ -51,8 +51,8 @@ inline void PAMassAssembleDiagonal2D(const int NE,
|
||||
{
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
constexpr int MD1 = T_D1D ? T_D1D : MAX_D1D;
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : MAX_Q1D;
|
||||
constexpr int MD1 = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
|
||||
double QD[MQ1][MD1];
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
@@ -90,10 +90,10 @@ inline void SmemPAMassAssembleDiagonal2D(const int NE,
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
constexpr int NBZ = T_NBZ ? T_NBZ : 1;
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : MAX_Q1D;
|
||||
constexpr int MD1 = T_D1D ? T_D1D : MAX_D1D;
|
||||
MFEM_VERIFY(D1D <= MD1, "");
|
||||
MFEM_VERIFY(Q1D <= MQ1, "");
|
||||
const int max_q1d = T_Q1D ? T_Q1D : DeviceDofQuadLimits::Get().MAX_Q1D;
|
||||
const int max_d1d = T_D1D ? T_D1D : DeviceDofQuadLimits::Get().MAX_D1D;
|
||||
MFEM_VERIFY(D1D <= max_d1d, "");
|
||||
MFEM_VERIFY(Q1D <= max_q1d, "");
|
||||
auto b = Reshape(b_.Read(), Q1D, D1D);
|
||||
auto D = Reshape(d_.Read(), Q1D, Q1D, NE);
|
||||
auto Y = Reshape(y_.ReadWrite(), D1D, D1D, NE);
|
||||
@@ -103,8 +103,8 @@ inline void SmemPAMassAssembleDiagonal2D(const int NE,
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
constexpr int NBZ = T_NBZ ? T_NBZ : 1;
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : MAX_Q1D;
|
||||
constexpr int MD1 = T_D1D ? T_D1D : MAX_D1D;
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
|
||||
constexpr int MD1 = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
|
||||
MFEM_SHARED double B[MQ1][MD1];
|
||||
MFEM_SHARED double QDZ[NBZ][MQ1][MD1];
|
||||
double (*QD)[MD1] = (double (*)[MD1])(QDZ + tidz);
|
||||
@@ -156,8 +156,8 @@ inline void PAMassAssembleDiagonal3D(const int NE,
|
||||
{
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
MFEM_VERIFY(D1D <= MAX_D1D, "");
|
||||
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
|
||||
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
|
||||
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
|
||||
auto B = Reshape(b.Read(), Q1D, D1D);
|
||||
auto D = Reshape(d.Read(), Q1D, Q1D, Q1D, NE);
|
||||
auto Y = Reshape(y.ReadWrite(), D1D, D1D, D1D, NE);
|
||||
@@ -165,8 +165,8 @@ inline void PAMassAssembleDiagonal3D(const int NE,
|
||||
{
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
constexpr int MD1 = T_D1D ? T_D1D : MAX_D1D;
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : MAX_Q1D;
|
||||
constexpr int MD1 = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
|
||||
double QQD[MQ1][MQ1][MD1];
|
||||
double QDD[MQ1][MD1][MD1];
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
@@ -226,10 +226,10 @@ inline void SmemPAMassAssembleDiagonal3D(const int NE,
|
||||
{
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : MAX_Q1D;
|
||||
constexpr int MD1 = T_D1D ? T_D1D : MAX_D1D;
|
||||
MFEM_VERIFY(D1D <= MD1, "");
|
||||
MFEM_VERIFY(Q1D <= MQ1, "");
|
||||
const int max_q1d = T_Q1D ? T_Q1D : DeviceDofQuadLimits::Get().MAX_Q1D;
|
||||
const int max_d1d = T_D1D ? T_D1D : DeviceDofQuadLimits::Get().MAX_D1D;
|
||||
MFEM_VERIFY(D1D <= max_d1d, "");
|
||||
MFEM_VERIFY(Q1D <= max_q1d, "");
|
||||
auto b = Reshape(b_.Read(), Q1D, D1D);
|
||||
auto D = Reshape(d_.Read(), Q1D, Q1D, Q1D, NE);
|
||||
auto Y = Reshape(y_.ReadWrite(), D1D, D1D, D1D, NE);
|
||||
@@ -238,8 +238,8 @@ inline void SmemPAMassAssembleDiagonal3D(const int NE,
|
||||
const int tidz = MFEM_THREAD_ID(z);
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
constexpr int MD1 = T_D1D ? T_D1D : MAX_D1D;
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : MAX_Q1D;
|
||||
constexpr int MD1 = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
|
||||
MFEM_SHARED double B[MQ1][MD1];
|
||||
MFEM_SHARED double QQD[MQ1][MQ1][MD1];
|
||||
MFEM_SHARED double QDD[MQ1][MD1][MD1];
|
||||
@@ -365,8 +365,8 @@ void PAMassApply2D_Element(const int e,
|
||||
}
|
||||
}
|
||||
|
||||
constexpr int max_D1D = MAX_D1D;
|
||||
constexpr int max_Q1D = MAX_Q1D;
|
||||
constexpr int max_D1D = DofQuadLimits::MAX_D1D;
|
||||
constexpr int max_Q1D = DofQuadLimits::MAX_Q1D;
|
||||
double sol_xy[max_Q1D][max_Q1D];
|
||||
for (int qy = 0; qy < Q1D; ++qy)
|
||||
{
|
||||
@@ -447,8 +447,8 @@ void SmemPAMassApply2D_Element(const int e,
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
constexpr int NBZ = T_NBZ ? T_NBZ : 1;
|
||||
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : MAX_Q1D;
|
||||
constexpr int MD1 = T_D1D ? T_D1D : MAX_D1D;
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
|
||||
constexpr int MD1 = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
|
||||
constexpr int MDQ = (MQ1 > MD1) ? MQ1 : MD1;
|
||||
|
||||
auto b = ConstDeviceMatrix(b_, Q1D, D1D);
|
||||
@@ -592,8 +592,8 @@ void PAMassApply3D_Element(const int e,
|
||||
}
|
||||
}
|
||||
|
||||
constexpr int max_D1D = MAX_D1D;
|
||||
constexpr int max_Q1D = MAX_Q1D;
|
||||
constexpr int max_D1D = DofQuadLimits::MAX_D1D;
|
||||
constexpr int max_Q1D = DofQuadLimits::MAX_Q1D;
|
||||
double sol_xyz[max_Q1D][max_Q1D][max_Q1D];
|
||||
for (int qz = 0; qz < Q1D; ++qz)
|
||||
{
|
||||
@@ -722,8 +722,8 @@ void SmemPAMassApply3D_Element(const int e,
|
||||
{
|
||||
constexpr int D1D = T_D1D ? T_D1D : d1d;
|
||||
constexpr int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : MAX_Q1D;
|
||||
constexpr int MD1 = T_D1D ? T_D1D : MAX_D1D;
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
|
||||
constexpr int MD1 = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
|
||||
constexpr int MDQ = (MQ1 > MD1) ? MQ1 : MD1;
|
||||
|
||||
auto b = ConstDeviceMatrix(b_, Q1D, D1D);
|
||||
@@ -948,8 +948,8 @@ inline void PAMassApply2D(const int NE,
|
||||
const int d1d = 0,
|
||||
const int q1d = 0)
|
||||
{
|
||||
MFEM_VERIFY(T_D1D ? T_D1D : d1d <= MAX_D1D, "");
|
||||
MFEM_VERIFY(T_Q1D ? T_Q1D : q1d <= MAX_Q1D, "");
|
||||
MFEM_VERIFY(T_D1D ? T_D1D : d1d <= DeviceDofQuadLimits::Get().MAX_D1D, "");
|
||||
MFEM_VERIFY(T_Q1D ? T_Q1D : q1d <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
|
||||
|
||||
const auto B = b_.Read();
|
||||
const auto Bt = bt_.Read();
|
||||
@@ -978,10 +978,10 @@ inline void SmemPAMassApply2D(const int NE,
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
constexpr int NBZ = T_NBZ ? T_NBZ : 1;
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : MAX_Q1D;
|
||||
constexpr int MD1 = T_D1D ? T_D1D : MAX_D1D;
|
||||
MFEM_VERIFY(D1D <= MD1, "");
|
||||
MFEM_VERIFY(Q1D <= MQ1, "");
|
||||
const int max_q1d = T_Q1D ? T_Q1D : DeviceDofQuadLimits::Get().MAX_Q1D;
|
||||
const int max_d1d = T_D1D ? T_D1D : DeviceDofQuadLimits::Get().MAX_D1D;
|
||||
MFEM_VERIFY(D1D <= max_d1d, "");
|
||||
MFEM_VERIFY(Q1D <= max_q1d, "");
|
||||
const auto b = b_.Read();
|
||||
const auto D = d_.Read();
|
||||
const auto x = x_.Read();
|
||||
@@ -1004,8 +1004,8 @@ inline void PAMassApply3D(const int NE,
|
||||
const int d1d = 0,
|
||||
const int q1d = 0)
|
||||
{
|
||||
MFEM_VERIFY(T_D1D ? T_D1D : d1d <= MAX_D1D, "");
|
||||
MFEM_VERIFY(T_Q1D ? T_Q1D : q1d <= MAX_Q1D, "");
|
||||
MFEM_VERIFY(T_D1D ? T_D1D : d1d <= DeviceDofQuadLimits::Get().MAX_D1D, "");
|
||||
MFEM_VERIFY(T_Q1D ? T_Q1D : q1d <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
|
||||
|
||||
const auto B = b_.Read();
|
||||
const auto Bt = bt_.Read();
|
||||
@@ -1033,10 +1033,10 @@ inline void SmemPAMassApply3D(const int NE,
|
||||
MFEM_CONTRACT_VAR(bt_);
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
constexpr int M1Q = T_Q1D ? T_Q1D : MAX_Q1D;
|
||||
constexpr int M1D = T_D1D ? T_D1D : MAX_D1D;
|
||||
MFEM_VERIFY(D1D <= M1D, "");
|
||||
MFEM_VERIFY(Q1D <= M1Q, "");
|
||||
const int max_q1d = T_Q1D ? T_Q1D : DeviceDofQuadLimits::Get().MAX_Q1D;
|
||||
const int max_d1d = T_D1D ? T_D1D : DeviceDofQuadLimits::Get().MAX_D1D;
|
||||
MFEM_VERIFY(D1D <= max_d1d, "");
|
||||
MFEM_VERIFY(Q1D <= max_q1d, "");
|
||||
auto b = b_.Read();
|
||||
auto d = d_.Read();
|
||||
auto x = x_.Read();
|
||||
|
||||
@@ -128,7 +128,7 @@ void MassIntegrator::AssemblePABoundary(const FiniteElementSpace &fes)
|
||||
|
||||
int map_type = el.GetMapType();
|
||||
dim = el.GetDim(); // Dimension of the boundary element, *not* the mesh
|
||||
ne = fes.GetMesh()->GetNBE();
|
||||
ne = fes.GetMesh()->GetNFbyType(FaceType::Boundary);
|
||||
nq = ir->GetNPoints();
|
||||
face_geom = mesh->GetFaceGeometricFactors(*ir, GeometricFactors::DETERMINANTS,
|
||||
FaceType::Boundary, mt);
|
||||
|
||||
@@ -31,10 +31,6 @@ static void PAHcurlH1Apply2D(const int D1D,
|
||||
const Vector &x,
|
||||
Vector &y)
|
||||
{
|
||||
constexpr static int VDIM = 2;
|
||||
constexpr static int MAX_D1D = HCURL_MAX_D1D;
|
||||
constexpr static int MAX_Q1D = HCURL_MAX_Q1D;
|
||||
|
||||
auto Bc = Reshape(bc.Read(), Q1D, D1D);
|
||||
auto Gc = Reshape(gc.Read(), Q1D, D1D);
|
||||
auto Bot = Reshape(bot.Read(), D1D-1, Q1D);
|
||||
@@ -45,6 +41,10 @@ static void PAHcurlH1Apply2D(const int D1D,
|
||||
|
||||
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
|
||||
{
|
||||
constexpr static int VDIM = 2;
|
||||
constexpr static int MAX_D1D = DofQuadLimits::HCURL_MAX_D1D;
|
||||
constexpr static int MAX_Q1D = DofQuadLimits::HCURL_MAX_Q1D;
|
||||
|
||||
double mass[MAX_Q1D][MAX_Q1D][VDIM];
|
||||
|
||||
for (int qy = 0; qy < Q1D; ++qy)
|
||||
@@ -155,10 +155,6 @@ static void PAHcurlH1ApplyTranspose2D(const int D1D,
|
||||
const Vector &x,
|
||||
Vector &y)
|
||||
{
|
||||
constexpr static int VDIM = 2;
|
||||
constexpr static int MAX_D1D = HCURL_MAX_D1D;
|
||||
constexpr static int MAX_Q1D = HCURL_MAX_Q1D;
|
||||
|
||||
auto Bc = Reshape(bc.Read(), Q1D, D1D);
|
||||
auto Bo = Reshape(bo.Read(), Q1D, D1D-1);
|
||||
auto Bt = Reshape(bct.Read(), D1D, Q1D);
|
||||
@@ -169,6 +165,10 @@ static void PAHcurlH1ApplyTranspose2D(const int D1D,
|
||||
|
||||
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
|
||||
{
|
||||
constexpr static int VDIM = 2;
|
||||
constexpr static int MAX_D1D = DofQuadLimits::HCURL_MAX_D1D;
|
||||
constexpr static int MAX_Q1D = DofQuadLimits::HCURL_MAX_Q1D;
|
||||
|
||||
double mass[MAX_Q1D][MAX_Q1D][VDIM];
|
||||
|
||||
for (int qy = 0; qy < Q1D; ++qy)
|
||||
@@ -280,11 +280,10 @@ static void PAHcurlH1Apply3D(const int D1D,
|
||||
const Vector &x,
|
||||
Vector &y)
|
||||
{
|
||||
constexpr static int MAX_D1D = HCURL_MAX_D1D;
|
||||
constexpr static int MAX_Q1D = HCURL_MAX_Q1D;
|
||||
|
||||
MFEM_VERIFY(D1D <= MAX_D1D, "Error: D1D > MAX_D1D");
|
||||
MFEM_VERIFY(Q1D <= MAX_Q1D, "Error: Q1D > MAX_Q1D");
|
||||
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().HCURL_MAX_D1D,
|
||||
"Error: D1D > MAX_D1D");
|
||||
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().HCURL_MAX_Q1D,
|
||||
"Error: Q1D > MAX_Q1D");
|
||||
|
||||
constexpr static int VDIM = 3;
|
||||
|
||||
@@ -298,6 +297,9 @@ static void PAHcurlH1Apply3D(const int D1D,
|
||||
|
||||
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
|
||||
{
|
||||
constexpr static int MAX_D1D = DofQuadLimits::HCURL_MAX_D1D;
|
||||
constexpr static int MAX_Q1D = DofQuadLimits::HCURL_MAX_Q1D;
|
||||
|
||||
double mass[MAX_Q1D][MAX_Q1D][MAX_Q1D][VDIM];
|
||||
|
||||
for (int qz = 0; qz < Q1D; ++qz)
|
||||
@@ -470,11 +472,10 @@ static void PAHcurlH1ApplyTranspose3D(const int D1D,
|
||||
const Vector &x,
|
||||
Vector &y)
|
||||
{
|
||||
constexpr static int MAX_D1D = HCURL_MAX_D1D;
|
||||
constexpr static int MAX_Q1D = HCURL_MAX_Q1D;
|
||||
|
||||
MFEM_VERIFY(D1D <= MAX_D1D, "Error: D1D > MAX_D1D");
|
||||
MFEM_VERIFY(Q1D <= MAX_Q1D, "Error: Q1D > MAX_Q1D");
|
||||
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().HCURL_MAX_D1D,
|
||||
"Error: D1D > MAX_D1D");
|
||||
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().HCURL_MAX_Q1D,
|
||||
"Error: Q1D > MAX_Q1D");
|
||||
|
||||
constexpr static int VDIM = 3;
|
||||
|
||||
@@ -488,6 +489,9 @@ static void PAHcurlH1ApplyTranspose3D(const int D1D,
|
||||
|
||||
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
|
||||
{
|
||||
constexpr static int MAX_D1D = DofQuadLimits::HCURL_MAX_D1D;
|
||||
constexpr static int MAX_Q1D = DofQuadLimits::HCURL_MAX_Q1D;
|
||||
|
||||
double mass[MAX_Q1D][MAX_Q1D][MAX_Q1D][VDIM];
|
||||
|
||||
for (int qz = 0; qz < Q1D; ++qz)
|
||||
|
||||
@@ -233,8 +233,8 @@ static void PAVectorDiffusionDiagonal2D(const int NE,
|
||||
{
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
MFEM_VERIFY(D1D <= MAX_D1D, "");
|
||||
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
|
||||
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
|
||||
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
|
||||
auto B = Reshape(b.Read(), Q1D, D1D);
|
||||
auto G = Reshape(g.Read(), Q1D, D1D);
|
||||
// note the different shape for D, this is a (symmetric) matrix so we only
|
||||
@@ -245,8 +245,8 @@ static void PAVectorDiffusionDiagonal2D(const int NE,
|
||||
{
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
constexpr int MD1 = T_D1D ? T_D1D : MAX_D1D;
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : MAX_Q1D;
|
||||
constexpr int MD1 = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
|
||||
// gradphi \cdot Q \gradphi has four terms
|
||||
double QD0[MQ1][MD1];
|
||||
double QD1[MQ1][MD1];
|
||||
@@ -301,10 +301,10 @@ static void PAVectorDiffusionDiagonal3D(const int NE,
|
||||
constexpr int DIM = 3;
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : MAX_Q1D;
|
||||
constexpr int MD1 = T_D1D ? T_D1D : MAX_D1D;
|
||||
MFEM_VERIFY(D1D <= MD1, "");
|
||||
MFEM_VERIFY(Q1D <= MQ1, "");
|
||||
const int max_q1d = T_Q1D ? T_Q1D : DeviceDofQuadLimits::Get().MAX_Q1D;
|
||||
const int max_d1d = T_D1D ? T_D1D : DeviceDofQuadLimits::Get().MAX_D1D;
|
||||
MFEM_VERIFY(D1D <= max_d1d, "");
|
||||
MFEM_VERIFY(Q1D <= max_q1d, "");
|
||||
auto B = Reshape(b.Read(), Q1D, D1D);
|
||||
auto G = Reshape(g.Read(), Q1D, D1D);
|
||||
auto Q = Reshape(d.Read(), Q1D*Q1D*Q1D, 6, NE);
|
||||
@@ -313,8 +313,8 @@ static void PAVectorDiffusionDiagonal3D(const int NE,
|
||||
{
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
constexpr int MD1 = T_D1D ? T_D1D : MAX_D1D;
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : MAX_Q1D;
|
||||
constexpr int MD1 = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
|
||||
double QQD[MQ1][MQ1][MD1];
|
||||
double QDD[MQ1][MD1][MD1];
|
||||
for (int i = 0; i < DIM; ++i)
|
||||
@@ -442,8 +442,8 @@ void PAVectorDiffusionApply2D(const int NE,
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
const int VDIM = T_VDIM ? T_VDIM : vdim;
|
||||
MFEM_VERIFY(D1D <= MAX_D1D, "");
|
||||
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
|
||||
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
|
||||
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
|
||||
auto B = Reshape(b.Read(), Q1D, D1D);
|
||||
auto G = Reshape(g.Read(), Q1D, D1D);
|
||||
auto Bt = Reshape(bt.Read(), D1D, Q1D);
|
||||
@@ -456,8 +456,8 @@ void PAVectorDiffusionApply2D(const int NE,
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
const int VDIM = T_VDIM ? T_VDIM : vdim;
|
||||
constexpr int max_D1D = T_D1D ? T_D1D : MAX_D1D;
|
||||
constexpr int max_Q1D = T_Q1D ? T_Q1D : MAX_Q1D;
|
||||
constexpr int max_D1D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
|
||||
constexpr int max_Q1D = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
|
||||
|
||||
double grad[max_Q1D][max_Q1D][2];
|
||||
for (int c = 0; c < VDIM; c++)
|
||||
@@ -563,8 +563,8 @@ void PAVectorDiffusionApply3D(const int NE,
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
constexpr int VDIM = 3;
|
||||
MFEM_VERIFY(D1D <= MAX_D1D, "");
|
||||
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
|
||||
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
|
||||
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
|
||||
auto B = Reshape(b.Read(), Q1D, D1D);
|
||||
auto G = Reshape(g.Read(), Q1D, D1D);
|
||||
auto Bt = Reshape(bt.Read(), D1D, Q1D);
|
||||
@@ -576,8 +576,8 @@ void PAVectorDiffusionApply3D(const int NE,
|
||||
{
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
constexpr int max_D1D = T_D1D ? T_D1D : MAX_D1D;
|
||||
constexpr int max_Q1D = T_Q1D ? T_Q1D : MAX_Q1D;
|
||||
constexpr int max_D1D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
|
||||
constexpr int max_Q1D = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
|
||||
for (int c = 0; c < VDIM; ++ c)
|
||||
{
|
||||
double grad[max_Q1D][max_Q1D][max_Q1D][3];
|
||||
|
||||
@@ -170,9 +170,9 @@ static void PADivergenceApply2D(const int NE,
|
||||
const int TR_D1D = T_TR_D1D ? T_TR_D1D : tr_d1d;
|
||||
const int TE_D1D = T_TE_D1D ? T_TE_D1D : te_d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
MFEM_VERIFY(TR_D1D <= MAX_D1D, "");
|
||||
MFEM_VERIFY(TE_D1D <= MAX_D1D, "");
|
||||
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
|
||||
MFEM_VERIFY(TR_D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
|
||||
MFEM_VERIFY(TE_D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
|
||||
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
|
||||
auto B = Reshape(b.Read(), Q1D, TR_D1D);
|
||||
auto G = Reshape(g.Read(), Q1D, TR_D1D);
|
||||
auto Bt = Reshape(bt.Read(), TE_D1D, Q1D);
|
||||
@@ -186,8 +186,8 @@ static void PADivergenceApply2D(const int NE,
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
const int VDIM = 2;
|
||||
// the following variables are evaluated at compile time
|
||||
constexpr int max_TE_D1D = T_TE_D1D ? T_TE_D1D : MAX_D1D;
|
||||
constexpr int max_Q1D = T_Q1D ? T_Q1D : MAX_Q1D;
|
||||
constexpr int max_TE_D1D = T_TE_D1D ? T_TE_D1D : DofQuadLimits::MAX_D1D;
|
||||
constexpr int max_Q1D = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
|
||||
|
||||
double grad[max_Q1D][max_Q1D][VDIM];
|
||||
double div[max_Q1D][max_Q1D];
|
||||
@@ -308,9 +308,9 @@ static void PADivergenceApplyTranspose2D(const int NE,
|
||||
const int TR_D1D = T_TR_D1D ? T_TR_D1D : tr_d1d;
|
||||
const int TE_D1D = T_TE_D1D ? T_TE_D1D : te_d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
MFEM_VERIFY(TR_D1D <= MAX_D1D, "");
|
||||
MFEM_VERIFY(TE_D1D <= MAX_D1D, "");
|
||||
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
|
||||
MFEM_VERIFY(TR_D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
|
||||
MFEM_VERIFY(TE_D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
|
||||
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
|
||||
auto Bt = Reshape(bt.Read(), TR_D1D, Q1D);
|
||||
auto Gt = Reshape(gt.Read(), TR_D1D, Q1D);
|
||||
auto B = Reshape(b.Read(), Q1D, TE_D1D);
|
||||
@@ -324,8 +324,8 @@ static void PADivergenceApplyTranspose2D(const int NE,
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
const int VDIM = 2;
|
||||
// the following variables are evaluated at compile time
|
||||
constexpr int max_TR_D1D = T_TR_D1D ? T_TR_D1D : MAX_D1D;
|
||||
constexpr int max_Q1D = T_Q1D ? T_Q1D : MAX_Q1D;
|
||||
constexpr int max_TR_D1D = T_TR_D1D ? T_TR_D1D : DofQuadLimits::MAX_D1D;
|
||||
constexpr int max_Q1D = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
|
||||
|
||||
double quadTest[max_Q1D][max_Q1D];
|
||||
double grad[max_Q1D][max_Q1D][VDIM];
|
||||
@@ -424,9 +424,9 @@ static void PADivergenceApply3D(const int NE,
|
||||
const int TR_D1D = T_TR_D1D ? T_TR_D1D : tr_d1d;
|
||||
const int TE_D1D = T_TE_D1D ? T_TE_D1D : te_d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
MFEM_VERIFY(TR_D1D <= MAX_D1D, "");
|
||||
MFEM_VERIFY(TE_D1D <= MAX_D1D, "");
|
||||
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
|
||||
MFEM_VERIFY(TR_D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
|
||||
MFEM_VERIFY(TE_D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
|
||||
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
|
||||
auto B = Reshape(b.Read(), Q1D, TR_D1D);
|
||||
auto G = Reshape(g.Read(), Q1D, TR_D1D);
|
||||
auto Bt = Reshape(bt.Read(), TE_D1D, Q1D);
|
||||
@@ -440,8 +440,8 @@ static void PADivergenceApply3D(const int NE,
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
const int VDIM = 3;
|
||||
// the following variables are evaluated at compile time
|
||||
constexpr int max_TE_D1D = T_TE_D1D ? T_TE_D1D : MAX_D1D;
|
||||
constexpr int max_Q1D = T_Q1D ? T_Q1D : MAX_Q1D;
|
||||
constexpr int max_TE_D1D = T_TE_D1D ? T_TE_D1D : DofQuadLimits::MAX_D1D;
|
||||
constexpr int max_Q1D = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
|
||||
|
||||
double grad[max_Q1D][max_Q1D][max_Q1D][VDIM];
|
||||
double div[max_Q1D][max_Q1D][max_Q1D];
|
||||
@@ -607,9 +607,9 @@ static void PADivergenceApplyTranspose3D(const int NE,
|
||||
const int TR_D1D = T_TR_D1D ? T_TR_D1D : tr_d1d;
|
||||
const int TE_D1D = T_TE_D1D ? T_TE_D1D : te_d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
MFEM_VERIFY(TR_D1D <= MAX_D1D, "");
|
||||
MFEM_VERIFY(TE_D1D <= MAX_D1D, "");
|
||||
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
|
||||
MFEM_VERIFY(TR_D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
|
||||
MFEM_VERIFY(TE_D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
|
||||
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
|
||||
auto Bt = Reshape(bt.Read(), TR_D1D, Q1D);
|
||||
auto Gt = Reshape(gt.Read(), TR_D1D, Q1D);
|
||||
auto B = Reshape(b.Read(), Q1D, TE_D1D);
|
||||
@@ -623,8 +623,8 @@ static void PADivergenceApplyTranspose3D(const int NE,
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
const int VDIM = 3;
|
||||
// the following variables are evaluated at compile time
|
||||
constexpr int max_TR_D1D = T_TR_D1D ? T_TR_D1D : MAX_D1D;
|
||||
constexpr int max_Q1D = T_Q1D ? T_Q1D : MAX_Q1D;
|
||||
constexpr int max_TR_D1D = T_TR_D1D ? T_TR_D1D : DofQuadLimits::MAX_D1D;
|
||||
constexpr int max_Q1D = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
|
||||
|
||||
double quadTest[max_Q1D][max_Q1D][max_Q1D];
|
||||
double grad[max_Q1D][max_Q1D][max_Q1D][VDIM];
|
||||
@@ -786,9 +786,9 @@ static void SmemPADivergenceApply3D(const int NE,
|
||||
const int TE_D1D = T_TE_D1D ? T_TE_D1D : te_d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
|
||||
MFEM_VERIFY(TR_D1D <= MAX_D1D, "");
|
||||
MFEM_VERIFY(TE_D1D <= MAX_D1D, "");
|
||||
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
|
||||
MFEM_VERIFY(TR_D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
|
||||
MFEM_VERIFY(TE_D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
|
||||
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
|
||||
|
||||
auto b = Reshape(b_.Read(), Q1D, TR_D1D);
|
||||
auto g = Reshape(g_.Read(), Q1D, TR_D1D);
|
||||
@@ -804,9 +804,9 @@ static void SmemPADivergenceApply3D(const int NE,
|
||||
const int D1DR = T_TR_D1D ? T_TR_D1D : tr_d1d;
|
||||
const int D1DE = T_TE_D1D ? T_TE_D1D : te_d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : MAX_Q1D;
|
||||
constexpr int MD1R = T_TR_D1D ? T_TR_D1D : MAX_D1D;
|
||||
constexpr int MD1E = T_TE_D1D ? T_TE_D1D : MAX_D1D;
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
|
||||
constexpr int MD1R = T_TR_D1D ? T_TR_D1D : DofQuadLimits::MAX_D1D;
|
||||
constexpr int MD1E = T_TE_D1D ? T_TE_D1D : DofQuadLimits::MAX_D1D;
|
||||
constexpr int MD1 = MD1E > MD1R ? MD1E : MD1R;
|
||||
constexpr int MDQ = MQ1 > MD1 ? MQ1 : MD1;
|
||||
MFEM_SHARED double sBG[2][MQ1*MD1];
|
||||
|
||||
@@ -118,8 +118,8 @@ static void PAVectorMassAssembleDiagonal2D(const int NE,
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
constexpr int VDIM = 2;
|
||||
MFEM_VERIFY(D1D <= MAX_D1D, "");
|
||||
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
|
||||
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
|
||||
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
|
||||
auto B = Reshape(B_.Read(), Q1D, D1D);
|
||||
auto op = Reshape(op_.Read(), Q1D, Q1D, NE);
|
||||
auto y = Reshape(diag_.ReadWrite(), D1D, D1D, VDIM, NE);
|
||||
@@ -127,8 +127,8 @@ static void PAVectorMassAssembleDiagonal2D(const int NE,
|
||||
{
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
constexpr int max_D1D = T_D1D ? T_D1D : MAX_D1D;
|
||||
constexpr int max_Q1D = T_Q1D ? T_Q1D : MAX_Q1D;
|
||||
constexpr int max_D1D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
|
||||
constexpr int max_Q1D = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
|
||||
|
||||
double temp[max_Q1D][max_D1D];
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
@@ -170,8 +170,8 @@ static void PAVectorMassAssembleDiagonal3D(const int NE,
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
constexpr int VDIM = 3;
|
||||
MFEM_VERIFY(D1D <= MAX_D1D, "");
|
||||
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
|
||||
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
|
||||
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
|
||||
auto B = Reshape(B_.Read(), Q1D, D1D);
|
||||
auto op = Reshape(op_.Read(), Q1D, Q1D, Q1D, NE);
|
||||
auto y = Reshape(diag_.ReadWrite(), D1D, D1D, D1D, VDIM, NE);
|
||||
@@ -180,8 +180,8 @@ static void PAVectorMassAssembleDiagonal3D(const int NE,
|
||||
const int D1D = T_D1D ? T_D1D : d1d; // nvcc workaround
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
// the following variables are evaluated at compile time
|
||||
constexpr int max_D1D = T_D1D ? T_D1D : MAX_D1D;
|
||||
constexpr int max_Q1D = T_Q1D ? T_Q1D : MAX_Q1D;
|
||||
constexpr int max_D1D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
|
||||
constexpr int max_Q1D = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
|
||||
|
||||
double temp[max_Q1D][max_Q1D][max_D1D];
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
@@ -281,8 +281,8 @@ static void PAVectorMassApply2D(const int NE,
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
constexpr int VDIM = 2;
|
||||
MFEM_VERIFY(D1D <= MAX_D1D, "");
|
||||
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
|
||||
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
|
||||
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
|
||||
auto B = Reshape(B_.Read(), Q1D, D1D);
|
||||
auto Bt = Reshape(Bt_.Read(), D1D, Q1D);
|
||||
auto op = Reshape(op_.Read(), Q1D, Q1D, NE);
|
||||
@@ -293,8 +293,8 @@ static void PAVectorMassApply2D(const int NE,
|
||||
const int D1D = T_D1D ? T_D1D : d1d; // nvcc workaround
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
// the following variables are evaluated at compile time
|
||||
constexpr int max_D1D = T_D1D ? T_D1D : MAX_D1D;
|
||||
constexpr int max_Q1D = T_Q1D ? T_Q1D : MAX_Q1D;
|
||||
constexpr int max_D1D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
|
||||
constexpr int max_Q1D = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
|
||||
double sol_xy[max_Q1D][max_Q1D];
|
||||
for (int c = 0; c < VDIM; ++c)
|
||||
{
|
||||
@@ -377,8 +377,8 @@ static void PAVectorMassApply3D(const int NE,
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
constexpr int VDIM = 3;
|
||||
MFEM_VERIFY(D1D <= MAX_D1D, "");
|
||||
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
|
||||
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
|
||||
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
|
||||
auto B = Reshape(B_.Read(), Q1D, D1D);
|
||||
auto Bt = Reshape(Bt_.Read(), D1D, Q1D);
|
||||
auto op = Reshape(op_.Read(), Q1D, Q1D, Q1D, NE);
|
||||
@@ -388,8 +388,8 @@ static void PAVectorMassApply3D(const int NE,
|
||||
{
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
constexpr int max_D1D = T_D1D ? T_D1D : MAX_D1D;
|
||||
constexpr int max_Q1D = T_Q1D ? T_Q1D : MAX_Q1D;
|
||||
constexpr int max_D1D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
|
||||
constexpr int max_Q1D = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
|
||||
double sol_xyz[max_Q1D][max_Q1D][max_Q1D];
|
||||
for (int c = 0; c < VDIM; ++ c)
|
||||
{
|
||||
|
||||
@@ -38,7 +38,7 @@ static void BLFEvalAssemble2D(const int vdim, const int nbe, const int d,
|
||||
{
|
||||
if (M(e) == 0) { return; } // ignore
|
||||
|
||||
constexpr int Q = T_Q1D ? T_Q1D : MAX_Q1D;
|
||||
constexpr int Q = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
|
||||
double QQ[Q];
|
||||
|
||||
for (int c = 0; c < vdim; ++c)
|
||||
@@ -92,8 +92,8 @@ static void BLFEvalAssemble3D(const int vdim, const int nbe, const int d,
|
||||
{
|
||||
if (M(e) == 0) { return; } // ignore
|
||||
|
||||
constexpr int Q = T_Q1D ? T_Q1D : MAX_Q1D;
|
||||
constexpr int D = T_D1D ? T_D1D : MAX_D1D;
|
||||
constexpr int Q = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
|
||||
constexpr int D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
|
||||
|
||||
MFEM_SHARED double sBt[Q*D];
|
||||
MFEM_SHARED double sQQ[Q*Q];
|
||||
|
||||
@@ -33,7 +33,7 @@ void BFLFEvalAssemble2D(const int nbe, const int d, const int q,
|
||||
{
|
||||
if (M(e) == 0) { return; } // ignore (in a lambda return acts as continue)
|
||||
|
||||
constexpr int Q = T_Q1D ? T_Q1D : MAX_Q1D;
|
||||
constexpr int Q = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
|
||||
double QQ[Q];
|
||||
|
||||
for (int qx = 0; qx < q; ++qx)
|
||||
@@ -67,8 +67,8 @@ void BFLFEvalAssemble3D(const int nbe, const int d, const int q,
|
||||
{
|
||||
if (M(e) == 0) { return; } // ignore
|
||||
|
||||
constexpr int Q = T_Q1D ? T_Q1D : MAX_Q1D;
|
||||
constexpr int D = T_D1D ? T_D1D : MAX_D1D;
|
||||
constexpr int Q = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
|
||||
constexpr int D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
|
||||
|
||||
MFEM_SHARED double sBt[Q*D];
|
||||
MFEM_SHARED double sQQ[Q*Q];
|
||||
|
||||
@@ -36,8 +36,8 @@ static void DLFEvalAssemble2D(const int vdim, const int ne, const int d,
|
||||
{
|
||||
if (M(e) == 0) { return; } // ignore
|
||||
|
||||
constexpr int Q = T_Q1D ? T_Q1D : MAX_Q1D;
|
||||
constexpr int D = T_D1D ? T_D1D : MAX_D1D;
|
||||
constexpr int Q = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
|
||||
constexpr int D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
|
||||
|
||||
MFEM_SHARED double sBt[Q*D];
|
||||
MFEM_SHARED double sQQ[Q*Q];
|
||||
@@ -107,8 +107,8 @@ static void DLFEvalAssemble3D(const int vdim, const int ne, const int d,
|
||||
{
|
||||
if (M(e) == 0) { return; } // ignore
|
||||
|
||||
constexpr int Q = T_Q1D ? T_Q1D : MAX_Q1D;
|
||||
constexpr int D = T_D1D ? T_D1D : MAX_D1D;
|
||||
constexpr int Q = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
|
||||
constexpr int D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
|
||||
constexpr int MQD = (Q >= D) ? Q : D;
|
||||
|
||||
double u[D];
|
||||
|
||||
@@ -36,8 +36,8 @@ void DLFGradAssemble2D(const int vdim, const int ne, const int d, const int q,
|
||||
{
|
||||
if (M(e) == 0) { return; } // ignore
|
||||
|
||||
constexpr int Q = T_Q1D ? T_Q1D : MAX_Q1D;
|
||||
constexpr int D = T_D1D ? T_D1D : MAX_D1D;
|
||||
constexpr int Q = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
|
||||
constexpr int D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
|
||||
|
||||
MFEM_SHARED double sBGt[2][Q*D];
|
||||
MFEM_SHARED double sQQ[2][Q*Q];
|
||||
@@ -130,8 +130,8 @@ void DLFGradAssemble3D(const int vdim, const int ne, const int d, const int q,
|
||||
{
|
||||
if (M(e) == 0) { return; } // ignore
|
||||
|
||||
constexpr int Q = T_Q1D ? T_Q1D : MAX_Q1D;
|
||||
constexpr int D = T_D1D ? T_D1D : MAX_D1D;
|
||||
constexpr int Q = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
|
||||
constexpr int D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
|
||||
constexpr int MQD = (Q >= D) ? Q : D;
|
||||
|
||||
MFEM_SHARED double sBGt[2][Q*D];
|
||||
|
||||
@@ -22,8 +22,10 @@ static void HdivDLFAssemble2D(
|
||||
const double *bc, const double *j, const double *weights,
|
||||
const Vector &coeff, double *y)
|
||||
{
|
||||
MFEM_VERIFY(T_D1D || d <= HDIV_MAX_D1D, "Problem size too large.");
|
||||
MFEM_VERIFY(T_Q1D || q <= HDIV_MAX_Q1D, "Problem size too large.");
|
||||
MFEM_VERIFY(T_D1D || d <= DeviceDofQuadLimits::Get().HDIV_MAX_D1D,
|
||||
"Problem size too large.");
|
||||
MFEM_VERIFY(T_Q1D || q <= DeviceDofQuadLimits::Get().HDIV_MAX_Q1D,
|
||||
"Problem size too large.");
|
||||
|
||||
static constexpr int vdim = 2;
|
||||
const auto F = coeff.Read();
|
||||
@@ -40,8 +42,8 @@ static void HdivDLFAssemble2D(
|
||||
{
|
||||
if (M(e) == 0) { return; } // ignore
|
||||
|
||||
constexpr int Q = T_Q1D ? T_Q1D : HDIV_MAX_Q1D;
|
||||
constexpr int D = T_D1D ? T_D1D : HDIV_MAX_D1D;
|
||||
constexpr int Q = T_Q1D ? T_Q1D : DofQuadLimits::HDIV_MAX_Q1D;
|
||||
constexpr int D = T_D1D ? T_D1D : DofQuadLimits::HDIV_MAX_D1D;
|
||||
|
||||
MFEM_SHARED double sBot[Q*D];
|
||||
MFEM_SHARED double sBct[Q*D];
|
||||
@@ -121,8 +123,10 @@ static void HdivDLFAssemble3D(
|
||||
const double *bc, const double *j, const double *weights,
|
||||
const Vector &coeff, double *y)
|
||||
{
|
||||
MFEM_VERIFY(T_D1D || d <= HDIV_MAX_D1D, "Problem size too large.");
|
||||
MFEM_VERIFY(T_Q1D || q <= HDIV_MAX_Q1D, "Problem size too large.");
|
||||
MFEM_VERIFY(T_D1D || d <= DeviceDofQuadLimits::Get().HDIV_MAX_D1D,
|
||||
"Problem size too large.");
|
||||
MFEM_VERIFY(T_Q1D || q <= DeviceDofQuadLimits::Get().HDIV_MAX_Q1D,
|
||||
"Problem size too large.");
|
||||
|
||||
static constexpr int vdim = 3;
|
||||
const auto F = coeff.Read();
|
||||
@@ -139,8 +143,8 @@ static void HdivDLFAssemble3D(
|
||||
{
|
||||
if (M(e) == 0) { return; } // ignore
|
||||
|
||||
constexpr int Q = T_Q1D ? T_Q1D : HDIV_MAX_Q1D;
|
||||
constexpr int D = T_D1D ? T_D1D : HDIV_MAX_D1D;
|
||||
constexpr int Q = T_Q1D ? T_Q1D : DofQuadLimits::HDIV_MAX_Q1D;
|
||||
constexpr int D = T_D1D ? T_D1D : DofQuadLimits::HDIV_MAX_D1D;
|
||||
|
||||
MFEM_SHARED double sBot[Q*D];
|
||||
MFEM_SHARED double sBct[Q*D];
|
||||
|
||||
@@ -136,8 +136,8 @@ static void PAConvectionNLApply2D(const int NE,
|
||||
{
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
MFEM_VERIFY(D1D <= MAX_D1D, "");
|
||||
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
|
||||
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
|
||||
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
|
||||
auto B = Reshape(b.Read(), Q1D, D1D);
|
||||
auto G = Reshape(g.Read(), Q1D, D1D);
|
||||
auto Bt = Reshape(bt.Read(), D1D, Q1D);
|
||||
@@ -148,8 +148,8 @@ static void PAConvectionNLApply2D(const int NE,
|
||||
{
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
constexpr int max_D1D = T_D1D ? T_D1D : MAX_D1D;
|
||||
constexpr int max_Q1D = T_Q1D ? T_Q1D : MAX_Q1D;
|
||||
constexpr int max_D1D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
|
||||
constexpr int max_Q1D = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
|
||||
|
||||
double data[max_Q1D][max_Q1D][2];
|
||||
double grad0[max_Q1D][max_Q1D][2];
|
||||
@@ -273,8 +273,8 @@ static void PAConvectionNLApply3D(const int NE,
|
||||
constexpr int VDIM = 3;
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
MFEM_VERIFY(D1D <= MAX_D1D, "");
|
||||
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
|
||||
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
|
||||
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
|
||||
|
||||
auto B = Reshape(b.Read(), Q1D, D1D);
|
||||
auto G = Reshape(g.Read(), Q1D, D1D);
|
||||
@@ -288,8 +288,8 @@ static void PAConvectionNLApply3D(const int NE,
|
||||
constexpr int VDIM = 3;
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
constexpr int max_D1D = T_D1D ? T_D1D : MAX_D1D;
|
||||
constexpr int max_Q1D = T_Q1D ? T_Q1D : MAX_Q1D;
|
||||
constexpr int max_D1D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
|
||||
constexpr int max_Q1D = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
|
||||
|
||||
double data[max_Q1D][max_Q1D][max_Q1D][VDIM];
|
||||
double grad0[max_Q1D][max_Q1D][max_Q1D][VDIM];
|
||||
|
||||
+330
-2
@@ -16,6 +16,7 @@
|
||||
// Formulas at http://nines.cs.kuleuven.be/research/ecf/ecf.html
|
||||
|
||||
#include "fem.hpp"
|
||||
#include "../mesh/nurbs.hpp"
|
||||
#include <cmath>
|
||||
|
||||
#ifdef MFEM_USE_MPFR
|
||||
@@ -35,6 +36,7 @@ IntegrationRule::IntegrationRule(IntegrationRule &irx, IntegrationRule &iry)
|
||||
ny = iry.GetNPoints();
|
||||
SetSize(nx * ny);
|
||||
SetPointIndices();
|
||||
Order = std::min(irx.GetOrder(), iry.GetOrder());
|
||||
|
||||
for (j = 0; j < ny; j++)
|
||||
{
|
||||
@@ -59,6 +61,7 @@ IntegrationRule::IntegrationRule(IntegrationRule &irx, IntegrationRule &iry,
|
||||
const int nz = irz.GetNPoints();
|
||||
SetSize(nx*ny*nz);
|
||||
SetPointIndices();
|
||||
Order = std::min({irx.GetOrder(), iry.GetOrder(), irz.GetOrder()});
|
||||
|
||||
for (int iz = 0; iz < nz; ++iz)
|
||||
{
|
||||
@@ -124,6 +127,7 @@ void IntegrationRule::GrundmannMollerSimplexRule(int s, int n)
|
||||
np /= f;
|
||||
SetSize(np);
|
||||
SetPointIndices();
|
||||
Order = 2*s + 1;
|
||||
|
||||
int pt = 0;
|
||||
for (int i = 0; i <= s; i++)
|
||||
@@ -173,6 +177,52 @@ void IntegrationRule::GrundmannMollerSimplexRule(int s, int n)
|
||||
}
|
||||
}
|
||||
|
||||
IntegrationRule*
|
||||
IntegrationRule::ApplyToKnotIntervals(KnotVector const& kv) const
|
||||
{
|
||||
const int np = this->GetNPoints();
|
||||
const int ne = kv.GetNE();
|
||||
|
||||
IntegrationRule *kvir = new IntegrationRule(ne * np);
|
||||
kvir->SetOrder(GetOrder());
|
||||
|
||||
double x0 = kv[0];
|
||||
double x1 = x0;
|
||||
|
||||
int id = 0;
|
||||
for (int e=0; e<ne; ++e)
|
||||
{
|
||||
x0 = x1;
|
||||
|
||||
if (e == ne-1)
|
||||
{
|
||||
x1 = kv[kv.Size() - 1];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Find the next unique knot
|
||||
while (id < kv.Size() - 1)
|
||||
{
|
||||
id++;
|
||||
if (kv[id] != x0)
|
||||
{
|
||||
x1 = kv[id];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const double s = x1 - x0;
|
||||
|
||||
for (int j=0; j<this->GetNPoints(); ++j)
|
||||
{
|
||||
const double x = x0 + (s * (*this)[j].x);
|
||||
(*kvir)[(e * np) + j].Set1w(x, (*this)[j].weight);
|
||||
}
|
||||
}
|
||||
|
||||
return kvir;
|
||||
}
|
||||
|
||||
#ifdef MFEM_USE_MPFR
|
||||
|
||||
@@ -375,6 +425,7 @@ void QuadratureFunctions1D::GaussLegendre(const int np, IntegrationRule* ir)
|
||||
{
|
||||
ir->SetSize(np);
|
||||
ir->SetPointIndices();
|
||||
ir->SetOrder(2*np - 1);
|
||||
|
||||
switch (np)
|
||||
{
|
||||
@@ -481,9 +532,11 @@ void QuadratureFunctions1D::GaussLobatto(const int np, IntegrationRule* ir)
|
||||
if ( np == 1 )
|
||||
{
|
||||
ir->IntPoint(0).Set1w(0.5, 1.0);
|
||||
ir->SetOrder(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
ir->SetOrder(2*np - 3);
|
||||
|
||||
#ifndef MFEM_USE_MPFR
|
||||
|
||||
@@ -578,6 +631,7 @@ void QuadratureFunctions1D::OpenUniform(const int np, IntegrationRule* ir)
|
||||
{
|
||||
ir->SetSize(np);
|
||||
ir->SetPointIndices();
|
||||
ir->SetOrder(np - 1 + np%2);
|
||||
|
||||
// The Newton-Cotes quadrature is based on weights that integrate exactly the
|
||||
// interpolatory polynomial through the equally spaced quadrature points.
|
||||
@@ -594,6 +648,7 @@ void QuadratureFunctions1D::ClosedUniform(const int np,
|
||||
{
|
||||
ir->SetSize(np);
|
||||
ir->SetPointIndices();
|
||||
ir->SetOrder(np - 1 + np%2);
|
||||
if ( np == 1 ) // allow this case as "closed"
|
||||
{
|
||||
ir->IntPoint(0).Set1w(0.5, 1.0);
|
||||
@@ -612,6 +667,7 @@ void QuadratureFunctions1D::OpenHalfUniform(const int np, IntegrationRule* ir)
|
||||
{
|
||||
ir->SetSize(np);
|
||||
ir->SetPointIndices();
|
||||
ir->SetOrder(np - 1 + np%2);
|
||||
|
||||
// Open half points: the centers of np uniform intervals
|
||||
for (int i = 0; i < np ; ++i)
|
||||
@@ -628,6 +684,7 @@ void QuadratureFunctions1D::ClosedGL(const int np, IntegrationRule* ir)
|
||||
ir->SetPointIndices();
|
||||
ir->IntPoint(0).x = 0.0;
|
||||
ir->IntPoint(np-1).x = 1.0;
|
||||
ir->SetOrder(np - 1 + np%2); // Is this the correct order?
|
||||
|
||||
if ( np > 2 )
|
||||
{
|
||||
@@ -953,13 +1010,17 @@ const IntegrationRule &IntegrationRules::Get(int GeomType, int Order)
|
||||
if (!HaveIntRule(*ir_array, Order))
|
||||
{
|
||||
IntegrationRule *ir = GenerateIntegrationRule(GeomType, Order);
|
||||
#ifdef MFEM_DEBUG
|
||||
int RealOrder = Order;
|
||||
while (RealOrder+1 < ir_array->Size() &&
|
||||
(*ir_array)[RealOrder+1] == ir)
|
||||
{
|
||||
RealOrder++;
|
||||
}
|
||||
ir->SetOrder(RealOrder);
|
||||
MFEM_VERIFY(RealOrder == ir->GetOrder(), "internal error");
|
||||
#else
|
||||
MFEM_CONTRACT_VAR(ir);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1068,6 +1129,7 @@ IntegrationRule *IntegrationRules::PointIntegrationRule(int Order)
|
||||
IntegrationRule *ir = new IntegrationRule(1);
|
||||
ir->IntPoint(0).x = .0;
|
||||
ir->IntPoint(0).weight = 1.;
|
||||
ir->SetOrder(1);
|
||||
|
||||
PointIntRules[1] = PointIntRules[0] = ir;
|
||||
|
||||
@@ -1132,6 +1194,7 @@ IntegrationRule *IntegrationRules::SegmentIntegrationRule(int Order)
|
||||
{
|
||||
// Effectively passing memory management to SegmentIntegrationRules
|
||||
IntegrationRule *refined_ir = new IntegrationRule(2*n);
|
||||
refined_ir->SetOrder(ir->GetOrder());
|
||||
for (int j = 0; j < n; j++)
|
||||
{
|
||||
refined_ir->IntPoint(j).x = ir->IntPoint(j).x/2.0;
|
||||
@@ -1156,16 +1219,18 @@ IntegrationRule *IntegrationRules::TriangleIntegrationRule(int Order)
|
||||
// assuming that orders <= 25 are pre-allocated
|
||||
switch (Order)
|
||||
{
|
||||
case 0: // 1 point - 0 degree
|
||||
case 0: // 1 point - degree 1
|
||||
case 1:
|
||||
ir = new IntegrationRule(1);
|
||||
ir->AddTriMidPoint(0, 0.5);
|
||||
ir->SetOrder(1);
|
||||
TriangleIntRules[0] = TriangleIntRules[1] = ir;
|
||||
return ir;
|
||||
|
||||
case 2: // 3 point - 2 degree
|
||||
ir = new IntegrationRule(3);
|
||||
ir->AddTriPoints3(0, 1./6., 1./6.);
|
||||
ir->SetOrder(2);
|
||||
TriangleIntRules[2] = ir;
|
||||
// interior points
|
||||
return ir;
|
||||
@@ -1174,6 +1239,7 @@ IntegrationRule *IntegrationRules::TriangleIntegrationRule(int Order)
|
||||
ir = new IntegrationRule(4);
|
||||
ir->AddTriMidPoint(0, -0.28125); // -9./32.
|
||||
ir->AddTriPoints3(1, 0.2, 25./96.);
|
||||
ir->SetOrder(3);
|
||||
TriangleIntRules[3] = ir;
|
||||
return ir;
|
||||
|
||||
@@ -1181,6 +1247,7 @@ IntegrationRule *IntegrationRules::TriangleIntegrationRule(int Order)
|
||||
ir = new IntegrationRule(6);
|
||||
ir->AddTriPoints3(0, 0.091576213509770743460, 0.054975871827660933819);
|
||||
ir->AddTriPoints3(3, 0.44594849091596488632, 0.11169079483900573285);
|
||||
ir->SetOrder(4);
|
||||
TriangleIntRules[4] = ir;
|
||||
return ir;
|
||||
|
||||
@@ -1189,6 +1256,7 @@ IntegrationRule *IntegrationRules::TriangleIntegrationRule(int Order)
|
||||
ir->AddTriMidPoint(0, 0.1125);
|
||||
ir->AddTriPoints3(1, 0.10128650732345633880, 0.062969590272413576298);
|
||||
ir->AddTriPoints3(4, 0.47014206410511508977, 0.066197076394253090369);
|
||||
ir->SetOrder(5);
|
||||
TriangleIntRules[5] = ir;
|
||||
return ir;
|
||||
|
||||
@@ -1198,6 +1266,7 @@ IntegrationRule *IntegrationRules::TriangleIntegrationRule(int Order)
|
||||
ir->AddTriPoints3(3, 0.24928674517091042129, 0.058393137863189683013);
|
||||
ir->AddTriPoints6(6, 0.053145049844816947353, 0.31035245103378440542,
|
||||
0.041425537809186787597);
|
||||
ir->SetOrder(6);
|
||||
TriangleIntRules[6] = ir;
|
||||
return ir;
|
||||
|
||||
@@ -1212,6 +1281,7 @@ IntegrationRule *IntegrationRules::TriangleIntegrationRule(int Order)
|
||||
0.30472650086816719592, 0.028775042784981585738);
|
||||
ir->AddTriPoints3R(9, 0.51584233435359177926, 0.27771616697639178257,
|
||||
0.20644149867001643817, 0.067493187009802774463);
|
||||
ir->SetOrder(7);
|
||||
TriangleIntRules[7] = ir;
|
||||
return ir;
|
||||
|
||||
@@ -1227,6 +1297,7 @@ IntegrationRule *IntegrationRules::TriangleIntegrationRule(int Order)
|
||||
ir->AddTriPoints6(10, 0.008394777409957605337213834539296,
|
||||
0.263112829634638113421785786284643,
|
||||
0.0136151570872174971324223450369544);
|
||||
ir->SetOrder(8);
|
||||
TriangleIntRules[8] = ir;
|
||||
return ir;
|
||||
|
||||
@@ -1244,6 +1315,7 @@ IntegrationRule *IntegrationRules::TriangleIntegrationRule(int Order)
|
||||
ir->AddTriPoints6(13, 0.0368384120547362836348175987833851,
|
||||
0.2219629891607656956751025276931919,
|
||||
0.0216417696886446886446886446886446);
|
||||
ir->SetOrder(9);
|
||||
TriangleIntRules[9] = ir;
|
||||
return ir;
|
||||
|
||||
@@ -1263,6 +1335,7 @@ IntegrationRule *IntegrationRules::TriangleIntegrationRule(int Order)
|
||||
ir->AddTriPoints6(19, 0.0095408154002994575801528096228873,
|
||||
0.0668032510122002657735402127620247,
|
||||
4.71083348186641172996373548344341E-03);
|
||||
ir->SetOrder(10);
|
||||
TriangleIntRules[10] = ir;
|
||||
return ir;
|
||||
|
||||
@@ -1285,6 +1358,7 @@ IntegrationRule *IntegrationRules::TriangleIntegrationRule(int Order)
|
||||
ir->AddTriPoints6(22, 0.0448416775891304433090523914688007,
|
||||
0.2772206675282791551488214673424523,
|
||||
0.0205281577146442833208261574536469);
|
||||
ir->SetOrder(11);
|
||||
TriangleIntRules[11] = ir;
|
||||
return ir;
|
||||
|
||||
@@ -1301,6 +1375,7 @@ IntegrationRule *IntegrationRules::TriangleIntegrationRule(int Order)
|
||||
1.11783866011515E-02);
|
||||
ir->AddTriPoints6(27, 2.57340505483300E-02, 1.16251915907597E-01,
|
||||
8.65811555432950E-03);
|
||||
ir->SetOrder(12);
|
||||
TriangleIntRules[12] = ir;
|
||||
return ir;
|
||||
|
||||
@@ -1328,6 +1403,7 @@ IntegrationRule *IntegrationRules::TriangleIntegrationRule(int Order)
|
||||
ir->AddTriPoints6(31, 0.0897330604516053590796290561145196,
|
||||
0.2723110556841851025078181617634414,
|
||||
0.0182757511120486476280967518782978);
|
||||
ir->SetOrder(13);
|
||||
TriangleIntRules[13] = ir;
|
||||
return ir;
|
||||
|
||||
@@ -1347,6 +1423,7 @@ IntegrationRule *IntegrationRules::TriangleIntegrationRule(int Order)
|
||||
7.21815405676700E-03);
|
||||
ir->AddTriPoints6(36, 1.26833093287200E-03, 1.18974497696957E-01,
|
||||
2.50511441925050E-03);
|
||||
ir->SetOrder(14);
|
||||
TriangleIntRules[14] = ir;
|
||||
return ir;
|
||||
|
||||
@@ -1370,6 +1447,7 @@ IntegrationRule *IntegrationRules::TriangleIntegrationRule(int Order)
|
||||
0.012803670460631195);
|
||||
ir->AddTriPoints6(48, 0.1684044181246992, 0.281835668099084562,
|
||||
0.016544097765822835);
|
||||
ir->SetOrder(15);
|
||||
TriangleIntRules[15] = ir;
|
||||
return ir;
|
||||
|
||||
@@ -1397,6 +1475,7 @@ IntegrationRule *IntegrationRules::TriangleIntegrationRule(int Order)
|
||||
9.14639838501250E-03);
|
||||
ir->AddTriPoints6 (55, 1.46631822248280E-02, 8.07113136795640E-02,
|
||||
3.33281600208250E-03);
|
||||
ir->SetOrder(17);
|
||||
TriangleIntRules[16] = TriangleIntRules[17] = ir;
|
||||
return ir;
|
||||
|
||||
@@ -1428,6 +1507,7 @@ IntegrationRule *IntegrationRules::TriangleIntegrationRule(int Order)
|
||||
0.0051292818680995);
|
||||
ir->AddTriPoints6 (67, 0.065494628082938, 0.010161119296278,
|
||||
0.001899964427651);
|
||||
ir->SetOrder(19);
|
||||
TriangleIntRules[18] = TriangleIntRules[19] = ir;
|
||||
return ir;
|
||||
|
||||
@@ -1462,6 +1542,7 @@ IntegrationRule *IntegrationRules::TriangleIntegrationRule(int Order)
|
||||
0.009336472951467735);
|
||||
ir->AddTriPoints6(79, 0.140710844943938733, 0.323170566536257485,
|
||||
0.01140911202919763);
|
||||
ir->SetOrder(20);
|
||||
TriangleIntRules[20] = ir;
|
||||
return ir;
|
||||
|
||||
@@ -1513,6 +1594,7 @@ IntegrationRule *IntegrationRules::TriangleIntegrationRule(int Order)
|
||||
0.00707722325261307);
|
||||
ir->AddTriPoints6(120, 0.191771865867325067, 0.325618122595983752,
|
||||
0.007440689780584005);
|
||||
ir->SetOrder(25);
|
||||
TriangleIntRules[21] =
|
||||
TriangleIntRules[22] =
|
||||
TriangleIntRules[23] =
|
||||
@@ -1563,6 +1645,7 @@ IntegrationRule *IntegrationRules::TetrahedronIntegrationRule(int Order)
|
||||
case 1:
|
||||
ir = new IntegrationRule(1);
|
||||
ir->AddTetMidPoint(0, 1./6.);
|
||||
ir->SetOrder(1);
|
||||
TetrahedronIntRules[0] = TetrahedronIntRules[1] = ir;
|
||||
return ir;
|
||||
|
||||
@@ -1570,6 +1653,7 @@ IntegrationRule *IntegrationRules::TetrahedronIntegrationRule(int Order)
|
||||
ir = new IntegrationRule(4);
|
||||
// ir->AddTetPoints4(0, 0.13819660112501051518, 1./24.);
|
||||
ir->AddTetPoints4b(0, 0.58541019662496845446, 1./24.);
|
||||
ir->SetOrder(2);
|
||||
TetrahedronIntRules[2] = ir;
|
||||
return ir;
|
||||
|
||||
@@ -1577,6 +1661,7 @@ IntegrationRule *IntegrationRules::TetrahedronIntegrationRule(int Order)
|
||||
ir = new IntegrationRule(5);
|
||||
ir->AddTetMidPoint(0, -2./15.);
|
||||
ir->AddTetPoints4b(1, 0.5, 0.075);
|
||||
ir->SetOrder(3);
|
||||
TetrahedronIntRules[3] = ir;
|
||||
return ir;
|
||||
|
||||
@@ -1585,6 +1670,7 @@ IntegrationRule *IntegrationRules::TetrahedronIntegrationRule(int Order)
|
||||
ir->AddTetPoints4(0, 1./14., 343./45000.);
|
||||
ir->AddTetMidPoint(4, -74./5625.);
|
||||
ir->AddTetPoints6(5, 0.10059642383320079500, 28./1125.);
|
||||
ir->SetOrder(4);
|
||||
TetrahedronIntRules[4] = ir;
|
||||
return ir;
|
||||
|
||||
@@ -1595,6 +1681,7 @@ IntegrationRule *IntegrationRules::TetrahedronIntegrationRule(int Order)
|
||||
ir->AddTetPoints4(6, 0.092735250310891226402, 0.012248840519393658257);
|
||||
ir->AddTetPoints4b(10, 0.067342242210098170608,
|
||||
0.018781320953002641800);
|
||||
ir->SetOrder(5);
|
||||
TetrahedronIntRules[5] = ir;
|
||||
return ir;
|
||||
|
||||
@@ -1608,6 +1695,7 @@ IntegrationRule *IntegrationRules::TetrahedronIntegrationRule(int Order)
|
||||
9.2261969239424536825E-03);
|
||||
ir->AddTetPoints12(12, 0.063661001875017525299, 0.26967233145831580803,
|
||||
8.0357142857142857143E-03);
|
||||
ir->SetOrder(6);
|
||||
TetrahedronIntRules[6] = ir;
|
||||
return ir;
|
||||
|
||||
@@ -1621,6 +1709,7 @@ IntegrationRule *IntegrationRules::TetrahedronIntegrationRule(int Order)
|
||||
ir->AddTetPoints4b(15, 2.3825066607381275412E-03,
|
||||
4.8914252630734993858E-03);
|
||||
ir->AddTetPoints12(19, 0.1, 0.2, 0.027557319223985890653);
|
||||
ir->SetOrder(7);
|
||||
TetrahedronIntRules[7] = ir;
|
||||
return ir;
|
||||
|
||||
@@ -1638,6 +1727,7 @@ IntegrationRule *IntegrationRules::TetrahedronIntegrationRule(int Order)
|
||||
5.7044858086819185068E-03);
|
||||
ir->AddTetPoints4(38, 0.20682993161067320408, 0.014250305822866901248);
|
||||
ir->AddTetMidPoint(42, -0.020500188658639915841);
|
||||
ir->SetOrder(8);
|
||||
TetrahedronIntRules[8] = ir;
|
||||
return ir;
|
||||
|
||||
@@ -1668,6 +1758,7 @@ IntegrationRule *IntegrationRules::PyramidIntegrationRule(int Order)
|
||||
int npts = irc.GetNPoints();
|
||||
AllocIntRule(PyramidIntRules, Order);
|
||||
PyramidIntRules[Order] = new IntegrationRule(npts);
|
||||
PyramidIntRules[Order]->SetOrder(Order); // FIXME: see comment above
|
||||
|
||||
for (int k=0; k<npts; k++)
|
||||
{
|
||||
@@ -1690,6 +1781,12 @@ IntegrationRule *IntegrationRules::PrismIntegrationRule(int Order)
|
||||
int ns = irs.GetNPoints();
|
||||
AllocIntRule(PrismIntRules, Order);
|
||||
PrismIntRules[Order] = new IntegrationRule(nt * ns);
|
||||
PrismIntRules[Order]->SetOrder(std::min(irt.GetOrder(), irs.GetOrder()));
|
||||
while (Order < std::min(irt.GetOrder(), irs.GetOrder()))
|
||||
{
|
||||
AllocIntRule(PrismIntRules, ++Order);
|
||||
PrismIntRules[Order] = PrismIntRules[Order-1];
|
||||
}
|
||||
|
||||
for (int ks=0; ks<ns; ks++)
|
||||
{
|
||||
@@ -1725,4 +1822,235 @@ IntegrationRule *IntegrationRules::CubeIntegrationRule(int Order)
|
||||
return CubeIntRules[Order];
|
||||
}
|
||||
|
||||
IntegrationRule& NURBSMeshRules::GetElementRule(const int elem,
|
||||
const int patch, const int *ijk,
|
||||
Array<const KnotVector*> const& kv,
|
||||
bool & deleteRule) const
|
||||
{
|
||||
deleteRule = false;
|
||||
|
||||
// First check whether a rule has been assigned to element index elem.
|
||||
auto search = elementToRule.find(elem);
|
||||
if (search != elementToRule.end())
|
||||
{
|
||||
return *elementRule[search->second];
|
||||
}
|
||||
|
||||
MFEM_VERIFY(patchRules1D.NumRows(),
|
||||
"Undefined rule in NURBSMeshRules::GetElementRule");
|
||||
|
||||
// Use a tensor product of rules on the patch.
|
||||
MFEM_VERIFY(kv.Size() == dim, "");
|
||||
|
||||
int np = 1;
|
||||
std::vector<std::vector<double>> el(dim);
|
||||
|
||||
std::vector<int> npd;
|
||||
npd.assign(3, 0);
|
||||
|
||||
for (int d=0; d<dim; ++d)
|
||||
{
|
||||
const int order = kv[d]->GetOrder();
|
||||
|
||||
const double kv0 = (*kv[d])[order + ijk[d]];
|
||||
const double kv1 = (*kv[d])[order + ijk[d] + 1];
|
||||
|
||||
const bool rightEnd = (order + ijk[d] + 1) == (kv[d]->Size() - 1);
|
||||
|
||||
for (int i=0; i<patchRules1D(patch,d)->Size(); ++i)
|
||||
{
|
||||
const IntegrationPoint& ip = (*patchRules1D(patch,d))[i];
|
||||
if (kv0 <= ip.x && (ip.x < kv1 || rightEnd))
|
||||
{
|
||||
const double x = (ip.x - kv0) / (kv1 - kv0);
|
||||
el[d].push_back(x);
|
||||
el[d].push_back(ip.weight);
|
||||
}
|
||||
}
|
||||
|
||||
npd[d] = el[d].size() / 2;
|
||||
np *= npd[d];
|
||||
}
|
||||
|
||||
IntegrationRule *irp = new IntegrationRule(np);
|
||||
deleteRule = true;
|
||||
|
||||
// Set (*irp)[i + j*npd[0] + k*npd[0]*npd[1]] =
|
||||
// (el[0][2*i], el[1][2*j], el[2][2*k])
|
||||
|
||||
MFEM_VERIFY(npd[0] > 0 && npd[1] > 0, "Assuming 2D or 3D");
|
||||
|
||||
for (int i = 0; i < npd[0]; ++i)
|
||||
{
|
||||
for (int j = 0; j < npd[1]; ++j)
|
||||
{
|
||||
for (int k = 0; k < std::max(npd[2], 1); ++k)
|
||||
{
|
||||
const int id = i + j*npd[0] + k*npd[0]*npd[1];
|
||||
(*irp)[id].x = el[0][2*i];
|
||||
(*irp)[id].y = el[1][2*j];
|
||||
|
||||
(*irp)[id].weight = el[0][(2*i)+1];
|
||||
(*irp)[id].weight *= el[1][(2*j)+1];
|
||||
|
||||
if (npd[2] > 0)
|
||||
{
|
||||
(*irp)[id].z = el[2][2*k];
|
||||
(*irp)[id].weight *= el[2][(2*k)+1];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return *irp;
|
||||
}
|
||||
|
||||
void NURBSMeshRules::GetIntegrationPointFrom1D(const int patch, int i, int j,
|
||||
int k, IntegrationPoint & ip)
|
||||
{
|
||||
MFEM_VERIFY(patchRules1D.NumRows() > 0,
|
||||
"Assuming patchRules1D is set.");
|
||||
|
||||
ip.weight = (*patchRules1D(patch,0))[i].weight;
|
||||
ip.x = (*patchRules1D(patch,0))[i].x;
|
||||
|
||||
if (dim > 1)
|
||||
{
|
||||
ip.weight *= (*patchRules1D(patch,1))[j].weight;
|
||||
ip.y = (*patchRules1D(patch,1))[j].x; // 1D rule only has x
|
||||
}
|
||||
|
||||
if (dim > 2)
|
||||
{
|
||||
ip.weight *= (*patchRules1D(patch,2))[k].weight;
|
||||
ip.z = (*patchRules1D(patch,2))[k].x; // 1D rule only has x
|
||||
}
|
||||
}
|
||||
|
||||
void NURBSMeshRules::Finalize(Mesh const& mesh)
|
||||
{
|
||||
if ((int) pointToElem.size() == npatches) { return; } // Already set
|
||||
|
||||
MFEM_VERIFY(elementToRule.empty() && patchRules1D.NumRows() > 0
|
||||
&& npatches > 0, "Assuming patchRules1D is set.");
|
||||
MFEM_VERIFY(mesh.NURBSext, "");
|
||||
MFEM_VERIFY(mesh.Dimension() == dim, "");
|
||||
|
||||
pointToElem.resize(npatches);
|
||||
patchRules1D_KnotSpan.resize(npatches);
|
||||
|
||||
// First, find all the elements in each patch.
|
||||
std::vector<std::vector<int>> patchElements(npatches);
|
||||
|
||||
for (int e=0; e<mesh.GetNE(); ++e)
|
||||
{
|
||||
patchElements[mesh.NURBSext->GetElementPatch(e)].push_back(e);
|
||||
}
|
||||
|
||||
Array<int> ijk(3);
|
||||
Array<int> maxijk(3);
|
||||
Array<int> np(3); // Number of points in each dimension
|
||||
ijk = 0;
|
||||
|
||||
Array<const KnotVector*> pkv;
|
||||
|
||||
for (int p=0; p<npatches; ++p)
|
||||
{
|
||||
patchRules1D_KnotSpan[p].resize(dim);
|
||||
|
||||
// For each patch, get the range of ijk.
|
||||
mesh.NURBSext->GetPatchKnotVectors(p, pkv);
|
||||
MFEM_VERIFY((int) pkv.Size() == dim, "");
|
||||
|
||||
maxijk = 1;
|
||||
np = 1;
|
||||
for (int d=0; d<dim; ++d)
|
||||
{
|
||||
maxijk[d] = pkv[d]->GetNKS();
|
||||
np[d] = patchRules1D(p,d)->Size();
|
||||
}
|
||||
|
||||
// For each patch, set a map from ijk to element index.
|
||||
Array3D<int> ijk2elem(maxijk[0], maxijk[1], maxijk[2]);
|
||||
ijk2elem = -1;
|
||||
|
||||
for (auto elem : patchElements[p])
|
||||
{
|
||||
mesh.NURBSext->GetElementIJK(elem, ijk);
|
||||
MFEM_VERIFY(ijk2elem(ijk[0], ijk[1], ijk[2]) == -1, "");
|
||||
ijk2elem(ijk[0], ijk[1], ijk[2]) = elem;
|
||||
}
|
||||
|
||||
// For each point, find its ijk and from that its element index.
|
||||
// It is assumed here that the NURBSFiniteElement kv the same as the
|
||||
// patch kv.
|
||||
|
||||
for (int d=0; d<dim; ++d)
|
||||
{
|
||||
patchRules1D_KnotSpan[p][d].SetSize(patchRules1D(p,d)->Size());
|
||||
|
||||
for (int r=0; r<patchRules1D(p,d)->Size(); ++r)
|
||||
{
|
||||
const IntegrationPoint& ip = (*patchRules1D(p,d))[r];
|
||||
|
||||
const int order = pkv[d]->GetOrder();
|
||||
|
||||
// Find ijk_d such that ip.x is in the corresponding knot-span.
|
||||
int ijk_d = 0;
|
||||
bool found = false;
|
||||
while (!found)
|
||||
{
|
||||
const double kv0 = (*pkv[d])[order + ijk_d];
|
||||
const double kv1 = (*pkv[d])[order + ijk_d + 1];
|
||||
|
||||
const bool rightEnd = (order + ijk_d + 1) == (pkv[d]->Size() - 1);
|
||||
|
||||
if (kv0 <= ip.x && (ip.x < kv1 || rightEnd))
|
||||
{
|
||||
found = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
ijk_d++;
|
||||
}
|
||||
}
|
||||
|
||||
patchRules1D_KnotSpan[p][d][r] = ijk_d;
|
||||
}
|
||||
}
|
||||
|
||||
pointToElem[p].SetSize(np[0], np[1], np[2]);
|
||||
for (int i=0; i<np[0]; ++i)
|
||||
for (int j=0; j<np[1]; ++j)
|
||||
for (int k=0; k<np[2]; ++k)
|
||||
{
|
||||
const int elem = ijk2elem(patchRules1D_KnotSpan[p][0][i],
|
||||
patchRules1D_KnotSpan[p][1][j],
|
||||
patchRules1D_KnotSpan[p][2][k]);
|
||||
MFEM_VERIFY(elem >= 0, "");
|
||||
pointToElem[p](i,j,k) = elem;
|
||||
}
|
||||
} // Loop (p) over patches
|
||||
}
|
||||
|
||||
void NURBSMeshRules::SetPatchRules1D(const int patch,
|
||||
std::vector<const IntegrationRule*> & ir1D)
|
||||
{
|
||||
MFEM_VERIFY((int) ir1D.size() == dim, "Wrong dimension");
|
||||
|
||||
for (int i=0; i<dim; ++i)
|
||||
{
|
||||
patchRules1D(patch,i) = ir1D[i];
|
||||
}
|
||||
}
|
||||
|
||||
NURBSMeshRules::~NURBSMeshRules()
|
||||
{
|
||||
for (int i=0; i<patchRules1D.NumRows(); ++i)
|
||||
for (int j=0; j<patchRules1D.NumCols(); ++j)
|
||||
{
|
||||
delete patchRules1D(i, j);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+104
-3
@@ -15,9 +15,15 @@
|
||||
#include "../config/config.hpp"
|
||||
#include "../general/array.hpp"
|
||||
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
class KnotVector;
|
||||
class Mesh;
|
||||
|
||||
/* Classes for IntegrationPoint, IntegrationRule, and container class
|
||||
IntegrationRules. Declares the global variable IntRules */
|
||||
|
||||
@@ -91,7 +97,7 @@ class IntegrationRule : public Array<IntegrationPoint>
|
||||
{
|
||||
private:
|
||||
friend class IntegrationRules;
|
||||
int Order;
|
||||
int Order = 0;
|
||||
/** @brief The quadrature weights gathered as a contiguous array. Created
|
||||
by request with the method GetWeights(). */
|
||||
mutable Array<double> weights;
|
||||
@@ -212,11 +218,11 @@ private:
|
||||
|
||||
public:
|
||||
IntegrationRule() :
|
||||
Array<IntegrationPoint>(), Order(0) { }
|
||||
Array<IntegrationPoint>() { }
|
||||
|
||||
/// Construct an integration rule with given number of points
|
||||
explicit IntegrationRule(int NP) :
|
||||
Array<IntegrationPoint>(NP), Order(0)
|
||||
Array<IntegrationPoint>(NP)
|
||||
{
|
||||
for (int i = 0; i < this->Size(); i++)
|
||||
{
|
||||
@@ -257,10 +263,105 @@ public:
|
||||
a call like this: `IntPoint(i).weight`. */
|
||||
const Array<double> &GetWeights() const;
|
||||
|
||||
/// @brief Return an integration rule for KnotVector @a kv, defined by
|
||||
/// applying this rule on each knot interval.
|
||||
IntegrationRule* ApplyToKnotIntervals(KnotVector const& kv) const;
|
||||
|
||||
/// Destroys an IntegrationRule object
|
||||
~IntegrationRule() { }
|
||||
};
|
||||
|
||||
/// Class for defining different integration rules on each NURBS patch.
|
||||
class NURBSMeshRules
|
||||
{
|
||||
public:
|
||||
/// Construct a rule for each patch, using SetPatchRules1D.
|
||||
NURBSMeshRules(const int numPatches, const int dim_) :
|
||||
patchRules1D(numPatches, dim_),
|
||||
npatches(numPatches), dim(dim_) { }
|
||||
|
||||
/// Returns a rule for the element.
|
||||
IntegrationRule &GetElementRule(const int elem, const int patch,
|
||||
const int *ijk,
|
||||
Array<const KnotVector*> const& kv,
|
||||
bool & deleteRule) const;
|
||||
|
||||
/// Add a rule to be used for individual elements. Returns the rule index.
|
||||
std::size_t AddElementRule(IntegrationRule *ir_element)
|
||||
{
|
||||
elementRule.push_back(ir_element);
|
||||
return elementRule.size() - 1;
|
||||
}
|
||||
|
||||
/// @brief Set the integration rule for the element of the given index. This
|
||||
/// rule is used instead of the rule for the patch containing the element.
|
||||
void SetElementRule(const std::size_t element,
|
||||
const std::size_t elementRuleIndex)
|
||||
{
|
||||
elementToRule[element] = elementRuleIndex;
|
||||
}
|
||||
|
||||
/// @brief Set 1D integration rules to be used as a tensor product rule on
|
||||
/// the patch with index @a patch. This class takes ownership of these rules.
|
||||
void SetPatchRules1D(const int patch,
|
||||
std::vector<const IntegrationRule*> & ir1D);
|
||||
|
||||
/// @brief For tensor product rules defined on each patch by
|
||||
/// SetPatchRules1D(), return a pointer to the 1D rule in the specified
|
||||
/// @a dimension.
|
||||
const IntegrationRule* GetPatchRule1D(const int patch,
|
||||
const int dimension) const
|
||||
{
|
||||
return patchRules1D(patch, dimension);
|
||||
}
|
||||
|
||||
/// @brief For tensor product rules defined on each patch by
|
||||
/// SetPatchRules1D(), return the integration point with index (i,j,k).
|
||||
void GetIntegrationPointFrom1D(const int patch, int i, int j, int k,
|
||||
IntegrationPoint & ip);
|
||||
|
||||
/// @brief Finalize() must be called before this class can be used for
|
||||
/// assembly. In particular, it defines data used by GetPointElement().
|
||||
void Finalize(Mesh const& mesh);
|
||||
|
||||
/// @brief For tensor product rules defined on each patch by
|
||||
/// SetPatchRules1D(), returns the index of the element containing
|
||||
/// integration point (i,j,k) for patch index @a patch. Finalize() must be
|
||||
/// called first.
|
||||
int GetPointElement(int patch, int i, int j, int k) const
|
||||
{
|
||||
return pointToElem[patch](i,j,k);
|
||||
}
|
||||
|
||||
int GetDim() const { return dim; }
|
||||
|
||||
/// @brief For tensor product rules defined on each patch by
|
||||
/// SetPatchRules1D(), returns an array of knot span indices for each
|
||||
/// integration point in the specified @a dimension.
|
||||
const Array<int>& GetPatchRule1D_KnotSpan(const int patch,
|
||||
const int dimension) const
|
||||
{
|
||||
return patchRules1D_KnotSpan[patch][dimension];
|
||||
}
|
||||
|
||||
~NURBSMeshRules();
|
||||
|
||||
private:
|
||||
/// Tensor-product rules defined on all patches independently.
|
||||
Array2D<const IntegrationRule*> patchRules1D;
|
||||
|
||||
/// Integration rules defined on elements.
|
||||
std::vector<IntegrationRule*> elementRule;
|
||||
|
||||
std::map<std::size_t, std::size_t> elementToRule;
|
||||
|
||||
std::vector<Array3D<int>> pointToElem;
|
||||
std::vector<std::vector<Array<int>>> patchRules1D_KnotSpan;
|
||||
|
||||
const int npatches;
|
||||
const int dim;
|
||||
};
|
||||
|
||||
/// A Class that defines 1-D numerical quadrature rules on [0,1].
|
||||
class QuadratureFunctions1D
|
||||
{
|
||||
|
||||
+404
@@ -0,0 +1,404 @@
|
||||
// Copyright (c) 2010-2023, Lawrence Livermore National Security, LLC. Produced
|
||||
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
|
||||
// LICENSE and NOTICE for details. LLNL-CODE-806117.
|
||||
//
|
||||
// This file is part of the MFEM library. For more information and source code
|
||||
// availability visit https://mfem.org.
|
||||
//
|
||||
// MFEM is free software; you can redistribute it and/or modify it under the
|
||||
// terms of the BSD-3 license. We welcome feedback and contributions, see file
|
||||
// CONTRIBUTING.md for details.
|
||||
|
||||
#include "kdtree.hpp"
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
template<>
|
||||
void KDTreeNodalProjection<2>::Project(const Vector& coords,const Vector& src,
|
||||
int ordering, double lerr)
|
||||
{
|
||||
const int dim=dest->FESpace()->GetMesh()->SpaceDimension();
|
||||
const int vd=dest->VectorDim(); // dimension of the vector field
|
||||
const int np=src.Size()/vd; // number of points
|
||||
int ind;
|
||||
double dist;
|
||||
bool pt_inside_bbox;
|
||||
KDTree2D::PointND pnd;
|
||||
for (int i=0; i<np; i++)
|
||||
{
|
||||
pnd.xx[0]=coords(i*dim+0);
|
||||
pnd.xx[1]=coords(i*dim+1);
|
||||
|
||||
pt_inside_bbox=true;
|
||||
for (int j=0; j<dim; j++)
|
||||
{
|
||||
if (pnd.xx[j]>(maxbb[j]+lerr)) {pt_inside_bbox=false; break;}
|
||||
if (pnd.xx[j]<(minbb[j]-lerr)) {pt_inside_bbox=false; break;}
|
||||
}
|
||||
|
||||
if (pt_inside_bbox)
|
||||
{
|
||||
kdt->FindClosestPoint(pnd,ind,dist);
|
||||
if (dist<lerr)
|
||||
{
|
||||
if (dest->FESpace()->GetOrdering()==Ordering::byNODES)
|
||||
{
|
||||
if (ordering==Ordering::byNODES)
|
||||
{
|
||||
for (int di=0; di<vd; di++)
|
||||
{
|
||||
(*dest)[di*np+ind]=src[di*np+i];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int di=0; di<vd; di++)
|
||||
{
|
||||
(*dest)[di*np+ind]=src[di+i*vd];
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ordering==Ordering::byNODES)
|
||||
{
|
||||
for (int di=0; di<vd; di++)
|
||||
{
|
||||
(*dest)[di+ind*vd]=src[di*np+i];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int di=0; di<vd; di++)
|
||||
{
|
||||
(*dest)[di+ind*vd]=src[di+i*vd];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<>
|
||||
void KDTreeNodalProjection<3>::Project(const Vector& coords,const Vector& src,
|
||||
int ordering, double lerr)
|
||||
{
|
||||
const int dim=dest->FESpace()->GetMesh()->SpaceDimension();
|
||||
const int vd=dest->VectorDim(); // dimension of the vector field
|
||||
const int np=src.Size()/vd; // number of points
|
||||
int ind;
|
||||
double dist;
|
||||
bool pt_inside_bbox;
|
||||
KDTree3D::PointND pnd;
|
||||
for (int i=0; i<np; i++)
|
||||
{
|
||||
pnd.xx[0]=coords(i*dim+0);
|
||||
pnd.xx[1]=coords(i*dim+1);
|
||||
pnd.xx[2]=coords(i*dim+2);
|
||||
|
||||
pt_inside_bbox=true;
|
||||
for (int j=0; j<dim; j++)
|
||||
{
|
||||
if (pnd.xx[j]>(maxbb[j]+lerr)) {pt_inside_bbox=false; break;}
|
||||
if (pnd.xx[j]<(minbb[j]-lerr)) {pt_inside_bbox=false; break;}
|
||||
}
|
||||
|
||||
if (pt_inside_bbox)
|
||||
{
|
||||
kdt->FindClosestPoint(pnd,ind,dist);
|
||||
if (dist<lerr)
|
||||
{
|
||||
if (dest->FESpace()->GetOrdering()==Ordering::byNODES)
|
||||
{
|
||||
if (ordering==Ordering::byNODES)
|
||||
{
|
||||
for (int di=0; di<vd; di++)
|
||||
{
|
||||
(*dest)[di*np+ind]=src[di*np+i];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int di=0; di<vd; di++)
|
||||
{
|
||||
(*dest)[di*np+ind]=src[di+i*vd];
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ordering==Ordering::byNODES)
|
||||
{
|
||||
for (int di=0; di<vd; di++)
|
||||
{
|
||||
(*dest)[di+ind*vd]=src[di*np+i];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int di=0; di<vd; di++)
|
||||
{
|
||||
(*dest)[di+ind*vd]=src[di+i*vd];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<>
|
||||
void KDTreeNodalProjection<2>::Project(const GridFunction& gf, double lerr)
|
||||
{
|
||||
int ordering = gf.FESpace()->GetOrdering();
|
||||
Vector coo;
|
||||
int np=gf.FESpace()->GetVSize()/gf.FESpace()->GetVDim();
|
||||
coo.SetSize(np*2);
|
||||
int vd=dest->VectorDim();
|
||||
int ind;
|
||||
double dist;
|
||||
|
||||
Vector maxbb_src(2);
|
||||
Vector minbb_src(2);
|
||||
|
||||
// extract the nodal coordinates from gf
|
||||
{
|
||||
ElementTransformation *trans;
|
||||
const IntegrationRule* ir=nullptr;
|
||||
Array<int> vdofs;
|
||||
DenseMatrix elco;
|
||||
int isca=1;
|
||||
if (gf.FESpace()->GetOrdering()==Ordering::byVDIM)
|
||||
{
|
||||
isca=gf.FESpace()->GetVDim();
|
||||
}
|
||||
|
||||
// initialize bbmax and bbmin
|
||||
const FiniteElement* el=gf.FESpace()->GetFE(0);
|
||||
trans = gf.FESpace()->GetElementTransformation(0);
|
||||
ir=&(el->GetNodes());
|
||||
gf.FESpace()->GetElementVDofs(0,vdofs);
|
||||
elco.SetSize(2,ir->GetNPoints());
|
||||
trans->Transform(*ir,elco);
|
||||
for (int d=0; d<2; d++)
|
||||
{
|
||||
maxbb_src(d)=elco(d,0);
|
||||
minbb_src(d)=elco(d,0);
|
||||
}
|
||||
|
||||
for (int i=0; i<gf.FESpace()->GetNE(); i++)
|
||||
{
|
||||
el=gf.FESpace()->GetFE(i);
|
||||
//get the element transformation
|
||||
trans = gf.FESpace()->GetElementTransformation(i);
|
||||
ir=&(el->GetNodes());
|
||||
gf.FESpace()->GetElementVDofs(i,vdofs);
|
||||
elco.SetSize(2,ir->GetNPoints());
|
||||
trans->Transform(*ir,elco);
|
||||
for (int p=0; p<ir->GetNPoints(); p++)
|
||||
{
|
||||
for (int d=0; d<2; d++)
|
||||
{
|
||||
coo[vdofs[p]*2/isca+d]=elco(d,p);
|
||||
|
||||
if (maxbb_src(d)<elco(d,p)) {maxbb_src(d)=elco(d,p);}
|
||||
if (minbb_src(d)>elco(d,p)) {minbb_src(d)=elco(d,p);}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
maxbb_src+=lerr;
|
||||
minbb_src-=lerr;
|
||||
|
||||
// check for intersection
|
||||
bool flag;
|
||||
{
|
||||
flag=true;
|
||||
for (int i=0; i<2; i++)
|
||||
{
|
||||
if (minbb_src(i)>maxbb(i)) {flag=false;}
|
||||
if (maxbb_src(i)<minbb(i)) {flag=false;}
|
||||
}
|
||||
if (flag==false) {return;}
|
||||
}
|
||||
|
||||
{
|
||||
KDTree2D::PointND pnd;
|
||||
for (int i=0; i<np; i++)
|
||||
{
|
||||
pnd.xx[0]=coo(i*2+0);
|
||||
pnd.xx[1]=coo(i*2+1);
|
||||
|
||||
kdt->FindClosestPoint(pnd,ind,dist);
|
||||
if (dist<lerr)
|
||||
{
|
||||
if (dest->FESpace()->GetOrdering()==Ordering::byNODES)
|
||||
{
|
||||
if (ordering==Ordering::byNODES)
|
||||
{
|
||||
for (int di=0; di<vd; di++)
|
||||
{
|
||||
(*dest)[di*np+ind]=gf[di*np+i];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int di=0; di<vd; di++)
|
||||
{
|
||||
(*dest)[di*np+ind]=gf[di+i*vd];
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ordering==Ordering::byNODES)
|
||||
{
|
||||
for (int di=0; di<vd; di++)
|
||||
{
|
||||
(*dest)[di+ind*vd]=gf[di*np+i];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int di=0; di<vd; di++)
|
||||
{
|
||||
(*dest)[di+ind*vd]=gf[di+i*vd];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<>
|
||||
void KDTreeNodalProjection<3>::Project(const GridFunction& gf, double lerr)
|
||||
{
|
||||
int ordering = gf.FESpace()->GetOrdering();
|
||||
int dim=dest->FESpace()->GetMesh()->SpaceDimension();
|
||||
Vector coo;
|
||||
int np=gf.FESpace()->GetVSize()/gf.FESpace()->GetVDim();
|
||||
coo.SetSize(np*dim);
|
||||
int vd=dest->VectorDim();
|
||||
int ind;
|
||||
double dist;
|
||||
|
||||
Vector maxbb_src(dim);
|
||||
Vector minbb_src(dim);
|
||||
|
||||
// extract the nodal coordinates from gf
|
||||
{
|
||||
ElementTransformation *trans;
|
||||
const IntegrationRule* ir=nullptr;
|
||||
Array<int> vdofs;
|
||||
DenseMatrix elco;
|
||||
int isca=1;
|
||||
if (gf.FESpace()->GetOrdering()==Ordering::byVDIM)
|
||||
{
|
||||
isca=gf.FESpace()->GetVDim();
|
||||
}
|
||||
|
||||
// initialize bbmax and bbmin
|
||||
const FiniteElement* el=gf.FESpace()->GetFE(0);
|
||||
trans = gf.FESpace()->GetElementTransformation(0);
|
||||
ir=&(el->GetNodes());
|
||||
gf.FESpace()->GetElementVDofs(0,vdofs);
|
||||
elco.SetSize(dim,ir->GetNPoints());
|
||||
trans->Transform(*ir,elco);
|
||||
for (int d=0; d<dim; d++)
|
||||
{
|
||||
maxbb_src(d)=elco(d,0);
|
||||
minbb_src(d)=elco(d,0);
|
||||
}
|
||||
|
||||
for (int i=0; i<gf.FESpace()->GetNE(); i++)
|
||||
{
|
||||
el=gf.FESpace()->GetFE(i);
|
||||
// get the element transformation
|
||||
trans = gf.FESpace()->GetElementTransformation(i);
|
||||
ir=&(el->GetNodes());
|
||||
gf.FESpace()->GetElementVDofs(i,vdofs);
|
||||
elco.SetSize(dim,ir->GetNPoints());
|
||||
trans->Transform(*ir,elco);
|
||||
for (int p=0; p<ir->GetNPoints(); p++)
|
||||
{
|
||||
for (int d=0; d<dim; d++)
|
||||
{
|
||||
coo[vdofs[p]*dim/isca+d]=elco(d,p);
|
||||
|
||||
if (maxbb_src(d)<elco(d,p)) {maxbb_src(d)=elco(d,p);}
|
||||
if (minbb_src(d)>elco(d,p)) {minbb_src(d)=elco(d,p);}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
maxbb_src+=lerr;
|
||||
minbb_src-=lerr;
|
||||
|
||||
// check for intersection
|
||||
bool flag;
|
||||
{
|
||||
flag=true;
|
||||
for (int i=0; i<dim; i++)
|
||||
{
|
||||
if (minbb_src(i)>maxbb(i)) {flag=false;}
|
||||
if (maxbb_src(i)<minbb(i)) {flag=false;}
|
||||
}
|
||||
if (flag==false) {return;}
|
||||
}
|
||||
|
||||
{
|
||||
KDTree3D::PointND pnd;
|
||||
for (int i=0; i<np; i++)
|
||||
{
|
||||
pnd.xx[0]=coo(i*dim+0);
|
||||
pnd.xx[1]=coo(i*dim+1);
|
||||
pnd.xx[2]=coo(i*dim+2);
|
||||
|
||||
kdt->FindClosestPoint(pnd,ind,dist);
|
||||
if (dist<lerr)
|
||||
{
|
||||
if (dest->FESpace()->GetOrdering()==Ordering::byNODES)
|
||||
{
|
||||
if (ordering==Ordering::byNODES)
|
||||
{
|
||||
for (int di=0; di<vd; di++)
|
||||
{
|
||||
(*dest)[di*np+ind]=gf[di*np+i];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int di=0; di<vd; di++)
|
||||
{
|
||||
(*dest)[di*np+ind]=gf[di+i*vd];
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ordering==Ordering::byNODES)
|
||||
{
|
||||
for (int di=0; di<vd; di++)
|
||||
{
|
||||
(*dest)[di+ind*vd]=gf[di*np+i];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int di=0; di<vd; di++)
|
||||
{
|
||||
(*dest)[di+ind*vd]=gf[di+i*vd];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace mfem
|
||||
+177
@@ -0,0 +1,177 @@
|
||||
// Copyright (c) 2010-2023, Lawrence Livermore National Security, LLC. Produced
|
||||
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
|
||||
// LICENSE and NOTICE for details. LLNL-CODE-806117.
|
||||
//
|
||||
// This file is part of the MFEM library. For more information and source code
|
||||
// availability visit https://mfem.org.
|
||||
//
|
||||
// MFEM is free software; you can redistribute it and/or modify it under the
|
||||
// terms of the BSD-3 license. We welcome feedback and contributions, see file
|
||||
// CONTRIBUTING.md for details.
|
||||
|
||||
#ifndef MFEM_KDTREE_PROJECTION
|
||||
#define MFEM_KDTREE_PROJECTION
|
||||
|
||||
#include "../general/kdtree.hpp"
|
||||
#include "gridfunc.hpp"
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
/// Base class for KDTreeNodalProjection.
|
||||
class BaseKDTreeNodalProjection
|
||||
{
|
||||
public:
|
||||
virtual ~BaseKDTreeNodalProjection()
|
||||
{}
|
||||
|
||||
/// The projection method can be called as many time as necessary with
|
||||
/// different sets of coordinates and corresponding values. For vector
|
||||
/// grid function, users have to specify the data ordering and for all
|
||||
/// cases the user can modify the error tolerance err to smaller or
|
||||
/// bigger value. A node in the target grid function is matching
|
||||
/// a point with coordinates specified in the vector coords if the
|
||||
/// distance between them is smaller than lerr.
|
||||
virtual
|
||||
void Project(const Vector& coords,const Vector& src,
|
||||
int ordering, double lerr) = 0;
|
||||
|
||||
/// The project method can be called as many times as necessary with
|
||||
/// different grid functions gf. A node in the target grid function is
|
||||
/// matching a node from the source grid function if the distance
|
||||
/// between them is smaller than lerr.
|
||||
virtual
|
||||
void Project(const GridFunction& gf, double lerr) = 0;
|
||||
};
|
||||
|
||||
/// The class provides methods for projecting function values evaluated on a
|
||||
/// set of points to a grid function. The values are directly copied to the
|
||||
/// nodal values of the target grid function if any of the points is matching
|
||||
/// a node of the grid function. For example, if a parallel grid function is
|
||||
/// saved in parallel, every saved chunk can be read on every other process
|
||||
/// and mapped to a local grid function that does not have the same structure
|
||||
/// as the original one. The functionality is based on a kd-tree search in a
|
||||
/// cloud of points.
|
||||
template<int kdim=3>
|
||||
class KDTreeNodalProjection : public BaseKDTreeNodalProjection
|
||||
{
|
||||
private:
|
||||
/// Pointer to the KDTree
|
||||
std::unique_ptr<KDTree<int,double,kdim>> kdt;
|
||||
|
||||
/// Pointer to the target grid function
|
||||
GridFunction* dest;
|
||||
|
||||
/// Upper corner of the bounding box
|
||||
Vector maxbb;
|
||||
|
||||
/// Lower corner of the bounding box
|
||||
Vector minbb;
|
||||
|
||||
public:
|
||||
/// The constructor takes as input an L2 or H1 grid function (it can be
|
||||
/// a vector grid function). The Project method copies a set of values
|
||||
/// to the grid function.
|
||||
KDTreeNodalProjection(GridFunction& dest_)
|
||||
{
|
||||
dest=&dest_;
|
||||
FiniteElementSpace* space=dest->FESpace();
|
||||
|
||||
MFEM_VERIFY(
|
||||
dynamic_cast<const H1_FECollection*>(space->FEColl()) != nullptr ||
|
||||
dynamic_cast<const L2_FECollection*>(space->FEColl()) != nullptr,
|
||||
"Error!");
|
||||
|
||||
Mesh* mesh=space->GetMesh();
|
||||
|
||||
const int dim=mesh->SpaceDimension();
|
||||
MFEM_VERIFY(kdim==dim, "GridFunction dimension does not match!");
|
||||
|
||||
kdt=std::unique_ptr<KDTree<int,double,kdim>>(
|
||||
new KDTree<int,double,kdim>());
|
||||
|
||||
std::vector<bool> indt;
|
||||
indt.resize(space->GetVSize()/space->GetVDim(), true);
|
||||
|
||||
minbb.SetSize(dim);
|
||||
maxbb.SetSize(dim);
|
||||
|
||||
//set the loocal coordinates
|
||||
{
|
||||
ElementTransformation *trans;
|
||||
const IntegrationRule* ir=nullptr;
|
||||
Array<int> vdofs;
|
||||
DenseMatrix elco;
|
||||
int isca=1;
|
||||
if (space->GetOrdering()==Ordering::byVDIM)
|
||||
{
|
||||
isca=space->GetVDim();
|
||||
}
|
||||
|
||||
// intialize the bounding box
|
||||
const FiniteElement* el=space->GetFE(0);
|
||||
trans = space->GetElementTransformation(0);
|
||||
ir=&(el->GetNodes());
|
||||
space->GetElementVDofs(0,vdofs);
|
||||
elco.SetSize(dim,ir->GetNPoints());
|
||||
trans->Transform(*ir,elco);
|
||||
for (int d=0; d<dim; d++)
|
||||
{
|
||||
minbb[d]=elco(d,0);
|
||||
maxbb[d]=elco(d,0);
|
||||
}
|
||||
|
||||
for (int i=0; i<space->GetNE(); i++)
|
||||
{
|
||||
el=space->GetFE(i);
|
||||
// get the element transformation
|
||||
trans = space->GetElementTransformation(i);
|
||||
ir=&(el->GetNodes());
|
||||
space->GetElementVDofs(i,vdofs);
|
||||
elco.SetSize(dim,ir->GetNPoints());
|
||||
trans->Transform(*ir,elco);
|
||||
|
||||
for (int p=0; p<ir->GetNPoints(); p++)
|
||||
{
|
||||
int bind=vdofs[p]/isca;
|
||||
if (indt[bind]==true)
|
||||
{
|
||||
kdt->AddPoint(elco.GetColumn(p),bind);
|
||||
indt[bind]=false;
|
||||
|
||||
for (int d=0; d<kdim; d++)
|
||||
{
|
||||
if (minbb[d]>elco(d,p)) {minbb[d]=elco(d,p);}
|
||||
if (maxbb[d]<elco(d,p)) {maxbb[d]=elco(d,p);}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// build the KDTree
|
||||
kdt->Sort();
|
||||
}
|
||||
|
||||
/// The projection method can be called as many time as necessary with
|
||||
/// different sets of coordinates and corresponding values. For vector
|
||||
/// grid function, users have to specify the data ordering and for all
|
||||
/// cases the user can modify the error tolerance err to smaller or
|
||||
/// bigger value. A node in the target grid function is matching
|
||||
/// a point with coordinates specified in the vector coords if the
|
||||
/// distance between them is smaller than lerr.
|
||||
virtual
|
||||
void Project(const Vector& coords,const Vector& src,
|
||||
int ordering=Ordering::byNODES, double lerr=1e-8);
|
||||
|
||||
/// The project method can be called as many times as necessary with
|
||||
/// different grid functions gf. A node in the target grid function is
|
||||
/// matching a node from the source grid function if the distance
|
||||
/// between them is smaller than lerr.
|
||||
virtual
|
||||
void Project(const GridFunction& gf, double lerr=1e-8);
|
||||
};
|
||||
|
||||
} // namespace mfem
|
||||
|
||||
#endif // MFEM_KDTREE_PROJECTION
|
||||
+5
-1
@@ -27,15 +27,19 @@ LinearForm::LinearForm(FiniteElementSpace *f, LinearForm *lf)
|
||||
// Linear forms are stored on the device
|
||||
UseDevice(true);
|
||||
|
||||
// Copy the pointers to the integrators
|
||||
// Copy the pointers to the integrators and the corresponding marker arrays
|
||||
domain_integs = lf->domain_integs;
|
||||
domain_integs_marker = lf->domain_integs_marker;
|
||||
|
||||
domain_delta_integs = lf->domain_delta_integs;
|
||||
|
||||
boundary_integs = lf->boundary_integs;
|
||||
boundary_integs_marker = lf->boundary_integs_marker;
|
||||
|
||||
boundary_face_integs = lf->boundary_face_integs;
|
||||
boundary_face_integs_marker = lf->boundary_face_integs_marker;
|
||||
|
||||
interior_face_integs = lf->interior_face_integs;
|
||||
}
|
||||
|
||||
void LinearForm::AddDomainIntegrator(LinearFormIntegrator *lfi)
|
||||
|
||||
+2
-2
@@ -455,7 +455,7 @@ void VectorFEDomainLFIntegrator::AssembleRHSElementVect(
|
||||
{
|
||||
int dof = el.GetDof();
|
||||
int spaceDim = Tr.GetSpaceDim();
|
||||
int vdim = std::max(spaceDim, el.GetVDim());
|
||||
int vdim = std::max(spaceDim, el.GetRangeDim());
|
||||
|
||||
vshape.SetSize(dof,vdim);
|
||||
vec.SetSize(vdim);
|
||||
@@ -656,7 +656,7 @@ void VectorFEBoundaryTangentLFIntegrator::AssembleRHSElementVect(
|
||||
{
|
||||
int dof = el.GetDof();
|
||||
int dim = el.GetDim();
|
||||
int vdim = el.GetVDim();
|
||||
int vdim = el.GetRangeDim();
|
||||
DenseMatrix vshape(dof, vdim);
|
||||
Vector f_loc(3);
|
||||
Vector f_hat(2);
|
||||
|
||||
+2
-1
@@ -291,7 +291,8 @@ void BatchedLOR_AMS::FormCoordinateVectors(const Vector &X_vert)
|
||||
const auto ltdof_ldof = HypreRead(R->GetMemoryJ());
|
||||
|
||||
// Go from E-vector format directly to T-vector format
|
||||
MFEM_HYPRE_FORALL(i, ntdofs,
|
||||
//MFEM_HYPRE_FORALL(i, ntdofs,
|
||||
mfem::forall_switch(HypreUsingGPU(), ntdofs, [=] MFEM_HOST_DEVICE (int i)
|
||||
{
|
||||
const int j = d_offsets[ltdof_ldof[i]];
|
||||
for (int c = 0; c < sdim; ++c)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user