Compare commits
929
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
473361d332 | ||
|
|
3c370bb600 | ||
|
|
70a3355e90 | ||
|
|
454a215175 | ||
|
|
32ce005ca0 | ||
|
|
cd4e583f9f | ||
|
|
ee94776558 | ||
|
|
c34de48041 | ||
|
|
0694668c24 | ||
|
|
3492b20c70 | ||
|
|
5fec899806 | ||
|
|
fc010f0423 | ||
|
|
a9427e2663 | ||
|
|
f9be12c539 | ||
|
|
af478afd00 | ||
|
|
72deb3b12c | ||
|
|
519e86f134 | ||
|
|
fcdc9c43d5 | ||
|
|
f2578fd479 | ||
|
|
4fdf2cdda1 | ||
|
|
0af0b9b420 | ||
|
|
563cd25971 | ||
|
|
875c62ca1f | ||
|
|
731b0b7049 | ||
|
|
3c77ad25e9 | ||
|
|
4501988a3b | ||
|
|
cd82063118 | ||
|
|
cac3f72e9e | ||
|
|
d93a030431 | ||
|
|
8cfd5e0a07 | ||
|
|
63110738d4 | ||
|
|
e13d1a1d53 | ||
|
|
09e73b5cee | ||
|
|
464b441409 | ||
|
|
8ae9b217f9 | ||
|
|
3f0a5ad501 | ||
|
|
dfb697b9ae | ||
|
|
cf01c6cc8b | ||
|
|
e4dc9a3941 | ||
|
|
6a104e94e1 | ||
|
|
bf1b25d82e | ||
|
|
b7a0b2cf9a | ||
|
|
9a8f0ad0ef | ||
|
|
ee2c069531 | ||
|
|
27a60a4ca3 | ||
|
|
b1d5104fed | ||
|
|
26eecf7575 | ||
|
|
9c26ef5401 | ||
|
|
bce6e2ca76 | ||
|
|
26f8f0e955 | ||
|
|
324ab0684e | ||
|
|
c5efd6a06a | ||
|
|
0c167ab5e7 | ||
|
|
dfc2dfeb52 | ||
|
|
7173477670 | ||
|
|
30249a4857 | ||
|
|
8a9bdf863a | ||
|
|
b72368c698 | ||
|
|
e6224e00aa | ||
|
|
7b82f7b8e0 | ||
|
|
582ffe8b66 | ||
|
|
aa5b2d4b95 | ||
|
|
23616a21f0 | ||
|
|
df9cc72e58 | ||
|
|
15740fcbd3 | ||
|
|
862c539276 | ||
|
|
7ff759a7ee | ||
|
|
d220a2975c | ||
|
|
cdde0046ef | ||
|
|
9f36ae566c | ||
|
|
4465fcbd46 | ||
|
|
807b13b236 | ||
|
|
70f4468f0b | ||
|
|
5db2e7b347 | ||
|
|
c1df332094 | ||
|
|
75b115cf93 | ||
|
|
59579f2cdb | ||
|
|
c0d2821d3e | ||
|
|
082e25ffe8 | ||
|
|
7d343e56a5 | ||
|
|
1eb3d185d5 | ||
|
|
a2fd029daa | ||
|
|
b48b990ac8 | ||
|
|
80c69e9856 | ||
|
|
dbdee73113 | ||
|
|
7a8a1976a2 | ||
|
|
6911ed0a8a | ||
|
|
986e2c04d2 | ||
|
|
9db5388362 | ||
|
|
dbf987fb73 | ||
|
|
c4a6d855eb | ||
|
|
80c2ee6fed | ||
|
|
68aa9af7c2 | ||
|
|
19fa34eabe | ||
|
|
359ba5983b | ||
|
|
947f2f215a | ||
|
|
52ced84b8c | ||
|
|
6430c45f52 | ||
|
|
6d3c7dfc88 | ||
|
|
0e2d49799c | ||
|
|
562b980e7d | ||
|
|
388b7b61b2 | ||
|
|
2adb4576d3 | ||
|
|
9f2490cd95 | ||
|
|
4126d32772 | ||
|
|
080780f047 | ||
|
|
ca2ee9ab05 | ||
|
|
0d87692863 | ||
|
|
450628554c | ||
|
|
7bc231eb85 | ||
|
|
6de39a2637 | ||
|
|
c4a19c8df0 | ||
|
|
280e98b510 | ||
|
|
9794243c8b | ||
|
|
333726ce51 | ||
|
|
d14d286842 | ||
|
|
ea3bed0a91 | ||
|
|
877937b8ae | ||
|
|
1e2b33e21c | ||
|
|
f65311b8a0 | ||
|
|
1254e8782e | ||
|
|
b50d546dac | ||
|
|
fd01ef188f | ||
|
|
f2a29326c0 | ||
|
|
1f4a40d9a0 | ||
|
|
db003bdf86 | ||
|
|
8f8e5712ad | ||
|
|
e671fa5737 | ||
|
|
40d1550fd6 | ||
|
|
ae33f831eb | ||
|
|
2139999a06 | ||
|
|
df7f786c7f | ||
|
|
79859679fd | ||
|
|
193f8a6801 | ||
|
|
110720dd04 | ||
|
|
3fd335c77b | ||
|
|
c0a133fe2c | ||
|
|
1ffb08db61 | ||
|
|
3c0a73479a | ||
|
|
90e1f08bc7 | ||
|
|
eec906c43d | ||
|
|
ea8d19ccf1 | ||
|
|
def68ccace | ||
|
|
3962449ece | ||
|
|
37d004206a | ||
|
|
e1d9b7cfff | ||
|
|
d1c44a7369 | ||
|
|
2c39547bdd | ||
|
|
db66a4423f | ||
|
|
8425377bd1 | ||
|
|
ea76f8d477 | ||
|
|
992c5dfc4c | ||
|
|
e6826dda5a | ||
|
|
c4c14822ba | ||
|
|
8f21f70baf | ||
|
|
f0027c2ccd | ||
|
|
142b1ec60a | ||
|
|
77f1682547 | ||
|
|
0c4c006ef8 | ||
|
|
dd2c68fc72 | ||
|
|
6dc6a38ed8 | ||
|
|
95b3915b52 | ||
|
|
bebd0ff8ff | ||
|
|
c851e2ec1e | ||
|
|
3463dcec04 | ||
|
|
6ccb7dea8a | ||
|
|
bf82f4ce39 | ||
|
|
4fdb3621f5 | ||
|
|
6e575c4e1f | ||
|
|
79d1f22ebb | ||
|
|
3207b8b012 | ||
|
|
cd377f5201 | ||
|
|
4f35f73c69 | ||
|
|
97ac0c3a3e | ||
|
|
8af7877b68 | ||
|
|
6cdc6cd026 | ||
|
|
13dc17123d | ||
|
|
95327ad4c3 | ||
|
|
a186b57213 | ||
|
|
0c4d26917b | ||
|
|
fdc9d7f80e | ||
|
|
ec94332c2a | ||
|
|
21dc66a447 | ||
|
|
c4c67b141a | ||
|
|
c6329b292e | ||
|
|
5d4bf08ccf | ||
|
|
0196b7df4a | ||
|
|
5e75bd0837 | ||
|
|
5f889293c2 | ||
|
|
afc5aa96dc | ||
|
|
9b1d29a762 | ||
|
|
b4120d81e4 | ||
|
|
9125bf8291 | ||
|
|
9d285278f9 | ||
|
|
b435fbeae6 | ||
|
|
b593405fda | ||
|
|
5c356a3e2b | ||
|
|
2d57401575 | ||
|
|
9e764dc809 | ||
|
|
b7bddf91bc | ||
|
|
bdbd234c56 | ||
|
|
513fbe0a28 | ||
|
|
d4a5f69b52 | ||
|
|
770aa5bf52 | ||
|
|
cc2739ef78 | ||
|
|
9351fb1550 | ||
|
|
d6d94117f8 | ||
|
|
a7ad5add62 | ||
|
|
a26ef22a49 | ||
|
|
7f788e83b9 | ||
|
|
1d8952297f | ||
|
|
f5af06ecee | ||
|
|
c7b9cc6354 | ||
|
|
68bf2adbe4 | ||
|
|
1f89bfa040 | ||
|
|
d47695436a | ||
|
|
7284a6c4f9 | ||
|
|
46d05c44a0 | ||
|
|
a107678f13 | ||
|
|
3dc4463c56 | ||
|
|
0b79aa138c | ||
|
|
c76acb2a7b | ||
|
|
7b7f77379e | ||
|
|
2b0c1cd199 | ||
|
|
f0cb31088c | ||
|
|
b4793a0bd7 | ||
|
|
41cccee855 | ||
|
|
8fb8b77b3d | ||
|
|
f407ca7756 | ||
|
|
ab00472c5d | ||
|
|
c4a3d31289 | ||
|
|
8f6626aede | ||
|
|
e3beb0370e | ||
|
|
fab955250a | ||
|
|
c3dcf554df | ||
|
|
8f52ddcf6f | ||
|
|
696ce1e8ed | ||
|
|
87c6d3a370 | ||
|
|
20e77be88a | ||
|
|
8f2b4bb539 | ||
|
|
d70b99c4f3 | ||
|
|
97a568af13 | ||
|
|
550df43d5e | ||
|
|
ad993a8b27 | ||
|
|
6c032cb7cf | ||
|
|
8104dd3f04 | ||
|
|
bdd8696d22 | ||
|
|
032fb568be | ||
|
|
cd2715680f | ||
|
|
62997e9dc7 | ||
|
|
86405d95a2 | ||
|
|
a36151569f | ||
|
|
e0cb9ebe3b | ||
|
|
91cdbeee7d | ||
|
|
6f303de40d | ||
|
|
e0c5a8952a | ||
|
|
eb3bd655df | ||
|
|
6a862ca233 | ||
|
|
0466ee74f2 | ||
|
|
50b8873f20 | ||
|
|
0e7368c055 | ||
|
|
0f5898f3e0 | ||
|
|
cdc510145c | ||
|
|
3d6ee379e3 | ||
|
|
2361e45683 | ||
|
|
cd7dfe2188 | ||
|
|
25d3ce9704 | ||
|
|
acea08404c | ||
|
|
e718f2ec58 | ||
|
|
e0c1018c9c | ||
|
|
7f263221dd | ||
|
|
1bf00d3761 | ||
|
|
f6247a83dd | ||
|
|
f419dc71f8 | ||
|
|
36c3688968 | ||
|
|
90e79c29fe | ||
|
|
f8c659df1e | ||
|
|
b2a0f48001 | ||
|
|
fb200e4b98 | ||
|
|
da852fd0e4 | ||
|
|
c2657d20a8 | ||
|
|
47e9b29c0f | ||
|
|
cbcae09fe8 | ||
|
|
b75c6e96e6 | ||
|
|
a54c5d2105 | ||
|
|
cd5d098c95 | ||
|
|
30506b52d9 | ||
|
|
3f78374d2a | ||
|
|
bd7281bdfa | ||
|
|
1299d05d21 | ||
|
|
39944d8dfb | ||
|
|
6df8ae80cb | ||
|
|
0730fa304a | ||
|
|
c182459e6a | ||
|
|
6dfbe25c07 | ||
|
|
f82e8c04f9 | ||
|
|
70235124a6 | ||
|
|
a8e251c28e | ||
|
|
9df402b565 | ||
|
|
5ddbaed1f4 | ||
|
|
02edb95a31 | ||
|
|
a328693444 | ||
|
|
3889095a00 | ||
|
|
826b089e8f | ||
|
|
1bee2fc017 | ||
|
|
c0a66cee74 | ||
|
|
9b94a6c225 | ||
|
|
f0c4c45e02 | ||
|
|
8f6912dc2a | ||
|
|
ea6053ef9d | ||
|
|
7fc1fb501a | ||
|
|
f6afbb8cee | ||
|
|
20d5e01189 | ||
|
|
a979fc6aa6 | ||
|
|
8606afbc40 | ||
|
|
28f754844f | ||
|
|
2d6cb3f0e5 | ||
|
|
d06f52461e | ||
|
|
3853cb6860 | ||
|
|
f5d0db2a33 | ||
|
|
a102daf621 | ||
|
|
ba1805ced8 | ||
|
|
90863b64e4 | ||
|
|
05d71b6093 | ||
|
|
597cba8d37 | ||
|
|
4c1c8c89ad | ||
|
|
075a160187 | ||
|
|
6d8a96a8fb | ||
|
|
8d9579057f | ||
|
|
76d65f5866 | ||
|
|
61afd67059 | ||
|
|
3f0b53ac8e | ||
|
|
0fe75ffdc3 | ||
|
|
d896e940f7 | ||
|
|
dc0cfb4785 | ||
|
|
15874961af | ||
|
|
c325b92286 | ||
|
|
c731dee195 | ||
|
|
720fb72372 | ||
|
|
bbde976378 | ||
|
|
a6e81b4289 | ||
|
|
09165c10e6 | ||
|
|
95ca14247c | ||
|
|
1efc5e78e5 | ||
|
|
fb42b564f2 | ||
|
|
a553c2dba8 | ||
|
|
9f0216b037 | ||
|
|
6675385cbe | ||
|
|
8a810f7cf5 | ||
|
|
58ad1c79cd | ||
|
|
b6f755925c | ||
|
|
447cd0f500 | ||
|
|
2d68b877f2 | ||
|
|
64c78ff17e | ||
|
|
cce301f92b | ||
|
|
01444aa93c | ||
|
|
46ccaee493 | ||
|
|
25bd2f9596 | ||
|
|
516f709061 | ||
|
|
fa89692e57 | ||
|
|
1b6d878189 | ||
|
|
b32f8c8959 | ||
|
|
e45f5f8595 | ||
|
|
03e64ea9b1 | ||
|
|
4cc9b5c6f6 | ||
|
|
f73f41fc82 | ||
|
|
9b1b56a155 | ||
|
|
f95b18b457 | ||
|
|
af6d0d7479 | ||
|
|
d6cb23ab2f | ||
|
|
2a65d49db3 | ||
|
|
fd6e93c7ad | ||
|
|
712bee9cce | ||
|
|
34043e730b | ||
|
|
850c1813c3 | ||
|
|
84c08a69ee | ||
|
|
5496699870 | ||
|
|
2d3ec4ca67 | ||
|
|
6915a8c6f3 | ||
|
|
0950325080 | ||
|
|
03a6f1b190 | ||
|
|
7aa327174a | ||
|
|
769f672ac1 | ||
|
|
dca2a24af2 | ||
|
|
019194d42d | ||
|
|
07c0f31e37 | ||
|
|
8c861b4602 | ||
|
|
4caf208e36 | ||
|
|
b050e307db | ||
|
|
b70589bcac | ||
|
|
17bbaf500c | ||
|
|
267082d6f2 | ||
|
|
dd6c207534 | ||
|
|
71af00ab6d | ||
|
|
2d5f00635f | ||
|
|
03da0c870c | ||
|
|
933e1714c8 | ||
|
|
3f447cb11c | ||
|
|
a1179d6489 | ||
|
|
e629502dca | ||
|
|
ce434a9c82 | ||
|
|
48dd78b154 | ||
|
|
3e321e6c9e | ||
|
|
dc08fc65ce | ||
|
|
3276cb955f | ||
|
|
60ab10bf58 | ||
|
|
bcdbda1597 | ||
|
|
0239b86304 | ||
|
|
5932fcd331 | ||
|
|
aca8d51f95 | ||
|
|
5cf82dc903 | ||
|
|
631f8e4868 | ||
|
|
cb98ed992b | ||
|
|
368724d456 | ||
|
|
95eb39f60f | ||
|
|
a99efcdb63 | ||
|
|
7b0f4ad3fd | ||
|
|
0f4bdae918 | ||
|
|
cf93d97e99 | ||
|
|
2d84f0cb6e | ||
|
|
4b74777aae | ||
|
|
f7bfa3deb0 | ||
|
|
b5a7cf6470 | ||
|
|
28cfca4dba | ||
|
|
f19ec00b0a | ||
|
|
89346b597c | ||
|
|
66ff264731 | ||
|
|
1339b6b99a | ||
|
|
9480e5c5bb | ||
|
|
2cfb86aade | ||
|
|
1ac7837dc0 | ||
|
|
e6fc7893be | ||
|
|
058fdaae3f | ||
|
|
9a92e4875b | ||
|
|
0735280f9d | ||
|
|
e7c041247f | ||
|
|
78df8dffb2 | ||
|
|
d0f5cb73e7 | ||
|
|
af00755d68 | ||
|
|
cc21011998 | ||
|
|
09aa9374a9 | ||
|
|
78e8cdd7e8 | ||
|
|
056152aaa6 | ||
|
|
86e75206b1 | ||
|
|
04a3fd9bb2 | ||
|
|
db55be84ad | ||
|
|
2b962e18a6 | ||
|
|
6e5c7fd286 | ||
|
|
6303361f5a | ||
|
|
02424a41a9 | ||
|
|
091c6272fc | ||
|
|
e31e0b7c25 | ||
|
|
8bf7aaac1f | ||
|
|
f83036c4bc | ||
|
|
72f0b668c8 | ||
|
|
aefeb46c48 | ||
|
|
6e111c3ada | ||
|
|
101af72047 | ||
|
|
30a3d7c0d4 | ||
|
|
ea449e1c41 | ||
|
|
c9115e74fb | ||
|
|
35040b0336 | ||
|
|
01990d4605 | ||
|
|
4a3cd44695 | ||
|
|
3b059c3995 | ||
|
|
89dc5ce5c0 | ||
|
|
eb205caaa2 | ||
|
|
f50601f1aa | ||
|
|
529d6e3bc2 | ||
|
|
b289def58a | ||
|
|
ef29b1dd30 | ||
|
|
33b3ef6045 | ||
|
|
657f6ef5fe | ||
|
|
96cfef783c | ||
|
|
603f43e775 | ||
|
|
932508ad1b | ||
|
|
0e30ee1e15 | ||
|
|
dd236b8796 | ||
|
|
4ce11b4a12 | ||
|
|
cb580207c8 | ||
|
|
cd59e68993 | ||
|
|
9a47f4391d | ||
|
|
eb61aa4244 | ||
|
|
3659acd79d | ||
|
|
ccc006febf | ||
|
|
9d3047b3a7 | ||
|
|
f2ac9b5653 | ||
|
|
a2e33109eb | ||
|
|
b277a0cb2d | ||
|
|
f42334cb4d | ||
|
|
8f9e4b27fc | ||
|
|
076ad6907f | ||
|
|
f17b1c4e4f | ||
|
|
7cfd3f5c7e | ||
|
|
9faa6f8968 | ||
|
|
b5156dcdec | ||
|
|
cf6c98654a | ||
|
|
63ea83c455 | ||
|
|
38ee46c40f | ||
|
|
c271283490 | ||
|
|
808f5c94db | ||
|
|
e818d6645b | ||
|
|
73313bb44d | ||
|
|
287631bee4 | ||
|
|
4da6e52698 | ||
|
|
cc12d37693 | ||
|
|
35fe98417c | ||
|
|
936f1fc848 | ||
|
|
2cadeaad4c | ||
|
|
f7fa092013 | ||
|
|
9103db88b6 | ||
|
|
0303f12887 | ||
|
|
6650a1dffe | ||
|
|
9a22d4533f | ||
|
|
412715c2e4 | ||
|
|
9803cbb671 | ||
|
|
6805b8c7f6 | ||
|
|
7aeba0ff83 | ||
|
|
dbd55a8fb4 | ||
|
|
277199c3a5 | ||
|
|
e7e00e6e39 | ||
|
|
e78c1b8b4c | ||
|
|
dcec51b98a | ||
|
|
2e9f545a4e | ||
|
|
e49854f3ba | ||
|
|
0bb71aa1fa | ||
|
|
07dc0f6cfa | ||
|
|
847183e668 | ||
|
|
8a1a264eaa | ||
|
|
606a597303 | ||
|
|
e194835abd | ||
|
|
208f9b81b3 | ||
|
|
e50ebb573e | ||
|
|
c315298a86 | ||
|
|
12bafa69e8 | ||
|
|
1729961a89 | ||
|
|
6dcc19abab | ||
|
|
a5fccc7514 | ||
|
|
cfe25c432c | ||
|
|
b8fe4cbf97 | ||
|
|
ea0abf46fe | ||
|
|
556b43f900 | ||
|
|
aa567465ac | ||
|
|
986cee600f | ||
|
|
7634a4b663 | ||
|
|
1368cfb8cb | ||
|
|
53c561cbf0 | ||
|
|
3c2e847e0a | ||
|
|
838398e4e7 | ||
|
|
6daba6f9fa | ||
|
|
ac26026ff1 | ||
|
|
f65f60dbb5 | ||
|
|
9dab032bd0 | ||
|
|
d439781751 | ||
|
|
16c9123f98 | ||
|
|
cc86e59167 | ||
|
|
52eaf0deb7 | ||
|
|
e73ea1fb77 | ||
|
|
ea6c104475 | ||
|
|
a26eaed48a | ||
|
|
e7762d126e | ||
|
|
c61d0e07d3 | ||
|
|
31171c22ce | ||
|
|
ef47e36e41 | ||
|
|
3e7280df12 | ||
|
|
10915f67e1 | ||
|
|
e4b27670c8 | ||
|
|
969ba74440 | ||
|
|
68ae30ad6f | ||
|
|
720051d641 | ||
|
|
5c25fa49a7 | ||
|
|
d9ef117ee9 | ||
|
|
b7a8cf6290 | ||
|
|
bed1823d72 | ||
|
|
c51895ee22 | ||
|
|
a19255274d | ||
|
|
9e5323be86 | ||
|
|
93a3648712 | ||
|
|
b9932b5cb2 | ||
|
|
1e73159e11 | ||
|
|
00691298d1 | ||
|
|
07ff46c1d6 | ||
|
|
01eeccee7f | ||
|
|
39b6112e69 | ||
|
|
c70d2b7309 | ||
|
|
c98e8bfe07 | ||
|
|
ef9137bd1f | ||
|
|
e49a62ab1b | ||
|
|
8e0c42a132 | ||
|
|
d755037904 | ||
|
|
b577d2322e | ||
|
|
6f99204d37 | ||
|
|
c6e93f5474 | ||
|
|
21b6ade630 | ||
|
|
2e8685d80a | ||
|
|
6d8c32db80 | ||
|
|
4adb51df50 | ||
|
|
6cec49e220 | ||
|
|
9006171327 | ||
|
|
9e10cd87b1 | ||
|
|
3f7c551d66 | ||
|
|
a7a5ce5cb1 | ||
|
|
4218c11b41 | ||
|
|
e3b732761f | ||
|
|
44f8eb9990 | ||
|
|
44f58a169c | ||
|
|
3c4a860f3a | ||
|
|
18a256d17b | ||
|
|
a4d8700473 | ||
|
|
47b73713a6 | ||
|
|
43f4d9d6e3 | ||
|
|
081bbdd1c2 | ||
|
|
80b04009af | ||
|
|
7983d25a14 | ||
|
|
bf1a63c920 | ||
|
|
b64bb19cf8 | ||
|
|
321bcceb1c | ||
|
|
e64300f84b | ||
|
|
c3656a5573 | ||
|
|
f84d5d1bfa | ||
|
|
6ce9d7b3be | ||
|
|
02dd999886 | ||
|
|
5132b9191c | ||
|
|
3854184620 | ||
|
|
e16cf9a89d | ||
|
|
dd3e76db6c | ||
|
|
8578bf4918 | ||
|
|
97e5cf0dc4 | ||
|
|
40083984c1 | ||
|
|
96cc518acf | ||
|
|
acb1bb4dc2 | ||
|
|
8f391e9854 | ||
|
|
dfb73f248f | ||
|
|
c55f3c13af | ||
|
|
4a09b7a1fc | ||
|
|
1ea8e59f69 | ||
|
|
8d40910fd8 | ||
|
|
b2e61e7e1c | ||
|
|
7c80866b49 | ||
|
|
7ec6704a51 | ||
|
|
62dcb4cf1a | ||
|
|
0f0d70dad1 | ||
|
|
3c1606903c | ||
|
|
b6aa248fc9 | ||
|
|
80274347ae | ||
|
|
622985d8da | ||
|
|
cdfe8102ae | ||
|
|
754235e932 | ||
|
|
0cc04c8bd9 | ||
|
|
746fbca164 | ||
|
|
5f82901f73 | ||
|
|
e7f71da564 | ||
|
|
41a262563b | ||
|
|
b081aa7eea | ||
|
|
3c7a63f742 | ||
|
|
ffe14214ae | ||
|
|
c515b75b53 | ||
|
|
7d9048f9f0 | ||
|
|
3b2fe7ce7f | ||
|
|
5b82bf0328 | ||
|
|
ecab08e1b6 | ||
|
|
5602c66e1a | ||
|
|
900085cb9d | ||
|
|
0376760aa1 | ||
|
|
2ab9ae818e | ||
|
|
6857e4b277 | ||
|
|
639a0347fb | ||
|
|
a02f7165d8 | ||
|
|
4fb48b4e41 | ||
|
|
751dbd0ed9 | ||
|
|
c2c6a94d42 | ||
|
|
088ec0f461 | ||
|
|
7e1be9da75 | ||
|
|
be29d4a3d4 | ||
|
|
be34c5a6bd | ||
|
|
1035382fad | ||
|
|
8bd3569f6d | ||
|
|
e8908ad646 | ||
|
|
6c7673df1c | ||
|
|
1f7f394f4e | ||
|
|
bfc6b0708d | ||
|
|
3d5c6d58e8 | ||
|
|
6efbd4cc27 | ||
|
|
369b9365ad | ||
|
|
b35ff2270a | ||
|
|
7a54a543b0 | ||
|
|
15420f7049 | ||
|
|
dd20722733 | ||
|
|
5577edf446 | ||
|
|
230a345ef3 | ||
|
|
dd64dcc10b | ||
|
|
f89e89e9fa | ||
|
|
90f33b1a86 | ||
|
|
2e27af385c | ||
|
|
f1025ecdeb | ||
|
|
09b5dcab6d | ||
|
|
22e1f000b9 | ||
|
|
8884c31461 | ||
|
|
c354e4cd27 | ||
|
|
01d92c7133 | ||
|
|
04b868a47b | ||
|
|
136ae2d98f | ||
|
|
12896cd9ed | ||
|
|
15ecbb5e6e | ||
|
|
b5ed99e1cd | ||
|
|
8b99a6a847 | ||
|
|
4868222660 | ||
|
|
f4ef788e40 | ||
|
|
8f333155cc | ||
|
|
449a57d9ad | ||
|
|
41b65d6333 | ||
|
|
17e48c4d46 | ||
|
|
7ac5b61955 | ||
|
|
c98f117689 | ||
|
|
89f1dce705 | ||
|
|
7f17c1f049 | ||
|
|
7e6edcddec | ||
|
|
d89b01e24c | ||
|
|
33f1150c34 | ||
|
|
c6a05d371b | ||
|
|
f97a29f6e8 | ||
|
|
85ae72fada | ||
|
|
27a5bd71ee | ||
|
|
643db22bef | ||
|
|
97fb6be029 | ||
|
|
9587ef212d | ||
|
|
337a0298bf | ||
|
|
5499eb8939 | ||
|
|
35462b8645 | ||
|
|
5ccdd4b53d | ||
|
|
7930b9b3ca | ||
|
|
2534d2207d | ||
|
|
260b817b3c | ||
|
|
613d5dd826 | ||
|
|
323ee572b6 | ||
|
|
56ff5ac5bb | ||
|
|
e1a06bd6c8 | ||
|
|
9acae54669 | ||
|
|
7d92e22a45 | ||
|
|
7c0bc9c338 | ||
|
|
b62aa1491f | ||
|
|
7bff34ba6c | ||
|
|
c0d8ba243d | ||
|
|
c946067b9b | ||
|
|
db803eb74a | ||
|
|
4f0f353720 | ||
|
|
a3156023d0 | ||
|
|
c35e5ad7fe | ||
|
|
059f0acee6 | ||
|
|
a1ea837c1d | ||
|
|
186ab1409e | ||
|
|
1c6d968ed7 | ||
|
|
e18d795334 | ||
|
|
377c5d16f5 | ||
|
|
674379e6c9 | ||
|
|
d0f0e2c392 | ||
|
|
bf6d19e152 | ||
|
|
7794c291be | ||
|
|
7ca49cb200 | ||
|
|
e48d41c9dc | ||
|
|
0ead1d9c77 | ||
|
|
243b234033 | ||
|
|
e2168f9348 | ||
|
|
65516eca23 | ||
|
|
79d9314560 | ||
|
|
d91d39bc00 | ||
|
|
56c5f17e01 | ||
|
|
5afe2a09a3 | ||
|
|
64f8ab42c1 | ||
|
|
5fb9fc8ec5 | ||
|
|
5a5dcd44df | ||
|
|
d4ff68d2bd | ||
|
|
ac3417555c | ||
|
|
e8bd89a672 | ||
|
|
fc3c897fa6 | ||
|
|
58bc2b070e | ||
|
|
991284d3b6 | ||
|
|
587d437f32 | ||
|
|
c50a55f05c | ||
|
|
c0ae0f0a4b | ||
|
|
615448bbc3 | ||
|
|
68cfee09e0 | ||
|
|
a0656da6ef | ||
|
|
1395d44724 | ||
|
|
a42a394111 | ||
|
|
0fa8b85391 | ||
|
|
d4db7ef8cd | ||
|
|
3d9af90191 | ||
|
|
1ab9f62208 | ||
|
|
179e6ec141 | ||
|
|
2434d4ac71 | ||
|
|
1c146ff523 | ||
|
|
a9e5c58897 | ||
|
|
35d9fa1f6c | ||
|
|
fb9117e9fb | ||
|
|
00d3b1ca49 | ||
|
|
4af5e6a758 | ||
|
|
d4d149a5ff | ||
|
|
0f13bc76f5 | ||
|
|
b377eac8cd | ||
|
|
b0dd0109bb | ||
|
|
ac9f49a137 | ||
|
|
178b9b8170 | ||
|
|
886579fb48 | ||
|
|
7367c5a42e | ||
|
|
b47ec8d14d | ||
|
|
a31f758d55 | ||
|
|
175a4302c3 | ||
|
|
e31f662f8b | ||
|
|
903ddbf97d | ||
|
|
9c44c45a7e | ||
|
|
4da44357d0 | ||
|
|
bf55c1cc46 | ||
|
|
96d188ac12 | ||
|
|
c0a1e91237 | ||
|
|
788c1a15da | ||
|
|
bb72f2c0c6 | ||
|
|
edeb7ab0f9 | ||
|
|
55f954e6c3 | ||
|
|
587ef0ef47 | ||
|
|
23a18a46b3 | ||
|
|
8e00d7c191 | ||
|
|
b242fde7ec | ||
|
|
a09c9ef266 | ||
|
|
a2e5ffc9db | ||
|
|
6bebe4caf9 | ||
|
|
97e554fb13 | ||
|
|
3a30286567 | ||
|
|
bdc919f084 | ||
|
|
8cc6821cad | ||
|
|
f2851bbb61 | ||
|
|
49e19c2414 | ||
|
|
73cbdc75e1 | ||
|
|
81b91619ae | ||
|
|
070ab14951 | ||
|
|
bbbb50ff5b | ||
|
|
204c9c60d1 | ||
|
|
e7f8898546 | ||
|
|
9c64303464 | ||
|
|
28bf478b68 | ||
|
|
9b0edad337 | ||
|
|
d6cbd76c46 | ||
|
|
2c8a7548cb | ||
|
|
33ce5f1765 | ||
|
|
84ce97a114 | ||
|
|
c508781257 | ||
|
|
df994a4890 | ||
|
|
db63f71f40 | ||
|
|
c4b05bd83e | ||
|
|
6155e148a7 | ||
|
|
b8e0bd0692 | ||
|
|
675ecb994f | ||
|
|
e3d5c35614 | ||
|
|
953a063626 | ||
|
|
535e39bbb1 | ||
|
|
cfa41e0d9c | ||
|
|
0ee13cc107 | ||
|
|
4635107f2b | ||
|
|
e5c1b4412c | ||
|
|
a3cd66cf84 | ||
|
|
7abddc527a | ||
|
|
6afec618be | ||
|
|
fff5a50f21 | ||
|
|
181247ffcf | ||
|
|
cf5e341f49 | ||
|
|
15b20e62ac | ||
|
|
b8ad8fb003 | ||
|
|
7fe11de76a | ||
|
|
d12164148a | ||
|
|
f480dd23a4 | ||
|
|
e8b229bb54 | ||
|
|
f7db5cbc24 | ||
|
|
1a1df8de48 | ||
|
|
3f7fddb188 | ||
|
|
fd57eb3076 | ||
|
|
4e6ac3490e | ||
|
|
177e16ca9d | ||
|
|
29e3f9b7a6 | ||
|
|
458377891d | ||
|
|
821689c160 | ||
|
|
263b0cfa43 | ||
|
|
c30af860e7 | ||
|
|
419b7940d6 | ||
|
|
3dc33c6d8b | ||
|
|
22e54ea294 | ||
|
|
8b6b584117 | ||
|
|
43c65547c3 | ||
|
|
d3682b9dc2 | ||
|
|
944c983ae0 | ||
|
|
d393f6b614 | ||
|
|
02cc172bf0 | ||
|
|
fa3dc44076 | ||
|
|
8e60dd658d | ||
|
|
762ea3ebf6 | ||
|
|
4019c4fe17 | ||
|
|
b4c071b695 | ||
|
|
8969b905c1 | ||
|
|
71b570fb94 | ||
|
|
01a51c2214 | ||
|
|
c93f2d0b5a | ||
|
|
10d1c45969 | ||
|
|
e74f34cdd2 | ||
|
|
73752c7e7d | ||
|
|
167f855ffd | ||
|
|
522428a230 | ||
|
|
90b82487b3 | ||
|
|
18dffe91e1 | ||
|
|
f6996eb124 | ||
|
|
21a17a47b3 | ||
|
|
e6a7ef9247 | ||
|
|
d102c5507e | ||
|
|
6c5638ab05 | ||
|
|
36c7c73f9f | ||
|
|
0358087cd6 | ||
|
|
eb843cd051 | ||
|
|
5168fd5842 | ||
|
|
cb91e5d154 | ||
|
|
72447de801 | ||
|
|
de048ae478 | ||
|
|
d1d31f51a9 | ||
|
|
5d2c999758 | ||
|
|
6b0527108e | ||
|
|
d0c23a0ddf | ||
|
|
09c80b88d9 | ||
|
|
72c6958d6a | ||
|
|
8226c07595 | ||
|
|
47aefeb768 | ||
|
|
d35a1f647d | ||
|
|
10f0ea2eef |
@@ -132,12 +132,14 @@ jobs:
|
||||
hypre-target: int32
|
||||
precision: fp64
|
||||
enzyme: true
|
||||
config-opts: MFEM_USE_ENZYME=YES ENZYME_DIR=$(brew --prefix enzyme)
|
||||
config-opts: MFEM_USE_ENZYME=YES ENZYME_DIR=$(brew --prefix enzyme) LDFLAGS=-L$LLVM_PREFIX/lib/c++
|
||||
|
||||
name: ${{ matrix.os }}-${{ matrix.build-system }}-${{ matrix.target }}-${{ matrix.mpi }}-${{ matrix.hypre-target }}-${{ matrix.precision }}${{ matrix.enzyme && '-enzyme' || '' }}
|
||||
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
continue-on-error: ${{ matrix.enzyme && true || false }}
|
||||
|
||||
steps:
|
||||
# Fix 'No space left on device' errors for Ubuntu builds.
|
||||
- name: Run Actions Cleaner
|
||||
@@ -168,10 +170,13 @@ jobs:
|
||||
env
|
||||
shell: bash
|
||||
|
||||
# For info on Xcode see:
|
||||
# - https://github.com/actions/runner-images/issues/12541
|
||||
# - https://github.com/actions/runner-images/blob/releases/macos-15-arm64/20250811/images/macos/macos-15-arm64-Readme.md#xcode
|
||||
- name: Xcode version setup (MacOS)
|
||||
if: matrix.os == 'macos-latest'
|
||||
run: |
|
||||
XCODE_PATH="/Applications/Xcode_15.3.app"
|
||||
XCODE_PATH="/Applications/Xcode_16.4.app"
|
||||
echo "> sudo xcode-select -s ${XCODE_PATH}"
|
||||
sudo xcode-select -s ${XCODE_PATH}
|
||||
echo "> g++ -v"
|
||||
@@ -289,10 +294,12 @@ jobs:
|
||||
run: |
|
||||
export HOMEBREW_NO_INSTALL_CLEANUP=1
|
||||
brew update
|
||||
brew install llvm@19 enzyme
|
||||
echo "LLVM_PREFIX=$(brew --prefix llvm@19)" >> $GITHUB_ENV
|
||||
echo "OMPI_CC=$(brew --prefix llvm@19)/bin/clang" >> $GITHUB_ENV
|
||||
echo "OMPI_CXX=$(brew --prefix llvm@19)/bin/clang++" >> $GITHUB_ENV
|
||||
brew install enzyme
|
||||
ENZYME_LLVM=$(brew info enzyme | sed -n 's/^Required:.*\(llvm[^ ]*\).*/\1/p')
|
||||
LLVM_PREFIX=$(brew --prefix $ENZYME_LLVM)
|
||||
echo "LLVM_PREFIX=$LLVM_PREFIX" >> $GITHUB_ENV
|
||||
echo "OMPI_CC=$LLVM_PREFIX/bin/clang" >> $GITHUB_ENV
|
||||
echo "OMPI_CXX=$LLVM_PREFIX/bin/clang++" >> $GITHUB_ENV
|
||||
|
||||
# MFEM build and test
|
||||
- name: build
|
||||
|
||||
@@ -29,3 +29,47 @@ jobs:
|
||||
operations-per-run: 500
|
||||
exempt-issue-labels: "bug,WIP,ready-for-review,in-review,in-next"
|
||||
exempt-pr-labels: "bug,WIP,ready-for-review,in-review,in-next"
|
||||
|
||||
# Stale action for PRs with "in-review" label.
|
||||
stale-in-review-pr:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
issues: write
|
||||
pull-requests: write
|
||||
actions: write
|
||||
|
||||
steps:
|
||||
- uses: actions/stale@v9
|
||||
with:
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
stale-pr-message: ':warning: This PR has been automatically marked as stale because it has not had any activity in the last 150 days. *If no activity occurs in the next 30 days, it will be automatically closed.* Thank you for your contributions.'
|
||||
only-pr-labels: "in-review"
|
||||
days-before-pr-stale: 150
|
||||
days-before-pr-close: 30
|
||||
days-before-issue-stale: -1
|
||||
days-before-issue-close: -1
|
||||
stale-pr-label: 'stale'
|
||||
operations-per-run: 500
|
||||
|
||||
# Stale action for PRs with "WIP" label.
|
||||
stale-wip-pr:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
issues: write
|
||||
pull-requests: write
|
||||
actions: write
|
||||
|
||||
steps:
|
||||
- uses: actions/stale@v9
|
||||
with:
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
stale-pr-message: ':warning: This PR has been automatically marked as stale because it has not had any activity in the last 300 days. *If no activity occurs in the next 30 days, it will be automatically closed.* Thank you for your contributions.'
|
||||
only-pr-labels: "WIP"
|
||||
days-before-pr-stale: 300
|
||||
days-before-pr-close: 30
|
||||
days-before-issue-stale: -1
|
||||
days-before-issue-close: -1
|
||||
stale-pr-label: 'stale'
|
||||
operations-per-run: 500
|
||||
|
||||
+7
-4
@@ -208,10 +208,13 @@ miniapps/electromagnetics/volta
|
||||
miniapps/electromagnetics/tesla
|
||||
miniapps/electromagnetics/maxwell
|
||||
miniapps/electromagnetics/joule
|
||||
miniapps/electromagnetics/lorentz
|
||||
miniapps/electromagnetics/Volta-AMR*
|
||||
miniapps/electromagnetics/Tesla-AMR*
|
||||
miniapps/electromagnetics/Maxwell-Parallel*
|
||||
miniapps/electromagnetics/Joule_*
|
||||
miniapps/electromagnetics/Joule_[0-9]*
|
||||
miniapps/electromagnetics/Lorentz_[0-9]*
|
||||
miniapps/electromagnetics/Lorentz.dat
|
||||
|
||||
miniapps/gslib/field-diff
|
||||
miniapps/gslib/field-interp
|
||||
@@ -267,9 +270,9 @@ miniapps/meshing/bounding-box*
|
||||
miniapps/meshing/jacobian-determinant*
|
||||
|
||||
miniapps/mtop/parheat
|
||||
miniapps/mtop/ParHeat*
|
||||
miniapps/mtop/ParHeat/*
|
||||
miniapps/mtop/seqheat
|
||||
miniapps/mtop/SeqHeat*
|
||||
miniapps/mtop/SeqHeat/*
|
||||
|
||||
miniapps/autodiff/paradiff
|
||||
miniapps/autodiff/seqadiff
|
||||
@@ -277,7 +280,7 @@ miniapps/autodiff/seqtest
|
||||
miniapps/autodiff/par_example
|
||||
miniapps/autodiff/seq_example
|
||||
miniapps/autodiff/seq_test
|
||||
miniapps/autodiff/Exampl*
|
||||
miniapps/autodiff/Example/*
|
||||
|
||||
miniapps/navier/navier_mms
|
||||
miniapps/navier/navier_kovasznay
|
||||
|
||||
+529
-70
@@ -9,91 +9,550 @@
|
||||
# terms of the BSD-3 license. We welcome feedback and contributions, see file
|
||||
# CONTRIBUTING.md for details.
|
||||
|
||||
# DESCRIPTION:
|
||||
###############################################################################
|
||||
# General GitLab pipelines configurations for supercomputers and Linux clusters
|
||||
# at Lawrence Livermore National Laboratory (LLNL). This entire pipeline is
|
||||
# LLNL-specific!
|
||||
|
||||
include:
|
||||
- project: 'lc-templates/id_tokens'
|
||||
file: 'id_tokens.yml'
|
||||
|
||||
# The pipeline is divided into stages. Usually, jobs in a given stage wait for
|
||||
# the preceding stages to complete before to start. However, we sometimes use
|
||||
# the "needs" keyword and express the DAG of jobs for more efficiency.
|
||||
# - We use setup and setup_baseline phases to download content outside of mfem
|
||||
# directory.
|
||||
# - Allocate/Release is where ruby resource are allocated/released once for all.
|
||||
# - Build and Test is where we build and MFEM for multiple toolchains.
|
||||
# - Baseline_checks gathers baseline-type test suites execution
|
||||
# - Baseline_publish, only available on master, allows to update baseline
|
||||
# results
|
||||
stages:
|
||||
- sub-pipelines
|
||||
# at Lawrence Livermore National Laboratory (LLNL).
|
||||
# This entire pipeline is LLNL-specific
|
||||
#
|
||||
# Important note: This file is a template provided by llnl/radiuss-shared-ci.
|
||||
# Remains to set variable values, change the reference to the radiuss-shared-ci
|
||||
# repo, opt-in and out optional features. The project can then extend it with
|
||||
# additional stages.
|
||||
#
|
||||
# In addition, each project should copy over and complete:
|
||||
# - .gitlab/custom-jobs-and-variables.yml
|
||||
# - .gitlab/subscribed-pipelines.yml
|
||||
#
|
||||
# The jobs should be specified in a file local to the project,
|
||||
# - .gitlab/jobs/${CI_MACHINE}.yml
|
||||
# or generated (see LLNL/Umpire for an example).
|
||||
###############################################################################
|
||||
# MAP OF GITLAB CI
|
||||
#######################
|
||||
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
# File dependencies: direct, through jobs, through variables
|
||||
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
# .gitlab-ci.yml
|
||||
# ├── .build-and-test [job]
|
||||
# │ ├── .gitlab/custom-jobs-and-variables.yml
|
||||
# │ │ ├── .custom_job [job]
|
||||
# │ │ ├── .reproducer_vars [job]
|
||||
# │ │ ├── .report_job_success [job]
|
||||
# │ │ │ └── .gitlab/scripts/report_build_and_test [script]
|
||||
# │ │ │ ├── .gitlab/scripts/safe_create_rundir [script]
|
||||
# │ │ │ └── .gitlab/scripts/git_try_to_push [script]
|
||||
# │ │ ├── .report_job_failure [job]
|
||||
# │ │ │ └── .gitlab/scripts/report_build_and_test [script]
|
||||
# │ │ │ ├── .gitlab/scripts/safe_create_rundir [script]
|
||||
# │ │ │ └── .gitlab/scripts/git_try_to_push [script]
|
||||
# │ │ └── JOB_CMD [var]
|
||||
# │ │ └── tests/gitlab/build_and_test [script]
|
||||
# │ │ └── tests/gitlab/get_mfem_uberenv [script]
|
||||
# │ ├── <radiuss-shared-ci>/pipelines/matrix.yml [conditional]
|
||||
# │ │ ├── .on_matrix [job]
|
||||
# │ │ ├── .matrix_reproducer_init [job]
|
||||
# │ │ ├── .matrix_reproducer_vars [job]
|
||||
# │ │ ├── .matrix_reproducer_job [job]
|
||||
# │ │ ├── .matrix_job_command [job]
|
||||
# │ │ └── .job_on_matrix [job]
|
||||
# │ ├── <radiuss-shared-ci>/pipelines/dane.yml [conditional]
|
||||
# │ │ ├── .on_dane [job]
|
||||
# │ │ ├── .dane_reproducer_init [job]
|
||||
# │ │ ├── .dane_reproducer_vars [job]
|
||||
# │ │ ├── .dane_reproducer_job [job]
|
||||
# │ │ ├── .dane_job_command [job]
|
||||
# │ │ ├── .job_on_dane [job]
|
||||
# │ │ ├── allocate_resources [job]
|
||||
# │ │ └── release_resources [job]
|
||||
# │ ├── <radiuss-shared-ci>/pipelines/tioga.yml [conditional]
|
||||
# │ │ ├── .on_tioga [job]
|
||||
# │ │ ├── .tioga_reproducer_init [job]
|
||||
# │ │ ├── .tioga_reproducer_vars [job]
|
||||
# │ │ ├── .tioga_reproducer_job [job]
|
||||
# │ │ ├── .tioga_job_command [job]
|
||||
# │ │ ├── .job_on_tioga [job]
|
||||
# │ │ ├── allocate_resources [job]
|
||||
# │ │ └── release_resources [job]
|
||||
# │ ├── <artifact>/matrix-jobs.yml [conditional, from 'generate-job-lists']
|
||||
# │ │ ├── .gitlab/jobs/matrix.yml
|
||||
# │ │ │ ├── .matrix_reproducer_vars [job]
|
||||
# │ │ │ ├── setup [job]
|
||||
# │ │ │ │ └── ./tests/gitlab/build_and_test_setup [script]
|
||||
# │ │ │ ├── opt_mpi_cuda_gcc [job]
|
||||
# │ │ │ └── opt_mpi_cuda_hypre_cuda_gcc [job]
|
||||
# │ │ └── .gitlab/jobs/matrix-reports.yml [used conditionally]
|
||||
# │ │ ├── report_job_success
|
||||
# │ │ └── report_job_failure
|
||||
# │ ├── <artifact>/dane-jobs.yml [conditional, from 'generate-job-lists']
|
||||
# │ │ ├── .gitlab/jobs/dane.yml
|
||||
# │ │ │ ├── .dane_reproducer_vars [job]
|
||||
# │ │ │ ├── setup [job]
|
||||
# │ │ │ │ └── ./tests/gitlab/build_and_test_setup [script]
|
||||
# │ │ │ ├── debug_ser_gcc_10 [job]
|
||||
# │ │ │ ├── debug_par_gcc_10 [job]
|
||||
# │ │ │ ├── opt_ser_gcc_10 [job]
|
||||
# │ │ │ ├── opt_par_gcc_10 [job]
|
||||
# │ │ │ ├── opt_par_gcc_10_sundials [job]
|
||||
# │ │ │ ├── opt_par_gcc_10_petsc [job]
|
||||
# │ │ │ └── opt_par_gcc_10_pumi [job]
|
||||
# │ │ └── .gitlab/jobs/dane-reports.yml [used conditionally]
|
||||
# │ │ ├── report_job_success
|
||||
# │ │ └── report_job_failure
|
||||
# │ └── <artifact>/tioga-jobs.yml [conditional, from 'generate-job-lists']
|
||||
# │ ├── .gitlab/jobs/tioga.yml
|
||||
# │ │ ├── .tioga_reproducer_vars [job]
|
||||
# │ │ ├── setup [job]
|
||||
# │ │ │ └── ./tests/gitlab/build_and_test_setup [script]
|
||||
# │ │ └── cce_16_0_1 [job]
|
||||
# │ └── .gitlab/jobs/tioga-reports.yml [used conditionally]
|
||||
# │ ├── report_job_success
|
||||
# │ └── report_job_failure
|
||||
# └── .gitlab/subscribed-pipelines.yml
|
||||
# ├── .machine-check [job]
|
||||
# ├── generate-job-lists [job]
|
||||
# ├── dane-up-check [job]
|
||||
# ├── dane-build-and-test [job]
|
||||
# ├── dane-baseline [job]
|
||||
# │ └── .gitlab/dane-baseline.yml
|
||||
# │ ├── .on_dane [job]
|
||||
# │ ├── baselinecheck_mfem_intel_dane [job]
|
||||
# │ │ └── .gitlab/scripts/baseline [script]
|
||||
# │ ├── cleanup [job]
|
||||
# │ ├── report_baseline [job]
|
||||
# │ │ ├── .gitlab/scripts/safe_create_rundir [script]
|
||||
# │ │ └── .gitlab/scripts/git_try_to_push [script]
|
||||
# │ ├── baselinepublish_mfem_dane [job]
|
||||
# │ │ └── .gitlab/scripts/rebaseline [script]
|
||||
# │ ├── .gitlab/custom-jobs-and-variables.yml
|
||||
# │ │ └── <same as above: see .gitlab-ci.yml/.build-and-test>
|
||||
# │ └── .gitlab/configs/setup-baseline.yml
|
||||
# │ └── setup_baseline [job]
|
||||
# ├── tioga-up-check [job]
|
||||
# ├── tioga-build-and-test [job]
|
||||
# ├── matrix-up-check [job]
|
||||
# └── matrix-build-and-test [job]
|
||||
#
|
||||
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
# File tree hierarchy with file contents highlights
|
||||
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
# In addition to the files in the MFEM repo, the Gitlab CI uses files from the
|
||||
# radiuss/radiuss-shared-ci project, see below, after the <mfem-root> tree.
|
||||
#
|
||||
# <mfem root>
|
||||
# ├── .gitlab-ci.yml [this file]
|
||||
# │ ├── <jobs>
|
||||
# │ │ └── .build-and-test
|
||||
# │ ├── <included files>
|
||||
# │ │ ├── .gitlab/subscribed-pipelines.yml
|
||||
# │ │ ├── .gitlab/custom-jobs-and-variables.yml [by ".build-and-test"]
|
||||
# │ │ ├── <artifact> [by ".build-and-test"]
|
||||
# │ │ │ ├── artifact: '${CI_MACHINE}-jobs.yml'
|
||||
# │ │ │ └── job: 'generate-job-lists'
|
||||
# │ │ └── <external> [by ".build-and-test"]
|
||||
# │ │ ├── project: 'radiuss/radiuss-shared-ci'
|
||||
# │ │ ├── ref: 'v2025.09.1'
|
||||
# │ │ └── file: 'pipelines/${CI_MACHINE}.yml'
|
||||
# │ └── <defined variables>
|
||||
# │ ├── CUSTOM_CI_BUILDS_DIR
|
||||
# │ ├── USER_CI_TOP_DIR
|
||||
# │ ├── SHARED_REPOS_DIR
|
||||
# │ ├── AUTOTEST_ROOT
|
||||
# │ ├── MFEM_DATA_DIR
|
||||
# │ ├── AUTOTEST
|
||||
# │ ├── AUTOTEST_COMMIT
|
||||
# │ ├── REBASELINE
|
||||
# │ ├── GITHUB_PROJECT_NAME
|
||||
# │ └── GITHUB_PROJECT_ORG
|
||||
# ├── .gitlab
|
||||
# │ ├── configs
|
||||
# │ │ └── setup-baseline.yml
|
||||
# │ │ ├── <jobs>
|
||||
# │ │ │ └── setup_baseline
|
||||
# │ │ └── <used variables>
|
||||
# │ │ ├── MACHINE_NAME
|
||||
# │ │ ├── REBASELINE
|
||||
# │ │ ├── AUTOTEST
|
||||
# │ │ ├── AUTOTEST_COMMIT
|
||||
# │ │ ├── BUILD_ROOT
|
||||
# │ │ ├── TPLS_REPO
|
||||
# │ │ ├── TESTS_REPO
|
||||
# │ │ ├── AUTOTEST_ROOT
|
||||
# │ │ └── AUTOTEST_REPO
|
||||
# │ ├── jobs
|
||||
# │ │ ├── matrix-reports.yml
|
||||
# │ │ │ ├── <jobs>
|
||||
# │ │ │ │ ├── report_job_success
|
||||
# │ │ │ │ └── report_job_failure
|
||||
# │ │ │ └── <used jobs>
|
||||
# │ │ │ ├── .on_matrix
|
||||
# │ │ │ ├── .report_job_success
|
||||
# │ │ │ └── .report_job_failure
|
||||
# │ │ ├── matrix.yml
|
||||
# │ │ │ ├── <jobs>
|
||||
# │ │ │ │ ├── .matrix_reproducer_vars
|
||||
# │ │ │ │ ├── setup
|
||||
# │ │ │ │ ├── opt_mpi_cuda_gcc
|
||||
# │ │ │ │ └── opt_mpi_cuda_hypre_cuda_gcc
|
||||
# │ │ │ ├── <used jobs>
|
||||
# │ │ │ │ ├── .reproducer_vars
|
||||
# │ │ │ │ ├── .on_matrix
|
||||
# │ │ │ │ └── .job_on_matrix
|
||||
# │ │ │ ├── <included and used files>
|
||||
# │ │ │ │ └── tests/gitlab/build_and_test_setup [by "setup"]
|
||||
# │ │ │ └── <defined variables>
|
||||
# │ │ │ └── SPEC
|
||||
# │ │ ├── dane-reports.yml
|
||||
# │ │ │ ├── <jobs>
|
||||
# │ │ │ │ ├── report_job_success
|
||||
# │ │ │ │ └── report_job_failure
|
||||
# │ │ │ └── <used jobs>
|
||||
# │ │ │ ├── .on_dane
|
||||
# │ │ │ ├── .report_job_success
|
||||
# │ │ │ └── .report_job_failure
|
||||
# │ │ ├── dane.yml
|
||||
# │ │ │ ├── <jobs>
|
||||
# │ │ │ │ ├── .dane_reproducer_vars
|
||||
# │ │ │ │ ├── setup
|
||||
# │ │ │ │ ├── debug_ser_gcc_10
|
||||
# │ │ │ │ ├── debug_par_gcc_10
|
||||
# │ │ │ │ ├── opt_ser_gcc_10
|
||||
# │ │ │ │ ├── opt_par_gcc_10
|
||||
# │ │ │ │ ├── opt_par_gcc_10_sundials
|
||||
# │ │ │ │ ├── opt_par_gcc_10_petsc
|
||||
# │ │ │ │ └── opt_par_gcc_10_pumi
|
||||
# │ │ │ ├── <used jobs>
|
||||
# │ │ │ │ ├── .reproducer_vars
|
||||
# │ │ │ │ ├── .on_dane
|
||||
# │ │ │ │ └── .job_on_dane
|
||||
# │ │ │ ├── <included and used files>
|
||||
# │ │ │ │ └── tests/gitlab/build_and_test_setup [by "setup"]
|
||||
# │ │ │ └── <defined variables>
|
||||
# │ │ │ ├── SPEC
|
||||
# │ │ │ └── THREADS
|
||||
# │ │ ├── tioga-reports.yml
|
||||
# │ │ │ ├── <jobs>
|
||||
# │ │ │ │ ├── report_job_success
|
||||
# │ │ │ │ └── report_job_failure
|
||||
# │ │ │ └── <used jobs>
|
||||
# │ │ │ ├── .on_tioga
|
||||
# │ │ │ ├── .report_job_success
|
||||
# │ │ │ └── .report_job_failure
|
||||
# │ │ └── tioga.yml
|
||||
# │ │ ├── <jobs>
|
||||
# │ │ │ ├── .tioga_reproducer_vars
|
||||
# │ │ │ ├── setup
|
||||
# │ │ │ └── opt_mpi_rocm_hypre_rocm
|
||||
# │ │ ├── <used jobs>
|
||||
# │ │ │ ├── .reproducer_vars
|
||||
# │ │ │ ├── .on_tioga
|
||||
# │ │ │ └── .job_on_tioga
|
||||
# │ │ ├── <included and used files>
|
||||
# │ │ │ └── tests/gitlab/build_and_test_setup [by "setup"]
|
||||
# │ │ └── <defined variables>
|
||||
# │ │ ├── SPEC
|
||||
# │ │ └── THREADS
|
||||
# │ ├── scripts
|
||||
# │ │ ├── baseline
|
||||
# │ │ │ └── <used variables>
|
||||
# │ │ │ ├── BASELINE_TEST
|
||||
# │ │ │ ├── SYS_TYPE
|
||||
# │ │ │ ├── MACHINE_NAME
|
||||
# │ │ │ ├── CI_PROJECT_DIR
|
||||
# │ │ │ ├── ARTIFACTS_DIR
|
||||
# │ │ │ ├── BUILD_ROOT
|
||||
# │ │ │ └── TPLS_DIR
|
||||
# │ │ ├── git_try_to_push
|
||||
# │ │ ├── rebaseline
|
||||
# │ │ │ └── <used variables>
|
||||
# │ │ │ ├── CI_PROJECT_DIR
|
||||
# │ │ │ ├── ARTIFACTS_DIR
|
||||
# │ │ │ ├── SYS_TYPE
|
||||
# │ │ │ ├── BUILD_ROOT
|
||||
# │ │ │ ├── MACHINE_NAME
|
||||
# │ │ │ └── CI_PIPELINE_ID
|
||||
# │ │ ├── report_build_and_test
|
||||
# │ │ │ ├── <used files>
|
||||
# │ │ │ │ ├── .gitlab/scripts/safe_create_rundir
|
||||
# │ │ │ │ └── .gitlab/scripts/git_try_to_push
|
||||
# │ │ │ └── <used variables>
|
||||
# │ │ │ ├── AUTOTEST_ROOT
|
||||
# │ │ │ ├── CI_COMMIT_REF_SLUG
|
||||
# │ │ │ ├── CI_PROJECT_DIR
|
||||
# │ │ │ ├── CI_PIPELINE_URL
|
||||
# │ │ │ ├── AUTOTEST_COMMIT
|
||||
# │ │ │ └── CI_MACHINE
|
||||
# │ │ └── safe_create_rundir
|
||||
# │ ├── custom-jobs-and-variables.yml
|
||||
# │ │ ├── <jobs>
|
||||
# │ │ │ ├── .custom_job
|
||||
# │ │ │ ├── .reproducer_vars
|
||||
# │ │ │ ├── .report_job_success
|
||||
# │ │ │ └── .report_job_failure
|
||||
# │ │ ├── <used files>
|
||||
# │ │ │ ├── tests/gitlab/build_and_test [in JOB_CMD]
|
||||
# │ │ │ └── .gitlab/scripts/report_build_and_test [by .report_job_*]
|
||||
# │ │ ├── <defined variables>
|
||||
# │ │ │ ├── JOB_CMD
|
||||
# │ │ │ ├── BUILD_ROOT
|
||||
# │ │ │ ├── ALLOC_NAME
|
||||
# │ │ │ ├── TPLS_REPO
|
||||
# │ │ │ ├── TESTS_REPO
|
||||
# │ │ │ ├── AUTOTEST_REPO
|
||||
# │ │ │ ├── MFEM_DATA_REPO
|
||||
# │ │ │ ├── ARTIFACTS_DIR: artifacts
|
||||
# │ │ │ ├── SLURM_OVERLAP: 1
|
||||
# │ │ │ ├── DANE_SHARED_ALLOC
|
||||
# │ │ │ ├── DANE_JOB_ALLOC
|
||||
# │ │ │ ├── TIOGA_SHARED_ALLOC
|
||||
# │ │ │ ├── TIOGA_JOB_ALLOC
|
||||
# │ │ │ └── MATRIX_JOB_ALLOC
|
||||
# │ │ └── <used variables>
|
||||
# │ │ ├── SPEC
|
||||
# │ │ ├── BUILD_ROOT
|
||||
# │ │ └── ...
|
||||
# │ ├── dane-baseline.yml
|
||||
# │ │ ├── <jobs>
|
||||
# │ │ │ ├── .on_dane
|
||||
# │ │ │ ├── baselinecheck_mfem_intel_dane
|
||||
# │ │ │ ├── cleanup
|
||||
# │ │ │ ├── report_baseline
|
||||
# │ │ │ └── baselinepublish_mfem_dane
|
||||
# │ │ ├── <included and used files>
|
||||
# │ │ │ ├── .gitlab/custom-jobs-and-variables.yml
|
||||
# │ │ │ ├── .gitlab/configs/setup-baseline.yml
|
||||
# │ │ │ ├── .gitlab/scripts/rebaseline
|
||||
# │ │ │ ├── .gitlab/scripts/baseline
|
||||
# │ │ │ └── .gitlab/scripts/git_try_to_push
|
||||
# │ │ ├── <defined variables>
|
||||
# │ │ │ ├── BASELINE_TEST: baseline
|
||||
# │ │ │ ├── MACHINE_NAME: dane
|
||||
# │ │ │ ├── TPLS_DIR
|
||||
# │ │ │ └── export MFEM_TEST_NP
|
||||
# │ │ └── <used variables>
|
||||
# │ │ ├── ON_DANE
|
||||
# │ │ ├── AUTOTEST [defined by .gitlab-ci.yml]
|
||||
# │ │ ├── BUILD_ROOT [defined by custom-jobs-and-variables.yml]
|
||||
# │ │ ├── TPLS_DIR [defined by this file]
|
||||
# │ │ ├── ARTIFACTS_DIR [defined by custom-jobs-and-variables.yml]
|
||||
# │ │ ├── MACHINE_NAME [defined by this file]
|
||||
# │ │ ├── AUTOTEST_COMMIT [defined by .gitlab-ci.yml]
|
||||
# │ │ ├── AUTOTEST_ROOT [defined by .gitlab-ci.yml]
|
||||
# │ │ ├── BASELINE_TEST [defined by this file]
|
||||
# │ │ └── REBASELINE [defined by .gitlab-ci.yml]
|
||||
# │ └── subscribed-pipelines.yml
|
||||
# │ ├── <jobs>
|
||||
# │ │ ├── .machine-check
|
||||
# │ │ ├── generate-job-lists
|
||||
# │ │ ├── dane-up-check
|
||||
# │ │ ├── dane-build-and-test
|
||||
# │ │ ├── dane-baseline
|
||||
# │ │ ├── tioga-up-check
|
||||
# │ │ ├── tioga-build-and-test
|
||||
# │ │ ├── matrix-up-check
|
||||
# │ │ └── matrix-build-and-test
|
||||
# │ ├── <used jobs>
|
||||
# │ │ └── .build-and-test [from ".gitlab-ci.yml"]
|
||||
# │ ├── <included files>
|
||||
# │ │ └── .gitlab/dane-baseline.yml [by "dane-baseline"]
|
||||
# │ └── <used variables>
|
||||
# │ ├── GITHUB_PROJECT_ORG
|
||||
# │ ├── GITHUB_PROJECT_NAME
|
||||
# │ ├── AUTOTEST
|
||||
# │ ├── AUTOTEST_COMMIT
|
||||
# │ └── REBASELINE
|
||||
# └── tests
|
||||
# ├── gitlab
|
||||
# │ ├── build_and_test
|
||||
# │ │ ├── <builds and tests a given MFEM spec with uberenv>
|
||||
# │ │ ├── <used files>
|
||||
# │ │ │ ├── tests/uberenv/uberenv.py [deps mode, cloned]
|
||||
# │ │ │ └── tests/gitlab/get_mfem_uberenv [deps mode]
|
||||
# │ │ └── <used variables>
|
||||
# │ │ ├── SYS_TYPE
|
||||
# │ │ ├── THREADS [num. parallel jobs to build MFEM]
|
||||
# │ │ ├── MODULE_LIST [modules to load]
|
||||
# │ │ ├── CI_JOB_ID
|
||||
# │ │ ├── USE_DEV_SHM
|
||||
# │ │ ├── SPACK_DEBUG
|
||||
# │ │ ├── DEBUG_MODE
|
||||
# │ │ ├── REGISTRY_TOKEN
|
||||
# │ │ ├── CI_REGISTRY_USER (defined by Gitlab)
|
||||
# │ │ ├── USER
|
||||
# │ │ ├── CI_REGISTRY_IMAGE (defined by Gitlab)
|
||||
# │ │ └── CI_JOB_TOKEN (defined by Gitlab)
|
||||
# │ ├── build_and_test_setup
|
||||
# │ │ ├── <updates MFEM_DATA_REPO and AUTOTEST_REPO using locks>
|
||||
# │ │ └── <used variables>
|
||||
# │ │ ├── MFEM_DATA_REPO
|
||||
# │ │ ├── SHARED_REPOS_DIR
|
||||
# │ │ ├── AUTOTEST_REPO
|
||||
# │ │ └── AUTOTEST_ROOT
|
||||
# │ └── get_mfem_uberenv
|
||||
# │ ├── <github.com/mfem/mfem-uberenv.git -> tests/uberenv>
|
||||
# │ └── <defines the uberenv hash to use>
|
||||
# └── uberenv [cloned by tests/gitlab/get_mfem_uberenv]
|
||||
# └── uberenv.py
|
||||
#
|
||||
# <root of radiuss/radiuss-shared-ci, ref: 'v2025.09.1'>
|
||||
# └── pipelines
|
||||
# ├── matrix.yml
|
||||
# │ ├── <jobs>
|
||||
# │ │ ├── .on_matrix
|
||||
# │ │ ├── .matrix_reproducer_init
|
||||
# │ │ ├── .matrix_reproducer_vars
|
||||
# │ │ ├── .matrix_reproducer_job
|
||||
# │ │ ├── .matrix_job_command
|
||||
# │ │ └── .job_on_matrix
|
||||
# │ ├── <used jobs>
|
||||
# │ │ └── .custom_job [from .gitlab/custom-jobs-and-variables.yml]
|
||||
# │ └── <used variables>
|
||||
# │ ├── ON_MATRIX
|
||||
# │ ├── ADVANCED_JOB
|
||||
# │ ├── ALL_TARGETS
|
||||
# │ ├── SYS_TYPE
|
||||
# │ ├── LLNL_SERVICE_USER
|
||||
# │ ├── USER
|
||||
# │ ├── GITHUB_PROJECT_NAME
|
||||
# │ ├── GITHUB_PROJECT_ORG
|
||||
# │ ├── MATRIX_JOB_ALLOC
|
||||
# │ └── JOB_CMD
|
||||
# ├── dane.yml
|
||||
# │ ├── <jobs>
|
||||
# │ │ ├── .on_dane
|
||||
# │ │ ├── .dane_reproducer_init
|
||||
# │ │ ├── .dane_reproducer_vars
|
||||
# │ │ ├── .dane_reproducer_job
|
||||
# │ │ ├── .dane_job_command
|
||||
# │ │ ├── .job_on_dane
|
||||
# │ │ ├── allocate_resources
|
||||
# │ │ └── release_resources
|
||||
# │ ├── <used jobs>
|
||||
# │ │ └── .custom_job [from .gitlab/custom-jobs-and-variables.yml]
|
||||
# │ ├── <defined variables>
|
||||
# │ │ └── export JOBID
|
||||
# │ └── <used variables>
|
||||
# │ ├── ON_DANE
|
||||
# │ ├── ADVANCED_JOB
|
||||
# │ ├── ALL_TARGETS
|
||||
# │ ├── SYS_TYPE
|
||||
# │ ├── LLNL_SERVICE_USER
|
||||
# │ ├── USER
|
||||
# │ ├── GITHUB_PROJECT_NAME
|
||||
# │ ├── GITHUB_PROJECT_ORG
|
||||
# │ ├── DANE_JOB_ALLOC
|
||||
# │ ├── JOB_CMD
|
||||
# │ ├── JOBID
|
||||
# │ ├── ALLOC_NAME
|
||||
# │ └── DANE_SHARED_ALLOC
|
||||
# └── tioga.yml
|
||||
# ├── <jobs>
|
||||
# │ ├── .on_tioga
|
||||
# │ ├── .tioga_reproducer_init
|
||||
# │ ├── .tioga_reproducer_vars
|
||||
# │ ├── .tioga_reproducer_job
|
||||
# │ ├── .tioga_job_command
|
||||
# │ ├── .job_on_tioga
|
||||
# │ ├── allocate_resources
|
||||
# │ └── release_resources
|
||||
# ├── <used jobs>
|
||||
# │ └── .custom_job [from .gitlab/custom-jobs-and-variables.yml]
|
||||
# ├── <defined variables>
|
||||
# │ └── PROXY
|
||||
# └── <used variables>
|
||||
# ├── ON_TIOGA
|
||||
# ├── ADVANCED_JOB
|
||||
# ├── ALL_TARGETS
|
||||
# ├── SYS_TYPE
|
||||
# ├── LLNL_SERVICE_USER
|
||||
# ├── USER
|
||||
# ├── GITHUB_PROJECT_NAME
|
||||
# ├── GITHUB_PROJECT_ORG
|
||||
# ├── TIOGA_JOB_ALLOC
|
||||
# ├── JOB_CMD
|
||||
# ├── PROXY
|
||||
# ├── ALLOC_NAME
|
||||
# └── TIOGA_SHARED_ALLOC
|
||||
|
||||
###############################################################################
|
||||
# We define the following GitLab pipeline variables:
|
||||
variables:
|
||||
##### LC GITLAB CONFIGURATION
|
||||
CUSTOM_CI_BUILDS_DIR: "/usr/workspace/mfem/gitlab-runner"
|
||||
|
||||
##### PROJECT VARIABLES
|
||||
USER_CI_TOP_DIR: "${CUSTOM_CI_BUILDS_DIR}/${GITLAB_USER_LOGIN}"
|
||||
SHARED_REPOS_DIR: "${USER_CI_TOP_DIR}/repos"
|
||||
AUTOTEST_ROOT: "${SHARED_REPOS_DIR}"
|
||||
# MFEM_DATA_DIR is setup in '.gitlab/configs/setup-build-and-test.yml' and
|
||||
# used in '.gitlab/configs/<machine>-config.yml':
|
||||
MFEM_DATA_DIR: "${SHARED_REPOS_DIR}/mfem-data"
|
||||
|
||||
# AUTOTEST: enable (ON/YES) or disable (any other value) test reporting. See
|
||||
# also AUTOTEST_COMMIT.
|
||||
AUTOTEST: "OFF"
|
||||
# AUTOTEST_COMMIT: used only when AUTOTEST is set to ON/YES.
|
||||
# * If AUTOTEST_COMMIT is set to ON/YES, reporting jobs will commit their
|
||||
# files to the MFEM/autotest repo.
|
||||
# * If AUTOTEST_COMMIT is NOT set to ON/YES, reporting jobs will NOT commit
|
||||
# their files to the MFEM/autotest repo. Instead they will just show the
|
||||
# contents of the report files and remove them.
|
||||
AUTOTEST_COMMIT: "ON"
|
||||
# REBASELINE:
|
||||
# Defines the default choice for updating the saved baseline results. By default
|
||||
# the baseline can only be updated from the master branch. This variable offers
|
||||
# the option to manually ask for rebaselining from another branch if necessary.
|
||||
REBASELINE: "NO"
|
||||
AUTOTEST: "NO"
|
||||
# AUTOTEST_COMMIT: used only when AUTOTEST is set to YES.
|
||||
# * If AUTOTEST_COMMIT is NOT set to NO, reporting jobs will commit their
|
||||
# files to the MFEM/autotest repo.
|
||||
# * If AUTOTEST_COMMIT is set to NO, reporting jobs will NOT commit their
|
||||
# files to the MFEM/autotest repo. Instead they will just show the contents
|
||||
# of the report files and remove them.
|
||||
AUTOTEST_COMMIT: "YES"
|
||||
REBASELINE: "OFF"
|
||||
|
||||
# Trigger subpipelines:
|
||||
ruby-build-and-test:
|
||||
stage: sub-pipelines
|
||||
##### SHARED_CI CONFIGURATION
|
||||
# Required information about GitHub repository
|
||||
GITHUB_PROJECT_NAME: "mfem"
|
||||
GITHUB_PROJECT_ORG: "MFEM"
|
||||
# Override the pattern describing branches that will skip the "draft PR filter
|
||||
# test". Add protected branches here. See default value in
|
||||
# preliminary-ignore-draft-pr.yml.
|
||||
# ALWAYS_RUN_PATTERN: ""
|
||||
|
||||
###############################################################################
|
||||
##### High level stages
|
||||
# We organize the test-pipelines stage with sub-pipelines. Each sub-pipeline
|
||||
# corresponds to a test batch on a given machine.
|
||||
stages:
|
||||
- prerequisites
|
||||
- test-pipelines
|
||||
|
||||
###############################################################################
|
||||
# Template for jobs triggering a build-and-test sub-pipeline:
|
||||
.build-and-test:
|
||||
stage: test-pipelines
|
||||
variables:
|
||||
# Explicitly pass down values that we want to be able to set when triggering
|
||||
# pipelines manually or using scheduling
|
||||
# Explicitly pass down values that are not always propagated to child
|
||||
# pipelines, e.g. when a variable is set in the "Settings -> CI" web
|
||||
# interface (project variables).
|
||||
# Note: in some cases, this does not work as expected, e.g. when the
|
||||
# variable is not re-defined in the web interface; in such cases, the child
|
||||
# pipeline gets a definition like '${AUTOTEST}', i.e. it behaves as if
|
||||
# AUTOTEST is undefined, even though there is a default value in
|
||||
# .gitlab-ci.yml.
|
||||
AUTOTEST: "${AUTOTEST}"
|
||||
AUTOTEST_COMMIT: "${AUTOTEST_COMMIT}"
|
||||
trigger:
|
||||
include: .gitlab/ruby-build-and-test.yml
|
||||
include:
|
||||
- local: '.gitlab/custom-jobs-and-variables.yml'
|
||||
- project: 'radiuss/radiuss-shared-ci'
|
||||
ref: 'v2025.09.1'
|
||||
file: 'pipelines/${CI_MACHINE}.yml'
|
||||
- artifact: '${CI_MACHINE}-jobs.yml'
|
||||
job: 'generate-job-lists'
|
||||
strategy: depend
|
||||
forward:
|
||||
pipeline_variables: true
|
||||
|
||||
ruby-baseline:
|
||||
stage: sub-pipelines
|
||||
variables:
|
||||
# Explicitly pass down values that we want to be able to set when triggering
|
||||
# pipelines manually or using scheduling
|
||||
REBASELINE: "${REBASELINE}"
|
||||
AUTOTEST: "${AUTOTEST}"
|
||||
AUTOTEST_COMMIT: "${AUTOTEST_COMMIT}"
|
||||
trigger:
|
||||
include: .gitlab/ruby-baseline.yml
|
||||
strategy: depend
|
||||
|
||||
lassen-build-and-test:
|
||||
stage: sub-pipelines
|
||||
variables:
|
||||
# Explicitly pass down values that we want to be able to set when triggering
|
||||
# pipelines manually or using scheduling
|
||||
AUTOTEST: "${AUTOTEST}"
|
||||
AUTOTEST_COMMIT: "${AUTOTEST_COMMIT}"
|
||||
trigger:
|
||||
include: .gitlab/lassen-build-and-test.yml
|
||||
strategy: depend
|
||||
|
||||
corona-build-and-test:
|
||||
stage: sub-pipelines
|
||||
variables:
|
||||
# Explicitly pass down values that we want to be able to set when triggering
|
||||
# pipelines manually or using scheduling
|
||||
AUTOTEST: "${AUTOTEST}"
|
||||
AUTOTEST_COMMIT: "${AUTOTEST_COMMIT}"
|
||||
trigger:
|
||||
include: .gitlab/corona-build-and-test.yml
|
||||
strategy: depend
|
||||
###############################################################################
|
||||
include:
|
||||
# Sets ID tokens for every job using `default:`
|
||||
- project: 'lc-templates/id_tokens'
|
||||
file: 'id_tokens.yml'
|
||||
# [Optional] checks preliminary to running the actual CI test
|
||||
#- project: 'radiuss/radiuss-shared-ci'
|
||||
# ref: 'v2025.09.1'
|
||||
# file: 'preliminary-ignore-draft-pr.yml'
|
||||
# pipelines subscribed by the project
|
||||
- local: '.gitlab/subscribed-pipelines.yml'
|
||||
|
||||
+38
-14
@@ -8,6 +8,8 @@
|
||||
https://mfem.org
|
||||
|
||||
|
||||
FIXME: this file needs to be updated
|
||||
|
||||
This directory contains most of the GitLab CI configuration. MFEM runs both PR
|
||||
and nightly testing on GitLab.
|
||||
|
||||
@@ -15,18 +17,18 @@ and nightly testing on GitLab.
|
||||
|
||||
## Top level
|
||||
|
||||
The root configuration file is `.gitlab-ci.yml` at the root of MFEM repo.
|
||||
This file only defines one stage, in which we trigger several
|
||||
sub-pipelines.
|
||||
The root configuration file is `.gitlab-ci.yml` at the root of MFEM repo. This
|
||||
file only defines three stages, a prerequisites one, and two main stages in
|
||||
which we trigger several sub-pipelines.
|
||||
|
||||
We use sub-pipelines to isolate the test for one combination of `machine`
|
||||
and `test type`.
|
||||
|
||||
Machines typically include:
|
||||
|
||||
* Ruby: 2nd Gen Intel Xeon (Cascade Lake)
|
||||
* Lassen: Power9 + Nvidia GPU
|
||||
* Corona: AMD GPU
|
||||
* Dane: Intel Sapphire Rapids
|
||||
* Matrix: Intel Sapphire Rapids + Nvidia H100 GPU
|
||||
* Tioga: AMD MI250X GPU
|
||||
|
||||
Test types include:
|
||||
|
||||
@@ -39,9 +41,31 @@ altering the scheduling, execution and displaying of the others.
|
||||
|
||||
## Sub-pipelines
|
||||
|
||||
Each file is this directory is the root configuration file for one
|
||||
sub-pipeline. The naming reflects the corresponding couple (`machine`,
|
||||
`test_type`).
|
||||
### build-and-test
|
||||
|
||||
The build-and-test sub-pipelines leverage RADIUSS Shared CI to share most of
|
||||
the CI implementation. RADIUSS Shared CI provides a shared CI infrastructure
|
||||
vetted on most LC systems of interest and efficiently leveraging each machine
|
||||
scheduler to increase CI throughput. The maintenance of RADIUSS Shared CI is
|
||||
shared among several RADIUSS projects.
|
||||
|
||||
Jobs for the build-and-test sub-pipelines are defined in the jobs directory.
|
||||
Because build-and-test jobs leverage Uberenv and Spack to build the
|
||||
dependencies automatically, the jobs essentially consists in a `spack spec`
|
||||
defined in the jobs files, and some scheduling parameters defined in the
|
||||
`.gitlab/custom-jobs-and-variables.yml` file.
|
||||
|
||||
Build-and-test jobs all run the `tests/gitlab/build_and_test` script.
|
||||
|
||||
The build-and-test pipelines are controlled by the
|
||||
`.gitlab/subscribed-pipelines.yml` which defines which machines to run on and
|
||||
implements additional features like machine availability check, and job list
|
||||
generation.
|
||||
|
||||
### baseline
|
||||
|
||||
Baseline sub-pipelines are described by files with names reflecting the
|
||||
machine it runs on, e.g. `dane-baseline`.
|
||||
|
||||
Those files define the *stages* and the *jobs* for the sub-pipeline. They
|
||||
also contain any configuration that cannot be shared. For the most part
|
||||
@@ -63,11 +87,11 @@ usage function. This should be improved.
|
||||
|
||||
# More testing
|
||||
|
||||
## Adding a new target to a build_and_test pipeline
|
||||
## Adding a new target to a build-and-test pipeline
|
||||
|
||||
`build_and_test` pipelines rely on Spack to install dependencies. Spack is
|
||||
`build-and-test` pipelines rely on Spack to install dependencies. Spack is
|
||||
driven by Uberenv which helps freezing Spack configuration: the goal being to
|
||||
point to specific commit in Spack and isolate its configuration so that it is
|
||||
point to a specific commit in Spack and isolate its configuration so that it is
|
||||
not influenced by the user environment. More documentation about this can be
|
||||
found in `tests/gitlab`.
|
||||
|
||||
@@ -76,13 +100,13 @@ with a spack spec of MFEM, within the limits permitted by the MFEM spack
|
||||
package.
|
||||
|
||||
In any build-and-test sub-pipeline a job basically consists in defining the
|
||||
spack spec to use. Adding a job on ruby for example resumes to:
|
||||
spack spec to use. Adding a job on Dane for example resumes to:
|
||||
|
||||
```yaml
|
||||
<job_name>:
|
||||
variables:
|
||||
SPEC: "<spack_spec>"
|
||||
extends: .build_and_test_on_ruby
|
||||
extends: .job_on_dane
|
||||
```
|
||||
|
||||
The remaining and non trivial work is to make sure this spec is working. To
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
# Copyright (c) 2010-2025, 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:
|
||||
- project: 'lc-templates/id_tokens'
|
||||
file: 'id_tokens.yml'
|
||||
|
||||
# We define the following GitLab pipeline variables:
|
||||
variables:
|
||||
|
||||
# The path to the shared resource between all jobs. For example, external
|
||||
# repositories like 'tests' and 'tpls' are cloned here. Also, 'tpls' is built
|
||||
# once for all targets, so that build happen here. The BUILD_ROOT is unique to
|
||||
# the pipeline, preventing any form of concurrency with other pipelines. This
|
||||
# also means that the BUILD_ROOT directory will never be cleaned.
|
||||
# TODO: add a clean-up mechanism
|
||||
BUILD_ROOT: ${USER_CI_TOP_DIR}/${CI_PROJECT_NAME}-${MACHINE_NAME}-pipeline-${CI_PIPELINE_ID}
|
||||
|
||||
# On LLNL's ruby, there is only one allocation shared among jobs in order to
|
||||
# save time and resource. This allocation has to be uniquely named so that we
|
||||
# are sure to retrieve it.
|
||||
ALLOC_NAME: ${CI_PROJECT_NAME}_ci_${CI_PIPELINE_ID}
|
||||
|
||||
# Git repositories used in the pipeline
|
||||
TPLS_REPO: ssh://git@mybitbucket.llnl.gov:7999/mfem/tpls.git
|
||||
TESTS_REPO: ssh://git@mybitbucket.llnl.gov:7999/mfem/tests.git
|
||||
AUTOTEST_REPO: ssh://git@mybitbucket.llnl.gov:7999/mfem/autotest.git
|
||||
MFEM_DATA_REPO: https://github.com/mfem/data.git
|
||||
|
||||
# Directory used to place artifacts.
|
||||
ARTIFACTS_DIR: artifacts
|
||||
SLURM_OVERLAP: 1
|
||||
@@ -1,59 +0,0 @@
|
||||
# Copyright (c) 2010-2025, 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.
|
||||
|
||||
# GitLab pipeline configuration for the Corona machine at LLNL
|
||||
variables:
|
||||
MACHINE_NAME: corona
|
||||
|
||||
.on_corona:
|
||||
tags:
|
||||
- shell
|
||||
- corona
|
||||
rules:
|
||||
# Don't run corona jobs if...
|
||||
# Note: This makes corona an "opt-in" machine. To activate builds on corona
|
||||
# for a given GitLab clone of MFEM, go to Setting/CI-CD/variables, and set
|
||||
# "ON_CORONA" to "ON". An LC account on for corona is required to trigger a
|
||||
# pipeline there.
|
||||
- if: '$CI_COMMIT_BRANCH =~ /_cnone/ || $ON_CORONA != "ON"'
|
||||
when: never
|
||||
# Don't run autotest update if...
|
||||
- if: '$CI_JOB_NAME =~ /report/ && $AUTOTEST != "YES"'
|
||||
when: never
|
||||
# Report success on success status
|
||||
- if: '$CI_JOB_NAME =~ /report_job_success/ && $AUTOTEST == "YES"'
|
||||
when: on_success
|
||||
# Report failure on failure status
|
||||
- if: '$CI_JOB_NAME =~ /report_job_failure/ && $AUTOTEST == "YES"'
|
||||
when: on_failure
|
||||
# Always release resource
|
||||
- if: '$CI_JOB_NAME =~ /release_resource/'
|
||||
when: always
|
||||
# Always cleanup
|
||||
- if: '$CI_JOB_NAME =~ /cleanup/'
|
||||
when: always
|
||||
# Default is to run if previous stage succeeded
|
||||
- when: on_success
|
||||
|
||||
# Spack helped builds
|
||||
# Generic corona build job, extending build script
|
||||
.build_and_test_on_corona:
|
||||
extends: [.on_corona]
|
||||
stage: build_and_test
|
||||
script:
|
||||
# THREADS is used by 'tests/gitlab/build_and_test', run below
|
||||
- export THREADS=12
|
||||
- echo ${ALLOC_NAME}
|
||||
- export JOBID=$(squeue -h --name=${ALLOC_NAME} --format=%A)
|
||||
- echo ${JOBID}
|
||||
- echo ${MFEM_DATA_DIR}
|
||||
- echo ${SPEC}
|
||||
- srun $( [[ -n "${JOBID}" ]] && echo "--jobid=${JOBID}" ) -t 15 -N 1 tests/gitlab/build_and_test --spec "${SPEC}" --data-dir "${MFEM_DATA_DIR}" --data
|
||||
@@ -1,48 +0,0 @@
|
||||
# Copyright (c) 2010-2025, 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.
|
||||
|
||||
# GitLab pipelines configurations for the Lassen machine at LLNL
|
||||
variables:
|
||||
MACHINE_NAME: lassen
|
||||
|
||||
.on_lassen:
|
||||
tags:
|
||||
- shell
|
||||
- lassen
|
||||
rules:
|
||||
- if: '$CI_COMMIT_BRANCH =~ /_lnone/ || $ON_LASSEN == "OFF"' #run except if ...
|
||||
when: never
|
||||
# Don't run autotest update if...
|
||||
- if: '$CI_JOB_NAME =~ /report/ && $AUTOTEST != "YES"'
|
||||
when: never
|
||||
# Report success on success status
|
||||
- if: '$CI_JOB_NAME =~ /report_job_success/ && $AUTOTEST == "YES"'
|
||||
when: on_success
|
||||
# Report failure on failure status
|
||||
- if: '$CI_JOB_NAME =~ /report_job_failure/ && $AUTOTEST == "YES"'
|
||||
when: on_failure
|
||||
# Always cleanup
|
||||
- if: '$CI_JOB_NAME =~ /cleanup/'
|
||||
when: always
|
||||
- when: on_success
|
||||
|
||||
# Lassen uses a different job scheduler (spectrum lsf) that does not allow
|
||||
# pre-allocation the same way slurm does. We use the pci queue on lassen
|
||||
# to speed-up the allocation.
|
||||
.build_and_test_on_lassen:
|
||||
extends: [.on_lassen]
|
||||
stage: build_and_test
|
||||
script:
|
||||
- echo ${MFEM_DATA_DIR}
|
||||
- echo ${SPEC}
|
||||
# Next script uses 'THREADS': leaving it empty --> it uses 'make all -j'
|
||||
- lalloc 1 -W 45 -q pci --atsdisable tests/gitlab/build_and_test --spec "${SPEC}" --data-dir "${MFEM_DATA_DIR}" --data
|
||||
needs: [setup]
|
||||
@@ -1,77 +0,0 @@
|
||||
# Copyright (c) 2010-2025, 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.
|
||||
|
||||
# Jobs report
|
||||
.report_job_success:
|
||||
script:
|
||||
- echo ${MACHINE_NAME}
|
||||
- echo ${AUTOTEST}
|
||||
- echo ${AUTOTEST_COMMIT}
|
||||
- echo "AUTOTEST_ROOT ${AUTOTEST_ROOT}"
|
||||
- cd ${AUTOTEST_ROOT}
|
||||
- |
|
||||
(
|
||||
date
|
||||
echo "Waiting to acquire lock on '$PWD/autotest.lock' ..."
|
||||
# try to get an exclusive lock on fd 9 (autotest.lock) repeating the try
|
||||
# every 5 seconds; we may want to add a counter for the number of
|
||||
# retries to interrupt a potential infinite loop
|
||||
while ! flock -n 9; do
|
||||
sleep 5
|
||||
done
|
||||
echo "Acquired lock on '$PWD/autotest.lock'"
|
||||
date
|
||||
# Report SUCCESS while holding the file lock on 'autotest.lock'.
|
||||
# The next script uses the following environment variables:
|
||||
# - MACHINE_NAME, AUTOTEST_ROOT, AUTOTEST_COMMIT
|
||||
# - CI_COMMIT_REF_SLUG, CI_PROJECT_DIR, CI_PIPELINE_URL
|
||||
# It also calls the script '.gitlab/scripts/safe_create_rundir'.
|
||||
${CI_PROJECT_DIR}/.gitlab/scripts/report_build_and_test_success
|
||||
err=$?
|
||||
# sleep for a period to allow NFS to propagate the above changes;
|
||||
# clearly, there is no guarantee that other NFS clients will see the
|
||||
# changes even after the timeout
|
||||
sleep 10
|
||||
exit $err
|
||||
) 9> autotest.lock
|
||||
|
||||
.report_job_failure:
|
||||
script:
|
||||
- echo ${MACHINE_NAME}
|
||||
- echo ${AUTOTEST}
|
||||
- echo ${AUTOTEST_COMMIT}
|
||||
- echo "AUTOTEST_ROOT ${AUTOTEST_ROOT}"
|
||||
- cd ${AUTOTEST_ROOT}
|
||||
- |
|
||||
(
|
||||
date
|
||||
echo "Waiting to acquire lock on '$PWD/autotest.lock' ..."
|
||||
# try to get an exclusive lock on fd 9 (autotest.lock) repeating the try
|
||||
# every 5 seconds; we may want to add a counter for the number of
|
||||
# retries to interrupt a potential infinite loop
|
||||
while ! flock -n 9; do
|
||||
sleep 5
|
||||
done
|
||||
echo "Acquired lock on '$PWD/autotest.lock'"
|
||||
date
|
||||
# Report FAILURE while holding the file lock on 'autotest.lock'.
|
||||
# The next script uses the following environment variables:
|
||||
# - MACHINE_NAME, AUTOTEST_ROOT, AUTOTEST_COMMIT
|
||||
# - CI_COMMIT_REF_SLUG, CI_PROJECT_DIR, CI_PIPELINE_URL
|
||||
# It also calls the script '.gitlab/scripts/safe_create_rundir'.
|
||||
${CI_PROJECT_DIR}/.gitlab/scripts/report_build_and_test_failure
|
||||
err=$?
|
||||
# sleep for a period to allow NFS to propagate the above changes;
|
||||
# clearly, there is no guarantee that other NFS clients will see the
|
||||
# changes even after the timeout
|
||||
sleep 10
|
||||
exit $err
|
||||
) 9> autotest.lock
|
||||
@@ -1,55 +0,0 @@
|
||||
# Copyright (c) 2010-2025, 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.
|
||||
|
||||
# GitLab pipelines configurations for the Ruby machine at LLNL
|
||||
variables:
|
||||
MACHINE_NAME: ruby
|
||||
|
||||
.on_ruby:
|
||||
tags:
|
||||
- shell
|
||||
- ruby
|
||||
rules:
|
||||
# Don't run ruby jobs if...
|
||||
- if: '$CI_COMMIT_BRANCH =~ /_qnone/ || $ON_RUBY == "OFF"'
|
||||
when: never
|
||||
# Don't run autotest update if...
|
||||
- if: '$CI_JOB_NAME =~ /report/ && $AUTOTEST != "YES"'
|
||||
when: never
|
||||
# Report success on success status
|
||||
- if: '$CI_JOB_NAME =~ /report_job_success/ && $AUTOTEST == "YES"'
|
||||
when: on_success
|
||||
# Report failure on failure status
|
||||
- if: '$CI_JOB_NAME =~ /report_job_failure/ && $AUTOTEST == "YES"'
|
||||
when: on_failure
|
||||
# Always release resource
|
||||
- if: '$CI_JOB_NAME =~ /release_resource/'
|
||||
when: always
|
||||
# Always cleanup
|
||||
- if: '$CI_JOB_NAME =~ /cleanup/'
|
||||
when: always
|
||||
# Default is to run if previous stage succeeded
|
||||
- when: on_success
|
||||
|
||||
# Spack helped builds
|
||||
# Generic ruby build job, extending build script
|
||||
.build_and_test_on_ruby:
|
||||
extends: [.on_ruby]
|
||||
stage: build_and_test
|
||||
script:
|
||||
# THREADS is used by 'tests/gitlab/build_and_test', run below
|
||||
- export THREADS=16
|
||||
- echo ${ALLOC_NAME}
|
||||
- export JOBID=$(squeue -h --name=${ALLOC_NAME} --format=%A)
|
||||
- echo ${JOBID}
|
||||
- echo ${MFEM_DATA_DIR}
|
||||
- echo ${SPEC}
|
||||
- srun $( [[ -n "${JOBID}" ]] && echo "--jobid=${JOBID}" ) --reservation=ci -t 45 -N 1 tests/gitlab/build_and_test --spec "${SPEC}" --data-dir "${MFEM_DATA_DIR}" --data
|
||||
@@ -18,7 +18,7 @@
|
||||
setup_baseline:
|
||||
tags:
|
||||
- shell
|
||||
- ruby
|
||||
- dane
|
||||
stage: setup
|
||||
variables:
|
||||
GIT_STRATEGY: none
|
||||
|
||||
@@ -1,90 +0,0 @@
|
||||
# Copyright (c) 2010-2025, 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.
|
||||
|
||||
# Setup clones the mfem/data repo in ${SHARED_REPOS_DIR}. The build_and_test
|
||||
# script then symlinks the repo to the parent directory of the MFEM source
|
||||
# directory. Unit tests that depend on the mfem/data repo will then detect that
|
||||
# this directory is present and be enabled.
|
||||
setup:
|
||||
tags:
|
||||
- shell
|
||||
- ruby
|
||||
stage: setup
|
||||
variables:
|
||||
GIT_STRATEGY: none
|
||||
script:
|
||||
#
|
||||
# Setup MFEM_DATA_DIR=${SHARED_REPOS_DIR}/mfem-data, see '.gitlab-ci.yml'
|
||||
# and '.gitlab/configs/<machine>-config.yml'
|
||||
#
|
||||
- echo "MACHINE_NAME = ${MACHINE_NAME}"
|
||||
- echo "AUTOTEST = ${AUTOTEST}"
|
||||
- echo "AUTOTEST_COMMIT = ${AUTOTEST_COMMIT}"
|
||||
- echo "SHARED_REPOS_DIR ${SHARED_REPOS_DIR}"
|
||||
- mkdir -p ${SHARED_REPOS_DIR} && cd ${SHARED_REPOS_DIR}
|
||||
- command -v flock || echo "Required command 'flock' not found"
|
||||
- |
|
||||
(
|
||||
date
|
||||
echo "Waiting to acquire lock on '$PWD/mfem-data.lock' ..."
|
||||
# try to get an exclusive lock on fd 9 (mfem-data.lock) repeating the
|
||||
# try every 5 seconds; we may want to add a counter for the number of
|
||||
# retries to interrupt a potential infinite loop
|
||||
while ! flock -n 9; do
|
||||
sleep 5
|
||||
done
|
||||
echo "Acquired lock on '$PWD/mfem-data.lock'"
|
||||
date
|
||||
# clone/update the mfem/data repo while holding the file lock on
|
||||
# 'mfem-data.lock'
|
||||
err=0
|
||||
if [[ ! -d "mfem-data" ]]; then
|
||||
git clone ${MFEM_DATA_REPO} "mfem-data"
|
||||
else
|
||||
cd "mfem-data" && git pull && cd ..
|
||||
fi || err=1
|
||||
# sleep for a period to allow NFS to propagate the above changes;
|
||||
# clearly, there is no guarantee that other NFS clients will see the
|
||||
# changes even after the timeout
|
||||
sleep 10
|
||||
exit $err
|
||||
) 9> mfem-data.lock
|
||||
#
|
||||
# Setup ${AUTOTEST_ROOT}/autotest:
|
||||
#
|
||||
- echo "AUTOTEST_ROOT ${AUTOTEST_ROOT}"
|
||||
- mkdir -p ${AUTOTEST_ROOT} && cd ${AUTOTEST_ROOT}
|
||||
- |
|
||||
(
|
||||
date
|
||||
echo "Waiting to acquire lock on '$PWD/autotest.lock' ..."
|
||||
# try to get an exclusive lock on fd 9 (autotest.lock) repeating the try
|
||||
# every 5 seconds; we may want to add a counter for the number of
|
||||
# retries to interrupt a potential infinite loop
|
||||
while ! flock -n 9; do
|
||||
sleep 5
|
||||
done
|
||||
echo "Acquired lock on '$PWD/autotest.lock'"
|
||||
date
|
||||
# clone/update the autotest repo while holding the file lock on
|
||||
# 'autotest.lock'
|
||||
err=0
|
||||
if [[ ! -d "autotest" ]]; then
|
||||
git clone ${AUTOTEST_REPO}
|
||||
else
|
||||
cd autotest && git pull && cd ..
|
||||
fi || err=1
|
||||
# sleep for a period to allow NFS to propagate the above changes;
|
||||
# clearly, there is no guarantee that other NFS clients will see the
|
||||
# changes even after the timeout
|
||||
sleep 10
|
||||
exit $err
|
||||
) 9> autotest.lock
|
||||
@@ -1,67 +0,0 @@
|
||||
# Copyright (c) 2010-2025, 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.
|
||||
|
||||
stages:
|
||||
- setup
|
||||
- allocate_resource
|
||||
- build_and_test
|
||||
- release_resource_and_report
|
||||
|
||||
# Slurm shared allocation
|
||||
allocate_resource:
|
||||
variables:
|
||||
GIT_STRATEGY: none
|
||||
extends: .on_corona
|
||||
stage: allocate_resource
|
||||
script:
|
||||
- echo ${ALLOC_NAME}
|
||||
- salloc --exclusive --nodes=1 --partition=mi60 --time=45 --no-shell --job-name=${ALLOC_NAME}
|
||||
timeout: 6h
|
||||
needs: [setup]
|
||||
|
||||
# Build and test jobs, simply provide a spec
|
||||
rocm_gcc_8.3.1:
|
||||
variables:
|
||||
SPEC: "@develop%gcc@8.3.1+rocm amdgpu_target=gfx906"
|
||||
extends: .build_and_test_on_corona
|
||||
needs: [allocate_resource]
|
||||
|
||||
# Release slurm allocation
|
||||
release_resource:
|
||||
variables:
|
||||
GIT_STRATEGY: none
|
||||
extends: .on_corona
|
||||
stage: release_resource_and_report
|
||||
script:
|
||||
- echo ${ALLOC_NAME}
|
||||
- export JOBID=$(squeue -h --name=${ALLOC_NAME} --format=%A)
|
||||
- echo ${JOBID}
|
||||
- ([[ -n "${JOBID}" ]] && scancel ${JOBID})
|
||||
needs: [rocm_gcc_8.3.1]
|
||||
|
||||
# Jobs report
|
||||
report_job_success:
|
||||
stage: release_resource_and_report
|
||||
extends:
|
||||
- .on_corona
|
||||
- .report_job_success
|
||||
|
||||
report_job_failure:
|
||||
stage: release_resource_and_report
|
||||
extends:
|
||||
- .on_corona
|
||||
- .report_job_failure
|
||||
|
||||
include:
|
||||
- local: .gitlab/configs/common.yml
|
||||
- local: .gitlab/configs/corona-config.yml
|
||||
- local: .gitlab/configs/setup-build-and-test.yml
|
||||
- local: .gitlab/configs/report-build-and-test.yml
|
||||
@@ -0,0 +1,132 @@
|
||||
# Copyright (c) 2010-2025, 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:
|
||||
- project: 'lc-templates/id_tokens'
|
||||
file: 'id_tokens.yml'
|
||||
|
||||
# We define the following GitLab pipeline variables:
|
||||
variables:
|
||||
# Set the build-and-test command.
|
||||
# Nested variables are allowed and useful to customize the job command. We
|
||||
# protect variables with quotes so that their value may remain a string even if
|
||||
# they contain whitespaces.
|
||||
JOB_CMD:
|
||||
value: tests/gitlab/build_and_test --spec \"${SPEC}\" --data-dir ${MFEM_DATA_DIR} --data
|
||||
# The path to the shared resource between all jobs in the 'dane-baseline'
|
||||
# pipeline. For example, external repositories like 'tests' and 'tpls' are
|
||||
# cloned here. Also, 'tpls' is built once for all targets, so that build happens
|
||||
# here. The BUILD_ROOT is unique to the pipeline, preventing any form of
|
||||
# concurrency with other pipelines. This directory is removed by the 'cleanup'
|
||||
# stage in the 'dane-baseline' pipeline.
|
||||
BUILD_ROOT: ${USER_CI_TOP_DIR}/${CI_PROJECT_NAME}-${CI_MACHINE}-pipeline-${CI_PIPELINE_ID}
|
||||
|
||||
# On LLNL's dane and tioga, the 'build-and-test' pipelines creates only one
|
||||
# allocation shared among jobs in the pipeline in order to save time and
|
||||
# resources. This allocation has to be uniquely named so that we are sure to
|
||||
# retrieve it and avoid collisions.
|
||||
ALLOC_NAME: ${CI_PROJECT_NAME}_ci_${CI_PIPELINE_ID}
|
||||
|
||||
# Git repositories used in the pipelines:
|
||||
# - TPLS_REPO and TESTS_REPO are used only by the 'dane-baseline' pipeline
|
||||
# - AUTOTEST_REPO is used by all pipelines
|
||||
# - MFEM_DATA_REPO is used only by the 'build-and-test' pipelines
|
||||
TPLS_REPO: ssh://git@mybitbucket.llnl.gov:7999/mfem/tpls.git
|
||||
TESTS_REPO: ssh://git@mybitbucket.llnl.gov:7999/mfem/tests.git
|
||||
AUTOTEST_REPO: ssh://git@mybitbucket.llnl.gov:7999/mfem/autotest.git
|
||||
MFEM_DATA_REPO: https://github.com/mfem/data.git
|
||||
|
||||
# Directory used to place artifacts:
|
||||
# - ARTIFACTS_DIR is only used by the 'dane-baseline' pipeline
|
||||
ARTIFACTS_DIR: artifacts
|
||||
SLURM_OVERLAP: 1
|
||||
|
||||
# Dane
|
||||
# Arguments for top level allocation
|
||||
DANE_SHARED_ALLOC: "--exclusive --reservation=ci --time=60 --nodes=1"
|
||||
# Arguments for job level allocation
|
||||
# Note: We repeat the reservation, necessary when jobs are manually re-triggered.
|
||||
DANE_JOB_ALLOC: "--reservation=ci --overlap --nodes=1"
|
||||
|
||||
# Tioga
|
||||
# Arguments for top level allocation
|
||||
TIOGA_SHARED_ALLOC: "--queue=pci --exclusive --time-limit=45m --nodes=1"
|
||||
# Arguments for job level allocation
|
||||
TIOGA_JOB_ALLOC: "--nodes=1 --begin-time=+5s"
|
||||
|
||||
# Matrix
|
||||
# Arguments for top level allocation
|
||||
MATRIX_SHARED_ALLOC: "-p pdebug --exclusive --time=45 --nodes=1 -G 4"
|
||||
# Arguments for job level allocation
|
||||
# Note: We repeat the reservation, necessary when jobs are manually re-triggered.
|
||||
MATRIX_JOB_ALLOC: "--overlap --nodes=1"
|
||||
|
||||
# Configuration shared by build and test jobs specific to this project.
|
||||
# Not all configuration can be shared. Here projects can fine tune the
|
||||
# CI behavior.
|
||||
# See Umpire for an example (export junit test reports).
|
||||
.custom_job:
|
||||
artifacts:
|
||||
reports:
|
||||
|
||||
# Note: this part is not used by the 'dane-baseline' pipeline.
|
||||
# FIXME: BUILD_ROOT, TPLS_REPO, TESTS_REPO are not needed here.
|
||||
# Also, the definition of SHARED_REPOS_DIR is wrong.
|
||||
.reproducer_vars:
|
||||
script:
|
||||
- |
|
||||
echo -e "
|
||||
# Variables \n
|
||||
export SPEC=\"${SPEC//\"/\\\"}\" \n
|
||||
# Directories \n
|
||||
export BUILD_ROOT=\"\${working_dir}\" \n
|
||||
export SHARED_REPOS_DIR=\"\${BUILD_ROOT}/..\" \n
|
||||
export MFEM_DATA_DIR=\"\${SHARED_REPOS_DIR}/mfem-data\" \n
|
||||
# Repositories \n
|
||||
export TPLS_REPO=\"${TPLS_REPO//\"/\\\"}\" \n
|
||||
export TESTS_REPO=\"${TESTS_REPO//\"/\\\"}\" \n
|
||||
export AUTOTEST_REPO=\"${AUTOTEST_REPO//\"/\\\"}\" \n
|
||||
export MFEM_DATA_REPO=\"${MFEM_DATA_REPO//\"/\\\"}\" \n
|
||||
# Setup directories \n
|
||||
./tests/gitlab/build_and_test_setup \n
|
||||
# Using the CI build cache is optional and requires a token. Set it like so: \n
|
||||
# export REGISTRY_TOKEN=\"<your token here>\" \n"
|
||||
#
|
||||
|
||||
# Jobs report
|
||||
.report_job_success:
|
||||
script:
|
||||
- ${CI_PROJECT_DIR}/.gitlab/scripts/report_build_and_test SUCCESS
|
||||
rules:
|
||||
- when: on_success
|
||||
|
||||
.report_job_failure:
|
||||
script:
|
||||
- ${CI_PROJECT_DIR}/.gitlab/scripts/report_build_and_test FAILURE
|
||||
rules:
|
||||
- when: on_failure
|
||||
|
||||
# Keep the following for debugging purposes: renaming this job from
|
||||
# '.show_variables' to 'show_variables' will insert this debug job at the
|
||||
# beginning of all child pipelines.
|
||||
.show_variables:
|
||||
tags: [shell, oslic]
|
||||
variables:
|
||||
GIT_STRATEGY: none
|
||||
stage: .pre
|
||||
script:
|
||||
- |
|
||||
echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
|
||||
echo "AUTOTEST=${AUTOTEST}"
|
||||
echo "AUTOTEST_COMMIT=${AUTOTEST_COMMIT}"
|
||||
echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
|
||||
# Fail the job on purpose to prevent the rest of the pipeline from running
|
||||
false
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
variables:
|
||||
BASELINE_TEST: baseline
|
||||
MACHINE_NAME: dane
|
||||
|
||||
stages:
|
||||
- setup
|
||||
@@ -19,8 +20,27 @@ stages:
|
||||
- cleanup
|
||||
- baseline_publish
|
||||
|
||||
baselinecheck_mfem_intel_ruby:
|
||||
extends: [.on_ruby]
|
||||
.on_dane:
|
||||
tags:
|
||||
- shell
|
||||
- dane
|
||||
rules:
|
||||
# Don't run dane jobs if...
|
||||
- if: '$ON_DANE == "OFF"'
|
||||
when: never
|
||||
# Don't run autotest update if...
|
||||
# Note: in some cases, the content of AUTOTEST can be '${AUTOTEST}', so we
|
||||
# need to treat that value as the default value of 'OFF'.
|
||||
- if: '$CI_JOB_NAME =~ /report/ && $AUTOTEST != "ON" && $AUTOTEST != "YES"'
|
||||
when: never
|
||||
# Always cleanup
|
||||
- if: '$CI_JOB_NAME =~ /cleanup/'
|
||||
when: always
|
||||
# Default is to run if previous stage succeeded
|
||||
- when: on_success
|
||||
|
||||
baselinecheck_mfem_intel_dane:
|
||||
extends: [.on_dane]
|
||||
stage: baseline_check
|
||||
variables:
|
||||
# TPLS_DIR is used in .gitlab/scripts/baseline to provide the tpls location
|
||||
@@ -29,10 +49,13 @@ baselinecheck_mfem_intel_ruby:
|
||||
# .gitlab/configs/setup-baseline.yml.
|
||||
TPLS_DIR: ${BUILD_ROOT}/tpls
|
||||
script:
|
||||
- echo "AUTOTEST=$AUTOTEST"
|
||||
- echo "AUTOTEST_COMMIT=$AUTOTEST_COMMIT"
|
||||
- echo "AUTOTEST_ROOT=$AUTOTEST_ROOT"
|
||||
- echo ${BUILD_ROOT}
|
||||
- echo ${TPLS_DIR}
|
||||
# Used by the tests in MFEM/tests:
|
||||
- export MFEM_TEST_NP=48
|
||||
# Used by the tests in MFEM/tests, dane has 224 threads/node:
|
||||
- export MFEM_TEST_NP=192
|
||||
# The next script uses the following environment variables:
|
||||
# * BASELINE_TEST, SYS_TYPE, CI_PROJECT_DIR, ARTIFACTS_DIR,
|
||||
# * BUILD_ROOT, TPLS_DIR, MACHINE_NAME
|
||||
@@ -44,7 +67,7 @@ baselinecheck_mfem_intel_ruby:
|
||||
allow_failure: true
|
||||
|
||||
cleanup:
|
||||
extends: .on_ruby
|
||||
extends: .on_dane
|
||||
stage: cleanup
|
||||
variables:
|
||||
GIT_STRATEGY: none
|
||||
@@ -53,7 +76,7 @@ cleanup:
|
||||
- rm -rf "${BUILD_ROOT}" || true
|
||||
|
||||
report_baseline:
|
||||
extends: [.on_ruby]
|
||||
extends: [.on_dane]
|
||||
stage: baseline_report
|
||||
script:
|
||||
- echo ${MACHINE_NAME}
|
||||
@@ -89,7 +112,13 @@ report_baseline:
|
||||
cp ${rundir}/pipeline.txt ${rundir}/autotest-email.html
|
||||
fi
|
||||
msg="GitLab CI log for ${BASELINE_TEST} on ${MACHINE_NAME} ($(date +%Y-%m-%d))"
|
||||
if [[ "$AUTOTEST_COMMIT" != "NO" ]]; then
|
||||
# Note: in some cases, the content of AUTOTEST_COMMIT can be
|
||||
# '${AUTOTEST_COMMIT}', so we need to treat that value as the default
|
||||
# value of 'ON'.
|
||||
if [[ "$AUTOTEST_COMMIT" == '${AUTOTEST_COMMIT}' ]]; then
|
||||
AUTOTEST_COMMIT="ON"
|
||||
fi
|
||||
if [[ "$AUTOTEST_COMMIT" == "ON" || "$AUTOTEST_COMMIT" == "YES" ]]; then
|
||||
git pull && \
|
||||
git add ${rundir} && \
|
||||
git commit -m "${msg}" && \
|
||||
@@ -113,12 +142,12 @@ report_baseline:
|
||||
exit $err
|
||||
) 9> autotest.lock
|
||||
|
||||
baselinepublish_mfem_ruby:
|
||||
extends: [.on_ruby]
|
||||
baselinepublish_mfem_dane:
|
||||
extends: [.on_dane]
|
||||
stage: baseline_publish
|
||||
rules:
|
||||
# - if: '$CI_COMMIT_BRANCH == "master" || $REBASELINE == "YES"'
|
||||
- if: '$REBASELINE == "YES"'
|
||||
# - if: '$CI_COMMIT_BRANCH == "master" || $REBASELINE == "ON"'
|
||||
- if: '$REBASELINE == "ON"'
|
||||
when: manual
|
||||
script:
|
||||
- echo ${BUILD_ROOT}
|
||||
@@ -128,6 +157,5 @@ baselinepublish_mfem_ruby:
|
||||
- .gitlab/scripts/rebaseline
|
||||
|
||||
include:
|
||||
- local: .gitlab/configs/common.yml
|
||||
- local: .gitlab/configs/ruby-config.yml
|
||||
- local: .gitlab/custom-jobs-and-variables.yml
|
||||
- local: .gitlab/configs/setup-baseline.yml
|
||||
@@ -0,0 +1,19 @@
|
||||
# Copyright (c) 2010-2025, 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.
|
||||
|
||||
# Jobs report
|
||||
report_job_success:
|
||||
extends: [.on_dane, .report_job_success]
|
||||
stage: jobs-stage-3
|
||||
|
||||
report_job_failure:
|
||||
extends: [.on_dane, .report_job_failure]
|
||||
stage: jobs-stage-3
|
||||
@@ -0,0 +1,87 @@
|
||||
# Copyright (c) 2010-2025, 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.
|
||||
|
||||
# Override reproducer section to define MFEM specific variables.
|
||||
.dane_reproducer_vars:
|
||||
script:
|
||||
- !reference [.reproducer_vars, script]
|
||||
|
||||
# TODO: Setup script should be defined as a bash script (but then GIT_STRATEGY
|
||||
# cannot be "none" anymore).
|
||||
|
||||
# Setup clones the mfem/data repo in ${SHARED_REPOS_DIR}. The build_and_test
|
||||
# script then symlinks the repo to the parent directory of the MFEM source
|
||||
# directory. Unit tests that depend on the mfem/data repo will then detect that
|
||||
# this directory is present and be enabled.
|
||||
setup:
|
||||
extends: .on_dane
|
||||
stage: jobs-stage-1
|
||||
script:
|
||||
- ./tests/gitlab/build_and_test_setup
|
||||
|
||||
|
||||
########################
|
||||
# Overridden shared jobs
|
||||
########################
|
||||
# When using shared jobs, we can duplicate them here to override description and
|
||||
# add necessary changes.
|
||||
# We keep ${PROJECT_<MACHINE>_VARIANTS} and ${PROJECT_<MACHINE>_DEPS} So that
|
||||
# the comparison with the original job is easier.
|
||||
|
||||
|
||||
############
|
||||
# Extra jobs
|
||||
############
|
||||
# We do not recommend using ${PROJECT_<MACHINE>_VARIANTS} and
|
||||
# ${PROJECT_<MACHINE>_DEPS} in the extra jobs. There is not reason not to fully
|
||||
# describe the spec here.
|
||||
|
||||
.mfem_job_on_dane:
|
||||
extends: .job_on_dane
|
||||
stage: jobs-stage-2
|
||||
variables:
|
||||
# Dane has 224 threads/node and we run 7 separate jobs: 224=7*32
|
||||
THREADS: 28
|
||||
|
||||
debug_ser_gcc_10:
|
||||
extends: .mfem_job_on_dane
|
||||
variables:
|
||||
SPEC: "%gcc@10.3.1 +debug~mpi"
|
||||
|
||||
debug_par_gcc_10:
|
||||
extends: .mfem_job_on_dane
|
||||
variables:
|
||||
SPEC: "%gcc@10.3.1 +debug+mpi"
|
||||
|
||||
opt_ser_gcc_10:
|
||||
extends: .mfem_job_on_dane
|
||||
variables:
|
||||
SPEC: "%gcc@10.3.1 ~mpi"
|
||||
|
||||
opt_par_gcc_10:
|
||||
extends: .mfem_job_on_dane
|
||||
variables:
|
||||
SPEC: "%gcc@10.3.1"
|
||||
|
||||
opt_par_gcc_10_sundials:
|
||||
extends: .mfem_job_on_dane
|
||||
variables:
|
||||
SPEC: "%gcc@10.3.1 +sundials"
|
||||
|
||||
opt_par_gcc_10_petsc:
|
||||
extends: .mfem_job_on_dane
|
||||
variables:
|
||||
SPEC: "%gcc@10.3.1 +petsc ^petsc+mumps~superlu-dist"
|
||||
|
||||
opt_par_gcc_10_pumi:
|
||||
extends: .mfem_job_on_dane
|
||||
variables:
|
||||
SPEC: "%gcc@10.3.1 +pumi"
|
||||
@@ -0,0 +1,19 @@
|
||||
# Copyright (c) 2010-2025, 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.
|
||||
|
||||
# Jobs report
|
||||
report_job_success:
|
||||
extends: [.on_matrix, .report_job_success]
|
||||
stage: jobs-stage-3
|
||||
|
||||
report_job_failure:
|
||||
extends: [.on_matrix, .report_job_failure]
|
||||
stage: jobs-stage-3
|
||||
@@ -0,0 +1,65 @@
|
||||
# Copyright (c) 2010-2025, 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.
|
||||
|
||||
# Override reproducer section to define UMPIRE specific variables.
|
||||
.matrix_reproducer_vars:
|
||||
script:
|
||||
- !reference [.reproducer_vars, script]
|
||||
|
||||
#TODO: Setup script should be defined as a bash script (but then GIT_STRATEGY cannot be "none" anymore).
|
||||
|
||||
# Setup clones the mfem/data repo in ${SHARED_REPOS_DIR}. The build_and_test
|
||||
# script then symlinks the repo to the parent directory of the MFEM source
|
||||
# directory. Unit tests that depend on the mfem/data repo will then detect that
|
||||
# this directory is present and be enabled.
|
||||
setup:
|
||||
extends: .on_matrix
|
||||
stage: jobs-stage-1
|
||||
script:
|
||||
- ./tests/gitlab/build_and_test_setup
|
||||
|
||||
|
||||
########################
|
||||
# Overridden shared jobs
|
||||
########################
|
||||
# When using shared jobs , we can duplicate them here to override description and add necessary changes.
|
||||
# We keep ${PROJECT_<MACHINE>_VARIANTS} and ${PROJECT_<MACHINE>_DEPS} So that
|
||||
# the comparison with the original job is easier.
|
||||
|
||||
|
||||
############
|
||||
# Extra jobs
|
||||
############
|
||||
# We do not recommend using ${PROJECT_<MACHINE>_VARIANTS} and
|
||||
# ${PROJECT_<MACHINE>_DEPS} in the extra jobs. There is not reason not to fully
|
||||
# describe the spec here.
|
||||
|
||||
.mfem_job_on_matrix:
|
||||
extends: .job_on_matrix
|
||||
stage: jobs-stage-2
|
||||
variables:
|
||||
# We run 2 jobs on 1 node that has 112 threads
|
||||
THREADS: 48
|
||||
# These modules need to be consistent with the uberenv configurations:
|
||||
MODULE_LIST: "gcc/10.3.1-magic cuda/12.9.1"
|
||||
|
||||
allocate_resources:
|
||||
timeout: 4h
|
||||
|
||||
opt_mpi_cuda_gcc:
|
||||
extends: .mfem_job_on_matrix
|
||||
variables:
|
||||
SPEC: "%gcc@10.3.1 +mpi +cuda cuda_arch=90"
|
||||
|
||||
opt_mpi_cuda_hypre_cuda_gcc:
|
||||
extends: .mfem_job_on_matrix
|
||||
variables:
|
||||
SPEC: "%gcc@10.3.1 +mpi +cuda cuda_arch=90 ^hypre+cuda"
|
||||
@@ -0,0 +1,20 @@
|
||||
# Copyright (c) 2010-2025, 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.
|
||||
|
||||
# Jobs report
|
||||
report_job_success:
|
||||
extends: [.on_tioga, .report_job_success]
|
||||
stage: jobs-stage-3
|
||||
|
||||
report_job_failure:
|
||||
extends: [.on_tioga, .report_job_failure]
|
||||
stage: jobs-stage-3
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
# Copyright (c) 2010-2025, 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.
|
||||
|
||||
# Override reproducer section to define UMPIRE specific variables.
|
||||
.tioga_reproducer_vars:
|
||||
script:
|
||||
- !reference [.reproducer_vars, script]
|
||||
|
||||
#TODO: Setup script should be defined as a bash script (but then GIT_STRATEGY cannot be "none" anymore).
|
||||
|
||||
# Setup clones the mfem/data repo in ${SHARED_REPOS_DIR}. The build_and_test
|
||||
# script then symlinks the repo to the parent directory of the MFEM source
|
||||
# directory. Unit tests that depend on the mfem/data repo will then detect that
|
||||
# this directory is present and be enabled.
|
||||
setup:
|
||||
extends: .on_tioga
|
||||
stage: jobs-stage-1
|
||||
script:
|
||||
- ./tests/gitlab/build_and_test_setup
|
||||
|
||||
########################
|
||||
# Overridden shared jobs
|
||||
########################
|
||||
# When using shared jobs , we can duplicate them here to override description and add necessary changes.
|
||||
# We keep ${PROJECT_<MACHINE>_VARIANTS} and ${PROJECT_<MACHINE>_DEPS} So that
|
||||
# the comparison with the original job is easier.
|
||||
|
||||
|
||||
############
|
||||
# Extra jobs
|
||||
############
|
||||
# We do not recommend using ${PROJECT_<MACHINE>_VARIANTS} and
|
||||
# ${PROJECT_<MACHINE>_DEPS} in the extra jobs. There is not reason not to fully
|
||||
# describe the spec here.
|
||||
|
||||
# Build and test jobs, simply provide a spec
|
||||
|
||||
#.tioga_job_command:
|
||||
# script:
|
||||
# - echo PROXY="${PROXY}"
|
||||
# - echo TIOGA_JOB_ALLOC="${TIOGA_JOB_ALLOC}"
|
||||
# - "printf '#!/bin/bash\n%s\n' \"${JOB_CMD}\" > flux_script.sh"
|
||||
# - cat flux_script.sh
|
||||
# - ${PROXY} flux watch $( ${PROXY} flux batch -o output.stdout.type=kvs ${TIOGA_JOB_ALLOC} flux_script.sh )
|
||||
# - rm -f flux_script.sh
|
||||
|
||||
.mfem_job_on_tioga:
|
||||
extends: .job_on_tioga
|
||||
stage: jobs-stage-2
|
||||
variables:
|
||||
# We run 1 job on 1 node that has 64 threads
|
||||
THREADS: 64
|
||||
|
||||
opt_mpi_rocm_hypre_rocm:
|
||||
extends: .mfem_job_on_tioga
|
||||
variables:
|
||||
SPEC: "%rocmcc@=6.3.1 +rocm amdgpu_target=gfx90a ^hypre+rocm"
|
||||
|
||||
# cce_16_0_1:
|
||||
# extends: .mfem_job_on_tioga
|
||||
# variables:
|
||||
# SPEC: "%cce@=16.0.1"
|
||||
@@ -1,44 +0,0 @@
|
||||
# Copyright (c) 2010-2025, 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.
|
||||
|
||||
stages:
|
||||
- setup
|
||||
- build_and_test
|
||||
- report
|
||||
|
||||
opt_mpi_cuda_gcc:
|
||||
variables:
|
||||
SPEC: "%gcc@8.3.1 +mpi +cuda cuda_arch=70"
|
||||
extends: .build_and_test_on_lassen
|
||||
|
||||
opt_mpi_cuda_hypre_cuda_gcc:
|
||||
variables:
|
||||
SPEC: "%gcc@8.3.1 +mpi +cuda cuda_arch=70 ^hypre+cuda~shared cuda_arch=70"
|
||||
extends: .build_and_test_on_lassen
|
||||
|
||||
# Jobs report
|
||||
report_job_success:
|
||||
stage: report
|
||||
extends:
|
||||
- .on_lassen
|
||||
- .report_job_success
|
||||
|
||||
report_job_failure:
|
||||
stage: report
|
||||
extends:
|
||||
- .on_lassen
|
||||
- .report_job_failure
|
||||
|
||||
include:
|
||||
- local: .gitlab/configs/common.yml
|
||||
- local: .gitlab/configs/lassen-config.yml
|
||||
- local: .gitlab/configs/setup-build-and-test.yml
|
||||
- local: .gitlab/configs/report-build-and-test.yml
|
||||
@@ -1,94 +0,0 @@
|
||||
# Copyright (c) 2010-2025, 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.
|
||||
|
||||
stages:
|
||||
- setup
|
||||
- allocate_resource
|
||||
- build_and_test
|
||||
- release_resource_and_report
|
||||
|
||||
# Allocate
|
||||
allocate_resource:
|
||||
variables:
|
||||
GIT_STRATEGY: none
|
||||
extends: .on_ruby
|
||||
stage: allocate_resource
|
||||
script:
|
||||
- echo ${ALLOC_NAME}
|
||||
- salloc --exclusive --nodes=1 --reservation=ci --time=60 --no-shell --job-name=${ALLOC_NAME}
|
||||
timeout: 6h
|
||||
|
||||
# GitLab jobs for the Ruby machine at LLNL
|
||||
debug_ser_gcc_10:
|
||||
variables:
|
||||
SPEC: "%gcc@10.3.1 +debug~mpi"
|
||||
extends: .build_and_test_on_ruby
|
||||
|
||||
debug_par_gcc_10:
|
||||
variables:
|
||||
SPEC: "%gcc@10.3.1 +debug+mpi"
|
||||
extends: .build_and_test_on_ruby
|
||||
|
||||
opt_ser_gcc_10:
|
||||
variables:
|
||||
SPEC: "%gcc@10.3.1 ~mpi"
|
||||
extends: .build_and_test_on_ruby
|
||||
|
||||
opt_par_gcc_10:
|
||||
variables:
|
||||
SPEC: "%gcc@10.3.1"
|
||||
extends: .build_and_test_on_ruby
|
||||
|
||||
opt_par_gcc_10_sundials:
|
||||
variables:
|
||||
SPEC: "%gcc@10.3.1 +sundials"
|
||||
extends: .build_and_test_on_ruby
|
||||
|
||||
opt_par_gcc_10_petsc:
|
||||
variables:
|
||||
SPEC: "%gcc@10.3.1 +petsc ^petsc+mumps~superlu-dist"
|
||||
extends: .build_and_test_on_ruby
|
||||
|
||||
opt_par_gcc_10_pumi:
|
||||
variables:
|
||||
SPEC: "%gcc@10.3.1 +pumi"
|
||||
extends: .build_and_test_on_ruby
|
||||
|
||||
# Release
|
||||
release_resource:
|
||||
variables:
|
||||
GIT_STRATEGY: none
|
||||
extends: .on_ruby
|
||||
stage: release_resource_and_report
|
||||
script:
|
||||
- echo ${ALLOC_NAME}
|
||||
- export JOBID=$(squeue -h --name=${ALLOC_NAME} --format=%A)
|
||||
- echo ${JOBID}
|
||||
- ([[ -n "${JOBID}" ]] && scancel ${JOBID})
|
||||
|
||||
# Jobs report
|
||||
report_job_success:
|
||||
stage: release_resource_and_report
|
||||
extends:
|
||||
- .on_ruby
|
||||
- .report_job_success
|
||||
|
||||
report_job_failure:
|
||||
stage: release_resource_and_report
|
||||
extends:
|
||||
- .on_ruby
|
||||
- .report_job_failure
|
||||
|
||||
include:
|
||||
- local: .gitlab/configs/common.yml
|
||||
- local: .gitlab/configs/ruby-config.yml
|
||||
- local: .gitlab/configs/setup-build-and-test.yml
|
||||
- local: .gitlab/configs/report-build-and-test.yml
|
||||
@@ -14,7 +14,7 @@
|
||||
# locals
|
||||
glob_err=${BASELINE_TEST}.err
|
||||
base=${BASELINE_TEST}-${SYS_TYPE}
|
||||
if [[ "${MACHINE_NAME}" == "ruby" ]]; then
|
||||
if [[ "${MACHINE_NAME}" == "dane" ]]; then
|
||||
base="${BASELINE_TEST}-${MACHINE_NAME}"
|
||||
fi
|
||||
base_diff=${base}.diff
|
||||
@@ -31,12 +31,10 @@ cd tests
|
||||
mkdir _${BASELINE_TEST} && cd _${BASELINE_TEST}
|
||||
|
||||
# run
|
||||
if [[ "${MACHINE_NAME}" == "ruby" ]]; then
|
||||
if [[ "${MACHINE_NAME}" == "dane" ]]; then
|
||||
salloc --nodes=1 --exclusive --reservation=ci ../runtest ../../mfem "${BASELINE_TEST} ${TPLS_DIR}"
|
||||
elif [[ ${MACHINE_NAME} == "corona" ]]; then
|
||||
salloc --nodes=1 -t 60 -p pbatch ../runtest ../../mfem "${BASELINE_TEST} ${TPLS_DIR}"
|
||||
elif [[ ${MACHINE_NAME} == "lassen" ]]; then
|
||||
lalloc 1 -q pci ../runtest ../../mfem "${BASELINE_TEST} ${TPLS_DIR}"
|
||||
else
|
||||
echo "Unknown machine: MACHINE_NAME=$MACHINE_NAME"
|
||||
exit 1
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
# terms of the BSD-3 license. We welcome feedback and contributions, see file
|
||||
# CONTRIBUTING.md for details.
|
||||
|
||||
# There will be collision between corona and ruby baselines.
|
||||
# There will be collision between corona and dane baselines.
|
||||
# Once the corresponding files have been generated, we can switch to machine
|
||||
# specific ref.
|
||||
ARTIFACT_PATH=${CI_PROJECT_DIR}/${ARTIFACTS_DIR}/baseline-${SYS_TYPE}
|
||||
@@ -21,7 +21,7 @@ PATCH_FILE=${ARTIFACT_PATH}.patch
|
||||
FULL_FILE=${ARTIFACT_PATH}.out
|
||||
DIFF_FILE=${ARTIFACT_PATH}.diff
|
||||
|
||||
# There will be collision between corona and ruby baselines.
|
||||
# There will be collision between corona and dane baselines.
|
||||
# Once the corresponding files have been generated, we can switch to machine
|
||||
# specific ref.
|
||||
SAVED_NAME=baseline-${SYS_TYPE}.saved
|
||||
|
||||
Executable
+118
@@ -0,0 +1,118 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Copyright (c) 2010-2025, 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.
|
||||
|
||||
function info_msg ()
|
||||
{
|
||||
echo "[Information:] ${1}"
|
||||
}
|
||||
|
||||
function error_msg ()
|
||||
{
|
||||
echo "[Error:] ${1}"
|
||||
}
|
||||
|
||||
# Perform a report while holding a lock file to prevent concurrency on
|
||||
# the destination.
|
||||
# Usage:
|
||||
# locked_clone <report_function> <lock_name>
|
||||
function locked_report ()
|
||||
{
|
||||
if ! command -v flock
|
||||
then
|
||||
error_msg "Required command 'flock' not found"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
info_msg "Will report ${1} while holding a lock in ${2}"
|
||||
|
||||
( date; info_msg "Waiting to acquire lock on '${PWD}/${2}.lock' ..."
|
||||
# try to get an exclusive lock on fd 9 (mfem-data.lock) repeating the
|
||||
# try every 5 seconds; we may want to add a counter for the number of
|
||||
# retries to interrupt a potential infinite loop
|
||||
while ! flock -n 9; do sleep 5; done
|
||||
date; info_msg "Acquired lock on '${PWD}/${2}.lock'"
|
||||
|
||||
report ${1}
|
||||
err=$?
|
||||
|
||||
# sleep for a period to allow NFS to propagate the above changes;
|
||||
# clearly, there is no guarantee that other NFS clients will see the
|
||||
# changes even after the timeout
|
||||
sleep 10
|
||||
exit $err
|
||||
) 9> ${2}.lock
|
||||
}
|
||||
|
||||
function report ()
|
||||
{
|
||||
if [[ "${1}" == "SUCCESS" ]]
|
||||
then
|
||||
info_msg "All the ${MACHINE_NAME} jobs passed"
|
||||
status_msg="The 'build-and-test' jobs on ${MACHINE_NAME} were SUCCESSFUL."
|
||||
elif [[ "${1}" == "FAILURE" ]]
|
||||
then
|
||||
info_msg "At least one failure on ${MACHINE_NAME}"
|
||||
status_msg="Some 'build-and-test' jobs on ${MACHINE_NAME} FAILED."
|
||||
else
|
||||
error_msg "Unknown status: ${1} ... aborting"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cd ${AUTOTEST_ROOT}/autotest || \
|
||||
{ error_msg "Invalid 'autotest' dir: ${AUTOTEST_ROOT}/autotest"; exit 1; }
|
||||
mkdir -p ${MACHINE_NAME}
|
||||
|
||||
rundir="${MACHINE_NAME}/$(date +%Y-%m-%d)-gitlab-ci-${CI_COMMIT_REF_SLUG}"
|
||||
rundir=$(${CI_PROJECT_DIR}/.gitlab/scripts/safe_create_rundir $rundir)
|
||||
|
||||
printf "%s\n" "${status_msg}" \
|
||||
"Pipeline URL:" "$CI_PIPELINE_URL" > ${rundir}/gitlab.err
|
||||
|
||||
msg="GitLab CI log for build-and-test on ${MACHINE_NAME} ($(date +%Y-%m-%d))"
|
||||
|
||||
if [[ "${1}" == "FAILURE" ]]
|
||||
then
|
||||
# Create 'autotest-email.html' to indicate failure:
|
||||
cp ${rundir}/gitlab.err ${rundir}/autotest-email.html
|
||||
fi
|
||||
|
||||
# Note: in some cases, the content of AUTOTEST_COMMIT can be
|
||||
# '${AUTOTEST_COMMIT}', so we need to treat that value as the default
|
||||
# value of 'ON'.
|
||||
if [[ "$AUTOTEST_COMMIT" == '${AUTOTEST_COMMIT}' ]]; then
|
||||
AUTOTEST_COMMIT="ON"
|
||||
fi
|
||||
if [[ "$AUTOTEST_COMMIT" == "ON" || "$AUTOTEST_COMMIT" == "YES" ]]; then
|
||||
git pull && \
|
||||
git add ${rundir} && \
|
||||
git commit -m "${msg}" && \
|
||||
${CI_PROJECT_DIR}/.gitlab/scripts/git_try_to_push
|
||||
else
|
||||
for file in ${rundir}/*; do
|
||||
echo "------------------------------"
|
||||
echo "Content of '$file'"
|
||||
echo "******************************"
|
||||
cat $file
|
||||
echo "******************************"
|
||||
done
|
||||
rm -rf ${rundir} || true
|
||||
fi
|
||||
}
|
||||
|
||||
export MACHINE_NAME=${CI_MACHINE}
|
||||
info_msg "MACHINE_NAME is ${MACHINE_NAME}"
|
||||
info_msg "AUTOTEST_ROOT is ${AUTOTEST_ROOT}"
|
||||
info_msg "AUTOTEST=$AUTOTEST"
|
||||
info_msg "AUTOTEST_COMMIT=$AUTOTEST_COMMIT"
|
||||
|
||||
cd ${AUTOTEST_ROOT} && locked_report ${1} autotest
|
||||
@@ -1,45 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Copyright (c) 2010-2025, 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.
|
||||
|
||||
echo "Runs if there was at least one failure on ${MACHINE_NAME}"
|
||||
|
||||
cd ${AUTOTEST_ROOT}/autotest || \
|
||||
{ echo "Invalid 'autotest' dir: ${AUTOTEST_ROOT}/autotest"; exit 1; }
|
||||
mkdir -p ${MACHINE_NAME}
|
||||
|
||||
rundir="${MACHINE_NAME}/$(date +%Y-%m-%d)-gitlab-ci-${CI_COMMIT_REF_SLUG}"
|
||||
rundir=$(${CI_PROJECT_DIR}/.gitlab/scripts/safe_create_rundir $rundir)
|
||||
|
||||
printf "%s\n" "Some 'build-and-test' jobs on ${MACHINE_NAME} FAILED." \
|
||||
"Pipeline URL:" "$CI_PIPELINE_URL" > ${rundir}/gitlab.err
|
||||
|
||||
msg="GitLab CI log for build-and-test on ${MACHINE_NAME} ($(date +%Y-%m-%d))"
|
||||
|
||||
# Create 'autotest-email.html' to indicate failure:
|
||||
cp ${rundir}/gitlab.err ${rundir}/autotest-email.html
|
||||
|
||||
if [[ "$AUTOTEST_COMMIT" != "NO" ]]; then
|
||||
git pull && \
|
||||
git add ${rundir} && \
|
||||
git commit -m "${msg}" && \
|
||||
${CI_PROJECT_DIR}/.gitlab/scripts/git_try_to_push
|
||||
else
|
||||
for file in ${rundir}/*; do
|
||||
echo "------------------------------"
|
||||
echo "Content of '$file'"
|
||||
echo "******************************"
|
||||
cat $file
|
||||
echo "******************************"
|
||||
done
|
||||
rm -rf ${rundir} || true
|
||||
fi
|
||||
@@ -1,42 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Copyright (c) 2010-2025, 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.
|
||||
|
||||
echo "Can only run if all the ${MACHINE_NAME} jobs passed"
|
||||
|
||||
cd ${AUTOTEST_ROOT}/autotest || \
|
||||
{ echo "Invalid 'autotest' dir: ${AUTOTEST_ROOT}/autotest"; exit 1; }
|
||||
mkdir -p ${MACHINE_NAME}
|
||||
|
||||
rundir="${MACHINE_NAME}/$(date +%Y-%m-%d)-gitlab-ci-${CI_COMMIT_REF_SLUG}"
|
||||
rundir=$(${CI_PROJECT_DIR}/.gitlab/scripts/safe_create_rundir $rundir)
|
||||
|
||||
printf "%s\n" "The 'build-and-test' jobs on ${MACHINE_NAME} were SUCCESSFUL." \
|
||||
"Pipeline URL:" "$CI_PIPELINE_URL" > ${rundir}/gitlab.out
|
||||
|
||||
msg="GitLab CI log for build-and-test on ${MACHINE_NAME} ($(date +%Y-%m-%d))"
|
||||
|
||||
if [[ "$AUTOTEST_COMMIT" != "NO" ]]; then
|
||||
git pull && \
|
||||
git add ${rundir} && \
|
||||
git commit -m "${msg}" && \
|
||||
${CI_PROJECT_DIR}/.gitlab/scripts/git_try_to_push
|
||||
else
|
||||
for file in ${rundir}/*; do
|
||||
echo "------------------------------"
|
||||
echo "Content of '$file'"
|
||||
echo "******************************"
|
||||
cat $file
|
||||
echo "******************************"
|
||||
done
|
||||
rm -rf ${rundir} || true
|
||||
fi
|
||||
@@ -0,0 +1,130 @@
|
||||
# Copyright (c) 2010-2025, 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.
|
||||
|
||||
# The template job to test whether a machine is up.
|
||||
# Expects CI_MACHINE defined to machine name.
|
||||
.machine-check:
|
||||
stage: prerequisites
|
||||
tags: [shell, oslic]
|
||||
variables:
|
||||
GIT_STRATEGY: none
|
||||
script:
|
||||
- |
|
||||
if [[ $(jq '.[env.CI_MACHINE].total_nodes_up' /usr/global/tools/lorenz/data/loginnodeStatus) == 0 ]]
|
||||
then
|
||||
echo -e "\e[31mNo node available on ${CI_MACHINE}\e[0m"
|
||||
false && \
|
||||
curl --url "https://api.github.com/repos/${GITHUB_PROJECT_ORG}/${GITHUB_PROJECT_NAME}/statuses/${CI_COMMIT_SHA}" \
|
||||
--header 'Content-Type: application/json' \
|
||||
--header "authorization: Bearer ${GITHUB_TOKEN}" \
|
||||
--data "{ \"state\": \"failure\", \"target_url\": \"${CI_PIPELINE_URL}\", \"description\": \"GitLab ${CI_MACHINE} down\", \"context\": \"ci/gitlab/${CI_MACHINE}\" }"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
###
|
||||
# Trigger a build-and-test pipeline for a machine.
|
||||
# Comment the jobs for machines you don’t need.
|
||||
###
|
||||
|
||||
# One job to generate the job list for all the subpipelines
|
||||
generate-job-lists:
|
||||
stage: prerequisites
|
||||
tags: [shell, oslic]
|
||||
variables:
|
||||
LOCAL_JOBS_PATH: ".gitlab/jobs"
|
||||
script:
|
||||
- |
|
||||
echo "AUTOTEST=$AUTOTEST"
|
||||
echo "AUTOTEST_COMMIT=$AUTOTEST_COMMIT"
|
||||
echo "AUTOTEST_ROOT=$AUTOTEST_ROOT"
|
||||
- |
|
||||
cat ${LOCAL_JOBS_PATH}/dane.yml > dane-jobs.yml
|
||||
if [[ ${AUTOTEST} == "ON" || ${AUTOTEST} == "YES" ]]
|
||||
then
|
||||
cat ${LOCAL_JOBS_PATH}/dane-reports.yml >> dane-jobs.yml
|
||||
fi
|
||||
- |
|
||||
cat ${LOCAL_JOBS_PATH}/matrix.yml > matrix-jobs.yml
|
||||
if [[ ${AUTOTEST} == "ON" || ${AUTOTEST} == "YES" ]]
|
||||
then
|
||||
cat ${LOCAL_JOBS_PATH}/matrix-reports.yml >> matrix-jobs.yml
|
||||
fi
|
||||
- |
|
||||
cat ${LOCAL_JOBS_PATH}/tioga.yml > tioga-jobs.yml
|
||||
if [[ ${AUTOTEST} == "ON" || ${AUTOTEST} == "YES" ]]
|
||||
then
|
||||
cat ${LOCAL_JOBS_PATH}/tioga-reports.yml >> tioga-jobs.yml
|
||||
fi
|
||||
artifacts:
|
||||
paths:
|
||||
- dane-jobs.yml
|
||||
- matrix-jobs.yml
|
||||
- tioga-jobs.yml
|
||||
|
||||
|
||||
# DANE
|
||||
dane-up-check:
|
||||
variables:
|
||||
CI_MACHINE: "dane"
|
||||
extends: [.machine-check]
|
||||
|
||||
dane-build-and-test:
|
||||
variables:
|
||||
CI_MACHINE: "dane"
|
||||
needs: [dane-up-check, generate-job-lists]
|
||||
extends: [.build-and-test]
|
||||
|
||||
# DANE, MFEM Specific
|
||||
dane-baseline:
|
||||
stage: test-pipelines
|
||||
variables:
|
||||
# Explicitly pass down values that are not always propagated to child
|
||||
# pipelines, e.g. when a variable is set in the "Settings -> CI" web
|
||||
# interface (project variables).
|
||||
# Note: in some cases, this does not work as expected, e.g. when the
|
||||
# variable is not re-defined in the web interface; in such cases, the child
|
||||
# pipeline gets a definition like '${AUTOTEST}', i.e. it behaves as if
|
||||
# AUTOTEST is undefined, even though there is a default value in
|
||||
# .gitlab-ci.yml.
|
||||
AUTOTEST: "${AUTOTEST}"
|
||||
AUTOTEST_COMMIT: "${AUTOTEST_COMMIT}"
|
||||
trigger:
|
||||
include: .gitlab/dane-baseline.yml
|
||||
strategy: depend
|
||||
forward:
|
||||
pipeline_variables: true
|
||||
needs: [dane-up-check]
|
||||
|
||||
|
||||
# TIOGA
|
||||
tioga-up-check:
|
||||
variables:
|
||||
CI_MACHINE: "tioga"
|
||||
extends: [.machine-check]
|
||||
|
||||
tioga-build-and-test:
|
||||
variables:
|
||||
CI_MACHINE: "tioga"
|
||||
needs: [tioga-up-check, generate-job-lists]
|
||||
extends: [.build-and-test]
|
||||
|
||||
|
||||
# Matrix
|
||||
matrix-up-check:
|
||||
variables:
|
||||
CI_MACHINE: "matrix"
|
||||
extends: [.machine-check]
|
||||
|
||||
matrix-build-and-test:
|
||||
variables:
|
||||
CI_MACHINE: "matrix"
|
||||
needs: [matrix-up-check, generate-job-lists]
|
||||
extends: [.build-and-test]
|
||||
@@ -27,9 +27,27 @@ Discretization improvements
|
||||
- In the ParMoonolith integration, added support for variational resampling of
|
||||
H1 vector fields.
|
||||
|
||||
- Added support for boundary integration to the hyperbolic framework. In this
|
||||
regard, new classes `BdrHyperbolicDirichletIntegrator` and
|
||||
`BoundaryHyperbolicFlowIntegrator` have been introduced for implementation
|
||||
of weak Dirichlet boundary conditions with a general flux or for the linear
|
||||
case respectively.
|
||||
|
||||
- Added method to compute piecewise linear bounds on high-order functions on
|
||||
tensor-product elements.
|
||||
|
||||
- Parallel anisotropic refinement of hexahedral meshes is now supported,
|
||||
provided that neighboring hexahedra are not refined in conflicting directions.
|
||||
A new ParMesh method is added to check for such conflicts, before refinement.
|
||||
|
||||
Meshing improvements
|
||||
--------------------
|
||||
|
||||
- Introduced NC-patch NURBS meshes, which are conforming element-wise but allow
|
||||
for nonconforming patch topology. This new mesh format supports element
|
||||
spacing formulas for refinement, as well as local refinement factors for a
|
||||
subset of knot vectors.
|
||||
|
||||
- Added support for higher order meshes in Mesh::MakeSimplicial and
|
||||
ParMesh::MakeSimplicial.
|
||||
|
||||
@@ -44,9 +62,20 @@ GPU computing
|
||||
set. This is most often used for setting constant essential boundary
|
||||
conditions. A new function Vector::SetSubVectorHost has been added in cases
|
||||
where host execution is always needed (e.g. when the DOFs array is small).
|
||||
|
||||
- Introduced MFEM_FOREACH_THREAD_DIRECT, which directly maps loop tasks to GPU
|
||||
threads, assigning one task per thread.
|
||||
|
||||
- Implemented a GPU-accelerated matrix-free AMR derefinement `GridFunction`
|
||||
update operator. This supports mixed geometry meshes and variable order
|
||||
spaces, and is the default derefinement operator constructed by
|
||||
`FiniteElementSpace::Update` and `ParFiniteElementSpace::Update`.
|
||||
The operator requires `FiniteElementSpace::Nonconforming() == true`.
|
||||
- Added new method: GridFunction::GetGradients, with GPU support, for computing
|
||||
the gradients of a GridFunction on all elements.
|
||||
- Added GPU support in GradientGridFunctionCoefficient and
|
||||
InnerProductCoefficient by implementing their Project methods.
|
||||
|
||||
New and updated examples and miniapps
|
||||
-------------------------------------
|
||||
- Added miniapps to demonstrate an implementation of the absolute-value
|
||||
@@ -55,10 +84,22 @@ New and updated examples and miniapps
|
||||
operators as smoothers.
|
||||
These miniapps can be found in `miniapps/diag-smoothers`.
|
||||
|
||||
API changes
|
||||
- Added a new miniapp (meshing/mesh-bounding-boxes) that computes the bounding
|
||||
boxes for each element of a given mesh, and the bounds on the determinant of
|
||||
the Jacobian of the transformation.
|
||||
|
||||
- Added a new miniapp (tools/gridfunction-bounds) to compute piecewise linear
|
||||
bounds on a given high-order grid function.
|
||||
|
||||
- Added a new miniapp (electromagnetics/lorentz) which computes the trajectory
|
||||
of a charged particle, subject to Lorentz forces, in electrostatic and/or
|
||||
magnetostatic fields as computed by the volta or tesla miniapps.
|
||||
|
||||
API changes:
|
||||
-----------
|
||||
- mfem::internal::tensor and mfem::internal::dual have been moved to
|
||||
mfem::future::tensor and mfem::future::dual.
|
||||
|
||||
- API addition: in class `Operator`, added virtual functions: `AbsMult`, and
|
||||
`AbsMultTranspose`; in class `Vector`, added `Abs` and `Pow`.
|
||||
|
||||
@@ -66,16 +107,25 @@ Miscellaneous
|
||||
-------------
|
||||
- Added the "gpu", "raja-gpu", and "ceed-gpu" backend aliases/shortcuts which
|
||||
automatically select between CUDA or HIP.
|
||||
|
||||
- The CUDA-specific names used by some of the unit tests like 'cunit_tests' and
|
||||
'pcunit_tests' were replaced by names using 'gpu' instead of 'c' (short for
|
||||
CUDA) or 'cuda'. These tests automatically run the CUDA/HIP tests based on the
|
||||
MFEM build configuration.
|
||||
|
||||
- Added the option to enable GPU-aware MPI in MFEM using the environment
|
||||
variable 'MFEM_GPU_AWARE_MPI' set to any value. Setting this environment
|
||||
variable is an alternative to calling 'Device::SetGPUAwareMPI(true)'.
|
||||
|
||||
- Added parallel Address Sanitizer, serial and parallel Undefined Behavior
|
||||
Sanitizer and serial Memory Sanitizer GitHub actions tests on Ubuntu.
|
||||
|
||||
- FindPointsGSLIB has a new constructor that accepts the mesh object and
|
||||
internally calls the Setup() method so that the user does not have to.
|
||||
The FreeData() method has also been moved to the destructor so the user does
|
||||
not need to manually free-up the memory if the destructor is called before
|
||||
MPI_Finalize().
|
||||
|
||||
Version 4.8, released on Apr 9, 2025
|
||||
====================================
|
||||
|
||||
|
||||
+25
-11
@@ -278,6 +278,11 @@ if (MFEM_USE_OPENMP OR MFEM_USE_LEGACY_OPENMP)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Umpire (must be included before hypre, so hypre can use it if needed)
|
||||
if (MFEM_USE_UMPIRE)
|
||||
find_package(UMPIRE REQUIRED)
|
||||
endif()
|
||||
|
||||
# MPI -> hypre; PETSc (optional)
|
||||
if (MFEM_USE_MPI)
|
||||
find_package(MPI REQUIRED)
|
||||
@@ -495,14 +500,13 @@ endif()
|
||||
|
||||
# RAJA
|
||||
if (MFEM_USE_RAJA)
|
||||
# RAJA uses FindCUDA, which needs CMP0146=OLD in CMake >= 3.27
|
||||
if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.27.0)
|
||||
cmake_policy(SET CMP0146 OLD)
|
||||
endif()
|
||||
find_package(RAJA REQUIRED)
|
||||
endif()
|
||||
|
||||
# UMPIRE
|
||||
if (MFEM_USE_UMPIRE)
|
||||
find_package(UMPIRE REQUIRED)
|
||||
endif()
|
||||
|
||||
# GOOGLE-BENCHMARK
|
||||
if (MFEM_USE_BENCHMARK)
|
||||
find_package(Benchmark REQUIRED)
|
||||
@@ -596,18 +600,25 @@ set(MFEM_TPLS OPENMP HYPRE LAPACK BLAS SuperLUDist STRUMPACK METIS SuiteSparse
|
||||
NETCDF MPFR PUMI HIOP POSIXCLOCKS MFEMBacktrace ZLIB OCCA CEED RAJA UMPIRE
|
||||
ADIOS2 MKL_CPARDISO MKL_PARDISO AMGX MAGMA CUSPARSE CUBLAS CALIPER CODIPACK
|
||||
BENCHMARK PARELAG TRIBOL MPI_CXX HIP HIPBLAS HIPSPARSE MOONOLITH BLITZ
|
||||
ALGOIM ENZYME)
|
||||
ALGOIM ENZYME CUDA::cudart)
|
||||
|
||||
# Add all *_FOUND libraries in the variable TPL_LIBRARIES.
|
||||
# Add all created targets and *_FOUND libraries in the variables TPL_TARGETS and
|
||||
# TPL_LIBRARIES, respectively.
|
||||
set(TPL_TARGETS)
|
||||
set(TPL_LIBRARIES "")
|
||||
set(TPL_INCLUDE_DIRS "")
|
||||
foreach(TPL IN LISTS MFEM_TPLS)
|
||||
if (${TPL}_FOUND)
|
||||
if (${TPL}_FOUND OR TARGET ${TPL})
|
||||
message(STATUS "MFEM: using package ${TPL}")
|
||||
list(APPEND TPL_LIBRARIES ${${TPL}_LIBRARIES})
|
||||
list(APPEND TPL_INCLUDE_DIRS ${${TPL}_INCLUDE_DIRS})
|
||||
if (TARGET ${TPL})
|
||||
list(APPEND TPL_TARGETS ${TPL})
|
||||
else()
|
||||
list(APPEND TPL_LIBRARIES ${${TPL}_LIBRARIES})
|
||||
list(APPEND TPL_INCLUDE_DIRS ${${TPL}_INCLUDE_DIRS})
|
||||
endif()
|
||||
endif()
|
||||
endforeach(TPL)
|
||||
|
||||
list(REVERSE TPL_LIBRARIES)
|
||||
list(REMOVE_DUPLICATES TPL_LIBRARIES)
|
||||
list(REVERSE TPL_LIBRARIES)
|
||||
@@ -680,7 +691,10 @@ set(MFEM_INSTALL_DIR ${CMAKE_INSTALL_PREFIX})
|
||||
# Declaring the library
|
||||
mfem_add_library(mfem ${SOURCES} ${HEADERS} ${MASTER_HEADERS})
|
||||
# message(STATUS "TPL_LIBRARIES = ${TPL_LIBRARIES}")
|
||||
target_link_libraries(mfem PUBLIC ${TPL_LIBRARIES})
|
||||
target_link_libraries(mfem PUBLIC ${TPL_LIBRARIES} ${TPL_TARGETS})
|
||||
if (TPL_TARGETS)
|
||||
add_dependencies(mfem ${TPL_TARGETS})
|
||||
endif()
|
||||
if (MINGW)
|
||||
target_link_libraries(mfem PRIVATE ws2_32)
|
||||
endif()
|
||||
|
||||
@@ -121,6 +121,11 @@ Parallel build:
|
||||
make -j 4
|
||||
(For METIS 5, see https://mfem.org/building/#parallel-build-using-metis-5)
|
||||
|
||||
Parallel build with fetching of hypre and METIS:
|
||||
mkdir <mfem-buil-dir> ; cd <mfem-build-dir>
|
||||
cmake <mfem-source-dir> -DMFEM_USE_MPI=YES -DFETCH_TPLS=YES
|
||||
make -j 4
|
||||
|
||||
CUDA build:
|
||||
(this build requires CMake 3.17 or newer)
|
||||
mkdir <mfem-build-dir> ; cd <mfem-build-dir>
|
||||
@@ -663,6 +668,7 @@ The specific libraries and their options are:
|
||||
- OpenMP (optional), usually part of compiler, used when either MFEM_USE_OPENMP
|
||||
or MFEM_USE_LEGACY_OPENMP is set to YES.
|
||||
Options: OPENMP_OPT, OPENMP_LIB.
|
||||
Versions: OpenMP >= 3.1 when MFEM_USE_OPENMP=YES.
|
||||
|
||||
- High-resolution POSIX clocks: when using MFEM_TIMER_TYPE = 2, it may be
|
||||
necessary to link with a system library (e.g. librt.so).
|
||||
@@ -842,6 +848,7 @@ The specific libraries and their options are:
|
||||
- HIP (optional), used when MFEM_USE_HIP = YES.
|
||||
URL: https://rocmdocs.amd.com
|
||||
Options: HIP_CXX, HIP_ARCH, HIP_OPT, HIP_LIB.
|
||||
Versions: ROCm >= 5.6.1.
|
||||
|
||||
- OCCA (optional), used when MFEM_USE_OCCA = YES.
|
||||
URL: https://libocca.org
|
||||
@@ -852,7 +859,7 @@ The specific libraries and their options are:
|
||||
URL: https://github.com/CEED/libCEED
|
||||
https://ceed.exascaleproject.org/libceed
|
||||
Options: CEED_DIR, CEED_OPT, CEED_LIB.
|
||||
Versions: libCEED >= 0.12.
|
||||
Versions: libCEED >= 0.12.0.
|
||||
|
||||
- RAJA (optional), used when MFEM_USE_RAJA = YES.
|
||||
Beginning with MFEM v4.5.1, only RAJA v2022.10.3+ is supported.
|
||||
@@ -1074,6 +1081,9 @@ The following options are CMake specific:
|
||||
MFEM_ENABLE_TESTING - Enable the ctest framework for testing.
|
||||
MFEM_ENABLE_EXAMPLES - Build all of the examples by default.
|
||||
MFEM_ENABLE_MINIAPPS - Build all of the miniapps by default.
|
||||
FETCH_TPLS - Enable fetching of all supported third-party libraries.
|
||||
HYPRE_FETCH - Enable fetching of hypre.
|
||||
METIS_FETCH - Enable fetching of metis.
|
||||
|
||||
External libraries (CMake):
|
||||
---------------------------
|
||||
@@ -1135,6 +1145,12 @@ The following built-in CMake packages are also used:
|
||||
set the <LIBNAME>_LIBRARIES option directly; the configuration option
|
||||
<LIBNAME>_DIR is not supported.
|
||||
|
||||
The MFEM CMake build system also provides fetching (automated building) for the
|
||||
packages/libraries listed below. Note that when fetching is enabled, any related
|
||||
auto-detection functionality is disabled.
|
||||
|
||||
- HYPRE
|
||||
- METIS
|
||||
|
||||
Building without GNU make or CMake
|
||||
==================================
|
||||
|
||||
@@ -84,6 +84,31 @@ set_and_check(MFEM_LIBRARY_DIR "@PACKAGE_LIB_INSTALL_DIR@")
|
||||
|
||||
check_required_components(MFEM)
|
||||
|
||||
include(CMakeFindDependencyMacro)
|
||||
|
||||
if (MFEM_USE_CUDA)
|
||||
# required for projects linking to MFEM+CUDA, even if they don't use CUDA directly
|
||||
find_dependency(CUDAToolkit)
|
||||
endif (MFEM_USE_CUDA)
|
||||
|
||||
if (MFEM_USE_HIP)
|
||||
# hip/rocm uses the modern MFEM way of linking to targets, need to find dependencies
|
||||
find_dependency(HIP)
|
||||
find_dependency(HIPBLAS)
|
||||
find_dependency(HIPSPARSE)
|
||||
if (MFEM_USE_MPI)
|
||||
# assume HYPRE uses HIP
|
||||
# alternatively could check HYPRE_USING_HIP
|
||||
find_dependency(rocsparse)
|
||||
find_dependency(rocrand)
|
||||
find_dependency(rocsolver)
|
||||
endif (MFEM_USE_MPI)
|
||||
endif (MFEM_USE_HIP)
|
||||
|
||||
if (MFEM_USE_RAJA)
|
||||
find_dependency(RAJA)
|
||||
endif()
|
||||
|
||||
if (NOT TARGET mfem)
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/MFEMTargets.cmake)
|
||||
endif (NOT TARGET mfem)
|
||||
|
||||
@@ -9,21 +9,25 @@
|
||||
# terms of the BSD-3 license. We welcome feedback and contributions, see file
|
||||
# CONTRIBUTING.md for details.
|
||||
|
||||
# Defines the following variables:
|
||||
# Defines the following variables if fetching of TPLs is disabled (default):
|
||||
# - HYPRE_FOUND
|
||||
# - HYPRE_LIBRARIES
|
||||
# - HYPRE_INCLUDE_DIRS
|
||||
# - HYPRE_VERSION
|
||||
# - HYPRE_USING_CUDA (internal)
|
||||
# - HYPRE_USING_HIP (internal)
|
||||
# otherwise, the following are defined:
|
||||
# - HYPRE (imported library target)
|
||||
# - HYPRE_VERSION (cache variable)
|
||||
|
||||
if (HYPRE_FOUND)
|
||||
if (HYPRE_FOUND OR TARGET HYPRE)
|
||||
if (HYPRE_USING_CUDA)
|
||||
find_package(CUDAToolkit REQUIRED)
|
||||
endif()
|
||||
if (HYPRE_USING_HIP)
|
||||
find_package(rocsparse REQUIRED)
|
||||
find_package(rocrand REQUIRED)
|
||||
find_package(rocsolver REQUIRED)
|
||||
endif()
|
||||
if (HYPRE_LIBRARIES AND HYPRE_INCLUDE_DIRS AND HYPRE_VERSION)
|
||||
find_package_handle_standard_args(HYPRE
|
||||
@@ -33,6 +37,95 @@ if (HYPRE_FOUND)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (HYPRE_FETCH OR FETCH_TPLS)
|
||||
# Collect all HYPRE_ENABLE variables and pass them to hypre, assuming they are BOOL.
|
||||
set(HYPRE_CMAKE_OPTIONS "")
|
||||
get_cmake_property(all_vars VARIABLES)
|
||||
foreach(var ${all_vars})
|
||||
if(var MATCHES "^HYPRE_ENABLE")
|
||||
list(APPEND HYPRE_CMAKE_OPTIONS "-D${var}:BOOL=${${var}}")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
set(HYPRE_FETCH_VERSION 2.33.0)
|
||||
set(HYPRE_FETCH_TAG "v${HYPRE_FETCH_VERSION}" CACHE STRING "Tag, branch, or commit for HYPRE")
|
||||
add_library(HYPRE STATIC IMPORTED)
|
||||
# set options and associated dependencies
|
||||
list(APPEND HYPRE_CMAKE_OPTIONS -DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE})
|
||||
if (MFEM_USE_CUDA)
|
||||
list(APPEND HYPRE_CMAKE_OPTIONS -DHYPRE_ENABLE_CUDA:BOOL=ON -DCMAKE_CUDA_ARCHITECTURES:STRING=${CMAKE_CUDA_ARCHITECTURES})
|
||||
find_package(CUDAToolkit REQUIRED)
|
||||
target_link_libraries(HYPRE INTERFACE CUDA::cusparse CUDA::curand CUDA::cublas)
|
||||
elseif (MFEM_USE_HIP)
|
||||
list(APPEND HYPRE_CMAKE_OPTIONS -DHYPRE_ENABLE_HIP:BOOL=ON)
|
||||
find_package(rocsparse REQUIRED)
|
||||
find_package(rocrand REQUIRED)
|
||||
target_link_libraries(HYPRE INTERFACE rocsparse rocrand)
|
||||
endif()
|
||||
if (MFEM_USE_CUDA OR MFEM_USE_HIP)
|
||||
if (MFEM_USE_UMPIRE)
|
||||
if (EXISTS ${umpire_DIR})
|
||||
list(APPEND HYPRE_CMAKE_OPTIONS -DHYPRE_ENABLE_UMPIRE:BOOL=ON -Dumpire_DIR:PATH=${umpire_DIR})
|
||||
else()
|
||||
message(FATAL_ERROR "MFEM_USE_UMPIRE=ON, however umpire_DIR isn't visible to HYPRE")
|
||||
endif()
|
||||
else()
|
||||
list(APPEND HYPRE_CMAKE_OPTIONS -DHYPRE_ENABLE_UMPIRE:BOOL=OFF)
|
||||
message(WARNING
|
||||
"================================================================================
|
||||
Umpire is disabled while building HYPRE with GPU support.
|
||||
This is not recommended for performance reasons!
|
||||
Consider enabling Umpire with -DMFEM_USE_UMPIRE=ON and providing -DUMPIRE_DIR.
|
||||
================================================================================")
|
||||
endif()
|
||||
endif()
|
||||
if (MFEM_USE_SINGLE)
|
||||
list(APPEND HYPRE_CMAKE_OPTIONS -DHYPRE_ENABLE_SINGLE:BOOL=ON)
|
||||
endif()
|
||||
# define external project and create future include directory so it is present
|
||||
# to pass CMake checks at end of MFEM configuration step
|
||||
message(STATUS "Will fetch HYPRE ${HYPRE_FETCH_TAG} to be built with ${HYPRE_CMAKE_OPTIONS}")
|
||||
set(HYPRE_INSTALL ${CMAKE_BINARY_DIR}/fetch/hypre)
|
||||
include(ExternalProject)
|
||||
ExternalProject_Add(hypre
|
||||
GIT_REPOSITORY https://github.com/hypre-space/hypre.git
|
||||
GIT_TAG ${HYPRE_FETCH_TAG}
|
||||
GIT_SHALLOW TRUE
|
||||
GIT_PROGRESS TRUE
|
||||
UPDATE_DISCONNECTED TRUE
|
||||
SOURCE_SUBDIR src
|
||||
PREFIX ${HYPRE_INSTALL}
|
||||
BUILD_COMMAND ${CMAKE_COMMAND} --build . -- -j${CMAKE_BUILD_PARALLEL_LEVEL}
|
||||
CMAKE_CACHE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=${HYPRE_INSTALL} -DCMAKE_INSTALL_LIBDIR:PATH=lib ${HYPRE_CMAKE_OPTIONS})
|
||||
file(MAKE_DIRECTORY ${HYPRE_INSTALL}/include)
|
||||
# set imported library target properties
|
||||
add_dependencies(HYPRE hypre)
|
||||
set_target_properties(HYPRE PROPERTIES
|
||||
IMPORTED_LOCATION ${HYPRE_INSTALL}/lib/libHYPRE.a
|
||||
INTERFACE_INCLUDE_DIRECTORIES ${HYPRE_INSTALL}/include)
|
||||
# convert HYPRE version to integer
|
||||
if (HYPRE_FETCH_TAG MATCHES "^v?([0-9]+)\\.([0-9]+)\\.([0-9]+)$")
|
||||
# Exact release tag X.Y.Z
|
||||
string(REGEX MATCHALL "[0-9]+" HYPRE_SPLIT_VERSION "${HYPRE_FETCH_TAG}")
|
||||
elseif (HYPRE_FETCH_VERSION MATCHES "([0-9]+)\\.([0-9]+)(\\.([0-9]+))?")
|
||||
string(REGEX MATCHALL "[0-9]+" HYPRE_SPLIT_VERSION "${HYPRE_FETCH_VERSION}")
|
||||
else (NOT DEFINED HYPRE_VERSION)
|
||||
message(FATAL_ERROR "Unable to find HYPRE release version. Please provide it via -DHYPRE_VERSION")
|
||||
endif()
|
||||
if (HYPRE_SPLIT_VERSION AND NOT DEFINED HYPRE_VERSION)
|
||||
list(GET HYPRE_SPLIT_VERSION 0 HYPRE_MAJOR_VERSION)
|
||||
list(GET HYPRE_SPLIT_VERSION 1 HYPRE_MINOR_VERSION)
|
||||
if (HYPRE_SPLIT_VERSION GREATER 2)
|
||||
list(GET HYPRE_SPLIT_VERSION 2 HYPRE_PATCH_VERSION)
|
||||
else()
|
||||
set(HYPRE_PATCH_VERSION 0)
|
||||
endif()
|
||||
math(EXPR HYPRE_VERSION "10000*${HYPRE_MAJOR_VERSION} + 100*${HYPRE_MINOR_VERSION} + ${HYPRE_PATCH_VERSION}")
|
||||
set(HYPRE_VERSION ${HYPRE_VERSION} CACHE STRING "HYPRE version." FORCE)
|
||||
endif()
|
||||
return()
|
||||
endif()
|
||||
|
||||
include(MfemCmakeUtilities)
|
||||
mfem_find_package(HYPRE HYPRE HYPRE_DIR "include" "HYPRE.h" "lib" "HYPRE"
|
||||
"Paths to headers required by HYPRE." "Libraries required by HYPRE."
|
||||
@@ -97,7 +190,8 @@ endif()
|
||||
if (HYPRE_FOUND AND HYPRE_USING_HIP)
|
||||
find_package(rocsparse REQUIRED)
|
||||
find_package(rocrand REQUIRED)
|
||||
list(APPEND HYPRE_LIBRARIES ${rocsparse_LIBRARIES} ${rocrand_LIBRARIES})
|
||||
find_package(rocsolver REQUIRED)
|
||||
list(APPEND HYPRE_LIBRARIES ${rocsparse_LIBRARIES} ${rocrand_LIBRARIES} roc::rocsolver roc::rocblas)
|
||||
set(HYPRE_LIBRARIES ${HYPRE_LIBRARIES} CACHE STRING
|
||||
"HYPRE libraries + dependencies." FORCE)
|
||||
message(STATUS "Updated HYPRE_LIBRARIES: ${HYPRE_LIBRARIES}")
|
||||
|
||||
@@ -9,10 +9,39 @@
|
||||
# terms of the BSD-3 license. We welcome feedback and contributions, see file
|
||||
# CONTRIBUTING.md for details.
|
||||
|
||||
# Defines the following variables:
|
||||
# Defines the following variables if fetching of TPLs is disabled (default):
|
||||
# - METIS_FOUND
|
||||
# - METIS_LIBRARIES
|
||||
# - METIS_INCLUDE_DIRS
|
||||
# - METIS_VERSION_5
|
||||
# otherwise, the following are defined:
|
||||
# - METIS (imported library target)
|
||||
# - METIS_VERSION_5 (cache variable)
|
||||
|
||||
if (METIS_FETCH OR FETCH_TPLS)
|
||||
set(METIS_FETCH_VERSION 4.0.3)
|
||||
add_library(METIS STATIC IMPORTED)
|
||||
# define external project
|
||||
message(STATUS "Will fetch METIS ${METIS_FETCH_VERSION} to be built with default options")
|
||||
set(PREFIX ${CMAKE_BINARY_DIR}/fetch/metis)
|
||||
include(ExternalProject)
|
||||
ExternalProject_Add(metis
|
||||
GIT_REPOSITORY https://github.com/mfem/tpls
|
||||
GIT_TAG b60352fbe9675d374b00828055e55be4584c7995 # tag from 1/16/25
|
||||
GIT_SHALLOW TRUE
|
||||
UPDATE_DISCONNECTED TRUE
|
||||
PREFIX ${PREFIX}
|
||||
CONFIGURE_COMMAND tar -xzf ../metis/metis-${METIS_FETCH_VERSION}-mac.tgz --strip=1
|
||||
BUILD_COMMAND $(MAKE) COPTIONS=-Wno-incompatible-pointer-types
|
||||
INSTALL_COMMAND mkdir -p ${PREFIX}/lib && cp libmetis.a ${PREFIX}/lib/)
|
||||
# set imported library target properties
|
||||
add_dependencies(METIS metis)
|
||||
set_target_properties(METIS PROPERTIES
|
||||
IMPORTED_LOCATION ${PREFIX}/lib/libmetis.a)
|
||||
# set cache variables that would otherwise be set after mfem_find_package call
|
||||
set(METIS_VERSION_5 FALSE CACHE BOOL "Is METIS version 5?")
|
||||
return()
|
||||
endif()
|
||||
|
||||
include(MfemCmakeUtilities)
|
||||
mfem_find_package(METIS METIS METIS_DIR "include;Lib" "metis.h"
|
||||
|
||||
@@ -718,7 +718,7 @@ function(mfem_get_target_options Target CompileOptsVar LinkOptsVar)
|
||||
get_target_property(IsImported ${tgt} IMPORTED)
|
||||
# message(STATUS "${tgt}[IMPORTED]: ${IsImported}")
|
||||
# Generally, the possible target types are: STATIC_LIBRARY, MODULE_LIBRARY,
|
||||
# SHARED_LIBRARY, INTERFACE_LIBRARY, EXECUTABLE.
|
||||
# SHARED_LIBRARY, INTERFACE_LIBRARY, UNKNOWN_LIBRARY, EXECUTABLE.
|
||||
get_target_property(type ${tgt} TYPE)
|
||||
# message(STATUS "${tgt}[TYPE]: ${type}")
|
||||
unset(ImportConfig)
|
||||
@@ -766,7 +766,7 @@ function(mfem_get_target_options Target CompileOptsVar LinkOptsVar)
|
||||
else()
|
||||
message(STATUS " *** Warning: [${tgt}] LOCATION not defined!")
|
||||
endif()
|
||||
elseif ("${type}" STREQUAL "SHARED_LIBRARY")
|
||||
elseif ("${type}" STREQUAL "SHARED_LIBRARY" OR "${type}" STREQUAL "UNKNOWN_LIBRARY")
|
||||
get_target_property(Location ${tgt} LOCATION)
|
||||
if (Location)
|
||||
get_filename_component(Dir ${Location} DIRECTORY)
|
||||
@@ -932,12 +932,14 @@ function(mfem_export_mk_files)
|
||||
endif()
|
||||
set(MFEM_BUILD_TAG "${CMAKE_SYSTEM}")
|
||||
set(MFEM_PREFIX "${CMAKE_INSTALL_PREFIX}")
|
||||
# For the next 4 variable, these are the values for the build-tree version of
|
||||
# For the next 4 variables, these are the values for the build-tree version of
|
||||
# 'config.mk'
|
||||
set(MFEM_INC_DIR "${PROJECT_BINARY_DIR}")
|
||||
set(MFEM_LIB_DIR "${PROJECT_BINARY_DIR}")
|
||||
set(MFEM_TEST_MK "${PROJECT_SOURCE_DIR}/config/test.mk")
|
||||
set(MFEM_CONFIG_EXTRA "MFEM_BUILD_DIR ?= ${PROJECT_BINARY_DIR}")
|
||||
# TODO: CUDA/HIP support:
|
||||
set(MFEM_XLINKER "${CMAKE_CXX_LINKER_WRAPPER_FLAG}")
|
||||
set(MFEM_MPIEXEC ${MPIEXEC})
|
||||
if (NOT MFEM_MPIEXEC)
|
||||
set(MFEM_MPIEXEC "mpirun")
|
||||
|
||||
+4
-1
@@ -23,11 +23,14 @@
|
||||
#include "_config.hpp"
|
||||
#endif
|
||||
|
||||
#include <cstdint>
|
||||
#include <climits>
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
#if (defined(MFEM_USE_CUDA) && defined(__CUDACC__)) || \
|
||||
(defined(MFEM_USE_HIP) && defined(__HIPCC__))
|
||||
(defined(MFEM_USE_HIP) && defined(__HIP__))
|
||||
#define MFEM_HOST_DEVICE __host__ __device__
|
||||
#else
|
||||
#define MFEM_HOST_DEVICE
|
||||
|
||||
@@ -88,6 +88,7 @@ MFEM_BUILD_TAG = @MFEM_BUILD_TAG@
|
||||
MFEM_PREFIX = @MFEM_PREFIX@
|
||||
MFEM_INC_DIR = @MFEM_INC_DIR@
|
||||
MFEM_LIB_DIR = @MFEM_LIB_DIR@
|
||||
MFEM_XLINKER = @MFEM_XLINKER@
|
||||
|
||||
# Location of test.mk
|
||||
MFEM_TEST_MK = @MFEM_TEST_MK@
|
||||
|
||||
@@ -89,6 +89,12 @@ option(MFEM_ENABLE_EXAMPLES "Build all of the examples" OFF)
|
||||
option(MFEM_ENABLE_MINIAPPS "Build all of the miniapps" OFF)
|
||||
option(MFEM_ENABLE_BENCHMARKS "Build all of the benchmarks" OFF)
|
||||
|
||||
# Allow a user to specify fetching of certain third-party libraries instead of
|
||||
# searching for existing installations.
|
||||
option(FETCH_TPLS "Enable fetching of all supported third-party libraries" OFF)
|
||||
option(HYPRE_FETCH "Enable fetching of hypre" OFF)
|
||||
option(METIS_FETCH "Enable fetching of METIS" OFF)
|
||||
|
||||
# Setting CXX/MPICXX on the command line or in user.cmake will overwrite the
|
||||
# autodetected C++ compiler.
|
||||
# set(CXX g++)
|
||||
|
||||
+1
-1
@@ -57,7 +57,7 @@ CUDA_DIR = $(or $(CUDA_HOME),$(patsubst %/,%,$(dir \
|
||||
CLANG_CUDA_FLAGS = -xcuda --cuda-path=$(CUDA_DIR) --cuda-gpu-arch=$(CUDA_ARCH)
|
||||
# flags for nvcc
|
||||
NVCC_FLAGS = -x=cu --expt-extended-lambda --expt-relaxed-constexpr \
|
||||
-arch=$(CUDA_ARCH)
|
||||
-arch=$(CUDA_ARCH) -isystem "$(CUDA_DIR)/include"
|
||||
# Prefixes for passing flags to the host compiler and linker when using
|
||||
# CUDA_CXX=nvcc
|
||||
CUDA_XCOMPILER = -Xcompiler=
|
||||
|
||||
+593
@@ -0,0 +1,593 @@
|
||||
MFEM mesh v1.0
|
||||
|
||||
# Created by: Pointwise
|
||||
|
||||
# MFEM Geometry Types:
|
||||
#
|
||||
# POINT = 0
|
||||
# SEGMENT = 1
|
||||
# TRIANGLE = 2
|
||||
# SQUARE = 3
|
||||
# TETRAHEDRON = 4
|
||||
# CUBE = 5
|
||||
# PRISM = 6
|
||||
|
||||
dimension
|
||||
2
|
||||
|
||||
elements
|
||||
160
|
||||
1 3 1 164 163 0
|
||||
1 3 164 165 162 163
|
||||
1 3 2 166 164 1
|
||||
1 3 166 132 165 164
|
||||
1 3 3 167 166 2
|
||||
1 3 167 131 132 166
|
||||
1 3 4 168 167 3
|
||||
1 3 168 130 131 167
|
||||
1 3 5 169 168 4
|
||||
1 3 169 129 130 168
|
||||
1 3 6 170 169 5
|
||||
1 3 170 128 129 169
|
||||
1 3 171 172 170 6
|
||||
1 3 172 127 128 170
|
||||
1 3 124 125 172 171
|
||||
1 3 125 126 127 172
|
||||
1 3 162 165 173 161
|
||||
1 3 165 132 133 173
|
||||
1 3 161 173 174 160
|
||||
1 3 173 133 134 174
|
||||
1 3 160 174 175 159
|
||||
1 3 174 134 135 175
|
||||
1 3 6 7 176 171
|
||||
1 3 7 8 177 176
|
||||
1 3 171 176 123 124
|
||||
1 3 176 177 122 123
|
||||
1 3 159 175 178 158
|
||||
1 3 175 135 136 178
|
||||
1 3 158 178 179 157
|
||||
1 3 178 136 137 179
|
||||
1 3 157 179 180 156
|
||||
1 3 179 137 138 180
|
||||
1 3 122 177 181 121
|
||||
1 3 177 8 182 181
|
||||
1 3 8 9 183 182
|
||||
1 3 9 10 184 183
|
||||
1 3 10 11 185 184
|
||||
1 3 11 12 186 185
|
||||
1 3 12 13 187 186
|
||||
1 3 13 14 15 187
|
||||
1 3 121 181 119 120
|
||||
1 3 181 182 118 119
|
||||
1 3 182 183 117 118
|
||||
1 3 183 184 188 117
|
||||
1 3 184 185 109 188
|
||||
1 3 185 186 108 109
|
||||
1 3 186 187 189 108
|
||||
1 3 187 15 16 189
|
||||
1 3 109 110 190 188
|
||||
1 3 110 111 191 190
|
||||
1 3 111 112 113 191
|
||||
1 3 188 190 116 117
|
||||
1 3 190 191 115 116
|
||||
1 3 191 113 114 115
|
||||
1 3 189 192 107 108
|
||||
1 3 192 193 106 107
|
||||
1 3 193 194 105 106
|
||||
1 3 194 195 104 105
|
||||
1 3 195 196 103 104
|
||||
1 3 16 17 192 189
|
||||
1 3 17 18 193 192
|
||||
1 3 18 19 194 193
|
||||
1 3 19 20 195 194
|
||||
1 3 20 21 196 195
|
||||
1 3 97 98 197 96
|
||||
1 3 98 99 198 197
|
||||
1 3 99 100 199 198
|
||||
1 3 100 101 200 199
|
||||
1 3 101 102 201 200
|
||||
1 3 102 103 202 201
|
||||
1 3 103 196 203 202
|
||||
1 3 196 21 22 203
|
||||
1 3 96 197 204 95
|
||||
1 3 197 198 39 204
|
||||
1 3 198 199 38 39
|
||||
1 3 199 200 205 38
|
||||
1 3 200 201 32 205
|
||||
1 3 201 202 31 32
|
||||
1 3 202 203 206 31
|
||||
1 3 203 22 23 206
|
||||
1 3 32 33 207 205
|
||||
1 3 33 34 35 207
|
||||
1 3 205 207 37 38
|
||||
1 3 207 35 36 37
|
||||
1 3 39 40 208 204
|
||||
1 3 40 41 209 208
|
||||
1 3 41 42 210 209
|
||||
1 3 42 43 211 210
|
||||
1 3 43 44 212 211
|
||||
1 3 204 208 94 95
|
||||
1 3 208 209 93 94
|
||||
1 3 209 210 92 93
|
||||
1 3 210 211 91 92
|
||||
1 3 211 212 90 91
|
||||
1 3 90 212 213 89
|
||||
1 3 212 44 214 213
|
||||
1 3 44 45 215 214
|
||||
1 3 45 46 216 215
|
||||
1 3 46 47 217 216
|
||||
1 3 47 48 218 217
|
||||
1 3 48 49 219 218
|
||||
1 3 49 50 51 219
|
||||
1 3 89 213 87 88
|
||||
1 3 213 214 86 87
|
||||
1 3 214 215 85 86
|
||||
1 3 215 216 84 85
|
||||
1 3 216 217 83 84
|
||||
1 3 217 218 82 83
|
||||
1 3 218 219 220 82
|
||||
1 3 219 51 52 220
|
||||
1 3 53 221 220 52
|
||||
1 3 221 81 82 220
|
||||
1 3 54 222 221 53
|
||||
1 3 222 80 81 221
|
||||
1 3 55 223 222 54
|
||||
1 3 223 79 80 222
|
||||
1 3 26 27 224 25
|
||||
1 3 27 28 29 224
|
||||
1 3 25 224 225 24
|
||||
1 3 224 29 30 225
|
||||
1 3 24 225 206 23
|
||||
1 3 225 30 31 206
|
||||
1 3 154 155 226 153
|
||||
1 3 155 156 180 226
|
||||
1 3 153 226 227 152
|
||||
1 3 226 180 138 227
|
||||
1 3 152 227 228 151
|
||||
1 3 227 138 139 228
|
||||
1 3 151 228 229 150
|
||||
1 3 228 139 140 229
|
||||
1 3 150 229 230 149
|
||||
1 3 229 140 141 230
|
||||
1 3 149 230 231 148
|
||||
1 3 230 141 142 231
|
||||
1 3 148 231 232 147
|
||||
1 3 231 142 143 232
|
||||
1 3 147 232 145 146
|
||||
1 3 232 143 144 145
|
||||
1 3 56 233 223 55
|
||||
1 3 233 78 79 223
|
||||
1 3 57 234 233 56
|
||||
1 3 234 77 78 233
|
||||
1 3 58 235 234 57
|
||||
1 3 235 76 77 234
|
||||
1 3 61 236 59 60
|
||||
1 3 236 235 58 59
|
||||
1 3 62 237 236 61
|
||||
1 3 237 76 235 236
|
||||
1 3 63 238 237 62
|
||||
1 3 238 75 76 237
|
||||
1 3 64 239 238 63
|
||||
1 3 239 74 75 238
|
||||
1 3 65 240 239 64
|
||||
1 3 240 73 74 239
|
||||
1 3 66 241 240 65
|
||||
1 3 241 72 73 240
|
||||
1 3 67 242 241 66
|
||||
1 3 242 71 72 241
|
||||
1 3 68 69 242 67
|
||||
1 3 69 70 71 242
|
||||
|
||||
boundary
|
||||
164
|
||||
3 1 0 1
|
||||
3 1 1 2
|
||||
3 1 2 3
|
||||
3 1 3 4
|
||||
3 1 4 5
|
||||
3 1 5 6
|
||||
3 1 6 7
|
||||
3 1 7 8
|
||||
3 1 8 9
|
||||
3 1 9 10
|
||||
3 1 10 11
|
||||
3 1 11 12
|
||||
3 1 12 13
|
||||
3 1 13 14
|
||||
3 1 16 17
|
||||
3 1 17 18
|
||||
3 1 18 19
|
||||
3 1 19 20
|
||||
3 1 20 21
|
||||
3 1 21 22
|
||||
3 1 22 23
|
||||
3 1 23 24
|
||||
3 1 24 25
|
||||
3 1 25 26
|
||||
3 1 26 27
|
||||
3 1 27 28
|
||||
3 1 28 29
|
||||
3 1 29 30
|
||||
3 1 30 31
|
||||
3 1 31 32
|
||||
3 1 32 33
|
||||
3 1 33 34
|
||||
3 1 34 35
|
||||
3 1 35 36
|
||||
3 1 36 37
|
||||
3 1 37 38
|
||||
3 1 38 39
|
||||
3 1 39 40
|
||||
3 1 40 41
|
||||
3 1 41 42
|
||||
3 1 42 43
|
||||
3 1 43 44
|
||||
3 1 49 50
|
||||
3 1 48 49
|
||||
3 1 47 48
|
||||
3 1 46 47
|
||||
3 1 45 46
|
||||
3 1 44 45
|
||||
3 1 52 53
|
||||
3 1 53 54
|
||||
3 1 54 55
|
||||
3 1 57 58
|
||||
3 1 56 57
|
||||
3 1 55 56
|
||||
3 1 60 61
|
||||
3 1 61 62
|
||||
3 1 62 63
|
||||
3 1 63 64
|
||||
3 1 64 65
|
||||
3 1 65 66
|
||||
3 1 66 67
|
||||
3 1 67 68
|
||||
3 1 75 76
|
||||
3 1 74 75
|
||||
3 1 73 74
|
||||
3 1 72 73
|
||||
3 1 71 72
|
||||
3 1 70 71
|
||||
3 1 76 77
|
||||
3 1 77 78
|
||||
3 1 78 79
|
||||
3 1 81 82
|
||||
3 1 80 81
|
||||
3 1 79 80
|
||||
3 1 82 83
|
||||
3 1 83 84
|
||||
3 1 84 85
|
||||
3 1 85 86
|
||||
3 1 86 87
|
||||
3 1 87 88
|
||||
3 1 94 95
|
||||
3 1 93 94
|
||||
3 1 92 93
|
||||
3 1 91 92
|
||||
3 1 90 91
|
||||
3 1 96 97
|
||||
3 1 95 96
|
||||
3 1 97 98
|
||||
3 1 98 99
|
||||
3 1 99 100
|
||||
3 1 100 101
|
||||
3 1 101 102
|
||||
3 1 102 103
|
||||
3 1 107 108
|
||||
3 1 106 107
|
||||
3 1 105 106
|
||||
3 1 104 105
|
||||
3 1 103 104
|
||||
3 1 108 109
|
||||
3 1 109 110
|
||||
3 1 110 111
|
||||
3 1 111 112
|
||||
3 1 112 113
|
||||
3 1 113 114
|
||||
3 1 114 115
|
||||
3 1 115 116
|
||||
3 1 116 117
|
||||
3 1 119 120
|
||||
3 1 118 119
|
||||
3 1 117 118
|
||||
3 1 131 132
|
||||
3 1 130 131
|
||||
3 1 129 130
|
||||
3 1 128 129
|
||||
3 1 127 128
|
||||
3 1 126 127
|
||||
3 1 132 133
|
||||
3 1 133 134
|
||||
3 1 134 135
|
||||
3 1 137 138
|
||||
3 1 136 137
|
||||
3 1 135 136
|
||||
3 1 138 139
|
||||
3 1 139 140
|
||||
3 1 140 141
|
||||
3 1 141 142
|
||||
3 1 142 143
|
||||
3 1 143 144
|
||||
3 1 147 148
|
||||
3 1 146 147
|
||||
3 1 153 154
|
||||
3 1 152 153
|
||||
3 1 151 152
|
||||
3 1 150 151
|
||||
3 1 149 150
|
||||
3 1 148 149
|
||||
3 1 156 157
|
||||
3 1 157 158
|
||||
3 1 158 159
|
||||
3 1 161 162
|
||||
3 1 160 161
|
||||
3 1 159 160
|
||||
2 1 69 70
|
||||
2 1 68 69
|
||||
3 1 88 89
|
||||
3 1 89 90
|
||||
3 1 121 122
|
||||
3 1 120 121
|
||||
3 1 123 124
|
||||
3 1 122 123
|
||||
3 1 125 126
|
||||
3 1 124 125
|
||||
1 1 144 145
|
||||
1 1 145 146
|
||||
3 1 15 16
|
||||
3 1 14 15
|
||||
3 1 50 51
|
||||
3 1 51 52
|
||||
3 1 59 60
|
||||
3 1 58 59
|
||||
3 1 154 155
|
||||
3 1 155 156
|
||||
3 1 163 0
|
||||
3 1 162 163
|
||||
|
||||
vertices
|
||||
243
|
||||
2
|
||||
4 4
|
||||
4 3.5
|
||||
4 3
|
||||
4 2.5
|
||||
4 2
|
||||
4 1.5
|
||||
4 1
|
||||
4.5 1
|
||||
5 1
|
||||
5 1.5
|
||||
5 2
|
||||
5 2.5
|
||||
5 3
|
||||
5 3.5
|
||||
5 4
|
||||
5.500 4
|
||||
6 4
|
||||
6.500 4
|
||||
7 4
|
||||
7.5 4
|
||||
8 4
|
||||
8.5 4
|
||||
9 4
|
||||
9.5 4
|
||||
10 4
|
||||
10.5 4
|
||||
11 4
|
||||
11 3.5
|
||||
11 3
|
||||
10.5 3
|
||||
10 3
|
||||
9.5 3
|
||||
9.5 2.5
|
||||
10 2.5
|
||||
10.5 2.5
|
||||
10.5 2
|
||||
10.5 1.5
|
||||
10 1.5
|
||||
9.5 1.5
|
||||
9.5 1
|
||||
10 1
|
||||
10.5 1
|
||||
11 1
|
||||
11.5 1
|
||||
12 1
|
||||
12 1.5
|
||||
12 2
|
||||
12 2.5
|
||||
12 3
|
||||
12 3.5
|
||||
12 4
|
||||
12.5 4
|
||||
13 4
|
||||
13.333 3.75
|
||||
13.666 3.5
|
||||
14.000 3.25
|
||||
14.333 3.5
|
||||
14.666 3.75
|
||||
15.000 4
|
||||
15.500 4
|
||||
16.000 4
|
||||
16.000 3.5
|
||||
16.000 3
|
||||
16.000 2.5
|
||||
16.000 2
|
||||
16.000 1.5
|
||||
16.000 1
|
||||
16.000 0.5
|
||||
16.000 0
|
||||
15.500 0
|
||||
15.000 0
|
||||
15.000 0.5000000000000002
|
||||
15.000 1
|
||||
15.000 1.5
|
||||
15.000 2
|
||||
15.000 2.5
|
||||
15.000 3
|
||||
14.666 2.75
|
||||
14.333 2.5
|
||||
14.000 2.25
|
||||
13.666 2.5
|
||||
13.333 2.75
|
||||
13 3
|
||||
13 2.5
|
||||
13 2
|
||||
13 1.5
|
||||
13 1
|
||||
13 0.500
|
||||
13 0
|
||||
12.5 0
|
||||
12 0
|
||||
11.5 0
|
||||
11 0
|
||||
10.5 0
|
||||
10 0
|
||||
9.5 0
|
||||
9 0
|
||||
8.5 0
|
||||
8.5 0.5
|
||||
8.5 1
|
||||
8.5 1.5
|
||||
8.5 2
|
||||
8.5 2.5
|
||||
8.5 3
|
||||
8 3
|
||||
7.5 3
|
||||
7 3
|
||||
6.500 3
|
||||
6 3
|
||||
6 2.5
|
||||
6.5 2.5
|
||||
7 2.5
|
||||
7.5 2.5
|
||||
7.5 2
|
||||
7.5 1.5
|
||||
7.000 1.5
|
||||
6.5 1.5
|
||||
6 1.5
|
||||
6 1
|
||||
6 0.5
|
||||
6 0
|
||||
5.5 0
|
||||
5 0
|
||||
4.5 0
|
||||
4 0
|
||||
3.5 0
|
||||
3 0
|
||||
3 0.500
|
||||
3 1
|
||||
3 1.5
|
||||
3 2
|
||||
3 2.5
|
||||
3 3
|
||||
2.666 2.75
|
||||
2.333 2.5
|
||||
2.000 2.25
|
||||
1.666 2.5
|
||||
1.333 2.75
|
||||
1.000 3
|
||||
1.000 2.5
|
||||
1.000 2
|
||||
1.000 1.5
|
||||
1.000 1
|
||||
1.000 0.5000
|
||||
1.000 0
|
||||
0.5000 0
|
||||
0.0000 0
|
||||
0.0000 0.5
|
||||
0.0000 1
|
||||
0.0000 1.5
|
||||
0.0000 2
|
||||
0.0000 2.5
|
||||
0.0000 3
|
||||
0.0000 3.5
|
||||
0.0000 4
|
||||
0.5000 4
|
||||
1.000 4
|
||||
1.333 3.75
|
||||
1.666 3.5
|
||||
2.000 3.25
|
||||
2.333 3.5
|
||||
2.666 3.75
|
||||
3 4
|
||||
3.5 4
|
||||
3.5 3.5
|
||||
3 3.5
|
||||
3.5 3
|
||||
3.5 2.5
|
||||
3.5 2
|
||||
3.5 1.5
|
||||
3.5 1
|
||||
4 0.5
|
||||
3.5 0.5
|
||||
2.666 3.25
|
||||
2.333 3
|
||||
2.000 2.75
|
||||
4.5 0.5
|
||||
5 0.5
|
||||
1.666 3
|
||||
1.333 3.25
|
||||
1.000 3.5
|
||||
5.5 0.5
|
||||
5.500 1
|
||||
5.500 1.5
|
||||
5.500 2
|
||||
5.500 2.5
|
||||
5.500 3
|
||||
5.500 3.5
|
||||
6 2
|
||||
6 3.5
|
||||
6.5 2
|
||||
7 2
|
||||
6.5 3.5
|
||||
7 3.5
|
||||
7.5 3.5
|
||||
8 3.5
|
||||
8.5 3.5
|
||||
9 0.5
|
||||
9 1
|
||||
9 1.5
|
||||
9 2
|
||||
9 2.5
|
||||
9 3
|
||||
9 3.5
|
||||
9.5 0.5
|
||||
9.5 2
|
||||
9.5 3.5
|
||||
10 2
|
||||
10 0.5
|
||||
10.5 0.5
|
||||
11 0.5
|
||||
11.5 0.5
|
||||
12 0.5
|
||||
12.5 0.500
|
||||
12.5 1
|
||||
12.5 1.5
|
||||
12.5 2
|
||||
12.5 2.5
|
||||
12.5 3
|
||||
12.5 3.5
|
||||
13 3.5
|
||||
13.333 3.250
|
||||
13.666 3
|
||||
14.000 2.75
|
||||
10.5 3.5
|
||||
10 3.5
|
||||
0.500 3.5
|
||||
0.500 3
|
||||
0.500 2.5
|
||||
0.500 2
|
||||
0.500 1.5
|
||||
0.500 1
|
||||
0.500 0.5
|
||||
14.333 3
|
||||
14.666 3.25
|
||||
15.000 3.5
|
||||
15.500 3.5
|
||||
15.500 3
|
||||
15.500 2.5
|
||||
15.500 2
|
||||
15.500 1.5
|
||||
15.500 1
|
||||
15.500 0.5
|
||||
@@ -0,0 +1,342 @@
|
||||
MFEM NURBS NC-patch mesh v1.0
|
||||
dimension
|
||||
3
|
||||
|
||||
elements
|
||||
13
|
||||
0 1 5 0 8 10 11 9 4 6 7 5
|
||||
0 1 5 0 18 8 24 32 30 23 36 38
|
||||
0 1 5 0 0 18 32 14 12 30 38 29
|
||||
0 1 5 0 32 24 10 20 38 36 26 35
|
||||
0 1 5 0 14 32 20 2 29 38 35 16
|
||||
0 1 5 0 30 23 36 38 31 22 37 39
|
||||
0 1 5 0 12 30 38 29 13 31 39 28
|
||||
0 1 5 0 38 36 26 35 39 37 27 34
|
||||
0 1 5 0 29 38 35 16 28 39 34 17
|
||||
0 1 5 0 31 22 37 39 19 9 25 33
|
||||
0 1 5 0 13 31 39 28 1 19 33 15
|
||||
0 1 5 0 39 37 27 34 33 25 11 21
|
||||
0 1 5 0 28 39 34 17 15 33 21 3
|
||||
|
||||
boundary
|
||||
31
|
||||
9999 3 8 10 6 4
|
||||
9999 3 10 11 7 6
|
||||
9999 3 11 9 5 7
|
||||
9999 3 9 8 4 5
|
||||
9999 3 4 6 7 5
|
||||
9999 3 32 24 8 18
|
||||
9999 3 18 8 23 30
|
||||
9999 3 14 32 18 0
|
||||
9999 3 0 18 30 12
|
||||
9999 3 14 0 12 29
|
||||
9999 3 20 10 24 32
|
||||
9999 3 10 20 35 26
|
||||
9999 3 2 20 32 14
|
||||
9999 3 20 2 16 35
|
||||
9999 3 2 14 29 16
|
||||
9999 3 30 23 22 31
|
||||
9999 3 12 30 31 13
|
||||
9999 3 29 12 13 28
|
||||
9999 3 26 35 34 27
|
||||
9999 3 35 16 17 34
|
||||
9999 3 16 29 28 17
|
||||
9999 3 31 22 9 19
|
||||
9999 3 19 9 25 33
|
||||
9999 3 13 31 19 1
|
||||
9999 3 28 13 1 15
|
||||
9999 3 1 19 33 15
|
||||
9999 3 27 34 21 11
|
||||
9999 3 33 25 11 21
|
||||
9999 3 34 17 3 21
|
||||
9999 3 17 28 15 3
|
||||
9999 3 15 33 21 3
|
||||
|
||||
vertex_to_knotspan
|
||||
8
|
||||
23 0 1 8 10 11 9
|
||||
22 0 2 8 10 11 9
|
||||
24 1 0 8 10 11 9
|
||||
36 1 1 8 10 11 9
|
||||
37 1 2 8 10 11 9
|
||||
25 1 3 8 10 11 9
|
||||
26 2 1 8 10 11 9
|
||||
27 2 2 8 10 11 9
|
||||
|
||||
coordinates
|
||||
40
|
||||
3
|
||||
0 0 0
|
||||
0 1 0
|
||||
4 0 0
|
||||
4 1 0
|
||||
0 0 4
|
||||
0 1 4
|
||||
4 0 4
|
||||
4 1 4
|
||||
0 0 2
|
||||
0 1 2
|
||||
4 0 2
|
||||
4 1 2
|
||||
0 0.333333333333333 0
|
||||
0 0.666666666666667 0
|
||||
2 0 0
|
||||
2 1 0
|
||||
4 0.333333333333334 0
|
||||
4 0.666666666666667 0
|
||||
0 0 1
|
||||
0 1 1
|
||||
4 0 1
|
||||
4 1 1
|
||||
0 0.666666666666667 2
|
||||
0 0.333333333333333 2
|
||||
2 0 2
|
||||
2 1 2
|
||||
4 0.333333333333333 2
|
||||
4 0.666666666666667 2
|
||||
2 0.666666666666667 0
|
||||
2 0.333333333333333 0
|
||||
0 0.333333333333333 1
|
||||
0 0.666666666666667 1
|
||||
1.81325211007895 0 1
|
||||
1.81325211007895 1 1
|
||||
4 0.666666666666667 1
|
||||
4 0.333333333333333 1
|
||||
2 0.333333333333333 2
|
||||
2 0.666666666666667 2
|
||||
1.81325211007895 0.333333333333333 1
|
||||
1.81325211007895 0.666666666666667 1
|
||||
|
||||
edges
|
||||
87
|
||||
0 8 10
|
||||
1 10 11
|
||||
0 9 11
|
||||
1 8 9
|
||||
0 4 6
|
||||
1 6 7
|
||||
0 5 7
|
||||
1 4 5
|
||||
2 4 8
|
||||
2 6 10
|
||||
2 7 11
|
||||
2 5 9
|
||||
9 18 8
|
||||
7 8 24
|
||||
9 32 24
|
||||
7 18 32
|
||||
9 30 23
|
||||
7 23 36
|
||||
9 38 36
|
||||
7 30 38
|
||||
3 18 30
|
||||
3 8 23
|
||||
3 24 36
|
||||
3 32 38
|
||||
8 0 18
|
||||
8 14 32
|
||||
7 0 14
|
||||
8 12 30
|
||||
8 29 38
|
||||
7 12 29
|
||||
3 0 12
|
||||
3 14 29
|
||||
6 24 10
|
||||
9 20 10
|
||||
6 32 20
|
||||
6 36 26
|
||||
9 35 26
|
||||
6 38 35
|
||||
3 10 26
|
||||
3 20 35
|
||||
8 2 20
|
||||
6 14 2
|
||||
8 16 35
|
||||
6 29 16
|
||||
3 2 16
|
||||
9 31 22
|
||||
7 22 37
|
||||
9 39 37
|
||||
7 31 39
|
||||
4 30 31
|
||||
4 23 22
|
||||
4 36 37
|
||||
4 38 39
|
||||
8 13 31
|
||||
8 28 39
|
||||
7 13 28
|
||||
4 12 13
|
||||
4 29 28
|
||||
6 37 27
|
||||
9 34 27
|
||||
6 39 34
|
||||
4 26 27
|
||||
4 35 34
|
||||
8 17 34
|
||||
6 28 17
|
||||
4 16 17
|
||||
9 19 9
|
||||
7 9 25
|
||||
9 33 25
|
||||
7 19 33
|
||||
5 31 19
|
||||
5 22 9
|
||||
5 37 25
|
||||
5 39 33
|
||||
8 1 19
|
||||
8 15 33
|
||||
7 1 15
|
||||
5 13 1
|
||||
5 28 15
|
||||
6 25 11
|
||||
9 21 11
|
||||
6 33 21
|
||||
5 27 11
|
||||
5 34 21
|
||||
8 3 21
|
||||
6 15 3
|
||||
5 17 3
|
||||
|
||||
knotvectors
|
||||
10
|
||||
1 3 0 0 0.5 1 1
|
||||
1 4 0 0 0.333333333333333 0.666666666666667 1 1
|
||||
1 3 0 0 0.5 1 1
|
||||
1 2 0 0 1 1
|
||||
1 2 0 0 1 1
|
||||
1 2 0 0 1 1
|
||||
1 2 0 0 1 1
|
||||
1 2 0 0 1 1
|
||||
1 2 0 0 1 1
|
||||
1 2 0 0 1 1
|
||||
|
||||
spacing
|
||||
0
|
||||
|
||||
weights
|
||||
1.0
|
||||
1.0
|
||||
1.0
|
||||
1.0
|
||||
1.0
|
||||
1.0
|
||||
1.0
|
||||
1.0
|
||||
1.0
|
||||
1.0
|
||||
1.0
|
||||
1.0
|
||||
1.0
|
||||
1.0
|
||||
1.0
|
||||
1.0
|
||||
1.0
|
||||
1.0
|
||||
1.0
|
||||
1.0
|
||||
1.0
|
||||
1.0
|
||||
1.0
|
||||
1.0
|
||||
1.0
|
||||
1.0
|
||||
1.0
|
||||
1.0
|
||||
1.0
|
||||
1.0
|
||||
1.0
|
||||
1.0
|
||||
1.0
|
||||
1.0
|
||||
1.0
|
||||
1.0
|
||||
1.0
|
||||
1.0
|
||||
1.0
|
||||
1.0
|
||||
1.0
|
||||
1.0
|
||||
1.0
|
||||
1.0
|
||||
1.0
|
||||
1.0
|
||||
1.0
|
||||
1.0
|
||||
1.0
|
||||
1.0
|
||||
1.0
|
||||
1.0
|
||||
1.0
|
||||
1.0
|
||||
1.0
|
||||
1.0
|
||||
1.0
|
||||
1.0
|
||||
1.0
|
||||
1.0
|
||||
|
||||
FiniteElementSpace
|
||||
FiniteElementCollection: NURBS1
|
||||
VDim: 3
|
||||
Ordering: 1
|
||||
|
||||
0 0 0
|
||||
0 1 0
|
||||
4 0 0
|
||||
4 1 0
|
||||
0 0 4
|
||||
0 1 4
|
||||
4 0 4
|
||||
4 1 4
|
||||
0 0 2
|
||||
0 1 2
|
||||
4 0 2
|
||||
4 1 2
|
||||
0 0.333333333333333 0
|
||||
0 0.666666666666667 0
|
||||
2 0 0
|
||||
2 1 0
|
||||
4 0.333333333333334 0
|
||||
4 0.666666666666667 0
|
||||
0 0 1
|
||||
0 1 1
|
||||
4 0 1
|
||||
4 1 1
|
||||
0 0.666666666666667 2
|
||||
0 0.333333333333333 2
|
||||
2 0 2
|
||||
2 1 2
|
||||
4 0.333333333333333 2
|
||||
4 0.666666666666667 2
|
||||
2 0.666666666666667 0
|
||||
2 0.333333333333333 0
|
||||
0 0.333333333333333 1
|
||||
0 0.666666666666667 1
|
||||
1.81325211007895 0 1
|
||||
1.81325211007895 1 1
|
||||
4 0.666666666666667 1
|
||||
4 0.333333333333333 1
|
||||
2 0.333333333333333 2
|
||||
2 0.666666666666667 2
|
||||
1.81325211007895 0.333333333333333 1
|
||||
1.81325211007895 0.666666666666667 1
|
||||
2 0 4
|
||||
4 0.333333333333333 4
|
||||
4 0.666666666666667 4
|
||||
2 1 4
|
||||
0 0.333333333333333 4
|
||||
0 0.666666666666667 4
|
||||
0 0 3
|
||||
4 0 3
|
||||
4 1 3
|
||||
0 1 3
|
||||
2 0 3
|
||||
4 0.333333333333333 3
|
||||
4 0.666666666666667 3
|
||||
2 1 3
|
||||
0 0.666666666666667 3
|
||||
0 0.333333333333333 3
|
||||
2 0.333333333333333 4
|
||||
2 0.666666666666667 4
|
||||
2 0.333333333333333 3
|
||||
2 0.666666666666667 3
|
||||
@@ -0,0 +1,96 @@
|
||||
MFEM NURBS NC-patch mesh v1.0
|
||||
dimension
|
||||
2
|
||||
|
||||
# rank attr geom ref_type nodes/children
|
||||
elements
|
||||
3
|
||||
0 1 3 0 0 4 5 1
|
||||
0 1 3 0 6 7 4 2
|
||||
0 1 3 0 6 3 5 7
|
||||
|
||||
# attr geom nodes
|
||||
boundary
|
||||
7
|
||||
1 1 0 4
|
||||
1 1 5 1
|
||||
1 1 1 0
|
||||
1 1 2 6
|
||||
1 1 6 3
|
||||
1 1 4 2
|
||||
1 1 5 3
|
||||
|
||||
vertex_to_knotspan
|
||||
1
|
||||
7 1 4 5
|
||||
|
||||
# top-level node coordinates
|
||||
coordinates
|
||||
8
|
||||
2
|
||||
0 0
|
||||
0 1
|
||||
2 0
|
||||
2 1
|
||||
1 0
|
||||
1 1
|
||||
2 0.5
|
||||
1 0.5
|
||||
|
||||
edges
|
||||
11
|
||||
0 0 4
|
||||
1 4 5
|
||||
0 1 5
|
||||
1 0 1
|
||||
2 6 7
|
||||
4 7 4
|
||||
2 2 4
|
||||
4 6 2
|
||||
3 6 3
|
||||
2 3 5
|
||||
3 7 5
|
||||
|
||||
knotvectors
|
||||
5
|
||||
1 3 0 0 0.5 1 1
|
||||
1 3 0 0 0.5 1 1
|
||||
1 2 0 0 1 1
|
||||
1 2 0 0 1 1
|
||||
1 2 0 0 1 1
|
||||
|
||||
spacing
|
||||
0
|
||||
|
||||
weights
|
||||
1.0
|
||||
1.0
|
||||
1.0
|
||||
1.0
|
||||
1.0
|
||||
1.0
|
||||
1.0
|
||||
1.0
|
||||
1.0
|
||||
1.0
|
||||
1.0
|
||||
1.0
|
||||
|
||||
FiniteElementSpace
|
||||
FiniteElementCollection: NURBS1
|
||||
VDim: 2
|
||||
Ordering: 1
|
||||
|
||||
0 0
|
||||
0 1
|
||||
2 0
|
||||
2 1
|
||||
1 0
|
||||
1 1
|
||||
2 0.5
|
||||
1 0.5
|
||||
0.5 0
|
||||
0.5 1
|
||||
0 0.5
|
||||
0.5 0.5
|
||||
mfem_mesh_end
|
||||
@@ -202,6 +202,7 @@ namespace mfem {
|
||||
* - <a class="el" href="tesla_8cpp_source.html">Tesla</a>: simple magnetostatics simulation code
|
||||
* - <a class="el" href="maxwell_8cpp_source.html">Maxwell</a>: simple transient full-wave electromagnetics simulation code
|
||||
* - <a class="el" href="joule_8cpp_source.html">Joule</a>: transient magnetics and Joule heating miniapp
|
||||
* - <a class="el" href="lorentz_8cpp_source.html">Lorentz</a>: simple particle tracking code based on the Lorentz force
|
||||
* - <a class="el" href="classmfem_1_1navier_1_1NavierSolver.html">Navier</a>: solve the transient incompressible Navier-Stokes equations
|
||||
* - <a class="el" href="mobius-strip_8cpp_source.html">Mobius Strip</a>: generate various Mobius strip-like meshes
|
||||
* - <a class="el" href="klein-bottle_8cpp_source.html">Klein Bottle</a>: generate three types of Klein bottle surfaces
|
||||
|
||||
@@ -205,6 +205,15 @@ if (MFEM_ENABLE_TESTING)
|
||||
$<TARGET_FILE:ex25p> "-no-vis" "--mumps-solver"
|
||||
${MPIEXEC_POSTFLAGS})
|
||||
endif()
|
||||
|
||||
# Parallel libCEED example
|
||||
if (MFEM_USE_CEED AND MFEM_USE_MPI)
|
||||
add_test(NAME ex1p_ceed_np=${MFEM_MPI_NP}
|
||||
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP}
|
||||
${MPIEXEC_PREFLAGS}
|
||||
$<TARGET_FILE:ex1p> "-no-vis" "-d ceed-cpu" "-pa" "-a"
|
||||
${MPIEXEC_POSTFLAGS})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Include the examples/amgx directory if AmgX is enabled
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
// ex1 -m ../data/fichera-amr.mesh
|
||||
// ex1 -m ../data/mobius-strip.mesh
|
||||
// ex1 -m ../data/mobius-strip.mesh -o -1 -sc
|
||||
// ex1 -m ../data/nc3-nurbs.mesh -o -1
|
||||
//
|
||||
// Device sample runs:
|
||||
// ex1 -pa -d cuda
|
||||
|
||||
@@ -173,6 +173,12 @@ ex11p-test-cpardiso: ex11p
|
||||
@$(call mfem-test,$<, $(RUN_MPI), MKL_CPARDISO example,--cpardiso)
|
||||
test-par-YES: ex11p-test-cpardiso
|
||||
endif
|
||||
ifeq ($(MFEM_USE_CEED),YES)
|
||||
ex1p-test-ceed: ex1p
|
||||
@$(call mfem-test,$<, $(RUN_MPI),\
|
||||
Parallel libCEED example,-d ceed-cpu -pa -a)
|
||||
test-par-YES: ex1p-test-ceed
|
||||
endif
|
||||
|
||||
# Testing: "test" target and mfem-test* variables are defined in config/test.mk
|
||||
|
||||
|
||||
@@ -82,6 +82,8 @@ set(SRCS
|
||||
fe/fe_ser.cpp
|
||||
fe_coll.cpp
|
||||
fespace.cpp
|
||||
derefmat_op.cpp
|
||||
pderefmat_op.cpp
|
||||
geom.cpp
|
||||
gridfunc.cpp
|
||||
hybridization.cpp
|
||||
@@ -169,6 +171,11 @@ set(HDRS
|
||||
bilinearform.hpp
|
||||
bilinearform_ext.hpp
|
||||
bilininteg.hpp
|
||||
integ/lininteg_domain_kernels.hpp
|
||||
integ/bilininteg_dgdiffusion_kernels.hpp
|
||||
integ/bilininteg_dgtrace_kernels.hpp
|
||||
integ/bilininteg_vecdiffusion_kernels.hpp
|
||||
integ/bilininteg_convection_kernels.hpp
|
||||
integ/bilininteg_diffusion_kernels.hpp
|
||||
integ/bilininteg_elasticity_kernels.hpp
|
||||
integ/bilininteg_hcurl_kernels.hpp
|
||||
@@ -239,8 +246,13 @@ set(HDRS
|
||||
lor/lor_ams.hpp
|
||||
lor/lor_batched.hpp
|
||||
lor/lor_h1.hpp
|
||||
lor/lor_dg.hpp
|
||||
lor/lor_nd.hpp
|
||||
lor/lor_rt.hpp
|
||||
lor/lor_h1_impl.hpp
|
||||
lor/lor_dg_impl.hpp
|
||||
lor/lor_nd_impl.hpp
|
||||
lor/lor_rt_impl.hpp
|
||||
lor/lor_util.hpp
|
||||
multigrid.hpp
|
||||
nonlinearform.hpp
|
||||
|
||||
+26
-64
@@ -266,11 +266,7 @@ void PABilinearFormExtension::SetupRestrictionOperators(const L2FaceValues m)
|
||||
|
||||
// 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);
|
||||
}
|
||||
elem_attributes = &mesh.GetElementAttributes();
|
||||
}
|
||||
|
||||
// Construct face restriction operators only if the bilinear form has
|
||||
@@ -329,45 +325,7 @@ void PABilinearFormExtension::SetupRestrictionOperators(const L2FaceValues m)
|
||||
bdr_face_dYdn.SetSize(bdr_face_restrict_lex->Height());
|
||||
}
|
||||
|
||||
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.GetBdrElementFaceIndex(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.");
|
||||
}
|
||||
bdr_face_attributes = &trial_fes->GetMesh()->GetBdrFaceAttributes();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -429,7 +387,7 @@ void PABilinearFormExtension::AssembleDiagonal(Vector &y) const
|
||||
mfem::forall(ne, [=] MFEM_HOST_DEVICE (int e)
|
||||
{
|
||||
const int attr = d_attr[e];
|
||||
if (d_m[attr - 1] == 0)
|
||||
if (attr <= 0 || d_m[attr - 1] == 0)
|
||||
{
|
||||
for (int i = 0; i < nd; ++i)
|
||||
{
|
||||
@@ -450,7 +408,7 @@ void PABilinearFormExtension::AssembleDiagonal(Vector &y) const
|
||||
for (int i = 0; i < iSz; ++i)
|
||||
{
|
||||
assemble_diagonal_with_markers(*integrators[i], elem_markers[i],
|
||||
elem_attributes, localY);
|
||||
*elem_attributes, localY);
|
||||
}
|
||||
const ElementRestriction* H1elem_restrict =
|
||||
dynamic_cast<const ElementRestriction*>(elem_restrict);
|
||||
@@ -476,7 +434,7 @@ void PABilinearFormExtension::AssembleDiagonal(Vector &y) const
|
||||
for (int i = 0; i < iSz; ++i)
|
||||
{
|
||||
assemble_diagonal_with_markers(*integrators[i], elem_markers[i],
|
||||
elem_attributes, y);
|
||||
*elem_attributes, y);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -489,7 +447,7 @@ void PABilinearFormExtension::AssembleDiagonal(Vector &y) const
|
||||
for (int i = 0; i < n_bdr_integs; ++i)
|
||||
{
|
||||
assemble_diagonal_with_markers(*bdr_integs[i], bdr_markers[i],
|
||||
bdr_attributes, bdr_face_Y);
|
||||
*bdr_face_attributes, bdr_face_Y);
|
||||
}
|
||||
bdr_face_restrict_lex->AddAbsMultTranspose(bdr_face_Y, y);
|
||||
}
|
||||
@@ -588,7 +546,7 @@ void PABilinearFormExtension::MultInternal(const Vector &x, Vector &y,
|
||||
for (int i = 0; i < iSz; ++i)
|
||||
{
|
||||
AddMultWithMarkers(*integrators[i], localX, elem_markers[i],
|
||||
elem_attributes, false, localY, useAbs);
|
||||
*elem_attributes, false, localY, useAbs);
|
||||
}
|
||||
if (H1elem_restrict && useAbs)
|
||||
{
|
||||
@@ -690,8 +648,8 @@ void PABilinearFormExtension::MultInternal(const Vector &x, Vector &y,
|
||||
}
|
||||
for (int i = 0; i < n_bdr_integs; ++i)
|
||||
{
|
||||
AddMultWithMarkers(*bdr_integs[i], bdr_face_X, bdr_markers[i], bdr_attributes,
|
||||
false, bdr_face_Y);
|
||||
AddMultWithMarkers(*bdr_integs[i], bdr_face_X, bdr_markers[i],
|
||||
*bdr_face_attributes, false, bdr_face_Y);
|
||||
}
|
||||
for (int i = 0; i < n_bdr_face_integs; ++i)
|
||||
{
|
||||
@@ -699,12 +657,14 @@ void PABilinearFormExtension::MultInternal(const Vector &x, Vector &y,
|
||||
{
|
||||
AddMultNormalDerivativesWithMarkers(
|
||||
*bdr_face_integs[i], bdr_face_X, bdr_face_dXdn,
|
||||
bdr_face_markers[i], bdr_attributes, bdr_face_Y, bdr_face_dYdn);
|
||||
bdr_face_markers[i], *bdr_face_attributes, bdr_face_Y,
|
||||
bdr_face_dYdn);
|
||||
}
|
||||
else
|
||||
{
|
||||
AddMultWithMarkers(*bdr_face_integs[i], bdr_face_X, bdr_face_markers[i],
|
||||
bdr_attributes, false, bdr_face_Y);
|
||||
AddMultWithMarkers(*bdr_face_integs[i], bdr_face_X,
|
||||
bdr_face_markers[i], *bdr_face_attributes, false,
|
||||
bdr_face_Y);
|
||||
}
|
||||
}
|
||||
bdr_face_restrict_lex->AddMultTransposeInPlace(bdr_face_Y, y);
|
||||
@@ -727,7 +687,7 @@ void PABilinearFormExtension::MultTranspose(const Vector &x, Vector &y) const
|
||||
localY = 0.0;
|
||||
for (int i = 0; i < iSz; ++i)
|
||||
{
|
||||
AddMultWithMarkers(*integrators[i], localX, elem_markers[i], elem_attributes,
|
||||
AddMultWithMarkers(*integrators[i], localX, elem_markers[i], *elem_attributes,
|
||||
true, localY);
|
||||
}
|
||||
elem_restrict->MultTranspose(localY, y);
|
||||
@@ -774,13 +734,14 @@ void PABilinearFormExtension::MultTranspose(const Vector &x, Vector &y) const
|
||||
bdr_face_Y = 0.0;
|
||||
for (int i = 0; i < n_bdr_integs; ++i)
|
||||
{
|
||||
AddMultWithMarkers(*bdr_integs[i], bdr_face_X, bdr_markers[i], bdr_attributes,
|
||||
true, bdr_face_Y);
|
||||
AddMultWithMarkers(*bdr_integs[i], bdr_face_X, bdr_markers[i],
|
||||
*bdr_face_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);
|
||||
AddMultWithMarkers(*bdr_face_integs[i], bdr_face_X,
|
||||
bdr_face_markers[i], *bdr_face_attributes, true,
|
||||
bdr_face_Y);
|
||||
}
|
||||
bdr_face_restrict_lex->AddMultTransposeInPlace(bdr_face_Y, y);
|
||||
}
|
||||
@@ -804,7 +765,7 @@ static void AddWithMarkers_(
|
||||
mfem::forall(ne, [=] MFEM_HOST_DEVICE (int e)
|
||||
{
|
||||
const int attr = d_attr[e];
|
||||
if (d_m[attr - 1] == 0) { return; }
|
||||
if (attr <= 0 || d_m[attr - 1] == 0) { return; }
|
||||
for (int i = 0; i < nd; ++i)
|
||||
{
|
||||
d_y(i, e) += d_x(i, e);
|
||||
@@ -920,7 +881,8 @@ void EABilinearFormExtension::Assemble()
|
||||
{
|
||||
const int i = idx % sz;
|
||||
const int e = idx / sz;
|
||||
const real_t val = d_m[d_a[e] - 1] ? d_ea_1(i, e) : 0.0;
|
||||
const real_t val =
|
||||
d_a[e] > 0 ? (d_m[d_a[e] - 1] ? d_ea_1(i, e) : 0) : 0;
|
||||
if (add)
|
||||
{
|
||||
d_ea_2(i, e) += val;
|
||||
@@ -953,7 +915,7 @@ void EABilinearFormExtension::Assemble()
|
||||
ea_data_tmp.SetSize(ea_data.Size());
|
||||
integrators[i]->AssembleEA(*a->FESpace(), ea_data_tmp, false);
|
||||
add_with_markers(ea_data_tmp, ea_data, ne, *markers,
|
||||
elem_attributes, add);
|
||||
*elem_attributes, add);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -982,7 +944,7 @@ void EABilinearFormExtension::Assemble()
|
||||
ea_data_tmp.SetSize(ea_data_bdr.Size());
|
||||
bdr_integs[i]->AssembleEABoundary(*a->FESpace(), ea_data_tmp, add);
|
||||
add_with_markers(ea_data_tmp, ea_data_bdr, nf_bdr, *markers,
|
||||
bdr_attributes, add);
|
||||
*bdr_face_attributes, add);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1031,7 +993,7 @@ void EABilinearFormExtension::Assemble()
|
||||
ea_data_tmp,
|
||||
add);
|
||||
add_with_markers(ea_data_tmp, ea_data_bdr, nf_bdr, *markers,
|
||||
bdr_attributes, add);
|
||||
*bdr_face_attributes, add);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,7 +69,8 @@ class PABilinearFormExtension : public BilinearFormExtension
|
||||
protected:
|
||||
const FiniteElementSpace *trial_fes, *test_fes; // Not owned
|
||||
/// Attributes of all mesh elements.
|
||||
Array<int> elem_attributes, bdr_attributes;
|
||||
const Array<int> *elem_attributes; // Not owned
|
||||
const Array<int> *bdr_face_attributes; // Not owned
|
||||
mutable Vector tmp_evec; // Work array
|
||||
mutable Vector localX, localY;
|
||||
mutable Vector int_face_X, int_face_Y;
|
||||
|
||||
+152
-50
@@ -23,6 +23,8 @@
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
class QuadratureSpace;
|
||||
class FaceQuadratureSpace;
|
||||
|
||||
/// Abstract base class BilinearFormIntegrator
|
||||
class BilinearFormIntegrator : public NonlinearFormIntegrator
|
||||
@@ -812,7 +814,7 @@ protected:
|
||||
const FiniteElement & test_fe) const
|
||||
{
|
||||
return (trial_fe.GetDim() == 1 && test_fe.GetDim() == 1 &&
|
||||
trial_fe.GetDerivType() == mfem::FiniteElement::GRAD &&
|
||||
trial_fe.GetDerivType() == mfem::FiniteElement::GRAD &&
|
||||
test_fe.GetRangeType() == mfem::FiniteElement::SCALAR );
|
||||
}
|
||||
|
||||
@@ -884,7 +886,7 @@ protected:
|
||||
const FiniteElement & trial_fe,
|
||||
const FiniteElement & test_fe) const
|
||||
{
|
||||
return (trial_fe.GetDerivType() == mfem::FiniteElement::DIV &&
|
||||
return (trial_fe.GetDerivType() == mfem::FiniteElement::DIV &&
|
||||
test_fe.GetRangeType() == mfem::FiniteElement::SCALAR );
|
||||
}
|
||||
|
||||
@@ -919,7 +921,7 @@ protected:
|
||||
const FiniteElement & trial_fe,
|
||||
const FiniteElement & test_fe) const
|
||||
{
|
||||
return (trial_fe.GetDerivType() == mfem::FiniteElement::DIV &&
|
||||
return (trial_fe.GetDerivType() == mfem::FiniteElement::DIV &&
|
||||
test_fe.GetRangeType() == mfem::FiniteElement::VECTOR );
|
||||
}
|
||||
|
||||
@@ -1600,7 +1602,7 @@ public:
|
||||
{
|
||||
return (trial_fe.GetCurlDim() == 3 && test_fe.GetRangeDim() == 3 &&
|
||||
trial_fe.GetRangeType() == mfem::FiniteElement::VECTOR &&
|
||||
trial_fe.GetDerivType() == mfem::FiniteElement::CURL &&
|
||||
trial_fe.GetDerivType() == mfem::FiniteElement::CURL &&
|
||||
test_fe.GetRangeType() == mfem::FiniteElement::VECTOR );
|
||||
}
|
||||
|
||||
@@ -1635,7 +1637,7 @@ public:
|
||||
{
|
||||
return (trial_fe.GetDim() == 2 && test_fe.GetDim() == 2 &&
|
||||
trial_fe.GetRangeType() == mfem::FiniteElement::VECTOR &&
|
||||
trial_fe.GetDerivType() == mfem::FiniteElement::CURL &&
|
||||
trial_fe.GetDerivType() == mfem::FiniteElement::CURL &&
|
||||
test_fe.GetRangeType() == mfem::FiniteElement::VECTOR );
|
||||
}
|
||||
|
||||
@@ -1669,7 +1671,7 @@ public:
|
||||
{
|
||||
return (trial_fe.GetDim() == 2 && test_fe.GetDim() == 2 &&
|
||||
trial_fe.GetRangeType() == mfem::FiniteElement::SCALAR &&
|
||||
trial_fe.GetDerivType() == mfem::FiniteElement::GRAD &&
|
||||
trial_fe.GetDerivType() == mfem::FiniteElement::GRAD &&
|
||||
test_fe.GetRangeType() == mfem::FiniteElement::SCALAR );
|
||||
}
|
||||
|
||||
@@ -1760,7 +1762,7 @@ public:
|
||||
const FiniteElement & test_fe) const
|
||||
{
|
||||
return (trial_fe.GetRangeType() == mfem::FiniteElement::SCALAR &&
|
||||
trial_fe.GetDerivType() == mfem::FiniteElement::GRAD &&
|
||||
trial_fe.GetDerivType() == mfem::FiniteElement::GRAD &&
|
||||
test_fe.GetRangeType() == mfem::FiniteElement::SCALAR );
|
||||
}
|
||||
|
||||
@@ -1793,7 +1795,7 @@ public:
|
||||
const FiniteElement & test_fe) const
|
||||
{
|
||||
return (trial_fe.GetRangeType() == mfem::FiniteElement::SCALAR &&
|
||||
trial_fe.GetDerivType() == mfem::FiniteElement::GRAD &&
|
||||
trial_fe.GetDerivType() == mfem::FiniteElement::GRAD &&
|
||||
test_fe.GetRangeType() == mfem::FiniteElement::VECTOR &&
|
||||
test_fe.GetDerivType() == mfem::FiniteElement::DIV );
|
||||
}
|
||||
@@ -1832,7 +1834,7 @@ public:
|
||||
const FiniteElement & test_fe) const
|
||||
{
|
||||
return (trial_fe.GetRangeType() == mfem::FiniteElement::VECTOR &&
|
||||
trial_fe.GetDerivType() == mfem::FiniteElement::DIV &&
|
||||
trial_fe.GetDerivType() == mfem::FiniteElement::DIV &&
|
||||
test_fe.GetRangeType() == mfem::FiniteElement::SCALAR &&
|
||||
test_fe.GetDerivType() == mfem::FiniteElement::GRAD
|
||||
);
|
||||
@@ -1973,7 +1975,7 @@ protected:
|
||||
const FiniteElement & test_fe) const override
|
||||
{
|
||||
return (trial_fe.GetCurlDim() == 3 && test_fe.GetRangeDim() == 3 &&
|
||||
trial_fe.GetDerivType() == mfem::FiniteElement::CURL &&
|
||||
trial_fe.GetDerivType() == mfem::FiniteElement::CURL &&
|
||||
test_fe.GetRangeType() == mfem::FiniteElement::VECTOR );
|
||||
}
|
||||
|
||||
@@ -2494,8 +2496,7 @@ private:
|
||||
#endif
|
||||
|
||||
public:
|
||||
ConvectionIntegrator(VectorCoefficient &q, real_t a = 1.0)
|
||||
: Q(&q) { alpha = a; }
|
||||
ConvectionIntegrator(VectorCoefficient &q, real_t a = 1.0);
|
||||
|
||||
void AssembleElementMatrix(const FiniteElement &,
|
||||
ElementTransformation &,
|
||||
@@ -2528,6 +2529,28 @@ public:
|
||||
|
||||
bool SupportsCeed() const override { return DeviceCanUseCeed(); }
|
||||
|
||||
/// arguments: NE, B, G, Bt, Gt, pa_data, x, y, D1D, Q1D
|
||||
using ApplyKernelType = void (*)(const int, const Array<real_t> &,
|
||||
const Array<real_t> &,
|
||||
const Array<real_t> &,
|
||||
const Array<real_t> &, const Vector &,
|
||||
const Vector &, Vector &, const int,
|
||||
const int);
|
||||
|
||||
/// arguments: DIMS, D1D, Q1D
|
||||
MFEM_REGISTER_KERNELS(ApplyPAKernels, ApplyKernelType, (int, int, int));
|
||||
/// arguments: DIMS, D1D, Q1D
|
||||
MFEM_REGISTER_KERNELS(ApplyPATKernels, ApplyKernelType, (int, int, int));
|
||||
|
||||
template <int DIM, int D1D, int Q1D>
|
||||
static void AddSpecialization()
|
||||
{
|
||||
ApplyPAKernels::Specialization<DIM, D1D, Q1D>::Add();
|
||||
ApplyPATKernels::Specialization<DIM, D1D, Q1D>::Add();
|
||||
}
|
||||
|
||||
struct Kernels { Kernels(); };
|
||||
|
||||
protected:
|
||||
const IntegrationRule* GetDefaultIntegrationRule(
|
||||
const FiniteElement& trial_fe,
|
||||
@@ -2798,15 +2821,13 @@ protected:
|
||||
bool symmetric = true; ///< False if using a nonsymmetric matrix coefficient
|
||||
|
||||
public:
|
||||
CurlCurlIntegrator() { Q = NULL; DQ = NULL; MQ = NULL; }
|
||||
CurlCurlIntegrator();
|
||||
/// Construct a bilinear form integrator for Nedelec elements
|
||||
CurlCurlIntegrator(Coefficient &q, const IntegrationRule *ir = NULL) :
|
||||
BilinearFormIntegrator(ir), Q(&q), DQ(NULL), MQ(NULL) { }
|
||||
CurlCurlIntegrator(Coefficient &q, const IntegrationRule *ir = nullptr);
|
||||
CurlCurlIntegrator(DiagonalMatrixCoefficient &dq,
|
||||
const IntegrationRule *ir = NULL) :
|
||||
BilinearFormIntegrator(ir), Q(NULL), DQ(&dq), MQ(NULL) { }
|
||||
CurlCurlIntegrator(MatrixCoefficient &mq, const IntegrationRule *ir = NULL) :
|
||||
BilinearFormIntegrator(ir), Q(NULL), DQ(NULL), MQ(&mq) { }
|
||||
const IntegrationRule *ir = nullptr);
|
||||
CurlCurlIntegrator(MatrixCoefficient &mq,
|
||||
const IntegrationRule *ir = nullptr);
|
||||
|
||||
/* Given a particular Finite Element, compute the
|
||||
element curl-curl matrix elmat */
|
||||
@@ -2836,6 +2857,34 @@ public:
|
||||
void AssembleDiagonalPA(Vector& diag) override;
|
||||
|
||||
const Coefficient *GetCoefficient() const { return Q; }
|
||||
|
||||
/// arguments: d1d, q1d, symmetric, NE, bo, bc, bot, bct, gc, gct, pa_data,
|
||||
/// x, y, useAbs
|
||||
using ApplyKernelType = void (*)(
|
||||
const int, const int, const bool, const int, const Array<real_t> &,
|
||||
const Array<real_t> &, const Array<real_t> &, const Array<real_t> &,
|
||||
const Array<real_t> &, const Array<real_t> &, const Vector &,
|
||||
const Vector &, Vector &, const bool);
|
||||
|
||||
/// arguments: d1d, q1d, symmetric, ne, Bo, Bc, Go, Gc, pa_data, diag
|
||||
using DiagonalKernelType = void (*)(const int, const int, const bool,
|
||||
const int, const Array<real_t> &,
|
||||
const Array<real_t> &,
|
||||
const Array<real_t> &,
|
||||
const Array<real_t> &, const Vector &,
|
||||
Vector &);
|
||||
|
||||
/// parameters: dim, d1d, q1d
|
||||
MFEM_REGISTER_KERNELS(ApplyPAKernels, ApplyKernelType, (int, int, int));
|
||||
/// parameters: dim, d1d, q1d
|
||||
MFEM_REGISTER_KERNELS(DiagonalPAKernels, DiagonalKernelType, (int, int, int));
|
||||
struct Kernels { Kernels(); };
|
||||
|
||||
template <int DIM, int D1D, int Q1D> static void AddSpecialization()
|
||||
{
|
||||
ApplyPAKernels::Specialization<DIM, D1D, Q1D>::Add();
|
||||
DiagonalPAKernels::Specialization<DIM, D1D, Q1D>::Add();
|
||||
}
|
||||
};
|
||||
|
||||
/** Integrator for $(\mathrm{curl}(u), \mathrm{curl}(v))$ for FE spaces defined by 'dim' copies of a
|
||||
@@ -3089,21 +3138,18 @@ private:
|
||||
Vector vcoeff;
|
||||
|
||||
public:
|
||||
VectorDiffusionIntegrator() { }
|
||||
VectorDiffusionIntegrator(const IntegrationRule *ir = nullptr);
|
||||
|
||||
/** \brief Integrator with unit coefficient for caller-specified vector
|
||||
dimension.
|
||||
|
||||
If the vector dimension does not match the true dimension of the space,
|
||||
the resulting element matrix will be mathematically invalid. */
|
||||
VectorDiffusionIntegrator(int vector_dimension)
|
||||
: vdim(vector_dimension) { }
|
||||
VectorDiffusionIntegrator(int vector_dimension);
|
||||
|
||||
VectorDiffusionIntegrator(Coefficient &q)
|
||||
: Q(&q) { }
|
||||
VectorDiffusionIntegrator(Coefficient &q);
|
||||
|
||||
VectorDiffusionIntegrator(Coefficient &q, const IntegrationRule *ir)
|
||||
: BilinearFormIntegrator(ir), Q(&q) { }
|
||||
VectorDiffusionIntegrator(Coefficient &q, const IntegrationRule *ir);
|
||||
|
||||
/** \brief Integrator with scalar coefficient for caller-specified vector
|
||||
dimension.
|
||||
@@ -3113,8 +3159,7 @@ public:
|
||||
|
||||
If the vector dimension does not match the true dimension of the space,
|
||||
the resulting element matrix will be mathematically invalid. */
|
||||
VectorDiffusionIntegrator(Coefficient &q, int vector_dimension)
|
||||
: Q(&q), vdim(vector_dimension) { }
|
||||
VectorDiffusionIntegrator(Coefficient &q, int vector_dimension);
|
||||
|
||||
/** \brief Integrator with \c VectorCoefficient. The vector dimension of the
|
||||
\c FiniteElementSpace is assumed to be the same as the dimension of the
|
||||
@@ -3125,8 +3170,7 @@ public:
|
||||
|
||||
If the vector dimension does not match the true dimension of the space,
|
||||
the resulting element matrix will be mathematically invalid. */
|
||||
VectorDiffusionIntegrator(VectorCoefficient &vq)
|
||||
: VQ(&vq), vdim(vq.GetVDim()) { }
|
||||
VectorDiffusionIntegrator(VectorCoefficient &vq);
|
||||
|
||||
/** \brief Integrator with \c MatrixCoefficient. The vector dimension of the
|
||||
\c FiniteElementSpace is assumed to be the same as the dimension of the
|
||||
@@ -3137,8 +3181,7 @@ public:
|
||||
|
||||
If the vector dimension does not match the true dimension of the space,
|
||||
the resulting element matrix will be mathematically invalid. */
|
||||
VectorDiffusionIntegrator(MatrixCoefficient& mq)
|
||||
: MQ(&mq), vdim(mq.GetVDim()) { }
|
||||
VectorDiffusionIntegrator(MatrixCoefficient& mq);
|
||||
|
||||
void AssembleElementMatrix(const FiniteElement &el,
|
||||
ElementTransformation &Trans,
|
||||
@@ -3154,6 +3197,28 @@ public:
|
||||
void AddMultPA(const Vector &x, Vector &y) const override;
|
||||
void AddMultMF(const Vector &x, Vector &y) const override;
|
||||
bool SupportsCeed() const override { return DeviceCanUseCeed(); }
|
||||
|
||||
/// arguments: ne, B, G, Bt, Gt, pa_data, x, y, d1d, q1d, vdim
|
||||
using ApplyKernelType = void (*)(const int, const Array<real_t> &,
|
||||
const Array<real_t> &,
|
||||
const Array<real_t> &,
|
||||
const Array<real_t> &, const Vector &,
|
||||
const Vector &, Vector &, const int,
|
||||
const int, const int);
|
||||
|
||||
/// arguments: dim, vdim, d1d, q1d
|
||||
MFEM_REGISTER_KERNELS(ApplyPAKernels, ApplyKernelType, (int, int, int, int));
|
||||
|
||||
template <int DIM, int VDIM, int D1D, int Q1D>
|
||||
static void AddSpecialization()
|
||||
{
|
||||
ApplyPAKernels::Specialization<DIM, VDIM, D1D, Q1D>::Add();
|
||||
}
|
||||
|
||||
struct Kernels
|
||||
{
|
||||
Kernels();
|
||||
};
|
||||
};
|
||||
|
||||
/** Integrator for the linear elasticity form:
|
||||
@@ -3307,8 +3372,8 @@ public:
|
||||
class DGTraceIntegrator : public BilinearFormIntegrator
|
||||
{
|
||||
protected:
|
||||
Coefficient *rho;
|
||||
VectorCoefficient *u;
|
||||
Coefficient *rho = nullptr;
|
||||
VectorCoefficient *u = nullptr;
|
||||
real_t alpha, beta;
|
||||
// PA extension
|
||||
Vector pa_data;
|
||||
@@ -3321,17 +3386,16 @@ private:
|
||||
Vector tr_shape1, te_shape1, tr_shape2, te_shape2;
|
||||
|
||||
public:
|
||||
DGTraceIntegrator(real_t a, real_t b);
|
||||
|
||||
/// Construct integrator with $\rho = 1$, $\beta = \alpha/2$.
|
||||
DGTraceIntegrator(VectorCoefficient &u_, real_t a)
|
||||
{ rho = NULL; u = &u_; alpha = a; beta = 0.5*a; }
|
||||
DGTraceIntegrator(VectorCoefficient &u_, real_t a);
|
||||
|
||||
/// Construct integrator with $\rho = 1$.
|
||||
DGTraceIntegrator(VectorCoefficient &u_, real_t a, real_t b)
|
||||
{ rho = NULL; u = &u_; alpha = a; beta = b; }
|
||||
DGTraceIntegrator(VectorCoefficient &u_, real_t a, real_t b);
|
||||
|
||||
DGTraceIntegrator(Coefficient &rho_, VectorCoefficient &u_,
|
||||
real_t a, real_t b)
|
||||
{ rho = &rho_; u = &u_; alpha = a; beta = b; }
|
||||
real_t a, real_t b);
|
||||
|
||||
using BilinearFormIntegrator::AssembleFaceMatrix;
|
||||
void AssembleFaceMatrix(const FiniteElement &el1,
|
||||
@@ -3370,6 +3434,26 @@ public:
|
||||
static const IntegrationRule &GetRule(Geometry::Type geom, int order,
|
||||
const ElementTransformation &T);
|
||||
|
||||
/// arguments: nf, B, Bt, pa_data, x, y, dofs1D, quad1D
|
||||
using ApplyKernelType = void (*)(const int, const Array<real_t> &,
|
||||
const Array<real_t> &, const Vector &,
|
||||
const Vector &, Vector &, const int,
|
||||
const int);
|
||||
|
||||
/// arguments: DIM, d1d, q1d
|
||||
MFEM_REGISTER_KERNELS(ApplyPAKernels, ApplyKernelType, (int, int, int));
|
||||
/// arguments: DIM, d1d, q1d
|
||||
MFEM_REGISTER_KERNELS(ApplyPATKernels, ApplyKernelType, (int, int, int));
|
||||
|
||||
template <int DIM, int D1D, int Q1D> static void AddSpecialization()
|
||||
{
|
||||
ApplyPAKernels::Specialization<DIM, D1D, Q1D>::Add();
|
||||
ApplyPATKernels::Specialization<DIM, D1D, Q1D>::Add();
|
||||
}
|
||||
|
||||
struct Kernels { Kernels(); };
|
||||
|
||||
|
||||
private:
|
||||
void SetupPA(const FiniteElementSpace &fes, FaceType type);
|
||||
};
|
||||
@@ -3416,8 +3500,8 @@ public:
|
||||
class DGDiffusionIntegrator : public BilinearFormIntegrator
|
||||
{
|
||||
protected:
|
||||
Coefficient *Q;
|
||||
MatrixCoefficient *MQ;
|
||||
Coefficient *Q = nullptr;
|
||||
MatrixCoefficient *MQ = nullptr;
|
||||
real_t sigma, kappa;
|
||||
|
||||
// these are not thread-safe!
|
||||
@@ -3432,15 +3516,11 @@ protected:
|
||||
IntegrationRules irs{0, Quadrature1D::GaussLobatto};
|
||||
|
||||
public:
|
||||
DGDiffusionIntegrator(const real_t s, const real_t k)
|
||||
: Q(NULL), MQ(NULL), sigma(s), kappa(k) { }
|
||||
DGDiffusionIntegrator(Coefficient &q, const real_t s, const real_t k)
|
||||
: Q(&q), MQ(NULL), sigma(s), kappa(k) { }
|
||||
DGDiffusionIntegrator(MatrixCoefficient &q, const real_t s, const real_t k)
|
||||
: Q(NULL), MQ(&q), sigma(s), kappa(k) { }
|
||||
DGDiffusionIntegrator(const real_t s, const real_t k);
|
||||
DGDiffusionIntegrator(Coefficient &q, const real_t s, const real_t k);
|
||||
DGDiffusionIntegrator(MatrixCoefficient &q, const real_t s, const real_t k);
|
||||
using BilinearFormIntegrator::AssembleFaceMatrix;
|
||||
void AssembleFaceMatrix(const FiniteElement &el1,
|
||||
const FiniteElement &el2,
|
||||
void AssembleFaceMatrix(const FiniteElement &el1, const FiniteElement &el2,
|
||||
FaceElementTransformations &Trans,
|
||||
DenseMatrix &elmat) override;
|
||||
|
||||
@@ -3459,6 +3539,28 @@ public:
|
||||
|
||||
const IntegrationRule &GetRule(int order, Geometry::Type geom);
|
||||
|
||||
real_t GetPenaltyParameter() const { return kappa; }
|
||||
|
||||
/// arguments: nf, B, Bt, G, Gt, sigma, pa_data, x, dxdn, y, dydn, dofs1D,
|
||||
/// quad1D
|
||||
using ApplyKernelType = void (*)(const int, const Array<real_t> &,
|
||||
const Array<real_t> &,
|
||||
const Array<real_t> &,
|
||||
const Array<real_t> &, const real_t,
|
||||
const Vector &, const Vector &_,
|
||||
const Vector &, Vector &, Vector &,
|
||||
const int, const int);
|
||||
|
||||
/// arguments: DIM, d1d, q1d
|
||||
MFEM_REGISTER_KERNELS(ApplyPAKernels, ApplyKernelType, (int, int, int));
|
||||
|
||||
template <int DIM, int D1D, int Q1D> static void AddSpecialization()
|
||||
{
|
||||
ApplyPAKernels::Specialization<DIM, D1D, Q1D>::Add();
|
||||
}
|
||||
|
||||
struct Kernels { Kernels(); };
|
||||
|
||||
private:
|
||||
void SetupPA(const FiniteElementSpace &fes, FaceType type);
|
||||
};
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
// 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 <ceed/types.h>
|
||||
|
||||
/// A structure used to pass additional data to f_build_conv and f_apply_conv
|
||||
struct ConvectionContext {
|
||||
@@ -91,7 +92,7 @@ CEED_QFUNCTION(f_build_conv_const)(void *ctx, CeedInt Q,
|
||||
}
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
return CEED_ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
/// libCEED Q-function for building quadrature data for a convection operator
|
||||
@@ -167,7 +168,7 @@ CEED_QFUNCTION(f_build_conv_quad)(void *ctx, CeedInt Q,
|
||||
}
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
return CEED_ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
/// libCEED Q-function for applying a conv operator
|
||||
@@ -233,7 +234,7 @@ CEED_QFUNCTION(f_apply_conv)(void *ctx, CeedInt Q,
|
||||
}
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
return CEED_ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
/// libCEED Q-function for applying a conv operator
|
||||
@@ -381,7 +382,7 @@ CEED_QFUNCTION(f_apply_conv_mf_const)(void *ctx, CeedInt Q,
|
||||
}
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
return CEED_ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
CEED_QFUNCTION(f_apply_conv_mf_quad)(void *ctx, CeedInt Q,
|
||||
@@ -525,5 +526,5 @@ CEED_QFUNCTION(f_apply_conv_mf_quad)(void *ctx, CeedInt Q,
|
||||
}
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
return CEED_ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
// 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 <ceed/types.h>
|
||||
|
||||
/// A structure used to pass additional data to f_build_diff and f_apply_diff
|
||||
struct DiffusionContext { CeedInt dim, space_dim, vdim; CeedScalar coeff; };
|
||||
@@ -85,7 +85,7 @@ CEED_QFUNCTION(f_build_diff_const)(void *ctx, CeedInt Q,
|
||||
}
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
return CEED_ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
/// libCEED Q-function for building quadrature data for a diffusion operator
|
||||
@@ -161,7 +161,7 @@ CEED_QFUNCTION(f_build_diff_quad)(void *ctx, CeedInt Q,
|
||||
}
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
return CEED_ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
/// libCEED Q-function for applying a diff operator
|
||||
@@ -241,7 +241,7 @@ CEED_QFUNCTION(f_apply_diff)(void *ctx, CeedInt Q,
|
||||
}
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
return CEED_ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
/// libCEED Q-function for applying a diff operator
|
||||
@@ -394,7 +394,7 @@ CEED_QFUNCTION(f_apply_diff_mf_const)(void *ctx, CeedInt Q,
|
||||
}
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
return CEED_ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
CEED_QFUNCTION(f_apply_diff_mf_quad)(void *ctx, CeedInt Q,
|
||||
@@ -549,5 +549,5 @@ CEED_QFUNCTION(f_apply_diff_mf_quad)(void *ctx, CeedInt Q,
|
||||
}
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
return CEED_ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
// 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 <ceed/types.h>
|
||||
|
||||
/// A structure used to pass additional data to f_build_diff and f_apply_diff
|
||||
struct MassContext { CeedInt dim, space_dim, vdim; CeedScalar coeff; };
|
||||
@@ -53,7 +53,7 @@ CEED_QFUNCTION(f_build_mass_const)(void *ctx, CeedInt Q,
|
||||
}
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
return CEED_ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
/// libCEED Q-function for building quadrature data for a mass operator with a
|
||||
@@ -95,7 +95,7 @@ CEED_QFUNCTION(f_build_mass_quad)(void *ctx, CeedInt Q,
|
||||
}
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
return CEED_ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
/// libCEED Q-function for applying a mass operator
|
||||
@@ -135,7 +135,7 @@ CEED_QFUNCTION(f_apply_mass)(void *ctx, CeedInt Q,
|
||||
}
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
return CEED_ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
/// libCEED Q-function for applying a diff operator
|
||||
@@ -199,7 +199,7 @@ CEED_QFUNCTION(f_apply_mass_mf_const)(void *ctx, CeedInt Q,
|
||||
}
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
return CEED_ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
CEED_QFUNCTION(f_apply_mass_mf_quad)(void *ctx, CeedInt Q,
|
||||
@@ -266,5 +266,5 @@ CEED_QFUNCTION(f_apply_mass_mf_quad)(void *ctx, CeedInt Q,
|
||||
}
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
return CEED_ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
// 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 <ceed/types.h>
|
||||
|
||||
/// A structure used to pass additional data to f_build_conv and f_apply_conv
|
||||
struct NLConvectionContext { CeedInt dim, space_dim, vdim; CeedScalar coeff; };
|
||||
@@ -87,7 +88,7 @@ CEED_QFUNCTION(f_build_conv_const)(void *ctx, CeedInt Q,
|
||||
}
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
return CEED_ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
/// libCEED Q-function for building quadrature data for a convection operator
|
||||
@@ -167,7 +168,7 @@ CEED_QFUNCTION(f_build_conv_quad)(void *ctx, CeedInt Q,
|
||||
}
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
return CEED_ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
/// libCEED Q-function for applying a conv operator
|
||||
@@ -247,7 +248,7 @@ CEED_QFUNCTION(f_apply_conv)(void *ctx, CeedInt Q,
|
||||
}
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
return CEED_ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
/// libCEED Q-function for applying a conv operator
|
||||
@@ -362,7 +363,7 @@ CEED_QFUNCTION(f_apply_conv_mf_const)(void *ctx, CeedInt Q,
|
||||
}
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
return CEED_ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
CEED_QFUNCTION(f_apply_conv_mf_quad)(void *ctx, CeedInt Q,
|
||||
@@ -475,5 +476,5 @@ CEED_QFUNCTION(f_apply_conv_mf_quad)(void *ctx, CeedInt Q,
|
||||
}
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
return CEED_ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -18,10 +18,21 @@
|
||||
|
||||
#include <ceed.h>
|
||||
|
||||
#if !CEED_VERSION_GE(0,12,0)
|
||||
#if !CEED_VERSION_GE(0, 12, 0)
|
||||
#error MFEM requires a libCEED version >= 0.12.0
|
||||
#endif
|
||||
|
||||
#if !CEED_VERSION_GE(0, 13, 0)
|
||||
#define CeedOperatorCreateComposite(ceed, op) \
|
||||
CeedCompositeOperatorCreate((ceed), (op))
|
||||
#define CeedOperatorCompositeAddSub(op, sub) \
|
||||
CeedCompositeOperatorAddSub((op), (sub))
|
||||
#define CeedOperatorCompositeGetNumSub(op, num) \
|
||||
CeedCompositeOperatorGetNumSub((op), (num))
|
||||
#define CeedOperatorCompositeGetSubList(op, list) \
|
||||
CeedCompositeOperatorGetSubList((op), (list))
|
||||
#endif
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
|
||||
@@ -83,7 +83,7 @@ public:
|
||||
}
|
||||
|
||||
// Create composite CeedOperator
|
||||
CeedCompositeOperatorCreate(internal::ceed, &oper);
|
||||
CeedOperatorCreateComposite(internal::ceed, &oper);
|
||||
|
||||
// Create each sub-CeedOperator
|
||||
sub_ops.reserve(element_indices.size());
|
||||
@@ -101,7 +101,7 @@ public:
|
||||
int nelem = *count[value.first];
|
||||
sub_op->Assemble(info, fes, ir, nelem, indices, Q);
|
||||
sub_ops.push_back(sub_op);
|
||||
CeedCompositeOperatorAddSub(oper, sub_op->GetCeedOperator());
|
||||
CeedOperatorCompositeAddSub(oper, sub_op->GetCeedOperator());
|
||||
}
|
||||
|
||||
const int ndofs = fes.GetVDim() * fes.GetNDofs();
|
||||
|
||||
@@ -140,11 +140,7 @@ int CeedOperatorGetActiveField(CeedOperator oper, CeedOperatorField *field)
|
||||
CeedOperator *subops;
|
||||
if (isComposite)
|
||||
{
|
||||
#if CEED_VERSION_GE(0, 10, 2)
|
||||
ierr = CeedCompositeOperatorGetSubList(oper, &subops); PCeedChk(ierr);
|
||||
#else
|
||||
ierr = CeedOperatorGetSubList(oper, &subops); PCeedChk(ierr);
|
||||
#endif
|
||||
ierr = CeedOperatorCompositeGetSubList(oper, &subops); PCeedChk(ierr);
|
||||
ierr = CeedOperatorGetQFunction(subops[0], &qf); PCeedChk(ierr);
|
||||
}
|
||||
else
|
||||
@@ -171,7 +167,11 @@ int CeedOperatorGetActiveField(CeedOperator oper, CeedOperatorField *field)
|
||||
for (int i = 0; i < numinputfields; ++i)
|
||||
{
|
||||
ierr = CeedOperatorFieldGetVector(inputfields[i], &if_vector); PCeedChk(ierr);
|
||||
if (if_vector == CEED_VECTOR_ACTIVE)
|
||||
bool is_active = if_vector == CEED_VECTOR_ACTIVE;
|
||||
#if CEED_VERSION_GE(0, 13, 0)
|
||||
ierr = CeedVectorDestroy(&if_vector); PCeedChk(ierr);
|
||||
#endif
|
||||
if (is_active)
|
||||
{
|
||||
if (found)
|
||||
{
|
||||
|
||||
@@ -228,7 +228,7 @@ void AddToCompositeOperator(BilinearFormIntegrator *integ, CeedOperator op)
|
||||
{
|
||||
if (integ->SupportsCeed())
|
||||
{
|
||||
CeedCompositeOperatorAddSub(op, integ->GetCeedOp().GetCeedOperator());
|
||||
CeedOperatorCompositeAddSub(op, integ->GetCeedOp().GetCeedOperator());
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -240,7 +240,7 @@ CeedOperator CreateCeedCompositeOperatorFromBilinearForm(BilinearForm &form)
|
||||
{
|
||||
int ierr;
|
||||
CeedOperator op;
|
||||
ierr = CeedCompositeOperatorCreate(internal::ceed, &op); PCeedChk(ierr);
|
||||
ierr = CeedOperatorCreateComposite(internal::ceed, &op); PCeedChk(ierr);
|
||||
|
||||
MFEM_VERIFY(form.GetBBFI()->Size() == 0,
|
||||
"Not implemented for this integrator!");
|
||||
@@ -271,18 +271,13 @@ CeedOperator CoarsenCeedCompositeOperator(
|
||||
MFEM_ASSERT(isComposite, "");
|
||||
|
||||
CeedOperator op_coarse;
|
||||
ierr = CeedCompositeOperatorCreate(internal::ceed,
|
||||
ierr = CeedOperatorCreateComposite(internal::ceed,
|
||||
&op_coarse); PCeedChk(ierr);
|
||||
|
||||
int nsub;
|
||||
CeedOperator *subops;
|
||||
#if CEED_VERSION_GE(0, 10, 2)
|
||||
ierr = CeedCompositeOperatorGetNumSub(op, &nsub); PCeedChk(ierr);
|
||||
ierr = CeedCompositeOperatorGetSubList(op, &subops); PCeedChk(ierr);
|
||||
#else
|
||||
ierr = CeedOperatorGetNumSub(op, &nsub); PCeedChk(ierr);
|
||||
ierr = CeedOperatorGetSubList(op, &subops); PCeedChk(ierr);
|
||||
#endif
|
||||
ierr = CeedOperatorCompositeGetNumSub(op, &nsub); PCeedChk(ierr);
|
||||
ierr = CeedOperatorCompositeGetSubList(op, &subops); PCeedChk(ierr);
|
||||
for (int isub=0; isub<nsub; ++isub)
|
||||
{
|
||||
CeedOperator subop = subops[isub];
|
||||
@@ -294,7 +289,7 @@ CeedOperator CoarsenCeedCompositeOperator(
|
||||
// refcounted by existing objects
|
||||
ierr = CeedBasisDestroy(&basis_coarse); PCeedChk(ierr);
|
||||
ierr = CeedBasisDestroy(&basis_c2f); PCeedChk(ierr);
|
||||
ierr = CeedCompositeOperatorAddSub(op_coarse, subop_coarse);
|
||||
ierr = CeedOperatorCompositeAddSub(op_coarse, subop_coarse);
|
||||
PCeedChk(ierr);
|
||||
ierr = CeedOperatorDestroy(&subop_coarse); PCeedChk(ierr);
|
||||
}
|
||||
|
||||
@@ -81,12 +81,27 @@ int CeedSingleOperatorFullAssemble(CeedOperator op, SparseMatrix *out)
|
||||
ierr = CeedOperatorFieldGetVector(input_fields[i], &vec); PCeedChk(ierr);
|
||||
if (vec == CEED_VECTOR_ACTIVE)
|
||||
{
|
||||
ierr = CeedOperatorFieldGetBasis(input_fields[i], &basisin);
|
||||
PCeedChk(ierr);
|
||||
CeedBasis basis;
|
||||
ierr = CeedOperatorFieldGetBasis(input_fields[i], &basis); PCeedChk(ierr);
|
||||
if (!basisin)
|
||||
{
|
||||
ierr = CeedBasisReferenceCopy(basis, &basisin); PCeedChk(ierr);
|
||||
}
|
||||
#if CEED_VERSION_GE(0, 13, 0)
|
||||
ierr = CeedBasisDestroy(&basis); PCeedChk(ierr);
|
||||
#endif
|
||||
ierr = CeedBasisGetNumComponents(basisin, &ncomp); PCeedChk(ierr);
|
||||
ierr = CeedBasisGetDimension(basisin, &dim); PCeedChk(ierr);
|
||||
ierr = CeedOperatorFieldGetElemRestriction(input_fields[i], &rstrin);
|
||||
CeedElemRestriction rstr;
|
||||
ierr = CeedOperatorFieldGetElemRestriction(input_fields[i], &rstr);
|
||||
PCeedChk(ierr);
|
||||
if (!rstrin)
|
||||
{
|
||||
ierr = CeedElemRestrictionReferenceCopy(rstr, &rstrin); PCeedChk(ierr);
|
||||
}
|
||||
#if CEED_VERSION_GE(0, 13, 0)
|
||||
ierr = CeedElemRestrictionDestroy(&rstr); PCeedChk(ierr);
|
||||
#endif
|
||||
CeedEvalMode emode;
|
||||
ierr = CeedQFunctionFieldGetEvalMode(qffields[i], &emode);
|
||||
PCeedChk(ierr);
|
||||
@@ -112,6 +127,9 @@ int CeedSingleOperatorFullAssemble(CeedOperator op, SparseMatrix *out)
|
||||
break; // Caught by QF Assembly
|
||||
}
|
||||
}
|
||||
#if CEED_VERSION_GE(0, 13, 0)
|
||||
ierr = CeedVectorDestroy(&vec); PCeedChk(ierr);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Determine active output basis
|
||||
@@ -127,11 +145,25 @@ int CeedSingleOperatorFullAssemble(CeedOperator op, SparseMatrix *out)
|
||||
ierr = CeedOperatorFieldGetVector(output_fields[i], &vec); PCeedChk(ierr);
|
||||
if (vec == CEED_VECTOR_ACTIVE)
|
||||
{
|
||||
ierr = CeedOperatorFieldGetBasis(output_fields[i], &basisout);
|
||||
PCeedChk(ierr);
|
||||
ierr = CeedOperatorFieldGetElemRestriction(output_fields[i], &rstrout);
|
||||
PCeedChk(ierr);
|
||||
CeedBasis basis;
|
||||
ierr = CeedOperatorFieldGetBasis(output_fields[i], &basis); PCeedChk(ierr);
|
||||
if (!basisout)
|
||||
{
|
||||
ierr = CeedBasisReferenceCopy(basis, &basisout); PCeedChk(ierr);
|
||||
}
|
||||
#if CEED_VERSION_GE(0, 13, 0)
|
||||
ierr = CeedBasisDestroy(&basis); PCeedChk(ierr);
|
||||
#endif
|
||||
CeedElemRestriction rstr;
|
||||
ierr = CeedOperatorFieldGetElemRestriction(output_fields[i], &rstr);
|
||||
PCeedChk(ierr);
|
||||
if (!rstrout)
|
||||
{
|
||||
ierr = CeedElemRestrictionReferenceCopy(rstr, &rstrout); PCeedChk(ierr);
|
||||
}
|
||||
#if CEED_VERSION_GE(0, 13, 0)
|
||||
ierr = CeedElemRestrictionDestroy(&rstr); PCeedChk(ierr);
|
||||
#endif
|
||||
CeedEvalMode emode;
|
||||
ierr = CeedQFunctionFieldGetEvalMode(qffields[i], &emode);
|
||||
PCeedChk(ierr);
|
||||
@@ -157,6 +189,9 @@ int CeedSingleOperatorFullAssemble(CeedOperator op, SparseMatrix *out)
|
||||
break; // Caught by QF Assembly
|
||||
}
|
||||
}
|
||||
#if CEED_VERSION_GE(0, 13, 0)
|
||||
ierr = CeedVectorDestroy(&vec); PCeedChk(ierr);
|
||||
#endif
|
||||
}
|
||||
|
||||
CeedInt nelem, elemsize, nqpts;
|
||||
@@ -200,7 +235,11 @@ int CeedSingleOperatorFullAssemble(CeedOperator op, SparseMatrix *out)
|
||||
PCeedChk(ierr);
|
||||
|
||||
CeedInt layout[3];
|
||||
#if CEED_VERSION_GE(0, 13, 0)
|
||||
ierr = CeedElemRestrictionGetELayout(rstr_q, layout); PCeedChk(ierr);
|
||||
#else
|
||||
ierr = CeedElemRestrictionGetELayout(rstr_q, &layout); PCeedChk(ierr);
|
||||
#endif
|
||||
ierr = CeedElemRestrictionDestroy(&rstr_q); PCeedChk(ierr);
|
||||
|
||||
// enforce structurally symmetric for later elimination
|
||||
@@ -285,6 +324,10 @@ int CeedSingleOperatorFullAssemble(CeedOperator op, SparseMatrix *out)
|
||||
ierr = CeedVectorRestoreArrayRead(assembledqf, &assembledqfarray);
|
||||
PCeedChk(ierr);
|
||||
ierr = CeedVectorDestroy(&assembledqf); PCeedChk(ierr);
|
||||
ierr = CeedElemRestrictionDestroy(&rstrin); PCeedChk(ierr);
|
||||
ierr = CeedElemRestrictionDestroy(&rstrout); PCeedChk(ierr);
|
||||
ierr = CeedBasisDestroy(&basisin); PCeedChk(ierr);
|
||||
ierr = CeedBasisDestroy(&basisout); PCeedChk(ierr);
|
||||
ierr = CeedHackFree(&emodein); PCeedChk(ierr);
|
||||
ierr = CeedHackFree(&emodeout); PCeedChk(ierr);
|
||||
|
||||
@@ -310,13 +353,8 @@ int CeedOperatorFullAssemble(CeedOperator op, SparseMatrix **mat)
|
||||
{
|
||||
CeedInt numsub;
|
||||
CeedOperator *subops;
|
||||
#if CEED_VERSION_GE(0, 10, 2)
|
||||
CeedCompositeOperatorGetNumSub(op, &numsub);
|
||||
ierr = CeedCompositeOperatorGetSubList(op, &subops); PCeedChk(ierr);
|
||||
#else
|
||||
CeedOperatorGetNumSub(op, &numsub);
|
||||
ierr = CeedOperatorGetSubList(op, &subops); PCeedChk(ierr);
|
||||
#endif
|
||||
ierr = CeedOperatorCompositeGetNumSub(op, &numsub); PCeedChk(ierr);
|
||||
ierr = CeedOperatorCompositeGetSubList(op, &subops); PCeedChk(ierr);
|
||||
for (int i = 0; i < numsub; ++i)
|
||||
{
|
||||
ierr = CeedSingleOperatorFullAssemble(subops[i], out); PCeedChk(ierr);
|
||||
|
||||
@@ -120,7 +120,11 @@ int CeedATPMGElemRestriction(int order,
|
||||
}
|
||||
ierr = CeedVectorRestoreArray(in_lvec, &lvec_data); PCeedChk(ierr);
|
||||
CeedInt in_layout[3];
|
||||
#if CEED_VERSION_GE(0, 13, 0)
|
||||
ierr = CeedElemRestrictionGetELayout(er_in, in_layout); PCeedChk(ierr);
|
||||
#else
|
||||
ierr = CeedElemRestrictionGetELayout(er_in, &in_layout); PCeedChk(ierr);
|
||||
#endif
|
||||
if (in_layout[0] == 0 && in_layout[1] == 0 && in_layout[2] == 0)
|
||||
{
|
||||
return CeedError(ceed, 1, "Cannot interpret e-vector ordering of given"
|
||||
@@ -664,7 +668,11 @@ int CeedATPMGOperator(CeedOperator oper, int order_reduction,
|
||||
|
||||
for (int i = 0; i < numinputfields; ++i)
|
||||
{
|
||||
#if CEED_VERSION_GE(0, 13, 0)
|
||||
const char * fieldname;
|
||||
#else
|
||||
char * fieldname;
|
||||
#endif
|
||||
ierr = CeedQFunctionFieldGetName(inputqfields[i], &fieldname); PCeedChk(ierr);
|
||||
if (if_vector[i] == CEED_VECTOR_ACTIVE)
|
||||
{
|
||||
@@ -676,10 +684,19 @@ int CeedATPMGOperator(CeedOperator oper, int order_reduction,
|
||||
ierr = CeedOperatorSetField(coper, fieldname, er_input[i], basis_input[i],
|
||||
if_vector[i]); PCeedChk(ierr);
|
||||
}
|
||||
#if CEED_VERSION_GE(0, 13, 0)
|
||||
ierr = CeedVectorDestroy(&if_vector[i]); PCeedChk(ierr);
|
||||
ierr = CeedElemRestrictionDestroy(&er_input[i]); PCeedChk(ierr);
|
||||
ierr = CeedBasisDestroy(&basis_input[i]); PCeedChk(ierr);
|
||||
#endif
|
||||
}
|
||||
for (int i = 0; i < numoutputfields; ++i)
|
||||
{
|
||||
#if CEED_VERSION_GE(0, 13, 0)
|
||||
const char * fieldname;
|
||||
#else
|
||||
char * fieldname;
|
||||
#endif
|
||||
ierr = CeedQFunctionFieldGetName(outputqfields[i], &fieldname); PCeedChk(ierr);
|
||||
if (of_vector[i] == CEED_VECTOR_ACTIVE)
|
||||
{
|
||||
@@ -691,6 +708,11 @@ int CeedATPMGOperator(CeedOperator oper, int order_reduction,
|
||||
ierr = CeedOperatorSetField(coper, fieldname, er_output[i], basis_output[i],
|
||||
of_vector[i]); PCeedChk(ierr);
|
||||
}
|
||||
#if CEED_VERSION_GE(0, 13, 0)
|
||||
ierr = CeedVectorDestroy(&of_vector[i]); PCeedChk(ierr);
|
||||
ierr = CeedElemRestrictionDestroy(&er_output[i]); PCeedChk(ierr);
|
||||
ierr = CeedBasisDestroy(&basis_output[i]); PCeedChk(ierr);
|
||||
#endif
|
||||
}
|
||||
delete [] er_input;
|
||||
delete [] er_output;
|
||||
@@ -741,7 +763,9 @@ int CeedOperatorGetOrder(CeedOperator oper, CeedInt * order)
|
||||
int P1d;
|
||||
ierr = CeedBasisGetNumNodes1D(basis, &P1d); PCeedChk(ierr);
|
||||
*order = P1d - 1;
|
||||
|
||||
#if CEED_VERSION_GE(0, 13, 0)
|
||||
ierr = CeedBasisDestroy(&basis); PCeedChk(ierr);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
// Implementation of Coefficient class
|
||||
|
||||
#include "fem.hpp"
|
||||
#include "../general/forall.hpp"
|
||||
|
||||
#include <cmath>
|
||||
#include <limits>
|
||||
@@ -80,6 +81,49 @@ real_t PWConstCoefficient::Eval(ElementTransformation & T,
|
||||
return (constants(att-1));
|
||||
}
|
||||
|
||||
void PWConstCoefficient::Project(QuadratureFunction &qf)
|
||||
{
|
||||
auto &qs = *qf.GetSpace();
|
||||
|
||||
const bool compressed =
|
||||
qs.Offsets(QSpaceOffsetStorage::COMPRESSED).Size() == 1;
|
||||
const int *offsets = qs.Offsets(QSpaceOffsetStorage::COMPRESSED).Read();
|
||||
const int ne = qs.GetNE();
|
||||
|
||||
const int *attributes = [&]()
|
||||
{
|
||||
if (dynamic_cast<QuadratureSpace*>(&qs) != nullptr)
|
||||
{
|
||||
return qs.GetMesh()->GetElementAttributes().Read();
|
||||
}
|
||||
else if (auto *qs_f = dynamic_cast<FaceQuadratureSpace*>(&qs))
|
||||
{
|
||||
MFEM_VERIFY(qs_f->GetFaceType() == FaceType::Boundary,
|
||||
"Interior faces do not have attributes.");
|
||||
return qs.GetMesh()->GetBdrFaceAttributes().Read();
|
||||
}
|
||||
else
|
||||
{
|
||||
MFEM_ABORT("Unsupported case.");
|
||||
}
|
||||
}();
|
||||
|
||||
const real_t *d_c = constants.Read();
|
||||
real_t *d_qf = qf.Write();
|
||||
|
||||
mfem::forall(ne, [=] MFEM_HOST_DEVICE (int e)
|
||||
{
|
||||
const int a = attributes[e];
|
||||
const real_t elementConstant = d_c[a - 1];
|
||||
const int begin = compressed ? e*offsets[0] : offsets[e];
|
||||
const int end = compressed ? (e+1)*offsets[0] : offsets[e+1];
|
||||
for (int i = begin; i < end; ++i)
|
||||
{
|
||||
d_qf[i] = elementConstant;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void PWCoefficient::InitMap(const Array<int> & attr,
|
||||
const Array<Coefficient*> & coefs)
|
||||
{
|
||||
@@ -519,6 +563,26 @@ void GradientGridFunctionCoefficient::Eval(
|
||||
}
|
||||
}
|
||||
|
||||
void GradientGridFunctionCoefficient::Project(QuadratureFunction &qf)
|
||||
{
|
||||
const FiniteElementSpace &fes = *GridFunc->FESpace();
|
||||
const Mesh &mesh = *fes.GetMesh();
|
||||
const int sdim = mesh.SpaceDimension();
|
||||
const int gf_vdim = fes.GetVDim(); // assumed to be 1 in this class
|
||||
qf.SetVDim(sdim*gf_vdim);
|
||||
if (mesh.GetNE() == 0) { return; }
|
||||
// All mesh element must be the same type:
|
||||
MFEM_VERIFY(mesh.GetNumGeometries(mesh.Dimension()) == 1,
|
||||
"All mesh elements must be the same type!");
|
||||
const IntegrationRule &ir = qf.GetIntRule(0);
|
||||
// All elements must use the same quadrature rule:
|
||||
MFEM_VERIFY(qf.Size() == sdim*gf_vdim*ir.GetNPoints()*mesh.GetNE(),
|
||||
"All mesh elements must use the same quadrature rule!");
|
||||
// QuadratureFunction uses the layout qf_vdim x nq x ne, i.e.
|
||||
// gf_vdim x sdim x nq x nq, so we need to request QVectorLayout::byVDIM:
|
||||
GridFunc->GetGradients(ir, qf, QVectorLayout::byVDIM);
|
||||
}
|
||||
|
||||
CurlGridFunctionCoefficient::CurlGridFunctionCoefficient(
|
||||
const GridFunction *gf)
|
||||
: VectorCoefficient(0)
|
||||
@@ -1065,6 +1129,41 @@ real_t InnerProductCoefficient::Eval(ElementTransformation &T,
|
||||
return va * vb;
|
||||
}
|
||||
|
||||
void InnerProductCoefficient::Project(QuadratureFunction &qf)
|
||||
{
|
||||
MFEM_VERIFY(a->GetVDim() == b->GetVDim(),
|
||||
"Incompatible vector coefficients: a->GetVDim(): "
|
||||
<< a->GetVDim() << ", b->GetVDim(): " << b->GetVDim());
|
||||
|
||||
const int vdim = a->GetVDim();
|
||||
MFEM_VERIFY(vdim >= 1, "invalid vdim: " << vdim);
|
||||
|
||||
// When running on device, make sure the output data is allocated before any
|
||||
// local temporary data to reduce potential heap fragmentation:
|
||||
auto dot_d = qf.Write();
|
||||
|
||||
QuadratureFunction qf_a(qf.GetSpace(), vdim);
|
||||
QuadratureFunction qf_b(qf.GetSpace(), vdim);
|
||||
|
||||
a->Project(qf_a);
|
||||
b->Project(qf_b);
|
||||
|
||||
auto a_d = qf_a.Read();
|
||||
auto b_d = qf_b.Read();
|
||||
|
||||
mfem::forall(qf.GetSpace()->GetSize(), [=] MFEM_HOST_DEVICE (int i)
|
||||
{
|
||||
const real_t *ai = a_d + i*vdim;
|
||||
const real_t *bi = b_d + i*vdim;
|
||||
real_t dot = ai[0]*bi[0];
|
||||
for (int d = 1; d < vdim; d++)
|
||||
{
|
||||
dot += ai[d]*bi[d];
|
||||
}
|
||||
dot_d[i] = dot;
|
||||
});
|
||||
}
|
||||
|
||||
VectorRotProductCoefficient::VectorRotProductCoefficient(VectorCoefficient &A,
|
||||
VectorCoefficient &B)
|
||||
: a(&A), b(&B), va(A.GetVDim()), vb(B.GetVDim())
|
||||
|
||||
@@ -132,6 +132,9 @@ public:
|
||||
/// Evaluate the coefficient.
|
||||
real_t Eval(ElementTransformation &T,
|
||||
const IntegrationPoint &ip) override;
|
||||
|
||||
/// Fill the QuadratureFunction @a qf with the piecewise constant values.
|
||||
void Project(QuadratureFunction &qf) override;
|
||||
};
|
||||
|
||||
/** @brief A piecewise coefficient with the pieces keyed off the element
|
||||
@@ -894,6 +897,9 @@ public:
|
||||
void Eval(DenseMatrix &M, ElementTransformation &T,
|
||||
const IntegrationRule &ir) override;
|
||||
|
||||
/// @copydoc VectorCoefficient::Project(QuadratureFunction &)
|
||||
void Project(QuadratureFunction &qf) override;
|
||||
|
||||
virtual ~GradientGridFunctionCoefficient() { }
|
||||
};
|
||||
|
||||
@@ -1771,6 +1777,9 @@ public:
|
||||
/// Evaluate the coefficient at @a ip.
|
||||
real_t Eval(ElementTransformation &T,
|
||||
const IntegrationPoint &ip) override;
|
||||
|
||||
/// @copydoc Coefficient::Project(QuadratureFunction &)
|
||||
void Project(QuadratureFunction &qf) override;
|
||||
};
|
||||
|
||||
/// Scalar coefficient defined as a cross product of two vectors in the xy-plane.
|
||||
|
||||
@@ -912,7 +912,7 @@ ConduitDataCollection::GridFunctionToBlueprintField(mfem::GridFunction *gf,
|
||||
|
||||
if (vdim == 1) // scalar case
|
||||
{
|
||||
n_field["values"].set_external(gf->GetData(),
|
||||
n_field["values"].set_external(const_cast<real_t *>(gf->HostRead()),
|
||||
ndofs);
|
||||
}
|
||||
else // vector case
|
||||
@@ -925,18 +925,18 @@ ConduitDataCollection::GridFunctionToBlueprintField(mfem::GridFunction *gf,
|
||||
int vdim_stride = (ordering == Ordering::byNODES ? ndofs : 1);
|
||||
|
||||
index_t offset = 0;
|
||||
index_t stride = sizeof(double) * entry_stride;
|
||||
index_t stride = sizeof(real_t) * entry_stride;
|
||||
|
||||
for (int d = 0; d < vdim; d++)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << "v" << d;
|
||||
std::string comp_name = oss.str();
|
||||
n_field["values"][comp_name].set_external(gf->GetData(),
|
||||
n_field["values"][comp_name].set_external(const_cast<real_t *>(gf->HostRead()),
|
||||
ndofs,
|
||||
offset,
|
||||
stride);
|
||||
offset += sizeof(double) * vdim_stride;
|
||||
offset += sizeof(real_t) * vdim_stride;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,266 @@
|
||||
// Copyright (c) 2010-2025, 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 "derefmat_op.hpp"
|
||||
#include "fes_kernels.hpp"
|
||||
|
||||
/// \cond DO_NOT_DOCUMENT
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
namespace internal
|
||||
{
|
||||
template <Ordering::Type Order, bool Atomic>
|
||||
static void DerefMultKernelImpl(const DerefineMatrixOp &op, const Vector &x,
|
||||
Vector &y)
|
||||
{
|
||||
DerefineMatrixOpMultFunctor<Order, Atomic> func;
|
||||
func.xptr = x.Read();
|
||||
y.UseDevice();
|
||||
y = 0.;
|
||||
func.yptr = y.ReadWrite();
|
||||
func.bsptr = op.block_storage.Read();
|
||||
func.boptr = op.block_offsets.Read();
|
||||
func.brptr = op.block_row_idcs_offsets.Read();
|
||||
func.bcptr = op.block_col_idcs_offsets.Read();
|
||||
func.rptr = op.row_idcs.Read();
|
||||
func.cptr = op.col_idcs.Read();
|
||||
func.vdims = op.fespace->GetVDim();
|
||||
func.nblocks = op.block_offsets.Size();
|
||||
func.width = op.Width() / func.vdims;
|
||||
func.height = op.Height() / func.vdims;
|
||||
func.Run(op.max_rows);
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
DerefineMatrixOp::DerefineMatrixOp(FiniteElementSpace &fespace_, int old_ndofs,
|
||||
const Table *old_elem_dof,
|
||||
const Table *old_elem_fos)
|
||||
: Operator(fespace_.GetVSize(), old_ndofs * fespace_.GetVDim()),
|
||||
fespace(&fespace_)
|
||||
{
|
||||
static Kernels kernels;
|
||||
constexpr int max_team_size = 256;
|
||||
/// TODO: Implement DofTransformation support
|
||||
|
||||
MFEM_VERIFY(fespace->Nonconforming(),
|
||||
"Not implemented for conforming meshes.");
|
||||
MFEM_VERIFY(old_ndofs, "Missing previous (finer) space.");
|
||||
MFEM_VERIFY(fespace->GetNDofs() <= old_ndofs,
|
||||
"Previous space is not finer.");
|
||||
|
||||
const CoarseFineTransformations &dtrans =
|
||||
fespace->GetMesh()->ncmesh->GetDerefinementTransforms();
|
||||
|
||||
MFEM_ASSERT(dtrans.embeddings.Size() == old_elem_dof->Size(), "");
|
||||
|
||||
const bool is_dg = fespace->FEColl()->GetContType()
|
||||
== FiniteElementCollection::DISCONTINUOUS;
|
||||
DenseMatrix localRVO; // for variable-order only
|
||||
|
||||
DenseTensor localR[Geometry::NumGeom];
|
||||
int total_rows = 0;
|
||||
int total_cols = 0;
|
||||
block_offsets.SetSize(dtrans.embeddings.Size());
|
||||
block_offsets.HostWrite();
|
||||
if (fespace->IsVariableOrder())
|
||||
{
|
||||
// TODO: any potential for some compression here?
|
||||
// determine storage size and offsets
|
||||
block_offsets[0] = 0;
|
||||
int total_size = 0;
|
||||
for (int k = 0; k < dtrans.embeddings.Size(); ++k)
|
||||
{
|
||||
const Embedding &emb = dtrans.embeddings[k];
|
||||
const FiniteElement *fe = fespace->GetFE(emb.parent);
|
||||
const int ldof = fe->GetDof();
|
||||
if (k + 1 < dtrans.embeddings.Size())
|
||||
{
|
||||
block_offsets[k + 1] = block_offsets[k] + ldof * ldof;
|
||||
}
|
||||
total_rows += ldof;
|
||||
total_cols += ldof;
|
||||
total_size += ldof * ldof;
|
||||
}
|
||||
block_storage.SetSize(total_size);
|
||||
}
|
||||
else
|
||||
{
|
||||
// compression scheme:
|
||||
// block_offsets is the start of each block, potentially repeated
|
||||
// only need to store localR for used shapes
|
||||
Mesh::GeometryList elem_geoms(*fespace->GetMesh());
|
||||
|
||||
int geom_offsets[Geometry::NumGeom];
|
||||
{
|
||||
int size = 0;
|
||||
for (int i = 0; i < elem_geoms.Size(); ++i)
|
||||
{
|
||||
fespace->GetLocalDerefinementMatrices(elem_geoms[i],
|
||||
localR[elem_geoms[i]]);
|
||||
geom_offsets[elem_geoms[i]] = size;
|
||||
size += localR[elem_geoms[i]].TotalSize();
|
||||
}
|
||||
block_storage.SetSize(size);
|
||||
// copy blocks into block_storage
|
||||
auto bs_ptr = block_storage.HostWrite();
|
||||
for (int i = 0; i < elem_geoms.Size(); ++i)
|
||||
{
|
||||
std::copy(localR[elem_geoms[i]].Data(),
|
||||
localR[elem_geoms[i]].Data()
|
||||
+ localR[elem_geoms[i]].TotalSize(),
|
||||
bs_ptr);
|
||||
bs_ptr += localR[elem_geoms[i]].TotalSize();
|
||||
}
|
||||
}
|
||||
for (int k = 0; k < dtrans.embeddings.Size(); ++k)
|
||||
{
|
||||
const Embedding &emb = dtrans.embeddings[k];
|
||||
Geometry::Type geom =
|
||||
fespace->GetMesh()->GetElementBaseGeometry(emb.parent);
|
||||
|
||||
auto size = localR[geom].SizeI() * localR[geom].SizeJ();
|
||||
total_rows += localR[geom].SizeI();
|
||||
total_cols += localR[geom].SizeJ();
|
||||
// set block offsets and sizes
|
||||
block_offsets[k] = geom_offsets[geom] + size * emb.matrix;
|
||||
}
|
||||
}
|
||||
row_idcs.SetSize(total_rows);
|
||||
row_idcs.HostWrite();
|
||||
col_idcs.SetSize(total_cols);
|
||||
col_idcs.HostWrite();
|
||||
block_row_idcs_offsets.SetSize(dtrans.embeddings.Size() + 1);
|
||||
block_row_idcs_offsets.HostWrite();
|
||||
block_col_idcs_offsets.SetSize(dtrans.embeddings.Size() + 1);
|
||||
block_col_idcs_offsets.HostWrite();
|
||||
block_row_idcs_offsets[0] = 0;
|
||||
block_col_idcs_offsets[0] = 0;
|
||||
|
||||
// compute index information
|
||||
Array<int> dofs, old_dofs;
|
||||
max_rows = 1;
|
||||
|
||||
{
|
||||
Array<int> mark(fespace->GetNDofs());
|
||||
mark = 0;
|
||||
auto bs_ptr = block_storage.HostWrite();
|
||||
int ridx = 0;
|
||||
int cidx = 0;
|
||||
int num_marked = 0;
|
||||
for (int k = 0; k < dtrans.embeddings.Size(); k++)
|
||||
{
|
||||
const Embedding &emb = dtrans.embeddings[k];
|
||||
Geometry::Type geom =
|
||||
fespace->GetMesh()->GetElementBaseGeometry(emb.parent);
|
||||
|
||||
if (fespace->IsVariableOrder())
|
||||
{
|
||||
const FiniteElement *fe = fespace->GetFE(emb.parent);
|
||||
const DenseTensor &pmats = dtrans.point_matrices[geom];
|
||||
const int ldof = fe->GetDof();
|
||||
|
||||
IsoparametricTransformation isotr;
|
||||
isotr.SetIdentityTransformation(geom);
|
||||
|
||||
localRVO.SetSize(ldof, ldof);
|
||||
isotr.SetPointMat(pmats(emb.matrix));
|
||||
// Local restriction is size ldofxldof assuming that the parent
|
||||
// and child are of same polynomial order.
|
||||
fe->GetLocalRestriction(isotr, localRVO);
|
||||
// copy block
|
||||
auto size = localRVO.Height() * localRVO.Width();
|
||||
std::copy(localRVO.Data(), localRVO.Data() + size, bs_ptr);
|
||||
bs_ptr += size;
|
||||
}
|
||||
DenseMatrix &lR =
|
||||
fespace->IsVariableOrder() ? localRVO : localR[geom](emb.matrix);
|
||||
block_row_idcs_offsets[k + 1] =
|
||||
block_row_idcs_offsets[k] + lR.Height();
|
||||
block_col_idcs_offsets[k + 1] = block_col_idcs_offsets[k] + lR.Width();
|
||||
max_rows = std::max(lR.Height(), max_rows);
|
||||
// index information
|
||||
fespace->elem_dof->GetRow(emb.parent, dofs);
|
||||
old_elem_dof->GetRow(k, old_dofs);
|
||||
MFEM_VERIFY(old_dofs.Size() == dofs.Size(),
|
||||
"Parent and child must have same #dofs.");
|
||||
for (int i = 0; i < lR.Height(); ++i, ++ridx)
|
||||
{
|
||||
if (!std::isfinite(lR(i, 0)))
|
||||
{
|
||||
row_idcs[ridx] = INT_MAX;
|
||||
continue;
|
||||
}
|
||||
int r = dofs[i];
|
||||
int m = (r >= 0) ? r : (-1 - r);
|
||||
if (is_dg || !mark[m])
|
||||
{
|
||||
row_idcs[ridx] = r;
|
||||
mark[m] = 1;
|
||||
++num_marked;
|
||||
}
|
||||
else
|
||||
{
|
||||
row_idcs[ridx] = INT_MAX;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < lR.Width(); ++i, ++cidx)
|
||||
{
|
||||
col_idcs[cidx] = old_dofs[i];
|
||||
}
|
||||
}
|
||||
if (!is_dg && !fespace->IsVariableOrder())
|
||||
{
|
||||
MFEM_VERIFY(num_marked * fespace->GetVDim() == Height(),
|
||||
"internal error: not all rows were set.");
|
||||
}
|
||||
}
|
||||
// if not using GPU, set max_rows/max_cols to zero
|
||||
if (Device::Allows(Backend::DEVICE_MASK))
|
||||
{
|
||||
max_rows = std::min(max_rows, max_team_size);
|
||||
}
|
||||
else
|
||||
{
|
||||
max_rows = 1;
|
||||
}
|
||||
}
|
||||
|
||||
void DerefineMatrixOp::Mult(const Vector &x, Vector &y) const
|
||||
{
|
||||
const bool is_dg = fespace->FEColl()->GetContType()
|
||||
== FiniteElementCollection::DISCONTINUOUS;
|
||||
// DG needs atomic summation
|
||||
MultKernel::Run(fespace->GetOrdering(), is_dg, *this, x, y);
|
||||
}
|
||||
|
||||
DerefineMatrixOp::Kernels::Kernels()
|
||||
{
|
||||
MultKernel::Specialization<Ordering::byNODES, false>::Add();
|
||||
MultKernel::Specialization<Ordering::byVDIM, false>::Add();
|
||||
MultKernel::Specialization<Ordering::byNODES, true>::Add();
|
||||
MultKernel::Specialization<Ordering::byVDIM, true>::Add();
|
||||
}
|
||||
|
||||
template <Ordering::Type Order, bool Atomic>
|
||||
DerefineMatrixOp::MultKernelType DerefineMatrixOp::MultKernel::Kernel()
|
||||
{
|
||||
return internal::DerefMultKernelImpl<Order, Atomic>;
|
||||
}
|
||||
|
||||
DerefineMatrixOp::MultKernelType
|
||||
DerefineMatrixOp::MultKernel::Fallback(Ordering::Type, bool)
|
||||
{
|
||||
MFEM_ABORT("invalid MultKernel parameters");
|
||||
}
|
||||
} // namespace mfem
|
||||
/// \endcond DO_NOT_DOCUMENT
|
||||
@@ -0,0 +1,65 @@
|
||||
// Copyright (c) 2010-2025, 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_DEREFMAT_OP
|
||||
#define MFEM_DEREFMAT_OP
|
||||
|
||||
#include "fespace.hpp"
|
||||
|
||||
#include "kernel_dispatch.hpp"
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
/// \cond DO_NOT_DOCUMENT
|
||||
|
||||
struct DerefineMatrixOp : public Operator
|
||||
{
|
||||
FiniteElementSpace *fespace;
|
||||
/// offsets into block_storage
|
||||
Array<int> block_offsets;
|
||||
/// offsets into row_idcs
|
||||
Array<int> block_row_idcs_offsets;
|
||||
/// offsets into col_idcs
|
||||
Array<int> block_col_idcs_offsets;
|
||||
/// mapping for row dofs, INT_MAX indicates the block row should be ignored.
|
||||
/// negative means the row data should be negated.
|
||||
Array<int> row_idcs;
|
||||
/// mapping for col dofs, negative means the col data should be negated.
|
||||
Array<int> col_idcs;
|
||||
/// dense block matrices which can be reused to construct the full matrix
|
||||
/// operation. These are stored contiguously and blocks have no restrictions
|
||||
/// on shape (can be rectangle and differ from block to block).
|
||||
Vector block_storage;
|
||||
/// maximum height of any block in block_storage for GPU
|
||||
/// parallelization, or 1 for CPU runs.
|
||||
int max_rows;
|
||||
|
||||
using MultKernelType = void (*)(const DerefineMatrixOp &, const Vector &,
|
||||
Vector &);
|
||||
/// template args: ordering, atomic
|
||||
MFEM_REGISTER_KERNELS(MultKernel, MultKernelType, (Ordering::Type, bool));
|
||||
|
||||
struct Kernels
|
||||
{
|
||||
Kernels();
|
||||
};
|
||||
|
||||
void Mult(const Vector &x, Vector &y) const;
|
||||
|
||||
DerefineMatrixOp(FiniteElementSpace &fespace_, int old_ndofs,
|
||||
const Table *old_elem_dof, const Table *old_elem_fos);
|
||||
};
|
||||
|
||||
/// \endcond DO_NOT_DOCUMENT
|
||||
|
||||
} // namespace mfem
|
||||
#endif
|
||||
+43
-11
@@ -231,22 +231,53 @@ public:
|
||||
const std::vector<FieldDescriptor> ¶meters,
|
||||
const ParMesh &mesh);
|
||||
|
||||
/// MultLevel enum to indicate if the T->L Operators are used in the
|
||||
/// Mult method.
|
||||
enum MultLevel
|
||||
{
|
||||
TVECTOR,
|
||||
LVECTOR
|
||||
};
|
||||
|
||||
/// @brief Set the MultLevel mode for the DifferentiableOperator.
|
||||
/// The default is TVECTOR, which means that the Operator will use
|
||||
/// T->L before Mult and L->T Operators after.
|
||||
void SetMultLevel(MultLevel level)
|
||||
{
|
||||
mult_level = level;
|
||||
}
|
||||
|
||||
/// @brief Compute the action of the operator on a given vector.
|
||||
///
|
||||
/// @param solutions_t The solution vector in which to compute the action.
|
||||
/// This has to be a T-dof vector.
|
||||
/// @param result_t Result vector of the action of the operator on
|
||||
/// solutions_t. The result is a T-dof vector.
|
||||
void Mult(const Vector &solutions_t, Vector &result_t) const override
|
||||
/// @param solutions_in The solution vector in which to compute the action.
|
||||
/// This has to be a T-dof vector if MultLevel is set to TVECTOR, or L-dof
|
||||
/// Vector if MultLevel is set to LVECTOR.
|
||||
/// @param result_in Result vector of the action of the operator on
|
||||
/// solutions. The result is a T-dof vector or L-dof vector depending on
|
||||
/// the MultLevel.
|
||||
void Mult(const Vector &solutions_in, Vector &result_in) const override
|
||||
{
|
||||
MFEM_ASSERT(!action_callbacks.empty(), "no integrators have been set");
|
||||
prolongation(solutions, solutions_t, solutions_l);
|
||||
residual_l = 0.0;
|
||||
for (auto &action : action_callbacks)
|
||||
|
||||
if (mult_level == MultLevel::LVECTOR)
|
||||
{
|
||||
action(solutions_l, parameters_l, residual_l);
|
||||
get_lvectors(solutions, solutions_in, solutions_l);
|
||||
result_in = 0.0;
|
||||
for (auto &action : action_callbacks)
|
||||
{
|
||||
action(solutions_l, parameters_l, result_in);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
prolongation(solutions, solutions_in, solutions_l);
|
||||
residual_l = 0.0;
|
||||
for (auto &action : action_callbacks)
|
||||
{
|
||||
action(solutions_l, parameters_l, residual_l);
|
||||
}
|
||||
prolongation_transpose(residual_l, result_in);
|
||||
}
|
||||
prolongation_transpose(residual_l, result_t);
|
||||
}
|
||||
|
||||
/// @brief Add a domain integrator to the operator.
|
||||
@@ -345,6 +376,8 @@ public:
|
||||
private:
|
||||
const ParMesh &mesh;
|
||||
|
||||
MultLevel mult_level = TVECTOR;
|
||||
|
||||
std::vector<action_t> action_callbacks;
|
||||
std::map<size_t,
|
||||
std::vector<derivative_action_t>> derivative_action_callbacks;
|
||||
@@ -354,7 +387,6 @@ private:
|
||||
std::vector<assemble_derivative_hypreparmatrix_callback_t>>
|
||||
assemble_derivative_hypreparmatrix_callbacks;
|
||||
|
||||
|
||||
std::vector<FieldDescriptor> solutions;
|
||||
std::vector<FieldDescriptor> parameters;
|
||||
// solutions and parameters
|
||||
|
||||
+22
-4
@@ -327,8 +327,8 @@ void print_mpi_sync(const std::string& msg)
|
||||
// First gather string lengths
|
||||
size_t msg_len = msg.length();
|
||||
std::vector<size_t> lengths(nranks);
|
||||
MPI_Gather(&msg_len, 1, MPI_INT,
|
||||
lengths.data(), 1, MPI_INT,
|
||||
MPI_Gather(&msg_len, 1, MPITypeMap<size_t>::mpi_type,
|
||||
lengths.data(), 1, MPITypeMap<size_t>::mpi_type,
|
||||
0, MPI_COMM_WORLD);
|
||||
|
||||
if (myrank == 0)
|
||||
@@ -568,7 +568,7 @@ struct ThreadBlocks
|
||||
int z = 1;
|
||||
};
|
||||
|
||||
#if (defined(MFEM_USE_CUDA) || defined(MFEM_USE_HIP))
|
||||
#if defined(MFEM_USE_CUDA_OR_HIP)
|
||||
template <typename func_t>
|
||||
__global__ void forall_kernel_shmem(func_t f, int n)
|
||||
{
|
||||
@@ -591,7 +591,7 @@ void forall(func_t f,
|
||||
if (Device::Allows(Backend::CUDA_MASK) ||
|
||||
Device::Allows(Backend::HIP_MASK))
|
||||
{
|
||||
#if (defined(MFEM_USE_CUDA) || defined(MFEM_USE_HIP))
|
||||
#if defined(MFEM_USE_CUDA_OR_HIP)
|
||||
// int gridsize = (N + Z - 1) / Z;
|
||||
int num_bytes = num_shmem * sizeof(decltype(shmem));
|
||||
dim3 block_size(blocks.x, blocks.y, blocks.z);
|
||||
@@ -1076,6 +1076,24 @@ void prolongation(const std::vector<FieldDescriptor> fields,
|
||||
}
|
||||
}
|
||||
|
||||
inline
|
||||
void get_lvectors(const std::vector<FieldDescriptor> fields,
|
||||
const Vector &x,
|
||||
std::vector<Vector> &fields_l)
|
||||
{
|
||||
int data_offset = 0;
|
||||
for (std::size_t i = 0; i < fields.size(); i++)
|
||||
{
|
||||
const int sz = GetVSize(fields[i]);
|
||||
fields_l[i].SetSize(sz);
|
||||
|
||||
const Vector x_i(const_cast<Vector&>(x), data_offset, sz);
|
||||
fields_l[i] = x_i;
|
||||
|
||||
data_offset += sz;
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief Get a transpose prolongation callback for a field descriptor.
|
||||
///
|
||||
/// In the special case of a one field operator, the transpose prolongation
|
||||
|
||||
@@ -259,6 +259,30 @@ inline void FaceIdxToVolIdx3D(const int index, const int size1d,
|
||||
i = yz_plane ? level : _i;
|
||||
}
|
||||
|
||||
MFEM_HOST_DEVICE
|
||||
inline int FaceIdxToVolIdx(int dim, int i, int size1d, int face0, int face1,
|
||||
int side, int orientation)
|
||||
{
|
||||
if (dim == 2)
|
||||
{
|
||||
int ix, iy;
|
||||
internal::FaceIdxToVolIdx2D(i, size1d, face0, face1, side, ix, iy);
|
||||
return ix + iy*size1d;
|
||||
}
|
||||
else if (dim == 3)
|
||||
{
|
||||
int ix, iy, iz;
|
||||
internal::FaceIdxToVolIdx3D(i, size1d, face0, face1, side, orientation,
|
||||
ix, iy, iz);
|
||||
return ix + size1d*iy + size1d*size1d*iz;
|
||||
}
|
||||
else
|
||||
{
|
||||
MFEM_ABORT_KERNEL("Invalid dimension");
|
||||
return -1;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
} // namespace mfem
|
||||
|
||||
+3
-7
@@ -401,9 +401,6 @@ FiniteElementCollection *FiniteElementCollection::New(const char *name)
|
||||
{
|
||||
MFEM_ABORT("unknown FiniteElementCollection: " << name);
|
||||
}
|
||||
MFEM_VERIFY(!strcmp(fec->Name(), name), "input name: \"" << name
|
||||
<< "\" does not match the created collection name: \""
|
||||
<< fec->Name() << '"');
|
||||
|
||||
return fec;
|
||||
}
|
||||
@@ -2459,8 +2456,7 @@ RT_FECollection::RT_FECollection(const int order, const int dim,
|
||||
const char *cb_name = BasisType::Name(cb_type); // this may abort
|
||||
MFEM_ABORT("unknown closed BasisType: " << cb_name);
|
||||
}
|
||||
if (Quadrature1D::CheckOpen(op_type) == Quadrature1D::Invalid &&
|
||||
ob_type != BasisType::IntegratedGLL)
|
||||
if (Quadrature1D::CheckOpen(op_type) == Quadrature1D::Invalid)
|
||||
{
|
||||
const char *ob_name = BasisType::Name(ob_type); // this may abort
|
||||
MFEM_ABORT("unknown open BasisType: " << ob_name);
|
||||
@@ -2518,6 +2514,7 @@ RT_FECollection::RT_FECollection(const int p, const int dim,
|
||||
const int map_type, const bool signs,
|
||||
const int ob_type)
|
||||
: FiniteElementCollection(p + 1)
|
||||
, dim(dim)
|
||||
, ob_type(ob_type)
|
||||
{
|
||||
if (Quadrature1D::CheckOpen(BasisType::GetQuadrature1D(ob_type)) ==
|
||||
@@ -2786,8 +2783,7 @@ ND_FECollection::ND_FECollection(const int p, const int dim,
|
||||
int cp_type = BasisType::GetQuadrature1D(cb_type);
|
||||
|
||||
// Error checking
|
||||
if (Quadrature1D::CheckOpen(op_type) == Quadrature1D::Invalid &&
|
||||
ob_type != BasisType::IntegratedGLL)
|
||||
if (Quadrature1D::CheckOpen(op_type) == Quadrature1D::Invalid)
|
||||
{
|
||||
const char *ob_name = BasisType::Name(ob_type);
|
||||
MFEM_ABORT("Invalid open basis point type: " << ob_name);
|
||||
|
||||
@@ -464,6 +464,13 @@ public:
|
||||
RT_Trace_FECollection(const int p, const int dim,
|
||||
const int map_type = FiniteElement::INTEGRAL,
|
||||
const int ob_type = BasisType::GaussLegendre);
|
||||
|
||||
FiniteElementCollection *Clone(int p) const override
|
||||
{
|
||||
const int map_type = (strncmp(rt_name, "RT_Trace", 8) == 0)?
|
||||
(FiniteElement::INTEGRAL):(FiniteElement::VALUE);
|
||||
return new RT_Trace_FECollection(p, dim, map_type, ob_type);
|
||||
}
|
||||
};
|
||||
|
||||
/** Arbitrary order discontinuous finite elements defined on the interface
|
||||
@@ -475,6 +482,13 @@ public:
|
||||
DG_Interface_FECollection(const int p, const int dim,
|
||||
const int map_type = FiniteElement::VALUE,
|
||||
const int ob_type = BasisType::GaussLegendre);
|
||||
|
||||
FiniteElementCollection *Clone(int p) const override
|
||||
{
|
||||
const int map_type = (strncmp(rt_name, "DG_Iface", 8) == 0)?
|
||||
(FiniteElement::VALUE):(FiniteElement::INTEGRAL);
|
||||
return new DG_Interface_FECollection(p, dim, map_type, ob_type);
|
||||
}
|
||||
};
|
||||
|
||||
/// Arbitrary order H(curl)-conforming Nedelec finite elements.
|
||||
|
||||
@@ -0,0 +1,249 @@
|
||||
// Copyright (c) 2010-2025, 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_FES_KERNELS_HPP
|
||||
#define MFEM_FES_KERNELS_HPP
|
||||
|
||||
#include "../general/forall.hpp"
|
||||
|
||||
#include <climits>
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
/// \cond DO_NOT_DOCUMENT
|
||||
namespace internal
|
||||
{
|
||||
|
||||
///
|
||||
/// Implements matrix-vector multiply $y = A x$ for a sparse matrix composed of
|
||||
/// a sum of smaller dense blocks. There is additional permutation/sign
|
||||
/// information associated with each block. The base class only implements
|
||||
/// helper routines such as computing block widths, index into x, index into y,
|
||||
/// and column in A given sub-block information.
|
||||
/// @sa DerefineMatrixOpMultFunctor
|
||||
///
|
||||
/// @tparam Order vdim ordering for x and y. Note that for Diag = false this is
|
||||
/// ignored for x as x has a special interleaved order.
|
||||
/// @tparam Base used for the curious recurring template pattern (CRTP) so the
|
||||
/// base class can access child class fields without virtual functions
|
||||
/// @tparam Diag true if this corresponds to the diagonal block (coarse element
|
||||
/// and fine element are on our rank), false otherwise (coarse element is on our
|
||||
/// rank, fine element is on a different rank).
|
||||
///
|
||||
template <Ordering::Type Order, class Base, bool Diag = true>
|
||||
struct DerefineMatrixOpFunctorBase;
|
||||
|
||||
template <class Base>
|
||||
struct DerefineMatrixOpFunctorBase<Ordering::byNODES, Base, true>
|
||||
{
|
||||
/// block column indices offsets
|
||||
const int *bcptr;
|
||||
/// column indices
|
||||
const int *cptr;
|
||||
|
||||
int MFEM_HOST_DEVICE BlockWidth(int k) const
|
||||
{
|
||||
return bcptr[k + 1] - bcptr[k];
|
||||
}
|
||||
|
||||
void MFEM_HOST_DEVICE Col(int j, int k, int &col, int &sign) const
|
||||
{
|
||||
col = cptr[bcptr[k] + j];
|
||||
if (col < 0)
|
||||
{
|
||||
col = -1 - col;
|
||||
sign = -sign;
|
||||
}
|
||||
}
|
||||
|
||||
int MFEM_HOST_DEVICE IndexX(int col, int vdim, int) const
|
||||
{
|
||||
return col + vdim * static_cast<const Base *>(this)->width;
|
||||
}
|
||||
int MFEM_HOST_DEVICE IndexY(int row, int vdim) const
|
||||
{
|
||||
return row + vdim * static_cast<const Base *>(this)->height;
|
||||
}
|
||||
};
|
||||
|
||||
template <class Base>
|
||||
struct DerefineMatrixOpFunctorBase<Ordering::byVDIM, Base, true>
|
||||
{
|
||||
/// block column indices offsets
|
||||
const int *bcptr;
|
||||
/// column indices
|
||||
const int *cptr;
|
||||
|
||||
int MFEM_HOST_DEVICE BlockWidth(int k) const
|
||||
{
|
||||
return bcptr[k + 1] - bcptr[k];
|
||||
}
|
||||
|
||||
void MFEM_HOST_DEVICE Col(int j, int k, int &col, int &sign) const
|
||||
{
|
||||
col = cptr[bcptr[k] + j];
|
||||
if (col < 0)
|
||||
{
|
||||
col = -1 - col;
|
||||
sign = -sign;
|
||||
}
|
||||
}
|
||||
|
||||
int MFEM_HOST_DEVICE IndexX(int col, int vdim, int) const
|
||||
{
|
||||
return vdim + col * static_cast<const Base *>(this)->vdims;
|
||||
}
|
||||
int MFEM_HOST_DEVICE IndexY(int row, int vdim) const
|
||||
{
|
||||
return vdim + row * static_cast<const Base *>(this)->vdims;
|
||||
}
|
||||
};
|
||||
|
||||
template <class Base>
|
||||
struct DerefineMatrixOpFunctorBase<Ordering::byNODES, Base, false>
|
||||
{
|
||||
/// receive segment offsets
|
||||
const int *segptr;
|
||||
/// receive segment index
|
||||
const int *rsptr;
|
||||
/// off-diagonal block column offsets
|
||||
const int *coptr;
|
||||
/// off-diagonal block widths
|
||||
const int *bwptr;
|
||||
|
||||
int MFEM_HOST_DEVICE BlockWidth(int k) const { return bwptr[k]; }
|
||||
|
||||
void MFEM_HOST_DEVICE Col(int j, int k, int &col, int &sign) const
|
||||
{
|
||||
col = coptr[k] + j;
|
||||
}
|
||||
|
||||
int MFEM_HOST_DEVICE IndexX(int col, int vdim, int k) const
|
||||
{
|
||||
int tmp = rsptr[k];
|
||||
int segwidth = segptr[tmp + 1] - segptr[tmp];
|
||||
return segptr[tmp] * static_cast<const Base *>(this)->vdims + col +
|
||||
vdim * segwidth;
|
||||
}
|
||||
int MFEM_HOST_DEVICE IndexY(int row, int vdim) const
|
||||
{
|
||||
return row + vdim * static_cast<const Base *>(this)->height;
|
||||
}
|
||||
};
|
||||
|
||||
template <class Base>
|
||||
struct DerefineMatrixOpFunctorBase<Ordering::byVDIM, Base, false>
|
||||
{
|
||||
/// receive segment offsets
|
||||
const int *segptr;
|
||||
/// receive segment index
|
||||
const int *rsptr;
|
||||
/// off-diagonal block column offsets
|
||||
const int *coptr;
|
||||
/// off-diagonal block widths
|
||||
const int *bwptr;
|
||||
|
||||
int MFEM_HOST_DEVICE BlockWidth(int k) const { return bwptr[k]; }
|
||||
|
||||
void MFEM_HOST_DEVICE Col(int j, int k, int &col, int &sign) const
|
||||
{
|
||||
col = coptr[k] + j;
|
||||
}
|
||||
|
||||
int MFEM_HOST_DEVICE IndexX(int col, int vdim, int k) const
|
||||
{
|
||||
int tmp = rsptr[k];
|
||||
int segwidth = segptr[tmp + 1] - segptr[tmp];
|
||||
return segptr[tmp] * static_cast<const Base *>(this)->vdims + col +
|
||||
vdim * segwidth;
|
||||
}
|
||||
int MFEM_HOST_DEVICE IndexY(int row, int vdim) const
|
||||
{
|
||||
return vdim + row * static_cast<const Base *>(this)->vdims;
|
||||
}
|
||||
};
|
||||
|
||||
/// internally used to implement the derefinement operator Mult diagonal
|
||||
/// block
|
||||
template <Ordering::Type Order, bool Atomic, bool Diag = true>
|
||||
struct DerefineMatrixOpMultFunctor
|
||||
: public DerefineMatrixOpFunctorBase<
|
||||
Order, DerefineMatrixOpMultFunctor<Order, Atomic, Diag>, Diag>
|
||||
{
|
||||
const real_t *xptr;
|
||||
real_t *yptr;
|
||||
/// block storage
|
||||
const real_t *bsptr;
|
||||
/// block offsets
|
||||
const int *boptr;
|
||||
/// block row index offsets
|
||||
const int *brptr;
|
||||
/// row indices
|
||||
const int *rptr;
|
||||
|
||||
// number of blocks
|
||||
int nblocks;
|
||||
// number of components
|
||||
int vdims;
|
||||
/// overall operator height (for vdim = 1)
|
||||
int height;
|
||||
/// overall operator width (for vdim = 1)
|
||||
int width;
|
||||
void MFEM_HOST_DEVICE operator()(int kidx) const
|
||||
{
|
||||
int k = kidx % nblocks;
|
||||
int vdim = kidx / nblocks;
|
||||
|
||||
int block_height = brptr[k + 1] - brptr[k];
|
||||
int block_width = this->BlockWidth(k);
|
||||
MFEM_FOREACH_THREAD(i, x, block_height)
|
||||
{
|
||||
int row = rptr[brptr[k] + i];
|
||||
int rsign = 1;
|
||||
if (row < 0)
|
||||
{
|
||||
row = -1 - row;
|
||||
rsign = -1;
|
||||
}
|
||||
if (row < INT_MAX)
|
||||
{
|
||||
// row not marked as unused
|
||||
real_t sum = 0;
|
||||
for (int j = 0; j < block_width; ++j)
|
||||
{
|
||||
int col, sign = rsign;
|
||||
this->Col(j, k, col, sign);
|
||||
sum += sign * bsptr[boptr[k] + i + j * block_height] *
|
||||
xptr[this->IndexX(col, vdim, k)];
|
||||
}
|
||||
#if defined(__CUDA_ARCH__) || defined(__HIP_DEVICE_COMPILE__)
|
||||
if (Atomic)
|
||||
{
|
||||
atomicAdd(yptr + this->IndexY(row, vdim), sum);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
yptr[this->IndexY(row, vdim)] += sum;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// N is the max block row size (doesn't have to be a power of 2)
|
||||
void Run(int N) const { forall_2D(nblocks * vdims, N, 1, *this); }
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
/// \endcond DO_NOT_DOCUMENT
|
||||
} // namespace mfem
|
||||
|
||||
#endif
|
||||
+13
-6
@@ -17,6 +17,9 @@
|
||||
#include "fem.hpp"
|
||||
#include "ceed/interface/util.hpp"
|
||||
|
||||
#include "derefmat_op.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <cstdarg>
|
||||
|
||||
@@ -24,9 +27,9 @@ using namespace std;
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
template <> void Ordering::
|
||||
DofsToVDofs<Ordering::byNODES>(int ndofs, int vdim, Array<int> &dofs)
|
||||
template <>
|
||||
void Ordering::DofsToVDofs<Ordering::byNODES>(int ndofs, int vdim,
|
||||
Array<int> &dofs)
|
||||
{
|
||||
// static method
|
||||
int size = dofs.Size();
|
||||
@@ -40,8 +43,9 @@ DofsToVDofs<Ordering::byNODES>(int ndofs, int vdim, Array<int> &dofs)
|
||||
}
|
||||
}
|
||||
|
||||
template <> void Ordering::
|
||||
DofsToVDofs<Ordering::byVDIM>(int ndofs, int vdim, Array<int> &dofs)
|
||||
template <>
|
||||
void Ordering::DofsToVDofs<Ordering::byVDIM>(int ndofs, int vdim,
|
||||
Array<int> &dofs)
|
||||
{
|
||||
// static method
|
||||
int size = dofs.Size();
|
||||
@@ -55,7 +59,6 @@ DofsToVDofs<Ordering::byVDIM>(int ndofs, int vdim, Array<int> &dofs)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
FiniteElementSpace::FiniteElementSpace()
|
||||
: mesh(NULL), fec(NULL), vdim(0), ordering(Ordering::byNODES),
|
||||
ndofs(0), nvdofs(0), nedofs(0), nfdofs(0), nbdofs(0),
|
||||
@@ -4244,7 +4247,11 @@ void FiniteElementSpace::Update(bool want_transform)
|
||||
case Mesh::DEREFINE:
|
||||
{
|
||||
BuildConformingInterpolation();
|
||||
#if 0
|
||||
Th.Reset(DerefinementMatrix(old_ndofs, old_elem_dof, old_elem_fos));
|
||||
#else
|
||||
Th.Reset(new DerefineMatrixOp(*this, old_ndofs, old_elem_dof, old_elem_fos));
|
||||
#endif
|
||||
if (IsVariableOrder())
|
||||
{
|
||||
if (cP && cR_hp)
|
||||
|
||||
+11
-3
@@ -113,7 +113,7 @@ class QuadratureSpace;
|
||||
class QuadratureInterpolator;
|
||||
class FaceQuadratureInterpolator;
|
||||
class PRefinementTransferOperator;
|
||||
|
||||
struct DerefineMatrixOp;
|
||||
|
||||
/** @brief Class FiniteElementSpace - responsible for providing FEM view of the
|
||||
mesh, mainly managing the set of degrees of freedom.
|
||||
@@ -246,6 +246,7 @@ class FiniteElementSpace
|
||||
friend class PRefinementTransferOperator;
|
||||
friend void Mesh::Swap(Mesh &, bool);
|
||||
friend class LORBase;
|
||||
friend struct DerefineMatrixOp;
|
||||
|
||||
protected:
|
||||
/// The mesh that FE space lives on (not owned).
|
||||
@@ -682,8 +683,12 @@ public:
|
||||
NURBSExtension *GetNURBSext() { return NURBSext; }
|
||||
NURBSExtension *StealNURBSext();
|
||||
|
||||
bool Conforming() const { return mesh->Conforming() && cP == NULL; }
|
||||
bool Nonconforming() const { return mesh->Nonconforming() || cP != NULL; }
|
||||
bool Conforming() const
|
||||
{
|
||||
return NURBSext != NULL ||
|
||||
(mesh->Conforming() && cP == NULL);
|
||||
}
|
||||
bool Nonconforming() const { return !Conforming(); }
|
||||
|
||||
/** Set the prolongation operator of the space to an arbitrary sparse matrix,
|
||||
creating a copy of the argument. */
|
||||
@@ -921,6 +926,9 @@ public:
|
||||
{ return mesh->GetBdrElementType(i); }
|
||||
|
||||
/// Returns ElementTransformation for the @a i-th element.
|
||||
/// @note The returned pointer references an object owned by the associated
|
||||
/// @a Mesh that will be modified by other calls to `GetElementTransformation`.
|
||||
/// As such, this pointer should @b not be deleted by the caller.
|
||||
ElementTransformation *GetElementTransformation(int i) const
|
||||
{ return mesh->GetElementTransformation(i); }
|
||||
|
||||
|
||||
+46
-2
@@ -68,7 +68,7 @@ GridFunction::GridFunction(Mesh *m, std::istream &input)
|
||||
Vector::Load(input, fes->GetVSize());
|
||||
|
||||
// if the mesh is a legacy (v1.1) NC mesh, it has old vertex ordering
|
||||
if (fes->Nonconforming() &&
|
||||
if (fes->Nonconforming() && fes->GetMesh()->ncmesh &&
|
||||
fes->GetMesh()->ncmesh->IsLegacyLoaded())
|
||||
{
|
||||
LegacyNCReorder();
|
||||
@@ -1374,6 +1374,50 @@ void GridFunction::GetVectorGradientHat(
|
||||
MultAtB(loc_data_mat, dshape, gh);
|
||||
}
|
||||
|
||||
void GridFunction::GetGradients(const IntegrationRule &ir, Vector &grad,
|
||||
QVectorLayout ql, MemoryType d_mt) const
|
||||
{
|
||||
const FiniteElement &fe = *fes->GetTypicalFE();
|
||||
const int dim = fe.GetDim();
|
||||
const int vdim = fes->GetVDim();
|
||||
const int NE = fes->GetNE();
|
||||
const int ND = fe.GetDof();
|
||||
const int NQ = ir.GetNPoints();
|
||||
|
||||
MemoryType my_d_mt = (d_mt != MemoryType::DEFAULT) ? d_mt :
|
||||
Device::GetDeviceMemoryType();
|
||||
|
||||
// ql == QVectorLayout::byNODES : NQ x VDIM x DIM x NE
|
||||
// ql == QVectorLayout::byVDIM : VDIM x DIM x NQPT x NE
|
||||
grad.SetSize(dim*vdim*NQ*NE, my_d_mt);
|
||||
|
||||
const QuadratureInterpolator &qi = *fes->GetQuadratureInterpolator(ir);
|
||||
qi.SetOutputLayout(ql);
|
||||
|
||||
const bool use_tensor_products = UsesTensorBasis(*fes);
|
||||
qi.DisableTensorProducts(!use_tensor_products);
|
||||
const ElementDofOrdering e_ordering = use_tensor_products ?
|
||||
ElementDofOrdering::LEXICOGRAPHIC :
|
||||
ElementDofOrdering::NATIVE;
|
||||
const Operator *elem_restr = fes->GetElementRestriction(e_ordering);
|
||||
|
||||
// Pre-compute the geometric factors in order to set the desired MemoryType
|
||||
// they use:
|
||||
fes->GetMesh()->GetGeometricFactors(
|
||||
ir, GeometricFactors::JACOBIANS, my_d_mt);
|
||||
|
||||
if (elem_restr) // currently, always true
|
||||
{
|
||||
Vector f_e(vdim*ND*NE, my_d_mt);
|
||||
elem_restr->Mult(*this, f_e);
|
||||
qi.PhysDerivatives(f_e, grad);
|
||||
}
|
||||
else
|
||||
{
|
||||
qi.PhysDerivatives(*this, grad);
|
||||
}
|
||||
}
|
||||
|
||||
real_t GridFunction::GetDivergence(ElementTransformation &T) const
|
||||
{
|
||||
DofTransformation doftrans;
|
||||
@@ -2624,7 +2668,7 @@ void GridFunction::ProjectBdrCoefficient(Coefficient *coeff[],
|
||||
}
|
||||
for (int i = 0; i < values_counter.Size(); i++)
|
||||
{
|
||||
MFEM_ASSERT(bool(values_counter[i]) == ess_vdofs_marker[i],
|
||||
MFEM_ASSERT(bool(values_counter[i]) == bool(ess_vdofs_marker[i]),
|
||||
"internal error");
|
||||
}
|
||||
#endif
|
||||
|
||||
+31
-2
@@ -153,7 +153,8 @@ public:
|
||||
/// Shortcut for calling SetFromTrueDofs() with GetTrueVector() as argument.
|
||||
void SetFromTrueVector() { SetFromTrueDofs(GetTrueVector()); }
|
||||
|
||||
/// Returns the values in the vertices of i'th element for dimension vdim.
|
||||
/** @brief Returns the values at the vertices of element @a i for the 1-based
|
||||
dimension vdim. */
|
||||
void GetNodalValues(int i, Array<real_t> &nval, int vdim = 1) const;
|
||||
|
||||
/** @name Element index Get Value Methods
|
||||
@@ -308,7 +309,8 @@ public:
|
||||
/// For a vector grid function, makes sure that the ordering is byNODES.
|
||||
void ReorderByNodes();
|
||||
|
||||
/// Return the values as a vector on mesh vertices for dimension vdim.
|
||||
/** @brief Returns the values as a vector at mesh vertices, for the 1-based
|
||||
dimension vdim. */
|
||||
void GetNodalValues(Vector &nval, int vdim = 1) const;
|
||||
|
||||
void GetVectorFieldNodalValues(Vector &val, int comp) const;
|
||||
@@ -359,6 +361,33 @@ public:
|
||||
variable. */
|
||||
void GetVectorGradientHat(ElementTransformation &T, DenseMatrix &gh) const;
|
||||
|
||||
/** @brief Evaluate the gradients of the GridFunction at the given quadrature
|
||||
points, @a ir, in all mesh elements. */
|
||||
/** This method assumes that all mesh elements are the same type and that the
|
||||
IntegrationRule @a ir is consistent with that type of element.
|
||||
|
||||
@param[in] ir Quadrature points at which the gradients are to be
|
||||
evaluated.
|
||||
@param[out] grad Output vector of size `SDIM*VDIM*NQ*NE` where `SDIM` is
|
||||
the spatial dimention of the mesh, `VDIM` is the vector
|
||||
dimension of the GridFunction, `NQ` is the number of
|
||||
quadrature points in @a ir, and `NE` is the number of
|
||||
elements in the mesh. The layout of @a grad is
|
||||
determined by the parameter @a ql: when @a ql is
|
||||
QVectorLayout::byNODES, the layout is
|
||||
`NQ x VDIM x SDIM x NE`; when @a ql is
|
||||
QVectorLayout::byVDIM, the layout is
|
||||
`VDIM x SDIM x NQ x NE`.
|
||||
@param[in] ql Determines the layout of the output vector @a grad; see
|
||||
the description of @a grad for details.
|
||||
@param[in] d_mt MemoryType to use for allocating the output vector
|
||||
@a grad, as well the GeometricFactors and temporary
|
||||
vector used by the method. By default, the current
|
||||
device memory type is used. */
|
||||
void GetGradients(const IntegrationRule &ir, Vector &grad,
|
||||
QVectorLayout ql = QVectorLayout::byNODES,
|
||||
MemoryType d_mt = MemoryType::DEFAULT) const;
|
||||
|
||||
/** Compute $ (\int_{\Omega} (*this) \psi_i)/(\int_{\Omega} \psi_i) $,
|
||||
where $ \psi_i $ are the basis functions for the FE space of avgs.
|
||||
Both FE spaces should be scalar and on the same mesh. */
|
||||
|
||||
+154
-128
@@ -85,9 +85,9 @@ namespace mfem
|
||||
{
|
||||
|
||||
FindPointsGSLIB::FindPointsGSLIB()
|
||||
: mesh(NULL),
|
||||
fec_map_lin(NULL),
|
||||
fdataD(NULL), cr(NULL), gsl_comm(NULL),
|
||||
: mesh(nullptr),
|
||||
fec_map_lin(nullptr),
|
||||
fdataD(nullptr), cr(nullptr), gsl_comm(nullptr),
|
||||
dim(-1), points_cnt(-1), setupflag(false), default_interp_value(0),
|
||||
avgtype(AvgType::ARITHMETIC), bdr_tol(1e-8)
|
||||
{
|
||||
@@ -97,10 +97,10 @@ FindPointsGSLIB::FindPointsGSLIB()
|
||||
gf_rst_map.SetSize(4);
|
||||
for (int i = 0; i < mesh_split.Size(); i++)
|
||||
{
|
||||
mesh_split[i] = NULL;
|
||||
ir_split[i] = NULL;
|
||||
fes_rst_map[i] = NULL;
|
||||
gf_rst_map[i] = NULL;
|
||||
mesh_split[i] = nullptr;
|
||||
ir_split[i] = nullptr;
|
||||
fes_rst_map[i] = nullptr;
|
||||
gf_rst_map[i] = nullptr;
|
||||
}
|
||||
|
||||
gsl_comm = new gslib::comm;
|
||||
@@ -117,27 +117,40 @@ FindPointsGSLIB::FindPointsGSLIB()
|
||||
crystal_init(cr, gsl_comm);
|
||||
}
|
||||
|
||||
FindPointsGSLIB::FindPointsGSLIB(Mesh &mesh_in, const double bb_t,
|
||||
const double newt_tol, const int npt_max)
|
||||
: FindPointsGSLIB()
|
||||
{
|
||||
Setup(mesh_in, bb_t, newt_tol, npt_max);
|
||||
}
|
||||
|
||||
FindPointsGSLIB::~FindPointsGSLIB()
|
||||
{
|
||||
crystal_free(cr);
|
||||
comm_free(gsl_comm);
|
||||
delete gsl_comm;
|
||||
delete cr;
|
||||
for (int i = 0; i < 4; i++)
|
||||
FreeData();
|
||||
#ifdef MFEM_USE_MPI
|
||||
if (!Mpi::IsFinalized()) // currently segfaults inside gslib otherwise
|
||||
#endif
|
||||
{
|
||||
if (mesh_split[i]) { delete mesh_split[i]; mesh_split[i] = NULL; }
|
||||
if (ir_split[i]) { delete ir_split[i]; ir_split[i] = NULL; }
|
||||
if (fes_rst_map[i]) { delete fes_rst_map[i]; fes_rst_map[i] = NULL; }
|
||||
if (gf_rst_map[i]) { delete gf_rst_map[i]; gf_rst_map[i] = NULL; }
|
||||
crystal_free(cr);
|
||||
comm_free(gsl_comm);
|
||||
delete gsl_comm;
|
||||
delete cr;
|
||||
}
|
||||
if (fec_map_lin) { delete fec_map_lin; fec_map_lin = NULL; }
|
||||
for (int i = 0; i < mesh_split.Size(); i++)
|
||||
{
|
||||
if (mesh_split[i]) { delete mesh_split[i]; mesh_split[i] = nullptr; }
|
||||
if (ir_split[i]) { delete ir_split[i]; ir_split[i] = nullptr; }
|
||||
if (fes_rst_map[i]) { delete fes_rst_map[i]; fes_rst_map[i] = nullptr; }
|
||||
if (gf_rst_map[i]) { delete gf_rst_map[i]; gf_rst_map[i] = nullptr; }
|
||||
}
|
||||
if (fec_map_lin) { delete fec_map_lin; fec_map_lin = nullptr; }
|
||||
}
|
||||
|
||||
#ifdef MFEM_USE_MPI
|
||||
FindPointsGSLIB::FindPointsGSLIB(MPI_Comm comm_)
|
||||
: mesh(NULL),
|
||||
fec_map_lin(NULL),
|
||||
fdataD(NULL), cr(NULL), gsl_comm(NULL),
|
||||
: mesh(nullptr),
|
||||
fec_map_lin(nullptr),
|
||||
fdataD(nullptr), cr(nullptr), gsl_comm(nullptr),
|
||||
dim(-1), points_cnt(-1), setupflag(false), default_interp_value(0),
|
||||
avgtype(AvgType::ARITHMETIC), bdr_tol(1e-8)
|
||||
{
|
||||
@@ -147,10 +160,10 @@ FindPointsGSLIB::FindPointsGSLIB(MPI_Comm comm_)
|
||||
gf_rst_map.SetSize(4);
|
||||
for (int i = 0; i < mesh_split.Size(); i++)
|
||||
{
|
||||
mesh_split[i] = NULL;
|
||||
ir_split[i] = NULL;
|
||||
fes_rst_map[i] = NULL;
|
||||
gf_rst_map[i] = NULL;
|
||||
mesh_split[i] = nullptr;
|
||||
ir_split[i] = nullptr;
|
||||
fes_rst_map[i] = nullptr;
|
||||
gf_rst_map[i] = nullptr;
|
||||
}
|
||||
|
||||
gsl_comm = new gslib::comm;
|
||||
@@ -158,12 +171,21 @@ FindPointsGSLIB::FindPointsGSLIB(MPI_Comm comm_)
|
||||
comm_init(gsl_comm, comm_);
|
||||
crystal_init(cr, gsl_comm);
|
||||
}
|
||||
|
||||
FindPointsGSLIB::FindPointsGSLIB(ParMesh &mesh_in, const double bb_t,
|
||||
const double newt_tol, const int npt_max)
|
||||
: FindPointsGSLIB(mesh_in.GetComm())
|
||||
{
|
||||
Setup(mesh_in, bb_t, newt_tol, npt_max);
|
||||
}
|
||||
#endif
|
||||
|
||||
void FindPointsGSLIB::Setup(Mesh &m, const double bb_t, const double newt_tol,
|
||||
const int npt_max)
|
||||
{
|
||||
MFEM_VERIFY(m.GetNodes() != NULL, "Mesh nodes are required.");
|
||||
MFEM_VERIFY(m.SpaceDimension() == m.Dimension(),
|
||||
"Mesh spatial dimension and reference element dimension must be the same");
|
||||
const int meshOrder = m.GetNodes()->FESpace()->GetMaxElementOrder();
|
||||
|
||||
// call FreeData if FindPointsGSLIB::Setup has been called already
|
||||
@@ -171,37 +193,9 @@ void FindPointsGSLIB::Setup(Mesh &m, const double bb_t, const double newt_tol,
|
||||
|
||||
mesh = &m;
|
||||
dim = mesh->Dimension();
|
||||
unsigned dof1D = meshOrder + 1;
|
||||
const unsigned int dof1D = meshOrder+1;
|
||||
|
||||
SetupSplitMeshes();
|
||||
if (dim == 2)
|
||||
{
|
||||
if (ir_split[0]) { delete ir_split[0]; ir_split[0] = NULL; }
|
||||
ir_split[0] = new IntegrationRule(3*pow(dof1D, dim));
|
||||
SetupIntegrationRuleForSplitMesh(mesh_split[0], ir_split[0], meshOrder);
|
||||
|
||||
if (ir_split[1]) { delete ir_split[1]; ir_split[1] = NULL; }
|
||||
ir_split[1] = new IntegrationRule(pow(dof1D, dim));
|
||||
SetupIntegrationRuleForSplitMesh(mesh_split[1], ir_split[1], meshOrder);
|
||||
}
|
||||
else if (dim == 3)
|
||||
{
|
||||
if (ir_split[0]) { delete ir_split[0]; ir_split[0] = NULL; }
|
||||
ir_split[0] = new IntegrationRule(pow(dof1D, dim));
|
||||
SetupIntegrationRuleForSplitMesh(mesh_split[0], ir_split[0], meshOrder);
|
||||
|
||||
if (ir_split[1]) { delete ir_split[1]; ir_split[1] = NULL; }
|
||||
ir_split[1] = new IntegrationRule(4*pow(dof1D, dim));
|
||||
SetupIntegrationRuleForSplitMesh(mesh_split[1], ir_split[1], meshOrder);
|
||||
|
||||
if (ir_split[2]) { delete ir_split[2]; ir_split[2] = NULL; }
|
||||
ir_split[2] = new IntegrationRule(3*pow(dof1D, dim));
|
||||
SetupIntegrationRuleForSplitMesh(mesh_split[2], ir_split[2], meshOrder);
|
||||
|
||||
if (ir_split[3]) { delete ir_split[3]; ir_split[3] = NULL; }
|
||||
ir_split[3] = new IntegrationRule(8*pow(dof1D, dim));
|
||||
SetupIntegrationRuleForSplitMesh(mesh_split[3], ir_split[3], meshOrder);
|
||||
}
|
||||
SetupSplitMeshesAndIntegrationRules(meshOrder);
|
||||
|
||||
GetNodalValues(mesh->GetNodes(), gsl_mesh);
|
||||
|
||||
@@ -1128,13 +1122,18 @@ void FindPointsGSLIB::Interpolate(Mesh &m, const Vector &point_pos,
|
||||
void FindPointsGSLIB::FreeData()
|
||||
{
|
||||
if (!setupflag) { return; }
|
||||
if (dim == 2)
|
||||
#ifdef MFEM_USE_MPI
|
||||
if (!Mpi::IsFinalized()) // currently segfaults inside gslib otherwise
|
||||
#endif
|
||||
{
|
||||
findpts_free_2((gslib::findpts_data_2 *)this->fdataD);
|
||||
}
|
||||
else
|
||||
{
|
||||
findpts_free_3((gslib::findpts_data_3 *)this->fdataD);
|
||||
if (dim == 2)
|
||||
{
|
||||
findpts_free_2((gslib::findpts_data_2 *)this->fdataD);
|
||||
}
|
||||
else
|
||||
{
|
||||
findpts_free_3((gslib::findpts_data_3 *)this->fdataD);
|
||||
}
|
||||
}
|
||||
gsl_code.DeleteAll();
|
||||
gsl_proc.DeleteAll();
|
||||
@@ -1158,8 +1157,8 @@ void FindPointsGSLIB::FreeData()
|
||||
|
||||
void FindPointsGSLIB::SetupSplitMeshes()
|
||||
{
|
||||
fec_map_lin = new H1_FECollection(1, dim);
|
||||
if (mesh->Dimension() == 2)
|
||||
if (fec_map_lin == nullptr) { fec_map_lin = new H1_FECollection(1, dim); }
|
||||
if (dim == 2)
|
||||
{
|
||||
int Nvert = 7;
|
||||
int NEsplit = 3;
|
||||
@@ -1201,7 +1200,7 @@ void FindPointsGSLIB::SetupSplitMeshes()
|
||||
mesh_split[1] = new Mesh(Mesh::MakeCartesian2D(1, 1,
|
||||
Element::QUADRILATERAL));
|
||||
}
|
||||
else if (mesh->Dimension() == 3)
|
||||
else if (dim == 3)
|
||||
{
|
||||
mesh_split[0] = new Mesh(Mesh::MakeCartesian3D(1, 1, 1,
|
||||
Element::HEXAHEDRON));
|
||||
@@ -1346,41 +1345,6 @@ void FindPointsGSLIB::SetupSplitMeshes()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NE_split_total = 0;
|
||||
split_element_map.SetSize(0);
|
||||
split_element_index.SetSize(0);
|
||||
int NEsplit = 0;
|
||||
for (int e = 0; e < mesh->GetNE(); e++)
|
||||
{
|
||||
const Geometry::Type gt = mesh->GetElement(e)->GetGeometryType();
|
||||
if (gt == Geometry::TRIANGLE || gt == Geometry::PRISM)
|
||||
{
|
||||
NEsplit = 3;
|
||||
}
|
||||
else if (gt == Geometry::TETRAHEDRON)
|
||||
{
|
||||
NEsplit = 4;
|
||||
}
|
||||
else if (gt == Geometry::PYRAMID)
|
||||
{
|
||||
NEsplit = 8;
|
||||
}
|
||||
else if (gt == Geometry::SQUARE || gt == Geometry::CUBE)
|
||||
{
|
||||
NEsplit = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
MFEM_ABORT("Unsupported geometry type.");
|
||||
}
|
||||
NE_split_total += NEsplit;
|
||||
for (int i = 0; i < NEsplit; i++)
|
||||
{
|
||||
split_element_map.Append(e);
|
||||
split_element_index.Append(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FindPointsGSLIB::SetupIntegrationRuleForSplitMesh(Mesh *meshin,
|
||||
@@ -1431,6 +1395,79 @@ void FindPointsGSLIB::SetupIntegrationRuleForSplitMesh(Mesh *meshin,
|
||||
}
|
||||
}
|
||||
|
||||
void FindPointsGSLIB::SetupSplitMeshesAndIntegrationRules(const int order)
|
||||
{
|
||||
MFEM_VERIFY(mesh, "Setup FindPointsGSLIB with mesh first.");
|
||||
const int dof1D = order+1;
|
||||
const int dim = mesh->Dimension();
|
||||
|
||||
SetupSplitMeshes();
|
||||
if (dim == 2)
|
||||
{
|
||||
if (ir_split[0]) { delete ir_split[0]; ir_split[0] = NULL; }
|
||||
ir_split[0] = new IntegrationRule(3*pow(dof1D, dim));
|
||||
SetupIntegrationRuleForSplitMesh(mesh_split[0], ir_split[0], order);
|
||||
|
||||
if (ir_split[1]) { delete ir_split[1]; ir_split[1] = NULL; }
|
||||
ir_split[1] = new IntegrationRule(pow(dof1D, dim));
|
||||
SetupIntegrationRuleForSplitMesh(mesh_split[1], ir_split[1], order);
|
||||
}
|
||||
else if (dim == 3)
|
||||
{
|
||||
if (ir_split[0]) { delete ir_split[0]; ir_split[0] = NULL; }
|
||||
ir_split[0] = new IntegrationRule(pow(dof1D, dim));
|
||||
SetupIntegrationRuleForSplitMesh(mesh_split[0], ir_split[0], order);
|
||||
|
||||
if (ir_split[1]) { delete ir_split[1]; ir_split[1] = NULL; }
|
||||
ir_split[1] = new IntegrationRule(4*pow(dof1D, dim));
|
||||
SetupIntegrationRuleForSplitMesh(mesh_split[1], ir_split[1], order);
|
||||
|
||||
if (ir_split[2]) { delete ir_split[2]; ir_split[2] = NULL; }
|
||||
ir_split[2] = new IntegrationRule(3*pow(dof1D, dim));
|
||||
SetupIntegrationRuleForSplitMesh(mesh_split[2], ir_split[2], order);
|
||||
|
||||
if (ir_split[3]) { delete ir_split[3]; ir_split[3] = NULL; }
|
||||
ir_split[3] = new IntegrationRule(8*pow(dof1D, dim));
|
||||
SetupIntegrationRuleForSplitMesh(mesh_split[3], ir_split[3], order);
|
||||
}
|
||||
|
||||
// Setup map for non tensor-product elements
|
||||
NE_split_total = 0;
|
||||
split_element_map.SetSize(0);
|
||||
split_element_index.SetSize(0);
|
||||
int NEsplit = 0;
|
||||
for (int e = 0; e < mesh->GetNE(); e++)
|
||||
{
|
||||
const Geometry::Type gt = mesh->GetElement(e)->GetGeometryType();
|
||||
if (gt == Geometry::TRIANGLE || gt == Geometry::PRISM)
|
||||
{
|
||||
NEsplit = 3;
|
||||
}
|
||||
else if (gt == Geometry::TETRAHEDRON)
|
||||
{
|
||||
NEsplit = 4;
|
||||
}
|
||||
else if (gt == Geometry::PYRAMID)
|
||||
{
|
||||
NEsplit = 8;
|
||||
}
|
||||
else if (gt == Geometry::SQUARE || gt == Geometry::CUBE)
|
||||
{
|
||||
NEsplit = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
MFEM_ABORT("Unsupported geometry type.");
|
||||
}
|
||||
NE_split_total += NEsplit;
|
||||
for (int i = 0; i < NEsplit; i++)
|
||||
{
|
||||
split_element_map.Append(e);
|
||||
split_element_index.Append(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FindPointsGSLIB::GetNodalValues(const GridFunction *gf_in,
|
||||
Vector &node_vals)
|
||||
{
|
||||
@@ -2081,6 +2118,19 @@ void FindPointsGSLIB::InterpolateGeneral(const GridFunction &field_in,
|
||||
} // parallel
|
||||
}
|
||||
|
||||
Array<unsigned int> FindPointsGSLIB::GetPointsNotFoundIndices() const
|
||||
{
|
||||
Array<unsigned int> nf_idxs;
|
||||
for (int i = 0; i < gsl_code.Size(); i++)
|
||||
{
|
||||
if (gsl_code[i] == 2)
|
||||
{
|
||||
nf_idxs.Append(i);
|
||||
}
|
||||
}
|
||||
return nf_idxs;
|
||||
}
|
||||
|
||||
void FindPointsGSLIB::DistributePointInfoToOwningMPIRanks(
|
||||
Array<unsigned int> &recv_elem, Vector &recv_ref,
|
||||
Array<unsigned int> &recv_code)
|
||||
@@ -2386,6 +2436,10 @@ void OversetFindPointsGSLIB::Setup(Mesh &m, const int meshid,
|
||||
{
|
||||
MFEM_VERIFY(m.GetNodes() != NULL, "Mesh nodes are required.");
|
||||
const int meshOrder = m.GetNodes()->FESpace()->GetMaxElementOrder();
|
||||
const int gfOrder = gfmax ? gfmax->FESpace()->GetMaxElementOrder() :
|
||||
meshOrder;
|
||||
MFEM_VERIFY(meshOrder == gfOrder,
|
||||
"Mesh order must match gfmax order in OversetFindPointsGSLIB.");
|
||||
|
||||
// FreeData if OversetFindPointsGSLIB::Setup has been called already
|
||||
if (setupflag) { FreeData(); }
|
||||
@@ -2395,35 +2449,7 @@ void OversetFindPointsGSLIB::Setup(Mesh &m, const int meshid,
|
||||
const FiniteElement *fe = mesh->GetNodalFESpace()->GetTypicalFE();
|
||||
unsigned dof1D = fe->GetOrder() + 1;
|
||||
|
||||
SetupSplitMeshes();
|
||||
if (dim == 2)
|
||||
{
|
||||
if (ir_split[0]) { delete ir_split[0]; ir_split[0] = NULL; }
|
||||
ir_split[0] = new IntegrationRule(3*pow(dof1D, dim));
|
||||
SetupIntegrationRuleForSplitMesh(mesh_split[0], ir_split[0], meshOrder);
|
||||
|
||||
if (ir_split[1]) { delete ir_split[1]; ir_split[1] = NULL; }
|
||||
ir_split[1] = new IntegrationRule(pow(dof1D, dim));
|
||||
SetupIntegrationRuleForSplitMesh(mesh_split[1], ir_split[1], meshOrder);
|
||||
}
|
||||
else if (dim == 3)
|
||||
{
|
||||
if (ir_split[0]) { delete ir_split[0]; ir_split[0] = NULL; }
|
||||
ir_split[0] = new IntegrationRule(pow(dof1D, dim));
|
||||
SetupIntegrationRuleForSplitMesh(mesh_split[0], ir_split[0], meshOrder);
|
||||
|
||||
if (ir_split[1]) { delete ir_split[1]; ir_split[1] = NULL; }
|
||||
ir_split[1] = new IntegrationRule(4*pow(dof1D, dim));
|
||||
SetupIntegrationRuleForSplitMesh(mesh_split[1], ir_split[1], meshOrder);
|
||||
|
||||
if (ir_split[2]) { delete ir_split[2]; ir_split[2] = NULL; }
|
||||
ir_split[2] = new IntegrationRule(3*pow(dof1D, dim));
|
||||
SetupIntegrationRuleForSplitMesh(mesh_split[2], ir_split[2], meshOrder);
|
||||
|
||||
if (ir_split[3]) { delete ir_split[3]; ir_split[3] = NULL; }
|
||||
ir_split[3] = new IntegrationRule(8*pow(dof1D, dim));
|
||||
SetupIntegrationRuleForSplitMesh(mesh_split[3], ir_split[3], meshOrder);
|
||||
}
|
||||
SetupSplitMeshesAndIntegrationRules(meshOrder);
|
||||
|
||||
GetNodalValues(mesh->GetNodes(), gsl_mesh);
|
||||
|
||||
@@ -2480,7 +2506,7 @@ void OversetFindPointsGSLIB::FindPoints(const Vector &point_pos,
|
||||
{
|
||||
MFEM_VERIFY(setupflag, "Use OversetFindPointsGSLIB::Setup before "
|
||||
"finding points.");
|
||||
MFEM_VERIFY(overset, "Please setup FindPoints for overlapping grids.");
|
||||
MFEM_VERIFY(overset, "Please use OversetFindPoints for overlapping grids.");
|
||||
points_cnt = point_pos.Size() / dim;
|
||||
unsigned int match = 0; // Don't find points in the mesh if point_id=mesh_id
|
||||
|
||||
|
||||
+28
-3
@@ -13,7 +13,11 @@
|
||||
#define MFEM_GSLIB
|
||||
|
||||
#include "../config/config.hpp"
|
||||
#ifdef MFEM_USE_MPI
|
||||
#include "pgridfunc.hpp"
|
||||
#else
|
||||
#include "gridfunc.hpp"
|
||||
#endif
|
||||
|
||||
#ifdef MFEM_USE_GSLIB
|
||||
|
||||
@@ -131,6 +135,10 @@ protected:
|
||||
IntegrationRule *irule,
|
||||
int order);
|
||||
|
||||
/// Helper function that calls \ref SetupSplitMeshes and
|
||||
/// \ref SetupIntegrationRuleForSplitMesh.
|
||||
virtual void SetupSplitMeshesAndIntegrationRules(const int order);
|
||||
|
||||
/// Get GridFunction value at the points expected by GSLIB.
|
||||
virtual void GetNodalValues(const GridFunction *gf_in, Vector &node_vals);
|
||||
|
||||
@@ -190,14 +198,23 @@ protected:
|
||||
void InterpolateOnDevice(const Vector &field_in_evec, Vector &field_out,
|
||||
const int nel, const int ncomp,
|
||||
const int dof1dsol, const int ordering);
|
||||
|
||||
public:
|
||||
FindPointsGSLIB();
|
||||
FindPointsGSLIB(Mesh &mesh_in, const double bb_t = 0.1,
|
||||
const double newt_tol = 1.0e-12,
|
||||
const int npt_max = 256);
|
||||
|
||||
#ifdef MFEM_USE_MPI
|
||||
FindPointsGSLIB(MPI_Comm comm_);
|
||||
FindPointsGSLIB(ParMesh &mesh_in, const double bb_t = 0.1,
|
||||
const double newt_tol = 1.0e-12,
|
||||
const int npt_max = 256);
|
||||
#endif
|
||||
|
||||
virtual ~FindPointsGSLIB();
|
||||
FindPointsGSLIB(const FindPointsGSLIB&) = delete;
|
||||
FindPointsGSLIB& operator=(const FindPointsGSLIB&) = delete;
|
||||
|
||||
/** Initializes the internal mesh in gslib, by sending the positions of the
|
||||
Gauss-Lobatto nodes of the input Mesh object \p m.
|
||||
@@ -212,8 +229,8 @@ public:
|
||||
@param[in] npt_max (Optional) Number of points for simultaneous
|
||||
iteration. This alters performance and
|
||||
memory footprint.*/
|
||||
void Setup(Mesh &m, const double bb_t = 0.1,
|
||||
const double newt_tol = 1.0e-12,
|
||||
|
||||
void Setup(Mesh &m, const double bb_t = 0.1, const double newt_tol = 1.0e-12,
|
||||
const int npt_max = 256);
|
||||
/** Searches positions given in physical space by \p point_pos.
|
||||
These positions can be ordered byNodes: (XXX...,YYY...,ZZZ) or
|
||||
@@ -289,7 +306,12 @@ public:
|
||||
|
||||
/** Cleans up memory allocated internally by gslib.
|
||||
Note that in parallel, this must be called before MPI_Finalize(), as it
|
||||
calls MPI_Comm_free() for internal gslib communicators. */
|
||||
calls MPI_Comm_free() for internal gslib communicators. FreeData is
|
||||
also called by the class destructor and there are no memory leaks if the
|
||||
destructor is called before MPI_Finalize(). If the destructor is called
|
||||
after MPI_Finalize(), there will be an error because gslib will try to
|
||||
invoke some MPI functions.
|
||||
*/
|
||||
virtual void FreeData();
|
||||
|
||||
/// Return code for each point searched by FindPoints: inside element (0), on
|
||||
@@ -312,6 +334,9 @@ public:
|
||||
/// point found by FindPoints.
|
||||
virtual const Vector &GetGSLIBReferencePosition() const { return gsl_ref; }
|
||||
|
||||
/// Get array of indices of not-found points.
|
||||
Array<unsigned int> GetPointsNotFoundIndices() const;
|
||||
|
||||
/** @name Methods to support a custom interpolation procedure.
|
||||
\brief The physical-space point that the user seeks to interpolate at
|
||||
could be located inside an element on another mpi rank.
|
||||
|
||||
+348
-35
@@ -181,7 +181,7 @@ void HyperbolicFormIntegrator::AssembleFaceVector(
|
||||
// current elements' the number of degrees of freedom
|
||||
// does not consider the number of equations
|
||||
const int dof1 = el1.GetDof();
|
||||
const int dof2 = el2.GetDof();
|
||||
const int dof2 = (Tr.Elem2No >= 0)?(el2.GetDof()):(0);
|
||||
|
||||
#ifdef MFEM_THREAD_SAFE
|
||||
// Local storage for element integration
|
||||
@@ -219,7 +219,9 @@ void HyperbolicFormIntegrator::AssembleFaceVector(
|
||||
const IntegrationRule *ir = IntRule;
|
||||
if (!ir)
|
||||
{
|
||||
const int order = 2*std::max(el1.GetOrder(), el2.GetOrder()) + IntOrderOffset;
|
||||
const int max_el_order = dof2 ? std::max(el1.GetOrder(),
|
||||
el2.GetOrder()) : el1.GetOrder();
|
||||
const int order = 2*max_el_order + IntOrderOffset;
|
||||
ir = &IntRules.Get(Tr.GetGeometryType(), order);
|
||||
}
|
||||
// loop over integration points
|
||||
@@ -231,18 +233,22 @@ void HyperbolicFormIntegrator::AssembleFaceVector(
|
||||
|
||||
// Calculate basis functions on both elements at the face
|
||||
el1.CalcShape(Tr.GetElement1IntPoint(), shape1);
|
||||
el2.CalcShape(Tr.GetElement2IntPoint(), shape2);
|
||||
|
||||
// Interpolate elfun at the point
|
||||
elfun1_mat.MultTranspose(shape1, state1);
|
||||
elfun2_mat.MultTranspose(shape2, state2);
|
||||
|
||||
if (dof2)
|
||||
{
|
||||
// Calculate basis functions on both elements at the face
|
||||
el2.CalcShape(Tr.GetElement2IntPoint(), shape2);
|
||||
// Interpolate elfun at the point
|
||||
elfun2_mat.MultTranspose(shape2, state2);
|
||||
}
|
||||
|
||||
// Get the normal vector and the flux on the face
|
||||
if (nor.Size() == 1) // if 1D, use 1 or -1.
|
||||
{
|
||||
// This assume the 1D integration point is in (0,1). This may not work
|
||||
// if this changes.
|
||||
nor(0) = (Tr.GetElement1IntPoint().x - 0.5) * 2.0;
|
||||
nor(0) = 2*Tr.GetElement1IntPoint().x - 1.;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -250,14 +256,18 @@ void HyperbolicFormIntegrator::AssembleFaceVector(
|
||||
}
|
||||
// Compute F(u+, x) and F(u-, x) with maximum characteristic speed
|
||||
// Compute hat(F) using evaluated quantities
|
||||
const real_t speed = numFlux.Eval(state1, state2, nor, Tr, fluxN);
|
||||
const real_t speed = (dof2) ? numFlux.Eval(state1, state2, nor, Tr, fluxN):
|
||||
fluxFunction.ComputeFluxDotN(state1, nor, Tr, fluxN);
|
||||
|
||||
// Update the global max char speed
|
||||
max_char_speed = std::max(speed, max_char_speed);
|
||||
|
||||
// pre-multiply integration weight to flux
|
||||
AddMult_a_VWt(-ip.weight*sign, shape1, fluxN, elvect1_mat);
|
||||
AddMult_a_VWt(+ip.weight*sign, shape2, fluxN, elvect2_mat);
|
||||
if (dof2)
|
||||
{
|
||||
AddMult_a_VWt(+ip.weight*sign, shape2, fluxN, elvect2_mat);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -268,7 +278,7 @@ void HyperbolicFormIntegrator::AssembleFaceGrad(
|
||||
// current elements' the number of degrees of freedom
|
||||
// does not consider the number of equations
|
||||
const int dof1 = el1.GetDof();
|
||||
const int dof2 = el2.GetDof();
|
||||
const int dof2 = (Tr.Elem2No >= 0)?(el2.GetDof()):(0);
|
||||
|
||||
#ifdef MFEM_THREAD_SAFE
|
||||
// Local storage for element integration
|
||||
@@ -302,7 +312,9 @@ void HyperbolicFormIntegrator::AssembleFaceGrad(
|
||||
const IntegrationRule *ir = IntRule;
|
||||
if (!ir)
|
||||
{
|
||||
const int order = 2*std::max(el1.GetOrder(), el2.GetOrder()) + IntOrderOffset;
|
||||
const int max_el_order = dof2 ? std::max(el1.GetOrder(),
|
||||
el2.GetOrder()) : el1.GetOrder();
|
||||
const int order = 2*max_el_order + IntOrderOffset;
|
||||
ir = &IntRules.Get(Tr.GetGeometryType(), order);
|
||||
}
|
||||
// loop over integration points
|
||||
@@ -312,20 +324,25 @@ void HyperbolicFormIntegrator::AssembleFaceGrad(
|
||||
|
||||
Tr.SetAllIntPoints(&ip); // set face and element int. points
|
||||
|
||||
// Calculate basis functions on both elements at the face
|
||||
// Calculate basis functions of the first element at the face
|
||||
el1.CalcShape(Tr.GetElement1IntPoint(), shape1);
|
||||
el2.CalcShape(Tr.GetElement2IntPoint(), shape2);
|
||||
|
||||
// Interpolate elfun at the point
|
||||
elfun1_mat.MultTranspose(shape1, state1);
|
||||
elfun2_mat.MultTranspose(shape2, state2);
|
||||
|
||||
if (dof2)
|
||||
{
|
||||
// Calculate basis function of the second element at the face
|
||||
el2.CalcShape(Tr.GetElement2IntPoint(), shape2);
|
||||
|
||||
// Interpolate elfun at the point
|
||||
elfun2_mat.MultTranspose(shape2, state2);
|
||||
}
|
||||
|
||||
// Get the normal vector and the flux on the face
|
||||
if (nor.Size() == 1) // if 1D, use 1 or -1.
|
||||
{
|
||||
// This assume the 1D integration point is in (0,1). This may not work
|
||||
// if this changes.
|
||||
nor(0) = (Tr.GetElement1IntPoint().x - 0.5) * 2.0;
|
||||
nor(0) = 2*Tr.GetElement1IntPoint().x - 1.;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -335,7 +352,14 @@ void HyperbolicFormIntegrator::AssembleFaceGrad(
|
||||
// Trial side 1
|
||||
|
||||
// Compute hat(J) using evaluated quantities
|
||||
numFlux.Grad(1, state1, state2, nor, Tr, JDotN);
|
||||
if (dof2)
|
||||
{
|
||||
numFlux.Grad(1, state1, state2, nor, Tr, JDotN);
|
||||
}
|
||||
else
|
||||
{
|
||||
fluxFunction.ComputeFluxJacobianDotN(state1, nor, Tr, JDotN);
|
||||
}
|
||||
|
||||
const int ioff = fluxFunction.num_equations * dof1;
|
||||
|
||||
@@ -360,36 +384,325 @@ void HyperbolicFormIntegrator::AssembleFaceGrad(
|
||||
}
|
||||
}
|
||||
|
||||
// Trial side 2
|
||||
if (dof2)
|
||||
{
|
||||
// Trial side 2
|
||||
|
||||
// Compute hat(J) using evaluated quantities
|
||||
numFlux.Grad(2, state1, state2, nor, Tr, JDotN);
|
||||
|
||||
const int joff = ioff;
|
||||
|
||||
for (int di = 0; di < fluxFunction.num_equations; di++)
|
||||
for (int dj = 0; dj < fluxFunction.num_equations; dj++)
|
||||
{
|
||||
// pre-multiply integration weight to Jacobian
|
||||
const real_t w = +ip.weight * sign * JDotN(di,dj);
|
||||
for (int j = 0; j < dof2; j++)
|
||||
{
|
||||
// Test side 1
|
||||
for (int i = 0; i < dof1; i++)
|
||||
{
|
||||
elmat(i+dof1*di, joff+j+dof2*dj) += w * shape1(i) * shape2(j);
|
||||
}
|
||||
|
||||
// Test side 2
|
||||
for (int i = 0; i < dof2; i++)
|
||||
{
|
||||
elmat(ioff+i+dof2*di, joff+j+dof2*dj) -= w * shape2(i) * shape2(j);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BdrHyperbolicDirichletIntegrator::BdrHyperbolicDirichletIntegrator(
|
||||
const NumericalFlux &numFlux,
|
||||
VectorCoefficient &bdrState,
|
||||
const int IntOrderOffset,
|
||||
real_t sign)
|
||||
: NonlinearFormIntegrator(),
|
||||
numFlux(numFlux),
|
||||
fluxFunction(numFlux.GetFluxFunction()),
|
||||
u_vcoeff(bdrState),
|
||||
IntOrderOffset(IntOrderOffset),
|
||||
sign(sign),
|
||||
num_equations(fluxFunction.num_equations)
|
||||
{
|
||||
MFEM_VERIFY(fluxFunction.num_equations == bdrState.GetVDim(),
|
||||
"Flux function does not match the vector dimension of the coefficient!");
|
||||
#ifndef MFEM_THREAD_SAFE
|
||||
state_in.SetSize(num_equations);
|
||||
state_out.SetSize(num_equations);
|
||||
fluxN.SetSize(num_equations);
|
||||
JDotN.SetSize(num_equations);
|
||||
nor.SetSize(fluxFunction.dim);
|
||||
#endif
|
||||
ResetMaxCharSpeed();
|
||||
}
|
||||
|
||||
void BdrHyperbolicDirichletIntegrator::AssembleFaceVector(
|
||||
const FiniteElement &el, const FiniteElement &,
|
||||
FaceElementTransformations &Tr, const Vector &elfun, Vector &elvect)
|
||||
{
|
||||
MFEM_ASSERT(Tr.Elem2No < 0, "Not a boundary face!");
|
||||
|
||||
// current elements' the number of degrees of freedom
|
||||
// does not consider the number of equations
|
||||
const int dof = el.GetDof();
|
||||
|
||||
#ifdef MFEM_THREAD_SAFE
|
||||
// Local storage for element integration
|
||||
|
||||
// shape function value at an integration point
|
||||
Vector shape(dof);
|
||||
// normal vector (usually not a unit vector)
|
||||
Vector nor(Tr.GetSpaceDim());
|
||||
// state value at an integration point - interior
|
||||
Vector state_in(num_equations);
|
||||
// state value at an integration point - boundary
|
||||
Vector state_out(num_equations);
|
||||
// hat(F)(u,x)
|
||||
Vector fluxN(num_equations);
|
||||
#else
|
||||
shape.SetSize(dof);
|
||||
#endif
|
||||
|
||||
elvect.SetSize(dof * num_equations);
|
||||
elvect = 0.0;
|
||||
|
||||
const DenseMatrix elfun_mat(elfun.GetData(), dof, num_equations);
|
||||
|
||||
DenseMatrix elvect_mat(elvect.GetData(), dof, num_equations);
|
||||
|
||||
// Obtain integration rule. If integration is rule is given, then use it.
|
||||
// Otherwise, get (2*p + IntOrderOffset) order integration rule
|
||||
const IntegrationRule *ir = IntRule;
|
||||
if (!ir)
|
||||
{
|
||||
const int order = 2*el.GetOrder() + IntOrderOffset;
|
||||
ir = &IntRules.Get(Tr.GetGeometryType(), order);
|
||||
}
|
||||
// loop over integration points
|
||||
for (int i = 0; i < ir->GetNPoints(); i++)
|
||||
{
|
||||
const IntegrationPoint &ip = ir->IntPoint(i);
|
||||
|
||||
Tr.SetAllIntPoints(&ip); // set face and element int. points
|
||||
|
||||
// Calculate basis functions at the face
|
||||
el.CalcShape(Tr.GetElement1IntPoint(), shape);
|
||||
|
||||
// Interpolate elfun at the point
|
||||
elfun_mat.MultTranspose(shape, state_in);
|
||||
|
||||
// Evaluate boundary state at the point
|
||||
u_vcoeff.Eval(state_out, Tr, ip);
|
||||
|
||||
// Get the normal vector and the flux on the face
|
||||
if (nor.Size() == 1) // if 1D, use 1 or -1.
|
||||
{
|
||||
nor(0) = 2*Tr.GetElement1IntPoint().x - 1.;
|
||||
}
|
||||
else
|
||||
{
|
||||
CalcOrtho(Tr.Jacobian(), nor);
|
||||
}
|
||||
// Compute F(u+, x) and F(u_b, x) with maximum characteristic speed
|
||||
// Compute hat(F) using evaluated quantities
|
||||
const real_t speed = numFlux.Eval(state_in, state_out, nor, Tr, fluxN);
|
||||
|
||||
// Update the global max char speed
|
||||
max_char_speed = std::max(speed, max_char_speed);
|
||||
|
||||
// pre-multiply integration weight to flux
|
||||
AddMult_a_VWt(-ip.weight*sign, shape, fluxN, elvect_mat);
|
||||
}
|
||||
}
|
||||
|
||||
void BdrHyperbolicDirichletIntegrator::AssembleFaceGrad(
|
||||
const FiniteElement &el, const FiniteElement &,
|
||||
FaceElementTransformations &Tr, const Vector &elfun, DenseMatrix &elmat)
|
||||
{
|
||||
// current elements' the number of degrees of freedom
|
||||
// does not consider the number of equations
|
||||
const int dof = el.GetDof();
|
||||
|
||||
#ifdef MFEM_THREAD_SAFE
|
||||
// Local storage for element integration
|
||||
|
||||
// shape function value at an integration point
|
||||
Vector shape(dof);
|
||||
// normal vector (usually not a unit vector)
|
||||
Vector nor(Tr.GetSpaceDim());
|
||||
// state value at an integration point - interior
|
||||
Vector state_in(num_equations);
|
||||
// state value at an integration point - boundary
|
||||
Vector state_out(num_equations);
|
||||
// hat(J)(u,x)
|
||||
DenseMatrix JDotN(num_equations);
|
||||
#else
|
||||
shape.SetSize(dof);
|
||||
#endif
|
||||
|
||||
elmat.SetSize(dof * num_equations);
|
||||
elmat = 0.0;
|
||||
|
||||
const DenseMatrix elfun_mat(elfun.GetData(), dof, num_equations);
|
||||
|
||||
// Obtain integration rule. If integration is rule is given, then use it.
|
||||
// Otherwise, get (2*p + IntOrderOffset) order integration rule
|
||||
const IntegrationRule *ir = IntRule;
|
||||
if (!ir)
|
||||
{
|
||||
const int order = 2*el.GetOrder() + IntOrderOffset;
|
||||
ir = &IntRules.Get(Tr.GetGeometryType(), order);
|
||||
}
|
||||
// loop over integration points
|
||||
for (int q = 0; q < ir->GetNPoints(); q++)
|
||||
{
|
||||
const IntegrationPoint &ip = ir->IntPoint(q);
|
||||
|
||||
Tr.SetAllIntPoints(&ip); // set face and element int. points
|
||||
|
||||
// Calculate basis functions at the face
|
||||
el.CalcShape(Tr.GetElement1IntPoint(), shape);
|
||||
|
||||
// Interpolate elfun at the point
|
||||
elfun_mat.MultTranspose(shape, state_in);
|
||||
|
||||
// Evaluate boundary state at the point
|
||||
u_vcoeff.Eval(state_out, Tr, ip);
|
||||
|
||||
// Get the normal vector and the flux on the face
|
||||
if (nor.Size() == 1) // if 1D, use 1 or -1.
|
||||
{
|
||||
nor(0) = 2*Tr.GetElement1IntPoint().x - 1.;
|
||||
}
|
||||
else
|
||||
{
|
||||
CalcOrtho(Tr.Jacobian(), nor);
|
||||
}
|
||||
|
||||
// Compute hat(J) using evaluated quantities
|
||||
numFlux.Grad(2, state1, state2, nor, Tr, JDotN);
|
||||
|
||||
const int joff = ioff;
|
||||
numFlux.Grad(1, state_in, state_out, nor, Tr, JDotN);
|
||||
|
||||
for (int di = 0; di < fluxFunction.num_equations; di++)
|
||||
for (int dj = 0; dj < fluxFunction.num_equations; dj++)
|
||||
{
|
||||
// pre-multiply integration weight to Jacobian
|
||||
const real_t w = +ip.weight * sign * JDotN(di,dj);
|
||||
for (int j = 0; j < dof2; j++)
|
||||
{
|
||||
// Test side 1
|
||||
for (int i = 0; i < dof1; i++)
|
||||
const real_t w = -ip.weight * sign * JDotN(di,dj);
|
||||
for (int j = 0; j < dof; j++)
|
||||
for (int i = 0; i < dof; i++)
|
||||
{
|
||||
elmat(i+dof1*di, joff+j+dof2*dj) += w * shape1(i) * shape2(j);
|
||||
elmat(i+dof*di, j+dof*dj) += w * shape(i) * shape(j);
|
||||
}
|
||||
|
||||
// Test side 2
|
||||
for (int i = 0; i < dof2; i++)
|
||||
{
|
||||
elmat(ioff+i+dof2*di, joff+j+dof2*dj) -= w * shape2(i) * shape2(j);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BoundaryHyperbolicFlowIntegrator::BoundaryHyperbolicFlowIntegrator(
|
||||
const FluxFunction &flux, VectorCoefficient &u, real_t alpha_, real_t beta_,
|
||||
const int IntOrderOffset_)
|
||||
: fluxFunction(flux), u_vcoeff(u), alpha(alpha_), beta(beta_),
|
||||
IntOrderOffset(IntOrderOffset_)
|
||||
{
|
||||
MFEM_VERIFY(fluxFunction.num_equations == u_vcoeff.GetVDim(),
|
||||
"Flux function does not match the vector dimension of the coefficient!");
|
||||
#ifndef MFEM_THREAD_SAFE
|
||||
state.SetSize(fluxFunction.num_equations);
|
||||
nor.SetSize(fluxFunction.dim);
|
||||
fluxN.SetSize(fluxFunction.num_equations);
|
||||
#endif
|
||||
ResetMaxCharSpeed();
|
||||
}
|
||||
|
||||
void BoundaryHyperbolicFlowIntegrator::AssembleRHSElementVect(
|
||||
const FiniteElement &el, ElementTransformation &Tr, Vector &elvect)
|
||||
{
|
||||
mfem_error("BoundaryHyperbolicFlowIntegrator::AssembleRHSElementVect\n"
|
||||
" is not implemented as boundary integrator!\n"
|
||||
" Use LinearForm::AddBdrFaceIntegrator instead of\n"
|
||||
" LinearForm::AddBoundaryIntegrator.");
|
||||
}
|
||||
|
||||
void BoundaryHyperbolicFlowIntegrator::AssembleRHSElementVect(
|
||||
const FiniteElement &el, FaceElementTransformations &Tr, Vector &elvect)
|
||||
{
|
||||
// current elements' the number of degrees of freedom
|
||||
// does not consider the number of equations
|
||||
const int dof = el.GetDof();
|
||||
|
||||
#ifdef MFEM_THREAD_SAFE
|
||||
// Local storage for element integration
|
||||
|
||||
// shape function value at an integration point
|
||||
Vector shape(dof);
|
||||
// state value at an integration point
|
||||
Vector state(fluxFunction.num_equations);
|
||||
// normal vector (usually not a unit vector)
|
||||
Vector nor(Tr.GetSpaceDim());
|
||||
// hat(F)(u,x)
|
||||
Vector fluxN(fluxFunction.num_equations);
|
||||
#else
|
||||
shape.SetSize(dof);
|
||||
#endif
|
||||
|
||||
elvect.SetSize(dof * fluxFunction.num_equations);
|
||||
elvect = 0.0;
|
||||
|
||||
DenseMatrix elvect_mat(elvect.GetData(), dof, fluxFunction.num_equations);
|
||||
|
||||
// Obtain integration rule. If integration is rule is given, then use it.
|
||||
// Otherwise, get (2*p + IntOrderOffset) order integration rule
|
||||
const IntegrationRule *ir = IntRule;
|
||||
if (!ir)
|
||||
{
|
||||
const int order = 2*el.GetOrder() + IntOrderOffset;
|
||||
ir = &IntRules.Get(Tr.GetGeometryType(), order);
|
||||
}
|
||||
// loop over integration points
|
||||
for (int i = 0; i < ir->GetNPoints(); i++)
|
||||
{
|
||||
const IntegrationPoint &ip = ir->IntPoint(i);
|
||||
|
||||
Tr.SetAllIntPoints(&ip); // set face and element int. points
|
||||
|
||||
// Calculate basis functions on both elements at the face
|
||||
el.CalcShape(Tr.GetElement1IntPoint(), shape);
|
||||
|
||||
// Evaluate the coefficient at the point
|
||||
u_vcoeff.Eval(state, Tr, ip);
|
||||
|
||||
// Get the normal vector and the flux on the face
|
||||
if (nor.Size() == 1) // if 1D, use 1 or -1.
|
||||
{
|
||||
nor(0) = 2*Tr.GetElement1IntPoint().x - 1.;
|
||||
}
|
||||
else
|
||||
{
|
||||
CalcOrtho(Tr.Jacobian(), nor);
|
||||
}
|
||||
// Compute F(u, x) with maximum characteristic speed
|
||||
const real_t speed = fluxFunction.ComputeFluxDotN(state, nor, Tr, fluxN);
|
||||
|
||||
// Update the global max char speed
|
||||
max_char_speed = std::max(speed, max_char_speed);
|
||||
|
||||
// pre-multiply integration weight to flux
|
||||
const real_t a = 0.5 * alpha * ip.weight;
|
||||
const real_t b = beta * ip.weight;
|
||||
|
||||
for (int n = 0; n < fluxFunction.num_equations; n++)
|
||||
{
|
||||
fluxN(n) = a * fluxN(n) - b * fabs(fluxN(n));
|
||||
}
|
||||
|
||||
AddMultVWt(shape, fluxN, elvect_mat);
|
||||
}
|
||||
}
|
||||
|
||||
real_t FluxFunction::ComputeFluxDotN(const Vector &U,
|
||||
const Vector &normal,
|
||||
FaceElementTransformations &Tr,
|
||||
|
||||
+188
-16
@@ -306,12 +306,14 @@ MFEM_DEPRECATED typedef NumericalFlux RiemannSolver;
|
||||
class HyperbolicFormIntegrator : public NonlinearFormIntegrator
|
||||
{
|
||||
private:
|
||||
// The maximum characteristic speed, updated during element/face vector assembly
|
||||
real_t max_char_speed;
|
||||
const NumericalFlux &numFlux; // Numerical flux that maps F(u±,x) to F̂
|
||||
const FluxFunction &fluxFunction;
|
||||
const int IntOrderOffset; // integration order offset, 2*p + IntOrderOffset.
|
||||
const real_t sign;
|
||||
|
||||
// The maximum characteristic speed, updated during element/face vector assembly
|
||||
real_t max_char_speed;
|
||||
|
||||
#ifndef MFEM_THREAD_SAFE
|
||||
// Local storage for element integration
|
||||
Vector shape; // shape function value at an integration point
|
||||
@@ -331,8 +333,9 @@ private:
|
||||
|
||||
public:
|
||||
const int num_equations; // the number of equations
|
||||
|
||||
/**
|
||||
* @brief Construct a new Hyperbolic Form Integrator object
|
||||
* @brief Construct a new HyperbolicFormIntegrator object
|
||||
*
|
||||
* @param[in] numFlux numerical flux
|
||||
* @param[in] IntOrderOffset integration order offset
|
||||
@@ -343,21 +346,14 @@ public:
|
||||
const int IntOrderOffset = 0,
|
||||
const real_t sign = 1.);
|
||||
|
||||
/**
|
||||
* @brief Reset the Max Char Speed 0
|
||||
*
|
||||
*/
|
||||
void ResetMaxCharSpeed()
|
||||
{
|
||||
max_char_speed = 0.0;
|
||||
}
|
||||
/// Reset the maximum characteristic speed to zero
|
||||
void ResetMaxCharSpeed() { max_char_speed = 0.0; }
|
||||
|
||||
real_t GetMaxCharSpeed()
|
||||
{
|
||||
return max_char_speed;
|
||||
}
|
||||
/// Get the maximum characteristic speed
|
||||
real_t GetMaxCharSpeed() const { return max_char_speed; }
|
||||
|
||||
const FluxFunction &GetFluxFunction() { return fluxFunction; }
|
||||
/// Get the associated flux function
|
||||
const FluxFunction &GetFluxFunction() const { return fluxFunction; }
|
||||
|
||||
/**
|
||||
* @brief Implements (F(u), ∇v) with abstract F computed by
|
||||
@@ -416,6 +412,182 @@ public:
|
||||
const Vector &elfun, DenseMatrix &elmat) override;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Abstract boundary hyperbolic form integrator, assembling
|
||||
* <F̂(u⁻,u_b,x) n, [v]> term for scalar finite elements at the boundary.
|
||||
*
|
||||
* This form integrator is coupled with a NumericalFlux that implements the
|
||||
* numerical flux F̂ at the boundary faces. The flux F is obtained from the
|
||||
* FluxFunction assigned to the aforementioned NumericalFlux with the given
|
||||
* boundary coefficient for the state u_b.
|
||||
*
|
||||
* Note the class can be used for imposing conditions on interior interfaces.
|
||||
*/
|
||||
class BdrHyperbolicDirichletIntegrator : public NonlinearFormIntegrator
|
||||
{
|
||||
private:
|
||||
const NumericalFlux &numFlux; // Numerical flux that maps F to F̂
|
||||
const FluxFunction &fluxFunction;
|
||||
VectorCoefficient &u_vcoeff; // Boundary state vector coefficient
|
||||
const int IntOrderOffset; // integration order offset, 2*p + IntOrderOffset.
|
||||
const real_t sign;
|
||||
|
||||
// The maximum characteristic speed, updated during element/face vector assembly
|
||||
real_t max_char_speed;
|
||||
|
||||
#ifndef MFEM_THREAD_SAFE
|
||||
// Local storage for element integration
|
||||
Vector shape; // shape function value at an integration point
|
||||
Vector state_in; // state value at an integration point - interior
|
||||
Vector state_out; // state value at an integration point - boundary
|
||||
Vector nor; // normal vector, see mfem::CalcOrtho()
|
||||
Vector fluxN; // F̂(u⁻,u_b,x) n
|
||||
DenseMatrix JDotN; // Ĵ(u⁻,u_b,x) n
|
||||
#endif
|
||||
|
||||
public:
|
||||
const int num_equations; // the number of equations
|
||||
|
||||
/**
|
||||
* @brief Construct a new BdrHyperbolicDirichletIntegrator object
|
||||
*
|
||||
* @param[in] numFlux numerical flux
|
||||
* @param[in] bdrState boundary state coefficient
|
||||
* @param[in] IntOrderOffset integration order offset
|
||||
* @param[in] sign sign of the convection term
|
||||
*/
|
||||
BdrHyperbolicDirichletIntegrator(
|
||||
const NumericalFlux &numFlux,
|
||||
VectorCoefficient &bdrState,
|
||||
const int IntOrderOffset = 0,
|
||||
const real_t sign = 1.);
|
||||
|
||||
/// Reset the maximum characteristic speed to zero
|
||||
void ResetMaxCharSpeed() { max_char_speed = 0.0; }
|
||||
|
||||
/// Get the maximum characteristic speed
|
||||
real_t GetMaxCharSpeed() const { return max_char_speed; }
|
||||
|
||||
/// Get the associated flux function
|
||||
const FluxFunction &GetFluxFunction() const { return fluxFunction; }
|
||||
|
||||
/**
|
||||
* @brief Implements <-F̂(u⁻,u_b,x) n, [v]> with abstract F̂ computed by
|
||||
* NumericalFlux::Eval() of the numerical flux object
|
||||
*
|
||||
* @param[in] el1 finite element of the interior element
|
||||
* @param[in] el2 not used
|
||||
* @param[in] Tr face element transformations
|
||||
* @param[in] elfun local coefficient of basis for the interior element
|
||||
* @param[out] elvect evaluated dual vector <-F̂(u⁻,u_b,x) n, [v]>
|
||||
*/
|
||||
void AssembleFaceVector(const FiniteElement &el1,
|
||||
const FiniteElement &el2,
|
||||
FaceElementTransformations &Tr,
|
||||
const Vector &elfun, Vector &elvect) override;
|
||||
|
||||
/**
|
||||
* @brief Implements <-Ĵ(u⁻,u_b,x) n, [v]> with abstract Ĵ computed by
|
||||
* NumericalFlux::Grad() of the numerical flux object
|
||||
*
|
||||
* @param[in] el1 finite element of the interior element
|
||||
* @param[in] el2 not used
|
||||
* @param[in] Tr face element transformations
|
||||
* @param[in] elfun local coefficient of basis for the interior element
|
||||
* @param[out] elmat evaluated Jacobian matrix <-Ĵ(u⁻,u_b,x) n, [v]>
|
||||
*/
|
||||
void AssembleFaceGrad(const FiniteElement &el1,
|
||||
const FiniteElement &el2,
|
||||
FaceElementTransformations &Tr,
|
||||
const Vector &elfun, DenseMatrix &elmat) override;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Abstract boundary hyperbolic linear form integrator, assembling
|
||||
* <ɑ/2 F(u,x) n - β |F(u,x) n|, v> terms for scalar finite elements.
|
||||
*
|
||||
* This form integrator is coupled with a FluxFunction that evaluates the
|
||||
* flux F at the boundary.
|
||||
*
|
||||
* Note the upwinding is performed component-wise. For general boundary
|
||||
* integration with a numerical flux, see BdrHyperbolicDirichletIntegrator.
|
||||
*/
|
||||
class BoundaryHyperbolicFlowIntegrator : public LinearFormIntegrator
|
||||
{
|
||||
const FluxFunction &fluxFunction;
|
||||
VectorCoefficient &u_vcoeff;
|
||||
const real_t alpha, beta;
|
||||
const int IntOrderOffset; // integration order offset, 2*p + IntOrderOffset.
|
||||
|
||||
// The maximum characteristic speed, updated during face vector assembly
|
||||
real_t max_char_speed;
|
||||
|
||||
#ifndef MFEM_THREAD_SAFE
|
||||
// Local storage for element integration
|
||||
Vector shape; // shape function value at an integration point
|
||||
Vector state; // state value at an integration point
|
||||
Vector nor; // normal vector, see mfem::CalcOrtho()
|
||||
Vector fluxN; // F(u,x) n
|
||||
#endif
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Construct a new BoundaryHyperbolicFlowIntegrator object
|
||||
*
|
||||
* @param[in] flux flux function
|
||||
* @param[in] u vector state coefficient
|
||||
* @param[in] alpha ɑ coefficient (β = ɑ/2)
|
||||
* @param[in] IntOrderOffset integration order offset
|
||||
*/
|
||||
BoundaryHyperbolicFlowIntegrator(const FluxFunction &flux, VectorCoefficient &u,
|
||||
real_t alpha = -1., int IntOrderOffset = 0)
|
||||
: BoundaryHyperbolicFlowIntegrator(flux, u, alpha, alpha/2., IntOrderOffset) { }
|
||||
|
||||
/**
|
||||
* @brief Construct a new BoundaryHyperbolicFlowIntegrator object
|
||||
*
|
||||
* @param[in] flux flux function
|
||||
* @param[in] u vector state coefficient
|
||||
* @param[in] alpha ɑ coefficient
|
||||
* @param[in] beta β coefficient
|
||||
* @param[in] IntOrderOffset integration order offset
|
||||
*/
|
||||
BoundaryHyperbolicFlowIntegrator(const FluxFunction &flux, VectorCoefficient &u,
|
||||
real_t alpha, real_t beta, int IntOrderOffset = 0);
|
||||
|
||||
/// Reset the maximum characteristic speed to zero
|
||||
void ResetMaxCharSpeed() { max_char_speed = 0.0; }
|
||||
|
||||
/// Get the maximum characteristic speed
|
||||
real_t GetMaxCharSpeed() const { return max_char_speed; }
|
||||
|
||||
/// Get the associated flux function
|
||||
const FluxFunction &GetFluxFunction() const { return fluxFunction; }
|
||||
|
||||
using LinearFormIntegrator::AssembleRHSElementVect;
|
||||
|
||||
/**
|
||||
* @warning Boundary element integration not implemented, use
|
||||
* AssembleRHSElementVect(const FiniteElement&,
|
||||
* FaceElementTransformations &, Vector &) instead
|
||||
*/
|
||||
void AssembleRHSElementVect(const FiniteElement &el,
|
||||
ElementTransformation &Tr,
|
||||
Vector &elvect) override;
|
||||
|
||||
/**
|
||||
* @brief Implements <-F(u,x) n, v> with abstract F computed by
|
||||
* FluxFunction::ComputeFluxDotN() of the flux function object
|
||||
*
|
||||
* @param[in] el finite element
|
||||
* @param[in] Tr face element transformations
|
||||
* @param[out] elvect evaluated dual vector <F(u,x) n, v>
|
||||
*/
|
||||
void AssembleRHSElementVect(const FiniteElement &el,
|
||||
FaceElementTransformations &Tr,
|
||||
Vector &elvect) override;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Rusanov flux, also known as local Lax-Friedrichs,
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -15,6 +15,86 @@
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
CurlCurlIntegrator::CurlCurlIntegrator() : Q(nullptr), DQ(nullptr), MQ(nullptr)
|
||||
{
|
||||
static Kernels kernels;
|
||||
}
|
||||
|
||||
CurlCurlIntegrator::CurlCurlIntegrator(Coefficient &q,
|
||||
const IntegrationRule *ir)
|
||||
: BilinearFormIntegrator(ir), Q(&q), DQ(nullptr), MQ(nullptr)
|
||||
{
|
||||
static Kernels kernels;
|
||||
}
|
||||
|
||||
CurlCurlIntegrator::CurlCurlIntegrator(DiagonalMatrixCoefficient &dq,
|
||||
const IntegrationRule *ir)
|
||||
: BilinearFormIntegrator(ir), Q(nullptr), DQ(&dq), MQ(nullptr)
|
||||
{
|
||||
static Kernels kernels;
|
||||
}
|
||||
|
||||
CurlCurlIntegrator::CurlCurlIntegrator(MatrixCoefficient &mq,
|
||||
const IntegrationRule *ir)
|
||||
: BilinearFormIntegrator(ir), Q(nullptr), DQ(nullptr), MQ(&mq)
|
||||
{
|
||||
static Kernels kernels;
|
||||
}
|
||||
|
||||
/// \cond DO_NOT_DOCUMENT
|
||||
|
||||
CurlCurlIntegrator::Kernels::Kernels()
|
||||
{
|
||||
CurlCurlIntegrator::AddSpecialization<3, 2, 3>();
|
||||
CurlCurlIntegrator::AddSpecialization<3, 3, 4>();
|
||||
CurlCurlIntegrator::AddSpecialization<3, 4, 5>();
|
||||
CurlCurlIntegrator::AddSpecialization<3, 5, 6>();
|
||||
}
|
||||
|
||||
CurlCurlIntegrator::ApplyKernelType
|
||||
CurlCurlIntegrator::ApplyPAKernels::Fallback(int DIM, int, int)
|
||||
{
|
||||
if (DIM == 2) { return internal::PACurlCurlApply2D; }
|
||||
else if (DIM == 3)
|
||||
{
|
||||
if (Device::Allows(Backend::DEVICE_MASK))
|
||||
{
|
||||
return internal::SmemPACurlCurlApply3D;
|
||||
}
|
||||
else
|
||||
{
|
||||
return internal::PACurlCurlApply3D;
|
||||
}
|
||||
}
|
||||
else { MFEM_ABORT(""); }
|
||||
}
|
||||
|
||||
CurlCurlIntegrator::DiagonalKernelType
|
||||
CurlCurlIntegrator::DiagonalPAKernels::Fallback(int DIM, int, int)
|
||||
{
|
||||
if (DIM == 2)
|
||||
{
|
||||
return internal::PACurlCurlAssembleDiagonal2D;
|
||||
}
|
||||
else if (DIM == 3)
|
||||
{
|
||||
if (Device::Allows(Backend::DEVICE_MASK))
|
||||
{
|
||||
return internal::SmemPACurlCurlAssembleDiagonal3D;
|
||||
}
|
||||
else
|
||||
{
|
||||
return internal::PACurlCurlAssembleDiagonal3D;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
MFEM_ABORT("");
|
||||
}
|
||||
}
|
||||
|
||||
/// \endcond DO_NOT_DOCUMENT
|
||||
|
||||
void CurlCurlIntegrator::AssemblePA(const FiniteElementSpace &fes)
|
||||
{
|
||||
// Assumes tensor-product elements
|
||||
@@ -77,129 +157,16 @@ void CurlCurlIntegrator::AssemblePA(const FiniteElementSpace &fes)
|
||||
|
||||
void CurlCurlIntegrator::AssembleDiagonalPA(Vector& diag)
|
||||
{
|
||||
if (dim == 3)
|
||||
{
|
||||
if (Device::Allows(Backend::DEVICE_MASK))
|
||||
{
|
||||
const int ID = (dofs1D << 4) | quad1D;
|
||||
switch (ID)
|
||||
{
|
||||
case 0x23:
|
||||
return internal::SmemPACurlCurlAssembleDiagonal3D<2,3>(
|
||||
dofs1D,
|
||||
quad1D,
|
||||
symmetric, ne,
|
||||
mapsO->B, mapsC->B,
|
||||
mapsO->G, mapsC->G,
|
||||
pa_data, diag);
|
||||
case 0x34:
|
||||
return internal::SmemPACurlCurlAssembleDiagonal3D<3,4>(
|
||||
dofs1D,
|
||||
quad1D,
|
||||
symmetric, ne,
|
||||
mapsO->B, mapsC->B,
|
||||
mapsO->G, mapsC->G,
|
||||
pa_data, diag);
|
||||
case 0x45:
|
||||
return internal::SmemPACurlCurlAssembleDiagonal3D<4,5>(
|
||||
dofs1D,
|
||||
quad1D,
|
||||
symmetric, ne,
|
||||
mapsO->B, mapsC->B,
|
||||
mapsO->G, mapsC->G,
|
||||
pa_data, diag);
|
||||
case 0x56:
|
||||
return internal::SmemPACurlCurlAssembleDiagonal3D<5,6>(
|
||||
dofs1D,
|
||||
quad1D,
|
||||
symmetric, ne,
|
||||
mapsO->B, mapsC->B,
|
||||
mapsO->G, mapsC->G,
|
||||
pa_data, diag);
|
||||
default:
|
||||
return internal::SmemPACurlCurlAssembleDiagonal3D(
|
||||
dofs1D, quad1D,
|
||||
symmetric, ne,
|
||||
mapsO->B, mapsC->B,
|
||||
mapsO->G, mapsC->G,
|
||||
pa_data, diag);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
internal::PACurlCurlAssembleDiagonal3D(dofs1D, quad1D, symmetric, ne,
|
||||
mapsO->B, mapsC->B,
|
||||
mapsO->G, mapsC->G,
|
||||
pa_data, diag);
|
||||
}
|
||||
}
|
||||
else if (dim == 2)
|
||||
{
|
||||
internal::PACurlCurlAssembleDiagonal2D(dofs1D, quad1D, ne,
|
||||
mapsO->B, mapsC->G, pa_data, diag);
|
||||
}
|
||||
else
|
||||
{
|
||||
MFEM_ABORT("Unsupported dimension!");
|
||||
}
|
||||
DiagonalPAKernels::Run(dim, dofs1D, quad1D, dofs1D, quad1D, symmetric, ne,
|
||||
mapsO->B, mapsC->B, mapsO->G, mapsC->G, pa_data,
|
||||
diag);
|
||||
}
|
||||
|
||||
void CurlCurlIntegrator::AddMultPA(const Vector &x, Vector &y) const
|
||||
{
|
||||
if (dim == 3)
|
||||
{
|
||||
if (Device::Allows(Backend::DEVICE_MASK))
|
||||
{
|
||||
const int ID = (dofs1D << 4) | quad1D;
|
||||
switch (ID)
|
||||
{
|
||||
case 0x23:
|
||||
return internal::SmemPACurlCurlApply3D<2,3>(
|
||||
dofs1D, quad1D,
|
||||
symmetric, ne,
|
||||
mapsO->B, mapsC->B, mapsO->Bt, mapsC->Bt,
|
||||
mapsC->G, mapsC->Gt, pa_data, x, y);
|
||||
case 0x34:
|
||||
return internal::SmemPACurlCurlApply3D<3,4>(
|
||||
dofs1D, quad1D,
|
||||
symmetric, ne,
|
||||
mapsO->B, mapsC->B, mapsO->Bt, mapsC->Bt,
|
||||
mapsC->G, mapsC->Gt, pa_data, x, y);
|
||||
case 0x45:
|
||||
return internal::SmemPACurlCurlApply3D<4,5>(
|
||||
dofs1D, quad1D,
|
||||
symmetric, ne,
|
||||
mapsO->B, mapsC->B, mapsO->Bt, mapsC->Bt,
|
||||
mapsC->G, mapsC->Gt, pa_data, x, y);
|
||||
case 0x56:
|
||||
return internal::SmemPACurlCurlApply3D<5,6>(
|
||||
dofs1D, quad1D,
|
||||
symmetric, ne,
|
||||
mapsO->B, mapsC->B, mapsO->Bt, mapsC->Bt,
|
||||
mapsC->G, mapsC->Gt, pa_data, x, y);
|
||||
default:
|
||||
return internal::SmemPACurlCurlApply3D(
|
||||
dofs1D, quad1D, symmetric, ne,
|
||||
mapsO->B, mapsC->B, mapsO->Bt, mapsC->Bt,
|
||||
mapsC->G, mapsC->Gt, pa_data, x, y);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
internal::PACurlCurlApply3D(dofs1D, quad1D, symmetric, ne, mapsO->B, mapsC->B,
|
||||
mapsO->Bt, mapsC->Bt, mapsC->G, mapsC->Gt,
|
||||
pa_data, x, y);
|
||||
}
|
||||
}
|
||||
else if (dim == 2)
|
||||
{
|
||||
internal::PACurlCurlApply2D(dofs1D, quad1D, ne, mapsO->B, mapsO->Bt,
|
||||
mapsC->G, mapsC->Gt, pa_data, x, y);
|
||||
}
|
||||
else
|
||||
{
|
||||
MFEM_ABORT("Unsupported dimension!");
|
||||
}
|
||||
ApplyPAKernels::Run(dim, dofs1D, quad1D, dofs1D, quad1D, symmetric, ne,
|
||||
mapsO->B, mapsC->B, mapsO->Bt, mapsC->Bt, mapsC->G,
|
||||
mapsC->Gt, pa_data, x, y, false);
|
||||
}
|
||||
|
||||
void CurlCurlIntegrator::AddAbsMultPA(const Vector &x, Vector &y) const
|
||||
@@ -209,61 +176,9 @@ void CurlCurlIntegrator::AddAbsMultPA(const Vector &x, Vector &y) const
|
||||
auto absO = mapsO->Abs();
|
||||
auto absC = mapsC->Abs();
|
||||
|
||||
if (dim == 3)
|
||||
{
|
||||
if (Device::Allows(Backend::DEVICE_MASK))
|
||||
{
|
||||
const int ID = (dofs1D << 4) | quad1D;
|
||||
switch (ID)
|
||||
{
|
||||
case 0x23:
|
||||
return internal::SmemPACurlCurlApply3D<2,3>(
|
||||
dofs1D, quad1D,
|
||||
symmetric, ne,
|
||||
absO.B, absC.B, absO.Bt, absC.Bt,
|
||||
absC.G, absC.Gt, abs_pa_data, x, y, true);
|
||||
case 0x34:
|
||||
return internal::SmemPACurlCurlApply3D<3,4>(
|
||||
dofs1D, quad1D,
|
||||
symmetric, ne,
|
||||
absO.B, absC.B, absO.Bt, absC.Bt,
|
||||
absC.G, absC.Gt, abs_pa_data, x, y, true);
|
||||
case 0x45:
|
||||
return internal::SmemPACurlCurlApply3D<4,5>(
|
||||
dofs1D, quad1D,
|
||||
symmetric, ne,
|
||||
absO.B, absC.B, absO.Bt, absC.Bt,
|
||||
absC.G, absC.Gt, abs_pa_data, x, y, true);
|
||||
case 0x56:
|
||||
return internal::SmemPACurlCurlApply3D<5,6>(
|
||||
dofs1D, quad1D,
|
||||
symmetric, ne,
|
||||
absO.B, absC.B, absO.Bt, absC.Bt,
|
||||
absC.G, absC.Gt, abs_pa_data, x, y, true);
|
||||
default:
|
||||
return internal::SmemPACurlCurlApply3D<0,0>(
|
||||
dofs1D, quad1D, symmetric, ne,
|
||||
absO.B, absC.B, absO.Bt, absC.Bt,
|
||||
absC.G, absC.Gt, abs_pa_data, x, y, true);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
internal::PACurlCurlApply3D<0,0>(
|
||||
dofs1D, quad1D, symmetric, ne,
|
||||
absO.B, absC.B, absO.Bt, absC.Bt, absC.G, absC.Gt,
|
||||
abs_pa_data, x, y, true);
|
||||
}
|
||||
}
|
||||
else if (dim == 2)
|
||||
{
|
||||
internal::PACurlCurlApply2D(dofs1D, quad1D, ne, absO.B, absO.Bt,
|
||||
absC.G, absC.Gt, abs_pa_data, x, y, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
MFEM_ABORT("Unsupported dimension!");
|
||||
}
|
||||
ApplyPAKernels::Run(dim, dofs1D, quad1D, dofs1D, quad1D, symmetric, ne,
|
||||
absO.B, absC.B, absO.Bt, absC.Bt, absC.G, absC.Gt,
|
||||
abs_pa_data, x, y, true);
|
||||
}
|
||||
|
||||
} // namespace mfem
|
||||
|
||||
@@ -0,0 +1,500 @@
|
||||
// Copyright (c) 2010-2025, 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_BILININTEG_DGDIFFUSION_KERNELS_HPP
|
||||
#define MFEM_BILININTEG_DGDIFFUSION_KERNELS_HPP
|
||||
|
||||
#include "../../general/forall.hpp"
|
||||
#include "../../mesh/face_nbr_geom.hpp"
|
||||
#include "../fe/face_map_utils.hpp"
|
||||
#include "../gridfunc.hpp"
|
||||
#include "../qfunction.hpp"
|
||||
|
||||
/// \cond DO_NOT_DOCUMENT
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
namespace internal
|
||||
{
|
||||
|
||||
template <int T_D1D = 0, int T_Q1D = 0>
|
||||
static void PADGDiffusionApply2D(const int NF, const Array<real_t> &b,
|
||||
const Array<real_t> &bt,
|
||||
const Array<real_t> &g,
|
||||
const Array<real_t> >, const real_t sigma,
|
||||
const Vector &pa_data, const Vector &x_,
|
||||
const Vector &dxdn_, Vector &y_, Vector &dydn_,
|
||||
const int d1d = 0, const int q1d = 0)
|
||||
{
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : 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 pa =
|
||||
Reshape(pa_data.Read(), 6, Q1D, NF); // (q, 1/h, J00, J01, J10, J11)
|
||||
|
||||
auto x = Reshape(x_.Read(), D1D, 2, NF);
|
||||
auto y = Reshape(y_.ReadWrite(), D1D, 2, NF);
|
||||
auto dxdn = Reshape(dxdn_.Read(), D1D, 2, NF);
|
||||
auto dydn = Reshape(dydn_.ReadWrite(), D1D, 2, NF);
|
||||
|
||||
const int NBX = std::max(D1D, Q1D);
|
||||
|
||||
mfem::forall_2D(NF, NBX, 2, [=] MFEM_HOST_DEVICE(int f) -> void
|
||||
{
|
||||
constexpr int max_D1D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
|
||||
constexpr int max_Q1D = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
|
||||
|
||||
MFEM_SHARED real_t u0[max_D1D];
|
||||
MFEM_SHARED real_t u1[max_D1D];
|
||||
MFEM_SHARED real_t du0[max_D1D];
|
||||
MFEM_SHARED real_t du1[max_D1D];
|
||||
|
||||
MFEM_SHARED real_t Bu0[max_Q1D];
|
||||
MFEM_SHARED real_t Bu1[max_Q1D];
|
||||
MFEM_SHARED real_t Bdu0[max_Q1D];
|
||||
MFEM_SHARED real_t Bdu1[max_Q1D];
|
||||
|
||||
MFEM_SHARED real_t r[max_Q1D];
|
||||
|
||||
MFEM_SHARED real_t BG[2 * max_D1D * max_Q1D];
|
||||
DeviceMatrix B(BG, Q1D, D1D);
|
||||
DeviceMatrix G(BG + D1D * Q1D, Q1D, D1D);
|
||||
|
||||
if (MFEM_THREAD_ID(y) == 0)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(p, x, Q1D)
|
||||
{
|
||||
for (int d = 0; d < D1D; ++d)
|
||||
{
|
||||
B(p, d) = B_(p, d);
|
||||
G(p, d) = G_(p, d);
|
||||
}
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
|
||||
// copy edge values to u0, u1 and copy edge normals to du0, du1
|
||||
MFEM_FOREACH_THREAD(side, y, 2)
|
||||
{
|
||||
real_t *u = (side == 0) ? u0 : u1;
|
||||
real_t *du = (side == 0) ? du0 : du1;
|
||||
MFEM_FOREACH_THREAD(d, x, D1D)
|
||||
{
|
||||
u[d] = x(d, side, f);
|
||||
du[d] = dxdn(d, side, f);
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
|
||||
// eval @ quad points
|
||||
MFEM_FOREACH_THREAD(side, y, 2)
|
||||
{
|
||||
real_t *u = (side == 0) ? u0 : u1;
|
||||
real_t *du = (side == 0) ? du0 : du1;
|
||||
real_t *Bu = (side == 0) ? Bu0 : Bu1;
|
||||
real_t *Bdu = (side == 0) ? Bdu0 : Bdu1;
|
||||
|
||||
MFEM_FOREACH_THREAD(p, x, Q1D)
|
||||
{
|
||||
const real_t Je_side[] = {pa(2 + 2 * side, p, f),
|
||||
pa(2 + 2 * side + 1, p, f)
|
||||
};
|
||||
|
||||
Bu[p] = 0.0;
|
||||
Bdu[p] = 0.0;
|
||||
|
||||
for (int d = 0; d < D1D; ++d)
|
||||
{
|
||||
const real_t b = B(p, d);
|
||||
const real_t g = G(p, d);
|
||||
|
||||
Bu[p] += b * u[d];
|
||||
Bdu[p] += Je_side[0] * b * du[d] + Je_side[1] * g * u[d];
|
||||
}
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
|
||||
// term - < {Q du/dn}, [v] > + kappa * < {Q/h} [u], [v] >:
|
||||
if (MFEM_THREAD_ID(y) == 0)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(p, x, Q1D)
|
||||
{
|
||||
const real_t q = pa(0, p, f);
|
||||
const real_t hi = pa(1, p, f);
|
||||
const real_t jump = Bu0[p] - Bu1[p];
|
||||
const real_t avg = Bdu0[p] + Bdu1[p]; // = {Q du/dn} * w * det(J)
|
||||
r[p] = -avg + hi * q * jump;
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
|
||||
MFEM_FOREACH_THREAD(d, x, D1D)
|
||||
{
|
||||
real_t Br = 0.0;
|
||||
|
||||
for (int p = 0; p < Q1D; ++p)
|
||||
{
|
||||
Br += B(p, d) * r[p];
|
||||
}
|
||||
|
||||
u0[d] = Br; // overwrite u0, u1
|
||||
u1[d] = -Br;
|
||||
} // for d
|
||||
MFEM_SYNC_THREAD;
|
||||
|
||||
MFEM_FOREACH_THREAD(side, y, 2)
|
||||
{
|
||||
real_t *du = (side == 0) ? du0 : du1;
|
||||
MFEM_FOREACH_THREAD(d, x, D1D) { du[d] = 0.0; }
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
|
||||
// term sigma * < [u], {Q dv/dn} >
|
||||
MFEM_FOREACH_THREAD(side, y, 2)
|
||||
{
|
||||
real_t *const du = (side == 0) ? du0 : du1;
|
||||
real_t *const u = (side == 0) ? u0 : u1;
|
||||
|
||||
MFEM_FOREACH_THREAD(d, x, D1D)
|
||||
{
|
||||
for (int p = 0; p < Q1D; ++p)
|
||||
{
|
||||
const real_t Je[] = {pa(2 + 2 * side, p, f),
|
||||
pa(2 + 2 * side + 1, p, f)
|
||||
};
|
||||
const real_t jump = Bu0[p] - Bu1[p];
|
||||
const real_t r_p = Je[0] * jump; // normal
|
||||
const real_t w_p = Je[1] * jump; // tangential
|
||||
du[d] += sigma * B(p, d) * r_p;
|
||||
u[d] += sigma * G(p, d) * w_p;
|
||||
}
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
|
||||
MFEM_FOREACH_THREAD(side, y, 2)
|
||||
{
|
||||
real_t *u = (side == 0) ? u0 : u1;
|
||||
real_t *du = (side == 0) ? du0 : du1;
|
||||
MFEM_FOREACH_THREAD(d, x, D1D)
|
||||
{
|
||||
y(d, side, f) += u[d];
|
||||
dydn(d, side, f) += du[d];
|
||||
}
|
||||
}
|
||||
}); // mfem::forall
|
||||
}
|
||||
|
||||
template <int T_D1D = 0, int T_Q1D = 0>
|
||||
static void PADGDiffusionApply3D(const int NF, const Array<real_t> &b,
|
||||
const Array<real_t> &bt,
|
||||
const Array<real_t> &g,
|
||||
const Array<real_t> >, const real_t sigma,
|
||||
const Vector &pa_data, const Vector &x_,
|
||||
const Vector &dxdn_, Vector &y_, Vector &dydn_,
|
||||
const int d1d = 0, const int q1d = 0)
|
||||
{
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : 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);
|
||||
|
||||
// (J0[0], J0[1], J0[2], J1[0], J1[1], J1[2], q/h)
|
||||
auto pa = Reshape(pa_data.Read(), 7, Q1D, Q1D, NF);
|
||||
|
||||
auto x = Reshape(x_.Read(), D1D, D1D, 2, NF);
|
||||
auto y = Reshape(y_.ReadWrite(), D1D, D1D, 2, NF);
|
||||
auto dxdn = Reshape(dxdn_.Read(), D1D, D1D, 2, NF);
|
||||
auto dydn = Reshape(dydn_.ReadWrite(), D1D, D1D, 2, NF);
|
||||
|
||||
const int NBX = std::max(D1D, Q1D);
|
||||
|
||||
mfem::forall_3D(NF, NBX, NBX, 2, [=] MFEM_HOST_DEVICE(int f) -> void
|
||||
{
|
||||
constexpr int max_D1D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
|
||||
constexpr int max_Q1D = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
|
||||
|
||||
MFEM_SHARED real_t u0[max_Q1D][max_Q1D];
|
||||
MFEM_SHARED real_t u1[max_Q1D][max_Q1D];
|
||||
|
||||
MFEM_SHARED real_t du0[max_Q1D][max_Q1D];
|
||||
MFEM_SHARED real_t du1[max_Q1D][max_Q1D];
|
||||
|
||||
MFEM_SHARED real_t Gu0[max_Q1D][max_Q1D];
|
||||
MFEM_SHARED real_t Gu1[max_Q1D][max_Q1D];
|
||||
|
||||
MFEM_SHARED real_t Bu0[max_Q1D][max_Q1D];
|
||||
MFEM_SHARED real_t Bu1[max_Q1D][max_Q1D];
|
||||
|
||||
MFEM_SHARED real_t Bdu0[max_Q1D][max_Q1D];
|
||||
MFEM_SHARED real_t Bdu1[max_Q1D][max_Q1D];
|
||||
|
||||
MFEM_SHARED real_t kappa_Qh[max_Q1D][max_Q1D];
|
||||
|
||||
MFEM_SHARED real_t nJe[2][max_Q1D][max_Q1D][3];
|
||||
MFEM_SHARED real_t BG[2 * max_D1D * max_Q1D];
|
||||
|
||||
// some buffers are reused multiple times, but for clarity have new names:
|
||||
real_t(*Bj0)[max_Q1D] = Bu0;
|
||||
real_t(*Bj1)[max_Q1D] = Bu1;
|
||||
real_t(*Bjn0)[max_Q1D] = Bdu0;
|
||||
real_t(*Bjn1)[max_Q1D] = Bdu1;
|
||||
real_t(*Gj0)[max_Q1D] = Gu0;
|
||||
real_t(*Gj1)[max_Q1D] = Gu1;
|
||||
|
||||
DeviceMatrix B(BG, Q1D, D1D);
|
||||
DeviceMatrix G(BG + D1D * Q1D, Q1D, D1D);
|
||||
|
||||
// copy face values to u0, u1 and copy normals to du0, du1
|
||||
MFEM_FOREACH_THREAD(side, z, 2)
|
||||
{
|
||||
real_t(*u)[max_Q1D] = (side == 0) ? u0 : u1;
|
||||
real_t(*du)[max_Q1D] = (side == 0) ? du0 : du1;
|
||||
|
||||
MFEM_FOREACH_THREAD(d2, x, D1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(d1, y, D1D)
|
||||
{
|
||||
u[d2][d1] = x(d1, d2, side,
|
||||
f); // copy transposed for better memory access
|
||||
du[d2][d1] = dxdn(d1, d2, side, f);
|
||||
}
|
||||
}
|
||||
|
||||
MFEM_FOREACH_THREAD(p1, x, Q1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(p2, y, Q1D)
|
||||
{
|
||||
for (int l = 0; l < 3; ++l)
|
||||
{
|
||||
nJe[side][p2][p1][l] = pa(3 * side + l, p1, p2, f);
|
||||
}
|
||||
|
||||
if (side == 0)
|
||||
{
|
||||
kappa_Qh[p2][p1] = pa(6, p1, p2, f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (side == 0)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(p, x, Q1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(d, y, D1D)
|
||||
{
|
||||
B(p, d) = B_(p, d);
|
||||
G(p, d) = G_(p, d);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
|
||||
// eval u and normal derivative @ quad points
|
||||
MFEM_FOREACH_THREAD(side, z, 2)
|
||||
{
|
||||
real_t(*u)[max_Q1D] = (side == 0) ? u0 : u1;
|
||||
real_t(*du)[max_Q1D] = (side == 0) ? du0 : du1;
|
||||
real_t(*Bu)[max_Q1D] = (side == 0) ? Bu0 : Bu1;
|
||||
real_t(*Bdu)[max_Q1D] = (side == 0) ? Bdu0 : Bdu1;
|
||||
real_t(*Gu)[max_Q1D] = (side == 0) ? Gu0 : Gu1;
|
||||
|
||||
MFEM_FOREACH_THREAD(p1, x, Q1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(d2, y, D1D)
|
||||
{
|
||||
real_t bu = 0.0;
|
||||
real_t bdu = 0.0;
|
||||
real_t gu = 0.0;
|
||||
|
||||
for (int d1 = 0; d1 < D1D; ++d1)
|
||||
{
|
||||
const real_t b = B(p1, d1);
|
||||
const real_t g = G(p1, d1);
|
||||
|
||||
bu += b * u[d2][d1];
|
||||
bdu += b * du[d2][d1];
|
||||
gu += g * u[d2][d1];
|
||||
}
|
||||
|
||||
Bu[p1][d2] = bu;
|
||||
Bdu[p1][d2] = bdu;
|
||||
Gu[p1][d2] = gu;
|
||||
}
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
|
||||
MFEM_FOREACH_THREAD(side, z, 2)
|
||||
{
|
||||
real_t(*u)[max_Q1D] = (side == 0) ? u0 : u1;
|
||||
real_t(*du)[max_Q1D] = (side == 0) ? du0 : du1;
|
||||
real_t(*Bu)[max_Q1D] = (side == 0) ? Bu0 : Bu1;
|
||||
real_t(*Gu)[max_Q1D] = (side == 0) ? Gu0 : Gu1;
|
||||
real_t(*Bdu)[max_Q1D] = (side == 0) ? Bdu0 : Bdu1;
|
||||
|
||||
MFEM_FOREACH_THREAD(p2, x, Q1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(p1, y, Q1D)
|
||||
{
|
||||
const real_t *Je = nJe[side][p2][p1];
|
||||
|
||||
real_t bbu = 0.0;
|
||||
real_t bgu = 0.0;
|
||||
real_t gbu = 0.0;
|
||||
real_t bbdu = 0.0;
|
||||
|
||||
for (int d2 = 0; d2 < D1D; ++d2)
|
||||
{
|
||||
const real_t b = B(p2, d2);
|
||||
const real_t g = G(p2, d2);
|
||||
bbu += b * Bu[p1][d2];
|
||||
gbu += g * Bu[p1][d2];
|
||||
bgu += b * Gu[p1][d2];
|
||||
bbdu += b * Bdu[p1][d2];
|
||||
}
|
||||
|
||||
u[p2][p1] = bbu;
|
||||
// du <- Q du/dn * w * det(J)
|
||||
du[p2][p1] = Je[0] * bbdu + Je[1] * bgu + Je[2] * gbu;
|
||||
}
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
|
||||
MFEM_FOREACH_THREAD(side, z, 2)
|
||||
{
|
||||
real_t(*Bj)[max_Q1D] = (side == 0) ? Bj0 : Bj1;
|
||||
real_t(*Bjn)[max_Q1D] = (side == 0) ? Bjn0 : Bjn1;
|
||||
real_t(*Gj)[max_Q1D] = (side == 0) ? Gj0 : Gj1;
|
||||
|
||||
MFEM_FOREACH_THREAD(d1, x, D1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(p2, y, Q1D)
|
||||
{
|
||||
real_t bj = 0.0;
|
||||
real_t bjn = 0.0;
|
||||
real_t gj = 0.0;
|
||||
real_t br = 0.0;
|
||||
|
||||
for (int p1 = 0; p1 < Q1D; ++p1)
|
||||
{
|
||||
const real_t b = B(p1, d1);
|
||||
const real_t g = G(p1, d1);
|
||||
|
||||
const real_t *Je = nJe[side][p2][p1];
|
||||
|
||||
const real_t jump = u0[p2][p1] - u1[p2][p1];
|
||||
const real_t avg = du0[p2][p1] + du1[p2][p1];
|
||||
|
||||
// r = - < {Q du/dn}, [v] > + kappa * < {Q/h} [u], [v] >
|
||||
const real_t r = -avg + kappa_Qh[p2][p1] * jump;
|
||||
|
||||
// bj, gj, bjn contribute to sigma term
|
||||
bj += b * Je[0] * jump;
|
||||
gj += g * Je[1] * jump;
|
||||
bjn += b * Je[2] * jump;
|
||||
|
||||
br += b * r;
|
||||
}
|
||||
|
||||
Bj[d1][p2] = sigma * bj;
|
||||
Bjn[d1][p2] = sigma * bjn;
|
||||
|
||||
// group br and gj together since we will multiply them both by B
|
||||
// and then sum
|
||||
const real_t sgn = (side == 0) ? 1.0 : -1.0;
|
||||
Gj[d1][p2] = sgn * br + sigma * gj;
|
||||
}
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
|
||||
MFEM_FOREACH_THREAD(side, z, 2)
|
||||
{
|
||||
real_t(*u)[max_Q1D] = (side == 0) ? u0 : u1;
|
||||
real_t(*du)[max_Q1D] = (side == 0) ? du0 : du1;
|
||||
real_t(*Bj)[max_Q1D] = (side == 0) ? Bj0 : Bj1;
|
||||
real_t(*Bjn)[max_Q1D] = (side == 0) ? Bjn0 : Bjn1;
|
||||
real_t(*Gj)[max_Q1D] = (side == 0) ? Gj0 : Gj1;
|
||||
|
||||
MFEM_FOREACH_THREAD(d2, x, D1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(d1, y, D1D)
|
||||
{
|
||||
real_t bbj = 0.0;
|
||||
real_t gbj = 0.0;
|
||||
real_t bgj = 0.0;
|
||||
|
||||
for (int p2 = 0; p2 < Q1D; ++p2)
|
||||
{
|
||||
const real_t b = B(p2, d2);
|
||||
const real_t g = G(p2, d2);
|
||||
|
||||
bbj += b * Bj[d1][p2];
|
||||
bgj += b * Gj[d1][p2];
|
||||
gbj += g * Bjn[d1][p2];
|
||||
}
|
||||
|
||||
du[d2][d1] = bbj;
|
||||
u[d2][d1] = bgj + gbj;
|
||||
}
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
|
||||
// map back to y and dydn
|
||||
MFEM_FOREACH_THREAD(side, z, 2)
|
||||
{
|
||||
const real_t(*u)[max_Q1D] = (side == 0) ? u0 : u1;
|
||||
const real_t(*du)[max_Q1D] = (side == 0) ? du0 : du1;
|
||||
|
||||
MFEM_FOREACH_THREAD(d2, x, D1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(d1, y, D1D)
|
||||
{
|
||||
y(d1, d2, side, f) += u[d2][d1];
|
||||
dydn(d1, d2, side, f) += du[d2][d1];
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
template <int DIM, int D1D, int Q1D>
|
||||
DGDiffusionIntegrator::ApplyKernelType
|
||||
DGDiffusionIntegrator::ApplyPAKernels::Kernel()
|
||||
{
|
||||
if constexpr (DIM == 2)
|
||||
{
|
||||
return internal::PADGDiffusionApply2D<D1D, Q1D>;
|
||||
}
|
||||
else if constexpr (DIM == 3)
|
||||
{
|
||||
return internal::PADGDiffusionApply3D<D1D, Q1D>;
|
||||
}
|
||||
MFEM_ABORT("");
|
||||
}
|
||||
} // namespace mfem
|
||||
/// \endcond DO_NOT_DOCUMENT
|
||||
#endif
|
||||
@@ -11,42 +11,39 @@
|
||||
|
||||
#include "../../general/forall.hpp"
|
||||
#include "../../mesh/face_nbr_geom.hpp"
|
||||
#include "../fe/face_map_utils.hpp"
|
||||
#include "../gridfunc.hpp"
|
||||
#include "../qfunction.hpp"
|
||||
#include "../fe/face_map_utils.hpp"
|
||||
|
||||
using namespace std;
|
||||
#include "bilininteg_dgdiffusion_kernels.hpp"
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
static void PADGDiffusionSetup2D(const int Q1D,
|
||||
const int NE,
|
||||
const int NF,
|
||||
static void PADGDiffusionSetup2D(const int Q1D, const int NE, const int NF,
|
||||
const Array<real_t> &w,
|
||||
const GeometricFactors &el_geom,
|
||||
const FaceGeometricFactors &face_geom,
|
||||
const FaceNeighborGeometricFactors *nbr_geom,
|
||||
const Vector &q,
|
||||
const real_t sigma,
|
||||
const real_t kappa,
|
||||
Vector &pa_data,
|
||||
const Vector &q, const real_t sigma,
|
||||
const real_t kappa, Vector &pa_data,
|
||||
const Array<int> &face_info_)
|
||||
{
|
||||
const auto J_loc = Reshape(el_geom.J.Read(), Q1D, Q1D, 2, 2, NE);
|
||||
const auto detJe_loc = Reshape(el_geom.detJ.Read(), Q1D, Q1D, NE);
|
||||
|
||||
const int n_nbr = nbr_geom ? nbr_geom->num_neighbor_elems : 0;
|
||||
const auto J_shared = Reshape(nbr_geom ? nbr_geom->J.Read() : nullptr,
|
||||
Q1D, Q1D, 2, 2, n_nbr);
|
||||
const auto detJ_shared = Reshape(nbr_geom ? nbr_geom->detJ.Read() : nullptr,
|
||||
Q1D, Q1D, n_nbr);
|
||||
const auto J_shared =
|
||||
Reshape(nbr_geom ? nbr_geom->J.Read() : nullptr, Q1D, Q1D, 2, 2, n_nbr);
|
||||
const auto detJ_shared =
|
||||
Reshape(nbr_geom ? nbr_geom->detJ.Read() : nullptr, Q1D, Q1D, n_nbr);
|
||||
|
||||
const auto detJf = Reshape(face_geom.detJ.Read(), Q1D, NF);
|
||||
const auto n = Reshape(face_geom.normal.Read(), Q1D, 2, NF);
|
||||
|
||||
const bool const_q = (q.Size() == 1);
|
||||
const auto Q = const_q ? Reshape(q.Read(), 1,1) : Reshape(q.Read(), Q1D,NF);
|
||||
const auto Q =
|
||||
const_q ? Reshape(q.Read(), 1, 1) : Reshape(q.Read(), Q1D, NF);
|
||||
|
||||
const auto W = w.Read();
|
||||
|
||||
@@ -56,7 +53,7 @@ static void PADGDiffusionSetup2D(const int Q1D,
|
||||
// (q, 1/h, J0_0, J0_1, J1_0, J1_1)
|
||||
auto pa = Reshape(pa_data.Write(), 6, Q1D, NF);
|
||||
|
||||
mfem::forall(NF, [=] MFEM_HOST_DEVICE (int f) -> void
|
||||
mfem::forall(NF, [=] MFEM_HOST_DEVICE(int f) -> void
|
||||
{
|
||||
const int normal_dir[] = {face_info(0, f), face_info(1, f)};
|
||||
const int fid[] = {face_info(4, f), face_info(5, f)};
|
||||
@@ -74,7 +71,7 @@ static void PADGDiffusionSetup2D(const int Q1D,
|
||||
|
||||
for (int p = 0; p < Q1D; ++p)
|
||||
{
|
||||
const real_t Qp = const_q ? Q(0,0) : Q(p, f);
|
||||
const real_t Qp = const_q ? Q(0, 0) : Q(p, f);
|
||||
pa(0, p, f) = kappa * Qp * W[p] * detJf(p, f);
|
||||
|
||||
real_t hi = 0.0;
|
||||
@@ -85,17 +82,19 @@ static void PADGDiffusionSetup2D(const int Q1D,
|
||||
|
||||
// Always opposite direction in "native" ordering
|
||||
// Need to multiply the native=>lex0 with native=>lex1 and negate
|
||||
const int sgn = (side == 1) ? -1*sgn0*sgn1 : 1;
|
||||
const int sgn = (side == 1) ? -1 * sgn0 * sgn1 : 1;
|
||||
|
||||
const int e = el[side];
|
||||
const auto &J = (side == 1 && shared) ? J_shared : J_loc;
|
||||
const auto &detJ = (side == 1 && shared) ? detJ_shared : detJe_loc;
|
||||
|
||||
real_t nJi[2];
|
||||
nJi[0] = n(p,0,f)*J(i,j, 1,1, e) - n(p,1,f)*J(i,j,0,1,e);
|
||||
nJi[1] = -n(p,0,f)*J(i,j,1,0, e) + n(p,1,f)*J(i,j,0,0,e);
|
||||
nJi[0] =
|
||||
n(p, 0, f) * J(i, j, 1, 1, e) - n(p, 1, f) * J(i, j, 0, 1, e);
|
||||
nJi[1] =
|
||||
-n(p, 0, f) * J(i, j, 1, 0, e) + n(p, 1, f) * J(i, j, 0, 0, e);
|
||||
|
||||
const real_t dJe = detJ(i,j,e);
|
||||
const real_t dJe = detJ(i, j, e);
|
||||
const real_t dJf = detJf(p, f);
|
||||
|
||||
const real_t w = factor * Qp * W[p] * dJf / dJe;
|
||||
@@ -104,9 +103,9 @@ static void PADGDiffusionSetup2D(const int Q1D,
|
||||
const int ti = 1 - ni;
|
||||
|
||||
// Normal
|
||||
pa(2 + 2*side + 0, p, f) = w * nJi[ni];
|
||||
pa(2 + 2 * side + 0, p, f) = w * nJi[ni];
|
||||
// Tangential
|
||||
pa(2 + 2*side + 1, p, f) = sgn * w * nJi[ti];
|
||||
pa(2 + 2 * side + 1, p, f) = sgn * w * nJi[ti];
|
||||
|
||||
hi += factor * dJf / dJe;
|
||||
}
|
||||
@@ -122,47 +121,43 @@ static void PADGDiffusionSetup2D(const int Q1D,
|
||||
});
|
||||
}
|
||||
|
||||
static void PADGDiffusionSetup3D(const int Q1D,
|
||||
const int NE,
|
||||
const int NF,
|
||||
static void PADGDiffusionSetup3D(const int Q1D, const int NE, const int NF,
|
||||
const Array<real_t> &w,
|
||||
const GeometricFactors &el_geom,
|
||||
const FaceGeometricFactors &face_geom,
|
||||
const FaceNeighborGeometricFactors *nbr_geom,
|
||||
const Vector &q,
|
||||
const real_t sigma,
|
||||
const real_t kappa,
|
||||
Vector &pa_data,
|
||||
const Vector &q, const real_t sigma,
|
||||
const real_t kappa, Vector &pa_data,
|
||||
const Array<int> &face_info_)
|
||||
{
|
||||
const auto J_loc = Reshape(el_geom.J.Read(), Q1D, Q1D, Q1D, 3, 3, NE);
|
||||
const auto detJe_loc = Reshape(el_geom.detJ.Read(), Q1D, Q1D, Q1D, NE);
|
||||
|
||||
const int n_nbr = nbr_geom ? nbr_geom->num_neighbor_elems : 0;
|
||||
const auto J_shared = Reshape(nbr_geom ? nbr_geom->J.Read() : nullptr,
|
||||
Q1D, Q1D, Q1D, 3, 3, n_nbr);
|
||||
const auto detJ_shared = Reshape(nbr_geom ? nbr_geom->detJ.Read() : nullptr,
|
||||
Q1D, Q1D, Q1D, n_nbr);
|
||||
const auto J_shared = Reshape(nbr_geom ? nbr_geom->J.Read() : nullptr, Q1D,
|
||||
Q1D, Q1D, 3, 3, n_nbr);
|
||||
const auto detJ_shared =
|
||||
Reshape(nbr_geom ? nbr_geom->detJ.Read() : nullptr, Q1D, Q1D, Q1D, n_nbr);
|
||||
|
||||
const auto detJf = Reshape(face_geom.detJ.Read(), Q1D, Q1D, NF);
|
||||
const auto n = Reshape(face_geom.normal.Read(), Q1D, Q1D, 3, NF);
|
||||
|
||||
const bool const_q = (q.Size() == 1);
|
||||
const auto Q = const_q ? Reshape(q.Read(), 1, 1, 1)
|
||||
: Reshape(q.Read(), Q1D, Q1D, NF);
|
||||
const auto Q =
|
||||
const_q ? Reshape(q.Read(), 1, 1, 1) : Reshape(q.Read(), Q1D, Q1D, NF);
|
||||
|
||||
const auto W = Reshape(w.Read(), Q1D, Q1D);
|
||||
|
||||
// (perm[0], perm[1], perm[2], element_index, local_face_id, orientation)
|
||||
const auto face_info = Reshape(face_info_.Read(), 6, 2, NF);
|
||||
constexpr int _el_ = 3; // offset in face_info for element index
|
||||
constexpr int _el_ = 3; // offset in face_info for element index
|
||||
constexpr int _fid_ = 4; // offset in face_info for local face id
|
||||
constexpr int _or_ = 5; // offset in face_info for orientation
|
||||
constexpr int _or_ = 5; // offset in face_info for orientation
|
||||
|
||||
// (J00, J01, J02, J10, J11, J12, q/h)
|
||||
const auto pa = Reshape(pa_data.Write(), 7, Q1D, Q1D, NF);
|
||||
|
||||
mfem::forall_2D(NF, Q1D, Q1D, [=] MFEM_HOST_DEVICE (int f) -> void
|
||||
mfem::forall_2D(NF, Q1D, Q1D, [=] MFEM_HOST_DEVICE(int f) -> void
|
||||
{
|
||||
MFEM_SHARED int perm[2][3];
|
||||
MFEM_SHARED int el[2];
|
||||
@@ -172,10 +167,7 @@ static void PADGDiffusionSetup3D(const int Q1D,
|
||||
|
||||
MFEM_FOREACH_THREAD(side, x, 2)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(i, y, 3)
|
||||
{
|
||||
perm[side][i] = face_info(i, side, f);
|
||||
}
|
||||
MFEM_FOREACH_THREAD(i, y, 3) { perm[side][i] = face_info(i, side, f); }
|
||||
|
||||
if (MFEM_THREAD_ID(y) == 0)
|
||||
{
|
||||
@@ -200,16 +192,16 @@ static void PADGDiffusionSetup3D(const int Q1D,
|
||||
{
|
||||
MFEM_FOREACH_THREAD(p2, y, Q1D)
|
||||
{
|
||||
const real_t Qp = const_q ? Q(0,0,0) : Q(p1, p2, f);
|
||||
const real_t dJf = detJf(p1,p2,f);
|
||||
const real_t Qp = const_q ? Q(0, 0, 0) : Q(p1, p2, f);
|
||||
const real_t dJf = detJf(p1, p2, f);
|
||||
|
||||
real_t hi = 0.0;
|
||||
|
||||
for (int side = 0; side < nsides; ++side)
|
||||
{
|
||||
int i, j, k;
|
||||
internal::FaceIdxToVolIdx3D(
|
||||
p1 + Q1D*p2, Q1D, fid[0], fid[1], side, ortn[1], i, j, k);
|
||||
internal::FaceIdxToVolIdx3D(p1 + Q1D * p2, Q1D, fid[0], fid[1],
|
||||
side, ortn[1], i, j, k);
|
||||
|
||||
const int e = el[side];
|
||||
const auto &J = shared[side] ? J_shared : J_loc;
|
||||
@@ -217,27 +209,45 @@ static void PADGDiffusionSetup3D(const int Q1D,
|
||||
|
||||
// *INDENT-OFF*
|
||||
real_t nJi[3];
|
||||
nJi[0] = ( -J(i,j,k, 1,2, e)*J(i,j,k, 2,1, e) + J(i,j,k, 1,1, e)*J(i,j,k, 2,2, e)) * n(p1,p2, 0, f)
|
||||
+ ( J(i,j,k, 0,2, e)*J(i,j,k, 2,1, e) - J(i,j,k, 0,1, e)*J(i,j,k, 2,2, e)) * n(p1,p2, 1, f)
|
||||
+ (-J(i,j,k, 0,2, e)*J(i,j,k, 1,1, e) + J(i,j,k, 0,1, e)*J(i,j,k, 1,2, e)) * n(p1,p2, 2, f);
|
||||
nJi[0] = (-J(i, j, k, 1, 2, e) * J(i, j, k, 2, 1, e) +
|
||||
J(i, j, k, 1, 1, e) * J(i, j, k, 2, 2, e)) *
|
||||
n(p1, p2, 0, f) +
|
||||
(J(i, j, k, 0, 2, e) * J(i, j, k, 2, 1, e) -
|
||||
J(i, j, k, 0, 1, e) * J(i, j, k, 2, 2, e)) *
|
||||
n(p1, p2, 1, f) +
|
||||
(-J(i, j, k, 0, 2, e) * J(i, j, k, 1, 1, e) +
|
||||
J(i, j, k, 0, 1, e) * J(i, j, k, 1, 2, e)) *
|
||||
n(p1, p2, 2, f);
|
||||
|
||||
nJi[1] = ( J(i,j,k, 1,2, e)*J(i,j,k, 2,0, e) - J(i,j,k, 1,0, e)*J(i,j,k, 2,2, e)) * n(p1,p2, 0, f)
|
||||
+ (-J(i,j,k, 0,2, e)*J(i,j,k, 2,0, e) + J(i,j,k, 0,0, e)*J(i,j,k, 2,2, e)) * n(p1,p2, 1, f)
|
||||
+ ( J(i,j,k, 0,2, e)*J(i,j,k, 1,0, e) - J(i,j,k, 0,0, e)*J(i,j,k, 1,2, e)) * n(p1,p2, 2, f);
|
||||
nJi[1] = (J(i, j, k, 1, 2, e) * J(i, j, k, 2, 0, e) -
|
||||
J(i, j, k, 1, 0, e) * J(i, j, k, 2, 2, e)) *
|
||||
n(p1, p2, 0, f) +
|
||||
(-J(i, j, k, 0, 2, e) * J(i, j, k, 2, 0, e) +
|
||||
J(i, j, k, 0, 0, e) * J(i, j, k, 2, 2, e)) *
|
||||
n(p1, p2, 1, f) +
|
||||
(J(i, j, k, 0, 2, e) * J(i, j, k, 1, 0, e) -
|
||||
J(i, j, k, 0, 0, e) * J(i, j, k, 1, 2, e)) *
|
||||
n(p1, p2, 2, f);
|
||||
|
||||
nJi[2] = ( -J(i,j,k, 1,1, e)*J(i,j,k, 2,0, e) + J(i,j,k, 1,0, e)*J(i,j,k, 2,1, e)) * n(p1,p2, 0, f)
|
||||
+ ( J(i,j,k, 0,1, e)*J(i,j,k, 2,0, e) - J(i,j,k, 0,0, e)*J(i,j,k, 2,1, e)) * n(p1,p2, 1, f)
|
||||
+ (-J(i,j,k, 0,1, e)*J(i,j,k, 1,0, e) + J(i,j,k, 0,0, e)*J(i,j,k, 1,1, e)) * n(p1,p2, 2, f);
|
||||
nJi[2] = (-J(i, j, k, 1, 1, e) * J(i, j, k, 2, 0, e) +
|
||||
J(i, j, k, 1, 0, e) * J(i, j, k, 2, 1, e)) *
|
||||
n(p1, p2, 0, f) +
|
||||
(J(i, j, k, 0, 1, e) * J(i, j, k, 2, 0, e) -
|
||||
J(i, j, k, 0, 0, e) * J(i, j, k, 2, 1, e)) *
|
||||
n(p1, p2, 1, f) +
|
||||
(-J(i, j, k, 0, 1, e) * J(i, j, k, 1, 0, e) +
|
||||
J(i, j, k, 0, 0, e) * J(i, j, k, 1, 1, e)) *
|
||||
n(p1, p2, 2, f);
|
||||
// *INDENT-ON*
|
||||
|
||||
const real_t dJe = detJe(i,j,k,e);
|
||||
const real_t dJe = detJe(i, j, k, e);
|
||||
const real_t val = factor * Qp * W(p1, p2) * dJf / dJe;
|
||||
|
||||
for (int d = 0; d < 3; ++d)
|
||||
{
|
||||
const int idx = std::abs(perm[side][d]) - 1;
|
||||
const int sgn = (perm[side][d] < 0) ? -1 : 1;
|
||||
pa(3*side + d, p1, p2, f) = sgn * val * nJi[idx];
|
||||
pa(3 * side + d, p1, p2, f) = sgn * val * nJi[idx];
|
||||
}
|
||||
|
||||
hi += factor * dJf / dJe;
|
||||
@@ -257,7 +267,8 @@ static void PADGDiffusionSetup3D(const int Q1D,
|
||||
}
|
||||
|
||||
static void PADGDiffusionSetupFaceInfo2D(const int nf, const Mesh &mesh,
|
||||
const FaceType type, Array<int> &face_info_)
|
||||
const FaceType type,
|
||||
Array<int> &face_info_)
|
||||
{
|
||||
const int ne = mesh.GetNE();
|
||||
|
||||
@@ -326,8 +337,7 @@ inline void FaceNormalPermutation(int perm[3], const int face_id)
|
||||
|
||||
// Assigns to perm the permutation as in FaceNormalPermutation for the second
|
||||
// element on the face but signed to indicate the sign of the normal derivative.
|
||||
inline void SignedFaceNormalPermutation(int perm[3],
|
||||
const int face_id1,
|
||||
inline void SignedFaceNormalPermutation(int perm[3], const int face_id1,
|
||||
const int face_id2,
|
||||
const int orientation)
|
||||
{
|
||||
@@ -386,17 +396,19 @@ inline void SignedFaceNormalPermutation(int perm[3],
|
||||
}
|
||||
|
||||
static void PADGDiffusionSetupFaceInfo3D(const int nf, const Mesh &mesh,
|
||||
const FaceType type, Array<int> &face_info_)
|
||||
const FaceType type,
|
||||
Array<int> &face_info_)
|
||||
{
|
||||
const int ne = mesh.GetNE();
|
||||
|
||||
int fidx = 0;
|
||||
// face_info array has 12 entries per face, 6 for each of the adjacent elements:
|
||||
// (perm[0], perm[1], perm[2], element_index, local_face_id, orientation)
|
||||
// face_info array has 12 entries per face, 6 for each of the adjacent
|
||||
// elements: (perm[0], perm[1], perm[2], element_index, local_face_id,
|
||||
// orientation)
|
||||
face_info_.SetSize(nf * 12);
|
||||
constexpr int _e_ = 3; // offset for element index
|
||||
constexpr int _e_ = 3; // offset for element index
|
||||
constexpr int _fid_ = 4; // offset for local face id
|
||||
constexpr int _or_ = 5; // offset for orientation
|
||||
constexpr int _or_ = 5; // offset for orientation
|
||||
|
||||
auto face_info = Reshape(face_info_.HostWrite(), 6, 2, nf);
|
||||
for (int f = 0; f < mesh.GetNumFaces(); ++f)
|
||||
@@ -408,9 +420,9 @@ static void PADGDiffusionSetupFaceInfo3D(const int nf, const Mesh &mesh,
|
||||
const int fid0 = f_info.element[0].local_face_id;
|
||||
const int or0 = f_info.element[0].orientation;
|
||||
|
||||
face_info( _e_, 0, fidx) = f_info.element[0].index;
|
||||
face_info(_e_, 0, fidx) = f_info.element[0].index;
|
||||
face_info(_fid_, 0, fidx) = fid0;
|
||||
face_info( _or_, 0, fidx) = or0;
|
||||
face_info(_or_, 0, fidx) = or0;
|
||||
|
||||
FaceNormalPermutation(&face_info(0, 0, fidx), fid0);
|
||||
|
||||
@@ -421,16 +433,17 @@ static void PADGDiffusionSetupFaceInfo3D(const int nf, const Mesh &mesh,
|
||||
|
||||
if (f_info.IsShared())
|
||||
{
|
||||
face_info( _e_, 1, fidx) = ne + f_info.element[1].index;
|
||||
face_info(_e_, 1, fidx) = ne + f_info.element[1].index;
|
||||
}
|
||||
else
|
||||
{
|
||||
face_info( _e_, 1, fidx) = f_info.element[1].index;
|
||||
face_info(_e_, 1, fidx) = f_info.element[1].index;
|
||||
}
|
||||
face_info(_fid_, 1, fidx) = fid1;
|
||||
face_info( _or_, 1, fidx) = or1;
|
||||
face_info(_or_, 1, fidx) = or1;
|
||||
|
||||
SignedFaceNormalPermutation(&face_info(0, 1, fidx), fid0, fid1, or1);
|
||||
SignedFaceNormalPermutation(&face_info(0, 1, fidx), fid0, fid1,
|
||||
or1);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -448,8 +461,8 @@ static void PADGDiffusionSetupFaceInfo3D(const int nf, const Mesh &mesh,
|
||||
void DGDiffusionIntegrator::SetupPA(const FiniteElementSpace &fes,
|
||||
FaceType type)
|
||||
{
|
||||
const MemoryType mt = (pa_mt == MemoryType::DEFAULT) ?
|
||||
Device::GetDeviceMemoryType() : pa_mt;
|
||||
const MemoryType mt =
|
||||
(pa_mt == MemoryType::DEFAULT) ? Device::GetDeviceMemoryType() : pa_mt;
|
||||
|
||||
const int ne = fes.GetNE();
|
||||
nf = fes.GetNFbyType(type);
|
||||
@@ -458,16 +471,17 @@ void DGDiffusionIntegrator::SetupPA(const FiniteElementSpace &fes,
|
||||
Mesh &mesh = *fes.GetMesh();
|
||||
const Geometry::Type face_geom_type = mesh.GetTypicalFaceGeometry();
|
||||
const FiniteElement &el = *fes.GetTypicalTraceElement();
|
||||
const int ir_order = IntRule ? IntRule->GetOrder()
|
||||
const int ir_order = IntRule
|
||||
? IntRule->GetOrder()
|
||||
: GetRule(el.GetOrder(), face_geom_type).GetOrder();
|
||||
const IntegrationRule &ir = irs.Get(face_geom_type, ir_order);
|
||||
dim = mesh.Dimension();
|
||||
const int q1d = (ir.GetOrder() + 3)/2;
|
||||
MFEM_ASSERT(q1d == pow(real_t(ir.Size()), 1.0/(dim - 1)), "");
|
||||
const int q1d = (ir.GetOrder() + 3) / 2;
|
||||
MFEM_ASSERT(q1d == pow(real_t(ir.Size()), 1.0 / (dim - 1)), "");
|
||||
|
||||
const auto vol_ir = irs.Get(mesh.GetTypicalElementGeometry(), ir_order);
|
||||
const auto geom_flags = GeometricFactors::JACOBIANS |
|
||||
GeometricFactors::DETERMINANTS;
|
||||
const auto geom_flags =
|
||||
GeometricFactors::JACOBIANS | GeometricFactors::DETERMINANTS;
|
||||
const auto el_geom = mesh.GetGeometricFactors(vol_ir, geom_flags, mt);
|
||||
|
||||
std::unique_ptr<FaceNeighborGeometricFactors> nbr_geom;
|
||||
@@ -476,8 +490,8 @@ void DGDiffusionIntegrator::SetupPA(const FiniteElementSpace &fes,
|
||||
nbr_geom.reset(new FaceNeighborGeometricFactors(*el_geom));
|
||||
}
|
||||
|
||||
const auto face_geom_flags = FaceGeometricFactors::DETERMINANTS |
|
||||
FaceGeometricFactors::NORMALS;
|
||||
const auto face_geom_flags =
|
||||
FaceGeometricFactors::DETERMINANTS | FaceGeometricFactors::NORMALS;
|
||||
auto face_geom = mesh.GetFaceGeometricFactors(ir, face_geom_flags, type, mt);
|
||||
maps = &el.GetDofToQuad(ir, DofToQuad::TENSOR);
|
||||
dofs1D = maps->ndof;
|
||||
@@ -489,9 +503,18 @@ void DGDiffusionIntegrator::SetupPA(const FiniteElementSpace &fes,
|
||||
// Evaluate the coefficient at the face quadrature points.
|
||||
FaceQuadratureSpace fqs(mesh, ir, type);
|
||||
CoefficientVector q(fqs, CoefficientStorage::COMPRESSED);
|
||||
if (Q) { q.Project(*Q); }
|
||||
else if (MQ) { MFEM_ABORT("Not yet implemented"); /* q.Project(*MQ); */ }
|
||||
else { q.SetConstant(1.0); }
|
||||
if (Q)
|
||||
{
|
||||
q.Project(*Q);
|
||||
}
|
||||
else if (MQ)
|
||||
{
|
||||
MFEM_ABORT("Not yet implemented"); /* q.Project(*MQ); */
|
||||
}
|
||||
else
|
||||
{
|
||||
q.SetConstant(1.0);
|
||||
}
|
||||
|
||||
Array<int> face_info;
|
||||
if (dim == 1)
|
||||
@@ -501,14 +524,16 @@ void DGDiffusionIntegrator::SetupPA(const FiniteElementSpace &fes,
|
||||
else if (dim == 2)
|
||||
{
|
||||
PADGDiffusionSetupFaceInfo2D(nf, mesh, type, face_info);
|
||||
PADGDiffusionSetup2D(quad1D, ne, nf, ir.GetWeights(), *el_geom, *face_geom,
|
||||
nbr_geom.get(), q, sigma, kappa, pa_data, face_info);
|
||||
PADGDiffusionSetup2D(quad1D, ne, nf, ir.GetWeights(), *el_geom,
|
||||
*face_geom, nbr_geom.get(), q, sigma, kappa, pa_data,
|
||||
face_info);
|
||||
}
|
||||
else if (dim == 3)
|
||||
{
|
||||
PADGDiffusionSetupFaceInfo3D(nf, mesh, type, face_info);
|
||||
PADGDiffusionSetup3D(quad1D, ne, nf, ir.GetWeights(), *el_geom, *face_geom,
|
||||
nbr_geom.get(), q, sigma, kappa, pa_data, face_info);
|
||||
PADGDiffusionSetup3D(quad1D, ne, nf, ir.GetWeights(), *el_geom,
|
||||
*face_geom, nbr_geom.get(), q, sigma, kappa, pa_data,
|
||||
face_info);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -524,529 +549,76 @@ void DGDiffusionIntegrator::AssemblePABoundaryFaces(
|
||||
SetupPA(fes, FaceType::Boundary);
|
||||
}
|
||||
|
||||
template<int T_D1D = 0, int T_Q1D = 0> static
|
||||
void PADGDiffusionApply2D(const int NF,
|
||||
const Array<real_t> &b,
|
||||
const Array<real_t> &bt,
|
||||
const Array<real_t>& g,
|
||||
const Array<real_t>& gt,
|
||||
const real_t sigma,
|
||||
const Vector &pa_data,
|
||||
const Vector &x_,
|
||||
const Vector &dxdn_,
|
||||
Vector &y_,
|
||||
Vector &dydn_,
|
||||
const int d1d = 0,
|
||||
const int q1d = 0)
|
||||
void DGDiffusionIntegrator::AddMultPAFaceNormalDerivatives(const Vector &x,
|
||||
const Vector &dxdn,
|
||||
Vector &y,
|
||||
Vector &dydn) const
|
||||
{
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : 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 pa = Reshape(pa_data.Read(), 6, Q1D, NF); // (q, 1/h, J00, J01, J10, J11)
|
||||
|
||||
auto x = Reshape(x_.Read(), D1D, 2, NF);
|
||||
auto y = Reshape(y_.ReadWrite(), D1D, 2, NF);
|
||||
auto dxdn = Reshape(dxdn_.Read(), D1D, 2, NF);
|
||||
auto dydn = Reshape(dydn_.ReadWrite(), D1D, 2, NF);
|
||||
|
||||
const int NBX = std::max(D1D, Q1D);
|
||||
|
||||
mfem::forall_2D(NF, NBX, 2, [=] MFEM_HOST_DEVICE (int f) -> void
|
||||
{
|
||||
constexpr int max_D1D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
|
||||
constexpr int max_Q1D = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
|
||||
|
||||
MFEM_SHARED real_t u0[max_D1D];
|
||||
MFEM_SHARED real_t u1[max_D1D];
|
||||
MFEM_SHARED real_t du0[max_D1D];
|
||||
MFEM_SHARED real_t du1[max_D1D];
|
||||
|
||||
MFEM_SHARED real_t Bu0[max_Q1D];
|
||||
MFEM_SHARED real_t Bu1[max_Q1D];
|
||||
MFEM_SHARED real_t Bdu0[max_Q1D];
|
||||
MFEM_SHARED real_t Bdu1[max_Q1D];
|
||||
|
||||
MFEM_SHARED real_t r[max_Q1D];
|
||||
|
||||
MFEM_SHARED real_t BG[2*max_D1D*max_Q1D];
|
||||
DeviceMatrix B(BG, Q1D, D1D);
|
||||
DeviceMatrix G(BG + D1D*Q1D, Q1D, D1D);
|
||||
|
||||
if (MFEM_THREAD_ID(y) == 0)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(p,x,Q1D)
|
||||
{
|
||||
for (int d = 0; d < D1D; ++d)
|
||||
{
|
||||
B(p,d) = B_(p,d);
|
||||
G(p,d) = G_(p,d);
|
||||
}
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
|
||||
// copy edge values to u0, u1 and copy edge normals to du0, du1
|
||||
MFEM_FOREACH_THREAD(side,y,2)
|
||||
{
|
||||
real_t *u = (side == 0) ? u0 : u1;
|
||||
real_t *du = (side == 0) ? du0 : du1;
|
||||
MFEM_FOREACH_THREAD(d,x,D1D)
|
||||
{
|
||||
u[d] = x(d, side, f);
|
||||
du[d] = dxdn(d, side, f);
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
|
||||
// eval @ quad points
|
||||
MFEM_FOREACH_THREAD(side,y,2)
|
||||
{
|
||||
real_t *u = (side == 0) ? u0 : u1;
|
||||
real_t *du = (side == 0) ? du0 : du1;
|
||||
real_t *Bu = (side == 0) ? Bu0 : Bu1;
|
||||
real_t *Bdu = (side == 0) ? Bdu0 : Bdu1;
|
||||
|
||||
MFEM_FOREACH_THREAD(p,x,Q1D)
|
||||
{
|
||||
const real_t Je_side[] = {pa(2 + 2*side, p, f), pa(2 + 2*side + 1, p, f)};
|
||||
|
||||
Bu[p] = 0.0;
|
||||
Bdu[p] = 0.0;
|
||||
|
||||
for (int d = 0; d < D1D; ++d)
|
||||
{
|
||||
const real_t b = B(p,d);
|
||||
const real_t g = G(p,d);
|
||||
|
||||
Bu[p] += b*u[d];
|
||||
Bdu[p] += Je_side[0] * b * du[d] + Je_side[1] * g * u[d];
|
||||
}
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
|
||||
// term - < {Q du/dn}, [v] > + kappa * < {Q/h} [u], [v] >:
|
||||
if (MFEM_THREAD_ID(y) == 0)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(p,x,Q1D)
|
||||
{
|
||||
const real_t q = pa(0, p, f);
|
||||
const real_t hi = pa(1, p, f);
|
||||
const real_t jump = Bu0[p] - Bu1[p];
|
||||
const real_t avg = Bdu0[p] + Bdu1[p]; // = {Q du/dn} * w * det(J)
|
||||
r[p] = -avg + hi * q * jump;
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
|
||||
MFEM_FOREACH_THREAD(d,x,D1D)
|
||||
{
|
||||
real_t Br = 0.0;
|
||||
|
||||
for (int p = 0; p < Q1D; ++p)
|
||||
{
|
||||
Br += B(p, d) * r[p];
|
||||
}
|
||||
|
||||
u0[d] = Br; // overwrite u0, u1
|
||||
u1[d] = -Br;
|
||||
} // for d
|
||||
MFEM_SYNC_THREAD;
|
||||
|
||||
|
||||
MFEM_FOREACH_THREAD(side,y,2)
|
||||
{
|
||||
real_t *du = (side == 0) ? du0 : du1;
|
||||
MFEM_FOREACH_THREAD(d,x,D1D)
|
||||
{
|
||||
du[d] = 0.0;
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
|
||||
// term sigma * < [u], {Q dv/dn} >
|
||||
MFEM_FOREACH_THREAD(side,y,2)
|
||||
{
|
||||
real_t * const du = (side == 0) ? du0 : du1;
|
||||
real_t * const u = (side == 0) ? u0 : u1;
|
||||
|
||||
MFEM_FOREACH_THREAD(d,x,D1D)
|
||||
{
|
||||
for (int p = 0; p < Q1D; ++p)
|
||||
{
|
||||
const real_t Je[] = {pa(2 + 2*side, p, f), pa(2 + 2*side + 1, p, f)};
|
||||
const real_t jump = Bu0[p] - Bu1[p];
|
||||
const real_t r_p = Je[0] * jump; // normal
|
||||
const real_t w_p = Je[1] * jump; // tangential
|
||||
du[d] += sigma * B(p, d) * r_p;
|
||||
u[d] += sigma * G(p, d) * w_p;
|
||||
}
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
|
||||
MFEM_FOREACH_THREAD(side,y,2)
|
||||
{
|
||||
real_t *u = (side == 0) ? u0 : u1;
|
||||
real_t *du = (side == 0) ? du0 : du1;
|
||||
MFEM_FOREACH_THREAD(d,x,D1D)
|
||||
{
|
||||
y(d, side, f) += u[d];
|
||||
dydn(d, side, f) += du[d];
|
||||
}
|
||||
}
|
||||
}); // mfem::forall
|
||||
ApplyPAKernels::Run(dim, dofs1D, quad1D, nf, maps->B, maps->Bt, maps->G,
|
||||
maps->Gt, sigma, pa_data, x, dxdn, y, dydn, dofs1D,
|
||||
quad1D);
|
||||
}
|
||||
|
||||
template <int T_D1D = 0, int T_Q1D = 0>
|
||||
static void PADGDiffusionApply3D(const int NF,
|
||||
const Array<real_t>& b,
|
||||
const Array<real_t>& bt,
|
||||
const Array<real_t>& g,
|
||||
const Array<real_t>& gt,
|
||||
const real_t sigma,
|
||||
const Vector& pa_data,
|
||||
const Vector& x_,
|
||||
const Vector& dxdn_,
|
||||
Vector& y_,
|
||||
Vector& dydn_,
|
||||
const int d1d = 0,
|
||||
const int q1d = 0)
|
||||
DGDiffusionIntegrator::DGDiffusionIntegrator(const real_t s, const real_t k)
|
||||
: sigma(s), kappa(k)
|
||||
{
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : 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);
|
||||
|
||||
// (J0[0], J0[1], J0[2], J1[0], J1[1], J1[2], q/h)
|
||||
auto pa = Reshape(pa_data.Read(), 7, Q1D, Q1D, NF);
|
||||
|
||||
auto x = Reshape(x_.Read(), D1D, D1D, 2, NF);
|
||||
auto y = Reshape(y_.ReadWrite(), D1D, D1D, 2, NF);
|
||||
auto dxdn = Reshape(dxdn_.Read(), D1D, D1D, 2, NF);
|
||||
auto dydn = Reshape(dydn_.ReadWrite(), D1D, D1D, 2, NF);
|
||||
|
||||
const int NBX = std::max(D1D, Q1D);
|
||||
|
||||
mfem::forall_3D(NF, NBX, NBX, 2, [=] MFEM_HOST_DEVICE (int f) -> void
|
||||
{
|
||||
constexpr int max_D1D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
|
||||
constexpr int max_Q1D = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
|
||||
|
||||
MFEM_SHARED real_t u0[max_Q1D][max_Q1D];
|
||||
MFEM_SHARED real_t u1[max_Q1D][max_Q1D];
|
||||
|
||||
MFEM_SHARED real_t du0[max_Q1D][max_Q1D];
|
||||
MFEM_SHARED real_t du1[max_Q1D][max_Q1D];
|
||||
|
||||
MFEM_SHARED real_t Gu0[max_Q1D][max_Q1D];
|
||||
MFEM_SHARED real_t Gu1[max_Q1D][max_Q1D];
|
||||
|
||||
MFEM_SHARED real_t Bu0[max_Q1D][max_Q1D];
|
||||
MFEM_SHARED real_t Bu1[max_Q1D][max_Q1D];
|
||||
|
||||
MFEM_SHARED real_t Bdu0[max_Q1D][max_Q1D];
|
||||
MFEM_SHARED real_t Bdu1[max_Q1D][max_Q1D];
|
||||
|
||||
MFEM_SHARED real_t kappa_Qh[max_Q1D][max_Q1D];
|
||||
|
||||
MFEM_SHARED real_t nJe[2][max_Q1D][max_Q1D][3];
|
||||
MFEM_SHARED real_t BG[2*max_D1D*max_Q1D];
|
||||
|
||||
// some buffers are reused multiple times, but for clarity have new names:
|
||||
real_t (*Bj0)[max_Q1D] = Bu0;
|
||||
real_t (*Bj1)[max_Q1D] = Bu1;
|
||||
real_t (*Bjn0)[max_Q1D] = Bdu0;
|
||||
real_t (*Bjn1)[max_Q1D] = Bdu1;
|
||||
real_t (*Gj0)[max_Q1D] = Gu0;
|
||||
real_t (*Gj1)[max_Q1D] = Gu1;
|
||||
|
||||
DeviceMatrix B(BG, Q1D, D1D);
|
||||
DeviceMatrix G(BG + D1D*Q1D, Q1D, D1D);
|
||||
|
||||
// copy face values to u0, u1 and copy normals to du0, du1
|
||||
MFEM_FOREACH_THREAD(side, z, 2)
|
||||
{
|
||||
real_t (*u)[max_Q1D] = (side == 0) ? u0 : u1;
|
||||
real_t (*du)[max_Q1D] = (side == 0) ? du0 : du1;
|
||||
|
||||
MFEM_FOREACH_THREAD(d2, x, D1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(d1, y, D1D)
|
||||
{
|
||||
u[d2][d1] = x(d1, d2, side, f); // copy transposed for better memory access
|
||||
du[d2][d1] = dxdn(d1, d2, side, f);
|
||||
}
|
||||
}
|
||||
|
||||
MFEM_FOREACH_THREAD(p1, x, Q1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(p2, y, Q1D)
|
||||
{
|
||||
for (int l=0; l < 3; ++l)
|
||||
{
|
||||
nJe[side][p2][p1][l] = pa(3*side + l, p1, p2, f);
|
||||
}
|
||||
|
||||
if (side == 0)
|
||||
{
|
||||
kappa_Qh[p2][p1] = pa(6, p1, p2, f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (side == 0)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(p, x, Q1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(d, y, D1D)
|
||||
{
|
||||
B(p, d) = B_(p, d);
|
||||
G(p, d) = G_(p, d);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
|
||||
// eval u and normal derivative @ quad points
|
||||
MFEM_FOREACH_THREAD(side, z, 2)
|
||||
{
|
||||
real_t (*u)[max_Q1D] = (side == 0) ? u0 : u1;
|
||||
real_t (*du)[max_Q1D] = (side == 0) ? du0 : du1;
|
||||
real_t (*Bu)[max_Q1D] = (side == 0) ? Bu0 : Bu1;
|
||||
real_t (*Bdu)[max_Q1D] = (side == 0) ? Bdu0 : Bdu1;
|
||||
real_t (*Gu)[max_Q1D] = (side == 0) ? Gu0 : Gu1;
|
||||
|
||||
MFEM_FOREACH_THREAD(p1, x, Q1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(d2, y, D1D)
|
||||
{
|
||||
real_t bu = 0.0;
|
||||
real_t bdu = 0.0;
|
||||
real_t gu = 0.0;
|
||||
|
||||
for (int d1=0; d1 < D1D; ++d1)
|
||||
{
|
||||
const real_t b = B(p1, d1);
|
||||
const real_t g = G(p1, d1);
|
||||
|
||||
bu += b * u[d2][d1];
|
||||
bdu += b * du[d2][d1];
|
||||
gu += g * u[d2][d1];
|
||||
}
|
||||
|
||||
Bu[p1][d2] = bu;
|
||||
Bdu[p1][d2] = bdu;
|
||||
Gu[p1][d2] = gu;
|
||||
}
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
|
||||
MFEM_FOREACH_THREAD(side, z, 2)
|
||||
{
|
||||
real_t (*u)[max_Q1D] = (side == 0) ? u0 : u1;
|
||||
real_t (*du)[max_Q1D] = (side == 0) ? du0 : du1;
|
||||
real_t (*Bu)[max_Q1D] = (side == 0) ? Bu0 : Bu1;
|
||||
real_t (*Gu)[max_Q1D] = (side == 0) ? Gu0 : Gu1;
|
||||
real_t (*Bdu)[max_Q1D] = (side == 0) ? Bdu0 : Bdu1;
|
||||
|
||||
MFEM_FOREACH_THREAD(p2, x, Q1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(p1, y, Q1D)
|
||||
{
|
||||
const real_t * Je = nJe[side][p2][p1];
|
||||
|
||||
real_t bbu = 0.0;
|
||||
real_t bgu = 0.0;
|
||||
real_t gbu = 0.0;
|
||||
real_t bbdu = 0.0;
|
||||
|
||||
for (int d2 = 0; d2 < D1D; ++d2)
|
||||
{
|
||||
const real_t b = B(p2, d2);
|
||||
const real_t g = G(p2, d2);
|
||||
bbu += b * Bu[p1][d2];
|
||||
gbu += g * Bu[p1][d2];
|
||||
bgu += b * Gu[p1][d2];
|
||||
bbdu += b * Bdu[p1][d2];
|
||||
}
|
||||
|
||||
u[p2][p1] = bbu;
|
||||
// du <- Q du/dn * w * det(J)
|
||||
du[p2][p1] = Je[0] * bbdu + Je[1] * bgu + Je[2] * gbu;
|
||||
}
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
|
||||
MFEM_FOREACH_THREAD(side, z, 2)
|
||||
{
|
||||
real_t (*Bj)[max_Q1D] = (side == 0) ? Bj0 : Bj1;
|
||||
real_t (*Bjn)[max_Q1D] = (side == 0) ? Bjn0 : Bjn1;
|
||||
real_t (*Gj)[max_Q1D] = (side == 0) ? Gj0 : Gj1;
|
||||
|
||||
MFEM_FOREACH_THREAD(d1, x, D1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(p2, y, Q1D)
|
||||
{
|
||||
real_t bj = 0.0;
|
||||
real_t bjn = 0.0;
|
||||
real_t gj = 0.0;
|
||||
real_t br = 0.0;
|
||||
|
||||
for (int p1 = 0; p1 < Q1D; ++p1)
|
||||
{
|
||||
const real_t b = B(p1, d1);
|
||||
const real_t g = G(p1, d1);
|
||||
|
||||
const real_t * Je = nJe[side][p2][p1];
|
||||
|
||||
const real_t jump = u0[p2][p1] - u1[p2][p1];
|
||||
const real_t avg = du0[p2][p1] + du1[p2][p1];
|
||||
|
||||
// r = - < {Q du/dn}, [v] > + kappa * < {Q/h} [u], [v] >
|
||||
const real_t r = -avg + kappa_Qh[p2][p1] * jump;
|
||||
|
||||
// bj, gj, bjn contribute to sigma term
|
||||
bj += b * Je[0] * jump;
|
||||
gj += g * Je[1] * jump;
|
||||
bjn += b * Je[2] * jump;
|
||||
|
||||
br += b * r;
|
||||
}
|
||||
|
||||
Bj[d1][p2] = sigma * bj;
|
||||
Bjn[d1][p2] = sigma * bjn;
|
||||
|
||||
// group br and gj together since we will multiply them both by B
|
||||
// and then sum
|
||||
const real_t sgn = (side == 0) ? 1.0 : -1.0;
|
||||
Gj[d1][p2] = sgn * br + sigma * gj;
|
||||
}
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
|
||||
MFEM_FOREACH_THREAD(side, z, 2)
|
||||
{
|
||||
real_t (*u)[max_Q1D] = (side == 0) ? u0 : u1;
|
||||
real_t (*du)[max_Q1D] = (side == 0) ? du0 : du1;
|
||||
real_t (*Bj)[max_Q1D] = (side == 0) ? Bj0 : Bj1;
|
||||
real_t (*Bjn)[max_Q1D] = (side == 0) ? Bjn0 : Bjn1;
|
||||
real_t (*Gj)[max_Q1D] = (side == 0) ? Gj0 : Gj1;
|
||||
|
||||
MFEM_FOREACH_THREAD(d2, x, D1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(d1, y, D1D)
|
||||
{
|
||||
real_t bbj = 0.0;
|
||||
real_t gbj = 0.0;
|
||||
real_t bgj = 0.0;
|
||||
|
||||
for (int p2 = 0; p2 < Q1D; ++p2)
|
||||
{
|
||||
const real_t b = B(p2, d2);
|
||||
const real_t g = G(p2, d2);
|
||||
|
||||
bbj += b * Bj[d1][p2];
|
||||
bgj += b * Gj[d1][p2];
|
||||
gbj += g * Bjn[d1][p2];
|
||||
}
|
||||
|
||||
du[d2][d1] = bbj;
|
||||
u[d2][d1] = bgj + gbj;
|
||||
}
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
|
||||
// map back to y and dydn
|
||||
MFEM_FOREACH_THREAD(side, z, 2)
|
||||
{
|
||||
const real_t (*u)[max_Q1D] = (side == 0) ? u0 : u1;
|
||||
const real_t (*du)[max_Q1D] = (side == 0) ? du0 : du1;
|
||||
|
||||
MFEM_FOREACH_THREAD(d2, x, D1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(d1, y, D1D)
|
||||
{
|
||||
y(d1, d2, side, f) += u[d2][d1];
|
||||
dydn(d1, d2, side, f) += du[d2][d1];
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
static Kernels kernels;
|
||||
}
|
||||
|
||||
static void PADGDiffusionApply(const int dim,
|
||||
const int D1D,
|
||||
const int Q1D,
|
||||
const int NF,
|
||||
const Array<real_t> &B,
|
||||
const Array<real_t> &Bt,
|
||||
const Array<real_t> &G,
|
||||
const Array<real_t> &Gt,
|
||||
const real_t sigma,
|
||||
const Vector &pa_data,
|
||||
const Vector &x,
|
||||
const Vector &dxdn,
|
||||
Vector &y,
|
||||
Vector &dydn)
|
||||
DGDiffusionIntegrator::DGDiffusionIntegrator(Coefficient &q, const real_t s,
|
||||
const real_t k)
|
||||
: DGDiffusionIntegrator(s, k)
|
||||
{
|
||||
Q = &q;
|
||||
}
|
||||
|
||||
DGDiffusionIntegrator::DGDiffusionIntegrator(MatrixCoefficient &q,
|
||||
const real_t s, const real_t k)
|
||||
: DGDiffusionIntegrator(s, k)
|
||||
{
|
||||
MQ = &q;
|
||||
}
|
||||
|
||||
/// \cond DO_NOT_DOCUMENT
|
||||
|
||||
DGDiffusionIntegrator::ApplyKernelType
|
||||
DGDiffusionIntegrator::ApplyPAKernels::Fallback(int dim, int, int)
|
||||
{
|
||||
if (dim == 2)
|
||||
{
|
||||
auto kernel = PADGDiffusionApply2D<0,0>;
|
||||
switch ((D1D << 4 ) | Q1D)
|
||||
{
|
||||
case 0x23: kernel = PADGDiffusionApply2D<2,3>; break;
|
||||
case 0x34: kernel = PADGDiffusionApply2D<3,4>; break;
|
||||
case 0x45: kernel = PADGDiffusionApply2D<4,5>; break;
|
||||
case 0x56: kernel = PADGDiffusionApply2D<5,6>; break;
|
||||
case 0x67: kernel = PADGDiffusionApply2D<6,7>; break;
|
||||
case 0x78: kernel = PADGDiffusionApply2D<7,8>; break;
|
||||
case 0x89: kernel = PADGDiffusionApply2D<8,9>; break;
|
||||
case 0x9A: kernel = PADGDiffusionApply2D<9,10>; break;
|
||||
}
|
||||
kernel(NF, B, Bt, G, Gt, sigma, pa_data, x, dxdn, y, dydn, D1D, Q1D);
|
||||
return internal::PADGDiffusionApply2D;
|
||||
}
|
||||
else if (dim == 3)
|
||||
{
|
||||
auto kernel = PADGDiffusionApply3D<0,0>;
|
||||
switch ((D1D << 4) | Q1D)
|
||||
{
|
||||
case 0x24: kernel = PADGDiffusionApply3D<2,4>; break;
|
||||
case 0x35: kernel = PADGDiffusionApply3D<3,5>; break;
|
||||
case 0x46: kernel = PADGDiffusionApply3D<4,6>; break;
|
||||
case 0x57: kernel = PADGDiffusionApply3D<5,7>; break;
|
||||
case 0x68: kernel = PADGDiffusionApply3D<6,8>; break;
|
||||
case 0x79: kernel = PADGDiffusionApply3D<7,9>; break;
|
||||
case 0x8A: kernel = PADGDiffusionApply3D<8,10>; break;
|
||||
case 0x9B: kernel = PADGDiffusionApply3D<9,11>; break;
|
||||
}
|
||||
kernel(NF, B, Bt, G, Gt, sigma, pa_data, x, dxdn, y, dydn, D1D, Q1D);
|
||||
return internal::PADGDiffusionApply3D;
|
||||
}
|
||||
else
|
||||
{
|
||||
MFEM_ABORT("Unsupported dimension");
|
||||
MFEM_ABORT("");
|
||||
}
|
||||
}
|
||||
|
||||
void DGDiffusionIntegrator::AddMultPAFaceNormalDerivatives(
|
||||
const Vector &x, const Vector &dxdn, Vector &y, Vector &dydn) const
|
||||
DGDiffusionIntegrator::Kernels::Kernels()
|
||||
{
|
||||
PADGDiffusionApply(dim, dofs1D, quad1D, nf,
|
||||
maps->B, maps->Bt, maps->G, maps->Gt,
|
||||
sigma, pa_data, x, dxdn, y, dydn);
|
||||
DGDiffusionIntegrator::AddSpecialization<2, 2, 3>();
|
||||
DGDiffusionIntegrator::AddSpecialization<2, 3, 4>();
|
||||
DGDiffusionIntegrator::AddSpecialization<2, 4, 5>();
|
||||
DGDiffusionIntegrator::AddSpecialization<2, 5, 6>();
|
||||
DGDiffusionIntegrator::AddSpecialization<2, 6, 7>();
|
||||
DGDiffusionIntegrator::AddSpecialization<2, 7, 8>();
|
||||
DGDiffusionIntegrator::AddSpecialization<2, 8, 9>();
|
||||
DGDiffusionIntegrator::AddSpecialization<2, 9, 10>();
|
||||
|
||||
DGDiffusionIntegrator::AddSpecialization<3, 2, 4>();
|
||||
DGDiffusionIntegrator::AddSpecialization<3, 3, 5>();
|
||||
DGDiffusionIntegrator::AddSpecialization<3, 4, 6>();
|
||||
DGDiffusionIntegrator::AddSpecialization<3, 5, 7>();
|
||||
DGDiffusionIntegrator::AddSpecialization<3, 6, 8>();
|
||||
DGDiffusionIntegrator::AddSpecialization<3, 7, 9>();
|
||||
DGDiffusionIntegrator::AddSpecialization<3, 8, 10>();
|
||||
DGDiffusionIntegrator::AddSpecialization<3, 9, 11>();
|
||||
}
|
||||
|
||||
/// \endcond DO_NOT_DOCUMENT
|
||||
|
||||
} // namespace mfem
|
||||
|
||||
@@ -0,0 +1,793 @@
|
||||
// Copyright (c) 2010-2025, 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 BILININTEG_DGTRACE_KERNELS_HPP
|
||||
#define BILININTEG_DGTRACE_KERNELS_HPP
|
||||
|
||||
#include "../../general/forall.hpp"
|
||||
#include "../bilininteg.hpp"
|
||||
#include "../gridfunc.hpp"
|
||||
#include "../qfunction.hpp"
|
||||
#include "../restriction.hpp"
|
||||
|
||||
/// \cond DO_NOT_DOCUMENT
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
namespace internal
|
||||
{
|
||||
|
||||
// PA DGTrace Apply 2D kernel for Gauss-Lobatto/Bernstein
|
||||
template <int T_D1D = 0, int T_Q1D = 0>
|
||||
static void PADGTraceApply2D(const int NF, const Array<real_t> &b,
|
||||
const Array<real_t> &bt, const Vector &op_,
|
||||
const Vector &x_, Vector &y_, const int d1d = 0,
|
||||
const int q1d = 0)
|
||||
{
|
||||
const int VDIM = 1;
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : 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);
|
||||
auto x = Reshape(x_.Read(), D1D, VDIM, 2, NF);
|
||||
auto y = Reshape(y_.ReadWrite(), D1D, VDIM, 2, NF);
|
||||
|
||||
mfem::forall(NF, [=] MFEM_HOST_DEVICE(int f)
|
||||
{
|
||||
const int VDIM = 1;
|
||||
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 : DofQuadLimits::MAX_D1D;
|
||||
constexpr int max_Q1D = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
|
||||
real_t u0[max_D1D][VDIM];
|
||||
real_t u1[max_D1D][VDIM];
|
||||
for (int d = 0; d < D1D; d++)
|
||||
{
|
||||
for (int c = 0; c < VDIM; c++)
|
||||
{
|
||||
u0[d][c] = x(d, c, 0, f);
|
||||
u1[d][c] = x(d, c, 1, f);
|
||||
}
|
||||
}
|
||||
real_t Bu0[max_Q1D][VDIM];
|
||||
real_t Bu1[max_Q1D][VDIM];
|
||||
for (int q = 0; q < Q1D; ++q)
|
||||
{
|
||||
for (int c = 0; c < VDIM; c++)
|
||||
{
|
||||
Bu0[q][c] = 0.0;
|
||||
Bu1[q][c] = 0.0;
|
||||
}
|
||||
for (int d = 0; d < D1D; ++d)
|
||||
{
|
||||
const real_t b = B(q, d);
|
||||
for (int c = 0; c < VDIM; c++)
|
||||
{
|
||||
Bu0[q][c] += b * u0[d][c];
|
||||
Bu1[q][c] += b * u1[d][c];
|
||||
}
|
||||
}
|
||||
}
|
||||
real_t DBu[max_Q1D][VDIM];
|
||||
for (int q = 0; q < Q1D; ++q)
|
||||
{
|
||||
for (int c = 0; c < VDIM; c++)
|
||||
{
|
||||
DBu[q][c] = op(q, 0, 0, f) * Bu0[q][c] + op(q, 1, 0, f) * Bu1[q][c];
|
||||
}
|
||||
}
|
||||
real_t BDBu[max_D1D][VDIM];
|
||||
for (int d = 0; d < D1D; ++d)
|
||||
{
|
||||
for (int c = 0; c < VDIM; c++)
|
||||
{
|
||||
BDBu[d][c] = 0.0;
|
||||
}
|
||||
for (int q = 0; q < Q1D; ++q)
|
||||
{
|
||||
const real_t b = Bt(d, q);
|
||||
for (int c = 0; c < VDIM; c++)
|
||||
{
|
||||
BDBu[d][c] += b * DBu[q][c];
|
||||
}
|
||||
}
|
||||
for (int c = 0; c < VDIM; c++)
|
||||
{
|
||||
y(d, c, 0, f) += BDBu[d][c];
|
||||
y(d, c, 1, f) += -BDBu[d][c];
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// PA DGTrace Apply 3D kernel for Gauss-Lobatto/Bernstein
|
||||
template <int T_D1D = 0, int T_Q1D = 0>
|
||||
static void PADGTraceApply3D(const int NF, const Array<real_t> &b,
|
||||
const Array<real_t> &bt, const Vector &op_,
|
||||
const Vector &x_, Vector &y_, const int d1d = 0,
|
||||
const int q1d = 0)
|
||||
{
|
||||
const int VDIM = 1;
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : 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);
|
||||
auto x = Reshape(x_.Read(), D1D, D1D, VDIM, 2, NF);
|
||||
auto y = Reshape(y_.ReadWrite(), D1D, D1D, VDIM, 2, NF);
|
||||
|
||||
mfem::forall(NF, [=] MFEM_HOST_DEVICE(int f)
|
||||
{
|
||||
const int VDIM = 1;
|
||||
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 : DofQuadLimits::MAX_D1D;
|
||||
constexpr int max_Q1D = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
|
||||
real_t u0[max_D1D][max_D1D][VDIM];
|
||||
real_t u1[max_D1D][max_D1D][VDIM];
|
||||
for (int d1 = 0; d1 < D1D; d1++)
|
||||
{
|
||||
for (int d2 = 0; d2 < D1D; d2++)
|
||||
{
|
||||
for (int c = 0; c < VDIM; c++)
|
||||
{
|
||||
u0[d1][d2][c] = x(d1, d2, c, 0, f);
|
||||
u1[d1][d2][c] = x(d1, d2, c, 1, f);
|
||||
}
|
||||
}
|
||||
}
|
||||
real_t Bu0[max_Q1D][max_D1D][VDIM];
|
||||
real_t Bu1[max_Q1D][max_D1D][VDIM];
|
||||
for (int q = 0; q < Q1D; ++q)
|
||||
{
|
||||
for (int d2 = 0; d2 < D1D; d2++)
|
||||
{
|
||||
for (int c = 0; c < VDIM; c++)
|
||||
{
|
||||
Bu0[q][d2][c] = 0.0;
|
||||
Bu1[q][d2][c] = 0.0;
|
||||
}
|
||||
for (int d1 = 0; d1 < D1D; ++d1)
|
||||
{
|
||||
const real_t b = B(q, d1);
|
||||
for (int c = 0; c < VDIM; c++)
|
||||
{
|
||||
Bu0[q][d2][c] += b * u0[d1][d2][c];
|
||||
Bu1[q][d2][c] += b * u1[d1][d2][c];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
real_t BBu0[max_Q1D][max_Q1D][VDIM];
|
||||
real_t BBu1[max_Q1D][max_Q1D][VDIM];
|
||||
for (int q1 = 0; q1 < Q1D; ++q1)
|
||||
{
|
||||
for (int q2 = 0; q2 < Q1D; q2++)
|
||||
{
|
||||
for (int c = 0; c < VDIM; c++)
|
||||
{
|
||||
BBu0[q1][q2][c] = 0.0;
|
||||
BBu1[q1][q2][c] = 0.0;
|
||||
}
|
||||
for (int d2 = 0; d2 < D1D; ++d2)
|
||||
{
|
||||
const real_t b = B(q2, d2);
|
||||
for (int c = 0; c < VDIM; c++)
|
||||
{
|
||||
BBu0[q1][q2][c] += b * Bu0[q1][d2][c];
|
||||
BBu1[q1][q2][c] += b * Bu1[q1][d2][c];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
real_t DBBu[max_Q1D][max_Q1D][VDIM];
|
||||
for (int q1 = 0; q1 < Q1D; ++q1)
|
||||
{
|
||||
for (int q2 = 0; q2 < Q1D; q2++)
|
||||
{
|
||||
for (int c = 0; c < VDIM; c++)
|
||||
{
|
||||
DBBu[q1][q2][c] = op(q1, q2, 0, 0, f) * BBu0[q1][q2][c] +
|
||||
op(q1, q2, 1, 0, f) * BBu1[q1][q2][c];
|
||||
}
|
||||
}
|
||||
}
|
||||
real_t BDBBu[max_Q1D][max_D1D][VDIM];
|
||||
for (int q1 = 0; q1 < Q1D; ++q1)
|
||||
{
|
||||
for (int d2 = 0; d2 < D1D; d2++)
|
||||
{
|
||||
for (int c = 0; c < VDIM; c++)
|
||||
{
|
||||
BDBBu[q1][d2][c] = 0.0;
|
||||
}
|
||||
for (int q2 = 0; q2 < Q1D; ++q2)
|
||||
{
|
||||
const real_t b = Bt(d2, q2);
|
||||
for (int c = 0; c < VDIM; c++)
|
||||
{
|
||||
BDBBu[q1][d2][c] += b * DBBu[q1][q2][c];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
real_t BBDBBu[max_D1D][max_D1D][VDIM];
|
||||
for (int d1 = 0; d1 < D1D; ++d1)
|
||||
{
|
||||
for (int d2 = 0; d2 < D1D; d2++)
|
||||
{
|
||||
for (int c = 0; c < VDIM; c++)
|
||||
{
|
||||
BBDBBu[d1][d2][c] = 0.0;
|
||||
}
|
||||
for (int q1 = 0; q1 < Q1D; ++q1)
|
||||
{
|
||||
const real_t b = Bt(d1, q1);
|
||||
for (int c = 0; c < VDIM; c++)
|
||||
{
|
||||
BBDBBu[d1][d2][c] += b * BDBBu[q1][d2][c];
|
||||
}
|
||||
}
|
||||
for (int c = 0; c < VDIM; c++)
|
||||
{
|
||||
y(d1, d2, c, 0, f) += BBDBBu[d1][d2][c];
|
||||
y(d1, d2, c, 1, f) += -BBDBBu[d1][d2][c];
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Optimized PA DGTrace Apply 3D kernel for Gauss-Lobatto/Bernstein
|
||||
template <int T_D1D = 0, int T_Q1D = 0, int T_NBZ = 0>
|
||||
static void SmemPADGTraceApply3D(const int NF, const Array<real_t> &b,
|
||||
const Array<real_t> &bt, const Vector &op_,
|
||||
const Vector &x_, Vector &y_,
|
||||
const int d1d = 0, const int q1d = 0)
|
||||
{
|
||||
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 <= 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);
|
||||
auto x = Reshape(x_.Read(), D1D, D1D, 2, NF);
|
||||
auto y = Reshape(y_.ReadWrite(), D1D, D1D, 2, NF);
|
||||
|
||||
mfem::forall_2D_batch(NF, Q1D, Q1D, NBZ, [=] MFEM_HOST_DEVICE(int f)
|
||||
{
|
||||
const int tidz = MFEM_THREAD_ID(z);
|
||||
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 NBZ = T_NBZ ? T_NBZ : 1;
|
||||
constexpr int max_D1D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
|
||||
constexpr int max_Q1D = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
|
||||
MFEM_SHARED real_t u0[NBZ][max_D1D][max_D1D];
|
||||
MFEM_SHARED real_t u1[NBZ][max_D1D][max_D1D];
|
||||
MFEM_FOREACH_THREAD(d1, x, D1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(d2, y, D1D)
|
||||
{
|
||||
u0[tidz][d1][d2] = x(d1, d2, 0, f);
|
||||
u1[tidz][d1][d2] = x(d1, d2, 1, f);
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
MFEM_SHARED real_t Bu0[NBZ][max_Q1D][max_D1D];
|
||||
MFEM_SHARED real_t Bu1[NBZ][max_Q1D][max_D1D];
|
||||
MFEM_FOREACH_THREAD(q1, x, Q1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(d2, y, D1D)
|
||||
{
|
||||
real_t Bu0_ = 0.0;
|
||||
real_t Bu1_ = 0.0;
|
||||
for (int d1 = 0; d1 < D1D; ++d1)
|
||||
{
|
||||
const real_t b = B(q1, d1);
|
||||
Bu0_ += b * u0[tidz][d1][d2];
|
||||
Bu1_ += b * u1[tidz][d1][d2];
|
||||
}
|
||||
Bu0[tidz][q1][d2] = Bu0_;
|
||||
Bu1[tidz][q1][d2] = Bu1_;
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
MFEM_SHARED real_t BBu0[NBZ][max_Q1D][max_Q1D];
|
||||
MFEM_SHARED real_t BBu1[NBZ][max_Q1D][max_Q1D];
|
||||
MFEM_FOREACH_THREAD(q1, x, Q1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(q2, y, Q1D)
|
||||
{
|
||||
real_t BBu0_ = 0.0;
|
||||
real_t BBu1_ = 0.0;
|
||||
for (int d2 = 0; d2 < D1D; ++d2)
|
||||
{
|
||||
const real_t b = B(q2, d2);
|
||||
BBu0_ += b * Bu0[tidz][q1][d2];
|
||||
BBu1_ += b * Bu1[tidz][q1][d2];
|
||||
}
|
||||
BBu0[tidz][q1][q2] = BBu0_;
|
||||
BBu1[tidz][q1][q2] = BBu1_;
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
MFEM_SHARED real_t DBBu[NBZ][max_Q1D][max_Q1D];
|
||||
MFEM_FOREACH_THREAD(q1, x, Q1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(q2, y, Q1D)
|
||||
{
|
||||
DBBu[tidz][q1][q2] = op(q1, q2, 0, 0, f) * BBu0[tidz][q1][q2] +
|
||||
op(q1, q2, 1, 0, f) * BBu1[tidz][q1][q2];
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
MFEM_SHARED real_t BDBBu[NBZ][max_Q1D][max_D1D];
|
||||
MFEM_FOREACH_THREAD(q1, x, Q1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(d2, y, D1D)
|
||||
{
|
||||
real_t BDBBu_ = 0.0;
|
||||
for (int q2 = 0; q2 < Q1D; ++q2)
|
||||
{
|
||||
const real_t b = Bt(d2, q2);
|
||||
BDBBu_ += b * DBBu[tidz][q1][q2];
|
||||
}
|
||||
BDBBu[tidz][q1][d2] = BDBBu_;
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
MFEM_FOREACH_THREAD(d1, x, D1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(d2, y, D1D)
|
||||
{
|
||||
real_t BBDBBu_ = 0.0;
|
||||
for (int q1 = 0; q1 < Q1D; ++q1)
|
||||
{
|
||||
const real_t b = Bt(d1, q1);
|
||||
BBDBBu_ += b * BDBBu[tidz][q1][d2];
|
||||
}
|
||||
y(d1, d2, 0, f) += BBDBBu_;
|
||||
y(d1, d2, 1, f) += -BBDBBu_;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// PA DGTrace Apply 2D kernel for Gauss-Lobatto/Bernstein
|
||||
template <int T_D1D = 0, int T_Q1D = 0>
|
||||
static void PADGTraceApplyTranspose2D(const int NF, const Array<real_t> &b,
|
||||
const Array<real_t> &bt,
|
||||
const Vector &op_, const Vector &x_,
|
||||
Vector &y_, const int d1d = 0,
|
||||
const int q1d = 0)
|
||||
{
|
||||
const int VDIM = 1;
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : 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);
|
||||
auto x = Reshape(x_.Read(), D1D, VDIM, 2, NF);
|
||||
auto y = Reshape(y_.ReadWrite(), D1D, VDIM, 2, NF);
|
||||
|
||||
mfem::forall(NF, [=] MFEM_HOST_DEVICE(int f)
|
||||
{
|
||||
const int VDIM = 1;
|
||||
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 : DofQuadLimits::MAX_D1D;
|
||||
constexpr int max_Q1D = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
|
||||
real_t u0[max_D1D][VDIM];
|
||||
real_t u1[max_D1D][VDIM];
|
||||
for (int d = 0; d < D1D; d++)
|
||||
{
|
||||
for (int c = 0; c < VDIM; c++)
|
||||
{
|
||||
u0[d][c] = x(d, c, 0, f);
|
||||
u1[d][c] = x(d, c, 1, f);
|
||||
}
|
||||
}
|
||||
real_t Bu0[max_Q1D][VDIM];
|
||||
real_t Bu1[max_Q1D][VDIM];
|
||||
for (int q = 0; q < Q1D; ++q)
|
||||
{
|
||||
for (int c = 0; c < VDIM; c++)
|
||||
{
|
||||
Bu0[q][c] = 0.0;
|
||||
Bu1[q][c] = 0.0;
|
||||
}
|
||||
for (int d = 0; d < D1D; ++d)
|
||||
{
|
||||
const real_t b = B(q, d);
|
||||
for (int c = 0; c < VDIM; c++)
|
||||
{
|
||||
Bu0[q][c] += b * u0[d][c];
|
||||
Bu1[q][c] += b * u1[d][c];
|
||||
}
|
||||
}
|
||||
}
|
||||
real_t DBu0[max_Q1D][VDIM];
|
||||
real_t DBu1[max_Q1D][VDIM];
|
||||
for (int q = 0; q < Q1D; ++q)
|
||||
{
|
||||
for (int c = 0; c < VDIM; c++)
|
||||
{
|
||||
DBu0[q][c] =
|
||||
op(q, 0, 0, f) * Bu0[q][c] + op(q, 0, 1, f) * Bu1[q][c];
|
||||
DBu1[q][c] =
|
||||
op(q, 1, 0, f) * Bu0[q][c] + op(q, 1, 1, f) * Bu1[q][c];
|
||||
}
|
||||
}
|
||||
real_t BDBu0[max_D1D][VDIM];
|
||||
real_t BDBu1[max_D1D][VDIM];
|
||||
for (int d = 0; d < D1D; ++d)
|
||||
{
|
||||
for (int c = 0; c < VDIM; c++)
|
||||
{
|
||||
BDBu0[d][c] = 0.0;
|
||||
BDBu1[d][c] = 0.0;
|
||||
}
|
||||
for (int q = 0; q < Q1D; ++q)
|
||||
{
|
||||
const real_t b = Bt(d, q);
|
||||
for (int c = 0; c < VDIM; c++)
|
||||
{
|
||||
BDBu0[d][c] += b * DBu0[q][c];
|
||||
BDBu1[d][c] += b * DBu1[q][c];
|
||||
}
|
||||
}
|
||||
for (int c = 0; c < VDIM; c++)
|
||||
{
|
||||
y(d, c, 0, f) += BDBu0[d][c];
|
||||
y(d, c, 1, f) += BDBu1[d][c];
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// PA DGTrace Apply Transpose 3D kernel for Gauss-Lobatto/Bernstein
|
||||
template <int T_D1D = 0, int T_Q1D = 0>
|
||||
static void PADGTraceApplyTranspose3D(const int NF, const Array<real_t> &b,
|
||||
const Array<real_t> &bt,
|
||||
const Vector &op_, const Vector &x_,
|
||||
Vector &y_, const int d1d = 0,
|
||||
const int q1d = 0)
|
||||
{
|
||||
const int VDIM = 1;
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : 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);
|
||||
auto x = Reshape(x_.Read(), D1D, D1D, VDIM, 2, NF);
|
||||
auto y = Reshape(y_.ReadWrite(), D1D, D1D, VDIM, 2, NF);
|
||||
|
||||
mfem::forall(NF, [=] MFEM_HOST_DEVICE(int f)
|
||||
{
|
||||
const int VDIM = 1;
|
||||
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 : DofQuadLimits::MAX_D1D;
|
||||
constexpr int max_Q1D = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
|
||||
real_t u0[max_D1D][max_D1D][VDIM];
|
||||
real_t u1[max_D1D][max_D1D][VDIM];
|
||||
for (int d1 = 0; d1 < D1D; d1++)
|
||||
{
|
||||
for (int d2 = 0; d2 < D1D; d2++)
|
||||
{
|
||||
for (int c = 0; c < VDIM; c++)
|
||||
{
|
||||
u0[d1][d2][c] = x(d1, d2, c, 0, f);
|
||||
u1[d1][d2][c] = x(d1, d2, c, 1, f);
|
||||
}
|
||||
}
|
||||
}
|
||||
real_t Bu0[max_Q1D][max_D1D][VDIM];
|
||||
real_t Bu1[max_Q1D][max_D1D][VDIM];
|
||||
for (int q1 = 0; q1 < Q1D; ++q1)
|
||||
{
|
||||
for (int d2 = 0; d2 < D1D; ++d2)
|
||||
{
|
||||
for (int c = 0; c < VDIM; c++)
|
||||
{
|
||||
Bu0[q1][d2][c] = 0.0;
|
||||
Bu1[q1][d2][c] = 0.0;
|
||||
}
|
||||
for (int d1 = 0; d1 < D1D; ++d1)
|
||||
{
|
||||
const real_t b = B(q1, d1);
|
||||
for (int c = 0; c < VDIM; c++)
|
||||
{
|
||||
Bu0[q1][d2][c] += b * u0[d1][d2][c];
|
||||
Bu1[q1][d2][c] += b * u1[d1][d2][c];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
real_t BBu0[max_Q1D][max_Q1D][VDIM];
|
||||
real_t BBu1[max_Q1D][max_Q1D][VDIM];
|
||||
for (int q1 = 0; q1 < Q1D; ++q1)
|
||||
{
|
||||
for (int q2 = 0; q2 < Q1D; ++q2)
|
||||
{
|
||||
for (int c = 0; c < VDIM; c++)
|
||||
{
|
||||
BBu0[q1][q2][c] = 0.0;
|
||||
BBu1[q1][q2][c] = 0.0;
|
||||
}
|
||||
for (int d2 = 0; d2 < D1D; ++d2)
|
||||
{
|
||||
const real_t b = B(q2, d2);
|
||||
for (int c = 0; c < VDIM; c++)
|
||||
{
|
||||
BBu0[q1][q2][c] += b * Bu0[q1][d2][c];
|
||||
BBu1[q1][q2][c] += b * Bu1[q1][d2][c];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
real_t DBu0[max_Q1D][max_Q1D][VDIM];
|
||||
real_t DBu1[max_Q1D][max_Q1D][VDIM];
|
||||
for (int q1 = 0; q1 < Q1D; ++q1)
|
||||
{
|
||||
for (int q2 = 0; q2 < Q1D; ++q2)
|
||||
{
|
||||
const real_t D00 = op(q1, q2, 0, 0, f);
|
||||
const real_t D01 = op(q1, q2, 0, 1, f);
|
||||
const real_t D10 = op(q1, q2, 1, 0, f);
|
||||
const real_t D11 = op(q1, q2, 1, 1, f);
|
||||
for (int c = 0; c < VDIM; c++)
|
||||
{
|
||||
DBu0[q1][q2][c] = D00 * BBu0[q1][q2][c] + D01 * BBu1[q1][q2][c];
|
||||
DBu1[q1][q2][c] = D10 * BBu0[q1][q2][c] + D11 * BBu1[q1][q2][c];
|
||||
}
|
||||
}
|
||||
}
|
||||
real_t BDBu0[max_D1D][max_Q1D][VDIM];
|
||||
real_t BDBu1[max_D1D][max_Q1D][VDIM];
|
||||
for (int d1 = 0; d1 < D1D; ++d1)
|
||||
{
|
||||
for (int q2 = 0; q2 < Q1D; ++q2)
|
||||
{
|
||||
for (int c = 0; c < VDIM; c++)
|
||||
{
|
||||
BDBu0[d1][q2][c] = 0.0;
|
||||
BDBu1[d1][q2][c] = 0.0;
|
||||
}
|
||||
for (int q1 = 0; q1 < Q1D; ++q1)
|
||||
{
|
||||
const real_t b = Bt(d1, q1);
|
||||
for (int c = 0; c < VDIM; c++)
|
||||
{
|
||||
BDBu0[d1][q2][c] += b * DBu0[q1][q2][c];
|
||||
BDBu1[d1][q2][c] += b * DBu1[q1][q2][c];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
real_t BBDBu0[max_D1D][max_D1D][VDIM];
|
||||
real_t BBDBu1[max_D1D][max_D1D][VDIM];
|
||||
for (int d1 = 0; d1 < D1D; ++d1)
|
||||
{
|
||||
for (int d2 = 0; d2 < D1D; ++d2)
|
||||
{
|
||||
for (int c = 0; c < VDIM; c++)
|
||||
{
|
||||
BBDBu0[d1][d2][c] = 0.0;
|
||||
BBDBu1[d1][d2][c] = 0.0;
|
||||
}
|
||||
for (int q2 = 0; q2 < Q1D; ++q2)
|
||||
{
|
||||
const real_t b = Bt(d2, q2);
|
||||
for (int c = 0; c < VDIM; c++)
|
||||
{
|
||||
BBDBu0[d1][d2][c] += b * BDBu0[d1][q2][c];
|
||||
BBDBu1[d1][d2][c] += b * BDBu1[d1][q2][c];
|
||||
}
|
||||
}
|
||||
for (int c = 0; c < VDIM; c++)
|
||||
{
|
||||
y(d1, d2, c, 0, f) += BBDBu0[d1][d2][c];
|
||||
y(d1, d2, c, 1, f) += BBDBu1[d1][d2][c];
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Optimized PA DGTrace Apply Transpose 3D kernel for Gauss-Lobatto/Bernstein
|
||||
template <int T_D1D = 0, int T_Q1D = 0, int T_NBZ = 0>
|
||||
static void SmemPADGTraceApplyTranspose3D(const int NF, const Array<real_t> &b,
|
||||
const Array<real_t> &bt,
|
||||
const Vector &op_, const Vector &x_,
|
||||
Vector &y_, const int d1d = 0,
|
||||
const int q1d = 0)
|
||||
{
|
||||
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 <= 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);
|
||||
auto x = Reshape(x_.Read(), D1D, D1D, 2, NF);
|
||||
auto y = Reshape(y_.ReadWrite(), D1D, D1D, 2, NF);
|
||||
|
||||
mfem::forall_2D_batch(NF, Q1D, Q1D, NBZ, [=] MFEM_HOST_DEVICE(int f)
|
||||
{
|
||||
const int tidz = MFEM_THREAD_ID(z);
|
||||
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 NBZ = T_NBZ ? T_NBZ : 1;
|
||||
constexpr int max_D1D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
|
||||
constexpr int max_Q1D = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
|
||||
MFEM_SHARED real_t u0[NBZ][max_D1D][max_D1D];
|
||||
MFEM_SHARED real_t u1[NBZ][max_D1D][max_D1D];
|
||||
MFEM_FOREACH_THREAD(d1, x, D1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(d2, y, D1D)
|
||||
{
|
||||
u0[tidz][d1][d2] = x(d1, d2, 0, f);
|
||||
u1[tidz][d1][d2] = x(d1, d2, 1, f);
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
MFEM_SHARED real_t Bu0[NBZ][max_Q1D][max_D1D];
|
||||
MFEM_SHARED real_t Bu1[NBZ][max_Q1D][max_D1D];
|
||||
MFEM_FOREACH_THREAD(q1, x, Q1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(d2, y, D1D)
|
||||
{
|
||||
real_t Bu0_ = 0.0;
|
||||
real_t Bu1_ = 0.0;
|
||||
for (int d1 = 0; d1 < D1D; ++d1)
|
||||
{
|
||||
const real_t b = B(q1, d1);
|
||||
Bu0_ += b * u0[tidz][d1][d2];
|
||||
Bu1_ += b * u1[tidz][d1][d2];
|
||||
}
|
||||
Bu0[tidz][q1][d2] = Bu0_;
|
||||
Bu1[tidz][q1][d2] = Bu1_;
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
MFEM_SHARED real_t BBu0[NBZ][max_Q1D][max_Q1D];
|
||||
MFEM_SHARED real_t BBu1[NBZ][max_Q1D][max_Q1D];
|
||||
MFEM_FOREACH_THREAD(q1, x, Q1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(q2, y, Q1D)
|
||||
{
|
||||
real_t BBu0_ = 0.0;
|
||||
real_t BBu1_ = 0.0;
|
||||
for (int d2 = 0; d2 < D1D; ++d2)
|
||||
{
|
||||
const real_t b = B(q2, d2);
|
||||
BBu0_ += b * Bu0[tidz][q1][d2];
|
||||
BBu1_ += b * Bu1[tidz][q1][d2];
|
||||
}
|
||||
BBu0[tidz][q1][q2] = BBu0_;
|
||||
BBu1[tidz][q1][q2] = BBu1_;
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
MFEM_SHARED real_t DBBu0[NBZ][max_Q1D][max_Q1D];
|
||||
MFEM_SHARED real_t DBBu1[NBZ][max_Q1D][max_Q1D];
|
||||
MFEM_FOREACH_THREAD(q1, x, Q1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(q2, y, Q1D)
|
||||
{
|
||||
const real_t D00 = op(q1, q2, 0, 0, f);
|
||||
const real_t D01 = op(q1, q2, 0, 1, f);
|
||||
const real_t D10 = op(q1, q2, 1, 0, f);
|
||||
const real_t D11 = op(q1, q2, 1, 1, f);
|
||||
const real_t u0q = BBu0[tidz][q1][q2];
|
||||
const real_t u1q = BBu1[tidz][q1][q2];
|
||||
DBBu0[tidz][q1][q2] = D00 * u0q + D01 * u1q;
|
||||
DBBu1[tidz][q1][q2] = D10 * u0q + D11 * u1q;
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
MFEM_SHARED real_t BDBBu0[NBZ][max_Q1D][max_D1D];
|
||||
MFEM_SHARED real_t BDBBu1[NBZ][max_Q1D][max_D1D];
|
||||
MFEM_FOREACH_THREAD(q1, x, Q1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(d2, y, D1D)
|
||||
{
|
||||
real_t BDBBu0_ = 0.0;
|
||||
real_t BDBBu1_ = 0.0;
|
||||
for (int q2 = 0; q2 < Q1D; ++q2)
|
||||
{
|
||||
const real_t b = Bt(d2, q2);
|
||||
BDBBu0_ += b * DBBu0[tidz][q1][q2];
|
||||
BDBBu1_ += b * DBBu1[tidz][q1][q2];
|
||||
}
|
||||
BDBBu0[tidz][q1][d2] = BDBBu0_;
|
||||
BDBBu1[tidz][q1][d2] = BDBBu1_;
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
MFEM_FOREACH_THREAD(d1, x, D1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(d2, y, D1D)
|
||||
{
|
||||
real_t BBDBBu0_ = 0.0;
|
||||
real_t BBDBBu1_ = 0.0;
|
||||
for (int q1 = 0; q1 < Q1D; ++q1)
|
||||
{
|
||||
const real_t b = Bt(d1, q1);
|
||||
BBDBBu0_ += b * BDBBu0[tidz][q1][d2];
|
||||
BBDBBu1_ += b * BDBBu1[tidz][q1][d2];
|
||||
}
|
||||
y(d1, d2, 0, f) += BBDBBu0_;
|
||||
y(d1, d2, 1, f) += BBDBBu1_;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
template <int DIM, int D1D, int Q1D>
|
||||
DGTraceIntegrator::ApplyKernelType DGTraceIntegrator::ApplyPAKernels::Kernel()
|
||||
{
|
||||
if constexpr (DIM == 2)
|
||||
{
|
||||
return internal::PADGTraceApply2D<D1D, Q1D>;
|
||||
}
|
||||
else if constexpr (DIM == 3)
|
||||
{
|
||||
if constexpr (D1D == 3 || D1D == 4)
|
||||
{
|
||||
return internal::SmemPADGTraceApply3D<D1D, Q1D, 2>;
|
||||
}
|
||||
else
|
||||
{
|
||||
return internal::SmemPADGTraceApply3D<D1D, Q1D>;
|
||||
}
|
||||
}
|
||||
MFEM_ABORT("");
|
||||
}
|
||||
|
||||
template <int DIM, int D1D, int Q1D>
|
||||
DGTraceIntegrator::ApplyKernelType DGTraceIntegrator::ApplyPATKernels::Kernel()
|
||||
{
|
||||
if constexpr (DIM == 2)
|
||||
{
|
||||
return internal::PADGTraceApplyTranspose2D<D1D, Q1D>;
|
||||
}
|
||||
else if constexpr (DIM == 3)
|
||||
{
|
||||
return internal::SmemPADGTraceApplyTranspose3D<D1D, Q1D>;
|
||||
}
|
||||
MFEM_ABORT("");
|
||||
}
|
||||
} // namespace mfem
|
||||
|
||||
/// \endcond DO_NOT_DOCUMENT
|
||||
#endif
|
||||
+168
-925
File diff suppressed because it is too large
Load Diff
@@ -19,6 +19,8 @@ namespace mfem
|
||||
DiffusionIntegrator::Kernels::Kernels()
|
||||
{
|
||||
// 2D
|
||||
// Q = P+1
|
||||
DiffusionIntegrator::AddSpecialization<2,1,1>();
|
||||
DiffusionIntegrator::AddSpecialization<2,2,2>();
|
||||
DiffusionIntegrator::AddSpecialization<2,3,3>();
|
||||
DiffusionIntegrator::AddSpecialization<2,4,4>();
|
||||
@@ -27,17 +29,39 @@ DiffusionIntegrator::Kernels::Kernels()
|
||||
DiffusionIntegrator::AddSpecialization<2,7,7>();
|
||||
DiffusionIntegrator::AddSpecialization<2,8,8>();
|
||||
DiffusionIntegrator::AddSpecialization<2,9,9>();
|
||||
// Q = P+2
|
||||
DiffusionIntegrator::AddSpecialization<2,1,2>();
|
||||
DiffusionIntegrator::AddSpecialization<2,2,3>();
|
||||
DiffusionIntegrator::AddSpecialization<2,3,4>();
|
||||
DiffusionIntegrator::AddSpecialization<2,4,5>();
|
||||
DiffusionIntegrator::AddSpecialization<2,5,6>();
|
||||
DiffusionIntegrator::AddSpecialization<2,6,7>();
|
||||
DiffusionIntegrator::AddSpecialization<2,7,8>();
|
||||
DiffusionIntegrator::AddSpecialization<2,8,9>();
|
||||
DiffusionIntegrator::AddSpecialization<2,9,10>();
|
||||
// others
|
||||
// 3D
|
||||
// Q = P+1
|
||||
DiffusionIntegrator::AddSpecialization<3,1,1>();
|
||||
DiffusionIntegrator::AddSpecialization<3,2,2>();
|
||||
DiffusionIntegrator::AddSpecialization<3,3,3>();
|
||||
DiffusionIntegrator::AddSpecialization<3,4,4>();
|
||||
DiffusionIntegrator::AddSpecialization<3,5,5>();
|
||||
DiffusionIntegrator::AddSpecialization<3,6,6>();
|
||||
DiffusionIntegrator::AddSpecialization<3,7,7>();
|
||||
DiffusionIntegrator::AddSpecialization<3,8,8>();
|
||||
// Q = P+2
|
||||
DiffusionIntegrator::AddSpecialization<3,1,2>();
|
||||
DiffusionIntegrator::AddSpecialization<3,2,3>();
|
||||
DiffusionIntegrator::AddSpecialization<3,3,4>();
|
||||
DiffusionIntegrator::AddSpecialization<3,4,5>();
|
||||
DiffusionIntegrator::AddSpecialization<3,4,6>();
|
||||
DiffusionIntegrator::AddSpecialization<3,5,6>();
|
||||
DiffusionIntegrator::AddSpecialization<3,5,8>();
|
||||
DiffusionIntegrator::AddSpecialization<3,6,7>();
|
||||
DiffusionIntegrator::AddSpecialization<3,7,8>();
|
||||
DiffusionIntegrator::AddSpecialization<3,8,9>();
|
||||
// others
|
||||
DiffusionIntegrator::AddSpecialization<3,4,6>();
|
||||
DiffusionIntegrator::AddSpecialization<3,5,8>();
|
||||
}
|
||||
|
||||
namespace internal
|
||||
|
||||
@@ -672,12 +672,12 @@ inline void SmemPADiffusionApply2D(const int NE,
|
||||
real_t (*Gt)[MQ1] = (real_t (*)[MQ1]) (sBG+1);
|
||||
MFEM_SHARED real_t Xz[NBZ][MD1][MD1];
|
||||
MFEM_SHARED real_t GD[2][NBZ][MD1][MQ1];
|
||||
MFEM_SHARED real_t GQ[2][NBZ][MD1][MQ1];
|
||||
MFEM_SHARED real_t GQ[2][NBZ][MQ1][MQ1];
|
||||
real_t (*X)[MD1] = (real_t (*)[MD1])(Xz + tidz);
|
||||
real_t (*DQ0)[MD1] = (real_t (*)[MD1])(GD[0] + tidz);
|
||||
real_t (*DQ1)[MD1] = (real_t (*)[MD1])(GD[1] + tidz);
|
||||
real_t (*QQ0)[MD1] = (real_t (*)[MD1])(GQ[0] + tidz);
|
||||
real_t (*QQ1)[MD1] = (real_t (*)[MD1])(GQ[1] + tidz);
|
||||
real_t (*DQ0)[MQ1] = (real_t (*)[MQ1])(GD[0] + tidz);
|
||||
real_t (*DQ1)[MQ1] = (real_t (*)[MQ1])(GD[1] + tidz);
|
||||
real_t (*QQ0)[MQ1] = (real_t (*)[MQ1])(GQ[0] + tidz);
|
||||
real_t (*QQ1)[MQ1] = (real_t (*)[MQ1])(GQ[1] + tidz);
|
||||
MFEM_FOREACH_THREAD(dy,y,D1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(dx,x,D1D)
|
||||
@@ -1221,9 +1221,9 @@ using DiagonalKernelType = DiffusionIntegrator::DiagonalKernelType;
|
||||
template<int DIM, int T_D1D, int T_Q1D>
|
||||
ApplyKernelType DiffusionIntegrator::ApplyPAKernels::Kernel()
|
||||
{
|
||||
if (DIM == 2) { return internal::SmemPADiffusionApply2D<T_D1D,T_Q1D>; }
|
||||
else if (DIM == 3) { return internal::SmemPADiffusionApply3D<T_D1D, T_Q1D>; }
|
||||
else { MFEM_ABORT(""); }
|
||||
if constexpr (DIM == 2) { return internal::SmemPADiffusionApply2D<T_D1D,T_Q1D>; }
|
||||
else if constexpr (DIM == 3) { return internal::SmemPADiffusionApply3D<T_D1D, T_Q1D>; }
|
||||
MFEM_ABORT("");
|
||||
}
|
||||
|
||||
inline
|
||||
@@ -1237,9 +1237,9 @@ ApplyKernelType DiffusionIntegrator::ApplyPAKernels::Fallback(int DIM, int, int)
|
||||
template<int DIM, int D1D, int Q1D>
|
||||
DiagonalKernelType DiffusionIntegrator::DiagonalPAKernels::Kernel()
|
||||
{
|
||||
if (DIM == 2) { return internal::SmemPADiffusionDiagonal2D<D1D,Q1D>; }
|
||||
else if (DIM == 3) { return internal::SmemPADiffusionDiagonal3D<D1D, Q1D>; }
|
||||
else { MFEM_ABORT(""); }
|
||||
if constexpr (DIM == 2) { return internal::SmemPADiffusionDiagonal2D<D1D,Q1D>; }
|
||||
else if constexpr (DIM == 3) { return internal::SmemPADiffusionDiagonal3D<D1D, Q1D>; }
|
||||
MFEM_ABORT("");
|
||||
}
|
||||
|
||||
inline DiagonalKernelType
|
||||
|
||||
@@ -599,13 +599,11 @@ void PACurlCurlSetup3D(const int Q1D,
|
||||
});
|
||||
}
|
||||
|
||||
void PACurlCurlAssembleDiagonal2D(const int D1D,
|
||||
const int Q1D,
|
||||
const int NE,
|
||||
const Array<real_t> &bo,
|
||||
void PACurlCurlAssembleDiagonal2D(const int D1D, const int Q1D, const bool,
|
||||
const int NE, const Array<real_t> &bo,
|
||||
const Array<real_t> &, const Array<real_t> &,
|
||||
const Array<real_t> &gc,
|
||||
const Vector &pa_data,
|
||||
Vector &diag)
|
||||
const Vector &pa_data, Vector &diag)
|
||||
{
|
||||
auto Bo = Reshape(bo.Read(), Q1D, D1D-1);
|
||||
auto Gc = Reshape(gc.Read(), Q1D, D1D);
|
||||
@@ -653,16 +651,11 @@ void PACurlCurlAssembleDiagonal2D(const int D1D,
|
||||
}); // end of element loop
|
||||
}
|
||||
|
||||
void PACurlCurlApply2D(const int D1D,
|
||||
const int Q1D,
|
||||
const int NE,
|
||||
const Array<real_t> &bo,
|
||||
const Array<real_t> &bot,
|
||||
const Array<real_t> &gc,
|
||||
const Array<real_t> &gct,
|
||||
const Vector &pa_data,
|
||||
const Vector &x,
|
||||
Vector &y,
|
||||
void PACurlCurlApply2D(const int D1D, const int Q1D, const bool, const int NE,
|
||||
const Array<real_t> &bo, const Array<real_t> &,
|
||||
const Array<real_t> &bot, const Array<real_t> &,
|
||||
const Array<real_t> &gc, const Array<real_t> &gct,
|
||||
const Vector &pa_data, const Vector &x, Vector &y,
|
||||
const bool useAbs)
|
||||
{
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
/// \cond DO_NOT_DOCUMENT
|
||||
namespace internal
|
||||
{
|
||||
|
||||
@@ -426,8 +426,11 @@ void PACurlCurlSetup3D(const int Q1D,
|
||||
// PA H(curl) curl-curl Diagonal 2D kernel
|
||||
void PACurlCurlAssembleDiagonal2D(const int D1D,
|
||||
const int Q1D,
|
||||
const bool symmetric, // unused
|
||||
const int NE,
|
||||
const Array<real_t> &bo,
|
||||
const Array<real_t> &bc, // unused
|
||||
const Array<real_t> &go, // unused
|
||||
const Array<real_t> &gc,
|
||||
const Vector &pa_data,
|
||||
Vector &diag);
|
||||
@@ -831,9 +834,12 @@ inline void SmemPACurlCurlAssembleDiagonal3D(const int d1d,
|
||||
// PA H(curl) curl-curl Apply/AbsApply 2D kernel
|
||||
void PACurlCurlApply2D(const int D1D,
|
||||
const int Q1D,
|
||||
const bool symmetric, // unused
|
||||
const int NE,
|
||||
const Array<real_t> &bo,
|
||||
const Array<real_t> &bc, // unused
|
||||
const Array<real_t> &bot,
|
||||
const Array<real_t> &bct, // unused
|
||||
const Array<real_t> &gc,
|
||||
const Array<real_t> &gct,
|
||||
const Vector &pa_data,
|
||||
@@ -3158,6 +3164,49 @@ inline void SmemPAHcurlL2ApplyTranspose3D(const int d1d,
|
||||
|
||||
} // namespace internal
|
||||
|
||||
template<int DIM, int T_D1D, int T_Q1D>
|
||||
CurlCurlIntegrator::ApplyKernelType CurlCurlIntegrator::ApplyPAKernels::Kernel()
|
||||
{
|
||||
if constexpr (DIM == 2)
|
||||
{
|
||||
return internal::PACurlCurlApply2D;
|
||||
}
|
||||
else if constexpr (DIM == 3)
|
||||
{
|
||||
if (Device::Allows(Backend::DEVICE_MASK))
|
||||
{
|
||||
return internal::SmemPACurlCurlApply3D<T_D1D, T_Q1D>;
|
||||
}
|
||||
else
|
||||
{
|
||||
return internal::PACurlCurlApply3D;
|
||||
}
|
||||
}
|
||||
MFEM_ABORT("");
|
||||
}
|
||||
|
||||
template <int DIM, int T_D1D, int T_Q1D>
|
||||
CurlCurlIntegrator::DiagonalKernelType
|
||||
CurlCurlIntegrator::DiagonalPAKernels::Kernel()
|
||||
{
|
||||
if constexpr (DIM == 2)
|
||||
{
|
||||
return internal::PACurlCurlAssembleDiagonal2D;
|
||||
}
|
||||
else if constexpr (DIM == 3)
|
||||
{
|
||||
if (Device::Allows(Backend::DEVICE_MASK))
|
||||
{
|
||||
return internal::SmemPACurlCurlAssembleDiagonal3D<T_D1D, T_Q1D>;
|
||||
}
|
||||
else
|
||||
{
|
||||
return internal::PACurlCurlAssembleDiagonal3D;
|
||||
}
|
||||
}
|
||||
MFEM_ABORT("");
|
||||
}
|
||||
/// \endcond DO_NOT_DOCUMENT
|
||||
} // namespace mfem
|
||||
|
||||
#endif
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "../../linalg/vector.hpp"
|
||||
#include "../bilininteg.hpp"
|
||||
|
||||
/// \cond DO_NOT_DOCUMENT
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
@@ -819,4 +820,6 @@ inline void PAHcurlHdivApplyTranspose3D(const int d1d,
|
||||
|
||||
} // namespace mfem
|
||||
|
||||
/// \endcond DO_NOT_DOCUMENT
|
||||
|
||||
#endif
|
||||
|
||||
@@ -17,6 +17,8 @@ namespace mfem
|
||||
MassIntegrator::Kernels::Kernels()
|
||||
{
|
||||
// 2D
|
||||
// Q=P+1
|
||||
MassIntegrator::AddSpecialization<2,1,1>();
|
||||
MassIntegrator::AddSpecialization<2,2,2>();
|
||||
MassIntegrator::AddSpecialization<2,3,3>();
|
||||
MassIntegrator::AddSpecialization<2,4,4>();
|
||||
@@ -25,17 +27,45 @@ MassIntegrator::Kernels::Kernels()
|
||||
MassIntegrator::AddSpecialization<2,7,7>();
|
||||
MassIntegrator::AddSpecialization<2,8,8>();
|
||||
MassIntegrator::AddSpecialization<2,9,9>();
|
||||
// Q=P+2
|
||||
MassIntegrator::AddSpecialization<2,1,2>();
|
||||
MassIntegrator::AddSpecialization<2,2,3>();
|
||||
MassIntegrator::AddSpecialization<2,3,4>();
|
||||
MassIntegrator::AddSpecialization<2,4,5>();
|
||||
MassIntegrator::AddSpecialization<2,5,6>();
|
||||
MassIntegrator::AddSpecialization<2,6,7>();
|
||||
MassIntegrator::AddSpecialization<2,7,8>();
|
||||
MassIntegrator::AddSpecialization<2,8,9>();
|
||||
MassIntegrator::AddSpecialization<2,9,10>();
|
||||
// others
|
||||
MassIntegrator::AddSpecialization<2,2,4>();
|
||||
MassIntegrator::AddSpecialization<2,3,6>();
|
||||
MassIntegrator::AddSpecialization<2,4,6>();
|
||||
// 3D
|
||||
// Q=P+1
|
||||
MassIntegrator::AddSpecialization<3,1,1>();
|
||||
MassIntegrator::AddSpecialization<3,2,2>();
|
||||
MassIntegrator::AddSpecialization<3,3,3>();
|
||||
MassIntegrator::AddSpecialization<3,4,4>();
|
||||
MassIntegrator::AddSpecialization<3,5,5>();
|
||||
MassIntegrator::AddSpecialization<3,6,6>();
|
||||
MassIntegrator::AddSpecialization<3,7,7>();
|
||||
MassIntegrator::AddSpecialization<3,8,8>();
|
||||
MassIntegrator::AddSpecialization<3,9,9>();
|
||||
// Q=P+2
|
||||
MassIntegrator::AddSpecialization<3,1,2>();
|
||||
MassIntegrator::AddSpecialization<3,2,3>();
|
||||
MassIntegrator::AddSpecialization<3,3,4>();
|
||||
MassIntegrator::AddSpecialization<3,3,6>();
|
||||
MassIntegrator::AddSpecialization<3,4,5>();
|
||||
MassIntegrator::AddSpecialization<3,4,6>();
|
||||
MassIntegrator::AddSpecialization<3,5,6>();
|
||||
MassIntegrator::AddSpecialization<3,5,8>();
|
||||
MassIntegrator::AddSpecialization<3,6,7>();
|
||||
MassIntegrator::AddSpecialization<3,7,8>();
|
||||
MassIntegrator::AddSpecialization<3,8,9>();
|
||||
// others
|
||||
MassIntegrator::AddSpecialization<3,2,4>();
|
||||
MassIntegrator::AddSpecialization<3,4,6>();
|
||||
MassIntegrator::AddSpecialization<3,5,8>();
|
||||
}
|
||||
|
||||
namespace internal
|
||||
|
||||
@@ -1392,10 +1392,10 @@ using DiagonalKernelType = MassIntegrator::DiagonalKernelType;
|
||||
template<int DIM, int T_D1D, int T_Q1D>
|
||||
ApplyKernelType MassIntegrator::ApplyPAKernels::Kernel()
|
||||
{
|
||||
if (DIM == 1) { return internal::PAMassApply1D; }
|
||||
else if (DIM == 2) { return internal::SmemPAMassApply2D<T_D1D,T_Q1D>; }
|
||||
else if (DIM == 3) { return internal::SmemPAMassApply3D<T_D1D, T_Q1D>; }
|
||||
else { MFEM_ABORT(""); }
|
||||
if constexpr (DIM == 1) { return internal::PAMassApply1D; }
|
||||
else if constexpr (DIM == 2) { return internal::SmemPAMassApply2D<T_D1D,T_Q1D>; }
|
||||
else if constexpr (DIM == 3) { return internal::SmemPAMassApply3D<T_D1D, T_Q1D>; }
|
||||
MFEM_ABORT("");
|
||||
}
|
||||
|
||||
inline ApplyKernelType MassIntegrator::ApplyPAKernels::Fallback(
|
||||
@@ -1410,10 +1410,10 @@ inline ApplyKernelType MassIntegrator::ApplyPAKernels::Fallback(
|
||||
template<int DIM, int T_D1D, int T_Q1D>
|
||||
DiagonalKernelType MassIntegrator::DiagonalPAKernels::Kernel()
|
||||
{
|
||||
if (DIM == 1) { return internal::PAMassAssembleDiagonal1D; }
|
||||
else if (DIM == 2) { return internal::SmemPAMassAssembleDiagonal2D<T_D1D,T_Q1D>; }
|
||||
else if (DIM == 3) { return internal::SmemPAMassAssembleDiagonal3D<T_D1D, T_Q1D>; }
|
||||
else { MFEM_ABORT(""); }
|
||||
if constexpr (DIM == 1) { return internal::PAMassAssembleDiagonal1D; }
|
||||
else if constexpr (DIM == 2) { return internal::SmemPAMassAssembleDiagonal2D<T_D1D,T_Q1D>; }
|
||||
else if constexpr (DIM == 3) { return internal::SmemPAMassAssembleDiagonal3D<T_D1D, T_Q1D>; }
|
||||
MFEM_ABORT("");
|
||||
}
|
||||
|
||||
inline DiagonalKernelType MassIntegrator::DiagonalPAKernels::Fallback(
|
||||
|
||||
@@ -59,26 +59,23 @@ void MassIntegrator::AssemblePA(const FiniteElementSpace &fes)
|
||||
|
||||
QuadratureSpace qs(*mesh, *ir);
|
||||
CoefficientVector coeff(Q, qs, CoefficientStorage::COMPRESSED);
|
||||
|
||||
const int NE = ne;
|
||||
const int Q1D = quad1D;
|
||||
const int NQ = static_cast<int>(std::pow(Q1D, dim));
|
||||
const bool const_c = coeff.Size() == 1;
|
||||
const bool by_val = map_type == FiniteElement::VALUE;
|
||||
const auto W = Reshape(ir->GetWeights().Read(), NQ);
|
||||
const auto J = Reshape(geom->detJ.Read(), NQ, NE);
|
||||
const auto C = const_c ? Reshape(coeff.Read(), 1, 1) :
|
||||
Reshape(coeff.Read(), NQ,NE);
|
||||
auto v = Reshape(pa_data.Write(), NQ, NE);
|
||||
mfem::forall_2D(NE, NQ, 1, [=] MFEM_HOST_DEVICE (int e)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(i, x, NQ)
|
||||
const int NE = ne;
|
||||
const int NQ = nq;
|
||||
const bool const_c = coeff.Size() == 1;
|
||||
const bool by_val = map_type == FiniteElement::VALUE;
|
||||
const auto W = Reshape(ir->GetWeights().Read(), NQ);
|
||||
const auto J = Reshape(geom->detJ.Read(), NQ, NE);
|
||||
const auto C =
|
||||
const_c ? Reshape(coeff.Read(), 1, 1) : Reshape(coeff.Read(), NQ, NE);
|
||||
auto v = Reshape(pa_data.Write(), NQ, NE);
|
||||
mfem::forall(NQ, NE, [=] MFEM_HOST_DEVICE(int q, int e)
|
||||
{
|
||||
const real_t detJ = J(i,e);
|
||||
const real_t coeff = const_c ? C(0,0) : C(i,e);
|
||||
v(i,e) = W(i) * coeff * (by_val ? detJ : 1.0/detJ);
|
||||
}
|
||||
});
|
||||
const real_t detJ = J(q, e);
|
||||
const real_t coeff = const_c ? C(0, 0) : C(q, e);
|
||||
v(q, e) = W(q) * coeff * (by_val ? detJ : 1.0 / detJ);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void MassIntegrator::AssemblePABoundary(const FiniteElementSpace &fes)
|
||||
@@ -109,50 +106,22 @@ void MassIntegrator::AssemblePABoundary(const FiniteElementSpace &fes)
|
||||
CoefficientVector coeff(Q, qs, CoefficientStorage::COMPRESSED);
|
||||
|
||||
const int NE = ne;
|
||||
const int Q1D = quad1D;
|
||||
const int NQ = nq;
|
||||
const bool const_c = coeff.Size() == 1;
|
||||
const bool by_val = map_type == FiniteElement::VALUE;
|
||||
if (dim==1)
|
||||
{
|
||||
const auto W = Reshape(ir->GetWeights().Read(), Q1D);
|
||||
const auto J = Reshape(face_geom->detJ.Read(), Q1D, NE);
|
||||
const auto C = const_c ? Reshape(coeff.Read(), 1, 1) :
|
||||
Reshape(coeff.Read(), Q1D, NE);
|
||||
auto v = Reshape(pa_data.Write(), Q1D, NE);
|
||||
mfem::forall_2D(NE, Q1D, 1, [=] MFEM_HOST_DEVICE (int e)
|
||||
const auto W = Reshape(ir->GetWeights().Read(), NQ);
|
||||
const auto J = Reshape(face_geom->detJ.Read(), NQ, NE);
|
||||
const auto C = const_c ? Reshape(coeff.Read(), 1, 1)
|
||||
: Reshape(coeff.Read(), NQ, NE);
|
||||
auto v = Reshape(pa_data.Write(), NQ, NE);
|
||||
mfem::forall(NQ, NE, [=] MFEM_HOST_DEVICE(int q, int e)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qx,x,Q1D)
|
||||
{
|
||||
const real_t detJ = J(qx,e);
|
||||
const real_t coeff = const_c ? C(0,0) : C(qx,e);
|
||||
v(qx,e) = W(qx) * coeff * (by_val ? detJ : 1.0/detJ);
|
||||
}
|
||||
const real_t detJ = J(q, e);
|
||||
const real_t coeff = const_c ? C(0, 0) : C(q, e);
|
||||
v(q, e) = W(q) * coeff * (by_val ? detJ : 1.0 / detJ);
|
||||
});
|
||||
}
|
||||
else if (dim==2)
|
||||
{
|
||||
const auto W = Reshape(ir->GetWeights().Read(), Q1D,Q1D);
|
||||
const auto J = Reshape(face_geom->detJ.Read(), Q1D,Q1D,NE);
|
||||
const auto C = const_c ? Reshape(coeff.Read(), 1,1,1) :
|
||||
Reshape(coeff.Read(), Q1D,Q1D,NE);
|
||||
auto v = Reshape(pa_data.Write(), Q1D,Q1D, NE);
|
||||
mfem::forall_2D(NE, Q1D, Q1D, [=] MFEM_HOST_DEVICE (int e)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qx,x,Q1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qy,y,Q1D)
|
||||
{
|
||||
const real_t detJ = J(qx,qy,e);
|
||||
const real_t coeff = const_c ? C(0,0,0) : C(qx,qy,e);
|
||||
v(qx,qy,e) = W(qx,qy) * coeff * (by_val ? detJ : 1.0/detJ);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
MFEM_ABORT("Not supported.");
|
||||
}
|
||||
}
|
||||
|
||||
void MassIntegrator::AssembleDiagonalPA(Vector &diag)
|
||||
|
||||
@@ -0,0 +1,355 @@
|
||||
// Copyright (c) 2010-2025, 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_BILININTEG_VECDIFFUSION_KERNELS_HPP
|
||||
#define MFEM_BILININTEG_VECDIFFUSION_KERNELS_HPP
|
||||
|
||||
#include "../../general/forall.hpp"
|
||||
#include "../bilininteg.hpp"
|
||||
#include "../ceed/integrators/diffusion/diffusion.hpp"
|
||||
#include "../gridfunc.hpp"
|
||||
#include "../qfunction.hpp"
|
||||
/// \cond DO_NOT_DOCUMENT
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
namespace internal
|
||||
{
|
||||
|
||||
// PA Diffusion Apply 2D kernel
|
||||
template <int T_D1D = 0, int T_Q1D = 0, int T_VDIM = 0>
|
||||
static void
|
||||
PAVectorDiffusionApply2D(const int NE, const Array<real_t> &b,
|
||||
const Array<real_t> &g, const Array<real_t> &bt,
|
||||
const Array<real_t> >, const Vector &d_,
|
||||
const Vector &x_, Vector &y_, const int d1d = 0,
|
||||
const int q1d = 0, const int vdim = 0)
|
||||
{
|
||||
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 <= 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);
|
||||
auto Gt = Reshape(gt.Read(), D1D, Q1D);
|
||||
auto D = Reshape(d_.Read(), Q1D * Q1D, 3, NE);
|
||||
auto x = Reshape(x_.Read(), D1D, D1D, VDIM, NE);
|
||||
auto y = Reshape(y_.ReadWrite(), D1D, D1D, VDIM, NE);
|
||||
mfem::forall(NE, [=] MFEM_HOST_DEVICE(int e)
|
||||
{
|
||||
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 : DofQuadLimits::MAX_D1D;
|
||||
constexpr int max_Q1D = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
|
||||
|
||||
real_t grad[max_Q1D][max_Q1D][2];
|
||||
for (int c = 0; c < VDIM; c++)
|
||||
{
|
||||
for (int qy = 0; qy < Q1D; ++qy)
|
||||
{
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
grad[qy][qx][0] = 0.0;
|
||||
grad[qy][qx][1] = 0.0;
|
||||
}
|
||||
}
|
||||
for (int dy = 0; dy < D1D; ++dy)
|
||||
{
|
||||
real_t gradX[max_Q1D][2];
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
gradX[qx][0] = 0.0;
|
||||
gradX[qx][1] = 0.0;
|
||||
}
|
||||
for (int dx = 0; dx < D1D; ++dx)
|
||||
{
|
||||
const real_t s = x(dx, dy, c, e);
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
gradX[qx][0] += s * B(qx, dx);
|
||||
gradX[qx][1] += s * G(qx, dx);
|
||||
}
|
||||
}
|
||||
for (int qy = 0; qy < Q1D; ++qy)
|
||||
{
|
||||
const real_t wy = B(qy, dy);
|
||||
const real_t wDy = G(qy, dy);
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
grad[qy][qx][0] += gradX[qx][1] * wy;
|
||||
grad[qy][qx][1] += gradX[qx][0] * wDy;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Calculate Dxy, xDy in plane
|
||||
for (int qy = 0; qy < Q1D; ++qy)
|
||||
{
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
const int q = qx + qy * Q1D;
|
||||
const real_t O11 = D(q, 0, e);
|
||||
const real_t O12 = D(q, 1, e);
|
||||
const real_t O22 = D(q, 2, e);
|
||||
const real_t gradX = grad[qy][qx][0];
|
||||
const real_t gradY = grad[qy][qx][1];
|
||||
grad[qy][qx][0] = (O11 * gradX) + (O12 * gradY);
|
||||
grad[qy][qx][1] = (O12 * gradX) + (O22 * gradY);
|
||||
}
|
||||
}
|
||||
for (int qy = 0; qy < Q1D; ++qy)
|
||||
{
|
||||
real_t gradX[max_D1D][2];
|
||||
for (int dx = 0; dx < D1D; ++dx)
|
||||
{
|
||||
gradX[dx][0] = 0.0;
|
||||
gradX[dx][1] = 0.0;
|
||||
}
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
const real_t gX = grad[qy][qx][0];
|
||||
const real_t gY = grad[qy][qx][1];
|
||||
for (int dx = 0; dx < D1D; ++dx)
|
||||
{
|
||||
const real_t wx = Bt(dx, qx);
|
||||
const real_t wDx = Gt(dx, qx);
|
||||
gradX[dx][0] += gX * wDx;
|
||||
gradX[dx][1] += gY * wx;
|
||||
}
|
||||
}
|
||||
for (int dy = 0; dy < D1D; ++dy)
|
||||
{
|
||||
const real_t wy = Bt(dy, qy);
|
||||
const real_t wDy = Gt(dy, qy);
|
||||
for (int dx = 0; dx < D1D; ++dx)
|
||||
{
|
||||
y(dx, dy, c, e) +=
|
||||
((gradX[dx][0] * wy) + (gradX[dx][1] * wDy));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// PA Diffusion Apply 3D kernel
|
||||
template <const int T_D1D = 0, const int T_Q1D = 0>
|
||||
static void
|
||||
PAVectorDiffusionApply3D(const int NE, const Array<real_t> &b,
|
||||
const Array<real_t> &g, const Array<real_t> &bt,
|
||||
const Array<real_t> >, const Vector &op_,
|
||||
const Vector &x_, Vector &y_, const int d1d = 0,
|
||||
const int q1d = 0, const int sdim = 0)
|
||||
{
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
constexpr int VDIM = 3;
|
||||
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);
|
||||
auto Gt = Reshape(gt.Read(), D1D, Q1D);
|
||||
auto op = Reshape(op_.Read(), Q1D * Q1D * Q1D, 6, NE);
|
||||
auto x = Reshape(x_.Read(), D1D, D1D, D1D, VDIM, NE);
|
||||
auto y = Reshape(y_.ReadWrite(), D1D, D1D, D1D, VDIM, NE);
|
||||
mfem::forall(NE, [=] MFEM_HOST_DEVICE(int e)
|
||||
{
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : 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)
|
||||
{
|
||||
real_t grad[max_Q1D][max_Q1D][max_Q1D][3];
|
||||
for (int qz = 0; qz < Q1D; ++qz)
|
||||
{
|
||||
for (int qy = 0; qy < Q1D; ++qy)
|
||||
{
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
grad[qz][qy][qx][0] = 0.0;
|
||||
grad[qz][qy][qx][1] = 0.0;
|
||||
grad[qz][qy][qx][2] = 0.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int dz = 0; dz < D1D; ++dz)
|
||||
{
|
||||
real_t gradXY[max_Q1D][max_Q1D][3];
|
||||
for (int qy = 0; qy < Q1D; ++qy)
|
||||
{
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
gradXY[qy][qx][0] = 0.0;
|
||||
gradXY[qy][qx][1] = 0.0;
|
||||
gradXY[qy][qx][2] = 0.0;
|
||||
}
|
||||
}
|
||||
for (int dy = 0; dy < D1D; ++dy)
|
||||
{
|
||||
real_t gradX[max_Q1D][2];
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
gradX[qx][0] = 0.0;
|
||||
gradX[qx][1] = 0.0;
|
||||
}
|
||||
for (int dx = 0; dx < D1D; ++dx)
|
||||
{
|
||||
const real_t s = x(dx, dy, dz, c, e);
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
gradX[qx][0] += s * B(qx, dx);
|
||||
gradX[qx][1] += s * G(qx, dx);
|
||||
}
|
||||
}
|
||||
for (int qy = 0; qy < Q1D; ++qy)
|
||||
{
|
||||
const real_t wy = B(qy, dy);
|
||||
const real_t wDy = G(qy, dy);
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
const real_t wx = gradX[qx][0];
|
||||
const real_t wDx = gradX[qx][1];
|
||||
gradXY[qy][qx][0] += wDx * wy;
|
||||
gradXY[qy][qx][1] += wx * wDy;
|
||||
gradXY[qy][qx][2] += wx * wy;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int qz = 0; qz < Q1D; ++qz)
|
||||
{
|
||||
const real_t wz = B(qz, dz);
|
||||
const real_t wDz = G(qz, dz);
|
||||
for (int qy = 0; qy < Q1D; ++qy)
|
||||
{
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
grad[qz][qy][qx][0] += gradXY[qy][qx][0] * wz;
|
||||
grad[qz][qy][qx][1] += gradXY[qy][qx][1] * wz;
|
||||
grad[qz][qy][qx][2] += gradXY[qy][qx][2] * wDz;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Calculate Dxyz, xDyz, xyDz in plane
|
||||
for (int qz = 0; qz < Q1D; ++qz)
|
||||
{
|
||||
for (int qy = 0; qy < Q1D; ++qy)
|
||||
{
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
const int q = qx + (qy + qz * Q1D) * Q1D;
|
||||
const real_t O11 = op(q, 0, e);
|
||||
const real_t O12 = op(q, 1, e);
|
||||
const real_t O13 = op(q, 2, e);
|
||||
const real_t O22 = op(q, 3, e);
|
||||
const real_t O23 = op(q, 4, e);
|
||||
const real_t O33 = op(q, 5, e);
|
||||
const real_t gradX = grad[qz][qy][qx][0];
|
||||
const real_t gradY = grad[qz][qy][qx][1];
|
||||
const real_t gradZ = grad[qz][qy][qx][2];
|
||||
grad[qz][qy][qx][0] =
|
||||
(O11 * gradX) + (O12 * gradY) + (O13 * gradZ);
|
||||
grad[qz][qy][qx][1] =
|
||||
(O12 * gradX) + (O22 * gradY) + (O23 * gradZ);
|
||||
grad[qz][qy][qx][2] =
|
||||
(O13 * gradX) + (O23 * gradY) + (O33 * gradZ);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int qz = 0; qz < Q1D; ++qz)
|
||||
{
|
||||
real_t gradXY[max_D1D][max_D1D][3];
|
||||
for (int dy = 0; dy < D1D; ++dy)
|
||||
{
|
||||
for (int dx = 0; dx < D1D; ++dx)
|
||||
{
|
||||
gradXY[dy][dx][0] = 0;
|
||||
gradXY[dy][dx][1] = 0;
|
||||
gradXY[dy][dx][2] = 0;
|
||||
}
|
||||
}
|
||||
for (int qy = 0; qy < Q1D; ++qy)
|
||||
{
|
||||
real_t gradX[max_D1D][3];
|
||||
for (int dx = 0; dx < D1D; ++dx)
|
||||
{
|
||||
gradX[dx][0] = 0;
|
||||
gradX[dx][1] = 0;
|
||||
gradX[dx][2] = 0;
|
||||
}
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
const real_t gX = grad[qz][qy][qx][0];
|
||||
const real_t gY = grad[qz][qy][qx][1];
|
||||
const real_t gZ = grad[qz][qy][qx][2];
|
||||
for (int dx = 0; dx < D1D; ++dx)
|
||||
{
|
||||
const real_t wx = Bt(dx, qx);
|
||||
const real_t wDx = Gt(dx, qx);
|
||||
gradX[dx][0] += gX * wDx;
|
||||
gradX[dx][1] += gY * wx;
|
||||
gradX[dx][2] += gZ * wx;
|
||||
}
|
||||
}
|
||||
for (int dy = 0; dy < D1D; ++dy)
|
||||
{
|
||||
const real_t wy = Bt(dy, qy);
|
||||
const real_t wDy = Gt(dy, qy);
|
||||
for (int dx = 0; dx < D1D; ++dx)
|
||||
{
|
||||
gradXY[dy][dx][0] += gradX[dx][0] * wy;
|
||||
gradXY[dy][dx][1] += gradX[dx][1] * wDy;
|
||||
gradXY[dy][dx][2] += gradX[dx][2] * wy;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int dz = 0; dz < D1D; ++dz)
|
||||
{
|
||||
const real_t wz = Bt(dz, qz);
|
||||
const real_t wDz = Gt(dz, qz);
|
||||
for (int dy = 0; dy < D1D; ++dy)
|
||||
{
|
||||
for (int dx = 0; dx < D1D; ++dx)
|
||||
{
|
||||
y(dx, dy, dz, c, e) +=
|
||||
((gradXY[dy][dx][0] * wz) + (gradXY[dy][dx][1] * wz) +
|
||||
(gradXY[dy][dx][2] * wDz));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
} // namespace internal
|
||||
|
||||
template <int DIM, int VDIM, int T_D1D, int T_Q1D>
|
||||
VectorDiffusionIntegrator::ApplyKernelType
|
||||
VectorDiffusionIntegrator::ApplyPAKernels::Kernel()
|
||||
{
|
||||
if constexpr (DIM == 2)
|
||||
{
|
||||
return internal::PAVectorDiffusionApply2D<T_D1D, T_Q1D, VDIM>;
|
||||
}
|
||||
else if constexpr (DIM == 3)
|
||||
{
|
||||
return internal::PAVectorDiffusionApply3D;
|
||||
}
|
||||
MFEM_ABORT("");
|
||||
}
|
||||
|
||||
} // namespace mfem
|
||||
/// \endcond DO_NOT_DOCUMENT
|
||||
#endif
|
||||
@@ -15,9 +15,58 @@
|
||||
#include "../qfunction.hpp"
|
||||
#include "../ceed/integrators/diffusion/diffusion.hpp"
|
||||
|
||||
#include "bilininteg_vecdiffusion_kernels.hpp"
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
VectorDiffusionIntegrator::VectorDiffusionIntegrator(const IntegrationRule *ir)
|
||||
: BilinearFormIntegrator(ir)
|
||||
{
|
||||
static Kernels kernels;
|
||||
}
|
||||
|
||||
VectorDiffusionIntegrator::VectorDiffusionIntegrator(Coefficient &q)
|
||||
: VectorDiffusionIntegrator()
|
||||
{
|
||||
Q = &q;
|
||||
}
|
||||
|
||||
VectorDiffusionIntegrator::VectorDiffusionIntegrator(int vector_dimension)
|
||||
: VectorDiffusionIntegrator()
|
||||
{
|
||||
vdim = vector_dimension;
|
||||
}
|
||||
|
||||
VectorDiffusionIntegrator::VectorDiffusionIntegrator(Coefficient &q,
|
||||
const IntegrationRule *ir)
|
||||
: VectorDiffusionIntegrator(ir)
|
||||
{
|
||||
Q = &q;
|
||||
}
|
||||
|
||||
VectorDiffusionIntegrator::VectorDiffusionIntegrator(Coefficient &q,
|
||||
int vector_dimension)
|
||||
: VectorDiffusionIntegrator()
|
||||
{
|
||||
Q = &q;
|
||||
vdim = vector_dimension;
|
||||
}
|
||||
|
||||
VectorDiffusionIntegrator::VectorDiffusionIntegrator(VectorCoefficient &vq)
|
||||
: VectorDiffusionIntegrator()
|
||||
{
|
||||
VQ = &vq;
|
||||
vdim = vq.GetVDim();
|
||||
}
|
||||
|
||||
VectorDiffusionIntegrator::VectorDiffusionIntegrator(MatrixCoefficient &mq)
|
||||
: VectorDiffusionIntegrator()
|
||||
{
|
||||
MQ = &mq;
|
||||
vdim = mq.GetVDim();
|
||||
}
|
||||
|
||||
// PA Diffusion Assemble 2D kernel
|
||||
static void PAVectorDiffusionSetup2D(const int Q1D,
|
||||
const int NE,
|
||||
@@ -425,322 +474,6 @@ void VectorDiffusionIntegrator::AssembleDiagonalPA(Vector &diag)
|
||||
}
|
||||
}
|
||||
|
||||
// PA Diffusion Apply 2D kernel
|
||||
template<int T_D1D = 0, int T_Q1D = 0, int T_VDIM = 0> static
|
||||
void PAVectorDiffusionApply2D(const int NE,
|
||||
const Array<real_t> &b,
|
||||
const Array<real_t> &g,
|
||||
const Array<real_t> &bt,
|
||||
const Array<real_t> >,
|
||||
const Vector &d_,
|
||||
const Vector &x_,
|
||||
Vector &y_,
|
||||
const int d1d = 0,
|
||||
const int q1d = 0,
|
||||
const int vdim = 0)
|
||||
{
|
||||
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 <= 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);
|
||||
auto Gt = Reshape(gt.Read(), D1D, Q1D);
|
||||
auto D = Reshape(d_.Read(), Q1D*Q1D, 3, NE);
|
||||
auto x = Reshape(x_.Read(), D1D, D1D, VDIM, NE);
|
||||
auto y = Reshape(y_.ReadWrite(), D1D, D1D, VDIM, NE);
|
||||
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
|
||||
{
|
||||
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 : DofQuadLimits::MAX_D1D;
|
||||
constexpr int max_Q1D = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
|
||||
|
||||
real_t grad[max_Q1D][max_Q1D][2];
|
||||
for (int c = 0; c < VDIM; c++)
|
||||
{
|
||||
for (int qy = 0; qy < Q1D; ++qy)
|
||||
{
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
grad[qy][qx][0] = 0.0;
|
||||
grad[qy][qx][1] = 0.0;
|
||||
}
|
||||
}
|
||||
for (int dy = 0; dy < D1D; ++dy)
|
||||
{
|
||||
real_t gradX[max_Q1D][2];
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
gradX[qx][0] = 0.0;
|
||||
gradX[qx][1] = 0.0;
|
||||
}
|
||||
for (int dx = 0; dx < D1D; ++dx)
|
||||
{
|
||||
const real_t s = x(dx,dy,c,e);
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
gradX[qx][0] += s * B(qx,dx);
|
||||
gradX[qx][1] += s * G(qx,dx);
|
||||
}
|
||||
}
|
||||
for (int qy = 0; qy < Q1D; ++qy)
|
||||
{
|
||||
const real_t wy = B(qy,dy);
|
||||
const real_t wDy = G(qy,dy);
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
grad[qy][qx][0] += gradX[qx][1] * wy;
|
||||
grad[qy][qx][1] += gradX[qx][0] * wDy;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Calculate Dxy, xDy in plane
|
||||
for (int qy = 0; qy < Q1D; ++qy)
|
||||
{
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
const int q = qx + qy * Q1D;
|
||||
const real_t O11 = D(q,0,e);
|
||||
const real_t O12 = D(q,1,e);
|
||||
const real_t O22 = D(q,2,e);
|
||||
const real_t gradX = grad[qy][qx][0];
|
||||
const real_t gradY = grad[qy][qx][1];
|
||||
grad[qy][qx][0] = (O11 * gradX) + (O12 * gradY);
|
||||
grad[qy][qx][1] = (O12 * gradX) + (O22 * gradY);
|
||||
}
|
||||
}
|
||||
for (int qy = 0; qy < Q1D; ++qy)
|
||||
{
|
||||
real_t gradX[max_D1D][2];
|
||||
for (int dx = 0; dx < D1D; ++dx)
|
||||
{
|
||||
gradX[dx][0] = 0.0;
|
||||
gradX[dx][1] = 0.0;
|
||||
}
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
const real_t gX = grad[qy][qx][0];
|
||||
const real_t gY = grad[qy][qx][1];
|
||||
for (int dx = 0; dx < D1D; ++dx)
|
||||
{
|
||||
const real_t wx = Bt(dx,qx);
|
||||
const real_t wDx = Gt(dx,qx);
|
||||
gradX[dx][0] += gX * wDx;
|
||||
gradX[dx][1] += gY * wx;
|
||||
}
|
||||
}
|
||||
for (int dy = 0; dy < D1D; ++dy)
|
||||
{
|
||||
const real_t wy = Bt(dy,qy);
|
||||
const real_t wDy = Gt(dy,qy);
|
||||
for (int dx = 0; dx < D1D; ++dx)
|
||||
{
|
||||
y(dx,dy,c,e) += ((gradX[dx][0] * wy) + (gradX[dx][1] * wDy));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// PA Diffusion Apply 3D kernel
|
||||
template<const int T_D1D = 0,
|
||||
const int T_Q1D = 0> static
|
||||
void PAVectorDiffusionApply3D(const int NE,
|
||||
const Array<real_t> &b,
|
||||
const Array<real_t> &g,
|
||||
const Array<real_t> &bt,
|
||||
const Array<real_t> >,
|
||||
const Vector &op_,
|
||||
const Vector &x_,
|
||||
Vector &y_,
|
||||
int d1d = 0, int q1d = 0)
|
||||
{
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
constexpr int VDIM = 3;
|
||||
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);
|
||||
auto Gt = Reshape(gt.Read(), D1D, Q1D);
|
||||
auto op = Reshape(op_.Read(), Q1D*Q1D*Q1D, 6, NE);
|
||||
auto x = Reshape(x_.Read(), D1D, D1D, D1D, VDIM, NE);
|
||||
auto y = Reshape(y_.ReadWrite(), D1D, D1D, D1D, VDIM, NE);
|
||||
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
|
||||
{
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : 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)
|
||||
{
|
||||
real_t grad[max_Q1D][max_Q1D][max_Q1D][3];
|
||||
for (int qz = 0; qz < Q1D; ++qz)
|
||||
{
|
||||
for (int qy = 0; qy < Q1D; ++qy)
|
||||
{
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
grad[qz][qy][qx][0] = 0.0;
|
||||
grad[qz][qy][qx][1] = 0.0;
|
||||
grad[qz][qy][qx][2] = 0.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int dz = 0; dz < D1D; ++dz)
|
||||
{
|
||||
real_t gradXY[max_Q1D][max_Q1D][3];
|
||||
for (int qy = 0; qy < Q1D; ++qy)
|
||||
{
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
gradXY[qy][qx][0] = 0.0;
|
||||
gradXY[qy][qx][1] = 0.0;
|
||||
gradXY[qy][qx][2] = 0.0;
|
||||
}
|
||||
}
|
||||
for (int dy = 0; dy < D1D; ++dy)
|
||||
{
|
||||
real_t gradX[max_Q1D][2];
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
gradX[qx][0] = 0.0;
|
||||
gradX[qx][1] = 0.0;
|
||||
}
|
||||
for (int dx = 0; dx < D1D; ++dx)
|
||||
{
|
||||
const real_t s = x(dx,dy,dz,c,e);
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
gradX[qx][0] += s * B(qx,dx);
|
||||
gradX[qx][1] += s * G(qx,dx);
|
||||
}
|
||||
}
|
||||
for (int qy = 0; qy < Q1D; ++qy)
|
||||
{
|
||||
const real_t wy = B(qy,dy);
|
||||
const real_t wDy = G(qy,dy);
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
const real_t wx = gradX[qx][0];
|
||||
const real_t wDx = gradX[qx][1];
|
||||
gradXY[qy][qx][0] += wDx * wy;
|
||||
gradXY[qy][qx][1] += wx * wDy;
|
||||
gradXY[qy][qx][2] += wx * wy;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int qz = 0; qz < Q1D; ++qz)
|
||||
{
|
||||
const real_t wz = B(qz,dz);
|
||||
const real_t wDz = G(qz,dz);
|
||||
for (int qy = 0; qy < Q1D; ++qy)
|
||||
{
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
grad[qz][qy][qx][0] += gradXY[qy][qx][0] * wz;
|
||||
grad[qz][qy][qx][1] += gradXY[qy][qx][1] * wz;
|
||||
grad[qz][qy][qx][2] += gradXY[qy][qx][2] * wDz;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Calculate Dxyz, xDyz, xyDz in plane
|
||||
for (int qz = 0; qz < Q1D; ++qz)
|
||||
{
|
||||
for (int qy = 0; qy < Q1D; ++qy)
|
||||
{
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
const int q = qx + (qy + qz * Q1D) * Q1D;
|
||||
const real_t O11 = op(q,0,e);
|
||||
const real_t O12 = op(q,1,e);
|
||||
const real_t O13 = op(q,2,e);
|
||||
const real_t O22 = op(q,3,e);
|
||||
const real_t O23 = op(q,4,e);
|
||||
const real_t O33 = op(q,5,e);
|
||||
const real_t gradX = grad[qz][qy][qx][0];
|
||||
const real_t gradY = grad[qz][qy][qx][1];
|
||||
const real_t gradZ = grad[qz][qy][qx][2];
|
||||
grad[qz][qy][qx][0] = (O11*gradX)+(O12*gradY)+(O13*gradZ);
|
||||
grad[qz][qy][qx][1] = (O12*gradX)+(O22*gradY)+(O23*gradZ);
|
||||
grad[qz][qy][qx][2] = (O13*gradX)+(O23*gradY)+(O33*gradZ);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int qz = 0; qz < Q1D; ++qz)
|
||||
{
|
||||
real_t gradXY[max_D1D][max_D1D][3];
|
||||
for (int dy = 0; dy < D1D; ++dy)
|
||||
{
|
||||
for (int dx = 0; dx < D1D; ++dx)
|
||||
{
|
||||
gradXY[dy][dx][0] = 0;
|
||||
gradXY[dy][dx][1] = 0;
|
||||
gradXY[dy][dx][2] = 0;
|
||||
}
|
||||
}
|
||||
for (int qy = 0; qy < Q1D; ++qy)
|
||||
{
|
||||
real_t gradX[max_D1D][3];
|
||||
for (int dx = 0; dx < D1D; ++dx)
|
||||
{
|
||||
gradX[dx][0] = 0;
|
||||
gradX[dx][1] = 0;
|
||||
gradX[dx][2] = 0;
|
||||
}
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
const real_t gX = grad[qz][qy][qx][0];
|
||||
const real_t gY = grad[qz][qy][qx][1];
|
||||
const real_t gZ = grad[qz][qy][qx][2];
|
||||
for (int dx = 0; dx < D1D; ++dx)
|
||||
{
|
||||
const real_t wx = Bt(dx,qx);
|
||||
const real_t wDx = Gt(dx,qx);
|
||||
gradX[dx][0] += gX * wDx;
|
||||
gradX[dx][1] += gY * wx;
|
||||
gradX[dx][2] += gZ * wx;
|
||||
}
|
||||
}
|
||||
for (int dy = 0; dy < D1D; ++dy)
|
||||
{
|
||||
const real_t wy = Bt(dy,qy);
|
||||
const real_t wDy = Gt(dy,qy);
|
||||
for (int dx = 0; dx < D1D; ++dx)
|
||||
{
|
||||
gradXY[dy][dx][0] += gradX[dx][0] * wy;
|
||||
gradXY[dy][dx][1] += gradX[dx][1] * wDy;
|
||||
gradXY[dy][dx][2] += gradX[dx][2] * wy;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int dz = 0; dz < D1D; ++dz)
|
||||
{
|
||||
const real_t wz = Bt(dz,qz);
|
||||
const real_t wDz = Gt(dz,qz);
|
||||
for (int dy = 0; dy < D1D; ++dy)
|
||||
{
|
||||
for (int dx = 0; dx < D1D; ++dx)
|
||||
{
|
||||
y(dx,dy,dz,c,e) +=
|
||||
((gradXY[dy][dx][0] * wz) +
|
||||
(gradXY[dy][dx][1] * wz) +
|
||||
(gradXY[dy][dx][2] * wDz));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// PA Diffusion Apply kernel
|
||||
void VectorDiffusionIntegrator::AddMultPA(const Vector &x, Vector &y) const
|
||||
{
|
||||
@@ -757,27 +490,29 @@ void VectorDiffusionIntegrator::AddMultPA(const Vector &x, Vector &y) const
|
||||
const Array<real_t> &Bt = maps->Bt;
|
||||
const Array<real_t> &Gt = maps->Gt;
|
||||
const Vector &D = pa_data;
|
||||
|
||||
if (dim == 2 && sdim == 3)
|
||||
{
|
||||
switch ((dofs1D << 4 ) | quad1D)
|
||||
{
|
||||
case 0x22: return PAVectorDiffusionApply2D<2,2,3>(ne,B,G,Bt,Gt,D,x,y);
|
||||
case 0x33: return PAVectorDiffusionApply2D<3,3,3>(ne,B,G,Bt,Gt,D,x,y);
|
||||
case 0x44: return PAVectorDiffusionApply2D<4,4,3>(ne,B,G,Bt,Gt,D,x,y);
|
||||
case 0x55: return PAVectorDiffusionApply2D<5,5,3>(ne,B,G,Bt,Gt,D,x,y);
|
||||
default:
|
||||
return PAVectorDiffusionApply2D(ne,B,G,Bt,Gt,D,x,y,D1D,Q1D,sdim);
|
||||
}
|
||||
}
|
||||
if (dim == 2 && sdim == 2)
|
||||
{ return PAVectorDiffusionApply2D(ne,B,G,Bt,Gt,D,x,y,D1D,Q1D,sdim); }
|
||||
|
||||
if (dim == 3 && sdim == 3)
|
||||
{ return PAVectorDiffusionApply3D(ne,B,G,Bt,Gt,D,x,y,D1D,Q1D); }
|
||||
|
||||
MFEM_ABORT("Unknown kernel.");
|
||||
ApplyPAKernels::Run(dim, sdim, D1D, Q1D, ne, B, G, Bt, Gt, D, x, y, D1D,
|
||||
Q1D, sdim);
|
||||
}
|
||||
}
|
||||
|
||||
/// \cond DO_NOT_DOCUMENT
|
||||
|
||||
VectorDiffusionIntegrator::ApplyKernelType
|
||||
VectorDiffusionIntegrator::ApplyPAKernels::Fallback(int DIM, int, int, int)
|
||||
{
|
||||
if (DIM == 2) { return internal::PAVectorDiffusionApply2D; }
|
||||
else if (DIM == 3) { return internal::PAVectorDiffusionApply3D; }
|
||||
else { MFEM_ABORT(""); }
|
||||
}
|
||||
|
||||
VectorDiffusionIntegrator::Kernels::Kernels()
|
||||
{
|
||||
VectorDiffusionIntegrator::AddSpecialization<2, 3, 2, 2>();
|
||||
VectorDiffusionIntegrator::AddSpecialization<2, 3, 3, 3>();
|
||||
VectorDiffusionIntegrator::AddSpecialization<2, 3, 4, 4>();
|
||||
VectorDiffusionIntegrator::AddSpecialization<2, 3, 5, 5>();
|
||||
}
|
||||
|
||||
/// \endcond DO_NOT_DOCUMENT
|
||||
|
||||
} // namespace mfem
|
||||
|
||||
+55
-204
@@ -9,183 +9,19 @@
|
||||
// terms of the BSD-3 license. We welcome feedback and contributions, see file
|
||||
// CONTRIBUTING.md for details.
|
||||
|
||||
#include "../../general/forall.hpp"
|
||||
#include "../../fem/kernels.hpp"
|
||||
#include "../../general/forall.hpp"
|
||||
#include "../fem.hpp"
|
||||
|
||||
#include "lininteg_domain_kernels.hpp"
|
||||
|
||||
/// \cond DO_NOT_DOCUMENT
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
template<int T_D1D = 0, int T_Q1D = 0>
|
||||
static void DLFEvalAssemble2D(const int vdim, const int ne, const int d,
|
||||
const int q,
|
||||
const int map_type, const int *markers, const real_t *b,
|
||||
const real_t *detj, const real_t *weights,
|
||||
const Vector &coeff, real_t *y)
|
||||
{
|
||||
const auto F = coeff.Read();
|
||||
const auto M = Reshape(markers, ne);
|
||||
const auto B = Reshape(b, q, d);
|
||||
const auto DETJ = Reshape(detj, q, q, ne);
|
||||
const auto W = Reshape(weights, q, q);
|
||||
const bool cst = coeff.Size() == vdim;
|
||||
const auto C = cst ? Reshape(F,vdim,1,1,1) : Reshape(F,vdim,q,q,ne);
|
||||
auto Y = Reshape(y, d,d, vdim, ne);
|
||||
|
||||
mfem::forall_2D(ne, q, q, [=] MFEM_HOST_DEVICE (int e)
|
||||
{
|
||||
if (M(e) == 0) { return; } // ignore
|
||||
|
||||
constexpr int Q = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
|
||||
constexpr int D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
|
||||
|
||||
MFEM_SHARED real_t sBt[Q*D];
|
||||
MFEM_SHARED real_t sQQ[Q*Q];
|
||||
MFEM_SHARED real_t sQD[Q*D];
|
||||
|
||||
const DeviceMatrix Bt(sBt, d, q);
|
||||
kernels::internal::LoadB<D,Q>(d, q, B, sBt);
|
||||
|
||||
const DeviceMatrix QQ(sQQ, q, q);
|
||||
const DeviceMatrix QD(sQD, q, d);
|
||||
|
||||
for (int c = 0; c < vdim; ++c)
|
||||
{
|
||||
const real_t cst_val = C(c,0,0,0);
|
||||
MFEM_FOREACH_THREAD(x,x,q)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(y,y,q)
|
||||
{
|
||||
const real_t detJ = (map_type == FiniteElement::VALUE) ? DETJ(x,y,e) : 1.0;
|
||||
const real_t coeff_val = cst ? cst_val : C(c,x,y,e);
|
||||
QQ(y,x) = W(x,y) * coeff_val * detJ;
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
MFEM_FOREACH_THREAD(qy,y,q)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(dx,x,d)
|
||||
{
|
||||
real_t u = 0.0;
|
||||
for (int qx = 0; qx < q; ++qx) { u += QQ(qy,qx) * Bt(dx,qx); }
|
||||
QD(qy,dx) = u;
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
MFEM_FOREACH_THREAD(dy,y,d)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(dx,x,d)
|
||||
{
|
||||
real_t u = 0.0;
|
||||
for (int qy = 0; qy < q; ++qy) { u += QD(qy,dx) * Bt(dy,qy); }
|
||||
Y(dx,dy,c,e) += u;
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
template<int T_D1D = 0, int T_Q1D = 0>
|
||||
static void DLFEvalAssemble3D(const int vdim, const int ne, const int d,
|
||||
const int q,
|
||||
const int map_type, const int *markers, const real_t *b,
|
||||
const real_t *detj, const real_t *weights,
|
||||
const Vector &coeff, real_t *y)
|
||||
{
|
||||
const auto F = coeff.Read();
|
||||
const auto M = Reshape(markers, ne);
|
||||
const auto B = Reshape(b, q,d);
|
||||
const auto DETJ = Reshape(detj, q, q, q, ne);
|
||||
const auto W = Reshape(weights, q,q,q);
|
||||
const bool cst_coeff = coeff.Size() == vdim;
|
||||
const auto C = cst_coeff ? Reshape(F,vdim,1,1,1,1):Reshape(F,vdim,q,q,q,ne);
|
||||
|
||||
auto Y = Reshape(y, d,d,d, vdim, ne);
|
||||
|
||||
mfem::forall_2D(ne, q, q, [=] MFEM_HOST_DEVICE (int e)
|
||||
{
|
||||
if (M(e) == 0) { return; } // ignore
|
||||
|
||||
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;
|
||||
|
||||
real_t u[D];
|
||||
|
||||
MFEM_SHARED real_t sBt[Q*D];
|
||||
const DeviceMatrix Bt(sBt, d,q);
|
||||
kernels::internal::LoadB<D,Q>(d,q,B,sBt);
|
||||
|
||||
MFEM_SHARED real_t sQQQ[MQD*MQD*MQD];
|
||||
const DeviceCube QQQ(sQQQ, MQD, MQD, MQD);
|
||||
|
||||
for (int c = 0; c < vdim; ++c)
|
||||
{
|
||||
const real_t cst_val = C(c,0,0,0,0);
|
||||
MFEM_FOREACH_THREAD(x,x,q)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(y,y,q)
|
||||
{
|
||||
for (int z = 0; z < q; ++z)
|
||||
{
|
||||
const real_t detJ = (map_type == FiniteElement::VALUE) ? DETJ(x,y,z,e) : 1.0;
|
||||
const real_t coeff_val = cst_coeff ? cst_val : C(c,x,y,z,e);
|
||||
QQQ(z,y,x) = W(x,y,z) * coeff_val * detJ;
|
||||
}
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
MFEM_FOREACH_THREAD(qx,x,q)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qy,y,q)
|
||||
{
|
||||
for (int dz = 0; dz < d; ++dz) { u[dz] = 0.0; }
|
||||
for (int qz = 0; qz < q; ++qz)
|
||||
{
|
||||
const real_t ZYX = QQQ(qz,qy,qx);
|
||||
for (int dz = 0; dz < d; ++dz) { u[dz] += ZYX * Bt(dz,qz); }
|
||||
}
|
||||
for (int dz = 0; dz < d; ++dz) { QQQ(dz,qy,qx) = u[dz]; }
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
MFEM_FOREACH_THREAD(dz,y,d)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qx,x,q)
|
||||
{
|
||||
for (int dy = 0; dy < d; ++dy) { u[dy] = 0.0; }
|
||||
for (int qy = 0; qy < q; ++qy)
|
||||
{
|
||||
const real_t zYX = QQQ(dz,qy,qx);
|
||||
for (int dy = 0; dy < d; ++dy) { u[dy] += zYX * Bt(dy,qy); }
|
||||
}
|
||||
for (int dy = 0; dy < d; ++dy) { QQQ(dz,dy,qx) = u[dy]; }
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
MFEM_FOREACH_THREAD(dz,y,d)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(dy,x,d)
|
||||
{
|
||||
for (int dx = 0; dx < d; ++dx) { u[dx] = 0.0; }
|
||||
for (int qx = 0; qx < q; ++qx)
|
||||
{
|
||||
const real_t zyX = QQQ(dz,dy,qx);
|
||||
for (int dx = 0; dx < d; ++dx) { u[dx] += zyX * Bt(dx,qx); }
|
||||
}
|
||||
for (int dx = 0; dx < d; ++dx) { Y(dx,dy,dz,c,e) += u[dx]; }
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
static void DLFEvalAssemble(const FiniteElementSpace &fes,
|
||||
const IntegrationRule *ir,
|
||||
const Array<int> &markers,
|
||||
const Vector &coeff,
|
||||
const Array<int> &markers, const Vector &coeff,
|
||||
Vector &y)
|
||||
{
|
||||
Mesh *mesh = fes.GetMesh();
|
||||
@@ -197,50 +33,20 @@ static void DLFEvalAssemble(const FiniteElementSpace &fes,
|
||||
constexpr int flags = GeometricFactors::DETERMINANTS;
|
||||
const GeometricFactors *geom = mesh->GetGeometricFactors(*ir, flags, mt);
|
||||
const int map_type = fes.GetTypicalFE()->GetMapType();
|
||||
decltype(&DLFEvalAssemble2D<>) ker =
|
||||
dim == 2 ? DLFEvalAssemble2D<> : DLFEvalAssemble3D<>;
|
||||
|
||||
if (dim==2)
|
||||
{
|
||||
if (d==1 && q==1) { ker=DLFEvalAssemble2D<1,1>; }
|
||||
if (d==2 && q==2) { ker=DLFEvalAssemble2D<2,2>; }
|
||||
if (d==3 && q==3) { ker=DLFEvalAssemble2D<3,3>; }
|
||||
if (d==4 && q==4) { ker=DLFEvalAssemble2D<4,4>; }
|
||||
if (d==5 && q==5) { ker=DLFEvalAssemble2D<5,5>; }
|
||||
if (d==2 && q==3) { ker=DLFEvalAssemble2D<2,3>; }
|
||||
if (d==3 && q==4) { ker=DLFEvalAssemble2D<3,4>; }
|
||||
if (d==4 && q==5) { ker=DLFEvalAssemble2D<4,5>; }
|
||||
if (d==5 && q==6) { ker=DLFEvalAssemble2D<5,6>; }
|
||||
}
|
||||
|
||||
if (dim==3)
|
||||
{
|
||||
if (d==1 && q==1) { ker=DLFEvalAssemble3D<1,1>; }
|
||||
if (d==2 && q==2) { ker=DLFEvalAssemble3D<2,2>; }
|
||||
if (d==3 && q==3) { ker=DLFEvalAssemble3D<3,3>; }
|
||||
if (d==4 && q==4) { ker=DLFEvalAssemble3D<4,4>; }
|
||||
if (d==5 && q==5) { ker=DLFEvalAssemble3D<5,5>; }
|
||||
if (d==2 && q==3) { ker=DLFEvalAssemble3D<2,3>; }
|
||||
if (d==3 && q==4) { ker=DLFEvalAssemble3D<3,4>; }
|
||||
if (d==4 && q==5) { ker=DLFEvalAssemble3D<4,5>; }
|
||||
if (d==5 && q==6) { ker=DLFEvalAssemble3D<5,6>; }
|
||||
}
|
||||
|
||||
MFEM_VERIFY(ker, "No kernel ndof " << d << " nqpt " << q);
|
||||
|
||||
const int vdim = fes.GetVDim();
|
||||
const int ne = fes.GetMesh()->GetNE();
|
||||
const int *M = markers.Read();
|
||||
const real_t *B = maps.B.Read();
|
||||
const int *M = markers.Read();
|
||||
const real_t *detJ = geom->detJ.Read();
|
||||
const real_t *W = ir->GetWeights().Read();
|
||||
real_t *Y = y.ReadWrite();
|
||||
ker(vdim, ne, d, q, map_type, M, B, detJ, W, coeff, Y);
|
||||
DomainLFIntegrator::AssembleKernels::Run(dim, d, q, vdim, ne, d, q, map_type,
|
||||
M, B, detJ, W, coeff, Y);
|
||||
}
|
||||
|
||||
void DomainLFIntegrator::AssembleDevice(const FiniteElementSpace &fes,
|
||||
const Array<int> &markers,
|
||||
Vector &b)
|
||||
const Array<int> &markers, Vector &b)
|
||||
{
|
||||
const FiniteElement &fe = *fes.GetTypicalFE();
|
||||
const int qorder = oa * fe.GetOrder() + ob;
|
||||
@@ -266,4 +72,49 @@ void VectorDomainLFIntegrator::AssembleDevice(const FiniteElementSpace &fes,
|
||||
DLFEvalAssemble(fes, ir, markers, coeff, b);
|
||||
}
|
||||
|
||||
DomainLFIntegrator::AssembleKernelType
|
||||
DomainLFIntegrator::AssembleKernels::Fallback(int DIM, int, int)
|
||||
{
|
||||
switch (DIM)
|
||||
{
|
||||
case 1:
|
||||
return DLFEvalAssemble1D<0, 0>;
|
||||
case 2:
|
||||
return DLFEvalAssemble2D<0, 0>;
|
||||
case 3:
|
||||
return DLFEvalAssemble3D<0, 0>;
|
||||
}
|
||||
MFEM_ABORT("");
|
||||
}
|
||||
|
||||
DomainLFIntegrator::Kernels::Kernels()
|
||||
{
|
||||
// 2D
|
||||
// Q = P+1
|
||||
DomainLFIntegrator::AddSpecialization<2, 1, 1>();
|
||||
DomainLFIntegrator::AddSpecialization<2, 2, 2>();
|
||||
DomainLFIntegrator::AddSpecialization<2, 3, 3>();
|
||||
DomainLFIntegrator::AddSpecialization<2, 4, 4>();
|
||||
DomainLFIntegrator::AddSpecialization<2, 5, 5>();
|
||||
// Q = P+2
|
||||
DomainLFIntegrator::AddSpecialization<2, 2, 3>();
|
||||
DomainLFIntegrator::AddSpecialization<2, 3, 4>();
|
||||
DomainLFIntegrator::AddSpecialization<2, 4, 5>();
|
||||
DomainLFIntegrator::AddSpecialization<2, 5, 6>();
|
||||
// 3D
|
||||
// Q = P+1
|
||||
DomainLFIntegrator::AddSpecialization<3, 1, 1>();
|
||||
DomainLFIntegrator::AddSpecialization<3, 2, 2>();
|
||||
DomainLFIntegrator::AddSpecialization<3, 3, 3>();
|
||||
DomainLFIntegrator::AddSpecialization<3, 4, 4>();
|
||||
DomainLFIntegrator::AddSpecialization<3, 5, 5>();
|
||||
// Q = P+2
|
||||
DomainLFIntegrator::AddSpecialization<3, 2, 3>();
|
||||
DomainLFIntegrator::AddSpecialization<3, 3, 4>();
|
||||
DomainLFIntegrator::AddSpecialization<3, 4, 5>();
|
||||
DomainLFIntegrator::AddSpecialization<3, 5, 6>();
|
||||
}
|
||||
|
||||
/// \endcond DO_NOT_DOCUMENT
|
||||
|
||||
} // namespace mfem
|
||||
|
||||
@@ -0,0 +1,318 @@
|
||||
// Copyright (c) 2010-2025, 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_LININTEG_DOMAIN_KERNELS_HPP
|
||||
#define MFEM_LININTEG_DOMAIN_KERNELS_HPP
|
||||
|
||||
#include "../../fem/kernels.hpp"
|
||||
#include "../../general/forall.hpp"
|
||||
#include "../fem.hpp"
|
||||
|
||||
/// \cond DO_NOT_DOCUMENT
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
template <int T_D1D = 0, int T_Q1D = 0>
|
||||
static void DLFEvalAssemble1D(const int vdim, const int ne, const int d,
|
||||
const int q, const int map_type,
|
||||
const int *markers, const real_t *b,
|
||||
const real_t *detj, const real_t *weights,
|
||||
const Vector &coeff, real_t *y)
|
||||
{
|
||||
{
|
||||
constexpr int Q = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
|
||||
constexpr int D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
|
||||
MFEM_VERIFY(q <= Q, "");
|
||||
MFEM_VERIFY(d <= D, "");
|
||||
}
|
||||
|
||||
const auto F = coeff.Read();
|
||||
const auto B = Reshape(b, q, d);
|
||||
const auto DETJ = Reshape(detj, q, ne);
|
||||
const bool cst = coeff.Size() == vdim;
|
||||
const auto C = cst ? Reshape(F, vdim, 1, 1) : Reshape(F, vdim, q, ne);
|
||||
auto Y = Reshape(y, d, vdim, ne);
|
||||
|
||||
mfem::forall_2D(ne, d, 1, [=] MFEM_HOST_DEVICE(int e)
|
||||
{
|
||||
if (markers[e] == 0)
|
||||
{
|
||||
return;
|
||||
} // ignore
|
||||
|
||||
constexpr int Q = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
|
||||
constexpr int D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
|
||||
|
||||
MFEM_SHARED real_t sBt[Q * D];
|
||||
const DeviceMatrix Bt(sBt, d, q);
|
||||
kernels::internal::LoadB<D, Q>(d, q, B, sBt);
|
||||
|
||||
for (int c = 0; c < vdim; ++c)
|
||||
{
|
||||
const real_t cst_val = C(c, 0, 0);
|
||||
MFEM_FOREACH_THREAD(dx, x, d)
|
||||
{
|
||||
real_t u = 0;
|
||||
for (int qx = 0; qx < q; ++qx)
|
||||
{
|
||||
const real_t detJ =
|
||||
(map_type == FiniteElement::VALUE) ? DETJ(qx, e) : 1.0;
|
||||
const real_t coeff_val = cst ? cst_val : C(c, qx, e);
|
||||
u += weights[qx] * coeff_val * detJ * Bt(dx, qx);
|
||||
}
|
||||
Y(dx, c, e) += u;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
template <int T_D1D = 0, int T_Q1D = 0>
|
||||
static void DLFEvalAssemble2D(const int vdim, const int ne, const int d,
|
||||
const int q, const int map_type,
|
||||
const int *markers, const real_t *b,
|
||||
const real_t *detj, const real_t *weights,
|
||||
const Vector &coeff, real_t *y)
|
||||
{
|
||||
{
|
||||
constexpr int Q = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
|
||||
constexpr int D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
|
||||
MFEM_VERIFY(q <= Q, "");
|
||||
MFEM_VERIFY(d <= D, "");
|
||||
}
|
||||
|
||||
const auto F = coeff.Read();
|
||||
const auto B = Reshape(b, q, d);
|
||||
const auto DETJ = Reshape(detj, q, q, ne);
|
||||
const auto W = Reshape(weights, q, q);
|
||||
const bool cst = coeff.Size() == vdim;
|
||||
const auto C = cst ? Reshape(F, vdim, 1, 1, 1) : Reshape(F, vdim, q, q, ne);
|
||||
auto Y = Reshape(y, d, d, vdim, ne);
|
||||
|
||||
mfem::forall_2D(ne, q, q, [=] MFEM_HOST_DEVICE(int e)
|
||||
{
|
||||
if (markers[e] == 0)
|
||||
{
|
||||
return;
|
||||
} // ignore
|
||||
|
||||
constexpr int Q = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
|
||||
constexpr int D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
|
||||
|
||||
MFEM_SHARED real_t sBt[Q * D];
|
||||
MFEM_SHARED real_t sQQ[Q * Q];
|
||||
MFEM_SHARED real_t sQD[Q * D];
|
||||
|
||||
const DeviceMatrix Bt(sBt, d, q);
|
||||
kernels::internal::LoadB<D, Q>(d, q, B, sBt);
|
||||
|
||||
const DeviceMatrix QQ(sQQ, q, q);
|
||||
const DeviceMatrix QD(sQD, q, d);
|
||||
|
||||
for (int c = 0; c < vdim; ++c)
|
||||
{
|
||||
const real_t cst_val = C(c, 0, 0, 0);
|
||||
MFEM_FOREACH_THREAD(x, x, q)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(y, y, q)
|
||||
{
|
||||
const real_t detJ =
|
||||
(map_type == FiniteElement::VALUE) ? DETJ(x, y, e) : 1.0;
|
||||
const real_t coeff_val = cst ? cst_val : C(c, x, y, e);
|
||||
QQ(y, x) = W(x, y) * coeff_val * detJ;
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
MFEM_FOREACH_THREAD(qy, y, q)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(dx, x, d)
|
||||
{
|
||||
real_t u = 0.0;
|
||||
for (int qx = 0; qx < q; ++qx)
|
||||
{
|
||||
u += QQ(qy, qx) * Bt(dx, qx);
|
||||
}
|
||||
QD(qy, dx) = u;
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
MFEM_FOREACH_THREAD(dy, y, d)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(dx, x, d)
|
||||
{
|
||||
real_t u = 0.0;
|
||||
for (int qy = 0; qy < q; ++qy)
|
||||
{
|
||||
u += QD(qy, dx) * Bt(dy, qy);
|
||||
}
|
||||
Y(dx, dy, c, e) += u;
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
template <int T_D1D = 0, int T_Q1D = 0>
|
||||
static void DLFEvalAssemble3D(const int vdim, const int ne, const int d,
|
||||
const int q, const int map_type,
|
||||
const int* markers, const real_t *b,
|
||||
const real_t *detj, const real_t *weights,
|
||||
const Vector &coeff, real_t *y)
|
||||
{
|
||||
{
|
||||
constexpr int Q = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
|
||||
constexpr int D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
|
||||
MFEM_VERIFY(q <= Q, "");
|
||||
MFEM_VERIFY(d <= D, "");
|
||||
}
|
||||
|
||||
const auto F = coeff.Read();
|
||||
const auto B = Reshape(b, q, d);
|
||||
const auto DETJ = Reshape(detj, q, q, q, ne);
|
||||
const auto W = Reshape(weights, q, q, q);
|
||||
const bool cst_coeff = coeff.Size() == vdim;
|
||||
const auto C =
|
||||
cst_coeff ? Reshape(F, vdim, 1, 1, 1, 1) : Reshape(F, vdim, q, q, q, ne);
|
||||
|
||||
auto Y = Reshape(y, d, d, d, vdim, ne);
|
||||
|
||||
mfem::forall_2D(ne, q, q, [=] MFEM_HOST_DEVICE(int e)
|
||||
{
|
||||
if (markers[e] == 0)
|
||||
{
|
||||
return;
|
||||
} // ignore
|
||||
|
||||
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;
|
||||
|
||||
real_t u[D];
|
||||
|
||||
MFEM_SHARED real_t sBt[Q * D];
|
||||
const DeviceMatrix Bt(sBt, d, q);
|
||||
kernels::internal::LoadB<D, Q>(d, q, B, sBt);
|
||||
|
||||
MFEM_SHARED real_t sQQQ[MQD * MQD * MQD];
|
||||
const DeviceCube QQQ(sQQQ, MQD, MQD, MQD);
|
||||
|
||||
for (int c = 0; c < vdim; ++c)
|
||||
{
|
||||
const real_t cst_val = C(c, 0, 0, 0, 0);
|
||||
MFEM_FOREACH_THREAD(x, x, q)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(y, y, q)
|
||||
{
|
||||
for (int z = 0; z < q; ++z)
|
||||
{
|
||||
const real_t detJ = (map_type == FiniteElement::VALUE)
|
||||
? DETJ(x, y, z, e)
|
||||
: 1.0;
|
||||
const real_t coeff_val =
|
||||
cst_coeff ? cst_val : C(c, x, y, z, e);
|
||||
QQQ(z, y, x) = W(x, y, z) * coeff_val * detJ;
|
||||
}
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
MFEM_FOREACH_THREAD(qx, x, q)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qy, y, q)
|
||||
{
|
||||
for (int dz = 0; dz < d; ++dz)
|
||||
{
|
||||
u[dz] = 0.0;
|
||||
}
|
||||
for (int qz = 0; qz < q; ++qz)
|
||||
{
|
||||
const real_t ZYX = QQQ(qz, qy, qx);
|
||||
for (int dz = 0; dz < d; ++dz)
|
||||
{
|
||||
u[dz] += ZYX * Bt(dz, qz);
|
||||
}
|
||||
}
|
||||
for (int dz = 0; dz < d; ++dz)
|
||||
{
|
||||
QQQ(dz, qy, qx) = u[dz];
|
||||
}
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
MFEM_FOREACH_THREAD(dz, y, d)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qx, x, q)
|
||||
{
|
||||
for (int dy = 0; dy < d; ++dy)
|
||||
{
|
||||
u[dy] = 0.0;
|
||||
}
|
||||
for (int qy = 0; qy < q; ++qy)
|
||||
{
|
||||
const real_t zYX = QQQ(dz, qy, qx);
|
||||
for (int dy = 0; dy < d; ++dy)
|
||||
{
|
||||
u[dy] += zYX * Bt(dy, qy);
|
||||
}
|
||||
}
|
||||
for (int dy = 0; dy < d; ++dy)
|
||||
{
|
||||
QQQ(dz, dy, qx) = u[dy];
|
||||
}
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
MFEM_FOREACH_THREAD(dz, y, d)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(dy, x, d)
|
||||
{
|
||||
for (int dx = 0; dx < d; ++dx)
|
||||
{
|
||||
u[dx] = 0.0;
|
||||
}
|
||||
for (int qx = 0; qx < q; ++qx)
|
||||
{
|
||||
const real_t zyX = QQQ(dz, dy, qx);
|
||||
for (int dx = 0; dx < d; ++dx)
|
||||
{
|
||||
u[dx] += zyX * Bt(dx, qx);
|
||||
}
|
||||
}
|
||||
for (int dx = 0; dx < d; ++dx)
|
||||
{
|
||||
Y(dx, dy, dz, c, e) += u[dx];
|
||||
}
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
template <int DIM, int T_D1D, int T_Q1D>
|
||||
DomainLFIntegrator::AssembleKernelType
|
||||
DomainLFIntegrator::AssembleKernels::Kernel()
|
||||
{
|
||||
switch (DIM)
|
||||
{
|
||||
case 1:
|
||||
return DLFEvalAssemble1D<T_D1D, T_Q1D>;
|
||||
case 2:
|
||||
return DLFEvalAssemble2D<T_D1D, T_Q1D>;
|
||||
case 3:
|
||||
return DLFEvalAssemble3D<T_D1D, T_Q1D>;
|
||||
}
|
||||
MFEM_ABORT("");
|
||||
}
|
||||
/// \endcond DO_NOT_DOCUMENT
|
||||
|
||||
} // namespace mfem
|
||||
#endif
|
||||
@@ -947,6 +947,7 @@ int Quadrature1D::CheckOpen(int type)
|
||||
case OpenUniform:
|
||||
case ClosedUniform:
|
||||
case OpenHalfUniform:
|
||||
case ClosedGL:
|
||||
return type; // all types can work as open
|
||||
default:
|
||||
return Invalid;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user