mirror of
https://github.com/paboyle/Grid.git
synced 2026-09-30 13:08:05 +01:00
Compare commits
731
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
de8b2dcca3 | ||
|
|
efe000341d | ||
|
|
11086c5c25 | ||
|
|
91a7fe247b | ||
|
|
8a1be021d3 | ||
|
|
fd66325321 | ||
|
|
c637c0c48c | ||
|
|
c4b472176c | ||
|
|
856476a890 | ||
|
|
c509bd3fe2 | ||
|
|
49b934310b | ||
|
|
01e8cf5017 | ||
|
|
12f4499502 | ||
|
|
05aec72887 | ||
|
|
136d3802cb | ||
|
|
a4c55406ed | ||
|
|
c7f33ca2a8 | ||
|
|
0e3035c51d | ||
|
|
10fc263675 | ||
|
|
bccfd4cbb3 | ||
|
|
0b50d4a328 | ||
|
|
e232257cb6 | ||
|
|
09451b5e48 | ||
|
|
6364aa8acf | ||
|
|
b9e84ecab7 | ||
|
|
41032fef44 | ||
|
|
d77bc88170 | ||
|
|
494b3c9e57 | ||
|
|
2ba19a9e07 | ||
|
|
5d7cc29eaf | ||
|
|
f22a27d7f9 | ||
|
|
33a0bbb17b | ||
|
|
f592ec8baa | ||
|
|
8b007b5c24 | ||
|
|
9bb170576d | ||
|
|
a7e3977b75 | ||
|
|
995f20e45d | ||
|
|
d058b4e681 | ||
|
|
8e0d2f3402 | ||
|
|
2ac57370f1 | ||
|
|
344e832a4e | ||
|
|
cfe281f1a4 | ||
|
|
f5422c7334 | ||
|
|
68c76a410d | ||
|
|
69b6ba0a73 | ||
|
|
65349b07a7 | ||
|
|
7cd9914f0e | ||
|
|
f3f24b3017 | ||
|
|
8ef4657805 | ||
|
|
78c1086f8b | ||
|
|
68c13045d6 | ||
|
|
e9b6f58fdc | ||
|
|
839605c45c | ||
|
|
1ff1422e07 | ||
|
|
32376f0437 | ||
|
|
0c6e581336 | ||
|
|
e0a79a5bbf | ||
|
|
4c016cc1a4 | ||
|
|
2205b1e63e | ||
|
|
6f421c7a6f | ||
|
|
b62b9ac214 | ||
|
|
88d9922e4f | ||
|
|
9734e3ee58 | ||
|
|
8c3a599148 | ||
|
|
4a47b11876 | ||
|
|
f1382cf81d | ||
|
|
85699daef2 | ||
|
|
1651111d18 | ||
|
|
1ed4ea344d | ||
|
|
8f514ae550 | ||
|
|
4a7415e83c | ||
|
|
0ffcfea724 | ||
|
|
febe41cc1d | ||
|
|
62173395b8 | ||
|
|
b48611b80f | ||
|
|
6b559d68aa | ||
|
|
1982cc58dd | ||
|
|
2e2e5ce596 | ||
|
|
7d84dca8e9 | ||
|
|
2d3916418e | ||
|
|
21304e2139 | ||
|
|
7b850eb48b | ||
|
|
a3ace57e01 | ||
|
|
b1c3cbe35e | ||
|
|
f31d6bfec2 | ||
|
|
a7cfa26901 | ||
|
|
f333f3e575 | ||
|
|
2b4e253473 | ||
|
|
0ba3d469c7 | ||
|
|
f709329d96 | ||
|
|
f05b25dae4 | ||
|
|
3e1d268fa3 | ||
|
|
109c74bed8 | ||
|
|
3023287fd9 | ||
|
|
b3d6805638 | ||
|
|
291bc2a1f0 | ||
|
|
2f368c33fc | ||
|
|
9592115341 | ||
|
|
24c07694bc | ||
|
|
f0229025e2 | ||
|
|
6de9a45a09 | ||
|
|
03c3d495a2 | ||
|
|
49f25e08e8 | ||
|
|
efc0c65056 | ||
|
|
936eaac8e1 | ||
|
|
fe6a372f75 | ||
|
|
148fc052bd | ||
|
|
c073341a10 | ||
|
|
78299daaac | ||
|
|
866449c804 | ||
|
|
d69a52079f | ||
|
|
9f4f8a14a3 | ||
|
|
f6593dc881 | ||
|
|
b46d31d4b6 | ||
|
|
58567fc650 | ||
|
|
7c57cac670 | ||
|
|
d0b21bf1ff | ||
|
|
a1825d1f59 | ||
|
|
5a3e83ff7b | ||
|
|
52569d98d8 | ||
|
|
b351103c29 | ||
|
|
118cca4681 | ||
|
|
44de727cd2 | ||
|
|
888ebc3cf9 | ||
|
|
6c031a1b81 | ||
|
|
02aa4bd762 | ||
|
|
9aafa8ee60 | ||
|
|
430b98b354 | ||
|
|
84189867ef | ||
|
|
4ab8cfbe2a | ||
|
|
aadd9f4468 | ||
|
|
8fbb27ce13 | ||
|
|
21bba95909 | ||
|
|
6448fe7121 | ||
|
|
2458a11d1d | ||
|
|
d0ca7c3fe6 | ||
|
|
57f899d79c | ||
|
|
e881a0c157 | ||
|
|
f411657118 | ||
|
|
7458c6174b | ||
|
|
21b269d0f9 | ||
|
|
083af92ac2 | ||
|
|
2c162577b5 | ||
|
|
b1c4e96382 | ||
|
|
a55c6f34f3 | ||
|
|
beed527ea3 | ||
|
|
eaa633cf69 | ||
|
|
c632455129 | ||
|
|
c012899ed5 | ||
|
|
8bab544c2f | ||
|
|
76fc06a5dc | ||
|
|
4af6c7e7aa | ||
|
|
f60fbcfc4d | ||
|
|
464c81706e | ||
|
|
408130b808 | ||
|
|
375edd1370 | ||
|
|
6d912f6c67 | ||
|
|
6d1d28955e | ||
|
|
920b471761 | ||
|
|
63c21767ba | ||
|
|
7b6b712565 | ||
|
|
35abd05ee9 | ||
|
|
dd36e60f6a | ||
|
|
cb6c548e21 | ||
|
|
02c4ccf621 | ||
|
|
fd24588212 | ||
|
|
b800bb3ecb | ||
|
|
f8abd0978b | ||
|
|
12c7c493bf | ||
|
|
c7c9072313 | ||
|
|
2bf3be5fae | ||
|
|
3a40e4fc69 | ||
|
|
2e69e03f6f | ||
|
|
a09f9bb528 | ||
|
|
f0e341d726 | ||
|
|
6f09df0daf | ||
|
|
26cee605b8 | ||
|
|
b3fa18c229 | ||
|
|
2940c9bcfd | ||
|
|
0bb532f72b | ||
|
|
fada2aa0f7 | ||
|
|
c193e4e675 | ||
|
|
3ee682f676 | ||
|
|
d85ec3bac2 | ||
|
|
b52d8eb1e3 | ||
|
|
ee630d2e8b | ||
|
|
2f0af79869 | ||
|
|
1b7fb79ec0 | ||
|
|
2db1a4628c | ||
|
|
6aa047d842 | ||
|
|
8779c32ae1 | ||
|
|
c527dc3358 | ||
|
|
6b42577b6b | ||
|
|
fb3596f968 | ||
|
|
f3a0158213 | ||
|
|
0250aa9347 | ||
|
|
3df6743396 | ||
|
|
fb7d021b9d | ||
|
|
5f206df775 | ||
|
|
7727e81113 | ||
|
|
c4115544a5 | ||
|
|
08c47328ba | ||
|
|
09001aedca | ||
|
|
2c67304716 | ||
|
|
dc6d8686de | ||
|
|
cc2780bea3 | ||
|
|
6e5a2b7922 | ||
|
|
f4878d3a13 | ||
|
|
89d2fac92e | ||
|
|
f2d3e41cf2 | ||
|
|
3c27bb36d4 | ||
|
|
603d59f389 | ||
|
|
07a0ef3f95 | ||
|
|
503259f9c9 | ||
|
|
5be6a51044 | ||
|
|
ac69f042b1 | ||
|
|
133d5c2e34 | ||
|
|
2a94244890 | ||
|
|
a15a2dfd29 | ||
|
|
093bb02633 | ||
|
|
99a85116f8 | ||
|
|
27cdb79063 | ||
|
|
f4cbfd63ff | ||
|
|
2b794b6aa7 | ||
|
|
d0244a059f | ||
|
|
dcdd891d7d | ||
|
|
6d2df9de79 | ||
|
|
41d4e37bae | ||
|
|
ee5c0cc9b6 | ||
|
|
0a4020eb4d | ||
|
|
b2de26589b | ||
|
|
0677adb4dd | ||
|
|
231cc95be6 | ||
|
|
639f9cab82 | ||
|
|
4eac4e575e | ||
|
|
3f0f92cda6 | ||
|
|
d2650e89bd | ||
|
|
2962123cba | ||
|
|
830168ec37 | ||
|
|
584c921ca0 | ||
|
|
81347b4d16 | ||
|
|
2cfa0b0e6b | ||
|
|
fa5dee76b1 | ||
|
|
8d1679c6b8 | ||
|
|
3791a38f7c | ||
|
|
142f7b0c86 | ||
|
|
891ad66eab | ||
|
|
60c43151c5 | ||
|
|
e036800261 | ||
|
|
62900def36 | ||
|
|
e3a309a73f | ||
|
|
ad6c1c0c4e | ||
|
|
00b92a91b5 | ||
|
|
65533741f7 | ||
|
|
dc0259fbda | ||
|
|
131a6785d4 | ||
|
|
44f4f5c8e2 | ||
|
|
2679df034f | ||
|
|
bf71162b97 | ||
|
|
299e828d83 | ||
|
|
ef5452cddf | ||
|
|
80de748737 | ||
|
|
71e1006ba8 | ||
|
|
00f31ae83f | ||
|
|
cce339deaf | ||
|
|
24128ff109 | ||
|
|
34e9d3f0ca | ||
|
|
c995788259 | ||
|
|
94c7198001 | ||
|
|
04d86fe9f3 | ||
|
|
b78074b6a0 | ||
|
|
7dfd3cdae8 | ||
|
|
cecee1ef2c | ||
|
|
355d4b58be | ||
|
|
2c54a536f3 | ||
|
|
d868a45120 | ||
|
|
9deae8c962 | ||
|
|
db86cdd7bd | ||
|
|
ec9939c1ba | ||
|
|
f74617c124 | ||
|
|
8c6a3921ed | ||
|
|
a8a15dd9d0 | ||
|
|
3ce68a751a | ||
|
|
daa0977d01 | ||
|
|
a2929f4384 | ||
|
|
7fe3974c0a | ||
|
|
f7e86f81a0 | ||
|
|
fecec803d9 | ||
|
|
8fe9a13cdd | ||
|
|
d2c42e6f42 | ||
|
|
2881b3e8e5 | ||
|
|
049cc518f4 | ||
|
|
2e1c66897f | ||
|
|
adcef36189 | ||
|
|
2f121c41c9 | ||
|
|
e0ed7e300f | ||
|
|
485207901b | ||
|
|
c760f0a4c3 | ||
|
|
c84eeedec3 | ||
|
|
1ac3526f33 | ||
|
|
0de090ee74 | ||
|
|
91405de3f7 | ||
|
|
8fccda301a | ||
|
|
7a0abfac89 | ||
|
|
ae37fda699 | ||
|
|
b5fc5e2030 | ||
|
|
cc5d025ea4 | ||
|
|
ddcb53bce2 | ||
|
|
d1c80e1d46 | ||
|
|
c73cc7d354 | ||
|
|
49fdc324a0 | ||
|
|
f32714a2d1 | ||
|
|
73a955be20 | ||
|
|
66b7a0f871 | ||
|
|
2ab9d4bc56 | ||
|
|
4f41cd114d | ||
|
|
11c4f5e32c | ||
|
|
e9b9550298 | ||
|
|
7564fedf68 | ||
|
|
8db0ef9736 | ||
|
|
95d4b46446 | ||
|
|
5dfd216a34 | ||
|
|
c2e8d0aa88 | ||
|
|
0fe5aeffbb | ||
|
|
7fbc469046 | ||
|
|
bf96a4bdbf | ||
|
|
84685c9bc3 | ||
|
|
a8d4156997 | ||
|
|
c18074869b | ||
|
|
f4c6d39238 | ||
|
|
200d35b38a | ||
|
|
eb52e84d09 | ||
|
|
72abc34764 | ||
|
|
e3164d4c7b | ||
|
|
f5db386c55 | ||
|
|
294ee70a7a | ||
|
|
013ea4e8d1 | ||
|
|
7fbbb31a50 | ||
|
|
0e127b1fc7 | ||
|
|
68c028b0a6 | ||
|
|
255d4992e1 | ||
|
|
a0d399e5ce | ||
|
|
fd3b2e945a | ||
|
|
6c27c72585 | ||
|
|
9c003d2d72 | ||
|
|
4b8710970c | ||
|
|
68d686ec38 | ||
|
|
c48b69ca81 | ||
|
|
df8c208f5c | ||
|
|
61812ab7f1 | ||
|
|
b999984501 | ||
|
|
7836cc2d74 | ||
|
|
a61e0df54b | ||
|
|
9d835afa35 | ||
|
|
5e3be47117 | ||
|
|
48de706dd5 | ||
|
|
f871fb0c6d | ||
|
|
93771f3099 | ||
|
|
8cb205725b | ||
|
|
9ad580d82f | ||
|
|
899f961d0d | ||
|
|
54d789204f | ||
|
|
25828746f3 | ||
|
|
f362c00739 | ||
|
|
25d1cadd3b | ||
|
|
c24d53bbd1 | ||
|
|
2017e4e3b4 | ||
|
|
27a4d4c951 | ||
|
|
2f92721249 | ||
|
|
3c7a4106ed | ||
|
|
3252059daf | ||
|
|
6eed167f0c | ||
|
|
4ad0df6fde | ||
|
|
661381e881 | ||
|
|
68a5079f33 | ||
|
|
8634e19f1b | ||
|
|
9ada378e38 | ||
|
|
9d9692d439 | ||
|
|
0659ae4014 | ||
|
|
bfbf2f1fa0 | ||
|
|
dd6b796a01 | ||
|
|
52a856b4a8 | ||
|
|
04190ee7f3 | ||
|
|
587bfcc0f4 | ||
|
|
2700992ef5 | ||
|
|
8c658de179 | ||
|
|
ba37d51ee9 | ||
|
|
4f4181c54a | ||
|
|
4d4ac2517b | ||
|
|
e568c24d1d | ||
|
|
b458326744 | ||
|
|
6e7d5e2243 | ||
|
|
b35169f1dd | ||
|
|
441ad7498d | ||
|
|
6f6c5c549a | ||
|
|
1584e17b54 | ||
|
|
12982a4455 | ||
|
|
172f412102 | ||
|
|
a64497265d | ||
|
|
ca639c195f | ||
|
|
edc28dcfbf | ||
|
|
c45f24a1b5 | ||
|
|
aaf37ee4d7 | ||
|
|
1dddd17e3c | ||
|
|
661f1d3e8e | ||
|
|
edcf9b9293 | ||
|
|
49b8501fd4 | ||
|
|
d47484717e | ||
|
|
96272f3841 | ||
|
|
5c936d88a0 | ||
|
|
1c64ee926e | ||
|
|
2cbb72a81c | ||
|
|
31d83ee046 | ||
|
|
a9e8758a01 | ||
|
|
3e125c5b61 | ||
|
|
eac6ec4b5e | ||
|
|
213f8db6a2 | ||
|
|
cc6eb51e3e | ||
|
|
507009089b | ||
|
|
b234784c8e | ||
|
|
6ea2a8b7ca | ||
|
|
c1d0359aaa | ||
|
|
047ee4ad0b | ||
|
|
a13106da0c | ||
|
|
75113e6523 | ||
|
|
325c73d051 | ||
|
|
b25a59e95e | ||
|
|
7c4533797f | ||
|
|
af84fd65bb | ||
|
|
1a2613086a | ||
|
|
4f110c09a5 | ||
|
|
6764362237 | ||
|
|
2fa2b0e0b1 | ||
|
|
b61292f735 | ||
|
|
ce7720e221 | ||
|
|
853a5528dc | ||
|
|
169f405c9c | ||
|
|
c6125b01ce | ||
|
|
b0b5b34bff | ||
|
|
1c9722357d | ||
|
|
334da7f452 | ||
|
|
4669ecd4ba | ||
|
|
4573b34cac | ||
|
|
17f57e85d1 | ||
|
|
17f27b1ebd | ||
|
|
a16bbecb8a | ||
|
|
7c9b0dd842 | ||
|
|
6b7228b3e6 | ||
|
|
f117552334 | ||
|
|
a21a160029 | ||
|
|
6b8ffbe735 | ||
|
|
81050535a5 | ||
|
|
7dcf5c90e3 | ||
|
|
9ce00f26f9 | ||
|
|
85c253ed4a | ||
|
|
ccfc0a5a89 | ||
|
|
d3f857b1c9 | ||
|
|
fb62035aa0 | ||
|
|
0260bc7705 | ||
|
|
68e6a58f12 | ||
|
|
73ced656eb | ||
|
|
f69008edf1 | ||
|
|
57a49ed22f | ||
|
|
ff6413a764 | ||
|
|
2530bfed01 | ||
|
|
640515e3d8 | ||
|
|
97c579f637 | ||
|
|
74f79c5ac7 | ||
|
|
58c30c0cb1 | ||
|
|
917a92118a | ||
|
|
a4d8512fb8 | ||
|
|
5ec903044d | ||
|
|
04f9cf088d | ||
|
|
99107038f9 | ||
|
|
8a0cf0194f | ||
|
|
b78456bdf4 | ||
|
|
08543b6b11 | ||
|
|
63ba33371f | ||
|
|
683a7d2ddd | ||
|
|
1c680d4b7a | ||
|
|
afdcbf79d1 | ||
|
|
3c3ec4e267 | ||
|
|
bbe1d5b49e | ||
|
|
0f6009a29f | ||
|
|
1cfed3de7c | ||
|
|
edbc0d49d7 | ||
|
|
e9323460c7 | ||
|
|
58c2f60b69 | ||
|
|
bfa3a7b3b0 | ||
|
|
f212b0a963 | ||
|
|
62702dbcb8 | ||
|
|
41d6cab033 | ||
|
|
5a31e747c9 | ||
|
|
cbc73a3fd1 | ||
|
|
ee5cf6c8c5 | ||
|
|
d516938707 | ||
|
|
72344d1418 | ||
|
|
7ecf6ab38b | ||
|
|
2d4d70d3ec | ||
|
|
78f8d47528 | ||
|
|
b85f987b0b | ||
|
|
f57afe2079 | ||
|
|
8462bbfe63 | ||
|
|
229977c955 | ||
|
|
e485a07133 | ||
|
|
70ec2faa98 | ||
|
|
a66cecc509 | ||
|
|
0f6cdf3d4b | ||
|
|
1e63b73a14 | ||
|
|
2f849ee252 | ||
|
|
bb6ed44339 | ||
|
|
80302e95a8 | ||
|
|
9942723189 | ||
|
|
b938202081 | ||
|
|
e79ef469ac | ||
|
|
c793947209 | ||
|
|
3e9ee053a1 | ||
|
|
dda6c69d5b | ||
|
|
cd51b9af99 | ||
|
|
f32555dcc5 | ||
|
|
e93c883470 | ||
|
|
fcac5c0772 | ||
|
|
90f4000935 | ||
|
|
480708b9a0 | ||
|
|
c4baf876d4 | ||
|
|
2f4dac3531 | ||
|
|
3ec6890850 | ||
|
|
018801d973 | ||
|
|
1d83521daa | ||
|
|
fc5670c6a4 | ||
|
|
d9c435e282 | ||
|
|
614a0e8277 | ||
|
|
aaf39222c3 | ||
|
|
550142bd6a | ||
|
|
c0a929aef7 | ||
|
|
37fe944224 | ||
|
|
315a42843f | ||
|
|
83a101db83 | ||
|
|
c4274e1660 | ||
|
|
ba6db55cb0 | ||
|
|
e5ea84d531 | ||
|
|
15767a1491 | ||
|
|
4d2a32ae7a | ||
|
|
5b937e3644 | ||
|
|
e418b044f7 | ||
|
|
b8b05f143f | ||
|
|
6ec42b4b82 | ||
|
|
abb7d4d2f5 | ||
|
|
16ebbfff29 | ||
|
|
4828226095 | ||
|
|
8a049f27b8 | ||
|
|
43578a3eb4 | ||
|
|
fdbd42e542 | ||
|
|
e7e4cee4f3 | ||
|
|
ec3954ff5f | ||
|
|
0f468e2179 | ||
|
|
8e61286741 | ||
|
|
69e4ecc1d2 | ||
|
|
5f483df16b | ||
|
|
4680a977c3 | ||
|
|
de42456171 | ||
|
|
d55212c998 | ||
|
|
c6e1f64573 | ||
|
|
724cf02d4a | ||
|
|
49a0ae73eb | ||
|
|
6ab60c5b70 | ||
|
|
8c692b7ffd | ||
|
|
2976132bdd | ||
|
|
48177f2f2d | ||
|
|
c4ce70a821 | ||
|
|
315f1146cd | ||
|
|
a3e009ba54 | ||
|
|
eb7cf239d9 | ||
|
|
13ae371ef8 | ||
|
|
9f79a87102 | ||
|
|
4ded1ceeb0 | ||
|
|
9f202782c5 | ||
|
|
8bc12e0ce1 | ||
|
|
cc2f00f827 | ||
|
|
cd61e2e6d6 | ||
|
|
323ed1a588 | ||
|
|
68c66d2e4b | ||
|
|
1671adfd49 | ||
|
|
594a262dcc | ||
|
|
7f8ca54285 | ||
|
|
c5b23c367e | ||
|
|
b6fe03eb26 | ||
|
|
f37ed4958b | ||
|
|
5f85473d6b | ||
|
|
871649238c | ||
|
|
ac3b0ebc58 | ||
|
|
7c86d2085b | ||
|
|
9292be0b69 | ||
|
|
10141f90c9 | ||
|
|
a414430817 | ||
|
|
f20728baa9 | ||
|
|
d2e68c4355 | ||
|
|
1cb745c8dc | ||
|
|
faf4278019 | ||
|
|
194e4b94bb | ||
|
|
bfc1411c1f | ||
|
|
161637e573 | ||
|
|
4e0cf0cc28 | ||
|
|
cdf550845f | ||
|
|
3db7a5387b | ||
|
|
90dffc73c8 | ||
|
|
a1151fc734 | ||
|
|
ab3baeb38f | ||
|
|
389731d373 | ||
|
|
04f92ccddf | ||
|
|
3b2d805398 | ||
|
|
97b9c6f03d | ||
|
|
63982819c6 | ||
|
|
6fec507bef | ||
|
|
219b3bd34f | ||
|
|
9dc885d297 | ||
|
|
a70c1feecc | ||
|
|
38328100c9 | ||
|
|
9732519c41 | ||
|
|
fa4eeb28c4 | ||
|
|
10f7a17ae4 | ||
|
|
26f14d7dd7 | ||
|
|
24162c9ead | ||
|
|
73434db636 | ||
|
|
c6411f8514 | ||
|
|
6cf635d61c | ||
|
|
39558cce52 | ||
|
|
935cd1e173 | ||
|
|
55e39df30f | ||
|
|
581be32ed2 | ||
|
|
6bc136b1d0 | ||
|
|
df152648d6 | ||
|
|
4e965c168e | ||
|
|
f260af546e | ||
|
|
649b8c9aca | ||
|
|
0afa22747d | ||
|
|
fa43206c79 | ||
|
|
a367835bf2 | ||
|
|
d7743591ea | ||
|
|
c6cbe533ea | ||
|
|
8402ab6cf9 | ||
|
|
c63095345e | ||
|
|
a7ae46b61e | ||
|
|
cd63052205 | ||
|
|
699d537cd6 | ||
|
|
9031f0ed95 | ||
|
|
26b3d441bb | ||
|
|
99bc4cde56 | ||
|
|
e843d83d9d | ||
|
|
0f75ea52b7 | ||
|
|
8107b785cc | ||
|
|
37b777d801 | ||
|
|
7382787856 | ||
|
|
781c611ca0 | ||
|
|
b069090b52 | ||
|
|
0c1c1d9900 | ||
|
|
7f4ed6c2e5 | ||
|
|
56d32a4afb | ||
|
|
b8ee496ed6 | ||
|
|
0c668bf46a | ||
|
|
b87416dac4 | ||
|
|
176bf37372 | ||
|
|
b3d342ca22 | ||
|
|
e1f928398d | ||
|
|
8c579d2d4a | ||
|
|
840814c776 | ||
|
|
fc7d07ade0 | ||
|
|
b3be9195b4 | ||
|
|
9e3c187a4d | ||
|
|
8363edfcdb | ||
|
|
74af31564f | ||
|
|
e0819d395f | ||
|
|
95af55128e | ||
|
|
9f2a57e334 | ||
|
|
c645d33db5 | ||
|
|
e0f1349524 | ||
|
|
6f81906b00 | ||
|
|
79b761f923 | ||
|
|
0d4e31ca58 | ||
|
|
a2d83d4f3d | ||
|
|
89bacb0470 | ||
|
|
b07a354a33 | ||
|
|
19010ff66a | ||
|
|
5a477ed29e | ||
|
|
54128d579a | ||
|
|
e7b1933e88 | ||
|
|
1bad64ac6a | ||
|
|
15dfa9f663 | ||
|
|
2185b0d651 | ||
|
|
f61c0b5d03 | ||
|
|
074db32e54 | ||
|
|
d5f661ba70 | ||
|
|
1ab8d5cc13 | ||
|
|
789e892865 | ||
|
|
53cfa44d7a | ||
|
|
c433939795 | ||
|
|
b6a4c31b48 | ||
|
|
98b1439ff9 | ||
|
|
564738b1ff | ||
|
|
a80e43dbcf | ||
|
|
b99622d9fb | ||
|
|
937c77ead2 | ||
|
|
95e5a2ade3 | ||
|
|
91676d1dda | ||
|
|
ac3611bb19 | ||
|
|
cc4afb978d | ||
|
|
20e92a7009 | ||
|
|
42f0afcbfa | ||
|
|
20ac13fdf3 | ||
|
|
e38612e6fa | ||
|
|
c2b2b71c5d | ||
|
|
009f48a904 | ||
|
|
5cfc0180aa | ||
|
|
914f180fa3 | ||
|
|
6cb563a40c | ||
|
|
db3837be22 | ||
|
|
2f0dd83016 | ||
|
|
3ac27e5596 | ||
|
|
bd466a55a8 | ||
|
|
c8e6f58e24 | ||
|
|
888988ad37 | ||
|
|
e4a105a30b | ||
|
|
26ebe41fef | ||
|
|
1e496fee74 | ||
|
|
9f755e0379 | ||
|
|
4512dbdf58 | ||
|
|
483fd3cfa1 | ||
|
|
85516e9c7c | ||
|
|
0c006fbfaa | ||
|
|
54c10a42cc | ||
|
|
ef0fe2bcc1 |
No files matched your search
+5
-21
@@ -83,6 +83,7 @@ ltmain.sh
|
|||||||
.Trashes
|
.Trashes
|
||||||
ehthumbs.db
|
ehthumbs.db
|
||||||
Thumbs.db
|
Thumbs.db
|
||||||
|
.dirstamp
|
||||||
|
|
||||||
# build directory #
|
# build directory #
|
||||||
###################
|
###################
|
||||||
@@ -97,11 +98,8 @@ build.sh
|
|||||||
|
|
||||||
# Eigen source #
|
# Eigen source #
|
||||||
################
|
################
|
||||||
lib/Eigen/*
|
Grid/Eigen
|
||||||
|
Eigen/*
|
||||||
# FFTW source #
|
|
||||||
################
|
|
||||||
lib/fftw/*
|
|
||||||
|
|
||||||
# libtool macros #
|
# libtool macros #
|
||||||
##################
|
##################
|
||||||
@@ -112,21 +110,7 @@ m4/libtool.m4
|
|||||||
################
|
################
|
||||||
gh-pages/
|
gh-pages/
|
||||||
|
|
||||||
# Buck files #
|
|
||||||
##############
|
|
||||||
.buck*
|
|
||||||
buck-out
|
|
||||||
BUCK
|
|
||||||
make-bin-BUCK.sh
|
|
||||||
|
|
||||||
# generated sources #
|
# generated sources #
|
||||||
#####################
|
#####################
|
||||||
lib/qcd/spin/gamma-gen/*.h
|
Grid/qcd/spin/gamma-gen/*.h
|
||||||
lib/qcd/spin/gamma-gen/*.cc
|
Grid/qcd/spin/gamma-gen/*.cc
|
||||||
lib/version.h
|
|
||||||
|
|
||||||
# vs code editor files #
|
|
||||||
########################
|
|
||||||
.vscode/
|
|
||||||
.vscode/settings.json
|
|
||||||
settings.json
|
|
||||||
+20
-6
@@ -9,6 +9,11 @@ matrix:
|
|||||||
- os: osx
|
- os: osx
|
||||||
osx_image: xcode8.3
|
osx_image: xcode8.3
|
||||||
compiler: clang
|
compiler: clang
|
||||||
|
env: PREC=single
|
||||||
|
- os: osx
|
||||||
|
osx_image: xcode8.3
|
||||||
|
compiler: clang
|
||||||
|
env: PREC=double
|
||||||
|
|
||||||
before_install:
|
before_install:
|
||||||
- export GRIDDIR=`pwd`
|
- export GRIDDIR=`pwd`
|
||||||
@@ -16,9 +21,11 @@ before_install:
|
|||||||
- if [[ "$TRAVIS_OS_NAME" == "linux" ]] && [[ "$CC" == "clang" ]]; then export PATH="${GRIDDIR}/clang/bin:${PATH}"; fi
|
- if [[ "$TRAVIS_OS_NAME" == "linux" ]] && [[ "$CC" == "clang" ]]; then export PATH="${GRIDDIR}/clang/bin:${PATH}"; fi
|
||||||
- if [[ "$TRAVIS_OS_NAME" == "linux" ]] && [[ "$CC" == "clang" ]]; then export LD_LIBRARY_PATH="${GRIDDIR}/clang/lib:${LD_LIBRARY_PATH}"; fi
|
- if [[ "$TRAVIS_OS_NAME" == "linux" ]] && [[ "$CC" == "clang" ]]; then export LD_LIBRARY_PATH="${GRIDDIR}/clang/lib:${LD_LIBRARY_PATH}"; fi
|
||||||
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update; fi
|
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update; fi
|
||||||
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install libmpc; fi
|
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install libmpc openssl; fi
|
||||||
|
|
||||||
install:
|
install:
|
||||||
|
- export CWD=`pwd`
|
||||||
|
- echo $CWD
|
||||||
- export CC=$CC$VERSION
|
- export CC=$CC$VERSION
|
||||||
- export CXX=$CXX$VERSION
|
- export CXX=$CXX$VERSION
|
||||||
- echo $PATH
|
- echo $PATH
|
||||||
@@ -31,17 +38,24 @@ install:
|
|||||||
- which $CXX
|
- which $CXX
|
||||||
- $CXX --version
|
- $CXX --version
|
||||||
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then export LDFLAGS='-L/usr/local/lib'; fi
|
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then export LDFLAGS='-L/usr/local/lib'; fi
|
||||||
|
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then export EXTRACONF='--with-openssl=/usr/local/opt/openssl'; fi
|
||||||
|
|
||||||
script:
|
script:
|
||||||
- ./bootstrap.sh
|
- ./bootstrap.sh
|
||||||
- mkdir build
|
- mkdir build
|
||||||
- cd build
|
- cd build
|
||||||
- ../configure --enable-precision=single --enable-simd=SSE4 --enable-comms=none
|
- mkdir lime
|
||||||
|
- cd lime
|
||||||
|
- mkdir build
|
||||||
|
- cd build
|
||||||
|
- wget http://usqcd-software.github.io/downloads/c-lime/lime-1.3.2.tar.gz
|
||||||
|
- tar xf lime-1.3.2.tar.gz
|
||||||
|
- cd lime-1.3.2
|
||||||
|
- ./configure --prefix=$CWD/build/lime/install
|
||||||
- make -j4
|
- make -j4
|
||||||
- ./benchmarks/Benchmark_dwf --threads 1 --debug-signals
|
- make install
|
||||||
- echo make clean
|
- cd $CWD/build
|
||||||
- ../configure --enable-precision=double --enable-simd=SSE4 --enable-comms=none
|
- ../configure --enable-precision=$PREC --enable-simd=SSE4 --enable-comms=none --with-lime=$CWD/build/lime/install ${EXTRACONF}
|
||||||
- make -j4
|
- make -j4
|
||||||
- ./benchmarks/Benchmark_dwf --threads 1 --debug-signals
|
- ./benchmarks/Benchmark_dwf --threads 1 --debug-signals
|
||||||
- make check
|
- make check
|
||||||
|
|
||||||
File renamed without changes.
File renamed without changes.
@@ -48,6 +48,7 @@ Author: paboyle <paboyle@ph.ed.ac.uk>
|
|||||||
#include <Grid/serialisation/Serialisation.h>
|
#include <Grid/serialisation/Serialisation.h>
|
||||||
#include <Grid/threads/Threads.h>
|
#include <Grid/threads/Threads.h>
|
||||||
#include <Grid/util/Util.h>
|
#include <Grid/util/Util.h>
|
||||||
|
#include <Grid/util/Sha.h>
|
||||||
#include <Grid/communicator/Communicator.h>
|
#include <Grid/communicator/Communicator.h>
|
||||||
#include <Grid/cartesian/Cartesian.h>
|
#include <Grid/cartesian/Cartesian.h>
|
||||||
#include <Grid/tensors/Tensors.h>
|
#include <Grid/tensors/Tensors.h>
|
||||||
File renamed without changes.
File renamed without changes.
@@ -1,4 +1,9 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
// Force Eigen to use MKL if Grid has been configured with --enable-mkl
|
||||||
|
#ifdef USE_MKL
|
||||||
|
#define EIGEN_USE_MKL_ALL
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined __GNUC__
|
#if defined __GNUC__
|
||||||
#pragma GCC diagnostic push
|
#pragma GCC diagnostic push
|
||||||
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||||
@@ -21,6 +21,32 @@ if BUILD_HDF5
|
|||||||
extra_headers+=serialisation/Hdf5Type.h
|
extra_headers+=serialisation/Hdf5Type.h
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
all: version-cache
|
||||||
|
|
||||||
|
version-cache:
|
||||||
|
@if [ `git status --porcelain | grep -v '??' | wc -l` -gt 0 ]; then\
|
||||||
|
a="uncommited changes";\
|
||||||
|
else\
|
||||||
|
a="clean";\
|
||||||
|
fi;\
|
||||||
|
echo "`git log -n 1 --format=format:"#define GITHASH \\"%H:%d $$a\\"%n" HEAD`" > vertmp;\
|
||||||
|
if [ -e version-cache ]; then\
|
||||||
|
d=`diff vertmp version-cache`;\
|
||||||
|
if [ "$${d}" != "" ]; then\
|
||||||
|
mv vertmp version-cache;\
|
||||||
|
rm -f Version.h;\
|
||||||
|
fi;\
|
||||||
|
else\
|
||||||
|
mv vertmp version-cache;\
|
||||||
|
rm -f Version.h;\
|
||||||
|
fi;\
|
||||||
|
rm -f vertmp
|
||||||
|
|
||||||
|
Version.h:
|
||||||
|
cp version-cache Version.h
|
||||||
|
|
||||||
|
.PHONY: version-cache
|
||||||
|
|
||||||
#
|
#
|
||||||
# Libraries
|
# Libraries
|
||||||
#
|
#
|
||||||
@@ -30,8 +56,8 @@ include Eigen.inc
|
|||||||
lib_LIBRARIES = libGrid.a
|
lib_LIBRARIES = libGrid.a
|
||||||
|
|
||||||
CCFILES += $(extra_sources)
|
CCFILES += $(extra_sources)
|
||||||
HFILES += $(extra_headers)
|
HFILES += $(extra_headers) Config.h Version.h
|
||||||
|
|
||||||
libGrid_a_SOURCES = $(CCFILES)
|
libGrid_a_SOURCES = $(CCFILES)
|
||||||
libGrid_adir = $(pkgincludedir)
|
libGrid_adir = $(includedir)/Grid
|
||||||
nobase_dist_pkginclude_HEADERS = $(HFILES) $(eigen_files) Config.h
|
nobase_dist_pkginclude_HEADERS = $(HFILES) $(eigen_files) $(eigen_unsupp_files)
|
||||||
@@ -48,6 +48,12 @@ Author: Peter Boyle <paboyle@ph.ed.ac.uk>
|
|||||||
#include <Grid/algorithms/iterative/ConjugateGradientMixedPrec.h>
|
#include <Grid/algorithms/iterative/ConjugateGradientMixedPrec.h>
|
||||||
#include <Grid/algorithms/iterative/BlockConjugateGradient.h>
|
#include <Grid/algorithms/iterative/BlockConjugateGradient.h>
|
||||||
#include <Grid/algorithms/iterative/ConjugateGradientReliableUpdate.h>
|
#include <Grid/algorithms/iterative/ConjugateGradientReliableUpdate.h>
|
||||||
|
#include <Grid/algorithms/iterative/MinimalResidual.h>
|
||||||
|
#include <Grid/algorithms/iterative/GeneralisedMinimalResidual.h>
|
||||||
|
#include <Grid/algorithms/iterative/CommunicationAvoidingGeneralisedMinimalResidual.h>
|
||||||
|
#include <Grid/algorithms/iterative/FlexibleGeneralisedMinimalResidual.h>
|
||||||
|
#include <Grid/algorithms/iterative/FlexibleCommunicationAvoidingGeneralisedMinimalResidual.h>
|
||||||
|
#include <Grid/algorithms/iterative/MixedPrecisionFlexibleGeneralisedMinimalResidual.h>
|
||||||
#include <Grid/algorithms/iterative/ImplicitlyRestartedLanczos.h>
|
#include <Grid/algorithms/iterative/ImplicitlyRestartedLanczos.h>
|
||||||
#include <Grid/algorithms/CoarsenedMatrix.h>
|
#include <Grid/algorithms/CoarsenedMatrix.h>
|
||||||
#include <Grid/algorithms/FFT.h>
|
#include <Grid/algorithms/FFT.h>
|
||||||
@@ -211,6 +211,7 @@ namespace Grid {
|
|||||||
|
|
||||||
for(int b=0;b<nn;b++){
|
for(int b=0;b<nn;b++){
|
||||||
|
|
||||||
|
subspace[b] = zero;
|
||||||
gaussian(RNG,noise);
|
gaussian(RNG,noise);
|
||||||
scale = std::pow(norm2(noise),-0.5);
|
scale = std::pow(norm2(noise),-0.5);
|
||||||
noise=noise*scale;
|
noise=noise*scale;
|
||||||
@@ -296,12 +297,57 @@ namespace Grid {
|
|||||||
};
|
};
|
||||||
|
|
||||||
RealD Mdag (const CoarseVector &in, CoarseVector &out){
|
RealD Mdag (const CoarseVector &in, CoarseVector &out){
|
||||||
return M(in,out);
|
// // corresponds to Petrov-Galerkin coarsening
|
||||||
|
// return M(in,out);
|
||||||
|
|
||||||
|
// corresponds to Galerkin coarsening
|
||||||
|
CoarseVector tmp(Grid());
|
||||||
|
G5C(tmp, in);
|
||||||
|
M(tmp, out);
|
||||||
|
G5C(out, out);
|
||||||
|
return norm2(out);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Defer support for further coarsening for now
|
void Mdir(const CoarseVector &in, CoarseVector &out, int dir, int disp){
|
||||||
void Mdiag (const CoarseVector &in, CoarseVector &out){};
|
|
||||||
void Mdir (const CoarseVector &in, CoarseVector &out,int dir, int disp){};
|
conformable(_grid,in._grid);
|
||||||
|
conformable(in._grid,out._grid);
|
||||||
|
|
||||||
|
SimpleCompressor<siteVector> compressor;
|
||||||
|
Stencil.HaloExchange(in,compressor);
|
||||||
|
|
||||||
|
auto point = [dir, disp](){
|
||||||
|
if(dir == 0 and disp == 0)
|
||||||
|
return 8;
|
||||||
|
else
|
||||||
|
return (4 * dir + 1 - disp) / 2;
|
||||||
|
}();
|
||||||
|
|
||||||
|
parallel_for(int ss=0;ss<Grid()->oSites();ss++){
|
||||||
|
siteVector res = zero;
|
||||||
|
siteVector nbr;
|
||||||
|
int ptype;
|
||||||
|
StencilEntry *SE;
|
||||||
|
|
||||||
|
SE=Stencil.GetEntry(ptype,point,ss);
|
||||||
|
|
||||||
|
if(SE->_is_local&&SE->_permute) {
|
||||||
|
permute(nbr,in._odata[SE->_offset],ptype);
|
||||||
|
} else if(SE->_is_local) {
|
||||||
|
nbr = in._odata[SE->_offset];
|
||||||
|
} else {
|
||||||
|
nbr = Stencil.CommBuf()[SE->_offset];
|
||||||
|
}
|
||||||
|
|
||||||
|
res = res + A[point]._odata[ss]*nbr;
|
||||||
|
|
||||||
|
vstream(out._odata[ss],res);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void Mdiag(const CoarseVector &in, CoarseVector &out){
|
||||||
|
Mdir(in, out, 0, 0); // use the self coupling (= last) point of the stencil
|
||||||
|
};
|
||||||
|
|
||||||
CoarsenedMatrix(GridCartesian &CoarseGrid) :
|
CoarsenedMatrix(GridCartesian &CoarseGrid) :
|
||||||
|
|
||||||
@@ -417,7 +463,7 @@ namespace Grid {
|
|||||||
std::cout<<GridLogMessage<<"Computed Coarse Operator"<<std::endl;
|
std::cout<<GridLogMessage<<"Computed Coarse Operator"<<std::endl;
|
||||||
#endif
|
#endif
|
||||||
// ForceHermitian();
|
// ForceHermitian();
|
||||||
AssertHermitian();
|
// AssertHermitian();
|
||||||
// ForceDiagonal();
|
// ForceDiagonal();
|
||||||
}
|
}
|
||||||
void ForceDiagonal(void) {
|
void ForceDiagonal(void) {
|
||||||
File renamed without changes.
@@ -51,7 +51,7 @@ namespace Grid {
|
|||||||
|
|
||||||
virtual void Op (const Field &in, Field &out) = 0; // Abstract base
|
virtual void Op (const Field &in, Field &out) = 0; // Abstract base
|
||||||
virtual void AdjOp (const Field &in, Field &out) = 0; // Abstract base
|
virtual void AdjOp (const Field &in, Field &out) = 0; // Abstract base
|
||||||
virtual void HermOpAndNorm(const Field &in, Field &out,RealD &n1,RealD &n2)=0;
|
virtual void HermOpAndNorm(const Field &in, Field &out,RealD &n1,RealD &n2) = 0;
|
||||||
virtual void HermOp(const Field &in, Field &out)=0;
|
virtual void HermOp(const Field &in, Field &out)=0;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -309,36 +309,59 @@ namespace Grid {
|
|||||||
class SchurStaggeredOperator : public SchurOperatorBase<Field> {
|
class SchurStaggeredOperator : public SchurOperatorBase<Field> {
|
||||||
protected:
|
protected:
|
||||||
Matrix &_Mat;
|
Matrix &_Mat;
|
||||||
|
Field tmp;
|
||||||
|
RealD mass;
|
||||||
|
double tMpc;
|
||||||
|
double tIP;
|
||||||
|
double tMeo;
|
||||||
|
double taxpby_norm;
|
||||||
|
uint64_t ncall;
|
||||||
public:
|
public:
|
||||||
SchurStaggeredOperator (Matrix &Mat): _Mat(Mat){};
|
void Report(void)
|
||||||
|
{
|
||||||
|
std::cout << GridLogMessage << " HermOpAndNorm.Mpc "<< tMpc/ncall<<" usec "<<std::endl;
|
||||||
|
std::cout << GridLogMessage << " HermOpAndNorm.IP "<< tIP /ncall<<" usec "<<std::endl;
|
||||||
|
std::cout << GridLogMessage << " Mpc.MeoMoe "<< tMeo/ncall<<" usec "<<std::endl;
|
||||||
|
std::cout << GridLogMessage << " Mpc.axpby_norm "<< taxpby_norm/ncall<<" usec "<<std::endl;
|
||||||
|
}
|
||||||
|
SchurStaggeredOperator (Matrix &Mat): _Mat(Mat), tmp(_Mat.RedBlackGrid())
|
||||||
|
{
|
||||||
|
assert( _Mat.isTrivialEE() );
|
||||||
|
mass = _Mat.Mass();
|
||||||
|
tMpc=0;
|
||||||
|
tIP =0;
|
||||||
|
tMeo=0;
|
||||||
|
taxpby_norm=0;
|
||||||
|
ncall=0;
|
||||||
|
}
|
||||||
virtual void HermOpAndNorm(const Field &in, Field &out,RealD &n1,RealD &n2){
|
virtual void HermOpAndNorm(const Field &in, Field &out,RealD &n1,RealD &n2){
|
||||||
GridLogIterative.TimingMode(1);
|
ncall++;
|
||||||
std::cout << GridLogIterative << " HermOpAndNorm "<<std::endl;
|
tMpc-=usecond();
|
||||||
n2 = Mpc(in,out);
|
n2 = Mpc(in,out);
|
||||||
std::cout << GridLogIterative << " HermOpAndNorm.Mpc "<<std::endl;
|
tMpc+=usecond();
|
||||||
|
tIP-=usecond();
|
||||||
ComplexD dot= innerProduct(in,out);
|
ComplexD dot= innerProduct(in,out);
|
||||||
std::cout << GridLogIterative << " HermOpAndNorm.innerProduct "<<std::endl;
|
tIP+=usecond();
|
||||||
n1 = real(dot);
|
n1 = real(dot);
|
||||||
}
|
}
|
||||||
virtual void HermOp(const Field &in, Field &out){
|
virtual void HermOp(const Field &in, Field &out){
|
||||||
std::cout << GridLogIterative << " HermOp "<<std::endl;
|
ncall++;
|
||||||
Mpc(in,out);
|
tMpc-=usecond();
|
||||||
|
_Mat.Meooe(in,out);
|
||||||
|
_Mat.Meooe(out,tmp);
|
||||||
|
tMpc+=usecond();
|
||||||
|
taxpby_norm-=usecond();
|
||||||
|
axpby(out,-1.0,mass*mass,tmp,in);
|
||||||
|
taxpby_norm+=usecond();
|
||||||
}
|
}
|
||||||
virtual RealD Mpc (const Field &in, Field &out) {
|
virtual RealD Mpc (const Field &in, Field &out) {
|
||||||
Field tmp(in._grid);
|
tMeo-=usecond();
|
||||||
Field tmp2(in._grid);
|
|
||||||
|
|
||||||
std::cout << GridLogIterative << " HermOp.Mpc "<<std::endl;
|
|
||||||
_Mat.Mooee(in,out);
|
|
||||||
_Mat.Mooee(out,tmp);
|
|
||||||
std::cout << GridLogIterative << " HermOp.MooeeMooee "<<std::endl;
|
|
||||||
|
|
||||||
_Mat.Meooe(in,out);
|
_Mat.Meooe(in,out);
|
||||||
_Mat.Meooe(out,tmp2);
|
_Mat.Meooe(out,tmp);
|
||||||
std::cout << GridLogIterative << " HermOp.MeooeMeooe "<<std::endl;
|
tMeo+=usecond();
|
||||||
|
taxpby_norm-=usecond();
|
||||||
RealD nn=axpy_norm(out,-1.0,tmp2,tmp);
|
RealD nn=axpby_norm(out,-1.0,mass*mass,tmp,in);
|
||||||
std::cout << GridLogIterative << " HermOp.axpy_norm "<<std::endl;
|
taxpby_norm+=usecond();
|
||||||
return nn;
|
return nn;
|
||||||
}
|
}
|
||||||
virtual RealD MpcDag (const Field &in, Field &out){
|
virtual RealD MpcDag (const Field &in, Field &out){
|
||||||
@@ -357,6 +380,12 @@ namespace Grid {
|
|||||||
template<class Field> class OperatorFunction {
|
template<class Field> class OperatorFunction {
|
||||||
public:
|
public:
|
||||||
virtual void operator() (LinearOperatorBase<Field> &Linop, const Field &in, Field &out) = 0;
|
virtual void operator() (LinearOperatorBase<Field> &Linop, const Field &in, Field &out) = 0;
|
||||||
|
virtual void operator() (LinearOperatorBase<Field> &Linop, const std::vector<Field> &in,std::vector<Field> &out) {
|
||||||
|
assert(in.size()==out.size());
|
||||||
|
for(int k=0;k<in.size();k++){
|
||||||
|
(*this)(Linop,in[k],out[k]);
|
||||||
|
}
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
template<class Field> class LinearFunction {
|
template<class Field> class LinearFunction {
|
||||||
File renamed without changes.
@@ -55,6 +55,14 @@ namespace Grid {
|
|||||||
template<class Field> class CheckerBoardedSparseMatrixBase : public SparseMatrixBase<Field> {
|
template<class Field> class CheckerBoardedSparseMatrixBase : public SparseMatrixBase<Field> {
|
||||||
public:
|
public:
|
||||||
virtual GridBase *RedBlackGrid(void)=0;
|
virtual GridBase *RedBlackGrid(void)=0;
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
// Query the even even properties to make algorithmic decisions
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
virtual RealD Mass(void) { return 0.0; };
|
||||||
|
virtual int ConstEE(void) { return 0; }; // Disable assumptions unless overridden
|
||||||
|
virtual int isTrivialEE(void) { return 0; }; // by a derived class that knows better
|
||||||
|
|
||||||
// half checkerboard operaions
|
// half checkerboard operaions
|
||||||
virtual void Meooe (const Field &in, Field &out)=0;
|
virtual void Meooe (const Field &in, Field &out)=0;
|
||||||
virtual void Mooee (const Field &in, Field &out)=0;
|
virtual void Mooee (const Field &in, Field &out)=0;
|
||||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
+269
-177
@@ -33,7 +33,7 @@ directory
|
|||||||
|
|
||||||
namespace Grid {
|
namespace Grid {
|
||||||
|
|
||||||
enum BlockCGtype { BlockCG, BlockCGrQ, CGmultiRHS };
|
enum BlockCGtype { BlockCG, BlockCGrQ, CGmultiRHS, BlockCGVec, BlockCGrQVec };
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
// Block conjugate gradient. Dimension zero should be the block direction
|
// Block conjugate gradient. Dimension zero should be the block direction
|
||||||
@@ -42,7 +42,6 @@ template <class Field>
|
|||||||
class BlockConjugateGradient : public OperatorFunction<Field> {
|
class BlockConjugateGradient : public OperatorFunction<Field> {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
|
||||||
typedef typename Field::scalar_type scomplex;
|
typedef typename Field::scalar_type scomplex;
|
||||||
|
|
||||||
int blockDim ;
|
int blockDim ;
|
||||||
@@ -54,21 +53,15 @@ class BlockConjugateGradient : public OperatorFunction<Field> {
|
|||||||
RealD Tolerance;
|
RealD Tolerance;
|
||||||
Integer MaxIterations;
|
Integer MaxIterations;
|
||||||
Integer IterationsToComplete; //Number of iterations the CG took to finish. Filled in upon completion
|
Integer IterationsToComplete; //Number of iterations the CG took to finish. Filled in upon completion
|
||||||
|
Integer PrintInterval; //GridLogMessages or Iterative
|
||||||
|
|
||||||
BlockConjugateGradient(BlockCGtype cgtype,int _Orthog,RealD tol, Integer maxit, bool err_on_no_conv = true)
|
BlockConjugateGradient(BlockCGtype cgtype,int _Orthog,RealD tol, Integer maxit, bool err_on_no_conv = true)
|
||||||
: Tolerance(tol), CGtype(cgtype), blockDim(_Orthog), MaxIterations(maxit), ErrorOnNoConverge(err_on_no_conv)
|
: Tolerance(tol), CGtype(cgtype), blockDim(_Orthog), MaxIterations(maxit), ErrorOnNoConverge(err_on_no_conv),PrintInterval(100)
|
||||||
{};
|
{};
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// Thin QR factorisation (google it)
|
// Thin QR factorisation (google it)
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
void ThinQRfact (Eigen::MatrixXcd &m_rr,
|
|
||||||
Eigen::MatrixXcd &C,
|
|
||||||
Eigen::MatrixXcd &Cinv,
|
|
||||||
Field & Q,
|
|
||||||
const Field & R)
|
|
||||||
{
|
|
||||||
int Orthog = blockDim; // First dimension is block dim; this is an assumption
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
//Dimensions
|
//Dimensions
|
||||||
// R_{ferm x Nblock} = Q_{ferm x Nblock} x C_{Nblock x Nblock} -> ferm x Nblock
|
// R_{ferm x Nblock} = Q_{ferm x Nblock} x C_{Nblock x Nblock} -> ferm x Nblock
|
||||||
@@ -85,22 +78,20 @@ void ThinQRfact (Eigen::MatrixXcd &m_rr,
|
|||||||
// Cdag C = Rdag R ; passes.
|
// Cdag C = Rdag R ; passes.
|
||||||
// QdagQ = 1 ; passes
|
// QdagQ = 1 ; passes
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void ThinQRfact (Eigen::MatrixXcd &m_rr,
|
||||||
|
Eigen::MatrixXcd &C,
|
||||||
|
Eigen::MatrixXcd &Cinv,
|
||||||
|
Field & Q,
|
||||||
|
const Field & R)
|
||||||
|
{
|
||||||
|
int Orthog = blockDim; // First dimension is block dim; this is an assumption
|
||||||
sliceInnerProductMatrix(m_rr,R,R,Orthog);
|
sliceInnerProductMatrix(m_rr,R,R,Orthog);
|
||||||
|
|
||||||
// Force manifest hermitian to avoid rounding related
|
// Force manifest hermitian to avoid rounding related
|
||||||
m_rr = 0.5*(m_rr+m_rr.adjoint());
|
m_rr = 0.5*(m_rr+m_rr.adjoint());
|
||||||
|
|
||||||
#if 0
|
|
||||||
std::cout << " Calling Cholesky ldlt on m_rr " << m_rr <<std::endl;
|
|
||||||
Eigen::MatrixXcd L_ldlt = m_rr.ldlt().matrixL();
|
|
||||||
std::cout << " Called Cholesky ldlt on m_rr " << L_ldlt <<std::endl;
|
|
||||||
auto D_ldlt = m_rr.ldlt().vectorD();
|
|
||||||
std::cout << " Called Cholesky ldlt on m_rr " << D_ldlt <<std::endl;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// std::cout << " Calling Cholesky llt on m_rr " <<std::endl;
|
|
||||||
Eigen::MatrixXcd L = m_rr.llt().matrixL();
|
Eigen::MatrixXcd L = m_rr.llt().matrixL();
|
||||||
// std::cout << " Called Cholesky llt on m_rr " << L <<std::endl;
|
|
||||||
C = L.adjoint();
|
C = L.adjoint();
|
||||||
Cinv = C.inverse();
|
Cinv = C.inverse();
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
@@ -112,6 +103,25 @@ void ThinQRfact (Eigen::MatrixXcd &m_rr,
|
|||||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
sliceMulMatrix(Q,Cinv,R,Orthog);
|
sliceMulMatrix(Q,Cinv,R,Orthog);
|
||||||
}
|
}
|
||||||
|
// see comments above
|
||||||
|
void ThinQRfact (Eigen::MatrixXcd &m_rr,
|
||||||
|
Eigen::MatrixXcd &C,
|
||||||
|
Eigen::MatrixXcd &Cinv,
|
||||||
|
std::vector<Field> & Q,
|
||||||
|
const std::vector<Field> & R)
|
||||||
|
{
|
||||||
|
InnerProductMatrix(m_rr,R,R);
|
||||||
|
|
||||||
|
m_rr = 0.5*(m_rr+m_rr.adjoint());
|
||||||
|
|
||||||
|
Eigen::MatrixXcd L = m_rr.llt().matrixL();
|
||||||
|
|
||||||
|
C = L.adjoint();
|
||||||
|
Cinv = C.inverse();
|
||||||
|
|
||||||
|
MulMatrix(Q,Cinv,R);
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// Call one of several implementations
|
// Call one of several implementations
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
@@ -119,14 +129,20 @@ void operator()(LinearOperatorBase<Field> &Linop, const Field &Src, Field &Psi)
|
|||||||
{
|
{
|
||||||
if ( CGtype == BlockCGrQ ) {
|
if ( CGtype == BlockCGrQ ) {
|
||||||
BlockCGrQsolve(Linop,Src,Psi);
|
BlockCGrQsolve(Linop,Src,Psi);
|
||||||
} else if (CGtype == BlockCG ) {
|
|
||||||
BlockCGsolve(Linop,Src,Psi);
|
|
||||||
} else if (CGtype == CGmultiRHS ) {
|
} else if (CGtype == CGmultiRHS ) {
|
||||||
CGmultiRHSsolve(Linop,Src,Psi);
|
CGmultiRHSsolve(Linop,Src,Psi);
|
||||||
} else {
|
} else {
|
||||||
assert(0);
|
assert(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
virtual void operator()(LinearOperatorBase<Field> &Linop, const std::vector<Field> &Src, std::vector<Field> &Psi)
|
||||||
|
{
|
||||||
|
if ( CGtype == BlockCGrQVec ) {
|
||||||
|
BlockCGrQsolveVec(Linop,Src,Psi);
|
||||||
|
} else {
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////
|
||||||
// BlockCGrQ implementation:
|
// BlockCGrQ implementation:
|
||||||
@@ -139,7 +155,8 @@ void BlockCGrQsolve(LinearOperatorBase<Field> &Linop, const Field &B, Field &X)
|
|||||||
{
|
{
|
||||||
int Orthog = blockDim; // First dimension is block dim; this is an assumption
|
int Orthog = blockDim; // First dimension is block dim; this is an assumption
|
||||||
Nblock = B._grid->_fdimensions[Orthog];
|
Nblock = B._grid->_fdimensions[Orthog];
|
||||||
|
/* FAKE */
|
||||||
|
Nblock=8;
|
||||||
std::cout<<GridLogMessage<<" Block Conjugate Gradient : Orthog "<<Orthog<<" Nblock "<<Nblock<<std::endl;
|
std::cout<<GridLogMessage<<" Block Conjugate Gradient : Orthog "<<Orthog<<" Nblock "<<Nblock<<std::endl;
|
||||||
|
|
||||||
X.checkerboard = B.checkerboard;
|
X.checkerboard = B.checkerboard;
|
||||||
@@ -202,15 +219,10 @@ void BlockCGrQsolve(LinearOperatorBase<Field> &Linop, const Field &B, Field &X)
|
|||||||
std::cout << GridLogMessage<<"BlockCGrQ algorithm initialisation " <<std::endl;
|
std::cout << GridLogMessage<<"BlockCGrQ algorithm initialisation " <<std::endl;
|
||||||
|
|
||||||
//1. QC = R = B-AX, D = Q ; QC => Thin QR factorisation (google it)
|
//1. QC = R = B-AX, D = Q ; QC => Thin QR factorisation (google it)
|
||||||
|
|
||||||
Linop.HermOp(X, AD);
|
Linop.HermOp(X, AD);
|
||||||
tmp = B - AD;
|
tmp = B - AD;
|
||||||
//std::cout << GridLogMessage << " initial tmp " << norm2(tmp)<< std::endl;
|
|
||||||
ThinQRfact (m_rr, m_C, m_Cinv, Q, tmp);
|
ThinQRfact (m_rr, m_C, m_Cinv, Q, tmp);
|
||||||
//std::cout << GridLogMessage << " initial Q " << norm2(Q)<< std::endl;
|
|
||||||
//std::cout << GridLogMessage << " m_rr " << m_rr<<std::endl;
|
|
||||||
//std::cout << GridLogMessage << " m_C " << m_C<<std::endl;
|
|
||||||
//std::cout << GridLogMessage << " m_Cinv " << m_Cinv<<std::endl;
|
|
||||||
D=Q;
|
D=Q;
|
||||||
|
|
||||||
std::cout << GridLogMessage<<"BlockCGrQ computed initial residual and QR fact " <<std::endl;
|
std::cout << GridLogMessage<<"BlockCGrQ computed initial residual and QR fact " <<std::endl;
|
||||||
@@ -232,14 +244,12 @@ void BlockCGrQsolve(LinearOperatorBase<Field> &Linop, const Field &B, Field &X)
|
|||||||
MatrixTimer.Start();
|
MatrixTimer.Start();
|
||||||
Linop.HermOp(D, Z);
|
Linop.HermOp(D, Z);
|
||||||
MatrixTimer.Stop();
|
MatrixTimer.Stop();
|
||||||
//std::cout << GridLogMessage << " norm2 Z " <<norm2(Z)<<std::endl;
|
|
||||||
|
|
||||||
//4. M = [D^dag Z]^{-1}
|
//4. M = [D^dag Z]^{-1}
|
||||||
sliceInnerTimer.Start();
|
sliceInnerTimer.Start();
|
||||||
sliceInnerProductMatrix(m_DZ,D,Z,Orthog);
|
sliceInnerProductMatrix(m_DZ,D,Z,Orthog);
|
||||||
sliceInnerTimer.Stop();
|
sliceInnerTimer.Stop();
|
||||||
m_M = m_DZ.inverse();
|
m_M = m_DZ.inverse();
|
||||||
//std::cout << GridLogMessage << " m_DZ " <<m_DZ<<std::endl;
|
|
||||||
|
|
||||||
//5. X = X + D MC
|
//5. X = X + D MC
|
||||||
m_tmp = m_M * m_C;
|
m_tmp = m_M * m_C;
|
||||||
@@ -257,6 +267,7 @@ void BlockCGrQsolve(LinearOperatorBase<Field> &Linop, const Field &B, Field &X)
|
|||||||
|
|
||||||
//7. D = Q + D S^dag
|
//7. D = Q + D S^dag
|
||||||
m_tmp = m_S.adjoint();
|
m_tmp = m_S.adjoint();
|
||||||
|
|
||||||
sliceMaddTimer.Start();
|
sliceMaddTimer.Start();
|
||||||
sliceMaddMatrix(D,m_tmp,D,Q,Orthog);
|
sliceMaddMatrix(D,m_tmp,D,Q,Orthog);
|
||||||
sliceMaddTimer.Stop();
|
sliceMaddTimer.Stop();
|
||||||
@@ -317,152 +328,6 @@ void BlockCGrQsolve(LinearOperatorBase<Field> &Linop, const Field &B, Field &X)
|
|||||||
IterationsToComplete = k;
|
IterationsToComplete = k;
|
||||||
}
|
}
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
// Block conjugate gradient; Original O'Leary Dimension zero should be the block direction
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
|
||||||
void BlockCGsolve(LinearOperatorBase<Field> &Linop, const Field &Src, Field &Psi)
|
|
||||||
{
|
|
||||||
int Orthog = blockDim; // First dimension is block dim; this is an assumption
|
|
||||||
Nblock = Src._grid->_fdimensions[Orthog];
|
|
||||||
|
|
||||||
std::cout<<GridLogMessage<<" Block Conjugate Gradient : Orthog "<<Orthog<<" Nblock "<<Nblock<<std::endl;
|
|
||||||
|
|
||||||
Psi.checkerboard = Src.checkerboard;
|
|
||||||
conformable(Psi, Src);
|
|
||||||
|
|
||||||
Field P(Src);
|
|
||||||
Field AP(Src);
|
|
||||||
Field R(Src);
|
|
||||||
|
|
||||||
Eigen::MatrixXcd m_pAp = Eigen::MatrixXcd::Identity(Nblock,Nblock);
|
|
||||||
Eigen::MatrixXcd m_pAp_inv= Eigen::MatrixXcd::Identity(Nblock,Nblock);
|
|
||||||
Eigen::MatrixXcd m_rr = Eigen::MatrixXcd::Zero(Nblock,Nblock);
|
|
||||||
Eigen::MatrixXcd m_rr_inv = Eigen::MatrixXcd::Zero(Nblock,Nblock);
|
|
||||||
|
|
||||||
Eigen::MatrixXcd m_alpha = Eigen::MatrixXcd::Zero(Nblock,Nblock);
|
|
||||||
Eigen::MatrixXcd m_beta = Eigen::MatrixXcd::Zero(Nblock,Nblock);
|
|
||||||
|
|
||||||
// Initial residual computation & set up
|
|
||||||
std::vector<RealD> residuals(Nblock);
|
|
||||||
std::vector<RealD> ssq(Nblock);
|
|
||||||
|
|
||||||
sliceNorm(ssq,Src,Orthog);
|
|
||||||
RealD sssum=0;
|
|
||||||
for(int b=0;b<Nblock;b++) sssum+=ssq[b];
|
|
||||||
|
|
||||||
sliceNorm(residuals,Src,Orthog);
|
|
||||||
for(int b=0;b<Nblock;b++){ assert(std::isnan(residuals[b])==0); }
|
|
||||||
|
|
||||||
sliceNorm(residuals,Psi,Orthog);
|
|
||||||
for(int b=0;b<Nblock;b++){ assert(std::isnan(residuals[b])==0); }
|
|
||||||
|
|
||||||
// Initial search dir is guess
|
|
||||||
Linop.HermOp(Psi, AP);
|
|
||||||
|
|
||||||
|
|
||||||
/************************************************************************
|
|
||||||
* Block conjugate gradient (Stephen Pickles, thesis 1995, pp 71, O Leary 1980)
|
|
||||||
************************************************************************
|
|
||||||
* O'Leary : R = B - A X
|
|
||||||
* O'Leary : P = M R ; preconditioner M = 1
|
|
||||||
* O'Leary : alpha = PAP^{-1} RMR
|
|
||||||
* O'Leary : beta = RMR^{-1}_old RMR_new
|
|
||||||
* O'Leary : X=X+Palpha
|
|
||||||
* O'Leary : R_new=R_old-AP alpha
|
|
||||||
* O'Leary : P=MR_new+P beta
|
|
||||||
*/
|
|
||||||
|
|
||||||
R = Src - AP;
|
|
||||||
P = R;
|
|
||||||
sliceInnerProductMatrix(m_rr,R,R,Orthog);
|
|
||||||
|
|
||||||
GridStopWatch sliceInnerTimer;
|
|
||||||
GridStopWatch sliceMaddTimer;
|
|
||||||
GridStopWatch MatrixTimer;
|
|
||||||
GridStopWatch SolverTimer;
|
|
||||||
SolverTimer.Start();
|
|
||||||
|
|
||||||
int k;
|
|
||||||
for (k = 1; k <= MaxIterations; k++) {
|
|
||||||
|
|
||||||
RealD rrsum=0;
|
|
||||||
for(int b=0;b<Nblock;b++) rrsum+=real(m_rr(b,b));
|
|
||||||
|
|
||||||
std::cout << GridLogIterative << "\titeration "<<k<<" rr_sum "<<rrsum<<" ssq_sum "<< sssum
|
|
||||||
<<" / "<<std::sqrt(rrsum/sssum) <<std::endl;
|
|
||||||
|
|
||||||
MatrixTimer.Start();
|
|
||||||
Linop.HermOp(P, AP);
|
|
||||||
MatrixTimer.Stop();
|
|
||||||
|
|
||||||
// Alpha
|
|
||||||
sliceInnerTimer.Start();
|
|
||||||
sliceInnerProductMatrix(m_pAp,P,AP,Orthog);
|
|
||||||
sliceInnerTimer.Stop();
|
|
||||||
m_pAp_inv = m_pAp.inverse();
|
|
||||||
m_alpha = m_pAp_inv * m_rr ;
|
|
||||||
|
|
||||||
// Psi, R update
|
|
||||||
sliceMaddTimer.Start();
|
|
||||||
sliceMaddMatrix(Psi,m_alpha, P,Psi,Orthog); // add alpha * P to psi
|
|
||||||
sliceMaddMatrix(R ,m_alpha,AP, R,Orthog,-1.0);// sub alpha * AP to resid
|
|
||||||
sliceMaddTimer.Stop();
|
|
||||||
|
|
||||||
// Beta
|
|
||||||
m_rr_inv = m_rr.inverse();
|
|
||||||
sliceInnerTimer.Start();
|
|
||||||
sliceInnerProductMatrix(m_rr,R,R,Orthog);
|
|
||||||
sliceInnerTimer.Stop();
|
|
||||||
m_beta = m_rr_inv *m_rr;
|
|
||||||
|
|
||||||
// Search update
|
|
||||||
sliceMaddTimer.Start();
|
|
||||||
sliceMaddMatrix(AP,m_beta,P,R,Orthog);
|
|
||||||
sliceMaddTimer.Stop();
|
|
||||||
P= AP;
|
|
||||||
|
|
||||||
/*********************
|
|
||||||
* convergence monitor
|
|
||||||
*********************
|
|
||||||
*/
|
|
||||||
RealD max_resid=0;
|
|
||||||
RealD rr;
|
|
||||||
for(int b=0;b<Nblock;b++){
|
|
||||||
rr = real(m_rr(b,b))/ssq[b];
|
|
||||||
if ( rr > max_resid ) max_resid = rr;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( max_resid < Tolerance*Tolerance ) {
|
|
||||||
|
|
||||||
SolverTimer.Stop();
|
|
||||||
|
|
||||||
std::cout << GridLogMessage<<"BlockCG converged in "<<k<<" iterations"<<std::endl;
|
|
||||||
for(int b=0;b<Nblock;b++){
|
|
||||||
std::cout << GridLogMessage<< "\t\tblock "<<b<<" computed resid "
|
|
||||||
<< std::sqrt(real(m_rr(b,b))/ssq[b])<<std::endl;
|
|
||||||
}
|
|
||||||
std::cout << GridLogMessage<<"\tMax residual is "<<std::sqrt(max_resid)<<std::endl;
|
|
||||||
|
|
||||||
Linop.HermOp(Psi, AP);
|
|
||||||
AP = AP-Src;
|
|
||||||
std::cout << GridLogMessage <<"\t True residual is " << std::sqrt(norm2(AP)/norm2(Src)) <<std::endl;
|
|
||||||
|
|
||||||
std::cout << GridLogMessage << "Time Breakdown "<<std::endl;
|
|
||||||
std::cout << GridLogMessage << "\tElapsed " << SolverTimer.Elapsed() <<std::endl;
|
|
||||||
std::cout << GridLogMessage << "\tMatrix " << MatrixTimer.Elapsed() <<std::endl;
|
|
||||||
std::cout << GridLogMessage << "\tInnerProd " << sliceInnerTimer.Elapsed() <<std::endl;
|
|
||||||
std::cout << GridLogMessage << "\tMaddMatrix " << sliceMaddTimer.Elapsed() <<std::endl;
|
|
||||||
|
|
||||||
IterationsToComplete = k;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
std::cout << GridLogMessage << "BlockConjugateGradient did NOT converge" << std::endl;
|
|
||||||
|
|
||||||
if (ErrorOnNoConverge) assert(0);
|
|
||||||
IterationsToComplete = k;
|
|
||||||
}
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
|
||||||
// multiRHS conjugate gradient. Dimension zero should be the block direction
|
// multiRHS conjugate gradient. Dimension zero should be the block direction
|
||||||
// Use this for spread out across nodes
|
// Use this for spread out across nodes
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
@@ -600,6 +465,233 @@ void CGmultiRHSsolve(LinearOperatorBase<Field> &Linop, const Field &Src, Field &
|
|||||||
IterationsToComplete = k;
|
IterationsToComplete = k;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void InnerProductMatrix(Eigen::MatrixXcd &m , const std::vector<Field> &X, const std::vector<Field> &Y){
|
||||||
|
for(int b=0;b<Nblock;b++){
|
||||||
|
for(int bp=0;bp<Nblock;bp++) {
|
||||||
|
m(b,bp) = innerProduct(X[b],Y[bp]);
|
||||||
|
}}
|
||||||
|
}
|
||||||
|
void MaddMatrix(std::vector<Field> &AP, Eigen::MatrixXcd &m , const std::vector<Field> &X,const std::vector<Field> &Y,RealD scale=1.0){
|
||||||
|
// Should make this cache friendly with site outermost, parallel_for
|
||||||
|
// Deal with case AP aliases with either Y or X
|
||||||
|
std::vector<Field> tmp(Nblock,X[0]);
|
||||||
|
for(int b=0;b<Nblock;b++){
|
||||||
|
tmp[b] = Y[b];
|
||||||
|
for(int bp=0;bp<Nblock;bp++) {
|
||||||
|
tmp[b] = tmp[b] + (scale*m(bp,b))*X[bp];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for(int b=0;b<Nblock;b++){
|
||||||
|
AP[b] = tmp[b];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void MulMatrix(std::vector<Field> &AP, Eigen::MatrixXcd &m , const std::vector<Field> &X){
|
||||||
|
// Should make this cache friendly with site outermost, parallel_for
|
||||||
|
for(int b=0;b<Nblock;b++){
|
||||||
|
AP[b] = zero;
|
||||||
|
for(int bp=0;bp<Nblock;bp++) {
|
||||||
|
AP[b] += (m(bp,b))*X[bp];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
double normv(const std::vector<Field> &P){
|
||||||
|
double nn = 0.0;
|
||||||
|
for(int b=0;b<Nblock;b++) {
|
||||||
|
nn+=norm2(P[b]);
|
||||||
|
}
|
||||||
|
return nn;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
// BlockCGrQvec implementation:
|
||||||
|
//--------------------------
|
||||||
|
// X is guess/Solution
|
||||||
|
// B is RHS
|
||||||
|
// Solve A X_i = B_i ; i refers to Nblock index
|
||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
void BlockCGrQsolveVec(LinearOperatorBase<Field> &Linop, const std::vector<Field> &B, std::vector<Field> &X)
|
||||||
|
{
|
||||||
|
Nblock = B.size();
|
||||||
|
assert(Nblock == X.size());
|
||||||
|
|
||||||
|
std::cout<<GridLogMessage<<" Block Conjugate Gradient Vec rQ : Nblock "<<Nblock<<std::endl;
|
||||||
|
|
||||||
|
for(int b=0;b<Nblock;b++){
|
||||||
|
X[b].checkerboard = B[b].checkerboard;
|
||||||
|
conformable(X[b], B[b]);
|
||||||
|
conformable(X[b], X[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
Field Fake(B[0]);
|
||||||
|
|
||||||
|
std::vector<Field> tmp(Nblock,Fake);
|
||||||
|
std::vector<Field> Q(Nblock,Fake);
|
||||||
|
std::vector<Field> D(Nblock,Fake);
|
||||||
|
std::vector<Field> Z(Nblock,Fake);
|
||||||
|
std::vector<Field> AD(Nblock,Fake);
|
||||||
|
|
||||||
|
Eigen::MatrixXcd m_DZ = Eigen::MatrixXcd::Identity(Nblock,Nblock);
|
||||||
|
Eigen::MatrixXcd m_M = Eigen::MatrixXcd::Identity(Nblock,Nblock);
|
||||||
|
Eigen::MatrixXcd m_rr = Eigen::MatrixXcd::Zero(Nblock,Nblock);
|
||||||
|
|
||||||
|
Eigen::MatrixXcd m_C = Eigen::MatrixXcd::Zero(Nblock,Nblock);
|
||||||
|
Eigen::MatrixXcd m_Cinv = Eigen::MatrixXcd::Zero(Nblock,Nblock);
|
||||||
|
Eigen::MatrixXcd m_S = Eigen::MatrixXcd::Zero(Nblock,Nblock);
|
||||||
|
Eigen::MatrixXcd m_Sinv = Eigen::MatrixXcd::Zero(Nblock,Nblock);
|
||||||
|
|
||||||
|
Eigen::MatrixXcd m_tmp = Eigen::MatrixXcd::Identity(Nblock,Nblock);
|
||||||
|
Eigen::MatrixXcd m_tmp1 = Eigen::MatrixXcd::Identity(Nblock,Nblock);
|
||||||
|
|
||||||
|
// Initial residual computation & set up
|
||||||
|
std::vector<RealD> residuals(Nblock);
|
||||||
|
std::vector<RealD> ssq(Nblock);
|
||||||
|
|
||||||
|
RealD sssum=0;
|
||||||
|
for(int b=0;b<Nblock;b++){ ssq[b] = norm2(B[b]);}
|
||||||
|
for(int b=0;b<Nblock;b++) sssum+=ssq[b];
|
||||||
|
|
||||||
|
for(int b=0;b<Nblock;b++){ residuals[b] = norm2(B[b]);}
|
||||||
|
for(int b=0;b<Nblock;b++){ assert(std::isnan(residuals[b])==0); }
|
||||||
|
|
||||||
|
for(int b=0;b<Nblock;b++){ residuals[b] = norm2(X[b]);}
|
||||||
|
for(int b=0;b<Nblock;b++){ assert(std::isnan(residuals[b])==0); }
|
||||||
|
|
||||||
|
/************************************************************************
|
||||||
|
* Block conjugate gradient rQ (Sebastien Birk Thesis, after Dubrulle 2001)
|
||||||
|
************************************************************************
|
||||||
|
* Dimensions:
|
||||||
|
*
|
||||||
|
* X,B==(Nferm x Nblock)
|
||||||
|
* A==(Nferm x Nferm)
|
||||||
|
*
|
||||||
|
* Nferm = Nspin x Ncolour x Ncomplex x Nlattice_site
|
||||||
|
*
|
||||||
|
* QC = R = B-AX, D = Q ; QC => Thin QR factorisation (google it)
|
||||||
|
* for k:
|
||||||
|
* Z = AD
|
||||||
|
* M = [D^dag Z]^{-1}
|
||||||
|
* X = X + D MC
|
||||||
|
* QS = Q - ZM
|
||||||
|
* D = Q + D S^dag
|
||||||
|
* C = S C
|
||||||
|
*/
|
||||||
|
///////////////////////////////////////
|
||||||
|
// Initial block: initial search dir is guess
|
||||||
|
///////////////////////////////////////
|
||||||
|
std::cout << GridLogMessage<<"BlockCGrQvec algorithm initialisation " <<std::endl;
|
||||||
|
|
||||||
|
//1. QC = R = B-AX, D = Q ; QC => Thin QR factorisation (google it)
|
||||||
|
for(int b=0;b<Nblock;b++) {
|
||||||
|
Linop.HermOp(X[b], AD[b]);
|
||||||
|
tmp[b] = B[b] - AD[b];
|
||||||
|
}
|
||||||
|
|
||||||
|
ThinQRfact (m_rr, m_C, m_Cinv, Q, tmp);
|
||||||
|
|
||||||
|
for(int b=0;b<Nblock;b++) D[b]=Q[b];
|
||||||
|
|
||||||
|
std::cout << GridLogMessage<<"BlockCGrQ vec computed initial residual and QR fact " <<std::endl;
|
||||||
|
|
||||||
|
///////////////////////////////////////
|
||||||
|
// Timers
|
||||||
|
///////////////////////////////////////
|
||||||
|
GridStopWatch sliceInnerTimer;
|
||||||
|
GridStopWatch sliceMaddTimer;
|
||||||
|
GridStopWatch QRTimer;
|
||||||
|
GridStopWatch MatrixTimer;
|
||||||
|
GridStopWatch SolverTimer;
|
||||||
|
SolverTimer.Start();
|
||||||
|
|
||||||
|
int k;
|
||||||
|
for (k = 1; k <= MaxIterations; k++) {
|
||||||
|
|
||||||
|
//3. Z = AD
|
||||||
|
MatrixTimer.Start();
|
||||||
|
for(int b=0;b<Nblock;b++) Linop.HermOp(D[b], Z[b]);
|
||||||
|
MatrixTimer.Stop();
|
||||||
|
|
||||||
|
//4. M = [D^dag Z]^{-1}
|
||||||
|
sliceInnerTimer.Start();
|
||||||
|
InnerProductMatrix(m_DZ,D,Z);
|
||||||
|
sliceInnerTimer.Stop();
|
||||||
|
m_M = m_DZ.inverse();
|
||||||
|
|
||||||
|
//5. X = X + D MC
|
||||||
|
m_tmp = m_M * m_C;
|
||||||
|
sliceMaddTimer.Start();
|
||||||
|
MaddMatrix(X,m_tmp, D,X);
|
||||||
|
sliceMaddTimer.Stop();
|
||||||
|
|
||||||
|
//6. QS = Q - ZM
|
||||||
|
sliceMaddTimer.Start();
|
||||||
|
MaddMatrix(tmp,m_M,Z,Q,-1.0);
|
||||||
|
sliceMaddTimer.Stop();
|
||||||
|
QRTimer.Start();
|
||||||
|
ThinQRfact (m_rr, m_S, m_Sinv, Q, tmp);
|
||||||
|
QRTimer.Stop();
|
||||||
|
|
||||||
|
//7. D = Q + D S^dag
|
||||||
|
m_tmp = m_S.adjoint();
|
||||||
|
sliceMaddTimer.Start();
|
||||||
|
MaddMatrix(D,m_tmp,D,Q);
|
||||||
|
sliceMaddTimer.Stop();
|
||||||
|
|
||||||
|
//8. C = S C
|
||||||
|
m_C = m_S*m_C;
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
* convergence monitor
|
||||||
|
*********************
|
||||||
|
*/
|
||||||
|
m_rr = m_C.adjoint() * m_C;
|
||||||
|
|
||||||
|
RealD max_resid=0;
|
||||||
|
RealD rrsum=0;
|
||||||
|
RealD rr;
|
||||||
|
|
||||||
|
for(int b=0;b<Nblock;b++) {
|
||||||
|
rrsum+=real(m_rr(b,b));
|
||||||
|
rr = real(m_rr(b,b))/ssq[b];
|
||||||
|
if ( rr > max_resid ) max_resid = rr;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << GridLogIterative << "\t Block Iteration "<<k<<" ave resid "<< sqrt(rrsum/sssum) << " max "<< sqrt(max_resid) <<std::endl;
|
||||||
|
|
||||||
|
if ( max_resid < Tolerance*Tolerance ) {
|
||||||
|
|
||||||
|
SolverTimer.Stop();
|
||||||
|
|
||||||
|
std::cout << GridLogMessage<<"BlockCGrQ converged in "<<k<<" iterations"<<std::endl;
|
||||||
|
|
||||||
|
for(int b=0;b<Nblock;b++){
|
||||||
|
std::cout << GridLogMessage<< "\t\tblock "<<b<<" computed resid "<< std::sqrt(real(m_rr(b,b))/ssq[b])<<std::endl;
|
||||||
|
}
|
||||||
|
std::cout << GridLogMessage<<"\tMax residual is "<<std::sqrt(max_resid)<<std::endl;
|
||||||
|
|
||||||
|
for(int b=0;b<Nblock;b++) Linop.HermOp(X[b], AD[b]);
|
||||||
|
for(int b=0;b<Nblock;b++) AD[b] = AD[b]-B[b];
|
||||||
|
std::cout << GridLogMessage <<"\t True residual is " << std::sqrt(normv(AD)/normv(B)) <<std::endl;
|
||||||
|
|
||||||
|
std::cout << GridLogMessage << "Time Breakdown "<<std::endl;
|
||||||
|
std::cout << GridLogMessage << "\tElapsed " << SolverTimer.Elapsed() <<std::endl;
|
||||||
|
std::cout << GridLogMessage << "\tMatrix " << MatrixTimer.Elapsed() <<std::endl;
|
||||||
|
std::cout << GridLogMessage << "\tInnerProd " << sliceInnerTimer.Elapsed() <<std::endl;
|
||||||
|
std::cout << GridLogMessage << "\tMaddMatrix " << sliceMaddTimer.Elapsed() <<std::endl;
|
||||||
|
std::cout << GridLogMessage << "\tThinQRfact " << QRTimer.Elapsed() <<std::endl;
|
||||||
|
|
||||||
|
IterationsToComplete = k;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
std::cout << GridLogMessage << "BlockConjugateGradient(rQ) did NOT converge" << std::endl;
|
||||||
|
|
||||||
|
if (ErrorOnNoConverge) assert(0);
|
||||||
|
IterationsToComplete = k;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,244 @@
|
|||||||
|
/*************************************************************************************
|
||||||
|
|
||||||
|
Grid physics library, www.github.com/paboyle/Grid
|
||||||
|
|
||||||
|
Source file: ./lib/algorithms/iterative/CommunicationAvoidingGeneralisedMinimalResidual.h
|
||||||
|
|
||||||
|
Copyright (C) 2015
|
||||||
|
|
||||||
|
Author: Daniel Richtmann <daniel.richtmann@ur.de>
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License along
|
||||||
|
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
|
||||||
|
See the full license in the file "LICENSE" in the top level distribution
|
||||||
|
directory
|
||||||
|
*************************************************************************************/
|
||||||
|
/* END LEGAL */
|
||||||
|
#ifndef GRID_COMMUNICATION_AVOIDING_GENERALISED_MINIMAL_RESIDUAL_H
|
||||||
|
#define GRID_COMMUNICATION_AVOIDING_GENERALISED_MINIMAL_RESIDUAL_H
|
||||||
|
|
||||||
|
namespace Grid {
|
||||||
|
|
||||||
|
template<class Field>
|
||||||
|
class CommunicationAvoidingGeneralisedMinimalResidual : public OperatorFunction<Field> {
|
||||||
|
public:
|
||||||
|
bool ErrorOnNoConverge; // Throw an assert when CAGMRES fails to converge,
|
||||||
|
// defaults to true
|
||||||
|
|
||||||
|
RealD Tolerance;
|
||||||
|
|
||||||
|
Integer MaxIterations;
|
||||||
|
Integer RestartLength;
|
||||||
|
Integer MaxNumberOfRestarts;
|
||||||
|
Integer IterationCount; // Number of iterations the CAGMRES took to finish,
|
||||||
|
// filled in upon completion
|
||||||
|
|
||||||
|
GridStopWatch MatrixTimer;
|
||||||
|
GridStopWatch LinalgTimer;
|
||||||
|
GridStopWatch QrTimer;
|
||||||
|
GridStopWatch CompSolutionTimer;
|
||||||
|
|
||||||
|
Eigen::MatrixXcd H;
|
||||||
|
|
||||||
|
std::vector<std::complex<double>> y;
|
||||||
|
std::vector<std::complex<double>> gamma;
|
||||||
|
std::vector<std::complex<double>> c;
|
||||||
|
std::vector<std::complex<double>> s;
|
||||||
|
|
||||||
|
CommunicationAvoidingGeneralisedMinimalResidual(RealD tol,
|
||||||
|
Integer maxit,
|
||||||
|
Integer restart_length,
|
||||||
|
bool err_on_no_conv = true)
|
||||||
|
: Tolerance(tol)
|
||||||
|
, MaxIterations(maxit)
|
||||||
|
, RestartLength(restart_length)
|
||||||
|
, MaxNumberOfRestarts(MaxIterations/RestartLength + ((MaxIterations%RestartLength == 0) ? 0 : 1))
|
||||||
|
, ErrorOnNoConverge(err_on_no_conv)
|
||||||
|
, H(Eigen::MatrixXcd::Zero(RestartLength, RestartLength + 1)) // sizes taken from DD-αAMG code base
|
||||||
|
, y(RestartLength + 1, 0.)
|
||||||
|
, gamma(RestartLength + 1, 0.)
|
||||||
|
, c(RestartLength + 1, 0.)
|
||||||
|
, s(RestartLength + 1, 0.) {};
|
||||||
|
|
||||||
|
void operator()(LinearOperatorBase<Field> &LinOp, const Field &src, Field &psi) {
|
||||||
|
|
||||||
|
std::cout << GridLogWarning << "This algorithm currently doesn't differ from regular GMRES" << std::endl;
|
||||||
|
|
||||||
|
psi.checkerboard = src.checkerboard;
|
||||||
|
conformable(psi, src);
|
||||||
|
|
||||||
|
RealD guess = norm2(psi);
|
||||||
|
assert(std::isnan(guess) == 0);
|
||||||
|
|
||||||
|
RealD cp;
|
||||||
|
RealD ssq = norm2(src);
|
||||||
|
RealD rsq = Tolerance * Tolerance * ssq;
|
||||||
|
|
||||||
|
Field r(src._grid);
|
||||||
|
|
||||||
|
std::cout << std::setprecision(4) << std::scientific;
|
||||||
|
std::cout << GridLogIterative << "CommunicationAvoidingGeneralisedMinimalResidual: guess " << guess << std::endl;
|
||||||
|
std::cout << GridLogIterative << "CommunicationAvoidingGeneralisedMinimalResidual: src " << ssq << std::endl;
|
||||||
|
|
||||||
|
MatrixTimer.Reset();
|
||||||
|
LinalgTimer.Reset();
|
||||||
|
QrTimer.Reset();
|
||||||
|
CompSolutionTimer.Reset();
|
||||||
|
|
||||||
|
GridStopWatch SolverTimer;
|
||||||
|
SolverTimer.Start();
|
||||||
|
|
||||||
|
IterationCount = 0;
|
||||||
|
|
||||||
|
for (int k=0; k<MaxNumberOfRestarts; k++) {
|
||||||
|
|
||||||
|
cp = outerLoopBody(LinOp, src, psi, rsq);
|
||||||
|
|
||||||
|
// Stopping condition
|
||||||
|
if (cp <= rsq) {
|
||||||
|
|
||||||
|
SolverTimer.Stop();
|
||||||
|
|
||||||
|
LinOp.Op(psi,r);
|
||||||
|
axpy(r,-1.0,src,r);
|
||||||
|
|
||||||
|
RealD srcnorm = sqrt(ssq);
|
||||||
|
RealD resnorm = sqrt(norm2(r));
|
||||||
|
RealD true_residual = resnorm / srcnorm;
|
||||||
|
|
||||||
|
std::cout << GridLogMessage << "CommunicationAvoidingGeneralisedMinimalResidual: Converged on iteration " << IterationCount
|
||||||
|
<< " computed residual " << sqrt(cp / ssq)
|
||||||
|
<< " true residual " << true_residual
|
||||||
|
<< " target " << Tolerance << std::endl;
|
||||||
|
|
||||||
|
std::cout << GridLogMessage << "CAGMRES Time elapsed: Total " << SolverTimer.Elapsed() << std::endl;
|
||||||
|
std::cout << GridLogMessage << "CAGMRES Time elapsed: Matrix " << MatrixTimer.Elapsed() << std::endl;
|
||||||
|
std::cout << GridLogMessage << "CAGMRES Time elapsed: Linalg " << LinalgTimer.Elapsed() << std::endl;
|
||||||
|
std::cout << GridLogMessage << "CAGMRES Time elapsed: QR " << QrTimer.Elapsed() << std::endl;
|
||||||
|
std::cout << GridLogMessage << "CAGMRES Time elapsed: CompSol " << CompSolutionTimer.Elapsed() << std::endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << GridLogMessage << "CommunicationAvoidingGeneralisedMinimalResidual did NOT converge" << std::endl;
|
||||||
|
|
||||||
|
if (ErrorOnNoConverge)
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
RealD outerLoopBody(LinearOperatorBase<Field> &LinOp, const Field &src, Field &psi, RealD rsq) {
|
||||||
|
|
||||||
|
RealD cp = 0;
|
||||||
|
|
||||||
|
Field w(src._grid);
|
||||||
|
Field r(src._grid);
|
||||||
|
|
||||||
|
// this should probably be made a class member so that it is only allocated once, not in every restart
|
||||||
|
std::vector<Field> v(RestartLength + 1, src._grid); for (auto &elem : v) elem = zero;
|
||||||
|
|
||||||
|
MatrixTimer.Start();
|
||||||
|
LinOp.Op(psi, w);
|
||||||
|
MatrixTimer.Stop();
|
||||||
|
|
||||||
|
LinalgTimer.Start();
|
||||||
|
r = src - w;
|
||||||
|
|
||||||
|
gamma[0] = sqrt(norm2(r));
|
||||||
|
|
||||||
|
v[0] = (1. / gamma[0]) * r;
|
||||||
|
LinalgTimer.Stop();
|
||||||
|
|
||||||
|
for (int i=0; i<RestartLength; i++) {
|
||||||
|
|
||||||
|
IterationCount++;
|
||||||
|
|
||||||
|
arnoldiStep(LinOp, v, w, i);
|
||||||
|
|
||||||
|
qrUpdate(i);
|
||||||
|
|
||||||
|
cp = std::norm(gamma[i+1]);
|
||||||
|
|
||||||
|
std::cout << GridLogIterative << "CommunicationAvoidingGeneralisedMinimalResidual: Iteration " << IterationCount
|
||||||
|
<< " residual " << cp << " target " << rsq << std::endl;
|
||||||
|
|
||||||
|
if ((i == RestartLength - 1) || (IterationCount == MaxIterations) || (cp <= rsq)) {
|
||||||
|
|
||||||
|
computeSolution(v, psi, i);
|
||||||
|
|
||||||
|
return cp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(0); // Never reached
|
||||||
|
return cp;
|
||||||
|
}
|
||||||
|
|
||||||
|
void arnoldiStep(LinearOperatorBase<Field> &LinOp, std::vector<Field> &v, Field &w, int iter) {
|
||||||
|
|
||||||
|
MatrixTimer.Start();
|
||||||
|
LinOp.Op(v[iter], w);
|
||||||
|
MatrixTimer.Stop();
|
||||||
|
|
||||||
|
LinalgTimer.Start();
|
||||||
|
for (int i = 0; i <= iter; ++i) {
|
||||||
|
H(iter, i) = innerProduct(v[i], w);
|
||||||
|
w = w - H(iter, i) * v[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
H(iter, iter + 1) = sqrt(norm2(w));
|
||||||
|
v[iter + 1] = (1. / H(iter, iter + 1)) * w;
|
||||||
|
LinalgTimer.Stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
void qrUpdate(int iter) {
|
||||||
|
|
||||||
|
QrTimer.Start();
|
||||||
|
for (int i = 0; i < iter ; ++i) {
|
||||||
|
auto tmp = -s[i] * H(iter, i) + c[i] * H(iter, i + 1);
|
||||||
|
H(iter, i) = std::conj(c[i]) * H(iter, i) + std::conj(s[i]) * H(iter, i + 1);
|
||||||
|
H(iter, i + 1) = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute new Givens Rotation
|
||||||
|
ComplexD nu = sqrt(std::norm(H(iter, iter)) + std::norm(H(iter, iter + 1)));
|
||||||
|
c[iter] = H(iter, iter) / nu;
|
||||||
|
s[iter] = H(iter, iter + 1) / nu;
|
||||||
|
|
||||||
|
// Apply new Givens rotation
|
||||||
|
H(iter, iter) = nu;
|
||||||
|
H(iter, iter + 1) = 0.;
|
||||||
|
|
||||||
|
gamma[iter + 1] = -s[iter] * gamma[iter];
|
||||||
|
gamma[iter] = std::conj(c[iter]) * gamma[iter];
|
||||||
|
QrTimer.Stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
void computeSolution(std::vector<Field> const &v, Field &psi, int iter) {
|
||||||
|
|
||||||
|
CompSolutionTimer.Start();
|
||||||
|
for (int i = iter; i >= 0; i--) {
|
||||||
|
y[i] = gamma[i];
|
||||||
|
for (int k = i + 1; k <= iter; k++)
|
||||||
|
y[i] = y[i] - H(k, i) * y[k];
|
||||||
|
y[i] = y[i] / H(i, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i <= iter; i++)
|
||||||
|
psi = psi + v[i] * y[i];
|
||||||
|
CompSolutionTimer.Stop();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#endif
|
||||||
+22
-13
@@ -54,6 +54,7 @@ class ConjugateGradient : public OperatorFunction<Field> {
|
|||||||
|
|
||||||
void operator()(LinearOperatorBase<Field> &Linop, const Field &src, Field &psi) {
|
void operator()(LinearOperatorBase<Field> &Linop, const Field &src, Field &psi) {
|
||||||
|
|
||||||
|
|
||||||
psi.checkerboard = src.checkerboard;
|
psi.checkerboard = src.checkerboard;
|
||||||
conformable(psi, src);
|
conformable(psi, src);
|
||||||
|
|
||||||
@@ -70,7 +71,6 @@ class ConjugateGradient : public OperatorFunction<Field> {
|
|||||||
|
|
||||||
Linop.HermOpAndNorm(psi, mmp, d, b);
|
Linop.HermOpAndNorm(psi, mmp, d, b);
|
||||||
|
|
||||||
|
|
||||||
r = src - mmp;
|
r = src - mmp;
|
||||||
p = r;
|
p = r;
|
||||||
|
|
||||||
@@ -96,38 +96,44 @@ class ConjugateGradient : public OperatorFunction<Field> {
|
|||||||
<< "ConjugateGradient: k=0 residual " << cp << " target " << rsq << std::endl;
|
<< "ConjugateGradient: k=0 residual " << cp << " target " << rsq << std::endl;
|
||||||
|
|
||||||
GridStopWatch LinalgTimer;
|
GridStopWatch LinalgTimer;
|
||||||
|
GridStopWatch InnerTimer;
|
||||||
|
GridStopWatch AxpyNormTimer;
|
||||||
|
GridStopWatch LinearCombTimer;
|
||||||
GridStopWatch MatrixTimer;
|
GridStopWatch MatrixTimer;
|
||||||
GridStopWatch SolverTimer;
|
GridStopWatch SolverTimer;
|
||||||
|
|
||||||
SolverTimer.Start();
|
SolverTimer.Start();
|
||||||
int k;
|
int k;
|
||||||
for (k = 1; k <= MaxIterations; k++) {
|
for (k = 1; k <= MaxIterations*1000; k++) {
|
||||||
c = cp;
|
c = cp;
|
||||||
|
|
||||||
MatrixTimer.Start();
|
MatrixTimer.Start();
|
||||||
Linop.HermOpAndNorm(p, mmp, d, qq);
|
Linop.HermOp(p, mmp);
|
||||||
MatrixTimer.Stop();
|
MatrixTimer.Stop();
|
||||||
|
|
||||||
LinalgTimer.Start();
|
LinalgTimer.Start();
|
||||||
// RealD qqck = norm2(mmp);
|
|
||||||
// ComplexD dck = innerProduct(p,mmp);
|
|
||||||
|
|
||||||
|
InnerTimer.Start();
|
||||||
|
ComplexD dc = innerProduct(p,mmp);
|
||||||
|
InnerTimer.Stop();
|
||||||
|
d = dc.real();
|
||||||
a = c / d;
|
a = c / d;
|
||||||
b_pred = a * (a * qq - d) / c;
|
|
||||||
|
|
||||||
|
AxpyNormTimer.Start();
|
||||||
cp = axpy_norm(r, -a, mmp, r);
|
cp = axpy_norm(r, -a, mmp, r);
|
||||||
|
AxpyNormTimer.Stop();
|
||||||
b = cp / c;
|
b = cp / c;
|
||||||
|
|
||||||
// Fuse these loops ; should be really easy
|
LinearCombTimer.Start();
|
||||||
psi = a * p + psi;
|
parallel_for(int ss=0;ss<src._grid->oSites();ss++){
|
||||||
p = p * b + r;
|
vstream(psi[ss], a * p[ss] + psi[ss]);
|
||||||
|
vstream(p [ss], b * p[ss] + r[ss]);
|
||||||
|
}
|
||||||
|
LinearCombTimer.Stop();
|
||||||
LinalgTimer.Stop();
|
LinalgTimer.Stop();
|
||||||
|
|
||||||
std::cout << GridLogIterative << "ConjugateGradient: Iteration " << k
|
std::cout << GridLogIterative << "ConjugateGradient: Iteration " << k
|
||||||
<< " residual " << cp << " target " << rsq << std::endl;
|
<< " residual^2 " << sqrt(cp/ssq) << " target " << Tolerance << std::endl;
|
||||||
std::cout << GridLogDebug << "a = "<< a << " b_pred = "<< b_pred << " b = "<< b << std::endl;
|
|
||||||
std::cout << GridLogDebug << "qq = "<< qq << " d = "<< d << " c = "<< c << std::endl;
|
|
||||||
|
|
||||||
// Stopping condition
|
// Stopping condition
|
||||||
if (cp <= rsq) {
|
if (cp <= rsq) {
|
||||||
@@ -148,6 +154,9 @@ class ConjugateGradient : public OperatorFunction<Field> {
|
|||||||
std::cout << GridLogMessage << "\tElapsed " << SolverTimer.Elapsed() <<std::endl;
|
std::cout << GridLogMessage << "\tElapsed " << SolverTimer.Elapsed() <<std::endl;
|
||||||
std::cout << GridLogMessage << "\tMatrix " << MatrixTimer.Elapsed() <<std::endl;
|
std::cout << GridLogMessage << "\tMatrix " << MatrixTimer.Elapsed() <<std::endl;
|
||||||
std::cout << GridLogMessage << "\tLinalg " << LinalgTimer.Elapsed() <<std::endl;
|
std::cout << GridLogMessage << "\tLinalg " << LinalgTimer.Elapsed() <<std::endl;
|
||||||
|
std::cout << GridLogMessage << "\tInner " << InnerTimer.Elapsed() <<std::endl;
|
||||||
|
std::cout << GridLogMessage << "\tAxpyNorm " << AxpyNormTimer.Elapsed() <<std::endl;
|
||||||
|
std::cout << GridLogMessage << "\tLinearComb " << LinearCombTimer.Elapsed() <<std::endl;
|
||||||
|
|
||||||
if (ErrorOnNoConverge) assert(true_residual / Tolerance < 10000.0);
|
if (ErrorOnNoConverge) assert(true_residual / Tolerance < 10000.0);
|
||||||
|
|
||||||
File renamed without changes.
+41
-1
@@ -43,6 +43,7 @@ namespace Grid {
|
|||||||
public:
|
public:
|
||||||
RealD Tolerance;
|
RealD Tolerance;
|
||||||
Integer MaxIterations;
|
Integer MaxIterations;
|
||||||
|
Integer IterationsToComplete; //Number of iterations the CG took to finish. Filled in upon completion
|
||||||
int verbose;
|
int verbose;
|
||||||
MultiShiftFunction shifts;
|
MultiShiftFunction shifts;
|
||||||
|
|
||||||
@@ -164,6 +165,15 @@ void operator() (LinearOperatorBase<Field> &Linop, const Field &src, std::vector
|
|||||||
axpby(psi[s],0.,-bs[s]*alpha[s],src,src);
|
axpby(psi[s],0.,-bs[s]*alpha[s],src,src);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////
|
||||||
|
// Timers
|
||||||
|
///////////////////////////////////////
|
||||||
|
GridStopWatch AXPYTimer;
|
||||||
|
GridStopWatch ShiftTimer;
|
||||||
|
GridStopWatch QRTimer;
|
||||||
|
GridStopWatch MatrixTimer;
|
||||||
|
GridStopWatch SolverTimer;
|
||||||
|
SolverTimer.Start();
|
||||||
|
|
||||||
// Iteration loop
|
// Iteration loop
|
||||||
int k;
|
int k;
|
||||||
@@ -171,7 +181,9 @@ void operator() (LinearOperatorBase<Field> &Linop, const Field &src, std::vector
|
|||||||
for (k=1;k<=MaxIterations;k++){
|
for (k=1;k<=MaxIterations;k++){
|
||||||
|
|
||||||
a = c /cp;
|
a = c /cp;
|
||||||
|
AXPYTimer.Start();
|
||||||
axpy(p,a,p,r);
|
axpy(p,a,p,r);
|
||||||
|
AXPYTimer.Stop();
|
||||||
|
|
||||||
// Note to self - direction ps is iterated seperately
|
// Note to self - direction ps is iterated seperately
|
||||||
// for each shift. Does not appear to have any scope
|
// for each shift. Does not appear to have any scope
|
||||||
@@ -180,6 +192,7 @@ void operator() (LinearOperatorBase<Field> &Linop, const Field &src, std::vector
|
|||||||
// However SAME r is used. Could load "r" and update
|
// However SAME r is used. Could load "r" and update
|
||||||
// ALL ps[s]. 2/3 Bandwidth saving
|
// ALL ps[s]. 2/3 Bandwidth saving
|
||||||
// New Kernel: Load r, vector of coeffs, vector of pointers ps
|
// New Kernel: Load r, vector of coeffs, vector of pointers ps
|
||||||
|
AXPYTimer.Start();
|
||||||
for(int s=0;s<nshift;s++){
|
for(int s=0;s<nshift;s++){
|
||||||
if ( ! converged[s] ) {
|
if ( ! converged[s] ) {
|
||||||
if (s==0){
|
if (s==0){
|
||||||
@@ -190,22 +203,34 @@ void operator() (LinearOperatorBase<Field> &Linop, const Field &src, std::vector
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
AXPYTimer.Stop();
|
||||||
|
|
||||||
cp=c;
|
cp=c;
|
||||||
|
MatrixTimer.Start();
|
||||||
|
//Linop.HermOpAndNorm(p,mmp,d,qq); // d is used
|
||||||
|
// The below is faster on KNL
|
||||||
|
Linop.HermOp(p,mmp);
|
||||||
|
d=real(innerProduct(p,mmp));
|
||||||
|
|
||||||
Linop.HermOpAndNorm(p,mmp,d,qq);
|
MatrixTimer.Stop();
|
||||||
|
|
||||||
|
AXPYTimer.Start();
|
||||||
axpy(mmp,mass[0],p,mmp);
|
axpy(mmp,mass[0],p,mmp);
|
||||||
|
AXPYTimer.Stop();
|
||||||
RealD rn = norm2(p);
|
RealD rn = norm2(p);
|
||||||
d += rn*mass[0];
|
d += rn*mass[0];
|
||||||
|
|
||||||
bp=b;
|
bp=b;
|
||||||
b=-cp/d;
|
b=-cp/d;
|
||||||
|
|
||||||
|
AXPYTimer.Start();
|
||||||
c=axpy_norm(r,b,mmp,r);
|
c=axpy_norm(r,b,mmp,r);
|
||||||
|
AXPYTimer.Stop();
|
||||||
|
|
||||||
// Toggle the recurrence history
|
// Toggle the recurrence history
|
||||||
bs[0] = b;
|
bs[0] = b;
|
||||||
iz = 1-iz;
|
iz = 1-iz;
|
||||||
|
ShiftTimer.Start();
|
||||||
for(int s=1;s<nshift;s++){
|
for(int s=1;s<nshift;s++){
|
||||||
if((!converged[s])){
|
if((!converged[s])){
|
||||||
RealD z0 = z[s][1-iz];
|
RealD z0 = z[s][1-iz];
|
||||||
@@ -215,6 +240,7 @@ void operator() (LinearOperatorBase<Field> &Linop, const Field &src, std::vector
|
|||||||
bs[s] = b*z[s][iz]/z0; // NB sign rel to Mike
|
bs[s] = b*z[s][iz]/z0; // NB sign rel to Mike
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ShiftTimer.Stop();
|
||||||
|
|
||||||
for(int s=0;s<nshift;s++){
|
for(int s=0;s<nshift;s++){
|
||||||
int ss = s;
|
int ss = s;
|
||||||
@@ -257,6 +283,9 @@ void operator() (LinearOperatorBase<Field> &Linop, const Field &src, std::vector
|
|||||||
|
|
||||||
if ( all_converged ){
|
if ( all_converged ){
|
||||||
|
|
||||||
|
SolverTimer.Stop();
|
||||||
|
|
||||||
|
|
||||||
std::cout<<GridLogMessage<< "CGMultiShift: All shifts have converged iteration "<<k<<std::endl;
|
std::cout<<GridLogMessage<< "CGMultiShift: All shifts have converged iteration "<<k<<std::endl;
|
||||||
std::cout<<GridLogMessage<< "CGMultiShift: Checking solutions"<<std::endl;
|
std::cout<<GridLogMessage<< "CGMultiShift: Checking solutions"<<std::endl;
|
||||||
|
|
||||||
@@ -269,8 +298,19 @@ void operator() (LinearOperatorBase<Field> &Linop, const Field &src, std::vector
|
|||||||
RealD cn = norm2(src);
|
RealD cn = norm2(src);
|
||||||
std::cout<<GridLogMessage<<"CGMultiShift: shift["<<s<<"] true residual "<<std::sqrt(rn/cn)<<std::endl;
|
std::cout<<GridLogMessage<<"CGMultiShift: shift["<<s<<"] true residual "<<std::sqrt(rn/cn)<<std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::cout << GridLogMessage << "Time Breakdown "<<std::endl;
|
||||||
|
std::cout << GridLogMessage << "\tElapsed " << SolverTimer.Elapsed() <<std::endl;
|
||||||
|
std::cout << GridLogMessage << "\tAXPY " << AXPYTimer.Elapsed() <<std::endl;
|
||||||
|
std::cout << GridLogMessage << "\tMarix " << MatrixTimer.Elapsed() <<std::endl;
|
||||||
|
std::cout << GridLogMessage << "\tShift " << ShiftTimer.Elapsed() <<std::endl;
|
||||||
|
|
||||||
|
IterationsToComplete = k;
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
// ugly hack
|
// ugly hack
|
||||||
std::cout<<GridLogMessage<<"CG multi shift did not converge"<<std::endl;
|
std::cout<<GridLogMessage<<"CG multi shift did not converge"<<std::endl;
|
||||||
File renamed without changes.
File renamed without changes.
@@ -30,22 +30,23 @@ Author: Peter Boyle <paboyle@ph.ed.ac.uk>
|
|||||||
|
|
||||||
namespace Grid {
|
namespace Grid {
|
||||||
|
|
||||||
struct ZeroGuesser {
|
template<class Field>
|
||||||
|
class ZeroGuesser: public LinearFunction<Field> {
|
||||||
public:
|
public:
|
||||||
template<class Field>
|
virtual void operator()(const Field &src, Field &guess) { guess = zero; };
|
||||||
void operator()(const Field &src,Field &guess) { guess = Zero(); };
|
|
||||||
};
|
};
|
||||||
struct SourceGuesser {
|
|
||||||
|
template<class Field>
|
||||||
|
class SourceGuesser: public LinearFunction<Field> {
|
||||||
public:
|
public:
|
||||||
template<class Field>
|
virtual void operator()(const Field &src, Field &guess) { guess = src; };
|
||||||
void operator()(const Field &src,Field &guess) { guess = src; };
|
|
||||||
};
|
};
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
// Fine grid deflation
|
// Fine grid deflation
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
template<class Field>
|
template<class Field>
|
||||||
struct DeflatedGuesser {
|
class DeflatedGuesser: public LinearFunction<Field> {
|
||||||
private:
|
private:
|
||||||
const std::vector<Field> &evec;
|
const std::vector<Field> &evec;
|
||||||
const std::vector<RealD> &eval;
|
const std::vector<RealD> &eval;
|
||||||
@@ -54,7 +55,7 @@ public:
|
|||||||
|
|
||||||
DeflatedGuesser(const std::vector<Field> & _evec,const std::vector<RealD> & _eval) : evec(_evec), eval(_eval) {};
|
DeflatedGuesser(const std::vector<Field> & _evec,const std::vector<RealD> & _eval) : evec(_evec), eval(_eval) {};
|
||||||
|
|
||||||
void operator()(const Field &src,Field &guess) {
|
virtual void operator()(const Field &src,Field &guess) {
|
||||||
guess = zero;
|
guess = zero;
|
||||||
assert(evec.size()==eval.size());
|
assert(evec.size()==eval.size());
|
||||||
auto N = evec.size();
|
auto N = evec.size();
|
||||||
@@ -62,11 +63,12 @@ public:
|
|||||||
const Field& tmp = evec[i];
|
const Field& tmp = evec[i];
|
||||||
axpy(guess,TensorRemove(innerProduct(tmp,src)) / eval[i],tmp,guess);
|
axpy(guess,TensorRemove(innerProduct(tmp,src)) / eval[i],tmp,guess);
|
||||||
}
|
}
|
||||||
|
guess.checkerboard = src.checkerboard;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<class FineField, class CoarseField>
|
template<class FineField, class CoarseField>
|
||||||
class LocalCoherenceDeflatedGuesser {
|
class LocalCoherenceDeflatedGuesser: public LinearFunction<FineField> {
|
||||||
private:
|
private:
|
||||||
const std::vector<FineField> &subspace;
|
const std::vector<FineField> &subspace;
|
||||||
const std::vector<CoarseField> &evec_coarse;
|
const std::vector<CoarseField> &evec_coarse;
|
||||||
@@ -92,6 +94,7 @@ public:
|
|||||||
axpy(guess_coarse,TensorRemove(innerProduct(tmp,src_coarse)) / eval_coarse[i],tmp,guess_coarse);
|
axpy(guess_coarse,TensorRemove(innerProduct(tmp,src_coarse)) / eval_coarse[i],tmp,guess_coarse);
|
||||||
}
|
}
|
||||||
blockPromote(guess_coarse,guess,subspace);
|
blockPromote(guess_coarse,guess,subspace);
|
||||||
|
guess.checkerboard = src.checkerboard;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -0,0 +1,256 @@
|
|||||||
|
/*************************************************************************************
|
||||||
|
|
||||||
|
Grid physics library, www.github.com/paboyle/Grid
|
||||||
|
|
||||||
|
Source file: ./lib/algorithms/iterative/FlexibleCommunicationAvoidingGeneralisedMinimalResidual.h
|
||||||
|
|
||||||
|
Copyright (C) 2015
|
||||||
|
|
||||||
|
Author: Daniel Richtmann <daniel.richtmann@ur.de>
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License along
|
||||||
|
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
|
||||||
|
See the full license in the file "LICENSE" in the top level distribution
|
||||||
|
directory
|
||||||
|
*************************************************************************************/
|
||||||
|
/* END LEGAL */
|
||||||
|
#ifndef GRID_FLEXIBLE_COMMUNICATION_AVOIDING_GENERALISED_MINIMAL_RESIDUAL_H
|
||||||
|
#define GRID_FLEXIBLE_COMMUNICATION_AVOIDING_GENERALISED_MINIMAL_RESIDUAL_H
|
||||||
|
|
||||||
|
namespace Grid {
|
||||||
|
|
||||||
|
template<class Field>
|
||||||
|
class FlexibleCommunicationAvoidingGeneralisedMinimalResidual : public OperatorFunction<Field> {
|
||||||
|
public:
|
||||||
|
bool ErrorOnNoConverge; // Throw an assert when FCAGMRES fails to converge,
|
||||||
|
// defaults to true
|
||||||
|
|
||||||
|
RealD Tolerance;
|
||||||
|
|
||||||
|
Integer MaxIterations;
|
||||||
|
Integer RestartLength;
|
||||||
|
Integer MaxNumberOfRestarts;
|
||||||
|
Integer IterationCount; // Number of iterations the FCAGMRES took to finish,
|
||||||
|
// filled in upon completion
|
||||||
|
|
||||||
|
GridStopWatch MatrixTimer;
|
||||||
|
GridStopWatch PrecTimer;
|
||||||
|
GridStopWatch LinalgTimer;
|
||||||
|
GridStopWatch QrTimer;
|
||||||
|
GridStopWatch CompSolutionTimer;
|
||||||
|
|
||||||
|
Eigen::MatrixXcd H;
|
||||||
|
|
||||||
|
std::vector<std::complex<double>> y;
|
||||||
|
std::vector<std::complex<double>> gamma;
|
||||||
|
std::vector<std::complex<double>> c;
|
||||||
|
std::vector<std::complex<double>> s;
|
||||||
|
|
||||||
|
LinearFunction<Field> &Preconditioner;
|
||||||
|
|
||||||
|
FlexibleCommunicationAvoidingGeneralisedMinimalResidual(RealD tol,
|
||||||
|
Integer maxit,
|
||||||
|
LinearFunction<Field> &Prec,
|
||||||
|
Integer restart_length,
|
||||||
|
bool err_on_no_conv = true)
|
||||||
|
: Tolerance(tol)
|
||||||
|
, MaxIterations(maxit)
|
||||||
|
, RestartLength(restart_length)
|
||||||
|
, MaxNumberOfRestarts(MaxIterations/RestartLength + ((MaxIterations%RestartLength == 0) ? 0 : 1))
|
||||||
|
, ErrorOnNoConverge(err_on_no_conv)
|
||||||
|
, H(Eigen::MatrixXcd::Zero(RestartLength, RestartLength + 1)) // sizes taken from DD-αAMG code base
|
||||||
|
, y(RestartLength + 1, 0.)
|
||||||
|
, gamma(RestartLength + 1, 0.)
|
||||||
|
, c(RestartLength + 1, 0.)
|
||||||
|
, s(RestartLength + 1, 0.)
|
||||||
|
, Preconditioner(Prec) {};
|
||||||
|
|
||||||
|
void operator()(LinearOperatorBase<Field> &LinOp, const Field &src, Field &psi) {
|
||||||
|
|
||||||
|
std::cout << GridLogWarning << "This algorithm currently doesn't differ from regular FGMRES" << std::endl;
|
||||||
|
|
||||||
|
psi.checkerboard = src.checkerboard;
|
||||||
|
conformable(psi, src);
|
||||||
|
|
||||||
|
RealD guess = norm2(psi);
|
||||||
|
assert(std::isnan(guess) == 0);
|
||||||
|
|
||||||
|
RealD cp;
|
||||||
|
RealD ssq = norm2(src);
|
||||||
|
RealD rsq = Tolerance * Tolerance * ssq;
|
||||||
|
|
||||||
|
Field r(src._grid);
|
||||||
|
|
||||||
|
std::cout << std::setprecision(4) << std::scientific;
|
||||||
|
std::cout << GridLogIterative << "FlexibleCommunicationAvoidingGeneralisedMinimalResidual: guess " << guess << std::endl;
|
||||||
|
std::cout << GridLogIterative << "FlexibleCommunicationAvoidingGeneralisedMinimalResidual: src " << ssq << std::endl;
|
||||||
|
|
||||||
|
PrecTimer.Reset();
|
||||||
|
MatrixTimer.Reset();
|
||||||
|
LinalgTimer.Reset();
|
||||||
|
QrTimer.Reset();
|
||||||
|
CompSolutionTimer.Reset();
|
||||||
|
|
||||||
|
GridStopWatch SolverTimer;
|
||||||
|
SolverTimer.Start();
|
||||||
|
|
||||||
|
IterationCount = 0;
|
||||||
|
|
||||||
|
for (int k=0; k<MaxNumberOfRestarts; k++) {
|
||||||
|
|
||||||
|
cp = outerLoopBody(LinOp, src, psi, rsq);
|
||||||
|
|
||||||
|
// Stopping condition
|
||||||
|
if (cp <= rsq) {
|
||||||
|
|
||||||
|
SolverTimer.Stop();
|
||||||
|
|
||||||
|
LinOp.Op(psi,r);
|
||||||
|
axpy(r,-1.0,src,r);
|
||||||
|
|
||||||
|
RealD srcnorm = sqrt(ssq);
|
||||||
|
RealD resnorm = sqrt(norm2(r));
|
||||||
|
RealD true_residual = resnorm / srcnorm;
|
||||||
|
|
||||||
|
std::cout << GridLogMessage << "FlexibleCommunicationAvoidingGeneralisedMinimalResidual: Converged on iteration " << IterationCount
|
||||||
|
<< " computed residual " << sqrt(cp / ssq)
|
||||||
|
<< " true residual " << true_residual
|
||||||
|
<< " target " << Tolerance << std::endl;
|
||||||
|
|
||||||
|
std::cout << GridLogMessage << "FCAGMRES Time elapsed: Total " << SolverTimer.Elapsed() << std::endl;
|
||||||
|
std::cout << GridLogMessage << "FCAGMRES Time elapsed: Precon " << PrecTimer.Elapsed() << std::endl;
|
||||||
|
std::cout << GridLogMessage << "FCAGMRES Time elapsed: Matrix " << MatrixTimer.Elapsed() << std::endl;
|
||||||
|
std::cout << GridLogMessage << "FCAGMRES Time elapsed: Linalg " << LinalgTimer.Elapsed() << std::endl;
|
||||||
|
std::cout << GridLogMessage << "FCAGMRES Time elapsed: QR " << QrTimer.Elapsed() << std::endl;
|
||||||
|
std::cout << GridLogMessage << "FCAGMRES Time elapsed: CompSol " << CompSolutionTimer.Elapsed() << std::endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << GridLogMessage << "FlexibleCommunicationAvoidingGeneralisedMinimalResidual did NOT converge" << std::endl;
|
||||||
|
|
||||||
|
if (ErrorOnNoConverge)
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
RealD outerLoopBody(LinearOperatorBase<Field> &LinOp, const Field &src, Field &psi, RealD rsq) {
|
||||||
|
|
||||||
|
RealD cp = 0;
|
||||||
|
|
||||||
|
Field w(src._grid);
|
||||||
|
Field r(src._grid);
|
||||||
|
|
||||||
|
// these should probably be made class members so that they are only allocated once, not in every restart
|
||||||
|
std::vector<Field> v(RestartLength + 1, src._grid); for (auto &elem : v) elem = zero;
|
||||||
|
std::vector<Field> z(RestartLength + 1, src._grid); for (auto &elem : z) elem = zero;
|
||||||
|
|
||||||
|
MatrixTimer.Start();
|
||||||
|
LinOp.Op(psi, w);
|
||||||
|
MatrixTimer.Stop();
|
||||||
|
|
||||||
|
LinalgTimer.Start();
|
||||||
|
r = src - w;
|
||||||
|
|
||||||
|
gamma[0] = sqrt(norm2(r));
|
||||||
|
|
||||||
|
v[0] = (1. / gamma[0]) * r;
|
||||||
|
LinalgTimer.Stop();
|
||||||
|
|
||||||
|
for (int i=0; i<RestartLength; i++) {
|
||||||
|
|
||||||
|
IterationCount++;
|
||||||
|
|
||||||
|
arnoldiStep(LinOp, v, z, w, i);
|
||||||
|
|
||||||
|
qrUpdate(i);
|
||||||
|
|
||||||
|
cp = std::norm(gamma[i+1]);
|
||||||
|
|
||||||
|
std::cout << GridLogIterative << "FlexibleCommunicationAvoidingGeneralisedMinimalResidual: Iteration " << IterationCount
|
||||||
|
<< " residual " << cp << " target " << rsq << std::endl;
|
||||||
|
|
||||||
|
if ((i == RestartLength - 1) || (IterationCount == MaxIterations) || (cp <= rsq)) {
|
||||||
|
|
||||||
|
computeSolution(z, psi, i);
|
||||||
|
|
||||||
|
return cp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(0); // Never reached
|
||||||
|
return cp;
|
||||||
|
}
|
||||||
|
|
||||||
|
void arnoldiStep(LinearOperatorBase<Field> &LinOp, std::vector<Field> &v, std::vector<Field> &z, Field &w, int iter) {
|
||||||
|
|
||||||
|
PrecTimer.Start();
|
||||||
|
Preconditioner(v[iter], z[iter]);
|
||||||
|
PrecTimer.Stop();
|
||||||
|
|
||||||
|
MatrixTimer.Start();
|
||||||
|
LinOp.Op(z[iter], w);
|
||||||
|
MatrixTimer.Stop();
|
||||||
|
|
||||||
|
LinalgTimer.Start();
|
||||||
|
for (int i = 0; i <= iter; ++i) {
|
||||||
|
H(iter, i) = innerProduct(v[i], w);
|
||||||
|
w = w - H(iter, i) * v[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
H(iter, iter + 1) = sqrt(norm2(w));
|
||||||
|
v[iter + 1] = (1. / H(iter, iter + 1)) * w;
|
||||||
|
LinalgTimer.Stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
void qrUpdate(int iter) {
|
||||||
|
|
||||||
|
QrTimer.Start();
|
||||||
|
for (int i = 0; i < iter ; ++i) {
|
||||||
|
auto tmp = -s[i] * H(iter, i) + c[i] * H(iter, i + 1);
|
||||||
|
H(iter, i) = std::conj(c[i]) * H(iter, i) + std::conj(s[i]) * H(iter, i + 1);
|
||||||
|
H(iter, i + 1) = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute new Givens Rotation
|
||||||
|
ComplexD nu = sqrt(std::norm(H(iter, iter)) + std::norm(H(iter, iter + 1)));
|
||||||
|
c[iter] = H(iter, iter) / nu;
|
||||||
|
s[iter] = H(iter, iter + 1) / nu;
|
||||||
|
|
||||||
|
// Apply new Givens rotation
|
||||||
|
H(iter, iter) = nu;
|
||||||
|
H(iter, iter + 1) = 0.;
|
||||||
|
|
||||||
|
gamma[iter + 1] = -s[iter] * gamma[iter];
|
||||||
|
gamma[iter] = std::conj(c[iter]) * gamma[iter];
|
||||||
|
QrTimer.Stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
void computeSolution(std::vector<Field> const &z, Field &psi, int iter) {
|
||||||
|
|
||||||
|
CompSolutionTimer.Start();
|
||||||
|
for (int i = iter; i >= 0; i--) {
|
||||||
|
y[i] = gamma[i];
|
||||||
|
for (int k = i + 1; k <= iter; k++)
|
||||||
|
y[i] = y[i] - H(k, i) * y[k];
|
||||||
|
y[i] = y[i] / H(i, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i <= iter; i++)
|
||||||
|
psi = psi + z[i] * y[i];
|
||||||
|
CompSolutionTimer.Stop();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,254 @@
|
|||||||
|
/*************************************************************************************
|
||||||
|
|
||||||
|
Grid physics library, www.github.com/paboyle/Grid
|
||||||
|
|
||||||
|
Source file: ./lib/algorithms/iterative/FlexibleGeneralisedMinimalResidual.h
|
||||||
|
|
||||||
|
Copyright (C) 2015
|
||||||
|
|
||||||
|
Author: Daniel Richtmann <daniel.richtmann@ur.de>
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License along
|
||||||
|
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
|
||||||
|
See the full license in the file "LICENSE" in the top level distribution
|
||||||
|
directory
|
||||||
|
*************************************************************************************/
|
||||||
|
/* END LEGAL */
|
||||||
|
#ifndef GRID_FLEXIBLE_GENERALISED_MINIMAL_RESIDUAL_H
|
||||||
|
#define GRID_FLEXIBLE_GENERALISED_MINIMAL_RESIDUAL_H
|
||||||
|
|
||||||
|
namespace Grid {
|
||||||
|
|
||||||
|
template<class Field>
|
||||||
|
class FlexibleGeneralisedMinimalResidual : public OperatorFunction<Field> {
|
||||||
|
public:
|
||||||
|
bool ErrorOnNoConverge; // Throw an assert when FGMRES fails to converge,
|
||||||
|
// defaults to true
|
||||||
|
|
||||||
|
RealD Tolerance;
|
||||||
|
|
||||||
|
Integer MaxIterations;
|
||||||
|
Integer RestartLength;
|
||||||
|
Integer MaxNumberOfRestarts;
|
||||||
|
Integer IterationCount; // Number of iterations the FGMRES took to finish,
|
||||||
|
// filled in upon completion
|
||||||
|
|
||||||
|
GridStopWatch MatrixTimer;
|
||||||
|
GridStopWatch PrecTimer;
|
||||||
|
GridStopWatch LinalgTimer;
|
||||||
|
GridStopWatch QrTimer;
|
||||||
|
GridStopWatch CompSolutionTimer;
|
||||||
|
|
||||||
|
Eigen::MatrixXcd H;
|
||||||
|
|
||||||
|
std::vector<std::complex<double>> y;
|
||||||
|
std::vector<std::complex<double>> gamma;
|
||||||
|
std::vector<std::complex<double>> c;
|
||||||
|
std::vector<std::complex<double>> s;
|
||||||
|
|
||||||
|
LinearFunction<Field> &Preconditioner;
|
||||||
|
|
||||||
|
FlexibleGeneralisedMinimalResidual(RealD tol,
|
||||||
|
Integer maxit,
|
||||||
|
LinearFunction<Field> &Prec,
|
||||||
|
Integer restart_length,
|
||||||
|
bool err_on_no_conv = true)
|
||||||
|
: Tolerance(tol)
|
||||||
|
, MaxIterations(maxit)
|
||||||
|
, RestartLength(restart_length)
|
||||||
|
, MaxNumberOfRestarts(MaxIterations/RestartLength + ((MaxIterations%RestartLength == 0) ? 0 : 1))
|
||||||
|
, ErrorOnNoConverge(err_on_no_conv)
|
||||||
|
, H(Eigen::MatrixXcd::Zero(RestartLength, RestartLength + 1)) // sizes taken from DD-αAMG code base
|
||||||
|
, y(RestartLength + 1, 0.)
|
||||||
|
, gamma(RestartLength + 1, 0.)
|
||||||
|
, c(RestartLength + 1, 0.)
|
||||||
|
, s(RestartLength + 1, 0.)
|
||||||
|
, Preconditioner(Prec) {};
|
||||||
|
|
||||||
|
void operator()(LinearOperatorBase<Field> &LinOp, const Field &src, Field &psi) {
|
||||||
|
|
||||||
|
psi.checkerboard = src.checkerboard;
|
||||||
|
conformable(psi, src);
|
||||||
|
|
||||||
|
RealD guess = norm2(psi);
|
||||||
|
assert(std::isnan(guess) == 0);
|
||||||
|
|
||||||
|
RealD cp;
|
||||||
|
RealD ssq = norm2(src);
|
||||||
|
RealD rsq = Tolerance * Tolerance * ssq;
|
||||||
|
|
||||||
|
Field r(src._grid);
|
||||||
|
|
||||||
|
std::cout << std::setprecision(4) << std::scientific;
|
||||||
|
std::cout << GridLogIterative << "FlexibleGeneralisedMinimalResidual: guess " << guess << std::endl;
|
||||||
|
std::cout << GridLogIterative << "FlexibleGeneralisedMinimalResidual: src " << ssq << std::endl;
|
||||||
|
|
||||||
|
PrecTimer.Reset();
|
||||||
|
MatrixTimer.Reset();
|
||||||
|
LinalgTimer.Reset();
|
||||||
|
QrTimer.Reset();
|
||||||
|
CompSolutionTimer.Reset();
|
||||||
|
|
||||||
|
GridStopWatch SolverTimer;
|
||||||
|
SolverTimer.Start();
|
||||||
|
|
||||||
|
IterationCount = 0;
|
||||||
|
|
||||||
|
for (int k=0; k<MaxNumberOfRestarts; k++) {
|
||||||
|
|
||||||
|
cp = outerLoopBody(LinOp, src, psi, rsq);
|
||||||
|
|
||||||
|
// Stopping condition
|
||||||
|
if (cp <= rsq) {
|
||||||
|
|
||||||
|
SolverTimer.Stop();
|
||||||
|
|
||||||
|
LinOp.Op(psi,r);
|
||||||
|
axpy(r,-1.0,src,r);
|
||||||
|
|
||||||
|
RealD srcnorm = sqrt(ssq);
|
||||||
|
RealD resnorm = sqrt(norm2(r));
|
||||||
|
RealD true_residual = resnorm / srcnorm;
|
||||||
|
|
||||||
|
std::cout << GridLogMessage << "FlexibleGeneralisedMinimalResidual: Converged on iteration " << IterationCount
|
||||||
|
<< " computed residual " << sqrt(cp / ssq)
|
||||||
|
<< " true residual " << true_residual
|
||||||
|
<< " target " << Tolerance << std::endl;
|
||||||
|
|
||||||
|
std::cout << GridLogMessage << "FGMRES Time elapsed: Total " << SolverTimer.Elapsed() << std::endl;
|
||||||
|
std::cout << GridLogMessage << "FGMRES Time elapsed: Precon " << PrecTimer.Elapsed() << std::endl;
|
||||||
|
std::cout << GridLogMessage << "FGMRES Time elapsed: Matrix " << MatrixTimer.Elapsed() << std::endl;
|
||||||
|
std::cout << GridLogMessage << "FGMRES Time elapsed: Linalg " << LinalgTimer.Elapsed() << std::endl;
|
||||||
|
std::cout << GridLogMessage << "FGMRES Time elapsed: QR " << QrTimer.Elapsed() << std::endl;
|
||||||
|
std::cout << GridLogMessage << "FGMRES Time elapsed: CompSol " << CompSolutionTimer.Elapsed() << std::endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << GridLogMessage << "FlexibleGeneralisedMinimalResidual did NOT converge" << std::endl;
|
||||||
|
|
||||||
|
if (ErrorOnNoConverge)
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
RealD outerLoopBody(LinearOperatorBase<Field> &LinOp, const Field &src, Field &psi, RealD rsq) {
|
||||||
|
|
||||||
|
RealD cp = 0;
|
||||||
|
|
||||||
|
Field w(src._grid);
|
||||||
|
Field r(src._grid);
|
||||||
|
|
||||||
|
// these should probably be made class members so that they are only allocated once, not in every restart
|
||||||
|
std::vector<Field> v(RestartLength + 1, src._grid); for (auto &elem : v) elem = zero;
|
||||||
|
std::vector<Field> z(RestartLength + 1, src._grid); for (auto &elem : z) elem = zero;
|
||||||
|
|
||||||
|
MatrixTimer.Start();
|
||||||
|
LinOp.Op(psi, w);
|
||||||
|
MatrixTimer.Stop();
|
||||||
|
|
||||||
|
LinalgTimer.Start();
|
||||||
|
r = src - w;
|
||||||
|
|
||||||
|
gamma[0] = sqrt(norm2(r));
|
||||||
|
|
||||||
|
v[0] = (1. / gamma[0]) * r;
|
||||||
|
LinalgTimer.Stop();
|
||||||
|
|
||||||
|
for (int i=0; i<RestartLength; i++) {
|
||||||
|
|
||||||
|
IterationCount++;
|
||||||
|
|
||||||
|
arnoldiStep(LinOp, v, z, w, i);
|
||||||
|
|
||||||
|
qrUpdate(i);
|
||||||
|
|
||||||
|
cp = std::norm(gamma[i+1]);
|
||||||
|
|
||||||
|
std::cout << GridLogIterative << "FlexibleGeneralisedMinimalResidual: Iteration " << IterationCount
|
||||||
|
<< " residual " << cp << " target " << rsq << std::endl;
|
||||||
|
|
||||||
|
if ((i == RestartLength - 1) || (IterationCount == MaxIterations) || (cp <= rsq)) {
|
||||||
|
|
||||||
|
computeSolution(z, psi, i);
|
||||||
|
|
||||||
|
return cp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(0); // Never reached
|
||||||
|
return cp;
|
||||||
|
}
|
||||||
|
|
||||||
|
void arnoldiStep(LinearOperatorBase<Field> &LinOp, std::vector<Field> &v, std::vector<Field> &z, Field &w, int iter) {
|
||||||
|
|
||||||
|
PrecTimer.Start();
|
||||||
|
Preconditioner(v[iter], z[iter]);
|
||||||
|
PrecTimer.Stop();
|
||||||
|
|
||||||
|
MatrixTimer.Start();
|
||||||
|
LinOp.Op(z[iter], w);
|
||||||
|
MatrixTimer.Stop();
|
||||||
|
|
||||||
|
LinalgTimer.Start();
|
||||||
|
for (int i = 0; i <= iter; ++i) {
|
||||||
|
H(iter, i) = innerProduct(v[i], w);
|
||||||
|
w = w - H(iter, i) * v[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
H(iter, iter + 1) = sqrt(norm2(w));
|
||||||
|
v[iter + 1] = (1. / H(iter, iter + 1)) * w;
|
||||||
|
LinalgTimer.Stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
void qrUpdate(int iter) {
|
||||||
|
|
||||||
|
QrTimer.Start();
|
||||||
|
for (int i = 0; i < iter ; ++i) {
|
||||||
|
auto tmp = -s[i] * H(iter, i) + c[i] * H(iter, i + 1);
|
||||||
|
H(iter, i) = std::conj(c[i]) * H(iter, i) + std::conj(s[i]) * H(iter, i + 1);
|
||||||
|
H(iter, i + 1) = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute new Givens Rotation
|
||||||
|
ComplexD nu = sqrt(std::norm(H(iter, iter)) + std::norm(H(iter, iter + 1)));
|
||||||
|
c[iter] = H(iter, iter) / nu;
|
||||||
|
s[iter] = H(iter, iter + 1) / nu;
|
||||||
|
|
||||||
|
// Apply new Givens rotation
|
||||||
|
H(iter, iter) = nu;
|
||||||
|
H(iter, iter + 1) = 0.;
|
||||||
|
|
||||||
|
gamma[iter + 1] = -s[iter] * gamma[iter];
|
||||||
|
gamma[iter] = std::conj(c[iter]) * gamma[iter];
|
||||||
|
QrTimer.Stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
void computeSolution(std::vector<Field> const &z, Field &psi, int iter) {
|
||||||
|
|
||||||
|
CompSolutionTimer.Start();
|
||||||
|
for (int i = iter; i >= 0; i--) {
|
||||||
|
y[i] = gamma[i];
|
||||||
|
for (int k = i + 1; k <= iter; k++)
|
||||||
|
y[i] = y[i] - H(k, i) * y[k];
|
||||||
|
y[i] = y[i] / H(i, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i <= iter; i++)
|
||||||
|
psi = psi + z[i] * y[i];
|
||||||
|
CompSolutionTimer.Stop();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,242 @@
|
|||||||
|
/*************************************************************************************
|
||||||
|
|
||||||
|
Grid physics library, www.github.com/paboyle/Grid
|
||||||
|
|
||||||
|
Source file: ./lib/algorithms/iterative/GeneralisedMinimalResidual.h
|
||||||
|
|
||||||
|
Copyright (C) 2015
|
||||||
|
|
||||||
|
Author: Daniel Richtmann <daniel.richtmann@ur.de>
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License along
|
||||||
|
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
|
||||||
|
See the full license in the file "LICENSE" in the top level distribution
|
||||||
|
directory
|
||||||
|
*************************************************************************************/
|
||||||
|
/* END LEGAL */
|
||||||
|
#ifndef GRID_GENERALISED_MINIMAL_RESIDUAL_H
|
||||||
|
#define GRID_GENERALISED_MINIMAL_RESIDUAL_H
|
||||||
|
|
||||||
|
namespace Grid {
|
||||||
|
|
||||||
|
template<class Field>
|
||||||
|
class GeneralisedMinimalResidual : public OperatorFunction<Field> {
|
||||||
|
public:
|
||||||
|
bool ErrorOnNoConverge; // Throw an assert when GMRES fails to converge,
|
||||||
|
// defaults to true
|
||||||
|
|
||||||
|
RealD Tolerance;
|
||||||
|
|
||||||
|
Integer MaxIterations;
|
||||||
|
Integer RestartLength;
|
||||||
|
Integer MaxNumberOfRestarts;
|
||||||
|
Integer IterationCount; // Number of iterations the GMRES took to finish,
|
||||||
|
// filled in upon completion
|
||||||
|
|
||||||
|
GridStopWatch MatrixTimer;
|
||||||
|
GridStopWatch LinalgTimer;
|
||||||
|
GridStopWatch QrTimer;
|
||||||
|
GridStopWatch CompSolutionTimer;
|
||||||
|
|
||||||
|
Eigen::MatrixXcd H;
|
||||||
|
|
||||||
|
std::vector<std::complex<double>> y;
|
||||||
|
std::vector<std::complex<double>> gamma;
|
||||||
|
std::vector<std::complex<double>> c;
|
||||||
|
std::vector<std::complex<double>> s;
|
||||||
|
|
||||||
|
GeneralisedMinimalResidual(RealD tol,
|
||||||
|
Integer maxit,
|
||||||
|
Integer restart_length,
|
||||||
|
bool err_on_no_conv = true)
|
||||||
|
: Tolerance(tol)
|
||||||
|
, MaxIterations(maxit)
|
||||||
|
, RestartLength(restart_length)
|
||||||
|
, MaxNumberOfRestarts(MaxIterations/RestartLength + ((MaxIterations%RestartLength == 0) ? 0 : 1))
|
||||||
|
, ErrorOnNoConverge(err_on_no_conv)
|
||||||
|
, H(Eigen::MatrixXcd::Zero(RestartLength, RestartLength + 1)) // sizes taken from DD-αAMG code base
|
||||||
|
, y(RestartLength + 1, 0.)
|
||||||
|
, gamma(RestartLength + 1, 0.)
|
||||||
|
, c(RestartLength + 1, 0.)
|
||||||
|
, s(RestartLength + 1, 0.) {};
|
||||||
|
|
||||||
|
void operator()(LinearOperatorBase<Field> &LinOp, const Field &src, Field &psi) {
|
||||||
|
|
||||||
|
psi.checkerboard = src.checkerboard;
|
||||||
|
conformable(psi, src);
|
||||||
|
|
||||||
|
RealD guess = norm2(psi);
|
||||||
|
assert(std::isnan(guess) == 0);
|
||||||
|
|
||||||
|
RealD cp;
|
||||||
|
RealD ssq = norm2(src);
|
||||||
|
RealD rsq = Tolerance * Tolerance * ssq;
|
||||||
|
|
||||||
|
Field r(src._grid);
|
||||||
|
|
||||||
|
std::cout << std::setprecision(4) << std::scientific;
|
||||||
|
std::cout << GridLogIterative << "GeneralisedMinimalResidual: guess " << guess << std::endl;
|
||||||
|
std::cout << GridLogIterative << "GeneralisedMinimalResidual: src " << ssq << std::endl;
|
||||||
|
|
||||||
|
MatrixTimer.Reset();
|
||||||
|
LinalgTimer.Reset();
|
||||||
|
QrTimer.Reset();
|
||||||
|
CompSolutionTimer.Reset();
|
||||||
|
|
||||||
|
GridStopWatch SolverTimer;
|
||||||
|
SolverTimer.Start();
|
||||||
|
|
||||||
|
IterationCount = 0;
|
||||||
|
|
||||||
|
for (int k=0; k<MaxNumberOfRestarts; k++) {
|
||||||
|
|
||||||
|
cp = outerLoopBody(LinOp, src, psi, rsq);
|
||||||
|
|
||||||
|
// Stopping condition
|
||||||
|
if (cp <= rsq) {
|
||||||
|
|
||||||
|
SolverTimer.Stop();
|
||||||
|
|
||||||
|
LinOp.Op(psi,r);
|
||||||
|
axpy(r,-1.0,src,r);
|
||||||
|
|
||||||
|
RealD srcnorm = sqrt(ssq);
|
||||||
|
RealD resnorm = sqrt(norm2(r));
|
||||||
|
RealD true_residual = resnorm / srcnorm;
|
||||||
|
|
||||||
|
std::cout << GridLogMessage << "GeneralisedMinimalResidual: Converged on iteration " << IterationCount
|
||||||
|
<< " computed residual " << sqrt(cp / ssq)
|
||||||
|
<< " true residual " << true_residual
|
||||||
|
<< " target " << Tolerance << std::endl;
|
||||||
|
|
||||||
|
std::cout << GridLogMessage << "GMRES Time elapsed: Total " << SolverTimer.Elapsed() << std::endl;
|
||||||
|
std::cout << GridLogMessage << "GMRES Time elapsed: Matrix " << MatrixTimer.Elapsed() << std::endl;
|
||||||
|
std::cout << GridLogMessage << "GMRES Time elapsed: Linalg " << LinalgTimer.Elapsed() << std::endl;
|
||||||
|
std::cout << GridLogMessage << "GMRES Time elapsed: QR " << QrTimer.Elapsed() << std::endl;
|
||||||
|
std::cout << GridLogMessage << "GMRES Time elapsed: CompSol " << CompSolutionTimer.Elapsed() << std::endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << GridLogMessage << "GeneralisedMinimalResidual did NOT converge" << std::endl;
|
||||||
|
|
||||||
|
if (ErrorOnNoConverge)
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
RealD outerLoopBody(LinearOperatorBase<Field> &LinOp, const Field &src, Field &psi, RealD rsq) {
|
||||||
|
|
||||||
|
RealD cp = 0;
|
||||||
|
|
||||||
|
Field w(src._grid);
|
||||||
|
Field r(src._grid);
|
||||||
|
|
||||||
|
// this should probably be made a class member so that it is only allocated once, not in every restart
|
||||||
|
std::vector<Field> v(RestartLength + 1, src._grid); for (auto &elem : v) elem = zero;
|
||||||
|
|
||||||
|
MatrixTimer.Start();
|
||||||
|
LinOp.Op(psi, w);
|
||||||
|
MatrixTimer.Stop();
|
||||||
|
|
||||||
|
LinalgTimer.Start();
|
||||||
|
r = src - w;
|
||||||
|
|
||||||
|
gamma[0] = sqrt(norm2(r));
|
||||||
|
|
||||||
|
v[0] = (1. / gamma[0]) * r;
|
||||||
|
LinalgTimer.Stop();
|
||||||
|
|
||||||
|
for (int i=0; i<RestartLength; i++) {
|
||||||
|
|
||||||
|
IterationCount++;
|
||||||
|
|
||||||
|
arnoldiStep(LinOp, v, w, i);
|
||||||
|
|
||||||
|
qrUpdate(i);
|
||||||
|
|
||||||
|
cp = std::norm(gamma[i+1]);
|
||||||
|
|
||||||
|
std::cout << GridLogIterative << "GeneralisedMinimalResidual: Iteration " << IterationCount
|
||||||
|
<< " residual " << cp << " target " << rsq << std::endl;
|
||||||
|
|
||||||
|
if ((i == RestartLength - 1) || (IterationCount == MaxIterations) || (cp <= rsq)) {
|
||||||
|
|
||||||
|
computeSolution(v, psi, i);
|
||||||
|
|
||||||
|
return cp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(0); // Never reached
|
||||||
|
return cp;
|
||||||
|
}
|
||||||
|
|
||||||
|
void arnoldiStep(LinearOperatorBase<Field> &LinOp, std::vector<Field> &v, Field &w, int iter) {
|
||||||
|
|
||||||
|
MatrixTimer.Start();
|
||||||
|
LinOp.Op(v[iter], w);
|
||||||
|
MatrixTimer.Stop();
|
||||||
|
|
||||||
|
LinalgTimer.Start();
|
||||||
|
for (int i = 0; i <= iter; ++i) {
|
||||||
|
H(iter, i) = innerProduct(v[i], w);
|
||||||
|
w = w - H(iter, i) * v[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
H(iter, iter + 1) = sqrt(norm2(w));
|
||||||
|
v[iter + 1] = (1. / H(iter, iter + 1)) * w;
|
||||||
|
LinalgTimer.Stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
void qrUpdate(int iter) {
|
||||||
|
|
||||||
|
QrTimer.Start();
|
||||||
|
for (int i = 0; i < iter ; ++i) {
|
||||||
|
auto tmp = -s[i] * H(iter, i) + c[i] * H(iter, i + 1);
|
||||||
|
H(iter, i) = std::conj(c[i]) * H(iter, i) + std::conj(s[i]) * H(iter, i + 1);
|
||||||
|
H(iter, i + 1) = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute new Givens Rotation
|
||||||
|
ComplexD nu = sqrt(std::norm(H(iter, iter)) + std::norm(H(iter, iter + 1)));
|
||||||
|
c[iter] = H(iter, iter) / nu;
|
||||||
|
s[iter] = H(iter, iter + 1) / nu;
|
||||||
|
|
||||||
|
// Apply new Givens rotation
|
||||||
|
H(iter, iter) = nu;
|
||||||
|
H(iter, iter + 1) = 0.;
|
||||||
|
|
||||||
|
gamma[iter + 1] = -s[iter] * gamma[iter];
|
||||||
|
gamma[iter] = std::conj(c[iter]) * gamma[iter];
|
||||||
|
QrTimer.Stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
void computeSolution(std::vector<Field> const &v, Field &psi, int iter) {
|
||||||
|
|
||||||
|
CompSolutionTimer.Start();
|
||||||
|
for (int i = iter; i >= 0; i--) {
|
||||||
|
y[i] = gamma[i];
|
||||||
|
for (int k = i + 1; k <= iter; k++)
|
||||||
|
y[i] = y[i] - H(k, i) * y[k];
|
||||||
|
y[i] = y[i] / H(i, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i <= iter; i++)
|
||||||
|
psi = psi + v[i] * y[i];
|
||||||
|
CompSolutionTimer.Stop();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#endif
|
||||||
+2
-1
@@ -57,7 +57,8 @@ void basisRotate(std::vector<Field> &basis,Eigen::MatrixXd& Qt,int j0, int j1, i
|
|||||||
|
|
||||||
parallel_region
|
parallel_region
|
||||||
{
|
{
|
||||||
std::vector < vobj > B(Nm); // Thread private
|
|
||||||
|
std::vector < vobj , commAllocator<vobj> > B(Nm); // Thread private
|
||||||
|
|
||||||
parallel_for_internal(int ss=0;ss < grid->oSites();ss++){
|
parallel_for_internal(int ss=0;ss < grid->oSites();ss++){
|
||||||
for(int j=j0; j<j1; ++j) B[j]=0.;
|
for(int j=j0; j<j1; ++j) B[j]=0.;
|
||||||
+8
-6
@@ -286,8 +286,10 @@ public:
|
|||||||
|
|
||||||
void Orthogonalise(void ) {
|
void Orthogonalise(void ) {
|
||||||
CoarseScalar InnerProd(_CoarseGrid);
|
CoarseScalar InnerProd(_CoarseGrid);
|
||||||
blockOrthogonalise(InnerProd,subspace);std::cout << GridLogMessage <<" Gramm-Schmidt pass 1"<<std::endl;
|
std::cout << GridLogMessage <<" Gramm-Schmidt pass 1"<<std::endl;
|
||||||
blockOrthogonalise(InnerProd,subspace);std::cout << GridLogMessage <<" Gramm-Schmidt pass 2"<<std::endl;
|
blockOrthogonalise(InnerProd,subspace);
|
||||||
|
std::cout << GridLogMessage <<" Gramm-Schmidt pass 2"<<std::endl;
|
||||||
|
blockOrthogonalise(InnerProd,subspace);
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T> static RealD normalise(T& v)
|
template<typename T> static RealD normalise(T& v)
|
||||||
@@ -333,7 +335,7 @@ public:
|
|||||||
// create a smoother and see if we can get a cheap convergence test and smooth inside the IRL
|
// create a smoother and see if we can get a cheap convergence test and smooth inside the IRL
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
Chebyshev<FineField> ChebySmooth(cheby_smooth);
|
Chebyshev<FineField> ChebySmooth(cheby_smooth);
|
||||||
ProjectedFunctionHermOp<Fobj,CComplex,nbasis> ChebyOp (ChebySmooth,_FineOp,_subspace);
|
ProjectedFunctionHermOp<Fobj,CComplex,nbasis> ChebyOp (ChebySmooth,_FineOp,subspace);
|
||||||
ImplicitlyRestartedLanczosSmoothedTester<Fobj,CComplex,nbasis> ChebySmoothTester(ChebyOp,ChebySmooth,_FineOp,subspace,relax);
|
ImplicitlyRestartedLanczosSmoothedTester<Fobj,CComplex,nbasis> ChebySmoothTester(ChebyOp,ChebySmooth,_FineOp,subspace,relax);
|
||||||
|
|
||||||
for(int k=0;k<evec_coarse.size();k++){
|
for(int k=0;k<evec_coarse.size();k++){
|
||||||
@@ -374,14 +376,14 @@ public:
|
|||||||
RealD MaxIt, RealD betastp, int MinRes)
|
RealD MaxIt, RealD betastp, int MinRes)
|
||||||
{
|
{
|
||||||
Chebyshev<FineField> Cheby(cheby_op);
|
Chebyshev<FineField> Cheby(cheby_op);
|
||||||
ProjectedHermOp<Fobj,CComplex,nbasis> Op(_FineOp,_subspace);
|
ProjectedHermOp<Fobj,CComplex,nbasis> Op(_FineOp,subspace);
|
||||||
ProjectedFunctionHermOp<Fobj,CComplex,nbasis> ChebyOp (Cheby,_FineOp,_subspace);
|
ProjectedFunctionHermOp<Fobj,CComplex,nbasis> ChebyOp (Cheby,_FineOp,subspace);
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// create a smoother and see if we can get a cheap convergence test and smooth inside the IRL
|
// create a smoother and see if we can get a cheap convergence test and smooth inside the IRL
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
Chebyshev<FineField> ChebySmooth(cheby_smooth);
|
Chebyshev<FineField> ChebySmooth(cheby_smooth);
|
||||||
ImplicitlyRestartedLanczosSmoothedTester<Fobj,CComplex,nbasis> ChebySmoothTester(ChebyOp,ChebySmooth,_FineOp,_subspace,relax);
|
ImplicitlyRestartedLanczosSmoothedTester<Fobj,CComplex,nbasis> ChebySmoothTester(ChebyOp,ChebySmooth,_FineOp,subspace,relax);
|
||||||
|
|
||||||
evals_coarse.resize(Nm);
|
evals_coarse.resize(Nm);
|
||||||
evec_coarse.resize(Nm,_CoarseGrid);
|
evec_coarse.resize(Nm,_CoarseGrid);
|
||||||
@@ -0,0 +1,156 @@
|
|||||||
|
/*************************************************************************************
|
||||||
|
|
||||||
|
Grid physics library, www.github.com/paboyle/Grid
|
||||||
|
|
||||||
|
Source file: ./lib/algorithms/iterative/MinimalResidual.h
|
||||||
|
|
||||||
|
Copyright (C) 2015
|
||||||
|
|
||||||
|
Author: Daniel Richtmann <daniel.richtmann@ur.de>
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License along
|
||||||
|
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
|
||||||
|
See the full license in the file "LICENSE" in the top level distribution
|
||||||
|
directory
|
||||||
|
*************************************************************************************/
|
||||||
|
/* END LEGAL */
|
||||||
|
#ifndef GRID_MINIMAL_RESIDUAL_H
|
||||||
|
#define GRID_MINIMAL_RESIDUAL_H
|
||||||
|
|
||||||
|
namespace Grid {
|
||||||
|
|
||||||
|
template<class Field> class MinimalResidual : public OperatorFunction<Field> {
|
||||||
|
public:
|
||||||
|
bool ErrorOnNoConverge; // throw an assert when the MR fails to converge.
|
||||||
|
// Defaults true.
|
||||||
|
RealD Tolerance;
|
||||||
|
Integer MaxIterations;
|
||||||
|
RealD overRelaxParam;
|
||||||
|
Integer IterationsToComplete; // Number of iterations the MR took to finish.
|
||||||
|
// Filled in upon completion
|
||||||
|
|
||||||
|
MinimalResidual(RealD tol, Integer maxit, Real ovrelparam = 1.0, bool err_on_no_conv = true)
|
||||||
|
: Tolerance(tol), MaxIterations(maxit), overRelaxParam(ovrelparam), ErrorOnNoConverge(err_on_no_conv){};
|
||||||
|
|
||||||
|
void operator()(LinearOperatorBase<Field> &Linop, const Field &src, Field &psi) {
|
||||||
|
|
||||||
|
psi.checkerboard = src.checkerboard;
|
||||||
|
conformable(psi, src);
|
||||||
|
|
||||||
|
Complex a, c;
|
||||||
|
Real d;
|
||||||
|
|
||||||
|
Field Mr(src);
|
||||||
|
Field r(src);
|
||||||
|
|
||||||
|
// Initial residual computation & set up
|
||||||
|
RealD guess = norm2(psi);
|
||||||
|
assert(std::isnan(guess) == 0);
|
||||||
|
|
||||||
|
RealD ssq = norm2(src);
|
||||||
|
RealD rsq = Tolerance * Tolerance * ssq;
|
||||||
|
|
||||||
|
Linop.Op(psi, Mr);
|
||||||
|
|
||||||
|
r = src - Mr;
|
||||||
|
|
||||||
|
RealD cp = norm2(r);
|
||||||
|
|
||||||
|
std::cout << std::setprecision(4) << std::scientific;
|
||||||
|
std::cout << GridLogIterative << "MinimalResidual: guess " << guess << std::endl;
|
||||||
|
std::cout << GridLogIterative << "MinimalResidual: src " << ssq << std::endl;
|
||||||
|
std::cout << GridLogIterative << "MinimalResidual: mp " << d << std::endl;
|
||||||
|
std::cout << GridLogIterative << "MinimalResidual: cp,r " << cp << std::endl;
|
||||||
|
|
||||||
|
if (cp <= rsq) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << GridLogIterative << "MinimalResidual: k=0 residual " << cp << " target " << rsq << std::endl;
|
||||||
|
|
||||||
|
GridStopWatch LinalgTimer;
|
||||||
|
GridStopWatch MatrixTimer;
|
||||||
|
GridStopWatch SolverTimer;
|
||||||
|
|
||||||
|
SolverTimer.Start();
|
||||||
|
int k;
|
||||||
|
for (k = 1; k <= MaxIterations; k++) {
|
||||||
|
|
||||||
|
MatrixTimer.Start();
|
||||||
|
Linop.Op(r, Mr);
|
||||||
|
MatrixTimer.Stop();
|
||||||
|
|
||||||
|
LinalgTimer.Start();
|
||||||
|
|
||||||
|
c = innerProduct(Mr, r);
|
||||||
|
|
||||||
|
d = norm2(Mr);
|
||||||
|
|
||||||
|
a = c / d;
|
||||||
|
|
||||||
|
a = a * overRelaxParam;
|
||||||
|
|
||||||
|
psi = psi + r * a;
|
||||||
|
|
||||||
|
r = r - Mr * a;
|
||||||
|
|
||||||
|
cp = norm2(r);
|
||||||
|
|
||||||
|
LinalgTimer.Stop();
|
||||||
|
|
||||||
|
std::cout << GridLogIterative << "MinimalResidual: Iteration " << k
|
||||||
|
<< " residual " << cp << " target " << rsq << std::endl;
|
||||||
|
std::cout << GridLogDebug << "a = " << a << " c = " << c << " d = " << d << std::endl;
|
||||||
|
|
||||||
|
// Stopping condition
|
||||||
|
if (cp <= rsq) {
|
||||||
|
SolverTimer.Stop();
|
||||||
|
|
||||||
|
Linop.Op(psi, Mr);
|
||||||
|
r = src - Mr;
|
||||||
|
|
||||||
|
RealD srcnorm = sqrt(ssq);
|
||||||
|
RealD resnorm = sqrt(norm2(r));
|
||||||
|
RealD true_residual = resnorm / srcnorm;
|
||||||
|
|
||||||
|
std::cout << GridLogMessage << "MinimalResidual Converged on iteration " << k
|
||||||
|
<< " computed residual " << sqrt(cp / ssq)
|
||||||
|
<< " true residual " << true_residual
|
||||||
|
<< " target " << Tolerance << std::endl;
|
||||||
|
|
||||||
|
std::cout << GridLogMessage << "MR Time elapsed: Total " << SolverTimer.Elapsed() << std::endl;
|
||||||
|
std::cout << GridLogMessage << "MR Time elapsed: Matrix " << MatrixTimer.Elapsed() << std::endl;
|
||||||
|
std::cout << GridLogMessage << "MR Time elapsed: Linalg " << LinalgTimer.Elapsed() << std::endl;
|
||||||
|
|
||||||
|
if (ErrorOnNoConverge)
|
||||||
|
assert(true_residual / Tolerance < 10000.0);
|
||||||
|
|
||||||
|
IterationsToComplete = k;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << GridLogMessage << "MinimalResidual did NOT converge"
|
||||||
|
<< std::endl;
|
||||||
|
|
||||||
|
if (ErrorOnNoConverge)
|
||||||
|
assert(0);
|
||||||
|
|
||||||
|
IterationsToComplete = k;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} // namespace Grid
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,273 @@
|
|||||||
|
/*************************************************************************************
|
||||||
|
|
||||||
|
Grid physics library, www.github.com/paboyle/Grid
|
||||||
|
|
||||||
|
Source file: ./lib/algorithms/iterative/MixedPrecisionFlexibleGeneralisedMinimalResidual.h
|
||||||
|
|
||||||
|
Copyright (C) 2015
|
||||||
|
|
||||||
|
Author: Daniel Richtmann <daniel.richtmann@ur.de>
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License along
|
||||||
|
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
|
||||||
|
See the full license in the file "LICENSE" in the top level distribution
|
||||||
|
directory
|
||||||
|
*************************************************************************************/
|
||||||
|
/* END LEGAL */
|
||||||
|
#ifndef GRID_MIXED_PRECISION_FLEXIBLE_GENERALISED_MINIMAL_RESIDUAL_H
|
||||||
|
#define GRID_MIXED_PRECISION_FLEXIBLE_GENERALISED_MINIMAL_RESIDUAL_H
|
||||||
|
|
||||||
|
namespace Grid {
|
||||||
|
|
||||||
|
template<class FieldD, class FieldF, typename std::enable_if<getPrecision<FieldD>::value == 2, int>::type = 0, typename std::enable_if< getPrecision<FieldF>::value == 1, int>::type = 0>
|
||||||
|
class MixedPrecisionFlexibleGeneralisedMinimalResidual : public OperatorFunction<FieldD> {
|
||||||
|
public:
|
||||||
|
bool ErrorOnNoConverge; // Throw an assert when MPFGMRES fails to converge,
|
||||||
|
// defaults to true
|
||||||
|
|
||||||
|
RealD Tolerance;
|
||||||
|
|
||||||
|
Integer MaxIterations;
|
||||||
|
Integer RestartLength;
|
||||||
|
Integer MaxNumberOfRestarts;
|
||||||
|
Integer IterationCount; // Number of iterations the MPFGMRES took to finish,
|
||||||
|
// filled in upon completion
|
||||||
|
|
||||||
|
GridStopWatch MatrixTimer;
|
||||||
|
GridStopWatch PrecTimer;
|
||||||
|
GridStopWatch LinalgTimer;
|
||||||
|
GridStopWatch QrTimer;
|
||||||
|
GridStopWatch CompSolutionTimer;
|
||||||
|
GridStopWatch ChangePrecTimer;
|
||||||
|
|
||||||
|
Eigen::MatrixXcd H;
|
||||||
|
|
||||||
|
std::vector<std::complex<double>> y;
|
||||||
|
std::vector<std::complex<double>> gamma;
|
||||||
|
std::vector<std::complex<double>> c;
|
||||||
|
std::vector<std::complex<double>> s;
|
||||||
|
|
||||||
|
GridBase* SinglePrecGrid;
|
||||||
|
|
||||||
|
LinearFunction<FieldF> &Preconditioner;
|
||||||
|
|
||||||
|
MixedPrecisionFlexibleGeneralisedMinimalResidual(RealD tol,
|
||||||
|
Integer maxit,
|
||||||
|
GridBase * sp_grid,
|
||||||
|
LinearFunction<FieldF> &Prec,
|
||||||
|
Integer restart_length,
|
||||||
|
bool err_on_no_conv = true)
|
||||||
|
: Tolerance(tol)
|
||||||
|
, MaxIterations(maxit)
|
||||||
|
, RestartLength(restart_length)
|
||||||
|
, MaxNumberOfRestarts(MaxIterations/RestartLength + ((MaxIterations%RestartLength == 0) ? 0 : 1))
|
||||||
|
, ErrorOnNoConverge(err_on_no_conv)
|
||||||
|
, H(Eigen::MatrixXcd::Zero(RestartLength, RestartLength + 1)) // sizes taken from DD-αAMG code base
|
||||||
|
, y(RestartLength + 1, 0.)
|
||||||
|
, gamma(RestartLength + 1, 0.)
|
||||||
|
, c(RestartLength + 1, 0.)
|
||||||
|
, s(RestartLength + 1, 0.)
|
||||||
|
, SinglePrecGrid(sp_grid)
|
||||||
|
, Preconditioner(Prec) {};
|
||||||
|
|
||||||
|
void operator()(LinearOperatorBase<FieldD> &LinOp, const FieldD &src, FieldD &psi) {
|
||||||
|
|
||||||
|
psi.checkerboard = src.checkerboard;
|
||||||
|
conformable(psi, src);
|
||||||
|
|
||||||
|
RealD guess = norm2(psi);
|
||||||
|
assert(std::isnan(guess) == 0);
|
||||||
|
|
||||||
|
RealD cp;
|
||||||
|
RealD ssq = norm2(src);
|
||||||
|
RealD rsq = Tolerance * Tolerance * ssq;
|
||||||
|
|
||||||
|
FieldD r(src._grid);
|
||||||
|
|
||||||
|
std::cout << std::setprecision(4) << std::scientific;
|
||||||
|
std::cout << GridLogIterative << "MPFGMRES: guess " << guess << std::endl;
|
||||||
|
std::cout << GridLogIterative << "MPFGMRES: src " << ssq << std::endl;
|
||||||
|
|
||||||
|
PrecTimer.Reset();
|
||||||
|
MatrixTimer.Reset();
|
||||||
|
LinalgTimer.Reset();
|
||||||
|
QrTimer.Reset();
|
||||||
|
CompSolutionTimer.Reset();
|
||||||
|
ChangePrecTimer.Reset();
|
||||||
|
|
||||||
|
GridStopWatch SolverTimer;
|
||||||
|
SolverTimer.Start();
|
||||||
|
|
||||||
|
IterationCount = 0;
|
||||||
|
|
||||||
|
for (int k=0; k<MaxNumberOfRestarts; k++) {
|
||||||
|
|
||||||
|
cp = outerLoopBody(LinOp, src, psi, rsq);
|
||||||
|
|
||||||
|
// Stopping condition
|
||||||
|
if (cp <= rsq) {
|
||||||
|
|
||||||
|
SolverTimer.Stop();
|
||||||
|
|
||||||
|
LinOp.Op(psi,r);
|
||||||
|
axpy(r,-1.0,src,r);
|
||||||
|
|
||||||
|
RealD srcnorm = sqrt(ssq);
|
||||||
|
RealD resnorm = sqrt(norm2(r));
|
||||||
|
RealD true_residual = resnorm / srcnorm;
|
||||||
|
|
||||||
|
std::cout << GridLogMessage << "MPFGMRES: Converged on iteration " << IterationCount
|
||||||
|
<< " computed residual " << sqrt(cp / ssq)
|
||||||
|
<< " true residual " << true_residual
|
||||||
|
<< " target " << Tolerance << std::endl;
|
||||||
|
|
||||||
|
std::cout << GridLogMessage << "MPFGMRES Time elapsed: Total " << SolverTimer.Elapsed() << std::endl;
|
||||||
|
std::cout << GridLogMessage << "MPFGMRES Time elapsed: Precon " << PrecTimer.Elapsed() << std::endl;
|
||||||
|
std::cout << GridLogMessage << "MPFGMRES Time elapsed: Matrix " << MatrixTimer.Elapsed() << std::endl;
|
||||||
|
std::cout << GridLogMessage << "MPFGMRES Time elapsed: Linalg " << LinalgTimer.Elapsed() << std::endl;
|
||||||
|
std::cout << GridLogMessage << "MPFGMRES Time elapsed: QR " << QrTimer.Elapsed() << std::endl;
|
||||||
|
std::cout << GridLogMessage << "MPFGMRES Time elapsed: CompSol " << CompSolutionTimer.Elapsed() << std::endl;
|
||||||
|
std::cout << GridLogMessage << "MPFGMRES Time elapsed: PrecChange " << ChangePrecTimer.Elapsed() << std::endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << GridLogMessage << "MPFGMRES did NOT converge" << std::endl;
|
||||||
|
|
||||||
|
if (ErrorOnNoConverge)
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
RealD outerLoopBody(LinearOperatorBase<FieldD> &LinOp, const FieldD &src, FieldD &psi, RealD rsq) {
|
||||||
|
|
||||||
|
RealD cp = 0;
|
||||||
|
|
||||||
|
FieldD w(src._grid);
|
||||||
|
FieldD r(src._grid);
|
||||||
|
|
||||||
|
// these should probably be made class members so that they are only allocated once, not in every restart
|
||||||
|
std::vector<FieldD> v(RestartLength + 1, src._grid); for (auto &elem : v) elem = zero;
|
||||||
|
std::vector<FieldD> z(RestartLength + 1, src._grid); for (auto &elem : z) elem = zero;
|
||||||
|
|
||||||
|
MatrixTimer.Start();
|
||||||
|
LinOp.Op(psi, w);
|
||||||
|
MatrixTimer.Stop();
|
||||||
|
|
||||||
|
LinalgTimer.Start();
|
||||||
|
r = src - w;
|
||||||
|
|
||||||
|
gamma[0] = sqrt(norm2(r));
|
||||||
|
|
||||||
|
v[0] = (1. / gamma[0]) * r;
|
||||||
|
LinalgTimer.Stop();
|
||||||
|
|
||||||
|
for (int i=0; i<RestartLength; i++) {
|
||||||
|
|
||||||
|
IterationCount++;
|
||||||
|
|
||||||
|
arnoldiStep(LinOp, v, z, w, i);
|
||||||
|
|
||||||
|
qrUpdate(i);
|
||||||
|
|
||||||
|
cp = std::norm(gamma[i+1]);
|
||||||
|
|
||||||
|
std::cout << GridLogIterative << "MPFGMRES: Iteration " << IterationCount
|
||||||
|
<< " residual " << cp << " target " << rsq << std::endl;
|
||||||
|
|
||||||
|
if ((i == RestartLength - 1) || (IterationCount == MaxIterations) || (cp <= rsq)) {
|
||||||
|
|
||||||
|
computeSolution(z, psi, i);
|
||||||
|
|
||||||
|
return cp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(0); // Never reached
|
||||||
|
return cp;
|
||||||
|
}
|
||||||
|
|
||||||
|
void arnoldiStep(LinearOperatorBase<FieldD> &LinOp, std::vector<FieldD> &v, std::vector<FieldD> &z, FieldD &w, int iter) {
|
||||||
|
|
||||||
|
FieldF v_f(SinglePrecGrid);
|
||||||
|
FieldF z_f(SinglePrecGrid);
|
||||||
|
|
||||||
|
ChangePrecTimer.Start();
|
||||||
|
precisionChange(v_f, v[iter]);
|
||||||
|
precisionChange(z_f, z[iter]);
|
||||||
|
ChangePrecTimer.Stop();
|
||||||
|
|
||||||
|
PrecTimer.Start();
|
||||||
|
Preconditioner(v_f, z_f);
|
||||||
|
PrecTimer.Stop();
|
||||||
|
|
||||||
|
ChangePrecTimer.Start();
|
||||||
|
precisionChange(z[iter], z_f);
|
||||||
|
ChangePrecTimer.Stop();
|
||||||
|
|
||||||
|
MatrixTimer.Start();
|
||||||
|
LinOp.Op(z[iter], w);
|
||||||
|
MatrixTimer.Stop();
|
||||||
|
|
||||||
|
LinalgTimer.Start();
|
||||||
|
for (int i = 0; i <= iter; ++i) {
|
||||||
|
H(iter, i) = innerProduct(v[i], w);
|
||||||
|
w = w - H(iter, i) * v[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
H(iter, iter + 1) = sqrt(norm2(w));
|
||||||
|
v[iter + 1] = (1. / H(iter, iter + 1)) * w;
|
||||||
|
LinalgTimer.Stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
void qrUpdate(int iter) {
|
||||||
|
|
||||||
|
QrTimer.Start();
|
||||||
|
for (int i = 0; i < iter ; ++i) {
|
||||||
|
auto tmp = -s[i] * H(iter, i) + c[i] * H(iter, i + 1);
|
||||||
|
H(iter, i) = std::conj(c[i]) * H(iter, i) + std::conj(s[i]) * H(iter, i + 1);
|
||||||
|
H(iter, i + 1) = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute new Givens Rotation
|
||||||
|
ComplexD nu = sqrt(std::norm(H(iter, iter)) + std::norm(H(iter, iter + 1)));
|
||||||
|
c[iter] = H(iter, iter) / nu;
|
||||||
|
s[iter] = H(iter, iter + 1) / nu;
|
||||||
|
|
||||||
|
// Apply new Givens rotation
|
||||||
|
H(iter, iter) = nu;
|
||||||
|
H(iter, iter + 1) = 0.;
|
||||||
|
|
||||||
|
gamma[iter + 1] = -s[iter] * gamma[iter];
|
||||||
|
gamma[iter] = std::conj(c[iter]) * gamma[iter];
|
||||||
|
QrTimer.Stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
void computeSolution(std::vector<FieldD> const &z, FieldD &psi, int iter) {
|
||||||
|
|
||||||
|
CompSolutionTimer.Start();
|
||||||
|
for (int i = iter; i >= 0; i--) {
|
||||||
|
y[i] = gamma[i];
|
||||||
|
for (int k = i + 1; k <= iter; k++)
|
||||||
|
y[i] = y[i] - H(k, i) * y[k];
|
||||||
|
y[i] = y[i] / H(i, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i <= iter; i++)
|
||||||
|
psi = psi + z[i] * y[i];
|
||||||
|
CompSolutionTimer.Stop();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#endif
|
||||||
File renamed without changes.
File renamed without changes.
+13
-2
@@ -139,7 +139,10 @@ namespace Grid {
|
|||||||
MatTimer.Start();
|
MatTimer.Start();
|
||||||
Linop.HermOpAndNorm(psi,Az,zAz,zAAz);
|
Linop.HermOpAndNorm(psi,Az,zAz,zAAz);
|
||||||
MatTimer.Stop();
|
MatTimer.Stop();
|
||||||
|
|
||||||
|
LinalgTimer.Start();
|
||||||
r=src-Az;
|
r=src-Az;
|
||||||
|
LinalgTimer.Stop();
|
||||||
|
|
||||||
/////////////////////
|
/////////////////////
|
||||||
// p = Prec(r)
|
// p = Prec(r)
|
||||||
@@ -152,8 +155,10 @@ namespace Grid {
|
|||||||
Linop.HermOp(z,tmp);
|
Linop.HermOp(z,tmp);
|
||||||
MatTimer.Stop();
|
MatTimer.Stop();
|
||||||
|
|
||||||
|
LinalgTimer.Start();
|
||||||
ttmp=tmp;
|
ttmp=tmp;
|
||||||
tmp=tmp-r;
|
tmp=tmp-r;
|
||||||
|
LinalgTimer.Stop();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
std::cout<<GridLogMessage<<r<<std::endl;
|
std::cout<<GridLogMessage<<r<<std::endl;
|
||||||
@@ -166,12 +171,14 @@ namespace Grid {
|
|||||||
Linop.HermOpAndNorm(z,Az,zAz,zAAz);
|
Linop.HermOpAndNorm(z,Az,zAz,zAAz);
|
||||||
MatTimer.Stop();
|
MatTimer.Stop();
|
||||||
|
|
||||||
|
LinalgTimer.Start();
|
||||||
//p[0],q[0],qq[0]
|
//p[0],q[0],qq[0]
|
||||||
p[0]= z;
|
p[0]= z;
|
||||||
q[0]= Az;
|
q[0]= Az;
|
||||||
qq[0]= zAAz;
|
qq[0]= zAAz;
|
||||||
|
|
||||||
cp =norm2(r);
|
cp =norm2(r);
|
||||||
|
LinalgTimer.Stop();
|
||||||
|
|
||||||
for(int k=0;k<nstep;k++){
|
for(int k=0;k<nstep;k++){
|
||||||
|
|
||||||
@@ -181,12 +188,14 @@ namespace Grid {
|
|||||||
int peri_k = k %mmax;
|
int peri_k = k %mmax;
|
||||||
int peri_kp= kp%mmax;
|
int peri_kp= kp%mmax;
|
||||||
|
|
||||||
|
LinalgTimer.Start();
|
||||||
rq= real(innerProduct(r,q[peri_k])); // what if rAr not real?
|
rq= real(innerProduct(r,q[peri_k])); // what if rAr not real?
|
||||||
a = rq/qq[peri_k];
|
a = rq/qq[peri_k];
|
||||||
|
|
||||||
axpy(psi,a,p[peri_k],psi);
|
axpy(psi,a,p[peri_k],psi);
|
||||||
|
|
||||||
cp = axpy_norm(r,-a,q[peri_k],r);
|
cp = axpy_norm(r,-a,q[peri_k],r);
|
||||||
|
LinalgTimer.Stop();
|
||||||
|
|
||||||
if((k==nstep-1)||(cp<rsq)){
|
if((k==nstep-1)||(cp<rsq)){
|
||||||
return cp;
|
return cp;
|
||||||
@@ -202,6 +211,8 @@ namespace Grid {
|
|||||||
Linop.HermOpAndNorm(z,Az,zAz,zAAz);
|
Linop.HermOpAndNorm(z,Az,zAz,zAAz);
|
||||||
Linop.HermOp(z,tmp);
|
Linop.HermOp(z,tmp);
|
||||||
MatTimer.Stop();
|
MatTimer.Stop();
|
||||||
|
|
||||||
|
LinalgTimer.Start();
|
||||||
tmp=tmp-r;
|
tmp=tmp-r;
|
||||||
std::cout<<GridLogMessage<< " Preconditioner resid " <<sqrt(norm2(tmp)/norm2(r))<<std::endl;
|
std::cout<<GridLogMessage<< " Preconditioner resid " <<sqrt(norm2(tmp)/norm2(r))<<std::endl;
|
||||||
|
|
||||||
@@ -219,9 +230,9 @@ namespace Grid {
|
|||||||
|
|
||||||
}
|
}
|
||||||
qq[peri_kp]=norm2(q[peri_kp]); // could use axpy_norm
|
qq[peri_kp]=norm2(q[peri_kp]); // could use axpy_norm
|
||||||
|
LinalgTimer.Stop();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(0); // never reached
|
assert(0); // never reached
|
||||||
return cp;
|
return cp;
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,473 @@
|
|||||||
|
/*************************************************************************************
|
||||||
|
|
||||||
|
Grid physics library, www.github.com/paboyle/Grid
|
||||||
|
|
||||||
|
Source file: ./lib/algorithms/iterative/SchurRedBlack.h
|
||||||
|
|
||||||
|
Copyright (C) 2015
|
||||||
|
|
||||||
|
Author: Peter Boyle <paboyle@ph.ed.ac.uk>
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License along
|
||||||
|
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
|
||||||
|
See the full license in the file "LICENSE" in the top level distribution directory
|
||||||
|
*************************************************************************************/
|
||||||
|
/* END LEGAL */
|
||||||
|
#ifndef GRID_SCHUR_RED_BLACK_H
|
||||||
|
#define GRID_SCHUR_RED_BLACK_H
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Red black Schur decomposition
|
||||||
|
*
|
||||||
|
* M = (Mee Meo) = (1 0 ) (Mee 0 ) (1 Mee^{-1} Meo)
|
||||||
|
* (Moe Moo) (Moe Mee^-1 1 ) (0 Moo-Moe Mee^-1 Meo) (0 1 )
|
||||||
|
* = L D U
|
||||||
|
*
|
||||||
|
* L^-1 = (1 0 )
|
||||||
|
* (-MoeMee^{-1} 1 )
|
||||||
|
* L^{dag} = ( 1 Mee^{-dag} Moe^{dag} )
|
||||||
|
* ( 0 1 )
|
||||||
|
* L^{-d} = ( 1 -Mee^{-dag} Moe^{dag} )
|
||||||
|
* ( 0 1 )
|
||||||
|
*
|
||||||
|
* U^-1 = (1 -Mee^{-1} Meo)
|
||||||
|
* (0 1 )
|
||||||
|
* U^{dag} = ( 1 0)
|
||||||
|
* (Meo^dag Mee^{-dag} 1)
|
||||||
|
* U^{-dag} = ( 1 0)
|
||||||
|
* (-Meo^dag Mee^{-dag} 1)
|
||||||
|
***********************
|
||||||
|
* M psi = eta
|
||||||
|
***********************
|
||||||
|
*Odd
|
||||||
|
* i) D_oo psi_o = L^{-1} eta_o
|
||||||
|
* eta_o' = (D_oo)^dag (eta_o - Moe Mee^{-1} eta_e)
|
||||||
|
*
|
||||||
|
* Wilson:
|
||||||
|
* (D_oo)^{\dag} D_oo psi_o = (D_oo)^dag L^{-1} eta_o
|
||||||
|
* Stag:
|
||||||
|
* D_oo psi_o = L^{-1} eta = (eta_o - Moe Mee^{-1} eta_e)
|
||||||
|
*
|
||||||
|
* L^-1 eta_o= (1 0 ) (e
|
||||||
|
* (-MoeMee^{-1} 1 )
|
||||||
|
*
|
||||||
|
*Even
|
||||||
|
* ii) Mee psi_e + Meo psi_o = src_e
|
||||||
|
*
|
||||||
|
* => sol_e = M_ee^-1 * ( src_e - Meo sol_o )...
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* TODO: Other options:
|
||||||
|
*
|
||||||
|
* a) change checkerboards for Schur e<->o
|
||||||
|
*
|
||||||
|
* Left precon by Moo^-1
|
||||||
|
* b) Doo^{dag} M_oo^-dag Moo^-1 Doo psi_0 = (D_oo)^dag M_oo^-dag Moo^-1 L^{-1} eta_o
|
||||||
|
* eta_o' = (D_oo)^dag M_oo^-dag Moo^-1 (eta_o - Moe Mee^{-1} eta_e)
|
||||||
|
*
|
||||||
|
* Right precon by Moo^-1
|
||||||
|
* c) M_oo^-dag Doo^{dag} Doo Moo^-1 phi_0 = M_oo^-dag (D_oo)^dag L^{-1} eta_o
|
||||||
|
* eta_o' = M_oo^-dag (D_oo)^dag (eta_o - Moe Mee^{-1} eta_e)
|
||||||
|
* psi_o = M_oo^-1 phi_o
|
||||||
|
* TODO: Deflation
|
||||||
|
*/
|
||||||
|
namespace Grid {
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Use base class to share code
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Take a matrix and form a Red Black solver calling a Herm solver
|
||||||
|
// Use of RB info prevents making SchurRedBlackSolve conform to standard interface
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
template<class Field> class SchurRedBlackBase {
|
||||||
|
protected:
|
||||||
|
typedef CheckerBoardedSparseMatrixBase<Field> Matrix;
|
||||||
|
OperatorFunction<Field> & _HermitianRBSolver;
|
||||||
|
int CBfactorise;
|
||||||
|
bool subGuess;
|
||||||
|
public:
|
||||||
|
|
||||||
|
SchurRedBlackBase(OperatorFunction<Field> &HermitianRBSolver, const bool initSubGuess = false) :
|
||||||
|
_HermitianRBSolver(HermitianRBSolver)
|
||||||
|
{
|
||||||
|
CBfactorise = 0;
|
||||||
|
subtractGuess(initSubGuess);
|
||||||
|
};
|
||||||
|
void subtractGuess(const bool initSubGuess)
|
||||||
|
{
|
||||||
|
subGuess = initSubGuess;
|
||||||
|
}
|
||||||
|
bool isSubtractGuess(void)
|
||||||
|
{
|
||||||
|
return subGuess;
|
||||||
|
}
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////
|
||||||
|
// Shared code
|
||||||
|
/////////////////////////////////////////////////////////////
|
||||||
|
void operator() (Matrix & _Matrix,const Field &in, Field &out){
|
||||||
|
ZeroGuesser<Field> guess;
|
||||||
|
(*this)(_Matrix,in,out,guess);
|
||||||
|
}
|
||||||
|
void operator()(Matrix &_Matrix, const std::vector<Field> &in, std::vector<Field> &out)
|
||||||
|
{
|
||||||
|
ZeroGuesser<Field> guess;
|
||||||
|
(*this)(_Matrix,in,out,guess);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Guesser>
|
||||||
|
void operator()(Matrix &_Matrix, const std::vector<Field> &in, std::vector<Field> &out,Guesser &guess)
|
||||||
|
{
|
||||||
|
GridBase *grid = _Matrix.RedBlackGrid();
|
||||||
|
GridBase *fgrid= _Matrix.Grid();
|
||||||
|
int nblock = in.size();
|
||||||
|
|
||||||
|
std::vector<Field> src_o(nblock,grid);
|
||||||
|
std::vector<Field> sol_o(nblock,grid);
|
||||||
|
|
||||||
|
std::vector<Field> guess_save;
|
||||||
|
|
||||||
|
Field resid(fgrid);
|
||||||
|
Field tmp(grid);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////
|
||||||
|
// Prepare RedBlack source
|
||||||
|
////////////////////////////////////////////////
|
||||||
|
for(int b=0;b<nblock;b++){
|
||||||
|
RedBlackSource(_Matrix,in[b],tmp,src_o[b]);
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////
|
||||||
|
// Make the guesses
|
||||||
|
////////////////////////////////////////////////
|
||||||
|
if ( subGuess ) guess_save.resize(nblock,grid);
|
||||||
|
|
||||||
|
for(int b=0;b<nblock;b++){
|
||||||
|
guess(src_o[b],sol_o[b]);
|
||||||
|
|
||||||
|
if ( subGuess ) {
|
||||||
|
guess_save[b] = sol_o[b];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//////////////////////////////////////////////////////////////
|
||||||
|
// Call the block solver
|
||||||
|
//////////////////////////////////////////////////////////////
|
||||||
|
std::cout<<GridLogMessage << "SchurRedBlackBase calling the solver for "<<nblock<<" RHS" <<std::endl;
|
||||||
|
RedBlackSolve(_Matrix,src_o,sol_o);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////
|
||||||
|
// A2A boolean behavioural control & reconstruct other checkerboard
|
||||||
|
////////////////////////////////////////////////
|
||||||
|
for(int b=0;b<nblock;b++) {
|
||||||
|
|
||||||
|
if (subGuess) sol_o[b] = sol_o[b] - guess_save[b];
|
||||||
|
|
||||||
|
///////// Needs even source //////////////
|
||||||
|
pickCheckerboard(Even,tmp,in[b]);
|
||||||
|
RedBlackSolution(_Matrix,sol_o[b],tmp,out[b]);
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////
|
||||||
|
// Check unprec residual if possible
|
||||||
|
/////////////////////////////////////////////////
|
||||||
|
if ( ! subGuess ) {
|
||||||
|
_Matrix.M(out[b],resid);
|
||||||
|
resid = resid-in[b];
|
||||||
|
RealD ns = norm2(in[b]);
|
||||||
|
RealD nr = norm2(resid);
|
||||||
|
|
||||||
|
std::cout<<GridLogMessage<< "SchurRedBlackBase solver true unprec resid["<<b<<"] "<<std::sqrt(nr/ns) << std::endl;
|
||||||
|
} else {
|
||||||
|
std::cout<<GridLogMessage<< "SchurRedBlackBase Guess subtracted after solve["<<b<<"] " << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
template<class Guesser>
|
||||||
|
void operator() (Matrix & _Matrix,const Field &in, Field &out,Guesser &guess){
|
||||||
|
|
||||||
|
// FIXME CGdiagonalMee not implemented virtual function
|
||||||
|
// FIXME use CBfactorise to control schur decomp
|
||||||
|
GridBase *grid = _Matrix.RedBlackGrid();
|
||||||
|
GridBase *fgrid= _Matrix.Grid();
|
||||||
|
|
||||||
|
Field resid(fgrid);
|
||||||
|
Field src_o(grid);
|
||||||
|
Field src_e(grid);
|
||||||
|
Field sol_o(grid);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////
|
||||||
|
// RedBlack source
|
||||||
|
////////////////////////////////////////////////
|
||||||
|
RedBlackSource(_Matrix,in,src_e,src_o);
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
// Construct the guess
|
||||||
|
////////////////////////////////
|
||||||
|
Field tmp(grid);
|
||||||
|
guess(src_o,sol_o);
|
||||||
|
|
||||||
|
Field guess_save(grid);
|
||||||
|
guess_save = sol_o;
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////
|
||||||
|
// Call the red-black solver
|
||||||
|
//////////////////////////////////////////////////////////////
|
||||||
|
RedBlackSolve(_Matrix,src_o,sol_o);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////
|
||||||
|
// Fionn A2A boolean behavioural control
|
||||||
|
////////////////////////////////////////////////
|
||||||
|
if (subGuess) sol_o= sol_o-guess_save;
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////
|
||||||
|
// RedBlack solution needs the even source
|
||||||
|
///////////////////////////////////////////////////
|
||||||
|
RedBlackSolution(_Matrix,sol_o,src_e,out);
|
||||||
|
|
||||||
|
// Verify the unprec residual
|
||||||
|
if ( ! subGuess ) {
|
||||||
|
_Matrix.M(out,resid);
|
||||||
|
resid = resid-in;
|
||||||
|
RealD ns = norm2(in);
|
||||||
|
RealD nr = norm2(resid);
|
||||||
|
|
||||||
|
std::cout<<GridLogMessage << "SchurRedBlackBase solver true unprec resid "<< std::sqrt(nr/ns) << std::endl;
|
||||||
|
} else {
|
||||||
|
std::cout << GridLogMessage << "SchurRedBlackBase Guess subtracted after solve." << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////
|
||||||
|
// Override in derived. Not virtual as template methods
|
||||||
|
/////////////////////////////////////////////////////////////
|
||||||
|
virtual void RedBlackSource (Matrix & _Matrix,const Field &src, Field &src_e,Field &src_o) =0;
|
||||||
|
virtual void RedBlackSolution(Matrix & _Matrix,const Field &sol_o, const Field &src_e,Field &sol) =0;
|
||||||
|
virtual void RedBlackSolve (Matrix & _Matrix,const Field &src_o, Field &sol_o) =0;
|
||||||
|
virtual void RedBlackSolve (Matrix & _Matrix,const std::vector<Field> &src_o, std::vector<Field> &sol_o)=0;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class Field> class SchurRedBlackStaggeredSolve : public SchurRedBlackBase<Field> {
|
||||||
|
public:
|
||||||
|
typedef CheckerBoardedSparseMatrixBase<Field> Matrix;
|
||||||
|
|
||||||
|
SchurRedBlackStaggeredSolve(OperatorFunction<Field> &HermitianRBSolver, const bool initSubGuess = false)
|
||||||
|
: SchurRedBlackBase<Field> (HermitianRBSolver,initSubGuess)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////
|
||||||
|
// Override RedBlack specialisation
|
||||||
|
//////////////////////////////////////////////////////
|
||||||
|
virtual void RedBlackSource(Matrix & _Matrix,const Field &src, Field &src_e,Field &src_o)
|
||||||
|
{
|
||||||
|
GridBase *grid = _Matrix.RedBlackGrid();
|
||||||
|
GridBase *fgrid= _Matrix.Grid();
|
||||||
|
|
||||||
|
Field tmp(grid);
|
||||||
|
Field Mtmp(grid);
|
||||||
|
|
||||||
|
pickCheckerboard(Even,src_e,src);
|
||||||
|
pickCheckerboard(Odd ,src_o,src);
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////
|
||||||
|
// src_o = (source_o - Moe MeeInv source_e)
|
||||||
|
/////////////////////////////////////////////////////
|
||||||
|
_Matrix.MooeeInv(src_e,tmp); assert( tmp.checkerboard ==Even);
|
||||||
|
_Matrix.Meooe (tmp,Mtmp); assert( Mtmp.checkerboard ==Odd);
|
||||||
|
tmp=src_o-Mtmp; assert( tmp.checkerboard ==Odd);
|
||||||
|
|
||||||
|
_Matrix.Mooee(tmp,src_o); // Extra factor of "m" in source from dumb choice of matrix norm.
|
||||||
|
}
|
||||||
|
virtual void RedBlackSolution(Matrix & _Matrix,const Field &sol_o, const Field &src_e_c,Field &sol)
|
||||||
|
{
|
||||||
|
GridBase *grid = _Matrix.RedBlackGrid();
|
||||||
|
GridBase *fgrid= _Matrix.Grid();
|
||||||
|
|
||||||
|
Field tmp(grid);
|
||||||
|
Field sol_e(grid);
|
||||||
|
Field src_e(grid);
|
||||||
|
|
||||||
|
src_e = src_e_c; // Const correctness
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////
|
||||||
|
// sol_e = M_ee^-1 * ( src_e - Meo sol_o )...
|
||||||
|
///////////////////////////////////////////////////
|
||||||
|
_Matrix.Meooe(sol_o,tmp); assert( tmp.checkerboard ==Even);
|
||||||
|
src_e = src_e-tmp; assert( src_e.checkerboard ==Even);
|
||||||
|
_Matrix.MooeeInv(src_e,sol_e); assert( sol_e.checkerboard ==Even);
|
||||||
|
|
||||||
|
setCheckerboard(sol,sol_e); assert( sol_e.checkerboard ==Even);
|
||||||
|
setCheckerboard(sol,sol_o); assert( sol_o.checkerboard ==Odd );
|
||||||
|
}
|
||||||
|
virtual void RedBlackSolve (Matrix & _Matrix,const Field &src_o, Field &sol_o)
|
||||||
|
{
|
||||||
|
SchurStaggeredOperator<Matrix,Field> _HermOpEO(_Matrix);
|
||||||
|
this->_HermitianRBSolver(_HermOpEO,src_o,sol_o); assert(sol_o.checkerboard==Odd);
|
||||||
|
};
|
||||||
|
virtual void RedBlackSolve (Matrix & _Matrix,const std::vector<Field> &src_o, std::vector<Field> &sol_o)
|
||||||
|
{
|
||||||
|
SchurStaggeredOperator<Matrix,Field> _HermOpEO(_Matrix);
|
||||||
|
this->_HermitianRBSolver(_HermOpEO,src_o,sol_o);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
template<class Field> using SchurRedBlackStagSolve = SchurRedBlackStaggeredSolve<Field>;
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Site diagonal has Mooee on it.
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
template<class Field> class SchurRedBlackDiagMooeeSolve : public SchurRedBlackBase<Field> {
|
||||||
|
public:
|
||||||
|
typedef CheckerBoardedSparseMatrixBase<Field> Matrix;
|
||||||
|
|
||||||
|
SchurRedBlackDiagMooeeSolve(OperatorFunction<Field> &HermitianRBSolver, const bool initSubGuess = false)
|
||||||
|
: SchurRedBlackBase<Field> (HermitianRBSolver,initSubGuess) {};
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////
|
||||||
|
// Override RedBlack specialisation
|
||||||
|
//////////////////////////////////////////////////////
|
||||||
|
virtual void RedBlackSource(Matrix & _Matrix,const Field &src, Field &src_e,Field &src_o)
|
||||||
|
{
|
||||||
|
GridBase *grid = _Matrix.RedBlackGrid();
|
||||||
|
GridBase *fgrid= _Matrix.Grid();
|
||||||
|
|
||||||
|
Field tmp(grid);
|
||||||
|
Field Mtmp(grid);
|
||||||
|
|
||||||
|
pickCheckerboard(Even,src_e,src);
|
||||||
|
pickCheckerboard(Odd ,src_o,src);
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////
|
||||||
|
// src_o = Mdag * (source_o - Moe MeeInv source_e)
|
||||||
|
/////////////////////////////////////////////////////
|
||||||
|
_Matrix.MooeeInv(src_e,tmp); assert( tmp.checkerboard ==Even);
|
||||||
|
_Matrix.Meooe (tmp,Mtmp); assert( Mtmp.checkerboard ==Odd);
|
||||||
|
tmp=src_o-Mtmp; assert( tmp.checkerboard ==Odd);
|
||||||
|
|
||||||
|
// get the right MpcDag
|
||||||
|
SchurDiagMooeeOperator<Matrix,Field> _HermOpEO(_Matrix);
|
||||||
|
_HermOpEO.MpcDag(tmp,src_o); assert(src_o.checkerboard ==Odd);
|
||||||
|
|
||||||
|
}
|
||||||
|
virtual void RedBlackSolution(Matrix & _Matrix,const Field &sol_o, const Field &src_e,Field &sol)
|
||||||
|
{
|
||||||
|
GridBase *grid = _Matrix.RedBlackGrid();
|
||||||
|
GridBase *fgrid= _Matrix.Grid();
|
||||||
|
|
||||||
|
Field tmp(grid);
|
||||||
|
Field sol_e(grid);
|
||||||
|
Field src_e_i(grid);
|
||||||
|
///////////////////////////////////////////////////
|
||||||
|
// sol_e = M_ee^-1 * ( src_e - Meo sol_o )...
|
||||||
|
///////////////////////////////////////////////////
|
||||||
|
_Matrix.Meooe(sol_o,tmp); assert( tmp.checkerboard ==Even);
|
||||||
|
src_e_i = src_e-tmp; assert( src_e_i.checkerboard ==Even);
|
||||||
|
_Matrix.MooeeInv(src_e_i,sol_e); assert( sol_e.checkerboard ==Even);
|
||||||
|
|
||||||
|
setCheckerboard(sol,sol_e); assert( sol_e.checkerboard ==Even);
|
||||||
|
setCheckerboard(sol,sol_o); assert( sol_o.checkerboard ==Odd );
|
||||||
|
}
|
||||||
|
virtual void RedBlackSolve (Matrix & _Matrix,const Field &src_o, Field &sol_o)
|
||||||
|
{
|
||||||
|
SchurDiagMooeeOperator<Matrix,Field> _HermOpEO(_Matrix);
|
||||||
|
this->_HermitianRBSolver(_HermOpEO,src_o,sol_o); assert(sol_o.checkerboard==Odd);
|
||||||
|
};
|
||||||
|
virtual void RedBlackSolve (Matrix & _Matrix,const std::vector<Field> &src_o, std::vector<Field> &sol_o)
|
||||||
|
{
|
||||||
|
SchurDiagMooeeOperator<Matrix,Field> _HermOpEO(_Matrix);
|
||||||
|
this->_HermitianRBSolver(_HermOpEO,src_o,sol_o);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Site diagonal is identity, right preconditioned by Mee^inv
|
||||||
|
// ( 1 - Meo Moo^inv Moe Mee^inv ) phi =( 1 - Meo Moo^inv Moe Mee^inv ) Mee psi = = eta = eta
|
||||||
|
//=> psi = MeeInv phi
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
template<class Field> class SchurRedBlackDiagTwoSolve : public SchurRedBlackBase<Field> {
|
||||||
|
public:
|
||||||
|
typedef CheckerBoardedSparseMatrixBase<Field> Matrix;
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////
|
||||||
|
// Wrap the usual normal equations Schur trick
|
||||||
|
/////////////////////////////////////////////////////
|
||||||
|
SchurRedBlackDiagTwoSolve(OperatorFunction<Field> &HermitianRBSolver, const bool initSubGuess = false)
|
||||||
|
: SchurRedBlackBase<Field>(HermitianRBSolver,initSubGuess) {};
|
||||||
|
|
||||||
|
virtual void RedBlackSource(Matrix & _Matrix,const Field &src, Field &src_e,Field &src_o)
|
||||||
|
{
|
||||||
|
GridBase *grid = _Matrix.RedBlackGrid();
|
||||||
|
GridBase *fgrid= _Matrix.Grid();
|
||||||
|
|
||||||
|
SchurDiagTwoOperator<Matrix,Field> _HermOpEO(_Matrix);
|
||||||
|
|
||||||
|
Field tmp(grid);
|
||||||
|
Field Mtmp(grid);
|
||||||
|
|
||||||
|
pickCheckerboard(Even,src_e,src);
|
||||||
|
pickCheckerboard(Odd ,src_o,src);
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////
|
||||||
|
// src_o = Mdag * (source_o - Moe MeeInv source_e)
|
||||||
|
/////////////////////////////////////////////////////
|
||||||
|
_Matrix.MooeeInv(src_e,tmp); assert( tmp.checkerboard ==Even);
|
||||||
|
_Matrix.Meooe (tmp,Mtmp); assert( Mtmp.checkerboard ==Odd);
|
||||||
|
tmp=src_o-Mtmp; assert( tmp.checkerboard ==Odd);
|
||||||
|
|
||||||
|
// get the right MpcDag
|
||||||
|
_HermOpEO.MpcDag(tmp,src_o); assert(src_o.checkerboard ==Odd);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void RedBlackSolution(Matrix & _Matrix,const Field &sol_o, const Field &src_e,Field &sol)
|
||||||
|
{
|
||||||
|
GridBase *grid = _Matrix.RedBlackGrid();
|
||||||
|
GridBase *fgrid= _Matrix.Grid();
|
||||||
|
|
||||||
|
Field sol_o_i(grid);
|
||||||
|
Field tmp(grid);
|
||||||
|
Field sol_e(grid);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////
|
||||||
|
// MooeeInv due to pecond
|
||||||
|
////////////////////////////////////////////////
|
||||||
|
_Matrix.MooeeInv(sol_o,tmp);
|
||||||
|
sol_o_i = tmp;
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////
|
||||||
|
// sol_e = M_ee^-1 * ( src_e - Meo sol_o )...
|
||||||
|
///////////////////////////////////////////////////
|
||||||
|
_Matrix.Meooe(sol_o_i,tmp); assert( tmp.checkerboard ==Even);
|
||||||
|
tmp = src_e-tmp; assert( src_e.checkerboard ==Even);
|
||||||
|
_Matrix.MooeeInv(tmp,sol_e); assert( sol_e.checkerboard ==Even);
|
||||||
|
|
||||||
|
setCheckerboard(sol,sol_e); assert( sol_e.checkerboard ==Even);
|
||||||
|
setCheckerboard(sol,sol_o_i); assert( sol_o_i.checkerboard ==Odd );
|
||||||
|
};
|
||||||
|
|
||||||
|
virtual void RedBlackSolve (Matrix & _Matrix,const Field &src_o, Field &sol_o)
|
||||||
|
{
|
||||||
|
SchurDiagTwoOperator<Matrix,Field> _HermOpEO(_Matrix);
|
||||||
|
this->_HermitianRBSolver(_HermOpEO,src_o,sol_o);
|
||||||
|
};
|
||||||
|
virtual void RedBlackSolve (Matrix & _Matrix,const std::vector<Field> &src_o, std::vector<Field> &sol_o)
|
||||||
|
{
|
||||||
|
SchurDiagTwoOperator<Matrix,Field> _HermOpEO(_Matrix);
|
||||||
|
this->_HermitianRBSolver(_HermOpEO,src_o,sol_o);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#endif
|
||||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -50,8 +50,6 @@ void CartesianCommunicator::Init(int *argc, char ***argv)
|
|||||||
assert(0);
|
assert(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
Grid_quiesce_nodes();
|
|
||||||
|
|
||||||
// Never clean up as done once.
|
// Never clean up as done once.
|
||||||
MPI_Comm_dup (MPI_COMM_WORLD,&communicator_world);
|
MPI_Comm_dup (MPI_COMM_WORLD,&communicator_world);
|
||||||
|
|
||||||
@@ -124,10 +122,8 @@ CartesianCommunicator::CartesianCommunicator(const std::vector<int> &processors,
|
|||||||
// split the communicator
|
// split the communicator
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// int Nparent = parent._processors ;
|
// int Nparent = parent._processors ;
|
||||||
// std::cout << " splitting from communicator "<<parent.communicator <<std::endl;
|
|
||||||
int Nparent;
|
int Nparent;
|
||||||
MPI_Comm_size(parent.communicator,&Nparent);
|
MPI_Comm_size(parent.communicator,&Nparent);
|
||||||
// std::cout << " Parent size "<<Nparent <<std::endl;
|
|
||||||
|
|
||||||
int childsize=1;
|
int childsize=1;
|
||||||
for(int d=0;d<processors.size();d++) {
|
for(int d=0;d<processors.size();d++) {
|
||||||
@@ -136,8 +132,6 @@ CartesianCommunicator::CartesianCommunicator(const std::vector<int> &processors,
|
|||||||
int Nchild = Nparent/childsize;
|
int Nchild = Nparent/childsize;
|
||||||
assert (childsize * Nchild == Nparent);
|
assert (childsize * Nchild == Nparent);
|
||||||
|
|
||||||
// std::cout << " child size "<<childsize <<std::endl;
|
|
||||||
|
|
||||||
std::vector<int> ccoor(_ndimension); // coor within subcommunicator
|
std::vector<int> ccoor(_ndimension); // coor within subcommunicator
|
||||||
std::vector<int> scoor(_ndimension); // coor of split within parent
|
std::vector<int> scoor(_ndimension); // coor of split within parent
|
||||||
std::vector<int> ssize(_ndimension); // coor of split within parent
|
std::vector<int> ssize(_ndimension); // coor of split within parent
|
||||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -114,19 +114,150 @@ void GlobalSharedMemory::Init(Grid_MPI_Comm comm)
|
|||||||
assert(WorldNode!=-1);
|
assert(WorldNode!=-1);
|
||||||
_ShmSetup=1;
|
_ShmSetup=1;
|
||||||
}
|
}
|
||||||
|
// Gray encode support
|
||||||
void GlobalSharedMemory::OptimalCommunicator(const std::vector<int> &processors,Grid_MPI_Comm & optimal_comm)
|
int BinaryToGray (int binary) {
|
||||||
|
int gray = (binary>>1)^binary;
|
||||||
|
return gray;
|
||||||
|
}
|
||||||
|
int Log2Size(int TwoToPower,int MAXLOG2)
|
||||||
{
|
{
|
||||||
////////////////////////////////////////////////////////////////
|
|
||||||
// Assert power of two shm_size.
|
|
||||||
////////////////////////////////////////////////////////////////
|
|
||||||
int log2size = -1;
|
int log2size = -1;
|
||||||
for(int i=0;i<=MAXLOG2RANKSPERNODE;i++){
|
for(int i=0;i<=MAXLOG2;i++){
|
||||||
if ( (0x1<<i) == WorldShmSize ) {
|
if ( (0x1<<i) == TwoToPower ) {
|
||||||
log2size = i;
|
log2size = i;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return log2size;
|
||||||
|
}
|
||||||
|
void GlobalSharedMemory::OptimalCommunicator(const std::vector<int> &processors,Grid_MPI_Comm & optimal_comm)
|
||||||
|
{
|
||||||
|
#ifdef HYPERCUBE
|
||||||
|
////////////////////////////////////////////////////////////////
|
||||||
|
// Assert power of two shm_size.
|
||||||
|
////////////////////////////////////////////////////////////////
|
||||||
|
int log2size = Log2Size(WorldShmSize,MAXLOG2RANKSPERNODE);
|
||||||
|
assert(log2size != -1);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////
|
||||||
|
// Identify the hypercube coordinate of this node using hostname
|
||||||
|
////////////////////////////////////////////////////////////////
|
||||||
|
// n runs 0...7 9...16 18...25 27...34 (8*4) 5 bits
|
||||||
|
// i runs 0..7 3 bits
|
||||||
|
// r runs 0..3 2 bits
|
||||||
|
// 2^10 = 1024 nodes
|
||||||
|
const int maxhdim = 10;
|
||||||
|
std::vector<int> HyperCubeCoords(maxhdim,0);
|
||||||
|
std::vector<int> RootHyperCubeCoords(maxhdim,0);
|
||||||
|
int R;
|
||||||
|
int I;
|
||||||
|
int N;
|
||||||
|
const int namelen = _POSIX_HOST_NAME_MAX;
|
||||||
|
char name[namelen];
|
||||||
|
|
||||||
|
// Parse ICE-XA hostname to get hypercube location
|
||||||
|
gethostname(name,namelen);
|
||||||
|
int nscan = sscanf(name,"r%di%dn%d",&R,&I,&N) ;
|
||||||
|
assert(nscan==3);
|
||||||
|
|
||||||
|
int nlo = N%9;
|
||||||
|
int nhi = N/9;
|
||||||
|
uint32_t hypercoor = (R<<8)|(I<<5)|(nhi<<3)|nlo ;
|
||||||
|
uint32_t rootcoor = hypercoor;
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////
|
||||||
|
// Print debug info
|
||||||
|
//////////////////////////////////////////////////////////////////
|
||||||
|
for(int d=0;d<maxhdim;d++){
|
||||||
|
HyperCubeCoords[d] = (hypercoor>>d)&0x1;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string hname(name);
|
||||||
|
std::cout << "hostname "<<hname<<std::endl;
|
||||||
|
std::cout << "R " << R << " I " << I << " N "<< N
|
||||||
|
<< " hypercoor 0x"<<std::hex<<hypercoor<<std::dec<<std::endl;
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////
|
||||||
|
// broadcast node 0's base coordinate for this partition.
|
||||||
|
//////////////////////////////////////////////////////////////////
|
||||||
|
MPI_Bcast(&rootcoor, sizeof(rootcoor), MPI_BYTE, 0, WorldComm);
|
||||||
|
hypercoor=hypercoor-rootcoor;
|
||||||
|
assert(hypercoor<WorldSize);
|
||||||
|
assert(hypercoor>=0);
|
||||||
|
|
||||||
|
//////////////////////////////////////
|
||||||
|
// Printing
|
||||||
|
//////////////////////////////////////
|
||||||
|
for(int d=0;d<maxhdim;d++){
|
||||||
|
HyperCubeCoords[d] = (hypercoor>>d)&0x1;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////
|
||||||
|
// Identify subblock of ranks on node spreading across dims
|
||||||
|
// in a maximally symmetrical way
|
||||||
|
////////////////////////////////////////////////////////////////
|
||||||
|
int ndimension = processors.size();
|
||||||
|
std::vector<int> processor_coor(ndimension);
|
||||||
|
std::vector<int> WorldDims = processors; std::vector<int> ShmDims (ndimension,1); std::vector<int> NodeDims (ndimension);
|
||||||
|
std::vector<int> ShmCoor (ndimension); std::vector<int> NodeCoor (ndimension); std::vector<int> WorldCoor(ndimension);
|
||||||
|
std::vector<int> HyperCoor(ndimension);
|
||||||
|
int dim = 0;
|
||||||
|
for(int l2=0;l2<log2size;l2++){
|
||||||
|
while ( (WorldDims[dim] / ShmDims[dim]) <= 1 ) dim=(dim+1)%ndimension;
|
||||||
|
ShmDims[dim]*=2;
|
||||||
|
dim=(dim+1)%ndimension;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////
|
||||||
|
// Establish torus of processes and nodes with sub-blockings
|
||||||
|
////////////////////////////////////////////////////////////////
|
||||||
|
for(int d=0;d<ndimension;d++){
|
||||||
|
NodeDims[d] = WorldDims[d]/ShmDims[d];
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////
|
||||||
|
// Map Hcube according to physical lattice
|
||||||
|
// must partition. Loop over dims and find out who would join.
|
||||||
|
////////////////////////////////////////////////////////////////
|
||||||
|
int hcoor = hypercoor;
|
||||||
|
for(int d=0;d<ndimension;d++){
|
||||||
|
int bits = Log2Size(NodeDims[d],MAXLOG2RANKSPERNODE);
|
||||||
|
int msk = (0x1<<bits)-1;
|
||||||
|
HyperCoor[d]=hcoor & msk;
|
||||||
|
HyperCoor[d]=BinaryToGray(HyperCoor[d]); // Space filling curve magic
|
||||||
|
hcoor = hcoor >> bits;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////
|
||||||
|
// Check processor counts match
|
||||||
|
////////////////////////////////////////////////////////////////
|
||||||
|
int Nprocessors=1;
|
||||||
|
for(int i=0;i<ndimension;i++){
|
||||||
|
Nprocessors*=processors[i];
|
||||||
|
}
|
||||||
|
assert(WorldSize==Nprocessors);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////
|
||||||
|
// Establish mapping between lexico physics coord and WorldRank
|
||||||
|
////////////////////////////////////////////////////////////////
|
||||||
|
int rank;
|
||||||
|
|
||||||
|
Lexicographic::CoorFromIndexReversed(NodeCoor,WorldNode ,NodeDims);
|
||||||
|
|
||||||
|
for(int d=0;d<ndimension;d++) NodeCoor[d]=HyperCoor[d];
|
||||||
|
|
||||||
|
Lexicographic::CoorFromIndexReversed(ShmCoor ,WorldShmRank,ShmDims);
|
||||||
|
for(int d=0;d<ndimension;d++) WorldCoor[d] = NodeCoor[d]*ShmDims[d]+ShmCoor[d];
|
||||||
|
Lexicographic::IndexFromCoorReversed(WorldCoor,rank,WorldDims);
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////
|
||||||
|
// Build the new communicator
|
||||||
|
/////////////////////////////////////////////////////////////////
|
||||||
|
int ierr= MPI_Comm_split(WorldComm,0,rank,&optimal_comm);
|
||||||
|
assert(ierr==0);
|
||||||
|
#else
|
||||||
|
////////////////////////////////////////////////////////////////
|
||||||
|
// Assert power of two shm_size.
|
||||||
|
////////////////////////////////////////////////////////////////
|
||||||
|
int log2size = Log2Size(WorldShmSize,MAXLOG2RANKSPERNODE);
|
||||||
assert(log2size != -1);
|
assert(log2size != -1);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////
|
||||||
@@ -175,7 +306,69 @@ void GlobalSharedMemory::OptimalCommunicator(const std::vector<int> &processors,
|
|||||||
/////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////
|
||||||
int ierr= MPI_Comm_split(WorldComm,0,rank,&optimal_comm);
|
int ierr= MPI_Comm_split(WorldComm,0,rank,&optimal_comm);
|
||||||
assert(ierr==0);
|
assert(ierr==0);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// SHMGET
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#ifdef GRID_MPI3_SHMGET
|
||||||
|
void GlobalSharedMemory::SharedMemoryAllocate(uint64_t bytes, int flags)
|
||||||
|
{
|
||||||
|
std::cout << "SharedMemoryAllocate "<< bytes<< " shmget implementation "<<std::endl;
|
||||||
|
assert(_ShmSetup==1);
|
||||||
|
assert(_ShmAlloc==0);
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// allocate the shared windows for our group
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
MPI_Barrier(WorldShmComm);
|
||||||
|
WorldShmCommBufs.resize(WorldShmSize);
|
||||||
|
std::vector<int> shmids(WorldShmSize);
|
||||||
|
|
||||||
|
if ( WorldShmRank == 0 ) {
|
||||||
|
for(int r=0;r<WorldShmSize;r++){
|
||||||
|
size_t size = bytes;
|
||||||
|
key_t key = IPC_PRIVATE;
|
||||||
|
int flags = IPC_CREAT | SHM_R | SHM_W;
|
||||||
|
#ifdef SHM_HUGETLB
|
||||||
|
if (Hugepages) flags|=SHM_HUGETLB;
|
||||||
|
#endif
|
||||||
|
if ((shmids[r]= shmget(key,size, flags)) ==-1) {
|
||||||
|
int errsv = errno;
|
||||||
|
printf("Errno %d\n",errsv);
|
||||||
|
printf("key %d\n",key);
|
||||||
|
printf("size %lld\n",size);
|
||||||
|
printf("flags %d\n",flags);
|
||||||
|
perror("shmget");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MPI_Barrier(WorldShmComm);
|
||||||
|
MPI_Bcast(&shmids[0],WorldShmSize*sizeof(int),MPI_BYTE,0,WorldShmComm);
|
||||||
|
MPI_Barrier(WorldShmComm);
|
||||||
|
|
||||||
|
for(int r=0;r<WorldShmSize;r++){
|
||||||
|
WorldShmCommBufs[r] = (uint64_t *)shmat(shmids[r], NULL,0);
|
||||||
|
if (WorldShmCommBufs[r] == (uint64_t *)-1) {
|
||||||
|
perror("Shared memory attach failure");
|
||||||
|
shmctl(shmids[r], IPC_RMID, NULL);
|
||||||
|
exit(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MPI_Barrier(WorldShmComm);
|
||||||
|
///////////////////////////////////
|
||||||
|
// Mark for clean up
|
||||||
|
///////////////////////////////////
|
||||||
|
for(int r=0;r<WorldShmSize;r++){
|
||||||
|
shmctl(shmids[r], IPC_RMID,(struct shmid_ds *)NULL);
|
||||||
|
}
|
||||||
|
MPI_Barrier(WorldShmComm);
|
||||||
|
|
||||||
|
_ShmAlloc=1;
|
||||||
|
_ShmAllocBytes = bytes;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// Hugetlbfs mapping intended
|
// Hugetlbfs mapping intended
|
||||||
@@ -183,7 +376,7 @@ void GlobalSharedMemory::OptimalCommunicator(const std::vector<int> &processors,
|
|||||||
#ifdef GRID_MPI3_SHMMMAP
|
#ifdef GRID_MPI3_SHMMMAP
|
||||||
void GlobalSharedMemory::SharedMemoryAllocate(uint64_t bytes, int flags)
|
void GlobalSharedMemory::SharedMemoryAllocate(uint64_t bytes, int flags)
|
||||||
{
|
{
|
||||||
std::cout << "SharedMemoryAllocate "<< bytes<< " MMAP implementation "<<std::endl;
|
std::cout << "SharedMemoryAllocate "<< bytes<< " MMAP implementation "<< GRID_SHM_PATH <<std::endl;
|
||||||
assert(_ShmSetup==1);
|
assert(_ShmSetup==1);
|
||||||
assert(_ShmAlloc==0);
|
assert(_ShmAlloc==0);
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
@@ -193,7 +386,7 @@ void GlobalSharedMemory::SharedMemoryAllocate(uint64_t bytes, int flags)
|
|||||||
WorldShmCommBufs.resize(WorldShmSize);
|
WorldShmCommBufs.resize(WorldShmSize);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// Hugetlbf and others map filesystems as mappable huge pages
|
// Hugetlbfs and others map filesystems as mappable huge pages
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
char shm_name [NAME_MAX];
|
char shm_name [NAME_MAX];
|
||||||
for(int r=0;r<WorldShmSize;r++){
|
for(int r=0;r<WorldShmSize;r++){
|
||||||
@@ -220,7 +413,7 @@ void GlobalSharedMemory::SharedMemoryAllocate(uint64_t bytes, int flags)
|
|||||||
assert(((uint64_t)ptr&0x3F)==0);
|
assert(((uint64_t)ptr&0x3F)==0);
|
||||||
close(fd);
|
close(fd);
|
||||||
WorldShmCommBufs[r] =ptr;
|
WorldShmCommBufs[r] =ptr;
|
||||||
std::cout << "Set WorldShmCommBufs["<<r<<"]="<<ptr<< "("<< bytes<< "bytes)"<<std::endl;
|
// std::cout << "Set WorldShmCommBufs["<<r<<"]="<<ptr<< "("<< bytes<< "bytes)"<<std::endl;
|
||||||
}
|
}
|
||||||
_ShmAlloc=1;
|
_ShmAlloc=1;
|
||||||
_ShmAllocBytes = bytes;
|
_ShmAllocBytes = bytes;
|
||||||
@@ -262,7 +455,7 @@ void GlobalSharedMemory::SharedMemoryAllocate(uint64_t bytes, int flags)
|
|||||||
assert(((uint64_t)ptr&0x3F)==0);
|
assert(((uint64_t)ptr&0x3F)==0);
|
||||||
close(fd);
|
close(fd);
|
||||||
WorldShmCommBufs[r] =ptr;
|
WorldShmCommBufs[r] =ptr;
|
||||||
std::cout << "Set WorldShmCommBufs["<<r<<"]="<<ptr<< "("<< bytes<< "bytes)"<<std::endl;
|
// std::cout << "Set WorldShmCommBufs["<<r<<"]="<<ptr<< "("<< bytes<< "bytes)"<<std::endl;
|
||||||
}
|
}
|
||||||
_ShmAlloc=1;
|
_ShmAlloc=1;
|
||||||
_ShmAllocBytes = bytes;
|
_ShmAllocBytes = bytes;
|
||||||
@@ -306,7 +499,7 @@ void GlobalSharedMemory::SharedMemoryAllocate(uint64_t bytes, int flags)
|
|||||||
#endif
|
#endif
|
||||||
void * ptr = mmap(NULL,size, PROT_READ | PROT_WRITE, mmap_flag, fd, 0);
|
void * ptr = mmap(NULL,size, PROT_READ | PROT_WRITE, mmap_flag, fd, 0);
|
||||||
|
|
||||||
std::cout << "Set WorldShmCommBufs["<<r<<"]="<<ptr<< "("<< size<< "bytes)"<<std::endl;
|
// std::cout << "Set WorldShmCommBufs["<<r<<"]="<<ptr<< "("<< size<< "bytes)"<<std::endl;
|
||||||
if ( ptr == (void * )MAP_FAILED ) {
|
if ( ptr == (void * )MAP_FAILED ) {
|
||||||
perror("failed mmap");
|
perror("failed mmap");
|
||||||
assert(0);
|
assert(0);
|
||||||
@@ -344,6 +537,9 @@ void GlobalSharedMemory::SharedMemoryAllocate(uint64_t bytes, int flags)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////
|
||||||
// Global shared functionality finished
|
// Global shared functionality finished
|
||||||
// Now move to per communicator functionality
|
// Now move to per communicator functionality
|
||||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
+7422
-3252
File diff suppressed because it is too large.
Load diff
File renamed without changes.
File renamed without changes.
@@ -244,19 +244,11 @@ namespace Grid {
|
|||||||
|
|
||||||
template<class sobj,class vobj> strong_inline
|
template<class sobj,class vobj> strong_inline
|
||||||
RealD axpy_norm(Lattice<vobj> &ret,sobj a,const Lattice<vobj> &x,const Lattice<vobj> &y){
|
RealD axpy_norm(Lattice<vobj> &ret,sobj a,const Lattice<vobj> &x,const Lattice<vobj> &y){
|
||||||
ret.checkerboard = x.checkerboard;
|
return axpy_norm_fast(ret,a,x,y);
|
||||||
conformable(ret,x);
|
|
||||||
conformable(x,y);
|
|
||||||
axpy(ret,a,x,y);
|
|
||||||
return norm2(ret);
|
|
||||||
}
|
}
|
||||||
template<class sobj,class vobj> strong_inline
|
template<class sobj,class vobj> strong_inline
|
||||||
RealD axpby_norm(Lattice<vobj> &ret,sobj a,sobj b,const Lattice<vobj> &x,const Lattice<vobj> &y){
|
RealD axpby_norm(Lattice<vobj> &ret,sobj a,sobj b,const Lattice<vobj> &x,const Lattice<vobj> &y){
|
||||||
ret.checkerboard = x.checkerboard;
|
return axpby_norm_fast(ret,a,b,x,y);
|
||||||
conformable(ret,x);
|
|
||||||
conformable(x,y);
|
|
||||||
axpby(ret,a,b,x,y);
|
|
||||||
return norm2(ret); // FIXME implement parallel norm in ss loop
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -33,7 +33,7 @@ namespace Grid {
|
|||||||
// Deterministic Reduction operations
|
// Deterministic Reduction operations
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
template<class vobj> inline RealD norm2(const Lattice<vobj> &arg){
|
template<class vobj> inline RealD norm2(const Lattice<vobj> &arg){
|
||||||
ComplexD nrm = innerProduct(arg,arg);
|
auto nrm = innerProduct(arg,arg);
|
||||||
return std::real(nrm);
|
return std::real(nrm);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -43,32 +43,85 @@ inline ComplexD innerProduct(const Lattice<vobj> &left,const Lattice<vobj> &righ
|
|||||||
{
|
{
|
||||||
typedef typename vobj::scalar_type scalar_type;
|
typedef typename vobj::scalar_type scalar_type;
|
||||||
typedef typename vobj::vector_typeD vector_type;
|
typedef typename vobj::vector_typeD vector_type;
|
||||||
scalar_type nrm;
|
|
||||||
|
|
||||||
GridBase *grid = left._grid;
|
GridBase *grid = left._grid;
|
||||||
|
const int pad = 8;
|
||||||
|
|
||||||
std::vector<vector_type,alignedAllocator<vector_type> > sumarray(grid->SumArraySize());
|
ComplexD inner;
|
||||||
|
Vector<ComplexD> sumarray(grid->SumArraySize()*pad);
|
||||||
|
|
||||||
parallel_for(int thr=0;thr<grid->SumArraySize();thr++){
|
parallel_for(int thr=0;thr<grid->SumArraySize();thr++){
|
||||||
int nwork, mywork, myoff;
|
int nwork, mywork, myoff;
|
||||||
GridThread::GetWork(left._grid->oSites(),thr,mywork,myoff);
|
GridThread::GetWork(left._grid->oSites(),thr,mywork,myoff);
|
||||||
|
|
||||||
decltype(innerProductD(left._odata[0],right._odata[0])) vnrm=zero; // private to thread; sub summation
|
decltype(innerProductD(left._odata[0],right._odata[0])) vinner=zero; // private to thread; sub summation
|
||||||
for(int ss=myoff;ss<mywork+myoff; ss++){
|
for(int ss=myoff;ss<mywork+myoff; ss++){
|
||||||
vnrm = vnrm + innerProductD(left._odata[ss],right._odata[ss]);
|
vinner = vinner + innerProductD(left._odata[ss],right._odata[ss]);
|
||||||
}
|
}
|
||||||
sumarray[thr]=TensorRemove(vnrm) ;
|
// All threads sum across SIMD; reduce serial work at end
|
||||||
|
// one write per cacheline with streaming store
|
||||||
|
ComplexD tmp = Reduce(TensorRemove(vinner)) ;
|
||||||
|
vstream(sumarray[thr*pad],tmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
vector_type vvnrm; vvnrm=zero; // sum across threads
|
inner=0.0;
|
||||||
for(int i=0;i<grid->SumArraySize();i++){
|
for(int i=0;i<grid->SumArraySize();i++){
|
||||||
vvnrm = vvnrm+sumarray[i];
|
inner = inner+sumarray[i*pad];
|
||||||
}
|
}
|
||||||
nrm = Reduce(vvnrm);// sum across simd
|
right._grid->GlobalSum(inner);
|
||||||
right._grid->GlobalSum(nrm);
|
return inner;
|
||||||
|
}
|
||||||
|
|
||||||
|
/////////////////////////
|
||||||
|
// Fast axpby_norm
|
||||||
|
// z = a x + b y
|
||||||
|
// return norm z
|
||||||
|
/////////////////////////
|
||||||
|
template<class sobj,class vobj> strong_inline RealD
|
||||||
|
axpy_norm_fast(Lattice<vobj> &z,sobj a,const Lattice<vobj> &x,const Lattice<vobj> &y)
|
||||||
|
{
|
||||||
|
sobj one(1.0);
|
||||||
|
return axpby_norm_fast(z,a,one,x,y);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class sobj,class vobj> strong_inline RealD
|
||||||
|
axpby_norm_fast(Lattice<vobj> &z,sobj a,sobj b,const Lattice<vobj> &x,const Lattice<vobj> &y)
|
||||||
|
{
|
||||||
|
const int pad = 8;
|
||||||
|
z.checkerboard = x.checkerboard;
|
||||||
|
conformable(z,x);
|
||||||
|
conformable(x,y);
|
||||||
|
|
||||||
|
typedef typename vobj::scalar_type scalar_type;
|
||||||
|
typedef typename vobj::vector_typeD vector_type;
|
||||||
|
RealD nrm;
|
||||||
|
|
||||||
|
GridBase *grid = x._grid;
|
||||||
|
|
||||||
|
Vector<RealD> sumarray(grid->SumArraySize()*pad);
|
||||||
|
|
||||||
|
parallel_for(int thr=0;thr<grid->SumArraySize();thr++){
|
||||||
|
int nwork, mywork, myoff;
|
||||||
|
GridThread::GetWork(x._grid->oSites(),thr,mywork,myoff);
|
||||||
|
|
||||||
|
// private to thread; sub summation
|
||||||
|
decltype(innerProductD(z._odata[0],z._odata[0])) vnrm=zero;
|
||||||
|
for(int ss=myoff;ss<mywork+myoff; ss++){
|
||||||
|
vobj tmp = a*x._odata[ss]+b*y._odata[ss];
|
||||||
|
vnrm = vnrm + innerProductD(tmp,tmp);
|
||||||
|
vstream(z._odata[ss],tmp);
|
||||||
|
}
|
||||||
|
vstream(sumarray[thr*pad],real(Reduce(TensorRemove(vnrm)))) ;
|
||||||
|
}
|
||||||
|
|
||||||
|
nrm = 0.0; // sum across threads; linear in thread count but fast
|
||||||
|
for(int i=0;i<grid->SumArraySize();i++){
|
||||||
|
nrm = nrm+sumarray[i*pad];
|
||||||
|
}
|
||||||
|
z._grid->GlobalSum(nrm);
|
||||||
return nrm;
|
return nrm;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template<class Op,class T1>
|
template<class Op,class T1>
|
||||||
inline auto sum(const LatticeUnaryExpression<Op,T1> & expr)
|
inline auto sum(const LatticeUnaryExpression<Op,T1> & expr)
|
||||||
->typename decltype(expr.first.func(eval(0,std::get<0>(expr.second))))::scalar_object
|
->typename decltype(expr.first.func(eval(0,std::get<0>(expr.second))))::scalar_object
|
||||||
@@ -221,6 +274,115 @@ template<class vobj> inline void sliceSum(const Lattice<vobj> &Data,std::vector<
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<class vobj>
|
||||||
|
static void mySliceInnerProductVector( std::vector<ComplexD> & result, const Lattice<vobj> &lhs,const Lattice<vobj> &rhs,int orthogdim)
|
||||||
|
{
|
||||||
|
// std::cout << GridLogMessage << "Start mySliceInnerProductVector" << std::endl;
|
||||||
|
|
||||||
|
typedef typename vobj::scalar_type scalar_type;
|
||||||
|
std::vector<scalar_type> lsSum;
|
||||||
|
localSliceInnerProductVector(result, lhs, rhs, lsSum, orthogdim);
|
||||||
|
globalSliceInnerProductVector(result, lhs, lsSum, orthogdim);
|
||||||
|
// std::cout << GridLogMessage << "End mySliceInnerProductVector" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class vobj>
|
||||||
|
static void localSliceInnerProductVector(std::vector<ComplexD> &result, const Lattice<vobj> &lhs, const Lattice<vobj> &rhs, std::vector<typename vobj::scalar_type> &lsSum, int orthogdim)
|
||||||
|
{
|
||||||
|
// std::cout << GridLogMessage << "Start prep" << std::endl;
|
||||||
|
typedef typename vobj::vector_type vector_type;
|
||||||
|
typedef typename vobj::scalar_type scalar_type;
|
||||||
|
GridBase *grid = lhs._grid;
|
||||||
|
assert(grid!=NULL);
|
||||||
|
conformable(grid,rhs._grid);
|
||||||
|
|
||||||
|
const int Nd = grid->_ndimension;
|
||||||
|
const int Nsimd = grid->Nsimd();
|
||||||
|
|
||||||
|
assert(orthogdim >= 0);
|
||||||
|
assert(orthogdim < Nd);
|
||||||
|
|
||||||
|
int fd=grid->_fdimensions[orthogdim];
|
||||||
|
int ld=grid->_ldimensions[orthogdim];
|
||||||
|
int rd=grid->_rdimensions[orthogdim];
|
||||||
|
// std::cout << GridLogMessage << "Start alloc" << std::endl;
|
||||||
|
|
||||||
|
std::vector<vector_type,alignedAllocator<vector_type> > lvSum(rd); // will locally sum vectors first
|
||||||
|
lsSum.resize(ld,scalar_type(0.0)); // sum across these down to scalars
|
||||||
|
std::vector<iScalar<scalar_type>> extracted(Nsimd); // splitting the SIMD
|
||||||
|
// std::cout << GridLogMessage << "End alloc" << std::endl;
|
||||||
|
|
||||||
|
result.resize(fd); // And then global sum to return the same vector to every node for IO to file
|
||||||
|
for(int r=0;r<rd;r++){
|
||||||
|
lvSum[r]=zero;
|
||||||
|
}
|
||||||
|
|
||||||
|
int e1= grid->_slice_nblock[orthogdim];
|
||||||
|
int e2= grid->_slice_block [orthogdim];
|
||||||
|
int stride=grid->_slice_stride[orthogdim];
|
||||||
|
// std::cout << GridLogMessage << "End prep" << std::endl;
|
||||||
|
// std::cout << GridLogMessage << "Start parallel inner product, _rd = " << rd << std::endl;
|
||||||
|
vector_type vv;
|
||||||
|
parallel_for(int r=0;r<rd;r++)
|
||||||
|
{
|
||||||
|
|
||||||
|
int so=r*grid->_ostride[orthogdim]; // base offset for start of plane
|
||||||
|
|
||||||
|
for(int n=0;n<e1;n++){
|
||||||
|
for(int b=0;b<e2;b++){
|
||||||
|
int ss = so + n * stride + b;
|
||||||
|
vv = TensorRemove(innerProduct(lhs._odata[ss], rhs._odata[ss]));
|
||||||
|
lvSum[r] = lvSum[r] + vv;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// std::cout << GridLogMessage << "End parallel inner product" << std::endl;
|
||||||
|
|
||||||
|
// Sum across simd lanes in the plane, breaking out orthog dir.
|
||||||
|
std::vector<int> icoor(Nd);
|
||||||
|
for(int rt=0;rt<rd;rt++){
|
||||||
|
|
||||||
|
iScalar<vector_type> temp;
|
||||||
|
temp._internal = lvSum[rt];
|
||||||
|
extract(temp,extracted);
|
||||||
|
|
||||||
|
for(int idx=0;idx<Nsimd;idx++){
|
||||||
|
|
||||||
|
grid->iCoorFromIindex(icoor,idx);
|
||||||
|
|
||||||
|
int ldx =rt+icoor[orthogdim]*rd;
|
||||||
|
|
||||||
|
lsSum[ldx]=lsSum[ldx]+extracted[idx]._internal;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// std::cout << GridLogMessage << "End sum over simd lanes" << std::endl;
|
||||||
|
}
|
||||||
|
template <class vobj>
|
||||||
|
static void globalSliceInnerProductVector(std::vector<ComplexD> &result, const Lattice<vobj> &lhs, std::vector<typename vobj::scalar_type> &lsSum, int orthogdim)
|
||||||
|
{
|
||||||
|
typedef typename vobj::scalar_type scalar_type;
|
||||||
|
GridBase *grid = lhs._grid;
|
||||||
|
int fd = result.size();
|
||||||
|
int ld = lsSum.size();
|
||||||
|
// sum over nodes.
|
||||||
|
std::vector<scalar_type> gsum;
|
||||||
|
gsum.resize(fd, scalar_type(0.0));
|
||||||
|
// std::cout << GridLogMessage << "Start of gsum[t] creation:" << std::endl;
|
||||||
|
for(int t=0;t<fd;t++){
|
||||||
|
int pt = t/ld; // processor plane
|
||||||
|
int lt = t%ld;
|
||||||
|
if ( pt == grid->_processor_coor[orthogdim] ) {
|
||||||
|
gsum[t]=lsSum[lt];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// std::cout << GridLogMessage << "End of gsum[t] creation:" << std::endl;
|
||||||
|
// std::cout << GridLogMessage << "Start of GlobalSumVector:" << std::endl;
|
||||||
|
grid->GlobalSumVector(&gsum[0], fd);
|
||||||
|
// std::cout << GridLogMessage << "End of GlobalSumVector:" << std::endl;
|
||||||
|
|
||||||
|
result = gsum;
|
||||||
|
}
|
||||||
template<class vobj>
|
template<class vobj>
|
||||||
static void sliceInnerProductVector( std::vector<ComplexD> & result, const Lattice<vobj> &lhs,const Lattice<vobj> &rhs,int orthogdim)
|
static void sliceInnerProductVector( std::vector<ComplexD> & result, const Lattice<vobj> &lhs,const Lattice<vobj> &rhs,int orthogdim)
|
||||||
{
|
{
|
||||||
@@ -158,10 +158,19 @@ namespace Grid {
|
|||||||
// tens of seconds per trajectory so this is clean in all reasonable cases,
|
// tens of seconds per trajectory so this is clean in all reasonable cases,
|
||||||
// and margin of safety is orders of magnitude.
|
// and margin of safety is orders of magnitude.
|
||||||
// We could hack Sitmo to skip in the higher order words of state if necessary
|
// We could hack Sitmo to skip in the higher order words of state if necessary
|
||||||
|
//
|
||||||
|
// Replace with 2^30 ; avoid problem on large volumes
|
||||||
|
//
|
||||||
/////////////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////////////
|
||||||
// uint64_t skip = site+1; // Old init Skipped then drew. Checked compat with faster init
|
// uint64_t skip = site+1; // Old init Skipped then drew. Checked compat with faster init
|
||||||
|
const int shift = 30;
|
||||||
|
|
||||||
uint64_t skip = site;
|
uint64_t skip = site;
|
||||||
skip = skip<<40;
|
|
||||||
|
skip = skip<<shift;
|
||||||
|
|
||||||
|
assert((skip >> shift)==site); // check for overflow
|
||||||
|
|
||||||
eng.discard(skip);
|
eng.discard(skip);
|
||||||
// std::cout << " Engine " <<site << " state " <<eng<<std::endl;
|
// std::cout << " Engine " <<site << " state " <<eng<<std::endl;
|
||||||
}
|
}
|
||||||
@@ -308,6 +317,19 @@ namespace Grid {
|
|||||||
std::seed_seq src(seeds.begin(),seeds.end());
|
std::seed_seq src(seeds.begin(),seeds.end());
|
||||||
Seed(src,0);
|
Seed(src,0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SeedUniqueString(const std::string &s){
|
||||||
|
std::vector<int> seeds;
|
||||||
|
std::stringstream sha;
|
||||||
|
seeds = GridChecksum::sha256_seeds(s);
|
||||||
|
for(int i=0;i<seeds.size();i++) {
|
||||||
|
sha << std::hex << seeds[i];
|
||||||
|
}
|
||||||
|
std::cout << GridLogMessage << "Intialising serial RNG with unique string '"
|
||||||
|
<< s << "'" << std::endl;
|
||||||
|
std::cout << GridLogMessage << "Seed SHA256: " << sha.str() << std::endl;
|
||||||
|
SeedFixedIntegers(seeds);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class GridParallelRNG : public GridRNGbase {
|
class GridParallelRNG : public GridRNGbase {
|
||||||
@@ -368,6 +390,14 @@ namespace Grid {
|
|||||||
_time_counter += usecond()- inner_time_counter;
|
_time_counter += usecond()- inner_time_counter;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void SeedUniqueString(const std::string &s){
|
||||||
|
std::vector<int> seeds;
|
||||||
|
seeds = GridChecksum::sha256_seeds(s);
|
||||||
|
std::cout << GridLogMessage << "Intialising parallel RNG with unique string '"
|
||||||
|
<< s << "'" << std::endl;
|
||||||
|
std::cout << GridLogMessage << "Seed SHA256: " << GridChecksum::sha256_string(seeds) << std::endl;
|
||||||
|
SeedFixedIntegers(seeds);
|
||||||
|
}
|
||||||
void SeedFixedIntegers(const std::vector<int> &seeds){
|
void SeedFixedIntegers(const std::vector<int> &seeds){
|
||||||
|
|
||||||
// Everyone generates the same seed_seq based on input seeds
|
// Everyone generates the same seed_seq based on input seeds
|
||||||
File renamed without changes.
@@ -464,9 +464,11 @@ void InsertSliceLocal(const Lattice<vobj> &lowDim, Lattice<vobj> & higherDim,int
|
|||||||
assert(orthog>=0);
|
assert(orthog>=0);
|
||||||
|
|
||||||
for(int d=0;d<nh;d++){
|
for(int d=0;d<nh;d++){
|
||||||
|
if ( d!=orthog ) {
|
||||||
assert(lg->_processors[d] == hg->_processors[d]);
|
assert(lg->_processors[d] == hg->_processors[d]);
|
||||||
assert(lg->_ldimensions[d] == hg->_ldimensions[d]);
|
assert(lg->_ldimensions[d] == hg->_ldimensions[d]);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// the above should guarantee that the operations are local
|
// the above should guarantee that the operations are local
|
||||||
parallel_for(int idx=0;idx<lg->lSites();idx++){
|
parallel_for(int idx=0;idx<lg->lSites();idx++){
|
||||||
@@ -485,7 +487,7 @@ void InsertSliceLocal(const Lattice<vobj> &lowDim, Lattice<vobj> & higherDim,int
|
|||||||
|
|
||||||
|
|
||||||
template<class vobj>
|
template<class vobj>
|
||||||
void ExtractSliceLocal(Lattice<vobj> &lowDim, Lattice<vobj> & higherDim,int slice_lo,int slice_hi, int orthog)
|
void ExtractSliceLocal(Lattice<vobj> &lowDim,const Lattice<vobj> & higherDim,int slice_lo,int slice_hi, int orthog)
|
||||||
{
|
{
|
||||||
typedef typename vobj::scalar_object sobj;
|
typedef typename vobj::scalar_object sobj;
|
||||||
|
|
||||||
@@ -499,9 +501,11 @@ void ExtractSliceLocal(Lattice<vobj> &lowDim, Lattice<vobj> & higherDim,int slic
|
|||||||
assert(orthog>=0);
|
assert(orthog>=0);
|
||||||
|
|
||||||
for(int d=0;d<nh;d++){
|
for(int d=0;d<nh;d++){
|
||||||
|
if ( d!=orthog ) {
|
||||||
assert(lg->_processors[d] == hg->_processors[d]);
|
assert(lg->_processors[d] == hg->_processors[d]);
|
||||||
assert(lg->_ldimensions[d] == hg->_ldimensions[d]);
|
assert(lg->_ldimensions[d] == hg->_ldimensions[d]);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// the above should guarantee that the operations are local
|
// the above should guarantee that the operations are local
|
||||||
parallel_for(int idx=0;idx<lg->lSites();idx++){
|
parallel_for(int idx=0;idx<lg->lSites();idx++){
|
||||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -59,6 +59,7 @@ void GridLogTimestamp(int on){
|
|||||||
}
|
}
|
||||||
|
|
||||||
Colours GridLogColours(0);
|
Colours GridLogColours(0);
|
||||||
|
GridLogger GridLogMG (1, "MG" , GridLogColours, "NORMAL");
|
||||||
GridLogger GridLogIRL (1, "IRL" , GridLogColours, "NORMAL");
|
GridLogger GridLogIRL (1, "IRL" , GridLogColours, "NORMAL");
|
||||||
GridLogger GridLogSolver (1, "Solver", GridLogColours, "NORMAL");
|
GridLogger GridLogSolver (1, "Solver", GridLogColours, "NORMAL");
|
||||||
GridLogger GridLogError (1, "Error" , GridLogColours, "RED");
|
GridLogger GridLogError (1, "Error" , GridLogColours, "RED");
|
||||||
@@ -86,7 +86,7 @@ protected:
|
|||||||
Colours &Painter;
|
Colours &Painter;
|
||||||
int active;
|
int active;
|
||||||
int timing_mode;
|
int timing_mode;
|
||||||
int topWidth{-1};
|
int topWidth{-1}, chanWidth{-1};
|
||||||
static int timestamp;
|
static int timestamp;
|
||||||
std::string name, topName;
|
std::string name, topName;
|
||||||
std::string COLOUR;
|
std::string COLOUR;
|
||||||
@@ -126,6 +126,7 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
void setTopWidth(const int w) {topWidth = w;}
|
void setTopWidth(const int w) {topWidth = w;}
|
||||||
|
void setChanWidth(const int w) {chanWidth = w;}
|
||||||
|
|
||||||
friend std::ostream& operator<< (std::ostream& stream, Logger& log){
|
friend std::ostream& operator<< (std::ostream& stream, Logger& log){
|
||||||
|
|
||||||
@@ -136,13 +137,20 @@ public:
|
|||||||
stream << std::setw(log.topWidth);
|
stream << std::setw(log.topWidth);
|
||||||
}
|
}
|
||||||
stream << log.topName << log.background()<< " : ";
|
stream << log.topName << log.background()<< " : ";
|
||||||
stream << log.colour() << std::left << log.name << log.background() << " : ";
|
stream << log.colour() << std::left;
|
||||||
|
if (log.chanWidth > 0)
|
||||||
|
{
|
||||||
|
stream << std::setw(log.chanWidth);
|
||||||
|
}
|
||||||
|
stream << log.name << log.background() << " : ";
|
||||||
if ( log.timestamp ) {
|
if ( log.timestamp ) {
|
||||||
log.StopWatch->Stop();
|
log.StopWatch->Stop();
|
||||||
GridTime now = log.StopWatch->Elapsed();
|
GridTime now = log.StopWatch->Elapsed();
|
||||||
|
|
||||||
if ( log.timing_mode==1 ) log.StopWatch->Reset();
|
if ( log.timing_mode==1 ) log.StopWatch->Reset();
|
||||||
log.StopWatch->Start();
|
log.StopWatch->Start();
|
||||||
stream << log.evidence()<< std::setw(6)<<now << log.background() << " : " ;
|
stream << log.evidence()
|
||||||
|
<< now << log.background() << " : " ;
|
||||||
}
|
}
|
||||||
stream << log.colour();
|
stream << log.colour();
|
||||||
return stream;
|
return stream;
|
||||||
@@ -161,6 +169,7 @@ public:
|
|||||||
|
|
||||||
void GridLogConfigure(std::vector<std::string> &logstreams);
|
void GridLogConfigure(std::vector<std::string> &logstreams);
|
||||||
|
|
||||||
|
extern GridLogger GridLogMG;
|
||||||
extern GridLogger GridLogIRL;
|
extern GridLogger GridLogIRL;
|
||||||
extern GridLogger GridLogSolver;
|
extern GridLogger GridLogSolver;
|
||||||
extern GridLogger GridLogError;
|
extern GridLogger GridLogError;
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
#include <Grid/GridCore.h>
|
||||||
|
|
||||||
|
int Grid::BinaryIO::latticeWriteMaxRetry = -1;
|
||||||
@@ -81,6 +81,7 @@ inline void removeWhitespace(std::string &key)
|
|||||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
class BinaryIO {
|
class BinaryIO {
|
||||||
public:
|
public:
|
||||||
|
static int latticeWriteMaxRetry;
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
// more byte manipulation helpers
|
// more byte manipulation helpers
|
||||||
@@ -263,7 +264,7 @@ PARALLEL_CRITICAL
|
|||||||
GridBase *grid,
|
GridBase *grid,
|
||||||
std::vector<fobj> &iodata,
|
std::vector<fobj> &iodata,
|
||||||
std::string file,
|
std::string file,
|
||||||
uint64_t offset,
|
uint64_t& offset,
|
||||||
const std::string &format, int control,
|
const std::string &format, int control,
|
||||||
uint32_t &nersc_csum,
|
uint32_t &nersc_csum,
|
||||||
uint32_t &scidac_csuma,
|
uint32_t &scidac_csuma,
|
||||||
@@ -370,7 +371,7 @@ PARALLEL_CRITICAL
|
|||||||
#endif
|
#endif
|
||||||
} else {
|
} else {
|
||||||
std::cout << GridLogMessage <<"IOobject: C++ read I/O " << file << " : "
|
std::cout << GridLogMessage <<"IOobject: C++ read I/O " << file << " : "
|
||||||
<< iodata.size() * sizeof(fobj) << " bytes" << std::endl;
|
<< iodata.size() * sizeof(fobj) << " bytes and offset " << offset << std::endl;
|
||||||
std::ifstream fin;
|
std::ifstream fin;
|
||||||
fin.open(file, std::ios::binary | std::ios::in);
|
fin.open(file, std::ios::binary | std::ios::in);
|
||||||
if (control & BINARYIO_MASTER_APPEND)
|
if (control & BINARYIO_MASTER_APPEND)
|
||||||
@@ -431,14 +432,20 @@ PARALLEL_CRITICAL
|
|||||||
MPI_Abort(MPI_COMM_WORLD, 1); //assert(ierr == 0);
|
MPI_Abort(MPI_COMM_WORLD, 1); //assert(ierr == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cout << GridLogDebug << "MPI read I/O set view " << file << std::endl;
|
std::cout << GridLogDebug << "MPI write I/O set view " << file << std::endl;
|
||||||
ierr = MPI_File_set_view(fh, disp, mpiObject, fileArray, "native", MPI_INFO_NULL);
|
ierr = MPI_File_set_view(fh, disp, mpiObject, fileArray, "native", MPI_INFO_NULL);
|
||||||
assert(ierr == 0);
|
assert(ierr == 0);
|
||||||
|
|
||||||
std::cout << GridLogDebug << "MPI read I/O write all " << file << std::endl;
|
std::cout << GridLogDebug << "MPI write I/O write all " << file << std::endl;
|
||||||
ierr = MPI_File_write_all(fh, &iodata[0], 1, localArray, &status);
|
ierr = MPI_File_write_all(fh, &iodata[0], 1, localArray, &status);
|
||||||
assert(ierr == 0);
|
assert(ierr == 0);
|
||||||
|
|
||||||
|
MPI_Offset os;
|
||||||
|
MPI_File_get_position(fh, &os);
|
||||||
|
MPI_File_get_byte_offset(fh, os, &disp);
|
||||||
|
offset = disp;
|
||||||
|
|
||||||
|
|
||||||
MPI_File_close(&fh);
|
MPI_File_close(&fh);
|
||||||
MPI_Type_free(&fileArray);
|
MPI_Type_free(&fileArray);
|
||||||
MPI_Type_free(&localArray);
|
MPI_Type_free(&localArray);
|
||||||
@@ -448,7 +455,7 @@ PARALLEL_CRITICAL
|
|||||||
} else {
|
} else {
|
||||||
|
|
||||||
std::cout << GridLogMessage << "IOobject: C++ write I/O " << file << " : "
|
std::cout << GridLogMessage << "IOobject: C++ write I/O " << file << " : "
|
||||||
<< iodata.size() * sizeof(fobj) << " bytes" << std::endl;
|
<< iodata.size() * sizeof(fobj) << " bytes and offset " << offset << std::endl;
|
||||||
|
|
||||||
std::ofstream fout;
|
std::ofstream fout;
|
||||||
fout.exceptions ( std::fstream::failbit | std::fstream::badbit );
|
fout.exceptions ( std::fstream::failbit | std::fstream::badbit );
|
||||||
@@ -495,6 +502,7 @@ PARALLEL_CRITICAL
|
|||||||
exit(1);
|
exit(1);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
offset = fout.tellp();
|
||||||
fout.close();
|
fout.close();
|
||||||
}
|
}
|
||||||
timer.Stop();
|
timer.Stop();
|
||||||
@@ -575,7 +583,9 @@ PARALLEL_CRITICAL
|
|||||||
typedef typename vobj::scalar_object sobj;
|
typedef typename vobj::scalar_object sobj;
|
||||||
typedef typename vobj::Realified::scalar_type word; word w=0;
|
typedef typename vobj::Realified::scalar_type word; word w=0;
|
||||||
GridBase *grid = Umu._grid;
|
GridBase *grid = Umu._grid;
|
||||||
uint64_t lsites = grid->lSites();
|
uint64_t lsites = grid->lSites(), offsetCopy = offset;
|
||||||
|
int attemptsLeft = std::max(0, BinaryIO::latticeWriteMaxRetry);
|
||||||
|
bool checkWrite = (BinaryIO::latticeWriteMaxRetry >= 0);
|
||||||
|
|
||||||
std::vector<sobj> scalardata(lsites);
|
std::vector<sobj> scalardata(lsites);
|
||||||
std::vector<fobj> iodata(lsites); // Munge, checksum, byte order in here
|
std::vector<fobj> iodata(lsites); // Munge, checksum, byte order in here
|
||||||
@@ -590,9 +600,35 @@ PARALLEL_CRITICAL
|
|||||||
|
|
||||||
grid->Barrier();
|
grid->Barrier();
|
||||||
timer.Stop();
|
timer.Stop();
|
||||||
|
while (attemptsLeft >= 0)
|
||||||
|
{
|
||||||
|
grid->Barrier();
|
||||||
IOobject(w,grid,iodata,file,offset,format,BINARYIO_WRITE|BINARYIO_LEXICOGRAPHIC,
|
IOobject(w,grid,iodata,file,offset,format,BINARYIO_WRITE|BINARYIO_LEXICOGRAPHIC,
|
||||||
nersc_csum,scidac_csuma,scidac_csumb);
|
nersc_csum,scidac_csuma,scidac_csumb);
|
||||||
|
if (checkWrite)
|
||||||
|
{
|
||||||
|
std::vector<fobj> ckiodata(lsites);
|
||||||
|
uint32_t cknersc_csum, ckscidac_csuma, ckscidac_csumb;
|
||||||
|
uint64_t ckoffset = offsetCopy;
|
||||||
|
|
||||||
|
std::cout << GridLogMessage << "writeLatticeObject: read back object" << std::endl;
|
||||||
|
grid->Barrier();
|
||||||
|
IOobject(w,grid,ckiodata,file,ckoffset,format,BINARYIO_READ|BINARYIO_LEXICOGRAPHIC,
|
||||||
|
cknersc_csum,ckscidac_csuma,ckscidac_csumb);
|
||||||
|
if ((cknersc_csum != nersc_csum) or (ckscidac_csuma != scidac_csuma) or (ckscidac_csumb != scidac_csumb))
|
||||||
|
{
|
||||||
|
std::cout << GridLogMessage << "writeLatticeObject: read test checksum failure, re-writing (" << attemptsLeft << " attempt(s) remaining)" << std::endl;
|
||||||
|
offset = offsetCopy;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::cout << GridLogMessage << "writeLatticeObject: read test checksum correct" << std::endl;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
attemptsLeft--;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
std::cout<<GridLogMessage<<"writeLatticeObject: unvectorize overhead "<<timer.Elapsed() <<std::endl;
|
std::cout<<GridLogMessage<<"writeLatticeObject: unvectorize overhead "<<timer.Elapsed() <<std::endl;
|
||||||
}
|
}
|
||||||
@@ -699,7 +735,6 @@ PARALLEL_CRITICAL
|
|||||||
|
|
||||||
IOobject(w,grid,iodata,file,offset,format,BINARYIO_WRITE|BINARYIO_LEXICOGRAPHIC,
|
IOobject(w,grid,iodata,file,offset,format,BINARYIO_WRITE|BINARYIO_LEXICOGRAPHIC,
|
||||||
nersc_csum,scidac_csuma,scidac_csumb);
|
nersc_csum,scidac_csuma,scidac_csumb);
|
||||||
|
|
||||||
iodata.resize(1);
|
iodata.resize(1);
|
||||||
{
|
{
|
||||||
std::vector<RngStateType> tmp(RngStateCount);
|
std::vector<RngStateType> tmp(RngStateCount);
|
||||||
@@ -719,5 +754,6 @@ PARALLEL_CRITICAL
|
|||||||
std::cout << GridLogMessage << "RNG state overhead " << timer.Elapsed() << std::endl;
|
std::cout << GridLogMessage << "RNG state overhead " << timer.Elapsed() << std::endl;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -182,6 +182,11 @@ class GridLimeReader : public BinaryIO {
|
|||||||
{
|
{
|
||||||
filename= _filename;
|
filename= _filename;
|
||||||
File = fopen(filename.c_str(), "r");
|
File = fopen(filename.c_str(), "r");
|
||||||
|
if (File == nullptr)
|
||||||
|
{
|
||||||
|
std::cerr << "cannot open file '" << filename << "'" << std::endl;
|
||||||
|
abort();
|
||||||
|
}
|
||||||
LimeR = limeCreateReader(File);
|
LimeR = limeCreateReader(File);
|
||||||
}
|
}
|
||||||
/////////////////////////////////////////////
|
/////////////////////////////////////////////
|
||||||
@@ -228,7 +233,8 @@ class GridLimeReader : public BinaryIO {
|
|||||||
// std::cout << " ReadLatticeObject from offset "<<offset << std::endl;
|
// std::cout << " ReadLatticeObject from offset "<<offset << std::endl;
|
||||||
BinarySimpleMunger<sobj,sobj> munge;
|
BinarySimpleMunger<sobj,sobj> munge;
|
||||||
BinaryIO::readLatticeObject< vobj, sobj >(field, filename, munge, offset, format,nersc_csum,scidac_csuma,scidac_csumb);
|
BinaryIO::readLatticeObject< vobj, sobj >(field, filename, munge, offset, format,nersc_csum,scidac_csuma,scidac_csumb);
|
||||||
|
std::cout << GridLogMessage << "SciDAC checksum A " << std::hex << scidac_csuma << std::dec << std::endl;
|
||||||
|
std::cout << GridLogMessage << "SciDAC checksum B " << std::hex << scidac_csumb << std::dec << std::endl;
|
||||||
/////////////////////////////////////////////
|
/////////////////////////////////////////////
|
||||||
// Insist checksum is next record
|
// Insist checksum is next record
|
||||||
/////////////////////////////////////////////
|
/////////////////////////////////////////////
|
||||||
@@ -245,8 +251,7 @@ class GridLimeReader : public BinaryIO {
|
|||||||
////////////////////////////////////////////
|
////////////////////////////////////////////
|
||||||
// Read a generic serialisable object
|
// Read a generic serialisable object
|
||||||
////////////////////////////////////////////
|
////////////////////////////////////////////
|
||||||
template<class serialisable_object>
|
void readLimeObject(std::string &xmlstring,std::string record_name)
|
||||||
void readLimeObject(serialisable_object &object,std::string object_name,std::string record_name)
|
|
||||||
{
|
{
|
||||||
// should this be a do while; can we miss a first record??
|
// should this be a do while; can we miss a first record??
|
||||||
while ( limeReaderNextRecord(LimeR) == LIME_SUCCESS ) {
|
while ( limeReaderNextRecord(LimeR) == LIME_SUCCESS ) {
|
||||||
@@ -261,15 +266,23 @@ class GridLimeReader : public BinaryIO {
|
|||||||
limeReaderReadData((void *)&xmlc[0], &nbytes, LimeR);
|
limeReaderReadData((void *)&xmlc[0], &nbytes, LimeR);
|
||||||
// std::cout << GridLogMessage<< " readLimeObject matches XML " << &xmlc[0] <<std::endl;
|
// std::cout << GridLogMessage<< " readLimeObject matches XML " << &xmlc[0] <<std::endl;
|
||||||
|
|
||||||
std::string xmlstring(&xmlc[0]);
|
xmlstring = std::string(&xmlc[0]);
|
||||||
XmlReader RD(xmlstring, true, "");
|
|
||||||
read(RD,object_name,object);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
assert(0);
|
assert(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<class serialisable_object>
|
||||||
|
void readLimeObject(serialisable_object &object,std::string object_name,std::string record_name)
|
||||||
|
{
|
||||||
|
std::string xmlstring;
|
||||||
|
|
||||||
|
readLimeObject(xmlstring, record_name);
|
||||||
|
XmlReader RD(xmlstring, true, "");
|
||||||
|
read(RD,object_name,object);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class GridLimeWriter : public BinaryIO
|
class GridLimeWriter : public BinaryIO
|
||||||
@@ -320,16 +333,11 @@ class GridLimeWriter : public BinaryIO
|
|||||||
////////////////////////////////////////////
|
////////////////////////////////////////////
|
||||||
// Write a generic serialisable object
|
// Write a generic serialisable object
|
||||||
////////////////////////////////////////////
|
////////////////////////////////////////////
|
||||||
template<class serialisable_object>
|
void writeLimeObject(int MB,int ME,XmlWriter &writer,std::string object_name,std::string record_name)
|
||||||
void writeLimeObject(int MB,int ME,serialisable_object &object,std::string object_name,std::string record_name)
|
|
||||||
{
|
{
|
||||||
if ( boss_node ) {
|
if ( boss_node ) {
|
||||||
std::string xmlstring;
|
std::string xmlstring = writer.docString();
|
||||||
{
|
|
||||||
XmlWriter WR("","");
|
|
||||||
write(WR,object_name,object);
|
|
||||||
xmlstring = WR.XmlString();
|
|
||||||
}
|
|
||||||
// std::cout << "WriteLimeObject" << record_name <<std::endl;
|
// std::cout << "WriteLimeObject" << record_name <<std::endl;
|
||||||
uint64_t nbytes = xmlstring.size();
|
uint64_t nbytes = xmlstring.size();
|
||||||
// std::cout << " xmlstring "<< nbytes<< " " << xmlstring <<std::endl;
|
// std::cout << " xmlstring "<< nbytes<< " " << xmlstring <<std::endl;
|
||||||
@@ -343,6 +351,20 @@ class GridLimeWriter : public BinaryIO
|
|||||||
limeDestroyHeader(h);
|
limeDestroyHeader(h);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<class serialisable_object>
|
||||||
|
void writeLimeObject(int MB,int ME,serialisable_object &object,std::string object_name,std::string record_name, const unsigned int scientificPrec = 0)
|
||||||
|
{
|
||||||
|
XmlWriter WR("","");
|
||||||
|
|
||||||
|
if (scientificPrec)
|
||||||
|
{
|
||||||
|
WR.scientificFormat(true);
|
||||||
|
WR.setPrecision(scientificPrec);
|
||||||
|
}
|
||||||
|
write(WR,object_name,object);
|
||||||
|
writeLimeObject(MB, ME, WR, object_name, record_name);
|
||||||
|
}
|
||||||
////////////////////////////////////////////////////
|
////////////////////////////////////////////////////
|
||||||
// Write a generic lattice field and csum
|
// Write a generic lattice field and csum
|
||||||
// This routine is Collectively called by all nodes
|
// This routine is Collectively called by all nodes
|
||||||
@@ -449,7 +471,8 @@ class ScidacWriter : public GridLimeWriter {
|
|||||||
// Write generic lattice field in scidac format
|
// Write generic lattice field in scidac format
|
||||||
////////////////////////////////////////////////
|
////////////////////////////////////////////////
|
||||||
template <class vobj, class userRecord>
|
template <class vobj, class userRecord>
|
||||||
void writeScidacFieldRecord(Lattice<vobj> &field,userRecord _userRecord)
|
void writeScidacFieldRecord(Lattice<vobj> &field,userRecord _userRecord,
|
||||||
|
const unsigned int recordScientificPrec = 0)
|
||||||
{
|
{
|
||||||
GridBase * grid = field._grid;
|
GridBase * grid = field._grid;
|
||||||
|
|
||||||
@@ -467,7 +490,7 @@ class ScidacWriter : public GridLimeWriter {
|
|||||||
//////////////////////////////////////////////
|
//////////////////////////////////////////////
|
||||||
if ( this->boss_node ) {
|
if ( this->boss_node ) {
|
||||||
writeLimeObject(1,0,header ,std::string("FieldMetaData"),std::string(GRID_FORMAT)); // Open message
|
writeLimeObject(1,0,header ,std::string("FieldMetaData"),std::string(GRID_FORMAT)); // Open message
|
||||||
writeLimeObject(0,0,_userRecord,_userRecord.SerialisableClassName(),std::string(SCIDAC_RECORD_XML));
|
writeLimeObject(0,0,_userRecord,_userRecord.SerialisableClassName(),std::string(SCIDAC_RECORD_XML), recordScientificPrec);
|
||||||
writeLimeObject(0,0,_scidacRecord,_scidacRecord.SerialisableClassName(),std::string(SCIDAC_PRIVATE_RECORD_XML));
|
writeLimeObject(0,0,_scidacRecord,_scidacRecord.SerialisableClassName(),std::string(SCIDAC_PRIVATE_RECORD_XML));
|
||||||
}
|
}
|
||||||
// Collective call
|
// Collective call
|
||||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -49,14 +49,38 @@ inline double usecond(void) {
|
|||||||
|
|
||||||
typedef std::chrono::system_clock GridClock;
|
typedef std::chrono::system_clock GridClock;
|
||||||
typedef std::chrono::time_point<GridClock> GridTimePoint;
|
typedef std::chrono::time_point<GridClock> GridTimePoint;
|
||||||
typedef std::chrono::milliseconds GridTime;
|
|
||||||
typedef std::chrono::microseconds GridUsecs;
|
|
||||||
|
|
||||||
inline std::ostream& operator<< (std::ostream & stream, const std::chrono::milliseconds & time)
|
typedef std::chrono::seconds GridSecs;
|
||||||
|
typedef std::chrono::milliseconds GridMillisecs;
|
||||||
|
typedef std::chrono::microseconds GridUsecs;
|
||||||
|
typedef std::chrono::microseconds GridTime;
|
||||||
|
|
||||||
|
inline std::ostream& operator<< (std::ostream & stream, const GridSecs & time)
|
||||||
{
|
{
|
||||||
stream << time.count()<<" ms";
|
stream << time.count()<<" s";
|
||||||
return stream;
|
return stream;
|
||||||
}
|
}
|
||||||
|
inline std::ostream& operator<< (std::ostream & stream, const GridMillisecs & now)
|
||||||
|
{
|
||||||
|
GridSecs second(1);
|
||||||
|
auto secs = now/second ;
|
||||||
|
auto subseconds = now%second ;
|
||||||
|
auto fill = stream.fill();
|
||||||
|
stream << secs<<"."<<std::setw(3)<<std::setfill('0')<<subseconds.count()<<" s";
|
||||||
|
stream.fill(fill);
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
|
inline std::ostream& operator<< (std::ostream & stream, const GridUsecs & now)
|
||||||
|
{
|
||||||
|
GridSecs second(1);
|
||||||
|
auto seconds = now/second ;
|
||||||
|
auto subseconds = now%second ;
|
||||||
|
auto fill = stream.fill();
|
||||||
|
stream << seconds<<"."<<std::setw(6)<<std::setfill('0')<<subseconds.count()<<" s";
|
||||||
|
stream.fill(fill);
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class GridStopWatch {
|
class GridStopWatch {
|
||||||
private:
|
private:
|
||||||
@@ -96,6 +120,9 @@ public:
|
|||||||
assert(running == false);
|
assert(running == false);
|
||||||
return (uint64_t) accumulator.count();
|
return (uint64_t) accumulator.count();
|
||||||
}
|
}
|
||||||
|
bool isRunning(void){
|
||||||
|
return running;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
File renamed without changes.
Loaded 100 of 630 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user