mirror of
				https://github.com/paboyle/Grid.git
				synced 2025-10-26 17:49:33 +00:00 
			
		
		
		
	Compare commits
	
		
			2759 Commits
		
	
	
		
			feature/sh
			...
			feature/gp
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | 12eb2a6a34 | ||
|  | 7c8902b04f | ||
|  | 4278caa030 | ||
|  | be37dfb6f8 | ||
|  | 5e8437029f | ||
|  | e279b2be29 | ||
|  | 48e6efc7c9 | ||
| 55c095f620 | |||
|  | 3e49dc8a67 | ||
|  | 96ac56cace | ||
|  | 2b037e3daa | ||
|  | 2d2de7aede | ||
| e3966aa49b | |||
|  | ce97638bac | ||
|  | 53e3ab4131 | ||
| c2c4252a07 | |||
|  | 9cd33a7b9c | ||
|  | 639dc1ab21 | ||
|  | 9117f61109 | ||
|  | bca36d9bc3 | ||
|  | 263dcbabab | ||
|  | 9dad7a0094 | ||
|  | 8c6016f717 | ||
|  | 1282e1067f | ||
|  | 275c1c920f | ||
|  | fe700a183a | ||
|  | 34108296cd | ||
|  | 76c704b84b | ||
|  | ce255ec359 | ||
|  | 1c096626cb | ||
|  | ce8b247426 | ||
|  | 80481f81be | ||
|  | d85dcc72df | ||
|  | 3fedcd6d52 | ||
|  | 25ba4c5f80 | ||
|  | 671bcbcccb | ||
|  | ff325376cb | ||
|  | 9e926e3fc5 | ||
|  | 775eaee199 | ||
|  | 0fd2827d5d | ||
|  | bdd79f9ef8 | ||
|  | 0695f8cec2 | ||
|  | 9fa705c5a0 | ||
|  | 331f5a53dc | ||
|  | a23dc295ac | ||
|  | 08904f830e | ||
|  | fa9cd50c5b | ||
|  | 7c11525d1a | ||
|  | 42c1dbb1d1 | ||
|  | 6179acfda0 | ||
|  | 07601ac1f5 | ||
|  | 705a8098b2 | ||
|  | a29b43d755 | ||
|  | 368c8369ce | ||
|  | c0d89a2dbb | ||
|  | 78ebd93281 | ||
|  | 3d58daf70f | ||
|  | bd155ca5c0 | ||
|  | 91e2cf9b40 | ||
|  | 3cc9947731 | ||
|  | f15eeb0283 | ||
|  | 0996ba9396 | ||
|  | 966a203dcb | ||
|  | 44170cc15f | ||
| c3d0c176ab | |||
| 0a71f8bb10 | |||
| 3a31ba2ea2 | |||
| eac6337466 | |||
| ab7537e002 | |||
|  | 6e3c3214a3 | ||
|  | d6ffadb33b | ||
|  | 4c3225412b | ||
|  | b8f7bfbb26 | ||
|  | 7b7c470917 | ||
|  | 532e226b22 | ||
|  | 6a13731818 | ||
|  | 1059189abf | ||
|  | 1cd4ee0706 | ||
|  | b8f71b6777 | ||
|  | 703dc20377 | ||
|  | d976e5c514 | ||
|  | d7b3efe893 | ||
|  | f710d7bd45 | ||
|  | cb336aa8f8 | ||
|  | 462900b48d | ||
|  | 0561c2edeb | ||
|  | 0184719216 | ||
|  | 24202dbc51 | ||
|  | d763c303c5 | ||
|  | 8e394d3bf9 | ||
|  | b881d5489b | ||
|  | 82306913a8 | ||
|  | 49f90cc7eb | ||
|  | b77af0210b | ||
|  | 5254ede2d8 | ||
|  | 16e5d7945e | ||
|  | decc99ca76 | ||
|  | 464cd65931 | ||
|  | a1ec2f4723 | ||
|  | ea9662ec85 | ||
|  | 52c74f1cac | ||
|  | 9a13d2992c | ||
|  | b0449ae270 | ||
|  | 1299225105 | ||
|  | 5925e7f405 | ||
|  | be1fd4930f | ||
|  | 377fa5dec1 | ||
|  | e8b78f596e | ||
|  | 09720c40cd | ||
|  | bb024dd114 | ||
|  | 52456b9ec7 | ||
|  | b285138be4 | ||
|  | c7dbf4c87e | ||
|  | 1e889c93b8 | ||
|  | 7379047482 | ||
|  | d836ce3b78 | ||
|  | cefaacbc07 | ||
|  | 0074ef7f69 | ||
|  | 20359ca15f | ||
|  | 736358b0cb | ||
|  | 6b692aa726 | ||
|  | 7f99e1cd3b | ||
|  | f3c89df948 | ||
|  | b7e6d111d7 | ||
|  | f39cf69c33 | ||
|  | 8e27338df2 | ||
|  | bcbb5e9d26 | ||
|  | 0ea7f5279d | ||
|  | 18e5de426d | ||
|  | e896d81235 | ||
|  | 7b8ccff4f4 | ||
|  | 68541606ab | ||
|  | 339ea10cc7 | ||
|  | d0d8dc8042 | ||
|  | 81eb1fd9f2 | ||
|  | cb93d32cd9 | ||
|  | 8f223962ff | ||
|  | 36f06555a2 | ||
|  | d6c0e0756d | ||
|  | 3e41b1055c | ||
|  | 9fbcfe612c | ||
|  | e78a5e7838 | ||
|  | da8d87e9da | ||
|  | 8e3a05d89b | ||
|  | 8adc5da7dd | ||
|  | 29a244e423 | ||
|  | 18cbfecf02 | ||
|  | c933ac2248 | ||
|  | ad2c433574 | ||
|  | 86e7fb6e86 | ||
|  | fb91dda7be | ||
|  | 82cf7bc5ab | ||
|  | e452cc0a22 | ||
|  | 4d2b938166 | ||
|  | 10d16ab76c | ||
|  | 1f997fa484 | ||
|  | dc5024e88c | ||
|  | 6d77941990 | ||
|  | 0ee6e77cbc | ||
|  | 18d3cde29a | ||
|  | 7323099966 | ||
|  | 6379651cdd | ||
|  | ba4fd756b9 | ||
|  | d185fc1ebf | ||
|  | 96b36d8367 | ||
|  | 899f8b5065 | ||
|  | c8d0483fe9 | ||
|  | 0f214e5f76 | ||
|  | 8eea568426 | ||
|  | 9636324069 | ||
|  | 8a5489d9e6 | ||
|  | 8113845f9c | ||
|  | b47f73c222 | ||
|  | 5720ced0fd | ||
|  | 2c87b56b53 | ||
|  | dbad48d802 | ||
|  | 4557a1365a | ||
|  | 16e9b87d98 | ||
|  | 685eea3d0f | ||
|  | 65b48831fb | ||
|  | 57396fc595 | ||
|  | a2e199df50 | ||
|  | 020346c848 | ||
|  | c2625a127e | ||
|  | 8794d35c78 | ||
|  | 24bff6dbe6 | ||
|  | 45b15d10d3 | ||
|  | 33d6bbe32b | ||
|  | 7a1569bd46 | ||
|  | 6e2e904a0e | ||
|  | d92a17f359 | ||
|  | 47c063f984 | ||
|  | 7e27a5213a | ||
|  | ade4a126da | ||
|  | 7b59ab5bd7 | ||
|  | fcd8cfe257 | ||
|  | b4b53812cb | ||
|  | 085cac583f | ||
|  | 25e3b8640c | ||
|  | c81d3d422d | ||
|  | 44bbec50b0 | ||
|  | ec68b67d5d | ||
|  | 778450e0c8 | ||
|  | 567aa5f366 | ||
|  | 2ab7e2b175 | ||
|  | 6f61be044d | ||
|  | 269e00509e | ||
|  | a5e90b0ddc | ||
|  | 5622faf226 | ||
|  | 82ecd520c7 | ||
| 620965781e | |||
| 9c18638b24 | |||
| 4bfe678218 | |||
| fc6e584f2c | |||
| 7c3f400fc5 | |||
| 4bca2c17ce | |||
| 8d540a4e85 | |||
| b120ef1fe4 | |||
| 166feb6483 | |||
| f569813b60 | |||
| 0190ada714 | |||
| de1a1dccb3 | |||
| 0b3f40ce16 | |||
| e35e8da111 | |||
| 6fdf93d695 | |||
|  | ffde81f22a | ||
|  | d8098f1ecd | ||
|  | aca788cf4f | ||
| 6064f96fde | |||
| 4e52e46a2c | |||
| 6b27369ade | |||
| ab2e5f88cd | |||
| f244fed6ab | |||
| 9b3701ae27 | |||
| 4ac27340b9 | |||
| c7c0a1065f | |||
| 80947130f9 | |||
|  | 0aee73ea6b | ||
| e43d59045e | |||
| e553678599 | |||
| 0290ee1f6d | |||
| 9a34edcf9f | |||
|  | 246f10001e | ||
| e675c6a48c | |||
|  | a66d110b88 | ||
|  | 918e673078 | ||
|  | 44b53c3ba2 | ||
|  | 2095c12eac | ||
|  | a0e9f3b0a0 | ||
| ae5ad986e2 | |||
|  | a9342c6ae5 | ||
|  | ee6f96d85c | ||
|  | 77ca45ff49 | ||
|  | 4e9df9e93c | ||
|  | 9fe68857a9 | ||
|  | 37336c9e0c | ||
|  | 6c4da3bbc7 | ||
|  | a584b16c4a | ||
|  | dbd7f3f0fc | ||
|  | d14512ee03 | ||
|  | 48b1c806ed | ||
| 0a8b6724ef | |||
|  | ce102ac550 | ||
|  | 94accec311 | ||
|  | 1a82533d22 | ||
|  | e3c56fd9b3 | ||
|  | 955cc7790f | ||
|  | 1179123ac2 | ||
| d8512b03f8 | |||
| d90cf9d022 | |||
| 79e930ba12 | |||
|  | 22e35c9ddd | ||
|  | 698b45e163 | ||
|  | f1744b3f01 | ||
|  | 2b3c22f03d | ||
|  | 8423a05940 | ||
|  | 2acd8ece65 | ||
|  | b638509c61 | ||
| edeb590818 | |||
|  | d9438627d9 | ||
|  | b23305dbe2 | ||
|  | d3b5c02e2d | ||
|  | 8b6541fb60 | ||
|  | 6da9aa9971 | ||
|  | 44e0360b97 | ||
|  | 9003c4a07c | ||
|  | b52fa38f8c | ||
|  | 3f1c4d8789 | ||
| 4f0631615f | |||
| c2cd0e15d7 | |||
|  | 60330e05a3 | ||
|  | f9b8c0cccf | ||
|  | 3cad67e569 | ||
|  | 170ba4e619 | ||
|  | 204a090497 | ||
|  | 3c717c47ef | ||
|  | df41de4cb6 | ||
|  | 6d0b985697 | ||
|  | 94ebcf551c | ||
|  | 6fd4b0be91 | ||
|  | 7894ea6263 | ||
|  | 73d4676997 | ||
|  | 262a73c964 | ||
|  | 5921b1d2b9 | ||
|  | 6505efcb57 | ||
|  | b595f58e4c | ||
|  | b0de7ab7db | ||
|  | e1124d9572 | ||
|  | d416156c16 | ||
|  | cd8d939a1a | ||
|  | 760cfe294c | ||
|  | 13eaf21b5c | ||
|  | 1403ab231b | ||
|  | 0368fbcde8 | ||
|  | 2dd0ec7862 | ||
|  | f4241e59ba | ||
|  | 26b1d2df2d | ||
|  | bc14e86812 | ||
|  | 780a67844e | ||
|  | 8b7805200f | ||
|  | 2871dec6c0 | ||
|  | abde12433e | ||
|  | 1f88ba4e39 | ||
|  | ea5b3ed8a2 | ||
|  | a104115c7d | ||
|  | b899042d81 | ||
|  | 3e712fe643 | ||
|  | f4723e07c5 | ||
|  | 9ed2d02bb2 | ||
| 50d016340c | |||
|  | f7b4fd0f69 | ||
|  | 1f1aa92f14 | ||
| 00963a7499 | |||
|  | 82a77f9960 | ||
|  | 00b4139c16 | ||
|  | 3e9c757b3b | ||
| ecf736e6bf | |||
|  | f22ab5e1bc | ||
| 72f959c0b8 | |||
| 63001d3fa6 | |||
| b1d3d1f1a9 | |||
| c2250fa124 | |||
| 84940fbdf0 | |||
|  | 0a270b3e93 | ||
|  | 6536bed8a4 | ||
| 79160011a1 | |||
|  | 47f5b1e2b5 | ||
|  | a381d34f37 | ||
|  | f0c2108acf | ||
|  | 93a5fc083f | ||
|  | 6d1de8ed2e | ||
|  | 116dde31eb | ||
|  | 12d8bf1ced | ||
| d921a99b1a | |||
|  | 9790926cc5 | ||
|  | a6adb85a1b | ||
|  | 98b5b61fea | ||
|  | 6896c57d7c | ||
|  | b3d480a978 | ||
|  | bb731c97d6 | ||
|  | 974003ae96 | ||
|  | 93348775af | ||
| 91cffef883 | |||
| d3935ae7fc | |||
| 0b426bf9f6 | |||
|  | acd25d0d01 | ||
| b7db99967a | |||
| b930eda69d | |||
| 7852181c2c | |||
| bdf87bc994 | |||
|  | 136e7b2314 | ||
|  | 1ea64b24fe | ||
|  | 8f661f6c05 | ||
|  | ae9e248c95 | ||
|  | 351ffe73cd | ||
|  | 6160795a43 | ||
|  | ded2d5c3ab | ||
|  | 04255128ef | ||
|  | a9a3248cb5 | ||
|  | 7c461dc664 | ||
|  | 15fddde9bf | ||
|  | 048397d880 | ||
|  | 196c9e4a4a | ||
|  | 6a0823718e | ||
|  | 22476cc5a3 | ||
| cb16c96dc7 | |||
| e37614bde4 | |||
| 042bad2ced | |||
| 5bc0857412 | |||
| b540dc1cee | |||
| 7672bb6434 | |||
| f80c548365 | |||
|  | c8bcee6e97 | ||
| 6e0d43aef5 | |||
|  | c1257208e2 | ||
| 74c38822ed | |||
| 318c64adc2 | |||
| d5b053f86f | |||
| c60e50e3cb | |||
| 08d8b1d5fb | |||
| 90d6d28547 | |||
| 9c31305b8d | |||
| 2eb584fdf0 | |||
| 6b46834af8 | |||
| 3692c7f1ef | |||
| 0cf94587cd | |||
|  | 68868c83ff | ||
|  | 9b6ddb6e54 | ||
|  | 447b772136 | ||
|  | c5e081d69c | ||
|  | 535a6aaf05 | ||
|  | 91a7fe247b | ||
|  | 8a1be021d3 | ||
|  | e73b909a48 | ||
|  | a4d9200293 | ||
|  | 350508bdb3 | ||
|  | 38852737e4 | ||
|  | 802404c78c | ||
|  | 0e9b591c1c | ||
|  | c43a2b599a | ||
|  | 8c91e82ee8 | ||
|  | 9d866d062a | ||
|  | 3a4e397e72 | ||
|  | 2b6cfe555f | ||
|  | 7df58dd883 | ||
|  | 4bf86ae60a | ||
|  | 07ee87ff5a | ||
|  | 0c2498fe2f | ||
|  | ad2e65dad5 | ||
|  | 715babeac8 | ||
|  | 3eae9a9e3f | ||
|  | 186aad065f | ||
|  | bf5685eb11 | ||
|  | 4a96c067ae | ||
|  | ab063f33c0 | ||
|  | 9efcc535bc | ||
|  | 231b61d012 | ||
|  | e898f4f0b0 | ||
|  | d5db5f5242 | ||
|  | 2fcedb13dd | ||
|  | 35ed1defac | ||
|  | 4e95accf80 | ||
| fd66325321 | |||
| c637c0c48c | |||
| c4b472176c | |||
|  | 422764757d | ||
|  | 943fa48ce4 | ||
|  | fa97a56fdd | ||
| 856476a890 | |||
|  | afc462bd58 | ||
|  | b57a4d32aa | ||
| c509bd3fe2 | |||
| 49b934310b | |||
| 01e8cf5017 | |||
| 12f4499502 | |||
| 05aec72887 | |||
| 136d3802cb | |||
| a4c55406ed | |||
| c7f33ca2a8 | |||
| 0e3035c51d | |||
| 10fc263675 | |||
| bccfd4cbb3 | |||
| 0b50d4a328 | |||
|  | b74940b3d4 | ||
| e232257cb6 | |||
| 09451b5e48 | |||
| 6364aa8acf | |||
| b9e84ecab7 | |||
| 41032fef44 | |||
| d77bc88170 | |||
| 494b3c9e57 | |||
| 2ba19a9e07 | |||
| 5d7cc29eaf | |||
| f22a27d7f9 | |||
|  | 33a0bbb17b | ||
| f592ec8baa | |||
| 8b007b5c24 | |||
|  | 17b3f47b1e | ||
| 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 | |||
|  | dac9f8622e | ||
| 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 | ||
|  | d9de8fd5c9 | ||
|  | 7e3647246c | ||
| 4af6c7e7aa | |||
| f60fbcfc4d | |||
| 464c81706e | |||
|  | adbdc4e65b | ||
|  | e4deea4b94 | ||
|  | 94d721a20b | ||
| 408130b808 | |||
| 375edd1370 | |||
| 6d912f6c67 | |||
| 6d1d28955e | |||
| 920b471761 | |||
| 63c21767ba | |||
| 7b6b712565 | |||
| 35abd05ee9 | |||
|  | 7bf82f5b37 | ||
|  | f02c7ea534 | ||
|  | bc503b60e6 | ||
|  | 704ca162c1 | ||
|  | b5329d8852 | ||
|  | f27b9347ff | ||
|  | b4967f0231 | ||
|  | 6d0f1aabb1 | ||
|  | f4bfeb835d | ||
|  | 394b7b6276 | ||
| 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 | ||
|  | da17a015c7 | ||
|  | 1fd08c21ac | ||
|  | 28db0631ff | ||
|  | b35401b86b | ||
|  | a0714de8ec | ||
|  | 21a1710b43 | ||
|  | 34e9d3f0ca | ||
|  | c995788259 | ||
|  | 94c7198001 | ||
|  | 04d86fe9f3 | ||
|  | b78074b6a0 | ||
|  | 7dfd3cdae8 | ||
|  | cecee1ef2c | ||
|  | 355d4b58be | ||
|  | 2c54a536f3 | ||
|  | d868a45120 | ||
|  | 9deae8c962 | ||
|  | b2b5137d28 | ||
|  | db86cdd7bd | ||
|  | ec9939c1ba | ||
|  | 2cc07450f4 | ||
|  | c0e8bc9da9 | ||
|  | b1265ae867 | ||
|  | 32bb85ea4c | ||
|  | ca0607b6ef | ||
|  | 19b527e83f | ||
|  | 4730d4692a | ||
|  | 1bb456c0c5 | ||
|  | 4b04ae3611 | ||
|  | 2f776d51c6 | ||
|  | f74617c124 | ||
|  | 8c6a3921ed | ||
| a8a15dd9d0 | |||
| 3ce68a751a | |||
|  | daa0977d01 | ||
|  | a2929f4384 | ||
|  | 7fe3974c0a | ||
|  | f7e86f81a0 | ||
|  | fecec803d9 | ||
|  | 8fe9a13cdd | ||
|  | 3a50afe7e7 | ||
|  | f8e880b445 | ||
|  | 3e947527cb | ||
|  | 31f65beac8 | ||
|  | 38e2a32ac9 | ||
|  | efa84ca50a | ||
|  | 5e96d6d04c | ||
|  | df30bdc599 | ||
|  | 7f45222924 | ||
|  | dd891f5e3b | ||
| d2c42e6f42 | |||
|  | 2881b3e8e5 | ||
| 049cc518f4 | |||
| 2e1c66897f | |||
| adcef36189 | |||
|  | 2f121c41c9 | ||
| e0ed7e300f | |||
| 485207901b | |||
| c760f0a4c3 | |||
| c84eeedec3 | |||
|  | 1ac3526f33 | ||
|  | 0de090ee74 | ||
| 91405de3f7 | |||
|  | 8fccda301a | ||
|  | 7a0abfac89 | ||
|  | ae37fda699 | ||
|  | b5fc5e2030 | ||
|  | cc5d025ea4 | ||
|  | 6c97a6a071 | ||
|  | 73bb2d5128 | ||
|  | b710fec6ea | ||
|  | b2a8cd60f5 | ||
|  | 867ee364ab | ||
|  | 25becc9324 | ||
|  | 94d1ae4c82 | ||
|  | 2075b177ef | ||
|  | 847c761ccc | ||
|  | 8287ed8383 | ||
|  | e6be7416f4 | ||
|  | 26863b6d95 | ||
|  | ebd730bd54 | ||
|  | 066be31a3b | ||
|  | 7a4c142955 | ||
|  | ddcb53bce2 | ||
|  | d1c80e1d46 | ||
|  | c73cc7d354 | ||
|  | 49fdc324a0 | ||
|  | f32714a2d1 | ||
|  | 73a955be20 | ||
|  | 66b7a0f871 | ||
|  | 2ab9d4bc56 | ||
|  | 4f41cd114d | ||
|  | 11c4f5e32c | ||
|  | e9b9550298 | ||
|  | 7564fedf68 | ||
| 8db0ef9736 | |||
|  | 95d4b46446 | ||
|  | 251b904a28 | ||
|  | 5dfd216a34 | ||
|  | 5a112feac3 | ||
|  | 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 | ||
|  | eb7d34a4cc | ||
|  | aab27a655a | ||
|  | 93280bae85 | ||
|  | c5f93abcd7 | ||
|  | d5deef782d | ||
|  | 5f50473c0d | ||
| a61e0df54b | |||
| 9d835afa35 | |||
| 5e3be47117 | |||
|  | 13f50406e3 | ||
|  | 09cd46d337 | ||
|  | d3f51065c2 | ||
|  | 925ac4173d | ||
|  | eb921041d0 | ||
| 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 | ||
|  | fe6860b4dd | ||
|  | d6406b13e1 | ||
|  | e369d7306d | ||
|  | 9f8d63e104 | ||
|  | 9b0240d101 | ||
|  | b27f0e5a53 | ||
|  | 75e4483407 | ||
|  | 0734e9ddd4 | ||
|  | 809b1cdd58 | ||
|  | 1be8089604 | ||
|  | 3e0eff6468 | ||
|  | 7ecc47ac89 | ||
|  | e9f1ac09de | ||
|  | fa0d8feff4 | ||
| 49b8501fd4 | |||
| d47484717e | |||
|  | 05b44aef6b | ||
|  | 03e9832efa | ||
|  | 28a375d35d | ||
|  | 3b06381745 | ||
|  | 91a0a3f820 | ||
|  | 8f44c799a6 | ||
|  | 96272f3841 | ||
|  | 5c936d88a0 | ||
|  | 1c64ee926e | ||
|  | 2cbb72a81c | ||
|  | 31d83ee046 | ||
|  | a9e8758a01 | ||
|  | 3e125c5b61 | ||
|  | eac6ec4b5e | ||
|  | 213f8db6a2 | ||
|  | 6358f35b7e | ||
|  | 43f5a0df50 | ||
|  | c897878776 | ||
| cc6eb51e3e | |||
|  | 507009089b | ||
|  | 2baf193031 | ||
|  | 362ba0443a | ||
|  | 276a2353df | ||
| b234784c8e | |||
| 6ea2a8b7ca | |||
| c1d0359aaa | |||
| 047ee4ad0b | |||
| a13106da0c | |||
| 75113e6523 | |||
| 325c73d051 | |||
| b25a59e95e | |||
|  | c5b9147b53 | ||
|  | 64ac815fd9 | ||
|  | a1be533329 | ||
| 7c4533797f | |||
| af84fd65bb | |||
|  | 1a2613086a | ||
|  | 4f110c09a5 | ||
| 6764362237 | |||
| 2fa2b0e0b1 | |||
| b61292f735 | |||
| ce7720e221 | |||
| 853a5528dc | |||
| 169f405c9c | |||
| c6125b01ce | |||
| b0b5b34bff | |||
| 1c9722357d | |||
| 141da3ae71 | |||
| 94edf9cf8b | |||
| c11a3ca0a7 | |||
|  | 870b1a85ae | ||
|  | b5510427f9 | ||
|  | 26ed65c8f8 | ||
|  | f7f043d8cf | ||
|  | ddcaa6ad29 | ||
|  | 87c5c0271b | ||
|  | a3f5a13591 | ||
|  | 9fe28f00eb | ||
| 334da7f452 | |||
| 4669ecd4ba | |||
| 4573b34cac | |||
|  | a8a0bb85cc | ||
|  | 6411caad67 | ||
|  | 7533035a99 | ||
| 17f57e85d1 | |||
| c8d4d184ee | |||
| 17f27b1ebd | |||
| a16bbecb8a | |||
| 7c9b0dd842 | |||
| 6b7228b3e6 | |||
| f117552334 | |||
| a21a160029 | |||
| 1569a374a9 | |||
| eddf023b8a | |||
| 6b8ffbe735 | |||
| 81050535a5 | |||
| 7dcf5c90e3 | |||
| 9ce00f26f9 | |||
| 85c253ed4a | |||
| ccfc0a5a89 | |||
| d3f857b1c9 | |||
| fb62035aa0 | |||
| 0260bc7705 | |||
| 68e6a58f12 | |||
|  | 73ced656eb | ||
|  | f69008edf1 | ||
|  | 57a49ed22f | ||
|  | ff6413a764 | ||
|  | 2530bfed01 | ||
| 640515e3d8 | |||
|  | f089bf5629 | ||
|  | 276f113f28 | ||
| 97c579f637 | |||
| a13c109111 | |||
|  | ab6afd18ac | ||
|  | 5bde64d48b | ||
|  | 2f5add4d5f | ||
| c5a885dcd6 | |||
|  | 74f79c5ac7 | ||
|  | 58c30c0cb1 | ||
|  | 917a92118a | ||
| a4d8512fb8 | |||
| 5ec903044d | |||
|  | 04f9cf088d | ||
|  | 99107038f9 | ||
| 8a0cf0194f | |||
|  | b78456bdf4 | ||
|  | 08543b6b11 | ||
|  | 63ba33371f | ||
|  | 683a7d2ddd | ||
| 1c680d4b7a | |||
|  | b15db11c60 | ||
|  | f6077f9d48 | ||
|  | 572954ef12 | ||
|  | cedeaae7db | ||
|  | e6cf0b1e17 | ||
|  | 5412628ea6 | ||
|  | 1f70cedbab | ||
|  | b50f37cfb4 | ||
|  | cb0d2a1b03 | ||
|  | 6fe9b28a82 | ||
|  | b002587d7c | ||
|  | 6c08385782 | ||
|  | afdcbf79d1 | ||
|  | 3c3ec4e267 | ||
|  | bbe1d5b49e | ||
|  | 0f6009a29f | ||
|  | 1cfed3de7c | ||
|  | c9c073eee4 | ||
|  | f290b2e908 | ||
|  | 5f8225461b | ||
|  | 4e1272fabf | ||
|  | 607dc2d3c6 | ||
|  | 23c880b009 | ||
|  | 334bb6792f | ||
|  | a3690071b4 | ||
|  | 299d119013 | ||
|  | 55be842d23 | ||
|  | edbc0d49d7 | ||
| e9323460c7 | |||
| 20e186a1e0 | |||
|  | 6ef4af989b | ||
|  | ccde8b817f | ||
|  | 68168bf72d | ||
|  | e93d0feaa7 | ||
|  | 8f601d9b39 | ||
|  | 5436308e4a | ||
|  | 07fe7d0cbe | ||
|  | 60b57706c4 | ||
|  | 58c2f60b69 | ||
|  | bfa3a7b3b0 | ||
|  | 954e38bebe | ||
|  | b1a38bde7a | ||
|  | 9875c446c6 | ||
|  | 9c25eb35ca | ||
|  | 5ac96dbdc6 | ||
|  | 5cc9aca85d | ||
|  | ac29ebcb95 | ||
|  | 2581875edc | ||
|  | f212b0a963 | ||
|  | 62702dbcb8 | ||
| 41d6cab033 | |||
| 5a31e747c9 | |||
| cbc73a3fd1 | |||
|  | a5cfb89304 | ||
|  | f04a7251cc | ||
|  | d4ce7d9905 | ||
|  | 8a1d303ab9 | ||
|  | bf0a4de919 | ||
|  | 6fe5885fe4 | ||
|  | 17ac309e84 | ||
|  | 7467a1c027 | ||
|  | fdfb8a26a8 | ||
|  | 2df4e422ad | ||
|  | 3a3e3cac40 | ||
|  | b1c02ec310 | ||
|  | 38eadee2c9 | ||
|  | 42c70437be | ||
|  | 65274b4d7f | ||
|  | 6c6d43eb4e | ||
|  | e1dcfd3553 | ||
|  | 888838473a | ||
|  | 01568b0e62 | ||
|  | d5ce66f6ab | ||
|  | d86936a3de | ||
|  | ee5cf6c8c5 | ||
| d516938707 | |||
|  | 7e8be32755 | ||
| 72344d1418 | |||
| 7ecf6ab38b | |||
| 2d4d70d3ec | |||
| 78f8d47528 | |||
| b85f987b0b | |||
| f57afe2079 | |||
|  | 0fb84fa34b | ||
|  | 8462bbfe63 | ||
| 229977c955 | |||
| e485a07133 | |||
|  | 0880747edb | ||
|  | b801e1fcd6 | ||
|  | ff761ea4e6 | ||
| 70ec2faa98 | |||
|  | a31d3e60d8 | ||
|  | a66cecc509 | ||
|  | 0f6cdf3d4b | ||
|  | 1e63b73a14 | ||
| 2f849ee252 | |||
| bb6ed44339 | |||
|  | 4d60b92b7f | ||
| 360cface33 | |||
|  | 80302e95a8 | ||
|  | c159c70c84 | ||
|  | 28b5572755 | ||
|  | 5fac7080bc | ||
|  | 4548523ecc | ||
| caf2f6b274 | |||
| c49be8988b | |||
| 971c2379bd | |||
|  | 94b0d66e4c | ||
|  | 5e8af396fd | ||
|  | 4154fc6f44 | ||
|  | 4e3458516a | ||
|  | 90a2efb9b3 | ||
| 9942723189 | |||
| a7d19dbb64 | |||
| 90dbe03e17 | |||
| 8b14096990 | |||
|  | b938202081 | ||
| e79ef469ac | |||
| 485c5db0fe | |||
|  | c793947209 | ||
|  | 40699221e2 | ||
|  | 3cb1b545d0 | ||
| 3e9ee053a1 | |||
| dda6c69d5b | |||
| cd51b9af99 | |||
|  | e199ba7e88 | ||
|  | c399c2b44d | ||
|  | af7de7a294 | ||
|  | 1dc86efd26 | ||
|  | 4d53703c67 | ||
|  | d506c59efa | ||
|  | 44188a5c6f | ||
|  | 2018077770 | ||
|  | 984e06e2b5 | ||
|  | aead94e9a7 | ||
|  | 3277bda130 | ||
|  | 442b0b406c | ||
|  | 8824a54269 | ||
|  | c03423250f | ||
|  | 317fd0da44 | ||
|  | 783795a44a | ||
|  | 0e6197fbed | ||
|  | dad7862f91 | ||
|  | c89a883448 | ||
|  | c204288fbc | ||
|  | ad739f042a | ||
|  | db988301d0 | ||
|  | 9b1f29c4c2 | ||
|  | e5ea04ee0c | ||
|  | c92a3c6068 | ||
|  | 03f8da8fbc | ||
| f32555dcc5 | |||
| 30391cb2eb | |||
| e93c883470 | |||
|  | 2e88408f5c | ||
| 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 | |||
|  | 78a9e31ff0 | ||
|  | c1fc947bb8 | ||
|  | ff7b19a71b | ||
|  | 1c16ffa1c1 | ||
|  | 4962f59477 | ||
|  | e158b60bce | ||
|  | 34820bec27 | ||
|  | eed9aa9f0c | ||
|  | 8792ff6439 | ||
|  | 078901278c | ||
|  | bf5fb89aff | ||
|  | 7574c18cef | ||
|  | 36ea5f6b77 | ||
|  | 285deab432 | ||
|  | bb7d87d0a0 | ||
|  | ec3954ff5f | ||
|  | 0f468e2179 | ||
|  | 8e61286741 | ||
|  | 4790e99817 | ||
|  | 2dd63aa7a4 | ||
|  | 559a501140 | ||
|  | 945684c470 | ||
|  | e30a80a234 | ||
|  | 69e4ecc1d2 | ||
|  | 5f483df16b | ||
|  | 4680a977c3 | ||
|  | de42456171 | ||
|  | d55212c998 | ||
|  | c96483e3bd | ||
|  | c6e1f64573 | ||
|  | ae31a6a760 | ||
|  | dd8f2a64fe | ||
|  | 724cf02d4a | ||
|  | 7b8b2731e7 | ||
|  | 237a8ec918 | ||
|  | 49a0ae73eb | ||
|  | 6ab60c5b70 | ||
|  | 8c692b7ffd | ||
|  | 2976132bdd | ||
|  | 48177f2f2d | ||
|  | c4ce70a821 | ||
|  | 315f1146cd | ||
|  | a3e009ba54 | ||
|  | eb7cf239d9 | ||
|  | 13ae371ef8 | ||
|  | 9f79a87102 | ||
|  | 4ded1ceeb0 | ||
|  | 9f202782c5 | ||
|  | 8bc12e0ce1 | ||
|  | cc2f00f827 | ||
|  | cd61e2e6d6 | ||
|  | 323ed1a588 | ||
|  | 68c66d2e4b | ||
|  | 1671adfd49 | ||
|  | 594a262dcc | ||
|  | 7f8ca54285 | ||
|  | c5b23c367e | ||
|  | b6fe03eb26 | ||
|  | f37ed4958b | ||
|  | b9b5bdfc3a | ||
|  | 51eb2c5dfc | ||
|  | ede0dff794 | ||
|  | aa6de818e2 | ||
|  | dcf6517a93 | ||
|  | a308dff410 | ||
|  | 14ba20898a | ||
|  | a53d3ee19a | ||
|  | 5df435319d | ||
|  | 0da2d3e222 | ||
|  | 9c9dfbfa78 | ||
|  | e4df025d01 | ||
|  | cfeda9d536 | ||
|  | 4450b1993a | ||
|  | d03ce5c2a4 | ||
|  | 7d6522c1ef | ||
|  | b96832a922 | ||
|  | 5d7af47b05 | ||
|  | 053ef25c90 | ||
|  | 8ae77d3706 | ||
|  | 896f3a8002 | ||
|  | 5f85473d6b | ||
|  | 871649238c | ||
|  | ac3b0ebc58 | ||
|  | 7c86d2085b | ||
|  | 9292be0b69 | ||
|  | f0fcdf75b5 | ||
|  | 53bffb83d4 | ||
|  | 10141f90c9 | ||
|  | cd44e851f1 | ||
|  | a414430817 | ||
|  | f20728baa9 | ||
|  | d2e68c4355 | ||
|  | 1cb745c8dc | ||
|  | faf4278019 | ||
|  | 194e4b94bb | ||
|  | bfc1411c1f | ||
|  | 161637e573 | ||
|  | 79b50feacf | ||
|  | fb24e3a7d2 | ||
|  | 655a69259a | ||
|  | c67c1544cd | ||
|  | e657f9a344 | ||
|  | b6ebf35af5 | ||
|  | 604c05f4b8 | ||
|  | 70e276e1ab | ||
|  | 9472b02771 | ||
|  | 9597ab94eb | ||
|  | ce4da83bc2 | ||
|  | d557f3ef77 | ||
|  | f574c20118 | ||
|  | f102897385 | ||
|  | d6fce3e498 | ||
|  | 2d0bcc2606 | ||
|  | 45df59720e | ||
|  | 44ef5bc207 | ||
|  | 98af36217a | ||
|  | 4e0cf0cc28 | ||
|  | 507c4e9efc | ||
|  | be7b37b9c9 | ||
|  | c4f82e072b | ||
|  | 3f9654e397 | ||
|  | 912b50f6fa | ||
|  | 2a4a0e43c1 | ||
|  | 32523a229c | ||
|  | 1ebd56c3fb | ||
|  | 8dccffdfd5 | ||
|  | 5642ea270f | ||
|  | 43cea62855 | ||
|  | 2b4067bb71 | ||
|  | 85771e97e9 | ||
|  | 8b371ffa94 | ||
|  | bf659dfd92 | ||
|  | cdf550845f | ||
|  | 3db7a5387b | ||
|  | 76a4dd36d9 | ||
|  | f4010023ca | ||
|  | 24a4589def | ||
|  | c904822e74 | ||
|  | 40ee1e1957 | ||
|  | 461df78a3f | ||
|  | db9c9475d4 | ||
|  | 214f7a6f13 | ||
|  | c844cfcda8 | ||
|  | a3e3034e6f | ||
|  | e7cba358c2 | ||
|  | f8a5194c70 | ||
|  | cff3bae155 | ||
|  | 90dffc73c8 | ||
|  | 99329197ee | ||
|  | 421401af55 | ||
|  | 0626c1e39e | ||
|  | 725f03e2e2 | ||
|  | 65f77112e0 | ||
|  | 408b868475 | ||
|  | 1c797deb04 | ||
|  | b9d5a42b57 | ||
|  | e737591918 | ||
|  | ba5ea5830b | ||
|  | 43f244badf | ||
|  | e9c8ba5ef7 | ||
|  | d70709a8e8 | ||
|  | 733f8ff0b2 | ||
|  | 0bfa5bb213 | ||
|  | 1f26a234f9 | ||
|  | 13f0116425 | ||
|  | 25f589b064 | ||
|  | 210c50a278 | ||
|  | 549a143e78 | ||
|  | 277301486d | ||
|  | c851b39a49 | ||
|  | 15cc12eb6c | ||
|  | ae4f1f8c12 | ||
|  | 5609624b44 | ||
|  | b5a947dd79 | ||
|  | ee16f62322 | ||
|  | 3318de27d6 | ||
|  | ac56965306 | ||
|  | 8e99264f40 | ||
|  | 69327db9a9 | ||
|  | 7331ee2d80 | ||
|  | 918c105c57 | ||
|  | be1511d469 | ||
|  | f1c31df9d2 | ||
|  | ff7b587fad | ||
|  | 4e1135b214 | ||
|  | acd4955a18 | ||
|  | bd08dc4f45 | ||
|  | 22d137d4e5 | ||
|  | 87ee592176 | ||
|  | 063603b1ea | ||
|  | f292106db6 | ||
|  | 9d08aebea9 | ||
|  | 4e30739093 | ||
| a1151fc734 | |||
|  | ab3baeb38f | ||
|  | 389731d373 | ||
| 6e3ce7423e | |||
| 15f15a7cfd | |||
| 0e5f626226 | |||
|  | 04f92ccddf | ||
|  | 3b2d805398 | ||
|  | 97b9c6f03d | ||
|  | 63982819c6 | ||
|  | 6fec507bef | ||
|  | 219b3bd34f | ||
|  | 9dc885d297 | ||
|  | a70c1feecc | ||
|  | 38328100c9 | ||
|  | 9732519c41 | ||
|  | fa4eeb28c4 | ||
|  | b00d2d2c39 | ||
|  | f1b3e21830 | ||
|  | 90ea472411 | ||
|  | 56999474e2 | ||
|  | d74c21a386 | ||
|  | ca6bdd7302 | ||
|  | 6f20f1d224 | ||
|  | d0e357ef89 | ||
|  | 21251f2e1b | ||
|  | fcf1ccf669 | ||
|  | 49cce514f1 | ||
|  | 695af98a1d | ||
|  | f8cb46d360 | ||
|  | 0da64dea90 | ||
|  | 2cceebbf12 | ||
|  | 40232dcefe | ||
|  | dbd86bb95b | ||
|  | b8fd2c161f | ||
|  | df9b979583 | ||
|  | 23ef0e3e19 | ||
|  | ae9175735a | ||
|  | 2d13ea1a22 | ||
|  | 8c675064bd | ||
|  | 550b905bb8 | ||
|  | edb79dc088 | ||
|  | 88e635c5d1 | ||
|  | ecb4a24de8 | ||
|  | c8c1d36710 | ||
|  | b4bb428d9b | ||
|  | e9ef7e3852 | ||
|  | 31cbbfc07e | ||
|  | 4eb0552d1d | ||
|  | 08f2a4564f | ||
|  | 7e00f643f8 | ||
|  | c19ccdad7c | ||
|  | 8aed4181e1 | ||
|  | 06ab7f5661 | ||
|  | 645ec8eba0 | ||
|  | 72ffa8a88e | ||
|  | 4c829b410e | ||
|  | eda4fd9912 | ||
|  | 041d9137c0 | ||
|  | eeacdfe031 | ||
|  | e5535f4d72 | ||
|  | 044a292281 | ||
|  | fe0467df1e | ||
|  | 19234fb40e | ||
|  | f445257d28 | ||
|  | bdc2a987aa | ||
|  | 72acb0e48f | ||
|  | b4e9211df7 | ||
|  | 97019d2997 | ||
|  | 83c5f05094 | ||
|  | 1619e42d90 | ||
|  | 9f6cebe5ff | ||
|  | a84ebe5624 | ||
|  | c527e39881 | ||
|  | a0f4687887 | ||
|  | 3ef7b2389e | ||
|  | 7dfa3d0b50 | ||
|  | bf629dddce | ||
|  | 7747b95430 | ||
|  | ccd75c039a | ||
|  | 493ea80208 | ||
|  | 229baf3aba | ||
|  | 0ce4ecfc84 | ||
|  | ddfaae8ea6 | ||
|  | 70c5b781e5 | ||
|  | 901e359d28 | ||
|  | e857d4d4c8 | ||
|  | e5b77c7fd8 | ||
|  | 3b5d629048 | ||
|  | 08772d5e0c | ||
|  | 017dcd69a6 | ||
|  | 8178a17b88 | ||
|  | c5c1b53e54 | ||
|  | 440f9e2013 | ||
|  | c98657d588 | ||
|  | f450857716 | ||
|  | 9ec238df9e | ||
|  | 3ba8eb1500 | ||
|  | 8da49c5a34 | ||
|  | e04f61b1fa | ||
|  | 115e13b227 | ||
|  | 75f3062a80 | ||
|  | b460cd3ef1 | ||
|  | 0e6727a33b | ||
|  | 4c6745cb4c | ||
|  | efdd0e572c | ||
|  | ca60a218ac | ||
|  | 03633d709e | ||
|  | 4de58c4aab | ||
|  | 4f8b1c1940 | ||
|  | dec39b313d | ||
|  | dc835ad1cb | ||
|  | 71c8c9e4fb | ||
|  | a935ef7b39 | ||
|  | a97ad1a51d | ||
|  | 5ab9129db3 | ||
|  | 634943c11f | ||
|  | e598e65f69 | ||
|  | 291407dc7f | ||
|  | 641a28aa1d | ||
|  | 75207fa010 | ||
|  | c2b0e0269a | ||
|  | 7828887604 | ||
|  | e6efc93a7c | ||
|  | ff7e773d5e | ||
|  | a0380fad72 | ||
|  | 61e9a33777 | ||
|  | 3e139b52d3 | ||
|  | fd6031b005 | ||
|  | fe44fc50d9 | ||
|  | 2dd88cf3f8 | ||
|  | 6b7e82f1a9 | ||
|  | be612b3931 | ||
|  | f5e74033f9 | ||
|  | 8d52e0a349 | ||
|  | a60f6d353e | ||
|  | 5d3b574325 | ||
|  | 6ee5ea6b32 | ||
|  | cc349c6512 | ||
|  | fde2e07bf4 | ||
|  | 2f38fe8d45 | ||
|  | 813af84ae8 | ||
|  | cfe6c6838f | ||
|  | 12a7216dfe | ||
|  | 71ebd61327 | ||
|  | 2c2da60cc2 | ||
|  | 7631ed9c56 | ||
|  | 65669b116e | ||
|  | ae2a6cfc6e | ||
|  | c36223055e | ||
|  | e42de105c5 | ||
|  | b08dae0809 | ||
|  | 3bf8fddbb5 | ||
|  | d29fa23ebc | ||
|  | c978c88521 | ||
|  | 93f09818da | ||
|  | 54a8ea93ec | ||
|  | 56e87d6e55 | ||
|  | df29cc19ab | ||
|  | e61189db3f | ||
|  | 361ce948c3 | ||
|  | 049b4a4631 | ||
|  | 9f2f294a27 | ||
|  | 81dcd0e6ea | ||
|  | 34a788331f | ||
|  | e2c39945b3 | ||
|  | 1591d391b9 | ||
|  | f4c06ed8c0 | ||
|  | 1f49f781bf | ||
|  | 3a9f746421 | ||
|  | 4491d87766 | ||
|  | 0e080a7abc | ||
|  | 8bf78846ee | ||
|  | 9aa34dc803 | ||
|  | fdcbe0a0d1 | ||
|  | 6a62a9c6a5 | ||
|  | b331ecea78 | ||
|  | 66f8a2f082 | ||
|  | d58b7cf9b9 | ||
|  | 0d749becff | ||
|  | 1dbea9aa69 | ||
|  | c1438cbbe3 | ||
|  | f4623fd551 | ||
|  | 59ba9ff3bb | ||
|  | 1fbab4032b | ||
|  | c037244874 | ||
|  | f4272aa6fd | ||
|  | 8cb7a1a887 | ||
|  | b45bd8e097 | ||
|  | 5e48b701ec | ||
|  | 7f6bffe5ad | ||
|  | 6bf5fb1924 | ||
|  | 086db7bd19 | ||
|  | c0a9b38c02 | ||
|  | 6d7bdfb5f5 | ||
|  | be5d70ae6e | ||
|  | ab1068044e | ||
|  | dda151250f | ||
|  | 18daf85069 | ||
|  | 81cc28f6ca | ||
|  | c01a1e02fe | ||
|  | 7e70f4ed9c | ||
|  | 1056e36f11 | ||
|  | 0b8a88978b | ||
|  | 59b31b6bb8 | ||
|  | 69496482fc | ||
|  | 4be31ad1f6 | ||
|  | 176a021ce9 | ||
|  | b673174b71 | ||
|  | e6f7a5a818 | ||
|  | 68b69a2ac0 | ||
|  | bd15c38ae8 | ||
|  | b815f5f764 | ||
|  | 4da437431e | ||
|  | 3c7bf211a9 | ||
|  | 347d5404dd | ||
|  | 5e2cd0d07c | ||
|  | 62fcee72c5 | ||
|  | 0a6168eef0 | ||
|  | 63865e4232 | ||
|  | c64deedf74 | ||
|  | 3281559ec3 | ||
|  | 6a2eca2ec2 | ||
|  | d8ff895e74 | ||
|  | 00c49d4c17 | ||
|  | ec89714cce | ||
|  | 6ab744c720 | ||
|  | bbb657da5c | ||
|  | fbc2380cb8 | ||
|  | 08682c5461 | ||
|  | 13bce2a6bf | ||
|  | 70e689900b | ||
|  | b7f8c5b823 | ||
|  | 3923683e9b | ||
|  | e199fda9dc | ||
| 7bb405e790 | |||
|  | 10f7a17ae4 | ||
|  | 26f14d7dd7 | ||
| ec16eacc6a | |||
|  | cf858deb16 | ||
|  | a3affac963 | ||
| d9d1f43ba2 | |||
| b7cd721308 | |||
| 29f026c375 | |||
| 58c7a13d54 | |||
|  | 24162c9ead | ||
|  | 73434db636 | ||
|  | e564d11687 | ||
|  | 0b2162f375 | ||
|  | 5610570182 | ||
|  | 44f65526e0 | ||
|  | 43e48542ab | ||
|  | 0b85f1bfc8 | ||
|  | 9947cfbf14 | ||
|  | 357badce5e | ||
|  | 0091eec23a | ||
|  | 9e9c2962df | ||
|  | bda97212a9 | ||
|  | b91282ad46 | ||
|  | 0a68470f9a | ||
|  | 6ecf280723 | ||
|  | 7eeab7f995 | ||
|  | 9b32d51cd1 | ||
|  | 7b3ed160aa | ||
|  | 1a0163f45c | ||
|  | c6411f8514 | ||
|  | 9028e278e4 | ||
| dd62f2f371 | |||
| 0d612039ed | |||
| e8ac75055c | |||
| 8b30c5956c | |||
| 185da83454 | |||
| 6718fa8c4f | |||
|  | 4ce63af7d5 | ||
|  | 6cf635d61c | ||
|  | 39558cce52 | ||
|  | 935cd1e173 | ||
|  | 55e39df30f | ||
| 67c3fa0f5f | |||
| 65d4f17976 | |||
| e2fe97277b | |||
|  | 84f9c37ed4 | ||
| bcf6f3890c | |||
| 591a38c487 | |||
|  | 581be32ed2 | ||
| 842754bea9 | |||
|  | 6bc136b1d0 | ||
| 0887566134 | |||
| 61fc50d616 | |||
| a9c8d7dad0 | |||
| 259d504ef0 | |||
| f3a77f4b7f | |||
| 26d7b829a0 | |||
| 64161a8743 | |||
| 2401360784 | |||
|  | 2cfb50cbe5 | ||
| f9aa39e1c4 | |||
|  | df152648d6 | ||
| 0fbf445edd | |||
| e78794688a | |||
| 9e31307963 | |||
| 29e2eddea8 | |||
| 0a038ea15a | |||
| 62eb1f0e59 | |||
| 5422251959 | |||
|  | 9579c9c327 | ||
|  | 3729c7a7a6 | ||
|  | c24d4c8d0e | ||
|  | a14038051f | ||
|  | 3e560b9462 | ||
|  | d93c6760ec | ||
|  | ae3b7713a9 | ||
| cbd8fbe771 | |||
| d391f05cb7 | |||
| 3127b52c90 | |||
| 01f00385a4 | |||
| 59aae5f5ec | |||
| 624246409c | |||
| 2a9ebddad5 | |||
| ff7afe6e17 | |||
| 33cb509d4b | |||
| 456c78c233 | |||
| 2fd4989029 | |||
| 2427a21428 | |||
| 514993ed17 | |||
|  | 7a0c9e84f8 | ||
|  | caf1a3c85d | ||
|  | 21ca730a49 | ||
|  | c6cd27e9b2 | ||
|  | 6068411d61 | ||
|  | 4e965c168e | ||
|  | f260af546e | ||
|  | 28ceacec45 | ||
|  | e6a3e375cf | ||
|  | 4987edbd44 | ||
|  | ad140bb6e7 | ||
|  | 1f04e56038 | ||
|  | 4bfc8c85c3 | ||
|  | e55397bc13 | ||
|  | 649b8c9aca | ||
|  | 0afa22747d | ||
| a3fe874a5b | |||
| f403ab0133 | |||
|  | 94b8fb5686 | ||
|  | 1f1d77b01a | ||
|  | 6a15e2e8ef | ||
| 074d17429f | |||
|  | fa43206c79 | ||
|  | 25f73018f4 | ||
|  | 1d7ccc6b2c | ||
|  | a367835bf2 | ||
|  | d7743591ea | ||
|  | c6cbe533ea | ||
|  | 8402ab6cf9 | ||
|  | c63095345e | ||
|  | 59d9ccf70c | ||
|  | a7ae46b61e | ||
|  | cd63052205 | ||
|  | 699d537cd6 | ||
|  | 9031f0ed95 | ||
|  | 26b3d441bb | ||
|  | 99bc4cde56 | ||
|  | e843d83d9d | ||
|  | 0f75ea52b7 | ||
|  | 8107b785cc | ||
|  | 37b777d801 | ||
|  | 7382787856 | ||
|  | 781c611ca0 | ||
|  | b069090b52 | ||
|  | 0c1c1d9900 | ||
|  | 7f4ed6c2e5 | ||
|  | 56d32a4afb | ||
|  | b8ee496ed6 | ||
|  | 1860b1698c | ||
|  | 9b8d1cc3da | ||
|  | 0c668bf46a | ||
|  | 149c3f9e9c | ||
|  | b87416dac4 | ||
|  | 176bf37372 | ||
|  | c519aab19d | ||
|  | b3d342ca22 | ||
|  | e1f928398d | ||
|  | 69929f20bb | ||
|  | 8c579d2d4a | ||
|  | 840814c776 | ||
|  | fc7d07ade0 | ||
|  | b3be9195b4 | ||
|  | 9e3c187a4d | ||
|  | 8363edfcdb | ||
|  | 74af31564f | ||
|  | e0819d395f | ||
|  | a493429218 | ||
|  | 915f610da0 | ||
|  | c79606a5dc | ||
|  | 95af55128e | ||
|  | 9f2a57e334 | ||
|  | c645d33db5 | ||
|  | e0f1349524 | ||
|  | 360efd0088 | ||
|  | 7b42ac9982 | ||
|  | c5c647e35e | ||
| a4e5fd1000 | |||
| 682e7d7839 | |||
|  | 8e057721a9 | ||
|  | fa5e4add47 | ||
|  | 6f81906b00 | ||
|  | 79b761f923 | ||
|  | 0d4e31ca58 | ||
|  | a2d83d4f3d | ||
|  | 89bacb0470 | ||
|  | b07a354a33 | ||
|  | 19010ff66a | ||
|  | 27ea2afe86 | ||
|  | 78e8704eac | ||
|  | 67131d82f2 | ||
|  | 615a9448b9 | ||
|  | 00164f5ce5 | ||
|  | a7f72eb994 | ||
|  | 501fa1614a | ||
|  | 5bf42e1e15 | ||
|  | fe4d9b003c | ||
|  | 4a699b4da3 | ||
|  | 689323f4ee | ||
|  | 749189fd72 | ||
|  | f941c4ee18 | ||
|  | 84b441800f | ||
|  | 1ef424b139 | ||
|  | 5a477ed29e | ||
|  | 54128d579a | ||
|  | e7b1933e88 | ||
|  | 1bad64ac6a | ||
|  | 15dfa9f663 | ||
|  | 2185b0d651 | ||
|  | f61c0b5d03 | ||
|  | 074db32e54 | ||
|  | aa66f41c69 | ||
|  | f96c800d25 | ||
|  | 32a52d7583 | ||
|  | fa04b6d3c2 | ||
|  | 7fab183c0e | ||
|  | 9ec9850bdb | ||
|  | 0c4ddaea0b | ||
|  | 00ebc150ad | ||
|  | 0f3e9ae57d | ||
|  | 034de160bf | ||
|  | 76bcf6cd8c | ||
|  | 91b8bf0613 | ||
|  | 14507fd6e4 | ||
|  | 2db05ac214 | ||
|  | 31f99574fa | ||
|  | a34c8a2961 | ||
|  | ccd20df827 | ||
|  | e9be293444 | ||
|  | d577211cc3 | ||
|  | f4336e480a | ||
|  | e4d461cb03 | ||
|  | 3d63b4894e | ||
|  | 08583afaff | ||
|  | b395a312af | ||
|  | 66295b99aa | ||
|  | b8654be0ef | ||
|  | a479325349 | ||
|  | f6c3f6bf2d | ||
|  | d83868fdbb | ||
|  | 303e0b927d | ||
|  | 28ba8a0f48 | ||
|  | f9e28577f3 | ||
|  | e0cae833da | ||
|  | 8a3aae98f6 | ||
|  | 8309f2364b | ||
|  | d5f661ba70 | ||
|  | cac1750078 | ||
|  | e17cd35151 | ||
|  | ccdec7a7ab | ||
|  | 93642d813d | ||
|  | 1ab8d5cc13 | ||
|  | 789e892865 | ||
|  | 53cfa44d7a | ||
|  | 0bc381f982 | ||
|  | 2986aa76f8 | ||
|  | 657779374b | ||
|  | ec8cd11c1f | ||
|  | cbda4f66e0 | ||
|  | 6579dd30ff | ||
|  | 031c94e02e | ||
|  | 6391b2a1d0 | ||
|  | 2e50b55ae4 | ||
|  | c433939795 | ||
|  | b6a4c31b48 | ||
|  | 98b1439ff9 | ||
|  | 27936900e6 | ||
|  | 564738b1ff | ||
|  | cd3e810d25 | ||
|  | 317ddfedee | ||
|  | e325929851 | ||
|  | 47af3565f4 | ||
|  | 4b4d187935 | ||
|  | 9aff354ab5 | ||
|  | cb9ff20249 | ||
|  | a80e43dbcf | ||
|  | 9fe6ac71ea | ||
| 5c392a6ecc | |||
|  | f1fa00b71b | ||
|  | bf58557fb1 | ||
|  | 10cb37f504 | ||
|  | 1374c943d4 | ||
|  | a1d80282ec | ||
|  | 4eb8bbbebe | ||
|  | d1c6288c5f | ||
|  | dd949bc428 | ||
|  | bb7378cfc3 | ||
|  | f0e084a88c | ||
|  | 153672d8ec | ||
|  | 08ca338875 | ||
|  | f7cbf82c04 | ||
|  | 07009c569a | ||
|  | 15d690e9b9 | ||
| 63b2bc1936 | |||
|  | d810e8c8fb | ||
|  | 09f4cdb11e | ||
|  | 1e54882f71 | ||
|  | 27caff92c6 | ||
| d38cee73bf | |||
| 8784f2a88d | |||
| c497864b5d | |||
| 05c1c88440 | |||
|  | d54807b8c0 | ||
|  | f6ba2b95ce | ||
|  | 5625b47c7d | ||
|  | 1edcf902b7 | ||
|  | e5c19e1fd7 | ||
|  | a11d0a33d1 | ||
|  | 4f8b6f26b4 | ||
|  | 073525c5b3 | ||
|  | eb6153080a | ||
|  | f7072d1ac2 | ||
| a021933002 | |||
|  | b99622d9fb | ||
| 937c77ead2 | |||
| 95e5a2ade3 | |||
|  | 56478d63a5 | ||
| df21668f2c | |||
|  | 482368e9de | ||
|  | fddeb29d6b | ||
|  | a9ec5cf564 | ||
|  | 946a8671b9 | ||
|  | a6eeea777b | ||
|  | 771a1b8e79 | ||
|  | bfb68e6f02 | ||
|  | 77f7737ccc | ||
|  | 9a827d0242 | ||
|  | 999c623590 | ||
|  | 18c335198a | ||
|  | f9df685cde | ||
|  | 17c5b0f152 | ||
|  | 5918769f97 | ||
|  | b542d349b8 | ||
|  | 91eaace19d | ||
|  | bbaf1ada91 | ||
|  | 1950ac9294 | ||
|  | 13fa70ac1a | ||
|  | 7cb2b11f26 | ||
|  | 1184ed29ae | ||
|  | 203c7bf6fa | ||
|  | c709883f3f | ||
|  | aed5de4d50 | ||
|  | ba27cc6571 | ||
|  | d856327250 | ||
|  | d75369cb56 | ||
|  | bf973d0d56 | ||
|  | 837bf8a5be | ||
|  | c05b2199f6 | ||
|  | a5fe07c077 | ||
|  | b83b2b1415 | ||
|  | 91676d1dda | ||
|  | b331be9101 | ||
|  | 49c20a9fa8 | ||
|  | 7359df3501 | ||
|  | 59bd1fe21b | ||
| a56e3b40c4 | |||
|  | 4e907fef2c | ||
|  | 67888b657f | ||
|  | 74af885d4e | ||
|  | ac3611bb19 | ||
|  | d36d2fb40d | ||
|  | 5b9267e88d | ||
|  | 15fd4003ef | ||
|  | 4b4c2a715b | ||
|  | 54a5e6c1d0 | ||
|  | 73aeca7dea | ||
|  | ad89abb018 | ||
|  | 80c5bce5bb | ||
|  | f68b5de9c8 | ||
|  | d0f3d525d5 | ||
|  | f365a83fae | ||
|  | 3a58217405 | ||
|  | c289699d9a | ||
|  | c3b1263e75 | ||
|  | 34a9aeb331 | ||
| 5846566728 | |||
| 102ea9ae66 | |||
|  | cc4afb978d | ||
| 21b02760c3 | |||
|  | 2bcb704af2 | ||
|  | 5fa386ddc9 | ||
|  | edabb3577f | ||
|  | ce5df177ee | ||
|  | a0bb8e5b46 | ||
|  | 46f88e6d72 | ||
|  | dd8f1ea189 | ||
|  | b61835c1a5 | ||
|  | d9cd4f0273 | ||
|  | 459f70e8d4 | ||
|  | 061e48fd73 | ||
|  | ab50145001 | ||
|  | b49bec0cec | ||
|  | ae56e556c6 | ||
|  | 1cdf999668 | ||
|  | 11062fb686 | ||
|  | 383ca7d392 | ||
|  | a446d95c33 | ||
|  | be66e7dd95 | ||
|  | 6d0d064a6c | ||
|  | bfef525ed2 | ||
|  | 0b0cf62193 | ||
|  | 7d88198387 | ||
|  | 2f619482b8 | ||
|  | d6472eda8d | ||
|  | 9e658de238 | ||
|  | bcefdd7c4e | ||
|  | 9d45fca8bc | ||
|  | ac9e6b63c0 | ||
|  | e140b3f802 | ||
|  | d9d3d30cc7 | ||
|  | 47a12ec7b5 | ||
|  | ec1e2f7a40 | ||
|  | 41f73ec083 | ||
|  | fd367d8bfd | ||
|  | 6d0786ff9d | ||
|  | b7f93aeb4d | ||
|  | 202a7fe900 | ||
|  | 8d168ded4a | ||
|  | 8a3fe60a27 | ||
|  | 44051aecd1 | ||
|  | 06e6f8de00 | ||
|  | dbe4d7850c | ||
|  | 4fe182e5a7 | ||
|  | 75ee6cfc86 | ||
|  | fde71c3c52 | ||
|  | 175f393f9d | ||
|  | 7d867a8134 | ||
|  | 9939b267d2 | ||
|  | 323e9c439a | ||
|  | 28396f1048 | ||
|  | 67b34e5789 | ||
|  | 14d53e1c9e | ||
|  | 8bd869da37 | ||
|  | c7036f6717 | ||
|  | c0485d799d | ||
|  | 7abc5613bd | ||
|  | 237cfd11ab | ||
|  | a4b7dddb67 | ||
|  | 5696781862 | ||
|  | 8f4b3049cd | ||
|  | 2a6e673a91 | ||
|  | 9b6cde173f | ||
|  | 9f280b82c4 | ||
| c3f0889eda | |||
|  | 7a53dc3715 | ||
|  | 0f214ad427 | ||
|  | fe4912880d | ||
|  | 875e1a841f | ||
|  | 0366288b1c | ||
|  | 6293d438cd | ||
|  | 852ade029a | ||
|  | f038c6babe | ||
|  | 169f4b2711 | ||
|  | 2d8aff36fe | ||
|  | 9fa07eecde | ||
|  | 659d7d1a40 | ||
|  | f64fb7bd77 | ||
|  | 2a35449b91 | ||
|  | 184af5bd05 | ||
|  | 097c9637ee | ||
|  | dc6f078246 | ||
|  | 8a4714a4a6 | ||
|  | 40e119c61c | ||
|  | d9593c4b81 | ||
|  | ac740f73ce | ||
|  | 75dc7794b9 | ||
|  | dee68fc728 | ||
|  | a2d3643634 | ||
|  | 57002924bc | ||
|  | 7b0237b081 | ||
|  | b68ad0cc0b | ||
|  | 37263fd9b1 | ||
|  | 3d09e3e9e0 | ||
|  | 1354b46338 | ||
|  | 251a97fe1b | ||
|  | e18929eaa0 | ||
|  | f3b0a92e71 | ||
|  | a0be3f7330 | ||
|  | b5a6e4f1fd | ||
|  | 7a788db3dc | ||
|  | f20eceb6cd | ||
|  | 38325ebbc6 | ||
|  | b73bd151bb | ||
|  | 694b305cab | ||
|  | 2d3737a133 | ||
|  | ac1f1838bc | ||
|  | 09d09d0fe5 | ||
|  | bf630a6821 | ||
|  | 8859a151cc | ||
|  | 688a39cfd9 | ||
|  | 6f5a5cd9b3 | ||
|  | 0933aeefd4 | ||
|  | 322f61acee | ||
|  | 08e04b9676 | ||
| feaa2ac947 | |||
| 07de925127 | |||
|  | a9c816a268 | ||
|  | e43a8b6b8a | ||
|  | bf729766dd | ||
|  | dafb351d38 | ||
| 0b707b861c | |||
| 15e87a4607 | |||
| 7d7220cbd7 | |||
|  | 7d2d5e8d3d | ||
|  | 54e94360ad | ||
| 0af740dc15 | |||
| d2e8372df3 | |||
|  | 869b99ec1e | ||
|  | 4a29ab0d0a | ||
|  | 0165bcb58e | ||
|  | deca1ecc50 | ||
| 4372d04ad4 | |||
|  | 349d75e483 | ||
|  | 56abbdf4c2 | ||
|  | af71c63f4c | ||
|  | e51475703a | ||
|  | 1feddf4ba6 | ||
|  | 600d7ddc2e | ||
|  | e504260f3d | ||
|  | 0440d4ce66 | ||
|  | 08b0e472aa | ||
|  | c11d69787e | ||
|  | dc6b2d30d2 | ||
|  | 7a3bd5c66c | ||
|  | 18211eb5b1 | ||
|  | 863bb2ad10 | ||
|  | 5e4bea8f20 | ||
|  | 6ebf9f15b7 | ||
|  | 1d7aa673a4 | ||
|  | b9104f3072 | ||
| b22eab8c8b | |||
|  | a7d56523ab | ||
|  | 9e56c65730 | ||
|  | ef4f2b8c41 | ||
|  | e8b95bd35b | ||
|  | 7e35286860 | ||
|  | 0486ff8e79 | ||
| 1e8a2e1621 | |||
| 7587df831a | |||
|  | e9cc21900f | ||
|  | 0a8faac271 | ||
|  | abc4de0fd2 | ||
| b672717096 | |||
| 284ee194b1 | |||
|  | cfe3cd76d1 | ||
|  | 3fa5e3109f | ||
|  | 8b7049f737 | ||
|  | c85024683e | ||
|  | 1300b0b04b | ||
|  | e6d984b484 | ||
|  | 1d18d95d4f | ||
|  | ae39ec85a3 | ||
|  | b96daf53a0 | ||
|  | 46879e1658 | ||
|  | ae4de94798 | ||
|  | 0ab555b4f5 | ||
|  | 8e9be9f84f | ||
|  | d572170170 | ||
| 81b18f843a | |||
|  | 1bd311ba9c | ||
|  | 41af8c12d7 | ||
|  | a833f88c32 | ||
|  | 07b2c1b253 | ||
|  | 735cbdb983 | ||
|  | 2ad54c5a02 | ||
|  | 12ccc73cf5 | ||
|  | 3d04dc33c6 | ||
|  | e7564f8330 | ||
|  | 91199a8ea0 | ||
|  | 0494feec98 | ||
|  | a16b1e134e | ||
|  | 20e92a7009 | ||
|  | 5633a2db20 | ||
|  | 2d433ba307 | ||
|  | 769ad578f5 | ||
|  | eaac0044b5 | ||
|  | 56042f002c | ||
|  | 3bfd1f13e6 | ||
|  | 42f0afcbfa | ||
|  | 70ab598c96 | ||
|  | 1d0ca65e28 | ||
|  | 2bc4d0a20e | ||
|  | 20ac13fdf3 | ||
| 2490816297 | |||
| 5f55bca378 | |||
|  | e38612e6fa | ||
|  | c2b2b71c5d | ||
|  | 009f48a904 | ||
|  | b8e45ae490 | ||
|  | b35fc4e7f9 | ||
|  | 60f11bfd72 | ||
| f6aa82b7f2 | |||
| 22749699a3 | |||
|  | 8d442b502d | ||
|  | e5c8b7369e | ||
| 0503c028be | |||
|  | c504b4dbad | ||
|  | 622a21bec6 | ||
|  | eec79e0a1e | ||
|  | 092dcd4e04 | ||
|  | 4a8c4ccfba | ||
|  | 9b44189d5a | ||
|  | 7da4856e8e | ||
|  | aaf1e33a77 | ||
|  | 094c3d091a | ||
|  | 4b98e524a0 | ||
|  | 1a1f6d55f9 | ||
|  | 21421656ab | ||
|  | 6f687a67cd | ||
|  | b30754e762 | ||
|  | 1e429a0d57 | ||
|  | d38a4de36c | ||
|  | ef1b7db374 | ||
|  | 53a9aeb965 | ||
|  | e30fa9f4b8 | ||
|  | 58e8d0a10d | ||
|  | 62cf9cf638 | ||
|  | 0fb458879d | ||
|  | 725c513d94 | ||
| d8648307ff | |||
| 064315c00b | |||
|  | 7c6cc85df6 | ||
|  | a6691ef87c | ||
|  | 23135aa58a | ||
|  | 8e0ced627a | ||
|  | 0de314870d | ||
|  | ffb91e53d2 | ||
|  | f4e8bf2858 | ||
| a74c34315c | |||
|  | 69470ccc10 | ||
|  | b8b5934193 | ||
|  | 75856f2945 | ||
|  | 3c112a7a25 | ||
|  | ab3596d4d3 | ||
|  | a8c10b1933 | ||
|  | 15e801af3f | ||
|  | 0ffc235741 | ||
|  | 8e19c99c7d | ||
|  | a0bc0ad06f | ||
|  | a8fb2835ca | ||
|  | bc862ce3ab | ||
|  | 08b314fd0f | ||
| 22f4feee7b | |||
| 3f858d6755 | |||
|  | 3267683e22 | ||
|  | f46a67ffb3 | ||
|  | f7b8383ef5 | ||
|  | 10f2872aae | ||
|  | 34332fe393 | ||
|  | c2010f21ab | ||
|  | 98f610ce53 | ||
|  | d44cc204d1 | ||
| 35fa3d1dfd | |||
|  | cd73897b8d | ||
|  | c4435e6beb | ||
|  | 7a8f6af5f8 | ||
|  | 49a5d9bac7 | ||
|  | 2b3fdd4a58 | ||
|  | 34502ec471 | ||
|  | 8a43e88b4f | ||
| d1ece74137 | |||
|  | 238df20370 | ||
|  | 97a32a6145 | ||
|  | 655492a443 | ||
|  | 1cab06f6bd | ||
| 43c817cc67 | |||
|  | f8024c262b | ||
|  | 4cc5f01f4a | ||
|  | 5cfc0180aa | ||
|  | 914f180fa3 | ||
|  | 9c12c37aaf | ||
|  | 806eaa0530 | ||
|  | 01d0e54594 | ||
|  | 5aafa335fe | ||
|  | 8ba0494485 | ||
|  | d99d98d9fd | ||
|  | 95a017a4ae | ||
|  | 92f92379e6 | ||
|  | 529e78d43f | ||
|  | 4ec746d262 | ||
|  | 51bf1501fc | ||
|  | 66d819c054 | ||
|  | 3f3686f869 | ||
|  | 26bb829f8c | ||
|  | 67cb04fc66 | ||
|  | a40bd68aed | ||
|  | 36495e0fd2 | ||
|  | 93f6c15772 | ||
|  | cb93eeff21 | ||
|  | c7cc7e6101 | ||
|  | c349aa6511 | ||
|  | 3bae0a2d5c | ||
|  | c1c7566089 | ||
|  | 2439999ec8 | ||
|  | 1d96f662e3 | ||
|  | 41d1889941 | ||
|  | 0c3981e0c3 | ||
|  | c727bd4609 | ||
|  | db23749b67 | ||
|  | 751f2b9703 | ||
|  | 741bc836f6 | ||
|  | 6cb563a40c | ||
|  | 697c0603ce | ||
|  | 14bedebb11 | ||
|  | 8546d01a4c | ||
|  | 47b5c07ffb | ||
|  | da86a2bf54 | ||
|  | c1cb60a0b3 | ||
|  | 5ed5b4bfbf | ||
|  | de84aacdfd | ||
|  | 2888003765 | ||
|  | da06bf5b95 | ||
|  | 20999c1370 | ||
|  | 77e0af9c2e | ||
|  | 33f0ed1a33 | ||
|  | 50be56433b | ||
|  | 43924007db | ||
|  | 78ef10e60f | ||
|  | ca1077c560 | ||
| 679ae98b14 | |||
|  | 90f6bc16bb | ||
|  | 9b5b639546 | ||
|  | 945767c6d8 | ||
|  | 422cdf4979 | ||
|  | 38db174f3b | ||
|  | 92e364a35f | ||
|  | db3837be22 | ||
|  | 2f0dd83016 | ||
| 58299b8ba2 | |||
| 124bf4d829 | |||
| e8e56b3414 | |||
| 89c430136d | |||
| ea9aef7baa | |||
| c9e9e8061d | |||
|  | 453cf2a1c6 | ||
|  | de7bbfa5f9 | ||
| dda8d77c87 | |||
| aa29f4346a | |||
|  | 86116dbed6 | ||
|  | 7bd31e3f7c | ||
|  | 74f451715f | ||
|  | 655be8ed76 | ||
|  | 4063238943 | ||
|  | 3344788fa1 | ||
|  | 62a64d9108 | ||
|  | 49331a3e72 | ||
|  | 51d84ec057 | ||
|  | db14fb30df | ||
|  | b9356d3866 | ||
|  | 99a73f4287 | ||
|  | f302eea91e | ||
|  | 5553b8d2b8 | ||
|  | a6ccbbe108 | ||
|  | 3ac27e5596 | ||
|  | 99220f6531 | ||
|  | d2003f24f4 | ||
|  | 6299dd35f5 | ||
|  | a39daecb62 | ||
|  | 159770e21b | ||
|  | 2a6d093749 | ||
|  | c947947fad | ||
|  | f555b50547 | ||
|  | 738c1a11c2 | ||
|  | f8797e1e3e | ||
|  | fd1eb7de13 | ||
|  | 2ce898efa3 | ||
|  | dc5a6404ea | ||
|  | 44260643f6 | ||
|  | 1425afc72f | ||
|  | bd466a55a8 | ||
|  | ab66bac4e6 | ||
|  | 56277a11c8 | ||
|  | 752048f410 | ||
|  | 916e9e1d3e | ||
|  | 5b55867a7a | ||
|  | 3accb1ef89 | ||
|  | e3d0e31525 | ||
|  | 5812eb8a8c | ||
|  | 4dd3763294 | ||
|  | c429ace748 | ||
|  | ac58565d0a | ||
|  | 3703b718aa | ||
|  | b722889234 | ||
|  | abba44a837 | ||
|  | f301be94ce | ||
|  | 1d1b225497 | ||
|  | 53a785a3dd | ||
|  | 736bf3c866 | ||
|  | b9bbe5d188 | ||
|  | 3844bcf800 | ||
|  | e1a2319d01 | ||
|  | 180c732b4c | ||
|  | 957a706d0b | ||
|  | d2312e9874 | ||
|  | fc4ab9ccd5 | ||
|  | 4a340aa5ca | ||
|  | 3b7de792d5 | ||
|  | 557c3fa109 | ||
|  | ec18e9f7f6 | ||
|  | a839d5bc55 | ||
|  | de41b84c5c | ||
|  | 8e161152e4 | ||
|  | 3141ebac10 | ||
|  | 7ede696126 | ||
|  | bf516c3b81 | ||
|  | 441a52ee5d | ||
|  | a8db024c92 | ||
|  | a9c22d5f43 | ||
|  | 3ca41458a3 | ||
|  | 9e2d29c644 | ||
|  | b694996302 | ||
|  | 951be75292 | ||
|  | c8e6f58e24 | ||
|  | b9113ed310 | ||
|  | 888988ad37 | ||
| 1407418755 | |||
| a6a0da873f | |||
|  | 42fb49d3fd | ||
|  | 2a54c9aaab | ||
|  | 0957378679 | ||
|  | 2ed6c76fc5 | ||
|  | d3b9a7fa14 | ||
|  | 75ea306ce9 | ||
|  | 4226c633c4 | ||
|  | 5a4eafbf7e | ||
|  | eb8e26018b | ||
|  | db5ea001a3 | ||
|  | 2846f079e5 | ||
|  | 1d502e4ed6 | ||
|  | 73cdf0fffe | ||
|  | 1c25773319 | ||
|  | c38400b26f | ||
|  | 9c3065b860 | ||
|  | 94eb829d08 | ||
|  | 68392ddb5b | ||
|  | cb6b81ae82 | ||
|  | c382c351a5 | ||
|  | af2d6ce2e0 | ||
| 90ec6eda0c | |||
|  | ac1253bb76 | ||
| fe8d625694 | |||
| 53e76b41d2 | |||
| 8ef4300412 | |||
| 98a24ebf31 | |||
|  | e4a105a30b | ||
|  | 26ebe41fef | ||
|  | b12dc89d26 | ||
|  | d80d802f9d | ||
|  | 3d99b09dba | ||
|  | db5f6d3ae3 | ||
|  | 683550f116 | ||
|  | 5e477ec553 | ||
|  | 55d0329624 | ||
|  | 86aaa35294 | ||
|  | 363611ae21 | ||
|  | 172d3dc93a | ||
|  | 3b8a791e28 | ||
|  | 7b03d8d087 | ||
|  | 4b759b8f2a | ||
|  | 8c540333d5 | ||
|  | 6fd82228bf | ||
|  | ca6efc685e | ||
| 1e496fee74 | |||
| ff4e54ef80 | |||
|  | cd1bd921bd | ||
|  | b8ae787b5e | ||
|  | fbe2c3b5f9 | ||
|  | 1ed69816b9 | ||
|  | fff5751b1a | ||
|  | 2c81696fdd | ||
|  | c9dc22efa1 | ||
|  | 0ab04a000f | ||
|  | 9f755e0379 | ||
|  | 4512dbdf58 | ||
|  | 483fd3cfa1 | ||
|  | 3750b9ffee | ||
|  | 5e549ebd8b | ||
|  | fff484eca5 | ||
|  | 5fdc05782b | ||
|  | 85516e9c7c | ||
|  | 0c006fbfaa | ||
|  | 54c10a42cc | ||
|  | a04eb7df5d | ||
|  | 4c1ea8677e | ||
|  | ef0fe2bcc1 | ||
|  | 120fb59978 | ||
|  | fd56b3ff38 | ||
|  | 0ec6829edc | ||
|  | 18b7845b7b | ||
|  | 3d0fe15374 | ||
|  | 91886068fe | ||
|  | 6d1e9e5f92 | ||
|  | b640230b1e | ||
|  | 038b6ee9cd | ||
|  | 38806343a8 | ||
|  | 831ca4e3bf | ||
|  | b3dede4dd3 | ||
|  | 4e34132f4d | ||
|  | c07cb10247 | ||
|  | d7767a2a62 | ||
|  | ec035983fd | ||
|  | 596dcd85b2 | ||
|  | 7270c6a150 | ||
|  | f8b9ad7d50 | ||
|  | 04a1959895 | ||
|  | 93cc270016 | ||
|  | 29b60f7e1a | ||
|  | 902afcfbaf | ||
|  | 97a6b61551 | ||
|  | f011bdb869 | ||
|  | bafb101e4f | ||
|  | 08fdf05528 | ||
|  | 9e72a6b22e | ||
|  | 1c12c5612c | ||
|  | a8193c4bcb | ||
|  | c3d7ec65fa | ||
|  | 8b6a6c8236 | ||
|  | e0571c872b | ||
|  | c67f41887b | ||
|  | 84687ccf1f | ||
|  | 3274561cf8 | ||
| e08fbb3771 | |||
|  | d7464aa0fe | ||
|  | 00d29153f0 | ||
| 2ce989f220 | |||
|  | d7a1dc85be | ||
|  | fc19503673 | ||
|  | beba824136 | ||
|  | 6ebf8b12b6 | ||
|  | e5a7ed4362 | ||
|  | b9f7ea47c3 | ||
|  | 06f7ee202e | ||
|  | 2b2fc6453f | ||
|  | bdd2765461 | ||
|  | 4a45c06dd7 | ||
|  | d6a7d7d1e0 | ||
|  | 1a122a0dd8 | ||
|  | 20e20733e8 | ||
|  | b7cd1a19e3 | ||
|  | f510002a62 | ||
| eedcaf6470 | |||
|  | 1e257a1251 | ||
|  | 522f6bf91a | ||
|  | d35d87d2c2 | ||
|  | 74a5cda84b | ||
|  | 5be05d85b8 | ||
|  | 35ac85aea8 | ||
|  | fa237401ff | ||
|  | 97053adcb5 | ||
|  | f8fbe4d7a3 | ||
|  | ef31c012bf | ||
|  | 9e9f621d5d | ||
|  | 651e1a7cbc | ||
|  | c4d3672720 | ||
|  | 16be6d378c | ||
|  | f05d0565aa | ||
| b39f0d1fb6 | |||
| 9f1267dfe6 | |||
| 2e90285232 | |||
| e254de982e | |||
| 28d99b5297 | |||
|  | 9bf4108d1f | ||
|  | ee93f0218b | ||
|  | 6929a84c70 | ||
|  | 5c779a789b | ||
| 161ed102a5 | |||
|  | e863a948e3 | ||
|  | f65a585236 | ||
|  | 977f34dca6 | ||
|  | 90ad956340 | ||
|  | 7996f06335 | ||
|  | 7b40a3e3e5 | ||
|  | f7fbbaaca3 | ||
|  | 17629b8d9e | ||
|  | 0baa20d292 | ||
|  | 4571c918a4 | ||
|  | 5251ea4d30 | ||
|  | 7f456b4173 | ||
|  | ae99e99da2 | ||
|  | c291ef77b5 | ||
|  | 7dd2764bb2 | ||
|  | 244f8fb6dc | ||
| f3ca29af6c | |||
| 37988221a8 | |||
|  | 27dfe816fa | ||
|  | af29be2c90 | ||
|  | f96fac0aee | ||
| 7a327a3f28 | |||
|  | 07f2ebea1b | ||
|  | 851f2ad8ef | ||
|  | 23e0561dd6 | ||
|  | 8ae1a95ec6 | ||
|  | 82b7d4eaf0 | ||
|  | 78774fbdc0 | ||
|  | 924130833e | ||
|  | 0157274762 | ||
|  | 87e8aad5a0 | ||
|  | c6f59c2933 | ||
|  | b7f90aa011 | ||
| 92f8950a56 | |||
| 65987a8a58 | |||
| 889d828bc2 | |||
|  | f22b79da8f | ||
|  | 3855673ebf | ||
|  | 4db82da0db | ||
|  | 0cdc3d2fa5 | ||
| ad98b6193d | |||
| fc760016b3 | |||
| 2da86f7dae | |||
|  | 0dfda4bb90 | ||
|  | 1189ebc8b5 | ||
| 97843e2b58 | |||
| 82b3f54697 | |||
|  | 1bb8578173 | ||
| 673994b281 | |||
| bbc0eff078 | |||
| 4c60e31070 | |||
| afbf7d4c37 | |||
| 8c3cc32364 | |||
|  | 5214846341 | ||
| 4c3fd9fa3f | |||
| 17b3a10d46 | |||
| 149a46b92c | |||
|  | ce1a115e0b | ||
| db9c28a773 | |||
| 9ac3ac41df | |||
| 2af9ab9034 | |||
| 6f1ea96293 | |||
| 2e3c5890b6 | |||
| bc6678732f | |||
| b10ae00c8a | |||
|  | 0cd6b1858c | ||
|  | 0bd296dda4 | ||
|  | af0ccdd8e9 | ||
|  | 2fb92dbc6e | ||
|  | 5c74b6028b | ||
|  | e0be2b6e6c | ||
|  | ef72f322d2 | ||
|  | 7bc2065113 | ||
|  | 2bd4233919 | ||
|  | 143c70e29f | ||
|  | b812d5e39c | ||
|  | 01480da0a8 | ||
|  | 6ad73145bc | ||
| f7293f2ddb | |||
|  | 62749d05a6 | ||
|  | 3834feb4b7 | ||
|  | 6b8ee7bae0 | ||
|  | 739c2308b5 | ||
|  | 454302414d | ||
|  | a71b69389b | ||
|  | d49e502f53 | ||
|  | 92ec3404f8 | ||
|  | f4ebea3381 | ||
|  | cf167d0cd1 | ||
|  | 6f8b771a37 | ||
|  | 4e1ffdd17c | ||
|  | a783282b8b | ||
|  | 19b85d8486 | ||
|  | c363bdd784 | ||
|  | c30d96ea50 | ||
|  | 7ffe17ada1 | ||
| 330a9b3f4c | |||
|  | 28ff66a381 | ||
|  | 78c7bcee36 | ||
| 00a7b95631 | |||
| 94d8321d01 | |||
|  | ac24cc9f99 | ||
|  | 1d666771f9 | ||
|  | d50055cd96 | ||
|  | 3ab4c8c0bb | ||
|  | 47c7159177 | ||
|  | f415db583a | ||
|  | f55c16f984 | ||
|  | df67e013ca | ||
|  | 3e990c9d0a | ||
|  | 4b740fc8fd | ||
|  | cccd14b09e | ||
|  | e6acffdfc2 | ||
| 26d124283e | |||
| 0d889b7041 | |||
| ab31ad006a | |||
|  | 392130a537 | ||
|  | deef2673b2 | ||
|  | 977b0a6dd9 | ||
|  | 977d844394 | ||
| 6e4a06e180 | |||
|  | 590675e2ca | ||
|  | 8c65bdf6d3 | ||
|  | 74f1ed3bc5 | ||
|  | 79270ef510 | ||
|  | e250e6b7bb | ||
|  | 261342c15f | ||
|  | eda4dd622e | ||
|  | c68a2b9637 | ||
|  | 293df6cd20 | ||
|  | 65f61bb3bf | ||
|  | 26b9740d53 | ||
|  | 6eb873dd96 | ||
|  | 11b4c80b27 | ||
|  | c065e454c3 | ||
|  | d9b5fbd374 | ||
|  | cfbc1a26b8 | ||
|  | 257f69f931 | ||
|  | e415260961 | ||
|  | 446c768cd3 | 
							
								
								
									
										24
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										24
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -83,6 +83,7 @@ ltmain.sh | |||||||
| .Trashes | .Trashes | ||||||
| ehthumbs.db | ehthumbs.db | ||||||
| Thumbs.db | Thumbs.db | ||||||
|  | .dirstamp | ||||||
|  |  | ||||||
| # build directory # | # build directory # | ||||||
| ################### | ################### | ||||||
| @@ -92,28 +93,25 @@ build*/* | |||||||
| ##################### | ##################### | ||||||
| *.xcodeproj/* | *.xcodeproj/* | ||||||
| build.sh | build.sh | ||||||
|  | .vscode | ||||||
|  | *.code-workspace | ||||||
|  |  | ||||||
| # Eigen source # | # Eigen source # | ||||||
| ################ | ################ | ||||||
| lib/Eigen/* | Grid/Eigen | ||||||
|  | Eigen/* | ||||||
| # FFTW source # |  | ||||||
| ################ |  | ||||||
| lib/fftw/* |  | ||||||
|  |  | ||||||
| # libtool macros # | # libtool macros # | ||||||
| ################## | ################## | ||||||
| m4/lt* | m4/lt* | ||||||
| m4/libtool.m4 | m4/libtool.m4 | ||||||
|  |  | ||||||
| # Buck files # | # github pages # | ||||||
| ############## | ################ | ||||||
| .buck* | gh-pages/ | ||||||
| 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 | ||||||
|  | Grid/util/Version.h | ||||||
|   | |||||||
							
								
								
									
										99
									
								
								.travis.yml
									
									
									
									
									
								
							
							
						
						
									
										99
									
								
								.travis.yml
									
									
									
									
									
								
							| @@ -7,64 +7,13 @@ cache: | |||||||
| matrix: | matrix: | ||||||
|   include: |   include: | ||||||
|     - os:        osx |     - os:        osx | ||||||
|       osx_image: xcode7.2 |       osx_image: xcode8.3 | ||||||
|       compiler: clang |       compiler: clang | ||||||
|     - compiler: gcc |       env: PREC=single | ||||||
|       addons: |     - os:        osx | ||||||
|         apt: |       osx_image: xcode8.3 | ||||||
|           sources: |       compiler: clang | ||||||
|             - ubuntu-toolchain-r-test |       env: PREC=double | ||||||
|           packages: |  | ||||||
|             - g++-4.9 |  | ||||||
|             - libmpfr-dev |  | ||||||
|             - libgmp-dev |  | ||||||
|             - libmpc-dev |  | ||||||
|             - libopenmpi-dev |  | ||||||
|             - openmpi-bin |  | ||||||
|             - binutils-dev |  | ||||||
|       env: VERSION=-4.9 |  | ||||||
|     - compiler: gcc |  | ||||||
|       addons: |  | ||||||
|         apt: |  | ||||||
|           sources: |  | ||||||
|             - ubuntu-toolchain-r-test |  | ||||||
|           packages: |  | ||||||
|             - g++-5 |  | ||||||
|             - libmpfr-dev |  | ||||||
|             - libgmp-dev |  | ||||||
|             - libmpc-dev |  | ||||||
|             - libopenmpi-dev |  | ||||||
|             - openmpi-bin |  | ||||||
|             - binutils-dev |  | ||||||
|       env: VERSION=-5 |  | ||||||
|     - compiler: clang |  | ||||||
|       addons: |  | ||||||
|         apt: |  | ||||||
|           sources: |  | ||||||
|             - ubuntu-toolchain-r-test |  | ||||||
|           packages: |  | ||||||
|             - g++-4.8 |  | ||||||
|             - libmpfr-dev |  | ||||||
|             - libgmp-dev |  | ||||||
|             - libmpc-dev |  | ||||||
|             - libopenmpi-dev |  | ||||||
|             - openmpi-bin |  | ||||||
|             - binutils-dev |  | ||||||
|       env: CLANG_LINK=http://llvm.org/releases/3.8.0/clang+llvm-3.8.0-x86_64-linux-gnu-ubuntu-14.04.tar.xz |  | ||||||
|     - compiler: clang |  | ||||||
|       addons: |  | ||||||
|         apt: |  | ||||||
|           sources: |  | ||||||
|             - ubuntu-toolchain-r-test |  | ||||||
|           packages: |  | ||||||
|             - g++-4.8 |  | ||||||
|             - libmpfr-dev |  | ||||||
|             - libgmp-dev |  | ||||||
|             - libmpc-dev |  | ||||||
|             - libopenmpi-dev |  | ||||||
|             - openmpi-bin |  | ||||||
|             - binutils-dev |  | ||||||
|       env: CLANG_LINK=http://llvm.org/releases/3.7.0/clang+llvm-3.7.0-x86_64-linux-gnu-ubuntu-14.04.tar.xz |  | ||||||
|        |        | ||||||
| before_install: | before_install: | ||||||
|     - export GRIDDIR=`pwd` |     - export GRIDDIR=`pwd` | ||||||
| @@ -72,35 +21,41 @@ 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 | ||||||
|     - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install openmpi; fi |  | ||||||
|     - if [[ "$TRAVIS_OS_NAME" == "osx" ]] && [[ "$CC" == "gcc" ]]; then brew install gcc5; 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 | ||||||
|  |     - which autoconf | ||||||
|  |     - autoconf  --version | ||||||
|  |     - which automake | ||||||
|  |     - automake  --version | ||||||
|     - which $CC |     - which $CC | ||||||
|     - $CC  --version |     - $CC  --version | ||||||
|     - 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 |     - 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 |     - ./benchmarks/Benchmark_dwf --threads 1 --debug-signals | ||||||
|     - echo make clean |     - make check | ||||||
|     - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then export CXXFLAGS='-DMPI_UINT32_T=MPI_UNSIGNED -DMPI_UINT64_T=MPI_UNSIGNED_LONG'; fi |  | ||||||
|     - ../configure --enable-precision=single --enable-simd=SSE4 --enable-comms=mpi-auto |  | ||||||
|     - make -j4 |  | ||||||
|     - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then mpirun.openmpi -n 2 ./benchmarks/Benchmark_dwf --threads 1 --mpi 2.1.1.1; fi |  | ||||||
|  |  | ||||||
|  |  | ||||||
|   | |||||||
| @@ -0,0 +1,5 @@ | |||||||
|  | Version : 0.8.0 | ||||||
|  |  | ||||||
|  | - Clang 3.5 and above, ICPC v16 and above, GCC 6.3 and above recommended | ||||||
|  | - MPI and MPI3 comms optimisations for KNL and OPA finished | ||||||
|  | - Half precision comms | ||||||
|   | |||||||
							
								
								
									
										63
									
								
								Grid/DisableWarnings.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								Grid/DisableWarnings.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,63 @@ | |||||||
|  | /************************************************************************************* | ||||||
|  |  | ||||||
|  | Grid physics library, www.github.com/paboyle/Grid | ||||||
|  |  | ||||||
|  | Source file: ./lib/DisableWarnings.h | ||||||
|  |  | ||||||
|  | Copyright (C) 2016 | ||||||
|  |  | ||||||
|  | Author: Guido Cossu <guido.cossu@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 DISABLE_WARNINGS_H | ||||||
|  | #define DISABLE_WARNINGS_H | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | #if defined __GNUC__ && __GNUC__>=6 | ||||||
|  | #pragma GCC diagnostic ignored "-Wignored-attributes" | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  |  //disables and intel compiler specific warning (in json.hpp) | ||||||
|  | #pragma warning disable 488   | ||||||
|  |  | ||||||
|  | #ifdef __NVCC__ | ||||||
|  |  //disables nvcc specific warning in json.hpp | ||||||
|  | #pragma clang diagnostic ignored "-Wdeprecated-register" | ||||||
|  | #pragma diag_suppress unsigned_compare_with_zero | ||||||
|  | #pragma diag_suppress cast_to_qualified_type | ||||||
|  |  | ||||||
|  |  //disables nvcc specific warning in many files | ||||||
|  | #pragma diag_suppress esa_on_defaulted_function_ignored | ||||||
|  | #pragma diag_suppress extra_semicolon | ||||||
|  |  | ||||||
|  | //Eigen only | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | // Disable vectorisation in Eigen on the Power8/9 and PowerPC | ||||||
|  | #ifdef  __ALTIVEC__ | ||||||
|  | #define  EIGEN_DONT_VECTORIZE | ||||||
|  | #endif | ||||||
|  | #ifdef  __VSX__ | ||||||
|  | #define  EIGEN_DONT_VECTORIZE | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #endif | ||||||
| @@ -41,7 +41,10 @@ Author: paboyle <paboyle@ph.ed.ac.uk> | |||||||
| #include <Grid/GridCore.h> | #include <Grid/GridCore.h> | ||||||
| #include <Grid/GridQCDcore.h> | #include <Grid/GridQCDcore.h> | ||||||
| #include <Grid/qcd/action/Action.h> | #include <Grid/qcd/action/Action.h> | ||||||
|  | #include <Grid/qcd/utils/GaugeFix.h> | ||||||
|  | #include <Grid/qcd/utils/CovariantSmearing.h> | ||||||
| #include <Grid/qcd/smearing/Smearing.h> | #include <Grid/qcd/smearing/Smearing.h> | ||||||
|  | #include <Grid/parallelIO/MetaData.h> | ||||||
| #include <Grid/qcd/hmc/HMC_aggregate.h> | #include <Grid/qcd/hmc/HMC_aggregate.h> | ||||||
| 
 | 
 | ||||||
| #endif | #endif | ||||||
| @@ -38,37 +38,20 @@ Author: paboyle <paboyle@ph.ed.ac.uk> | |||||||
| #ifndef GRID_BASE_H | #ifndef GRID_BASE_H | ||||||
| #define GRID_BASE_H | #define GRID_BASE_H | ||||||
| 
 | 
 | ||||||
| ///////////////////
 |  | ||||||
| // Std C++ dependencies
 |  | ||||||
| ///////////////////
 |  | ||||||
| #include <cassert> |  | ||||||
| #include <complex> |  | ||||||
| #include <vector> |  | ||||||
| #include <iostream> |  | ||||||
| #include <iomanip> |  | ||||||
| #include <random> |  | ||||||
| #include <functional> |  | ||||||
| #include <stdio.h> |  | ||||||
| #include <stdlib.h> |  | ||||||
| #include <stdio.h> |  | ||||||
| #include <signal.h> |  | ||||||
| #include <ctime> |  | ||||||
| #include <sys/time.h> |  | ||||||
| #include <chrono> |  | ||||||
| 
 |  | ||||||
| ///////////////////
 |  | ||||||
| // Grid headers
 |  | ||||||
| ///////////////////
 |  | ||||||
| #include "Config.h" |  | ||||||
| 
 | 
 | ||||||
|  | #include <Grid/DisableWarnings.h> | ||||||
|  | #include <Grid/Namespace.h> | ||||||
|  | #include <Grid/GridStd.h> | ||||||
|  | #include <Grid/threads/Pragmas.h> | ||||||
| #include <Grid/perfmon/Timer.h> | #include <Grid/perfmon/Timer.h> | ||||||
| #include <Grid/perfmon/PerfCount.h> | #include <Grid/perfmon/PerfCount.h> | ||||||
|  | #include <Grid/util/Util.h> | ||||||
| #include <Grid/log/Log.h> | #include <Grid/log/Log.h> | ||||||
| #include <Grid/allocator/AlignedAllocator.h> | #include <Grid/allocator/AlignedAllocator.h> | ||||||
| #include <Grid/simd/Simd.h> | #include <Grid/simd/Simd.h> | ||||||
| #include <Grid/serialisation/Serialisation.h> |  | ||||||
| #include <Grid/threads/Threads.h> | #include <Grid/threads/Threads.h> | ||||||
| #include <Grid/util/Util.h> | #include <Grid/serialisation/Serialisation.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>       | ||||||
| @@ -77,5 +60,6 @@ Author: paboyle <paboyle@ph.ed.ac.uk> | |||||||
| #include <Grid/stencil/Stencil.h>       | #include <Grid/stencil/Stencil.h>       | ||||||
| #include <Grid/parallelIO/BinaryIO.h> | #include <Grid/parallelIO/BinaryIO.h> | ||||||
| #include <Grid/algorithms/Algorithms.h>    | #include <Grid/algorithms/Algorithms.h>    | ||||||
|  | NAMESPACE_CHECK(GridCore) | ||||||
| 
 | 
 | ||||||
| #endif | #endif | ||||||
| @@ -38,5 +38,6 @@ Author: paboyle <paboyle@ph.ed.ac.uk> | |||||||
| #include <Grid/qcd/spin/Spin.h> | #include <Grid/qcd/spin/Spin.h> | ||||||
| #include <Grid/qcd/utils/Utils.h> | #include <Grid/qcd/utils/Utils.h> | ||||||
| #include <Grid/qcd/representations/Representations.h> | #include <Grid/qcd/representations/Representations.h> | ||||||
|  | NAMESPACE_CHECK(GridQCDCore); | ||||||
| 
 | 
 | ||||||
| #endif | #endif | ||||||
							
								
								
									
										30
									
								
								Grid/GridStd.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								Grid/GridStd.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,30 @@ | |||||||
|  | #ifndef GRID_STD_H | ||||||
|  | #define GRID_STD_H | ||||||
|  |  | ||||||
|  | /////////////////// | ||||||
|  | // Std C++ dependencies | ||||||
|  | /////////////////// | ||||||
|  | #include <cassert> | ||||||
|  | #include <complex> | ||||||
|  | #include <vector> | ||||||
|  | #include <array> | ||||||
|  | #include <string> | ||||||
|  | #include <iostream> | ||||||
|  | #include <iomanip> | ||||||
|  | #include <random> | ||||||
|  | #include <functional> | ||||||
|  | #include <stdio.h> | ||||||
|  | #include <stdlib.h> | ||||||
|  | #include <stdio.h> | ||||||
|  | #include <signal.h> | ||||||
|  | #include <ctime> | ||||||
|  | #include <sys/time.h> | ||||||
|  | #include <chrono> | ||||||
|  | #include <zlib.h> | ||||||
|  |  | ||||||
|  | /////////////////// | ||||||
|  | // Grid config | ||||||
|  | /////////////////// | ||||||
|  | #include "Config.h" | ||||||
|  |  | ||||||
|  | #endif /* GRID_STD_H */ | ||||||
							
								
								
									
										41
									
								
								Grid/Grid_Eigen_Dense.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								Grid/Grid_Eigen_Dense.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,41 @@ | |||||||
|  | #include <Grid/GridCore.h> | ||||||
|  | #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__ | ||||||
|  | #pragma GCC diagnostic push | ||||||
|  | #pragma GCC diagnostic ignored "-Wdeprecated-declarations" | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | /* NVCC save and restore compile environment*/ | ||||||
|  | #ifdef __NVCC__ | ||||||
|  | #pragma push | ||||||
|  | #pragma diag_suppress code_is_unreachable | ||||||
|  | #pragma push_macro("__CUDA_ARCH__") | ||||||
|  | #pragma push_macro("__NVCC__") | ||||||
|  | #pragma push_macro("__CUDACC__") | ||||||
|  | #undef __NVCC__ | ||||||
|  | #undef __CUDACC__ | ||||||
|  | #undef __CUDA_ARCH__ | ||||||
|  | #define __NVCC__REDEFINE__ | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #include <Grid/Eigen/Dense> | ||||||
|  | #include <Grid/Eigen/unsupported/CXX11/Tensor> | ||||||
|  |  | ||||||
|  | /* NVCC restore */ | ||||||
|  | #ifdef __NVCC__REDEFINE__ | ||||||
|  | #pragma pop_macro("__CUDACC__") | ||||||
|  | #pragma pop_macro("__NVCC__") | ||||||
|  | #pragma pop_macro("__CUDA_ARCH__") | ||||||
|  | #pragma pop | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #if defined __GNUC__ | ||||||
|  | #pragma GCC diagnostic pop | ||||||
|  | #endif | ||||||
|  |  | ||||||
							
								
								
									
										1
									
								
								Grid/Grid_Eigen_Tensor.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								Grid/Grid_Eigen_Tensor.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | |||||||
|  | #include <Grid/Grid_Eigen_Dense.h> | ||||||
							
								
								
									
										63
									
								
								Grid/Makefile.am
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								Grid/Makefile.am
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,63 @@ | |||||||
|  | extra_sources= | ||||||
|  | extra_headers= | ||||||
|  |  | ||||||
|  | if BUILD_COMMS_MPI3 | ||||||
|  |   extra_sources+=communicator/Communicator_mpi3.cc | ||||||
|  |   extra_sources+=communicator/Communicator_base.cc | ||||||
|  |   extra_sources+=communicator/SharedMemoryMPI.cc | ||||||
|  |   extra_sources+=communicator/SharedMemory.cc | ||||||
|  | endif | ||||||
|  |  | ||||||
|  | if BUILD_COMMS_NONE | ||||||
|  |   extra_sources+=communicator/Communicator_none.cc | ||||||
|  |   extra_sources+=communicator/Communicator_base.cc | ||||||
|  |   extra_sources+=communicator/SharedMemoryNone.cc | ||||||
|  |   extra_sources+=communicator/SharedMemory.cc | ||||||
|  | endif | ||||||
|  |  | ||||||
|  | if BUILD_HDF5 | ||||||
|  |   extra_sources+=serialisation/Hdf5IO.cc  | ||||||
|  |   extra_headers+=serialisation/Hdf5IO.h | ||||||
|  |   extra_headers+=serialisation/Hdf5Type.h | ||||||
|  | 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 | ||||||
|  | # | ||||||
|  | include Make.inc | ||||||
|  | include Eigen.inc | ||||||
|  |  | ||||||
|  | lib_LIBRARIES = libGrid.a | ||||||
|  |  | ||||||
|  | CCFILES += $(extra_sources) | ||||||
|  | HFILES  += $(extra_headers) Config.h Version.h | ||||||
|  |  | ||||||
|  | libGrid_a_SOURCES              = $(CCFILES) | ||||||
|  | libGrid_adir                   = $(includedir)/Grid | ||||||
|  | nobase_dist_pkginclude_HEADERS = $(HFILES) $(eigen_files) $(eigen_unsupp_files) | ||||||
							
								
								
									
										38
									
								
								Grid/Namespace.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								Grid/Namespace.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,38 @@ | |||||||
|  | /************************************************************************************* | ||||||
|  |  | ||||||
|  | Grid physics library, www.github.com/paboyle/Grid | ||||||
|  |  | ||||||
|  | Source file: ./lib/Namespace.h | ||||||
|  |  | ||||||
|  | Copyright (C) 2016 | ||||||
|  |  | ||||||
|  | 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 */ | ||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #include <type_traits> | ||||||
|  | #include <cassert> | ||||||
|  |  | ||||||
|  | #define NAMESPACE_BEGIN(A) namespace A { | ||||||
|  | #define NAMESPACE_END(A)   } | ||||||
|  | #define GRID_NAMESPACE_BEGIN NAMESPACE_BEGIN(Grid) | ||||||
|  | #define GRID_NAMESPACE_END   NAMESPACE_END(Grid) | ||||||
|  | #define NAMESPACE_CHECK(x) struct namespaceTEST##x {};  static_assert(std::is_same<namespaceTEST##x, ::namespaceTEST##x>::value,"Not in :: at"  );  | ||||||
| @@ -37,37 +37,27 @@ Author: Peter Boyle <paboyle@ph.ed.ac.uk> | |||||||
| #include <Grid/algorithms/approx/Chebyshev.h> | #include <Grid/algorithms/approx/Chebyshev.h> | ||||||
| #include <Grid/algorithms/approx/Remez.h> | #include <Grid/algorithms/approx/Remez.h> | ||||||
| #include <Grid/algorithms/approx/MultiShiftFunction.h> | #include <Grid/algorithms/approx/MultiShiftFunction.h> | ||||||
|  | #include <Grid/algorithms/approx/Forecast.h> | ||||||
| 
 | 
 | ||||||
|  | #include <Grid/algorithms/iterative/Deflation.h> | ||||||
| #include <Grid/algorithms/iterative/ConjugateGradient.h> | #include <Grid/algorithms/iterative/ConjugateGradient.h> | ||||||
| #include <Grid/algorithms/iterative/ConjugateResidual.h> | #include <Grid/algorithms/iterative/ConjugateResidual.h> | ||||||
| #include <Grid/algorithms/iterative/NormalEquations.h> | #include <Grid/algorithms/iterative/NormalEquations.h> | ||||||
| #include <Grid/algorithms/iterative/SchurRedBlack.h> | #include <Grid/algorithms/iterative/SchurRedBlack.h> | ||||||
| #include <Grid/algorithms/iterative/ConjugateGradientMultiShift.h> | #include <Grid/algorithms/iterative/ConjugateGradientMultiShift.h> | ||||||
| #include <Grid/algorithms/iterative/ConjugateGradientMixedPrec.h> | #include <Grid/algorithms/iterative/ConjugateGradientMixedPrec.h> | ||||||
| 
 | #include <Grid/algorithms/iterative/BlockConjugateGradient.h> | ||||||
| // Lanczos support
 | #include <Grid/algorithms/iterative/ConjugateGradientReliableUpdate.h> | ||||||
| #include <Grid/algorithms/iterative/MatrixUtils.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/iterative/PowerMethod.h> | ||||||
|  | 
 | ||||||
| #include <Grid/algorithms/CoarsenedMatrix.h> | #include <Grid/algorithms/CoarsenedMatrix.h> | ||||||
| #include <Grid/algorithms/FFT.h> | #include <Grid/algorithms/FFT.h> | ||||||
| 
 | 
 | ||||||
| // Eigen/lanczos
 |  | ||||||
| // EigCg
 |  | ||||||
| // MCR
 |  | ||||||
| // Pcg
 |  | ||||||
| // Multishift CG
 |  | ||||||
| // Hdcg
 |  | ||||||
| // GCR
 |  | ||||||
| // etc..
 |  | ||||||
| 
 |  | ||||||
| // integrator/Leapfrog
 |  | ||||||
| // integrator/Omelyan
 |  | ||||||
| // integrator/ForceGradient
 |  | ||||||
| 
 |  | ||||||
| // montecarlo/hmc
 |  | ||||||
| // montecarlo/rhmc
 |  | ||||||
| // montecarlo/metropolis
 |  | ||||||
| // etc...
 |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| #endif | #endif | ||||||
							
								
								
									
										512
									
								
								Grid/algorithms/CoarsenedMatrix.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										512
									
								
								Grid/algorithms/CoarsenedMatrix.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,512 @@ | |||||||
|  | /************************************************************************************* | ||||||
|  |  | ||||||
|  |     Grid physics library, www.github.com/paboyle/Grid  | ||||||
|  |  | ||||||
|  |     Source file: ./lib/algorithms/CoarsenedMatrix.h | ||||||
|  |  | ||||||
|  |     Copyright (C) 2015 | ||||||
|  |  | ||||||
|  | Author: Azusa Yamaguchi <ayamaguc@staffmail.ed.ac.uk> | ||||||
|  | Author: Peter Boyle <paboyle@ph.ed.ac.uk> | ||||||
|  | Author: Peter Boyle <peterboyle@Peters-MacBook-Pro-2.local> | ||||||
|  | Author: paboyle <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_ALGORITHM_COARSENED_MATRIX_H | ||||||
|  | #define  GRID_ALGORITHM_COARSENED_MATRIX_H | ||||||
|  |  | ||||||
|  |  | ||||||
|  | NAMESPACE_BEGIN(Grid); | ||||||
|  |  | ||||||
|  | class Geometry { | ||||||
|  |   //    int dimension; | ||||||
|  | public: | ||||||
|  |   int npoint; | ||||||
|  |   std::vector<int> directions   ; | ||||||
|  |   std::vector<int> displacements; | ||||||
|  |  | ||||||
|  |   Geometry(int _d)  { | ||||||
|  |    | ||||||
|  |     int base = (_d==5) ? 1:0; | ||||||
|  |  | ||||||
|  |     // make coarse grid stencil for 4d , not 5d | ||||||
|  |     if ( _d==5 ) _d=4; | ||||||
|  |  | ||||||
|  |     npoint = 2*_d+1; | ||||||
|  |     directions.resize(npoint); | ||||||
|  |     displacements.resize(npoint); | ||||||
|  |     for(int d=0;d<_d;d++){ | ||||||
|  |       directions[2*d  ] = d+base; | ||||||
|  |       directions[2*d+1] = d+base; | ||||||
|  |       displacements[2*d  ] = +1; | ||||||
|  |       displacements[2*d+1] = -1; | ||||||
|  |     } | ||||||
|  |     directions   [2*_d]=0; | ||||||
|  |     displacements[2*_d]=0; | ||||||
|  |        | ||||||
|  |     //// report back | ||||||
|  |     std::cout<<GridLogMessage<<"directions    :"; | ||||||
|  |     for(int d=0;d<npoint;d++) std::cout<< directions[d]<< " "; | ||||||
|  |     std::cout <<std::endl; | ||||||
|  |     std::cout<<GridLogMessage<<"displacements :"; | ||||||
|  |     for(int d=0;d<npoint;d++) std::cout<< displacements[d]<< " "; | ||||||
|  |     std::cout<<std::endl; | ||||||
|  |   } | ||||||
|  |    | ||||||
|  |   /* | ||||||
|  |   // Original cleaner code | ||||||
|  |   Geometry(int _d) : dimension(_d), npoint(2*_d+1), directions(npoint), displacements(npoint) { | ||||||
|  |   for(int d=0;d<dimension;d++){ | ||||||
|  |   directions[2*d  ] = d; | ||||||
|  |   directions[2*d+1] = d; | ||||||
|  |   displacements[2*d  ] = +1; | ||||||
|  |   displacements[2*d+1] = -1; | ||||||
|  |   } | ||||||
|  |   directions   [2*dimension]=0; | ||||||
|  |   displacements[2*dimension]=0; | ||||||
|  |   } | ||||||
|  |   std::vector<int> GetDelta(int point) { | ||||||
|  |   std::vector<int> delta(dimension,0); | ||||||
|  |   delta[directions[point]] = displacements[point]; | ||||||
|  |   return delta; | ||||||
|  |   }; | ||||||
|  |   */     | ||||||
|  |  | ||||||
|  | }; | ||||||
|  |    | ||||||
|  | template<class Fobj,class CComplex,int nbasis> | ||||||
|  | class Aggregation   { | ||||||
|  | public: | ||||||
|  |   typedef iVector<CComplex,nbasis >             siteVector; | ||||||
|  |   typedef Lattice<siteVector>                 CoarseVector; | ||||||
|  |   typedef Lattice<iMatrix<CComplex,nbasis > > CoarseMatrix; | ||||||
|  |  | ||||||
|  |   typedef Lattice< CComplex >   CoarseScalar; // used for inner products on fine field | ||||||
|  |   typedef Lattice<Fobj >        FineField; | ||||||
|  |  | ||||||
|  |   GridBase *CoarseGrid; | ||||||
|  |   GridBase *FineGrid; | ||||||
|  |   std::vector<Lattice<Fobj> > subspace; | ||||||
|  |   int checkerboard; | ||||||
|  |   int Checkerboard(void){return checkerboard;} | ||||||
|  |   Aggregation(GridBase *_CoarseGrid,GridBase *_FineGrid,int _checkerboard) :  | ||||||
|  |     CoarseGrid(_CoarseGrid), | ||||||
|  |     FineGrid(_FineGrid), | ||||||
|  |     subspace(nbasis,_FineGrid), | ||||||
|  |     checkerboard(_checkerboard) | ||||||
|  |   { | ||||||
|  |   }; | ||||||
|  |    | ||||||
|  |   void Orthogonalise(void){ | ||||||
|  |     CoarseScalar InnerProd(CoarseGrid);  | ||||||
|  |     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 checking orthogonality"<<std::endl; | ||||||
|  |     //      CheckOrthogonal(); | ||||||
|  |   }  | ||||||
|  |   void CheckOrthogonal(void){ | ||||||
|  |     CoarseVector iProj(CoarseGrid);  | ||||||
|  |     CoarseVector eProj(CoarseGrid);  | ||||||
|  |     for(int i=0;i<nbasis;i++){ | ||||||
|  |       blockProject(iProj,subspace[i],subspace); | ||||||
|  |       eProj=Zero();  | ||||||
|  |       thread_for(ss, CoarseGrid->oSites(),{ | ||||||
|  | 	eProj[ss](i)=CComplex(1.0); | ||||||
|  |       }); | ||||||
|  |       eProj=eProj - iProj; | ||||||
|  |       std::cout<<GridLogMessage<<"Orthog check error "<<i<<" " << norm2(eProj)<<std::endl; | ||||||
|  |     } | ||||||
|  |     std::cout<<GridLogMessage <<"CheckOrthog done"<<std::endl; | ||||||
|  |   } | ||||||
|  |   void ProjectToSubspace(CoarseVector &CoarseVec,const FineField &FineVec){ | ||||||
|  |     blockProject(CoarseVec,FineVec,subspace); | ||||||
|  |   } | ||||||
|  |   void PromoteFromSubspace(const CoarseVector &CoarseVec,FineField &FineVec){ | ||||||
|  |     FineVec.Checkerboard() = subspace[0].Checkerboard(); | ||||||
|  |     blockPromote(CoarseVec,FineVec,subspace); | ||||||
|  |   } | ||||||
|  |   void CreateSubspaceRandom(GridParallelRNG &RNG){ | ||||||
|  |     for(int i=0;i<nbasis;i++){ | ||||||
|  |       random(RNG,subspace[i]); | ||||||
|  |       std::cout<<GridLogMessage<<" norm subspace["<<i<<"] "<<norm2(subspace[i])<<std::endl; | ||||||
|  |     } | ||||||
|  |     Orthogonalise(); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   /* | ||||||
|  |     virtual void CreateSubspaceLanczos(GridParallelRNG  &RNG,LinearOperatorBase<FineField> &hermop,int nn=nbasis)  | ||||||
|  |     { | ||||||
|  |     // Run a Lanczos with sloppy convergence | ||||||
|  |     const int Nstop = nn; | ||||||
|  |     const int Nk = nn+20; | ||||||
|  |     const int Np = nn+20; | ||||||
|  |     const int Nm = Nk+Np; | ||||||
|  |     const int MaxIt= 10000; | ||||||
|  |     RealD resid = 1.0e-3; | ||||||
|  |  | ||||||
|  |     Chebyshev<FineField> Cheb(0.5,64.0,21); | ||||||
|  |     ImplicitlyRestartedLanczos<FineField> IRL(hermop,Cheb,Nstop,Nk,Nm,resid,MaxIt); | ||||||
|  |     //	IRL.lock = 1; | ||||||
|  |  | ||||||
|  |     FineField noise(FineGrid); gaussian(RNG,noise); | ||||||
|  |     FineField tmp(FineGrid);  | ||||||
|  |     std::vector<RealD>     eval(Nm); | ||||||
|  |     std::vector<FineField> evec(Nm,FineGrid); | ||||||
|  |  | ||||||
|  |     int Nconv; | ||||||
|  |     IRL.calc(eval,evec, | ||||||
|  |     noise, | ||||||
|  |     Nconv); | ||||||
|  |  | ||||||
|  |     // pull back nn vectors | ||||||
|  |     for(int b=0;b<nn;b++){ | ||||||
|  |  | ||||||
|  |     subspace[b]   = evec[b]; | ||||||
|  |  | ||||||
|  |     std::cout << GridLogMessage <<"subspace["<<b<<"] = "<<norm2(subspace[b])<<std::endl; | ||||||
|  |  | ||||||
|  |     hermop.Op(subspace[b],tmp);  | ||||||
|  |     std::cout<<GridLogMessage << "filtered["<<b<<"] <f|MdagM|f> "<<norm2(tmp)<<std::endl; | ||||||
|  |  | ||||||
|  |     noise = tmp -  sqrt(eval[b])*subspace[b] ; | ||||||
|  |  | ||||||
|  |     std::cout<<GridLogMessage << " lambda_"<<b<<" = "<< eval[b] <<"  ;  [ M - Lambda ]_"<<b<<" vec_"<<b<<"  = " <<norm2(noise)<<std::endl; | ||||||
|  |  | ||||||
|  |     noise = tmp +  eval[b]*subspace[b] ; | ||||||
|  |  | ||||||
|  |     std::cout<<GridLogMessage << " lambda_"<<b<<" = "<< eval[b] <<"  ;  [ M - Lambda ]_"<<b<<" vec_"<<b<<"  = " <<norm2(noise)<<std::endl; | ||||||
|  |  | ||||||
|  |     } | ||||||
|  |     Orthogonalise(); | ||||||
|  |     for(int b=0;b<nn;b++){ | ||||||
|  |     std::cout << GridLogMessage <<"subspace["<<b<<"] = "<<norm2(subspace[b])<<std::endl; | ||||||
|  |     } | ||||||
|  |     } | ||||||
|  |   */ | ||||||
|  |   virtual void CreateSubspace(GridParallelRNG  &RNG,LinearOperatorBase<FineField> &hermop,int nn=nbasis) { | ||||||
|  |  | ||||||
|  |     RealD scale; | ||||||
|  |  | ||||||
|  |     ConjugateGradient<FineField> CG(1.0e-2,10000); | ||||||
|  |     FineField noise(FineGrid); | ||||||
|  |     FineField Mn(FineGrid); | ||||||
|  |  | ||||||
|  |     for(int b=0;b<nn;b++){ | ||||||
|  | 	 | ||||||
|  |       subspace[b] = Zero(); | ||||||
|  |       gaussian(RNG,noise); | ||||||
|  |       scale = std::pow(norm2(noise),-0.5);  | ||||||
|  |       noise=noise*scale; | ||||||
|  | 	 | ||||||
|  |       hermop.Op(noise,Mn); std::cout<<GridLogMessage << "noise   ["<<b<<"] <n|MdagM|n> "<<norm2(Mn)<<std::endl; | ||||||
|  |  | ||||||
|  |       for(int i=0;i<1;i++){ | ||||||
|  |  | ||||||
|  | 	CG(hermop,noise,subspace[b]); | ||||||
|  |  | ||||||
|  | 	noise = subspace[b]; | ||||||
|  | 	scale = std::pow(norm2(noise),-0.5);  | ||||||
|  | 	noise=noise*scale; | ||||||
|  |  | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       hermop.Op(noise,Mn); std::cout<<GridLogMessage << "filtered["<<b<<"] <f|MdagM|f> "<<norm2(Mn)<<std::endl; | ||||||
|  |       subspace[b]   = noise; | ||||||
|  |  | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     Orthogonalise(); | ||||||
|  |  | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  | // Fine Object == (per site) type of fine field | ||||||
|  | // nbasis      == number of deflation vectors | ||||||
|  | template<class Fobj,class CComplex,int nbasis> | ||||||
|  | class CoarsenedMatrix : public SparseMatrixBase<Lattice<iVector<CComplex,nbasis > > >  { | ||||||
|  | public: | ||||||
|  |      | ||||||
|  |   typedef iVector<CComplex,nbasis >             siteVector; | ||||||
|  |   typedef Lattice<siteVector>                 CoarseVector; | ||||||
|  |   typedef Lattice<iMatrix<CComplex,nbasis > > CoarseMatrix; | ||||||
|  |  | ||||||
|  |   typedef Lattice< CComplex >   CoarseScalar; // used for inner products on fine field | ||||||
|  |   typedef Lattice<Fobj >        FineField; | ||||||
|  |  | ||||||
|  |   //////////////////// | ||||||
|  |   // Data members | ||||||
|  |   //////////////////// | ||||||
|  |   Geometry         geom; | ||||||
|  |   GridBase *       _grid;  | ||||||
|  |  | ||||||
|  |   CartesianStencil<siteVector,siteVector,int> Stencil;  | ||||||
|  |  | ||||||
|  |   std::vector<CoarseMatrix> A; | ||||||
|  |  | ||||||
|  |        | ||||||
|  |   /////////////////////// | ||||||
|  |   // Interface | ||||||
|  |   /////////////////////// | ||||||
|  |   GridBase * Grid(void)         { return _grid; };   // this is all the linalg routines need to know | ||||||
|  |  | ||||||
|  |   RealD M (const CoarseVector &in, CoarseVector &out){ | ||||||
|  |  | ||||||
|  |     conformable(_grid,in.Grid()); | ||||||
|  |     conformable(in.Grid(),out.Grid()); | ||||||
|  |  | ||||||
|  |     SimpleCompressor<siteVector> compressor; | ||||||
|  |     Stencil.HaloExchange(in,compressor); | ||||||
|  |     auto in_v = in.View(); | ||||||
|  |     auto out_v = in.View(); | ||||||
|  |     thread_for(ss,Grid()->oSites(),{ | ||||||
|  |       siteVector res = Zero(); | ||||||
|  |       siteVector nbr; | ||||||
|  |       int ptype; | ||||||
|  |       StencilEntry *SE; | ||||||
|  |       for(int point=0;point<geom.npoint;point++){ | ||||||
|  |  | ||||||
|  | 	SE=Stencil.GetEntry(ptype,point,ss); | ||||||
|  | 	   | ||||||
|  | 	if(SE->_is_local&&SE->_permute) {  | ||||||
|  | 	  permute(nbr,in_v[SE->_offset],ptype); | ||||||
|  | 	} else if(SE->_is_local) {  | ||||||
|  | 	  nbr = in_v[SE->_offset]; | ||||||
|  | 	} else { | ||||||
|  | 	  nbr = Stencil.CommBuf()[SE->_offset]; | ||||||
|  | 	} | ||||||
|  | 	auto A_point = A[point].View(); | ||||||
|  | 	res = res + A_point[ss]*nbr; | ||||||
|  |       } | ||||||
|  |       vstream(out_v[ss],res); | ||||||
|  |     }); | ||||||
|  |     return norm2(out); | ||||||
|  |   }; | ||||||
|  |  | ||||||
|  |   RealD Mdag (const CoarseVector &in, CoarseVector &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); | ||||||
|  |   }; | ||||||
|  |  | ||||||
|  |   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; | ||||||
|  |     }(); | ||||||
|  |  | ||||||
|  |     auto out_v = out.View(); | ||||||
|  |     auto in_v  = in.View(); | ||||||
|  |     thread_for(ss,Grid()->oSites(),{ | ||||||
|  |       siteVector res = Zero(); | ||||||
|  |       siteVector nbr; | ||||||
|  |       int ptype; | ||||||
|  |       StencilEntry *SE; | ||||||
|  |        | ||||||
|  |       SE=Stencil.GetEntry(ptype,point,ss); | ||||||
|  |        | ||||||
|  |       if(SE->_is_local&&SE->_permute) { | ||||||
|  | 	permute(nbr,in_v[SE->_offset],ptype); | ||||||
|  |       } else if(SE->_is_local) { | ||||||
|  | 	nbr = in_v[SE->_offset]; | ||||||
|  |       } else { | ||||||
|  | 	nbr = Stencil.CommBuf()[SE->_offset]; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       auto A_point = A[point].View(); | ||||||
|  |       res = res + A_point[ss]*nbr; | ||||||
|  |        | ||||||
|  |       vstream(out_v[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) 	:  | ||||||
|  |  | ||||||
|  |     _grid(&CoarseGrid), | ||||||
|  |     geom(CoarseGrid._ndimension), | ||||||
|  |     Stencil(&CoarseGrid,geom.npoint,Even,geom.directions,geom.displacements,0), | ||||||
|  |     A(geom.npoint,&CoarseGrid) | ||||||
|  |   { | ||||||
|  |   }; | ||||||
|  |  | ||||||
|  |   void CoarsenOperator(GridBase *FineGrid,LinearOperatorBase<Lattice<Fobj> > &linop, | ||||||
|  | 		       Aggregation<Fobj,CComplex,nbasis> & Subspace){ | ||||||
|  |  | ||||||
|  |     FineField iblock(FineGrid); // contributions from within this block | ||||||
|  |     FineField oblock(FineGrid); // contributions from outwith this block | ||||||
|  |  | ||||||
|  |     FineField     phi(FineGrid); | ||||||
|  |     FineField     tmp(FineGrid); | ||||||
|  |     FineField     zz(FineGrid); zz=Zero(); | ||||||
|  |     FineField    Mphi(FineGrid); | ||||||
|  |  | ||||||
|  |     Lattice<iScalar<vInteger> > coor(FineGrid); | ||||||
|  |  | ||||||
|  |     CoarseVector iProj(Grid());  | ||||||
|  |     CoarseVector oProj(Grid());  | ||||||
|  |     CoarseScalar InnerProd(Grid());  | ||||||
|  |  | ||||||
|  |     // Orthogonalise the subblocks over the basis | ||||||
|  |     blockOrthogonalise(InnerProd,Subspace.subspace); | ||||||
|  |  | ||||||
|  |     // Compute the matrix elements of linop between this orthonormal | ||||||
|  |     // set of vectors. | ||||||
|  |     int self_stencil=-1; | ||||||
|  |     for(int p=0;p<geom.npoint;p++){  | ||||||
|  |       A[p]=Zero(); | ||||||
|  |       if( geom.displacements[p]==0){ | ||||||
|  | 	self_stencil=p; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |     assert(self_stencil!=-1); | ||||||
|  |  | ||||||
|  |     for(int i=0;i<nbasis;i++){ | ||||||
|  |       phi=Subspace.subspace[i]; | ||||||
|  | 	 | ||||||
|  |       std::cout<<GridLogMessage<<"("<<i<<").."<<std::endl; | ||||||
|  |  | ||||||
|  |       for(int p=0;p<geom.npoint;p++){  | ||||||
|  |  | ||||||
|  | 	int dir   = geom.directions[p]; | ||||||
|  | 	int disp  = geom.displacements[p]; | ||||||
|  |  | ||||||
|  | 	Integer block=(FineGrid->_rdimensions[dir])/(Grid()->_rdimensions[dir]); | ||||||
|  |  | ||||||
|  | 	LatticeCoordinate(coor,dir); | ||||||
|  |  | ||||||
|  | 	if ( disp==0 ){ | ||||||
|  | 	  linop.OpDiag(phi,Mphi); | ||||||
|  | 	} | ||||||
|  | 	else  { | ||||||
|  | 	  linop.OpDir(phi,Mphi,dir,disp);  | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	//////////////////////////////////////////////////////////////////////// | ||||||
|  | 	// Pick out contributions coming from this cell and neighbour cell | ||||||
|  | 	//////////////////////////////////////////////////////////////////////// | ||||||
|  | 	if ( disp==0 ) { | ||||||
|  | 	  iblock = Mphi; | ||||||
|  | 	  oblock = Zero(); | ||||||
|  | 	} else if ( disp==1 ) { | ||||||
|  | 	  oblock = where(mod(coor,block)==(block-1),Mphi,zz); | ||||||
|  | 	  iblock = where(mod(coor,block)!=(block-1),Mphi,zz); | ||||||
|  | 	} else if ( disp==-1 ) { | ||||||
|  | 	  oblock = where(mod(coor,block)==(Integer)0,Mphi,zz); | ||||||
|  | 	  iblock = where(mod(coor,block)!=(Integer)0,Mphi,zz); | ||||||
|  | 	} else { | ||||||
|  | 	  assert(0); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	Subspace.ProjectToSubspace(iProj,iblock); | ||||||
|  | 	Subspace.ProjectToSubspace(oProj,oblock); | ||||||
|  | 	//	  blockProject(iProj,iblock,Subspace.subspace); | ||||||
|  | 	//	  blockProject(oProj,oblock,Subspace.subspace); | ||||||
|  | 	auto iProj_v = iProj.View() ; | ||||||
|  | 	auto oProj_v = oProj.View() ; | ||||||
|  | 	auto A_p     =  A[p].View(); | ||||||
|  | 	auto A_self  = A[self_stencil].View(); | ||||||
|  | 	thread_for(ss, Grid()->oSites(),{ | ||||||
|  | 	  for(int j=0;j<nbasis;j++){ | ||||||
|  | 	    if( disp!= 0 ) { | ||||||
|  | 	      A_p[ss](j,i) = oProj_v[ss](j); | ||||||
|  | 	    } | ||||||
|  | 	    A_self[ss](j,i) =	A_self[ss](j,i) + iProj_v[ss](j); | ||||||
|  | 	  } | ||||||
|  | 	}); | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | #if 0 | ||||||
|  |     /////////////////////////// | ||||||
|  |     // test code worth preserving in if block | ||||||
|  |     /////////////////////////// | ||||||
|  |     std::cout<<GridLogMessage<< " Computed matrix elements "<< self_stencil <<std::endl; | ||||||
|  |     for(int p=0;p<geom.npoint;p++){ | ||||||
|  |       std::cout<<GridLogMessage<< "A["<<p<<"]" << std::endl; | ||||||
|  |       std::cout<<GridLogMessage<< A[p] << std::endl; | ||||||
|  |     } | ||||||
|  |     std::cout<<GridLogMessage<< " picking by block0 "<< self_stencil <<std::endl; | ||||||
|  |  | ||||||
|  |     phi=Subspace.subspace[0]; | ||||||
|  |     std::vector<int> bc(FineGrid->_ndimension,0); | ||||||
|  |  | ||||||
|  |     blockPick(Grid(),phi,tmp,bc);      // Pick out a block | ||||||
|  |     linop.Op(tmp,Mphi);                // Apply big dop | ||||||
|  |     blockProject(iProj,Mphi,Subspace.subspace); // project it and print it | ||||||
|  |     std::cout<<GridLogMessage<< " Computed matrix elements from block zero only "<<std::endl; | ||||||
|  |     std::cout<<GridLogMessage<< iProj <<std::endl; | ||||||
|  |     std::cout<<GridLogMessage<<"Computed Coarse Operator"<<std::endl; | ||||||
|  | #endif | ||||||
|  |       //      ForceHermitian(); | ||||||
|  |       // AssertHermitian(); | ||||||
|  |       // ForceDiagonal(); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   void ForceHermitian(void) { | ||||||
|  |     for(int d=0;d<4;d++){ | ||||||
|  |       int dd=d+1; | ||||||
|  |       A[2*d] = adj(Cshift(A[2*d+1],dd,1)); | ||||||
|  |     } | ||||||
|  |     //      A[8] = 0.5*(A[8] + adj(A[8])); | ||||||
|  |   } | ||||||
|  |   void AssertHermitian(void) { | ||||||
|  |     CoarseMatrix AA    (Grid()); | ||||||
|  |     CoarseMatrix AAc   (Grid()); | ||||||
|  |     CoarseMatrix Diff  (Grid()); | ||||||
|  |     for(int d=0;d<4;d++){ | ||||||
|  | 	 | ||||||
|  |       int dd=d+1; | ||||||
|  |       AAc = Cshift(A[2*d+1],dd,1); | ||||||
|  |       AA  = A[2*d]; | ||||||
|  | 	 | ||||||
|  |       Diff = AA - adj(AAc); | ||||||
|  |  | ||||||
|  |       std::cout<<GridLogMessage<<"Norm diff dim "<<d<<" "<< norm2(Diff)<<std::endl; | ||||||
|  |       std::cout<<GridLogMessage<<"Norm dim "<<d<<" "<< norm2(AA)<<std::endl; | ||||||
|  | 	   | ||||||
|  |     } | ||||||
|  |     Diff = A[8] - adj(A[8]); | ||||||
|  |     std::cout<<GridLogMessage<<"Norm diff local "<< norm2(Diff)<<std::endl; | ||||||
|  |     std::cout<<GridLogMessage<<"Norm local "<< norm2(A[8])<<std::endl; | ||||||
|  |   } | ||||||
|  |      | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | NAMESPACE_END(Grid); | ||||||
|  | #endif | ||||||
							
								
								
									
										291
									
								
								Grid/algorithms/FFT.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										291
									
								
								Grid/algorithms/FFT.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,291 @@ | |||||||
|  |  | ||||||
|  | /************************************************************************************* | ||||||
|  |  | ||||||
|  |     Grid physics library, www.github.com/paboyle/Grid  | ||||||
|  |  | ||||||
|  |     Source file: ./lib/Cshift.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_FFT_H_ | ||||||
|  | #define _GRID_FFT_H_ | ||||||
|  |  | ||||||
|  | #ifdef HAVE_FFTW | ||||||
|  | #ifdef USE_MKL | ||||||
|  | #include <fftw/fftw3.h> | ||||||
|  | #else | ||||||
|  | #include <fftw3.h> | ||||||
|  | #endif | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  |  | ||||||
|  | NAMESPACE_BEGIN(Grid); | ||||||
|  |  | ||||||
|  | template<class scalar> struct FFTW { }; | ||||||
|  |  | ||||||
|  | #ifdef HAVE_FFTW	 | ||||||
|  | template<> struct FFTW<ComplexD> { | ||||||
|  | public: | ||||||
|  |  | ||||||
|  |   typedef fftw_complex FFTW_scalar; | ||||||
|  |   typedef fftw_plan    FFTW_plan; | ||||||
|  |  | ||||||
|  |   static FFTW_plan fftw_plan_many_dft(int rank, const int *n,int howmany, | ||||||
|  | 				      FFTW_scalar *in, const int *inembed,		 | ||||||
|  | 				      int istride, int idist,		 | ||||||
|  | 				      FFTW_scalar *out, const int *onembed,		 | ||||||
|  | 				      int ostride, int odist,		 | ||||||
|  | 				      int sign, unsigned flags) { | ||||||
|  |     return ::fftw_plan_many_dft(rank,n,howmany,in,inembed,istride,idist,out,onembed,ostride,odist,sign,flags); | ||||||
|  |   }	   | ||||||
|  |      | ||||||
|  |   static void fftw_flops(const FFTW_plan p,double *add, double *mul, double *fmas){ | ||||||
|  |     ::fftw_flops(p,add,mul,fmas); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   inline static void fftw_execute_dft(const FFTW_plan p,FFTW_scalar *in,FFTW_scalar *out) { | ||||||
|  |     ::fftw_execute_dft(p,in,out); | ||||||
|  |   } | ||||||
|  |   inline static void fftw_destroy_plan(const FFTW_plan p) { | ||||||
|  |     ::fftw_destroy_plan(p); | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | template<> struct FFTW<ComplexF> { | ||||||
|  | public: | ||||||
|  |  | ||||||
|  |   typedef fftwf_complex FFTW_scalar; | ||||||
|  |   typedef fftwf_plan    FFTW_plan; | ||||||
|  |  | ||||||
|  |   static FFTW_plan fftw_plan_many_dft(int rank, const int *n,int howmany, | ||||||
|  | 				      FFTW_scalar *in, const int *inembed,		 | ||||||
|  | 				      int istride, int idist,		 | ||||||
|  | 				      FFTW_scalar *out, const int *onembed,		 | ||||||
|  | 				      int ostride, int odist,		 | ||||||
|  | 				      int sign, unsigned flags) { | ||||||
|  |     return ::fftwf_plan_many_dft(rank,n,howmany,in,inembed,istride,idist,out,onembed,ostride,odist,sign,flags); | ||||||
|  |   }	   | ||||||
|  |      | ||||||
|  |   static void fftw_flops(const FFTW_plan p,double *add, double *mul, double *fmas){ | ||||||
|  |     ::fftwf_flops(p,add,mul,fmas); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   inline static void fftw_execute_dft(const FFTW_plan p,FFTW_scalar *in,FFTW_scalar *out) { | ||||||
|  |     ::fftwf_execute_dft(p,in,out); | ||||||
|  |   } | ||||||
|  |   inline static void fftw_destroy_plan(const FFTW_plan p) { | ||||||
|  |     ::fftwf_destroy_plan(p); | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #ifndef FFTW_FORWARD | ||||||
|  | #define FFTW_FORWARD (-1) | ||||||
|  | #define FFTW_BACKWARD (+1) | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | class FFT { | ||||||
|  | private: | ||||||
|  |      | ||||||
|  |   GridCartesian *vgrid; | ||||||
|  |   GridCartesian *sgrid; | ||||||
|  |      | ||||||
|  |   int Nd; | ||||||
|  |   double flops; | ||||||
|  |   double flops_call; | ||||||
|  |   uint64_t usec; | ||||||
|  |      | ||||||
|  |   Coordinate dimensions; | ||||||
|  |   Coordinate processors; | ||||||
|  |   Coordinate processor_coor; | ||||||
|  |      | ||||||
|  | public: | ||||||
|  |      | ||||||
|  |   static const int forward=FFTW_FORWARD; | ||||||
|  |   static const int backward=FFTW_BACKWARD; | ||||||
|  |      | ||||||
|  |   double Flops(void) {return flops;} | ||||||
|  |   double MFlops(void) {return flops/usec;} | ||||||
|  |   double USec(void)   {return (double)usec;}     | ||||||
|  |  | ||||||
|  |   FFT ( GridCartesian * grid ) : | ||||||
|  |     vgrid(grid), | ||||||
|  |     Nd(grid->_ndimension), | ||||||
|  |     dimensions(grid->_fdimensions), | ||||||
|  |     processors(grid->_processors), | ||||||
|  |     processor_coor(grid->_processor_coor) | ||||||
|  |   { | ||||||
|  |     flops=0; | ||||||
|  |     usec =0; | ||||||
|  |     Coordinate layout(Nd,1); | ||||||
|  |     sgrid = new GridCartesian(dimensions,layout,processors); | ||||||
|  |   }; | ||||||
|  |      | ||||||
|  |   ~FFT ( void)  { | ||||||
|  |     delete sgrid; | ||||||
|  |   } | ||||||
|  |      | ||||||
|  |   template<class vobj> | ||||||
|  |   void FFT_dim_mask(Lattice<vobj> &result,const Lattice<vobj> &source,Coordinate mask,int sign){ | ||||||
|  |  | ||||||
|  |     conformable(result.Grid(),vgrid); | ||||||
|  |     conformable(source.Grid(),vgrid); | ||||||
|  |     Lattice<vobj> tmp(vgrid); | ||||||
|  |     tmp = source; | ||||||
|  |     for(int d=0;d<Nd;d++){ | ||||||
|  |       if( mask[d] ) { | ||||||
|  | 	FFT_dim(result,tmp,d,sign); | ||||||
|  | 	tmp=result; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   template<class vobj> | ||||||
|  |   void FFT_all_dim(Lattice<vobj> &result,const Lattice<vobj> &source,int sign){ | ||||||
|  |     Coordinate mask(Nd,1); | ||||||
|  |     FFT_dim_mask(result,source,mask,sign); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |   template<class vobj> | ||||||
|  |   void FFT_dim(Lattice<vobj> &result,const Lattice<vobj> &source,int dim, int sign){ | ||||||
|  | #ifndef HAVE_FFTW | ||||||
|  |     assert(0); | ||||||
|  | #else | ||||||
|  |     conformable(result.Grid(),vgrid); | ||||||
|  |     conformable(source.Grid(),vgrid); | ||||||
|  |  | ||||||
|  |     int L = vgrid->_ldimensions[dim]; | ||||||
|  |     int G = vgrid->_fdimensions[dim]; | ||||||
|  |        | ||||||
|  |     Coordinate layout(Nd,1); | ||||||
|  |     Coordinate pencil_gd(vgrid->_fdimensions); | ||||||
|  |        | ||||||
|  |     pencil_gd[dim] = G*processors[dim]; | ||||||
|  |        | ||||||
|  |     // Pencil global vol LxLxGxLxL per node | ||||||
|  |     GridCartesian pencil_g(pencil_gd,layout,processors); | ||||||
|  |        | ||||||
|  |     // Construct pencils | ||||||
|  |     typedef typename vobj::scalar_object sobj; | ||||||
|  |     typedef typename sobj::scalar_type   scalar; | ||||||
|  |        | ||||||
|  |     Lattice<sobj> pgbuf(&pencil_g); | ||||||
|  |     auto pgbuf_v = pgbuf.View(); | ||||||
|  |  | ||||||
|  |     typedef typename FFTW<scalar>::FFTW_scalar FFTW_scalar; | ||||||
|  |     typedef typename FFTW<scalar>::FFTW_plan   FFTW_plan; | ||||||
|  |        | ||||||
|  |     int Ncomp = sizeof(sobj)/sizeof(scalar); | ||||||
|  |     int Nlow  = 1; | ||||||
|  |     for(int d=0;d<dim;d++){ | ||||||
|  |       Nlow*=vgrid->_ldimensions[d]; | ||||||
|  |     } | ||||||
|  |        | ||||||
|  |     int rank = 1;  /* 1d transforms */ | ||||||
|  |     int n[] = {G}; /* 1d transforms of length G */ | ||||||
|  |     int howmany = Ncomp; | ||||||
|  |     int odist,idist,istride,ostride; | ||||||
|  |     idist   = odist   = 1;          /* Distance between consecutive FT's */ | ||||||
|  |     istride = ostride = Ncomp*Nlow; /* distance between two elements in the same FT */ | ||||||
|  |     int *inembed = n, *onembed = n; | ||||||
|  |        | ||||||
|  |     scalar div; | ||||||
|  |     if ( sign == backward ) div = 1.0/G; | ||||||
|  |     else if ( sign == forward ) div = 1.0; | ||||||
|  |     else assert(0); | ||||||
|  |        | ||||||
|  |     FFTW_plan p; | ||||||
|  |     { | ||||||
|  |       FFTW_scalar *in = (FFTW_scalar *)&pgbuf_v[0]; | ||||||
|  |       FFTW_scalar *out= (FFTW_scalar *)&pgbuf_v[0]; | ||||||
|  |       p = FFTW<scalar>::fftw_plan_many_dft(rank,n,howmany, | ||||||
|  | 					   in,inembed, | ||||||
|  | 					   istride,idist, | ||||||
|  | 					   out,onembed, | ||||||
|  | 					   ostride, odist, | ||||||
|  | 					   sign,FFTW_ESTIMATE); | ||||||
|  |     } | ||||||
|  |        | ||||||
|  |     // Barrel shift and collect global pencil | ||||||
|  |     Coordinate lcoor(Nd), gcoor(Nd); | ||||||
|  |     result = source; | ||||||
|  |     int pc = processor_coor[dim]; | ||||||
|  |     for(int p=0;p<processors[dim];p++) { | ||||||
|  |       thread_for(idx, sgrid->lSites(),{ | ||||||
|  |           Coordinate cbuf(Nd); | ||||||
|  |           sobj s; | ||||||
|  | 	  sgrid->LocalIndexToLocalCoor(idx,cbuf); | ||||||
|  | 	  peekLocalSite(s,result,cbuf); | ||||||
|  | 	  cbuf[dim]+=((pc+p) % processors[dim])*L; | ||||||
|  | 	  //            cbuf[dim]+=p*L; | ||||||
|  | 	  pokeLocalSite(s,pgbuf,cbuf); | ||||||
|  |       }); | ||||||
|  |       if (p != processors[dim] - 1) { | ||||||
|  | 	result = Cshift(result,dim,L); | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |        | ||||||
|  |     // Loop over orthog coords | ||||||
|  |     int NN=pencil_g.lSites(); | ||||||
|  |     GridStopWatch timer; | ||||||
|  |     timer.Start(); | ||||||
|  |     thread_for( idx,NN,{ | ||||||
|  |         Coordinate cbuf(Nd); | ||||||
|  | 	pencil_g.LocalIndexToLocalCoor(idx, cbuf); | ||||||
|  | 	if ( cbuf[dim] == 0 ) {  // restricts loop to plane at lcoor[dim]==0 | ||||||
|  | 	  FFTW_scalar *in = (FFTW_scalar *)&pgbuf_v[idx]; | ||||||
|  | 	  FFTW_scalar *out= (FFTW_scalar *)&pgbuf_v[idx]; | ||||||
|  | 	  FFTW<scalar>::fftw_execute_dft(p,in,out); | ||||||
|  | 	} | ||||||
|  |     }); | ||||||
|  |     timer.Stop(); | ||||||
|  |        | ||||||
|  |     // performance counting | ||||||
|  |     double add,mul,fma; | ||||||
|  |     FFTW<scalar>::fftw_flops(p,&add,&mul,&fma); | ||||||
|  |     flops_call = add+mul+2.0*fma; | ||||||
|  |     usec += timer.useconds(); | ||||||
|  |     flops+= flops_call*NN; | ||||||
|  |        | ||||||
|  |     // writing out result | ||||||
|  |     thread_for(idx,sgrid->lSites(),{ | ||||||
|  | 	Coordinate clbuf(Nd), cgbuf(Nd); | ||||||
|  | 	sobj s; | ||||||
|  | 	sgrid->LocalIndexToLocalCoor(idx,clbuf); | ||||||
|  | 	cgbuf = clbuf; | ||||||
|  | 	cgbuf[dim] = clbuf[dim]+L*pc; | ||||||
|  | 	peekLocalSite(s,pgbuf,cgbuf); | ||||||
|  | 	pokeLocalSite(s,result,clbuf); | ||||||
|  |     }); | ||||||
|  |     result = result*div; | ||||||
|  |        | ||||||
|  |     // destroying plan | ||||||
|  |     FFTW<scalar>::fftw_destroy_plan(p); | ||||||
|  | #endif | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | NAMESPACE_END(Grid); | ||||||
|  |  | ||||||
|  | #endif | ||||||
							
								
								
									
										495
									
								
								Grid/algorithms/LinearOperator.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										495
									
								
								Grid/algorithms/LinearOperator.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,495 @@ | |||||||
|  | /************************************************************************************* | ||||||
|  |  | ||||||
|  |     Grid physics library, www.github.com/paboyle/Grid  | ||||||
|  |  | ||||||
|  |     Source file: ./lib/algorithms/LinearOperator.h | ||||||
|  |  | ||||||
|  |     Copyright (C) 2015 | ||||||
|  |  | ||||||
|  | Author: Azusa Yamaguchi <ayamaguc@staffmail.ed.ac.uk> | ||||||
|  | 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 */ | ||||||
|  | #pragma once  | ||||||
|  |  | ||||||
|  | NAMESPACE_BEGIN(Grid); | ||||||
|  |  | ||||||
|  | ///////////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  | // LinearOperators Take a something and return a something. | ||||||
|  | ///////////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  | // | ||||||
|  | // Hopefully linearity is satisfied and the AdjOp is indeed the Hermitian Conjugateugate (transpose if real): | ||||||
|  | //SBase | ||||||
|  | //   i)  F(a x + b y) = aF(x) + b F(y). | ||||||
|  | //  ii)  <x|Op|y> = <y|AdjOp|x>^\ast | ||||||
|  | // | ||||||
|  | // Would be fun to have a test linearity & Herm Conj function! | ||||||
|  | ///////////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  | template<class Field> class LinearOperatorBase { | ||||||
|  | public: | ||||||
|  |  | ||||||
|  |   // Support for coarsening to a multigrid | ||||||
|  |   virtual void OpDiag (const Field &in, Field &out) = 0; // Abstract base | ||||||
|  |   virtual void OpDir  (const Field &in, Field &out,int dir,int disp) = 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 HermOpAndNorm(const Field &in, Field &out,RealD &n1,RealD &n2)=0; | ||||||
|  |   virtual void HermOp(const Field &in, Field &out)=0; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ///////////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  | // By sharing the class for Sparse Matrix across multiple operator wrappers, we can share code | ||||||
|  | // between RB and non-RB variants. Sparse matrix is like the fermion action def, and then | ||||||
|  | // the wrappers implement the specialisation of "Op" and "AdjOp" to the cases minimising | ||||||
|  | // replication of code. | ||||||
|  | // | ||||||
|  | // I'm not entirely happy with implementation; to share the Schur code between herm and non-herm | ||||||
|  | // while still having a "OpAndNorm" in the abstract base I had to implement it in both cases | ||||||
|  | // with an assert trap in the non-herm. This isn't right; there must be a better C++ way to | ||||||
|  | // do it, but I fear it required multiple inheritance and mixed in abstract base classes | ||||||
|  | ///////////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  |  | ||||||
|  | //////////////////////////////////////////////////////////////////// | ||||||
|  | // Construct herm op from non-herm matrix | ||||||
|  | //////////////////////////////////////////////////////////////////// | ||||||
|  | template<class Matrix,class Field> | ||||||
|  | class MdagMLinearOperator : public LinearOperatorBase<Field> { | ||||||
|  |   Matrix &_Mat; | ||||||
|  | public: | ||||||
|  |   MdagMLinearOperator(Matrix &Mat): _Mat(Mat){}; | ||||||
|  |  | ||||||
|  |   // Support for coarsening to a multigrid | ||||||
|  |   void OpDiag (const Field &in, Field &out) { | ||||||
|  |     _Mat.Mdiag(in,out); | ||||||
|  |   } | ||||||
|  |   void OpDir  (const Field &in, Field &out,int dir,int disp) { | ||||||
|  |     _Mat.Mdir(in,out,dir,disp); | ||||||
|  |   } | ||||||
|  |   void Op     (const Field &in, Field &out){ | ||||||
|  |     _Mat.M(in,out); | ||||||
|  |   } | ||||||
|  |   void AdjOp     (const Field &in, Field &out){ | ||||||
|  |     _Mat.Mdag(in,out); | ||||||
|  |   } | ||||||
|  |   void HermOpAndNorm(const Field &in, Field &out,RealD &n1,RealD &n2){ | ||||||
|  |     _Mat.MdagM(in,out,n1,n2); | ||||||
|  |   } | ||||||
|  |   void HermOp(const Field &in, Field &out){ | ||||||
|  |     RealD n1,n2; | ||||||
|  |     HermOpAndNorm(in,out,n1,n2); | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | //////////////////////////////////////////////////////////////////// | ||||||
|  | // Construct herm op and shift it for mgrid smoother | ||||||
|  | //////////////////////////////////////////////////////////////////// | ||||||
|  | template<class Matrix,class Field> | ||||||
|  | class ShiftedMdagMLinearOperator : public LinearOperatorBase<Field> { | ||||||
|  |   Matrix &_Mat; | ||||||
|  |   RealD _shift; | ||||||
|  | public: | ||||||
|  |   ShiftedMdagMLinearOperator(Matrix &Mat,RealD shift): _Mat(Mat), _shift(shift){}; | ||||||
|  |   // Support for coarsening to a multigrid | ||||||
|  |   void OpDiag (const Field &in, Field &out) { | ||||||
|  |     _Mat.Mdiag(in,out); | ||||||
|  |     assert(0); | ||||||
|  |   } | ||||||
|  |   void OpDir  (const Field &in, Field &out,int dir,int disp) { | ||||||
|  |     _Mat.Mdir(in,out,dir,disp); | ||||||
|  |     assert(0); | ||||||
|  |   } | ||||||
|  |   void Op     (const Field &in, Field &out){ | ||||||
|  |     _Mat.M(in,out); | ||||||
|  |     assert(0); | ||||||
|  |   } | ||||||
|  |   void AdjOp     (const Field &in, Field &out){ | ||||||
|  |     _Mat.Mdag(in,out); | ||||||
|  |     assert(0); | ||||||
|  |   } | ||||||
|  |   void HermOpAndNorm(const Field &in, Field &out,RealD &n1,RealD &n2){ | ||||||
|  |     _Mat.MdagM(in,out,n1,n2); | ||||||
|  |     out = out + _shift*in; | ||||||
|  |  | ||||||
|  |     ComplexD dot;	 | ||||||
|  |     dot= innerProduct(in,out); | ||||||
|  |     n1=real(dot); | ||||||
|  |     n2=norm2(out); | ||||||
|  |   } | ||||||
|  |   void HermOp(const Field &in, Field &out){ | ||||||
|  |     RealD n1,n2; | ||||||
|  |     HermOpAndNorm(in,out,n1,n2); | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | //////////////////////////////////////////////////////////////////// | ||||||
|  | // Wrap an already herm matrix | ||||||
|  | //////////////////////////////////////////////////////////////////// | ||||||
|  | template<class Matrix,class Field> | ||||||
|  | class HermitianLinearOperator : public LinearOperatorBase<Field> { | ||||||
|  |   Matrix &_Mat; | ||||||
|  | public: | ||||||
|  |   HermitianLinearOperator(Matrix &Mat): _Mat(Mat){}; | ||||||
|  |   // Support for coarsening to a multigrid | ||||||
|  |   void OpDiag (const Field &in, Field &out) { | ||||||
|  |     _Mat.Mdiag(in,out); | ||||||
|  |   } | ||||||
|  |   void OpDir  (const Field &in, Field &out,int dir,int disp) { | ||||||
|  |     _Mat.Mdir(in,out,dir,disp); | ||||||
|  |   } | ||||||
|  |   void Op     (const Field &in, Field &out){ | ||||||
|  |     _Mat.M(in,out); | ||||||
|  |   } | ||||||
|  |   void AdjOp     (const Field &in, Field &out){ | ||||||
|  |     _Mat.M(in,out); | ||||||
|  |   } | ||||||
|  |   void HermOpAndNorm(const Field &in, Field &out,RealD &n1,RealD &n2){ | ||||||
|  |     _Mat.M(in,out); | ||||||
|  | 	 | ||||||
|  |     ComplexD dot= innerProduct(in,out); n1=real(dot); | ||||||
|  |     n2=norm2(out); | ||||||
|  |   } | ||||||
|  |   void HermOp(const Field &in, Field &out){ | ||||||
|  |     _Mat.M(in,out); | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  |     ////////////////////////////////////////////////////////// | ||||||
|  |     // Even Odd Schur decomp operators; there are several | ||||||
|  |     // ways to introduce the even odd checkerboarding | ||||||
|  |     ////////////////////////////////////////////////////////// | ||||||
|  |  | ||||||
|  |     template<class Field> | ||||||
|  |     class SchurOperatorBase :  public LinearOperatorBase<Field> { | ||||||
|  |     public: | ||||||
|  |       virtual  RealD Mpc      (const Field &in, Field &out) =0; | ||||||
|  |       virtual  RealD MpcDag   (const Field &in, Field &out) =0; | ||||||
|  |       virtual void MpcDagMpc(const Field &in, Field &out,RealD &ni,RealD &no) { | ||||||
|  |       Field tmp(in.Grid()); | ||||||
|  |       tmp.Checkerboard() = in.Checkerboard(); | ||||||
|  | 	ni=Mpc(in,tmp); | ||||||
|  | 	no=MpcDag(tmp,out); | ||||||
|  |       } | ||||||
|  |       virtual void HermOpAndNorm(const Field &in, Field &out,RealD &n1,RealD &n2){ | ||||||
|  |       out.Checkerboard() = in.Checkerboard(); | ||||||
|  | 	MpcDagMpc(in,out,n1,n2); | ||||||
|  |       } | ||||||
|  |       virtual void HermOp(const Field &in, Field &out){ | ||||||
|  | 	RealD n1,n2; | ||||||
|  | 	HermOpAndNorm(in,out,n1,n2); | ||||||
|  |       } | ||||||
|  |       void Op     (const Field &in, Field &out){ | ||||||
|  | 	Mpc(in,out); | ||||||
|  |       } | ||||||
|  |       void AdjOp     (const Field &in, Field &out){  | ||||||
|  | 	MpcDag(in,out); | ||||||
|  |       } | ||||||
|  |       // Support for coarsening to a multigrid | ||||||
|  |       void OpDiag (const Field &in, Field &out) { | ||||||
|  | 	assert(0); // must coarsen the unpreconditioned system | ||||||
|  |       } | ||||||
|  |       void OpDir  (const Field &in, Field &out,int dir,int disp) { | ||||||
|  | 	assert(0); | ||||||
|  |       } | ||||||
|  |     }; | ||||||
|  |     template<class Matrix,class Field> | ||||||
|  |     class SchurDiagMooeeOperator :  public SchurOperatorBase<Field> { | ||||||
|  |     public: | ||||||
|  |       Matrix &_Mat; | ||||||
|  |       SchurDiagMooeeOperator (Matrix &Mat): _Mat(Mat){}; | ||||||
|  |       virtual  RealD Mpc      (const Field &in, Field &out) { | ||||||
|  |       Field tmp(in.Grid()); | ||||||
|  |       tmp.Checkerboard() = !in.Checkerboard(); | ||||||
|  | 	//std::cout <<"grid pointers: in._grid="<< in._grid << " out._grid=" << out._grid << "  _Mat.Grid=" << _Mat.Grid() << " _Mat.RedBlackGrid=" << _Mat.RedBlackGrid() << std::endl; | ||||||
|  |  | ||||||
|  | 	_Mat.Meooe(in,tmp); | ||||||
|  | 	_Mat.MooeeInv(tmp,out); | ||||||
|  | 	_Mat.Meooe(out,tmp); | ||||||
|  |  | ||||||
|  |       //std::cout << "cb in " << in.Checkerboard() << "  cb out " << out.Checkerboard() << std::endl; | ||||||
|  | 	_Mat.Mooee(in,out); | ||||||
|  | 	return axpy_norm(out,-1.0,tmp,out); | ||||||
|  |       } | ||||||
|  |       virtual  RealD MpcDag   (const Field &in, Field &out){ | ||||||
|  | 	Field tmp(in.Grid()); | ||||||
|  |  | ||||||
|  | 	_Mat.MeooeDag(in,tmp); | ||||||
|  |         _Mat.MooeeInvDag(tmp,out); | ||||||
|  | 	_Mat.MeooeDag(out,tmp); | ||||||
|  |  | ||||||
|  | 	_Mat.MooeeDag(in,out); | ||||||
|  | 	return axpy_norm(out,-1.0,tmp,out); | ||||||
|  |       } | ||||||
|  |     }; | ||||||
|  |     template<class Matrix,class Field> | ||||||
|  |       class SchurDiagOneOperator :  public SchurOperatorBase<Field> { | ||||||
|  |     protected: | ||||||
|  |       Matrix &_Mat; | ||||||
|  |     public: | ||||||
|  |       SchurDiagOneOperator (Matrix &Mat): _Mat(Mat){}; | ||||||
|  |  | ||||||
|  |       virtual  RealD Mpc      (const Field &in, Field &out) { | ||||||
|  | 	Field tmp(in.Grid()); | ||||||
|  |  | ||||||
|  | 	_Mat.Meooe(in,out); | ||||||
|  | 	_Mat.MooeeInv(out,tmp); | ||||||
|  | 	_Mat.Meooe(tmp,out); | ||||||
|  | 	_Mat.MooeeInv(out,tmp); | ||||||
|  |  | ||||||
|  | 	return axpy_norm(out,-1.0,tmp,in); | ||||||
|  |       } | ||||||
|  |       virtual  RealD MpcDag   (const Field &in, Field &out){ | ||||||
|  | 	Field tmp(in.Grid()); | ||||||
|  |  | ||||||
|  | 	_Mat.MooeeInvDag(in,out); | ||||||
|  | 	_Mat.MeooeDag(out,tmp); | ||||||
|  | 	_Mat.MooeeInvDag(tmp,out); | ||||||
|  | 	_Mat.MeooeDag(out,tmp); | ||||||
|  |  | ||||||
|  | 	return axpy_norm(out,-1.0,tmp,in); | ||||||
|  |       } | ||||||
|  |     }; | ||||||
|  |     template<class Matrix,class Field> | ||||||
|  |       class SchurDiagTwoOperator :  public SchurOperatorBase<Field> { | ||||||
|  |     protected: | ||||||
|  |       Matrix &_Mat; | ||||||
|  |     public: | ||||||
|  |       SchurDiagTwoOperator (Matrix &Mat): _Mat(Mat){}; | ||||||
|  |  | ||||||
|  |       virtual  RealD Mpc      (const Field &in, Field &out) { | ||||||
|  | 	Field tmp(in.Grid()); | ||||||
|  |  | ||||||
|  | 	_Mat.MooeeInv(in,out); | ||||||
|  | 	_Mat.Meooe(out,tmp); | ||||||
|  | 	_Mat.MooeeInv(tmp,out); | ||||||
|  | 	_Mat.Meooe(out,tmp); | ||||||
|  |  | ||||||
|  | 	return axpy_norm(out,-1.0,tmp,in); | ||||||
|  |       } | ||||||
|  |       virtual  RealD MpcDag   (const Field &in, Field &out){ | ||||||
|  | 	Field tmp(in.Grid()); | ||||||
|  |  | ||||||
|  | 	_Mat.MeooeDag(in,out); | ||||||
|  | 	_Mat.MooeeInvDag(out,tmp); | ||||||
|  | 	_Mat.MeooeDag(tmp,out); | ||||||
|  | 	_Mat.MooeeInvDag(out,tmp); | ||||||
|  |  | ||||||
|  | 	return axpy_norm(out,-1.0,tmp,in); | ||||||
|  |       } | ||||||
|  |     }; | ||||||
|  |     /////////////////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  |     // Left  handed Moo^-1 ; (Moo - Moe Mee^-1 Meo) psi = eta  -->  ( 1 - Moo^-1 Moe Mee^-1 Meo ) psi = Moo^-1 eta | ||||||
|  |     // Right handed Moo^-1 ; (Moo - Moe Mee^-1 Meo) Moo^-1 Moo psi = eta  -->  ( 1 - Moe Mee^-1 Meo ) Moo^-1 phi=eta ; psi = Moo^-1 phi | ||||||
|  |     /////////////////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  |     template<class Matrix,class Field> using SchurDiagOneRH = SchurDiagTwoOperator<Matrix,Field> ; | ||||||
|  |     template<class Matrix,class Field> using SchurDiagOneLH = SchurDiagOneOperator<Matrix,Field> ; | ||||||
|  |     /////////////////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  |     //  Staggered use | ||||||
|  |     /////////////////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  |     template<class Matrix,class Field> | ||||||
|  |       class SchurStaggeredOperator :  public SchurOperatorBase<Field> { | ||||||
|  |     protected: | ||||||
|  |       Matrix &_Mat; | ||||||
|  |       Field tmp; | ||||||
|  |       RealD mass; | ||||||
|  |       double tMpc; | ||||||
|  |       double tIP; | ||||||
|  |       double tMeo; | ||||||
|  |       double taxpby_norm; | ||||||
|  |       uint64_t ncall; | ||||||
|  | public: | ||||||
|  |       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){ | ||||||
|  | 	ncall++; | ||||||
|  | 	tMpc-=usecond(); | ||||||
|  |     n2 = Mpc(in,out); | ||||||
|  | 	tMpc+=usecond(); | ||||||
|  | 	tIP-=usecond(); | ||||||
|  |     ComplexD dot= innerProduct(in,out); | ||||||
|  | 	tIP+=usecond(); | ||||||
|  |     n1 = real(dot); | ||||||
|  |   } | ||||||
|  |   virtual void HermOp(const Field &in, Field &out){ | ||||||
|  | 	ncall++; | ||||||
|  | 	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)  | ||||||
|  |   { | ||||||
|  |  | ||||||
|  |     Field tmp(in.Grid()); | ||||||
|  |     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; | ||||||
|  |  | ||||||
|  |     tMeo-=usecond(); | ||||||
|  |     _Mat.Meooe(in,out); | ||||||
|  |     _Mat.Meooe(out,tmp); | ||||||
|  |     tMeo+=usecond(); | ||||||
|  |     taxpby_norm-=usecond(); | ||||||
|  |     RealD nn=axpby_norm(out,-1.0,mass*mass,tmp,in); | ||||||
|  |     taxpby_norm+=usecond(); | ||||||
|  |     return nn; | ||||||
|  |   } | ||||||
|  |   virtual  RealD MpcDag   (const Field &in, Field &out){ | ||||||
|  |     return Mpc(in,out); | ||||||
|  |   } | ||||||
|  |   virtual void MpcDagMpc(const Field &in, Field &out,RealD &ni,RealD &no) { | ||||||
|  |     assert(0);// Never need with staggered | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  | template<class Matrix,class Field> using SchurStagOperator = SchurStaggeredOperator<Matrix,Field>; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ///////////////////////////////////////////////////////////// | ||||||
|  | // Base classes for functions of operators | ||||||
|  | ///////////////////////////////////////////////////////////// | ||||||
|  | template<class Field> class OperatorFunction { | ||||||
|  | public: | ||||||
|  |   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 { | ||||||
|  | public: | ||||||
|  |   virtual void operator() (const Field &in, Field &out) = 0; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | template<class Field> class IdentityLinearFunction : public LinearFunction<Field> { | ||||||
|  | public: | ||||||
|  |   void operator() (const Field &in, Field &out){ | ||||||
|  |     out = in; | ||||||
|  |   }; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ///////////////////////////////////////////////////////////// | ||||||
|  | // Base classes for Multishift solvers for operators | ||||||
|  | ///////////////////////////////////////////////////////////// | ||||||
|  | template<class Field> class OperatorMultiFunction { | ||||||
|  | public: | ||||||
|  |   virtual void operator() (LinearOperatorBase<Field> &Linop, const Field &in, std::vector<Field> &out) = 0; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | // FIXME : To think about | ||||||
|  |  | ||||||
|  | // Chroma functionality list defining LinearOperator | ||||||
|  | /* | ||||||
|  |   virtual void operator() (T& chi, const T& psi, enum PlusMinus isign) const = 0; | ||||||
|  |   virtual void operator() (T& chi, const T& psi, enum PlusMinus isign, Real epsilon) const | ||||||
|  |   virtual const Subset& subset() const = 0; | ||||||
|  |   virtual unsigned long nFlops() const { return 0; } | ||||||
|  |   virtual void deriv(P& ds_u, const T& chi, const T& psi, enum PlusMinus isign) const | ||||||
|  |   class UnprecLinearOperator : public DiffLinearOperator<T,P,Q> | ||||||
|  |   const Subset& subset() const {return all;} | ||||||
|  |   }; | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | //////////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  | // Hermitian operator Linear function and operator function | ||||||
|  | //////////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  | template<class Field> | ||||||
|  | class HermOpOperatorFunction : public OperatorFunction<Field> { | ||||||
|  |   void operator() (LinearOperatorBase<Field> &Linop, const Field &in, Field &out) { | ||||||
|  |     Linop.HermOp(in,out); | ||||||
|  |   }; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | template<typename Field> | ||||||
|  | class PlainHermOp : public LinearFunction<Field> { | ||||||
|  | public: | ||||||
|  |   LinearOperatorBase<Field> &_Linop; | ||||||
|  |        | ||||||
|  |   PlainHermOp(LinearOperatorBase<Field>& linop) : _Linop(linop)  | ||||||
|  |   {} | ||||||
|  |        | ||||||
|  |   void operator()(const Field& in, Field& out) { | ||||||
|  |     _Linop.HermOp(in,out); | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | template<typename Field> | ||||||
|  | class FunctionHermOp : public LinearFunction<Field> { | ||||||
|  | public: | ||||||
|  |   OperatorFunction<Field>   & _poly; | ||||||
|  |   LinearOperatorBase<Field> &_Linop; | ||||||
|  |        | ||||||
|  |   FunctionHermOp(OperatorFunction<Field> & poly,LinearOperatorBase<Field>& linop)  | ||||||
|  |     : _poly(poly), _Linop(linop) {}; | ||||||
|  |        | ||||||
|  |   void operator()(const Field& in, Field& out) { | ||||||
|  |     _poly(_Linop,in,out); | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | template<class Field> | ||||||
|  | class Polynomial : public OperatorFunction<Field> { | ||||||
|  | private: | ||||||
|  |   std::vector<RealD> Coeffs; | ||||||
|  | public: | ||||||
|  |   using OperatorFunction<Field>::operator(); | ||||||
|  |  | ||||||
|  |   Polynomial(std::vector<RealD> &_Coeffs) : Coeffs(_Coeffs) { }; | ||||||
|  |  | ||||||
|  |   // Implement the required interface | ||||||
|  |   void operator() (LinearOperatorBase<Field> &Linop, const Field &in, Field &out) { | ||||||
|  |  | ||||||
|  |     Field AtoN(in.Grid()); | ||||||
|  |     Field Mtmp(in.Grid()); | ||||||
|  |     AtoN = in; | ||||||
|  |     out = AtoN*Coeffs[0]; | ||||||
|  |     for(int n=1;n<Coeffs.size();n++){ | ||||||
|  |       Mtmp = AtoN; | ||||||
|  |       Linop.HermOp(Mtmp,AtoN); | ||||||
|  |       out=out+AtoN*Coeffs[n]; | ||||||
|  |     } | ||||||
|  |   }; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | NAMESPACE_END(Grid); | ||||||
| @@ -1,4 +1,4 @@ | |||||||
|     /*************************************************************************************
 | /*************************************************************************************
 | ||||||
| 
 | 
 | ||||||
|     Grid physics library, www.github.com/paboyle/Grid  |     Grid physics library, www.github.com/paboyle/Grid  | ||||||
| 
 | 
 | ||||||
| @@ -23,24 +23,24 @@ Author: Azusa Yamaguchi <ayamaguc@staffmail.ed.ac.uk> | |||||||
|     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||||||
| 
 | 
 | ||||||
|     See the full license in the file "LICENSE" in the top level distribution directory |     See the full license in the file "LICENSE" in the top level distribution directory | ||||||
|     *************************************************************************************/ | *************************************************************************************/ | ||||||
|     /*  END LEGAL */ | /*  END LEGAL */ | ||||||
| #ifndef GRID_PRECONDITIONER_H | #ifndef GRID_PRECONDITIONER_H | ||||||
| #define GRID_PRECONDITIONER_H | #define GRID_PRECONDITIONER_H | ||||||
| 
 | 
 | ||||||
| namespace Grid { | NAMESPACE_BEGIN(Grid); | ||||||
| 
 | 
 | ||||||
|   template<class Field> class Preconditioner :  public LinearFunction<Field> {  | template<class Field> class Preconditioner :  public LinearFunction<Field> {  | ||||||
|     virtual void operator()(const Field &src, Field & psi)=0; |   virtual void operator()(const Field &src, Field & psi)=0; | ||||||
|   }; | }; | ||||||
| 
 | 
 | ||||||
|   template<class Field> class TrivialPrecon :  public Preconditioner<Field> {  | template<class Field> class TrivialPrecon :  public Preconditioner<Field> {  | ||||||
|   public: | public: | ||||||
|     void operator()(const Field &src, Field & psi){ |   void operator()(const Field &src, Field & psi){ | ||||||
|       psi = src; |     psi = src; | ||||||
|     } |   } | ||||||
|     TrivialPrecon(void){}; |   TrivialPrecon(void){}; | ||||||
|   }; | }; | ||||||
| 
 | 
 | ||||||
| } | NAMESPACE_END(Grid); | ||||||
| #endif | #endif | ||||||
							
								
								
									
										79
									
								
								Grid/algorithms/SparseMatrix.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										79
									
								
								Grid/algorithms/SparseMatrix.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,79 @@ | |||||||
|  | /************************************************************************************* | ||||||
|  |  | ||||||
|  |     Grid physics library, www.github.com/paboyle/Grid  | ||||||
|  |  | ||||||
|  |     Source file: ./lib/algorithms/SparseMatrix.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_ALGORITHM_SPARSE_MATRIX_H | ||||||
|  | #define  GRID_ALGORITHM_SPARSE_MATRIX_H | ||||||
|  |  | ||||||
|  |  | ||||||
|  | NAMESPACE_BEGIN(Grid); | ||||||
|  |  | ||||||
|  | ///////////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  | // Interface defining what I expect of a general sparse matrix, such as a Fermion action | ||||||
|  | ///////////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  | template<class Field> class SparseMatrixBase { | ||||||
|  | public: | ||||||
|  |   virtual GridBase *Grid(void) =0; | ||||||
|  |   // Full checkerboar operations | ||||||
|  |   virtual RealD M    (const Field &in, Field &out)=0; | ||||||
|  |   virtual RealD Mdag (const Field &in, Field &out)=0; | ||||||
|  |   virtual void  MdagM(const Field &in, Field &out,RealD &ni,RealD &no) { | ||||||
|  |     Field tmp (in.Grid()); | ||||||
|  |     ni=M(in,tmp); | ||||||
|  |     no=Mdag(tmp,out); | ||||||
|  |   } | ||||||
|  |   virtual  void Mdiag    (const Field &in, Field &out)=0; | ||||||
|  |   virtual  void Mdir     (const Field &in, Field &out,int dir, int disp)=0; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | ///////////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  | // Interface augmented by a red black sparse matrix, such as a Fermion action | ||||||
|  | ///////////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  | template<class Field> class CheckerBoardedSparseMatrixBase : public SparseMatrixBase<Field> { | ||||||
|  | public: | ||||||
|  |   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 1; }; // Disable assumptions unless overridden | ||||||
|  |       virtual int    isTrivialEE(void) { return 0; }; // by a derived class that knows better | ||||||
|  |  | ||||||
|  |   // half checkerboard operaions | ||||||
|  |   virtual  void Meooe    (const Field &in, Field &out)=0; | ||||||
|  |   virtual  void Mooee    (const Field &in, Field &out)=0; | ||||||
|  |   virtual  void MooeeInv (const Field &in, Field &out)=0; | ||||||
|  |  | ||||||
|  |   virtual  void MeooeDag    (const Field &in, Field &out)=0; | ||||||
|  |   virtual  void MooeeDag    (const Field &in, Field &out)=0; | ||||||
|  |   virtual  void MooeeInvDag (const Field &in, Field &out)=0; | ||||||
|  |  | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | NAMESPACE_END(Grid); | ||||||
|  |  | ||||||
|  | #endif | ||||||
							
								
								
									
										379
									
								
								Grid/algorithms/approx/Chebyshev.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										379
									
								
								Grid/algorithms/approx/Chebyshev.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,379 @@ | |||||||
|  | /************************************************************************************* | ||||||
|  |  | ||||||
|  |     Grid physics library, www.github.com/paboyle/Grid  | ||||||
|  |  | ||||||
|  |     Source file: ./lib/algorithms/approx/Chebyshev.h | ||||||
|  |  | ||||||
|  |     Copyright (C) 2015 | ||||||
|  |  | ||||||
|  | Author: Peter Boyle <paboyle@ph.ed.ac.uk> | ||||||
|  | Author: paboyle <paboyle@ph.ed.ac.uk> | ||||||
|  | Author: Christoph Lehner <clehner@bnl.gov> | ||||||
|  |  | ||||||
|  |     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_CHEBYSHEV_H | ||||||
|  | #define GRID_CHEBYSHEV_H | ||||||
|  |  | ||||||
|  | #include <Grid/algorithms/LinearOperator.h> | ||||||
|  |  | ||||||
|  | NAMESPACE_BEGIN(Grid); | ||||||
|  |  | ||||||
|  | struct ChebyParams : Serializable { | ||||||
|  |   GRID_SERIALIZABLE_CLASS_MEMBERS(ChebyParams, | ||||||
|  | 				  RealD, alpha,   | ||||||
|  | 				  RealD, beta,    | ||||||
|  | 				  int, Npoly); | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | //////////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  | // Generic Chebyshev approximations | ||||||
|  | //////////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  | template<class Field> | ||||||
|  | class Chebyshev : public OperatorFunction<Field> { | ||||||
|  | private: | ||||||
|  |   using OperatorFunction<Field>::operator(); | ||||||
|  |  | ||||||
|  |   std::vector<RealD> Coeffs; | ||||||
|  |   int order; | ||||||
|  |   RealD hi; | ||||||
|  |   RealD lo; | ||||||
|  |  | ||||||
|  | public: | ||||||
|  |   void csv(std::ostream &out){ | ||||||
|  |     RealD diff = hi-lo; | ||||||
|  |     RealD delta = diff*1.0e-9; | ||||||
|  |     for (RealD x=lo; x<hi; x+=delta) { | ||||||
|  |       delta*=1.1; | ||||||
|  |       RealD f = approx(x); | ||||||
|  |       out<< x<<" "<<f<<std::endl; | ||||||
|  |     } | ||||||
|  |     return; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   // Convenience for plotting the approximation | ||||||
|  |   void   PlotApprox(std::ostream &out) { | ||||||
|  |     out<<"Polynomial approx ["<<lo<<","<<hi<<"]"<<std::endl; | ||||||
|  |     for(RealD x=lo;x<hi;x+=(hi-lo)/50.0){ | ||||||
|  |       out <<x<<"\t"<<approx(x)<<std::endl; | ||||||
|  |     } | ||||||
|  |   }; | ||||||
|  |  | ||||||
|  |   Chebyshev(){}; | ||||||
|  |   Chebyshev(ChebyParams p){ Init(p.alpha,p.beta,p.Npoly);}; | ||||||
|  |   Chebyshev(RealD _lo,RealD _hi,int _order, RealD (* func)(RealD) ) {Init(_lo,_hi,_order,func);}; | ||||||
|  |   Chebyshev(RealD _lo,RealD _hi,int _order) {Init(_lo,_hi,_order);}; | ||||||
|  |  | ||||||
|  |   //////////////////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  |   // c.f. numerical recipes "chebft"/"chebev". This is sec 5.8 "Chebyshev approximation". | ||||||
|  |   //////////////////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  |   // CJ: the one we need for Lanczos | ||||||
|  |   void Init(RealD _lo,RealD _hi,int _order) | ||||||
|  |   { | ||||||
|  |     lo=_lo; | ||||||
|  |     hi=_hi; | ||||||
|  |     order=_order; | ||||||
|  |        | ||||||
|  |     if(order < 2) exit(-1); | ||||||
|  |     Coeffs.resize(order); | ||||||
|  |     Coeffs.assign(0.,order); | ||||||
|  |     Coeffs[order-1] = 1.; | ||||||
|  |   }; | ||||||
|  |  | ||||||
|  |   void Init(RealD _lo,RealD _hi,int _order, RealD (* func)(RealD)) | ||||||
|  |   { | ||||||
|  |     lo=_lo; | ||||||
|  |     hi=_hi; | ||||||
|  |     order=_order; | ||||||
|  |        | ||||||
|  |     if(order < 2) exit(-1); | ||||||
|  |     Coeffs.resize(order); | ||||||
|  |     for(int j=0;j<order;j++){ | ||||||
|  |       RealD s=0; | ||||||
|  |       for(int k=0;k<order;k++){ | ||||||
|  | 	RealD y=std::cos(M_PI*(k+0.5)/order); | ||||||
|  | 	RealD x=0.5*(y*(hi-lo)+(hi+lo)); | ||||||
|  | 	RealD f=func(x); | ||||||
|  | 	s=s+f*std::cos( j*M_PI*(k+0.5)/order ); | ||||||
|  |       } | ||||||
|  |       Coeffs[j] = s * 2.0/order; | ||||||
|  |     } | ||||||
|  |   }; | ||||||
|  |  | ||||||
|  |      | ||||||
|  |   void JacksonSmooth(void){ | ||||||
|  |     RealD M=order; | ||||||
|  |     RealD alpha = M_PI/(M+2); | ||||||
|  |     RealD lmax = std::cos(alpha); | ||||||
|  |     RealD sumUsq =0; | ||||||
|  |     std::vector<RealD> U(M); | ||||||
|  |     std::vector<RealD> a(M); | ||||||
|  |     std::vector<RealD> g(M); | ||||||
|  |     for(int n=0;n<=M;n++){ | ||||||
|  |       U[n] = std::sin((n+1)*std::acos(lmax))/std::sin(std::acos(lmax)); | ||||||
|  |       sumUsq += U[n]*U[n]; | ||||||
|  |     }       | ||||||
|  |     sumUsq = std::sqrt(sumUsq); | ||||||
|  |  | ||||||
|  |     for(int i=1;i<=M;i++){ | ||||||
|  |       a[i] = U[i]/sumUsq; | ||||||
|  |     } | ||||||
|  |     g[0] = 1.0; | ||||||
|  |     for(int m=1;m<=M;m++){ | ||||||
|  |       g[m] = 0; | ||||||
|  |       for(int i=0;i<=M-m;i++){ | ||||||
|  | 	g[m]+= a[i]*a[m+i]; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |     for(int m=1;m<=M;m++){ | ||||||
|  |       Coeffs[m]*=g[m]; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   RealD approx(RealD x) // Convenience for plotting the approximation | ||||||
|  |   { | ||||||
|  |     RealD Tn; | ||||||
|  |     RealD Tnm; | ||||||
|  |     RealD Tnp; | ||||||
|  |        | ||||||
|  |     RealD y=( x-0.5*(hi+lo))/(0.5*(hi-lo)); | ||||||
|  |        | ||||||
|  |     RealD T0=1; | ||||||
|  |     RealD T1=y; | ||||||
|  |        | ||||||
|  |     RealD sum; | ||||||
|  |     sum = 0.5*Coeffs[0]*T0; | ||||||
|  |     sum+= Coeffs[1]*T1; | ||||||
|  |        | ||||||
|  |     Tn =T1; | ||||||
|  |     Tnm=T0; | ||||||
|  |     for(int i=2;i<order;i++){ | ||||||
|  |       Tnp=2*y*Tn-Tnm; | ||||||
|  |       Tnm=Tn; | ||||||
|  |       Tn =Tnp; | ||||||
|  |       sum+= Tn*Coeffs[i]; | ||||||
|  |     } | ||||||
|  |     return sum; | ||||||
|  |   }; | ||||||
|  |  | ||||||
|  |   RealD approxD(RealD x) | ||||||
|  |   { | ||||||
|  |     RealD Un; | ||||||
|  |     RealD Unm; | ||||||
|  |     RealD Unp; | ||||||
|  |        | ||||||
|  |     RealD y=( x-0.5*(hi+lo))/(0.5*(hi-lo)); | ||||||
|  |        | ||||||
|  |     RealD U0=1; | ||||||
|  |     RealD U1=2*y; | ||||||
|  |        | ||||||
|  |     RealD sum; | ||||||
|  |     sum = Coeffs[1]*U0; | ||||||
|  |     sum+= Coeffs[2]*U1*2.0; | ||||||
|  |        | ||||||
|  |     Un =U1; | ||||||
|  |     Unm=U0; | ||||||
|  |     for(int i=2;i<order-1;i++){ | ||||||
|  |       Unp=2*y*Un-Unm; | ||||||
|  |       Unm=Un; | ||||||
|  |       Un =Unp; | ||||||
|  |       sum+= Un*Coeffs[i+1]*(i+1.0); | ||||||
|  |     } | ||||||
|  |     return sum/(0.5*(hi-lo)); | ||||||
|  |   }; | ||||||
|  |      | ||||||
|  |   RealD approxInv(RealD z, RealD x0, int maxiter, RealD resid) { | ||||||
|  |     RealD x = x0; | ||||||
|  |     RealD eps; | ||||||
|  |        | ||||||
|  |     int i; | ||||||
|  |     for (i=0;i<maxiter;i++) { | ||||||
|  |       eps = approx(x) - z; | ||||||
|  |       if (fabs(eps / z) < resid) | ||||||
|  | 	return x; | ||||||
|  |       x = x - eps / approxD(x); | ||||||
|  |     } | ||||||
|  |        | ||||||
|  |     return std::numeric_limits<double>::quiet_NaN(); | ||||||
|  |   } | ||||||
|  |      | ||||||
|  |   // Implement the required interface | ||||||
|  |   void operator() (LinearOperatorBase<Field> &Linop, const Field &in, Field &out) { | ||||||
|  |  | ||||||
|  |     GridBase *grid=in.Grid(); | ||||||
|  |  | ||||||
|  |     // std::cout << "Chevyshef(): in.Grid()="<<in.Grid()<<std::endl; | ||||||
|  |     //std::cout <<" Linop.Grid()="<<Linop.Grid()<<"Linop.RedBlackGrid()="<<Linop.RedBlackGrid()<<std::endl; | ||||||
|  |  | ||||||
|  |     int vol=grid->gSites(); | ||||||
|  |  | ||||||
|  |     Field T0(grid); T0 = in;   | ||||||
|  |     Field T1(grid);  | ||||||
|  |     Field T2(grid); | ||||||
|  |     Field y(grid); | ||||||
|  |        | ||||||
|  |     Field *Tnm = &T0; | ||||||
|  |     Field *Tn  = &T1; | ||||||
|  |     Field *Tnp = &T2; | ||||||
|  |  | ||||||
|  |     // Tn=T1 = (xscale M + mscale)in | ||||||
|  |     RealD xscale = 2.0/(hi-lo); | ||||||
|  |     RealD mscale = -(hi+lo)/(hi-lo); | ||||||
|  |     Linop.HermOp(T0,y); | ||||||
|  |     T1=y*xscale+in*mscale; | ||||||
|  |  | ||||||
|  |     // sum = .5 c[0] T0 + c[1] T1 | ||||||
|  |     out = (0.5*Coeffs[0])*T0 + Coeffs[1]*T1; | ||||||
|  |     for(int n=2;n<order;n++){ | ||||||
|  | 	 | ||||||
|  |       Linop.HermOp(*Tn,y); | ||||||
|  |  | ||||||
|  |       y=xscale*y+mscale*(*Tn); | ||||||
|  |  | ||||||
|  |       *Tnp=2.0*y-(*Tnm); | ||||||
|  |  | ||||||
|  |       out=out+Coeffs[n]* (*Tnp); | ||||||
|  |  | ||||||
|  |       // Cycle pointers to avoid copies | ||||||
|  |       Field *swizzle = Tnm; | ||||||
|  |       Tnm    =Tn; | ||||||
|  |       Tn     =Tnp; | ||||||
|  |       Tnp    =swizzle; | ||||||
|  | 	   | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | template<class Field> | ||||||
|  | class ChebyshevLanczos : public Chebyshev<Field> { | ||||||
|  | private: | ||||||
|  |   std::vector<RealD> Coeffs; | ||||||
|  |   int order; | ||||||
|  |   RealD alpha; | ||||||
|  |   RealD beta; | ||||||
|  |   RealD mu; | ||||||
|  |  | ||||||
|  | public: | ||||||
|  |   ChebyshevLanczos(RealD _alpha,RealD _beta,RealD _mu,int _order) : | ||||||
|  |     alpha(_alpha), | ||||||
|  |     beta(_beta), | ||||||
|  |     mu(_mu) | ||||||
|  |   { | ||||||
|  |     order=_order; | ||||||
|  |     Coeffs.resize(order); | ||||||
|  |     for(int i=0;i<_order;i++){ | ||||||
|  |       Coeffs[i] = 0.0; | ||||||
|  |     } | ||||||
|  |     Coeffs[order-1]=1.0; | ||||||
|  |   }; | ||||||
|  |  | ||||||
|  |   void csv(std::ostream &out){ | ||||||
|  |     for (RealD x=-1.2*alpha; x<1.2*alpha; x+=(2.0*alpha)/10000) { | ||||||
|  |       RealD f = approx(x); | ||||||
|  |       out<< x<<" "<<f<<std::endl; | ||||||
|  |     } | ||||||
|  |     return; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   RealD approx(RealD xx) // Convenience for plotting the approximation | ||||||
|  |   { | ||||||
|  |     RealD Tn; | ||||||
|  |     RealD Tnm; | ||||||
|  |     RealD Tnp; | ||||||
|  |     Real aa = alpha * alpha; | ||||||
|  |     Real bb = beta  *  beta; | ||||||
|  |        | ||||||
|  |     RealD x = ( 2.0 * (xx-mu)*(xx-mu) - (aa+bb) ) / (aa-bb); | ||||||
|  |  | ||||||
|  |     RealD y= x; | ||||||
|  |        | ||||||
|  |     RealD T0=1; | ||||||
|  |     RealD T1=y; | ||||||
|  |        | ||||||
|  |     RealD sum; | ||||||
|  |     sum = 0.5*Coeffs[0]*T0; | ||||||
|  |     sum+= Coeffs[1]*T1; | ||||||
|  |        | ||||||
|  |     Tn =T1; | ||||||
|  |     Tnm=T0; | ||||||
|  |     for(int i=2;i<order;i++){ | ||||||
|  |       Tnp=2*y*Tn-Tnm; | ||||||
|  |       Tnm=Tn; | ||||||
|  |       Tn =Tnp; | ||||||
|  |       sum+= Tn*Coeffs[i]; | ||||||
|  |     } | ||||||
|  |     return sum; | ||||||
|  |   }; | ||||||
|  |  | ||||||
|  |   // shift_Multiply in Rudy's code | ||||||
|  |   void AminusMuSq(LinearOperatorBase<Field> &Linop, const Field &in, Field &out)  | ||||||
|  |   { | ||||||
|  |     GridBase *grid=in.Grid(); | ||||||
|  |     Field tmp(grid); | ||||||
|  |  | ||||||
|  |     RealD aa= alpha*alpha; | ||||||
|  |     RealD bb= beta * beta; | ||||||
|  |  | ||||||
|  |     Linop.HermOp(in,out); | ||||||
|  |     out = out - mu*in; | ||||||
|  |  | ||||||
|  |     Linop.HermOp(out,tmp); | ||||||
|  |     tmp = tmp - mu * out; | ||||||
|  |  | ||||||
|  |     out = (2.0/ (aa-bb) ) * tmp -  ((aa+bb)/(aa-bb))*in; | ||||||
|  |   }; | ||||||
|  |   // Implement the required interface | ||||||
|  |   void operator() (LinearOperatorBase<Field> &Linop, const Field &in, Field &out) { | ||||||
|  |  | ||||||
|  |     GridBase *grid=in.Grid(); | ||||||
|  |  | ||||||
|  |     int vol=grid->gSites(); | ||||||
|  |  | ||||||
|  |     Field T0(grid); T0 = in;   | ||||||
|  |     Field T1(grid);  | ||||||
|  |     Field T2(grid); | ||||||
|  |     Field  y(grid); | ||||||
|  |        | ||||||
|  |     Field *Tnm = &T0; | ||||||
|  |     Field *Tn  = &T1; | ||||||
|  |     Field *Tnp = &T2; | ||||||
|  |  | ||||||
|  |     // Tn=T1 = (xscale M )*in | ||||||
|  |     AminusMuSq(Linop,T0,T1); | ||||||
|  |  | ||||||
|  |     // sum = .5 c[0] T0 + c[1] T1 | ||||||
|  |     out = (0.5*Coeffs[0])*T0 + Coeffs[1]*T1; | ||||||
|  |     for(int n=2;n<order;n++){ | ||||||
|  | 	 | ||||||
|  |       AminusMuSq(Linop,*Tn,y); | ||||||
|  |  | ||||||
|  |       *Tnp=2.0*y-(*Tnm); | ||||||
|  |  | ||||||
|  |       out=out+Coeffs[n]* (*Tnp); | ||||||
|  |  | ||||||
|  |       // Cycle pointers to avoid copies | ||||||
|  |       Field *swizzle = Tnm; | ||||||
|  |       Tnm    =Tn; | ||||||
|  |       Tn     =Tnp; | ||||||
|  |       Tnp    =swizzle; | ||||||
|  | 	   | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  | NAMESPACE_END(Grid); | ||||||
|  | #endif | ||||||
							
								
								
									
										152
									
								
								Grid/algorithms/approx/Forecast.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										152
									
								
								Grid/algorithms/approx/Forecast.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,152 @@ | |||||||
|  | /************************************************************************************* | ||||||
|  |  | ||||||
|  | Grid physics library, www.github.com/paboyle/Grid | ||||||
|  |  | ||||||
|  | Source file: ./lib/algorithms/approx/Forecast.h | ||||||
|  |  | ||||||
|  | Copyright (C) 2015 | ||||||
|  |  | ||||||
|  | Author: Peter Boyle <paboyle@ph.ed.ac.uk> | ||||||
|  | Author: paboyle <paboyle@ph.ed.ac.uk> | ||||||
|  | Author: David Murphy <dmurphy@phys.columbia.edu> | ||||||
|  |  | ||||||
|  | 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 INCLUDED_FORECAST_H | ||||||
|  | #define INCLUDED_FORECAST_H | ||||||
|  |  | ||||||
|  | NAMESPACE_BEGIN(Grid); | ||||||
|  |  | ||||||
|  | // Abstract base class. | ||||||
|  | // Takes a matrix (Mat), a source (phi), and a vector of Fields (chi) | ||||||
|  | // and returns a forecasted solution to the system D*psi = phi (psi). | ||||||
|  | template<class Matrix, class Field> | ||||||
|  | class Forecast | ||||||
|  | { | ||||||
|  | public: | ||||||
|  |   virtual Field operator()(Matrix &Mat, const Field& phi, const std::vector<Field>& chi) = 0; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | // Implementation of Brower et al.'s chronological inverter (arXiv:hep-lat/9509012), | ||||||
|  | // used to forecast solutions across poles of the EOFA heatbath. | ||||||
|  | // | ||||||
|  | // Modified from CPS (cps_pp/src/util/dirac_op/d_op_base/comsrc/minresext.C) | ||||||
|  | template<class Matrix, class Field> | ||||||
|  | class ChronoForecast : public Forecast<Matrix,Field> | ||||||
|  | { | ||||||
|  | public: | ||||||
|  |   Field operator()(Matrix &Mat, const Field& phi, const std::vector<Field>& prev_solns) | ||||||
|  |   { | ||||||
|  |     int degree = prev_solns.size(); | ||||||
|  |     Field chi(phi); // forecasted solution | ||||||
|  |  | ||||||
|  |     // Trivial cases | ||||||
|  |     if(degree == 0){ chi = Zero(); return chi; } | ||||||
|  |     else if(degree == 1){ return prev_solns[0]; } | ||||||
|  |  | ||||||
|  |     //    RealD dot; | ||||||
|  |     ComplexD xp; | ||||||
|  |     Field r(phi); // residual | ||||||
|  |     Field Mv(phi); | ||||||
|  |     std::vector<Field> v(prev_solns); // orthonormalized previous solutions | ||||||
|  |     std::vector<Field> MdagMv(degree,phi); | ||||||
|  |  | ||||||
|  |     // Array to hold the matrix elements | ||||||
|  |     std::vector<std::vector<ComplexD>> G(degree, std::vector<ComplexD>(degree)); | ||||||
|  |  | ||||||
|  |     // Solution and source vectors | ||||||
|  |     std::vector<ComplexD> a(degree); | ||||||
|  |     std::vector<ComplexD> b(degree); | ||||||
|  |  | ||||||
|  |     // Orthonormalize the vector basis | ||||||
|  |     for(int i=0; i<degree; i++){ | ||||||
|  |       v[i] *= 1.0/std::sqrt(norm2(v[i])); | ||||||
|  |       for(int j=i+1; j<degree; j++){ v[j] -= innerProduct(v[i],v[j]) * v[i]; } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // Perform sparse matrix multiplication and construct rhs | ||||||
|  |     for(int i=0; i<degree; i++){ | ||||||
|  |       b[i] = innerProduct(v[i],phi); | ||||||
|  |       Mat.M(v[i],Mv); | ||||||
|  |       Mat.Mdag(Mv,MdagMv[i]); | ||||||
|  |       G[i][i] = innerProduct(v[i],MdagMv[i]); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // Construct the matrix | ||||||
|  |     for(int j=0; j<degree; j++){ | ||||||
|  |       for(int k=j+1; k<degree; k++){ | ||||||
|  | 	G[j][k] = innerProduct(v[j],MdagMv[k]); | ||||||
|  | 	G[k][j] = conjugate(G[j][k]); | ||||||
|  |       }} | ||||||
|  |  | ||||||
|  |     // Gauss-Jordan elimination with partial pivoting | ||||||
|  |     for(int i=0; i<degree; i++){ | ||||||
|  |  | ||||||
|  |       // Perform partial pivoting | ||||||
|  |       int k = i; | ||||||
|  |       for(int j=i+1; j<degree; j++){ if(abs(G[j][j]) > abs(G[k][k])){ k = j; } } | ||||||
|  |       if(k != i){ | ||||||
|  | 	xp = b[k]; | ||||||
|  | 	b[k] = b[i]; | ||||||
|  | 	b[i] = xp; | ||||||
|  | 	for(int j=0; j<degree; j++){ | ||||||
|  | 	  xp = G[k][j]; | ||||||
|  | 	  G[k][j] = G[i][j]; | ||||||
|  | 	  G[i][j] = xp; | ||||||
|  | 	} | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       // Convert matrix to upper triangular form | ||||||
|  |       for(int j=i+1; j<degree; j++){ | ||||||
|  | 	xp = G[j][i]/G[i][i]; | ||||||
|  | 	b[j] -= xp * b[i]; | ||||||
|  | 	for(int k=0; k<degree; k++){ G[j][k] -= xp*G[i][k]; } | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // Use Gaussian elimination to solve equations and calculate initial guess | ||||||
|  |     chi = Zero(); | ||||||
|  |     r = phi; | ||||||
|  |     for(int i=degree-1; i>=0; i--){ | ||||||
|  |       a[i] = 0.0; | ||||||
|  |       for(int j=i+1; j<degree; j++){ a[i] += G[i][j] * a[j]; } | ||||||
|  |       a[i] = (b[i]-a[i])/G[i][i]; | ||||||
|  |       chi += a[i]*v[i]; | ||||||
|  |       r -= a[i]*MdagMv[i]; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     RealD true_r(0.0); | ||||||
|  |     ComplexD tmp; | ||||||
|  |     for(int i=0; i<degree; i++){ | ||||||
|  |       tmp = -b[i]; | ||||||
|  |       for(int j=0; j<degree; j++){ tmp += G[i][j]*a[j]; } | ||||||
|  |       tmp = conjugate(tmp)*tmp; | ||||||
|  |       true_r += std::sqrt(tmp.real()); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     RealD error = std::sqrt(norm2(r)/norm2(phi)); | ||||||
|  |     std::cout << GridLogMessage << "ChronoForecast: |res|/|src| = " << error << std::endl; | ||||||
|  |  | ||||||
|  |     return chi; | ||||||
|  |   }; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | NAMESPACE_END(Grid); | ||||||
|  |  | ||||||
|  | #endif | ||||||
| @@ -27,7 +27,8 @@ Author: Azusa Yamaguchi <ayamaguc@staffmail.ed.ac.uk> | |||||||
|     /*  END LEGAL */ |     /*  END LEGAL */ | ||||||
| #include <Grid/GridCore.h> | #include <Grid/GridCore.h> | ||||||
| 
 | 
 | ||||||
| namespace Grid { | NAMESPACE_BEGIN(Grid); | ||||||
|  | 
 | ||||||
| double MultiShiftFunction::approx(double x) | double MultiShiftFunction::approx(double x) | ||||||
| { | { | ||||||
|   double a = norm; |   double a = norm; | ||||||
| @@ -53,4 +54,4 @@ void MultiShiftFunction::csv(std::ostream &out) | |||||||
|   } |   } | ||||||
|   return; |   return; | ||||||
| } | } | ||||||
| } | NAMESPACE_END(Grid); | ||||||
| @@ -29,7 +29,7 @@ Author: Peter Boyle <paboyle@ph.ed.ac.uk> | |||||||
| #ifndef MULTI_SHIFT_FUNCTION | #ifndef MULTI_SHIFT_FUNCTION | ||||||
| #define MULTI_SHIFT_FUNCTION | #define MULTI_SHIFT_FUNCTION | ||||||
| 
 | 
 | ||||||
| namespace Grid { | NAMESPACE_BEGIN(Grid); | ||||||
| 
 | 
 | ||||||
| class MultiShiftFunction { | class MultiShiftFunction { | ||||||
| public: | public: | ||||||
| @@ -63,5 +63,5 @@ public: | |||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
| }; | }; | ||||||
| } | NAMESPACE_END(Grid); | ||||||
| #endif | #endif | ||||||
| @@ -298,7 +298,7 @@ void AlgRemez::stpini(bigfloat *step) { | |||||||
| // Search for error maxima and minima
 | // Search for error maxima and minima
 | ||||||
| void AlgRemez::search(bigfloat *step) { | void AlgRemez::search(bigfloat *step) { | ||||||
|   bigfloat a, q, xm, ym, xn, yn, xx0, xx1; |   bigfloat a, q, xm, ym, xn, yn, xx0, xx1; | ||||||
|   int i, j, meq, emsign, ensign, steps; |   int i, meq, emsign, ensign, steps; | ||||||
| 
 | 
 | ||||||
|   meq = neq + 1; |   meq = neq + 1; | ||||||
|   bigfloat *yy = new bigfloat[meq]; |   bigfloat *yy = new bigfloat[meq]; | ||||||
| @@ -306,7 +306,6 @@ void AlgRemez::search(bigfloat *step) { | |||||||
|   bigfloat eclose = 1.0e30; |   bigfloat eclose = 1.0e30; | ||||||
|   bigfloat farther = 0l; |   bigfloat farther = 0l; | ||||||
| 
 | 
 | ||||||
|   j = 1; |  | ||||||
|   xx0 = apstrt; |   xx0 = apstrt; | ||||||
| 
 | 
 | ||||||
|   for (i = 0; i < meq; i++) { |   for (i = 0; i < meq; i++) { | ||||||
| @@ -16,7 +16,7 @@ | |||||||
| #define INCLUDED_ALG_REMEZ_H | #define INCLUDED_ALG_REMEZ_H | ||||||
| 
 | 
 | ||||||
| #include <stddef.h> | #include <stddef.h> | ||||||
| #include <Config.h> | #include <Grid/GridStd.h> | ||||||
| 
 | 
 | ||||||
| #ifdef HAVE_LIBGMP | #ifdef HAVE_LIBGMP | ||||||
| #include "bigfloat.h" | #include "bigfloat.h" | ||||||
| @@ -58,8 +58,8 @@ | |||||||
| 
 | 
 | ||||||
| /* Compute the partial fraction expansion coefficients (alpha) from the
 | /* Compute the partial fraction expansion coefficients (alpha) from the
 | ||||||
|  * factored form */ |  * factored form */ | ||||||
| namespace Grid { | NAMESPACE_BEGIN(Grid); | ||||||
| namespace Approx { | NAMESPACE_BEGIN(Approx); | ||||||
| 
 | 
 | ||||||
| static void construct_partfrac(izd *z) { | static void construct_partfrac(izd *z) { | ||||||
|   int dn = z -> dn, dd = z -> dd, type = z -> type; |   int dn = z -> dn, dd = z -> dd, type = z -> type; | ||||||
| @@ -516,7 +516,9 @@ zolotarev_data* higham(PRECISION epsilon, int n) { | |||||||
|   free(d); |   free(d); | ||||||
|   return zd; |   return zd; | ||||||
| } | } | ||||||
| }} | 
 | ||||||
|  | NAMESPACE_END(Approx); | ||||||
|  | NAMESPACE_END(Grid); | ||||||
| 
 | 
 | ||||||
| #ifdef TEST | #ifdef TEST | ||||||
| 
 | 
 | ||||||
| @@ -585,6 +587,7 @@ static PRECISION zolotarev_cayley_eval(PRECISION x, zolotarev_data* rdata) { | |||||||
|   return (ONE - T) / (ONE + T); |   return (ONE - T) / (ONE + T); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
| /* Test program. Apart from printing out the parameters for R(x) it produces
 | /* Test program. Apart from printing out the parameters for R(x) it produces
 | ||||||
|  * the following data files for plotting (unless NPLOT is defined): |  * the following data files for plotting (unless NPLOT is defined): | ||||||
|  * |  * | ||||||
| @@ -723,5 +726,5 @@ int main(int argc, char** argv) { | |||||||
|   return EXIT_SUCCESS; |   return EXIT_SUCCESS; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| #endif /* TEST */ | #endif /* TEST */ | ||||||
|  | 
 | ||||||
| @@ -1,13 +1,13 @@ | |||||||
| /* -*- Mode: C; comment-column: 22; fill-column: 79; -*- */ | /* -*- Mode: C; comment-column: 22; fill-column: 79; -*- */ | ||||||
| 
 | 
 | ||||||
| #ifdef __cplusplus | #ifdef __cplusplus | ||||||
| namespace Grid { | #include <Grid/Namespace.h> | ||||||
| namespace Approx { | NAMESPACE_BEGIN(Grid); | ||||||
|  | NAMESPACE_BEGIN(Approx); | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| #define HVERSION Header Time-stamp: <14-OCT-2004 09:26:51.00 adk@MISSCONTRARY> | #define HVERSION Header Time-stamp: <14-OCT-2004 09:26:51.00 adk@MISSCONTRARY> | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| #ifndef ZOLOTAREV_INTERNAL | #ifndef ZOLOTAREV_INTERNAL | ||||||
| #ifndef PRECISION | #ifndef PRECISION | ||||||
| #define PRECISION double | #define PRECISION double | ||||||
| @@ -83,5 +83,6 @@ void zolotarev_free(zolotarev_data *zdata); | |||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| #ifdef __cplusplus | #ifdef __cplusplus | ||||||
| }} | NAMESPACE_END(Approx); | ||||||
|  | NAMESPACE_END(Grid); | ||||||
| #endif | #endif | ||||||
| @@ -10,10 +10,12 @@ | |||||||
| #ifndef INCLUDED_BIGFLOAT_H | #ifndef INCLUDED_BIGFLOAT_H | ||||||
| #define INCLUDED_BIGFLOAT_H | #define INCLUDED_BIGFLOAT_H | ||||||
| 
 | 
 | ||||||
| 
 | #define __GMP_WITHIN_CONFIGURE | ||||||
| #include <gmp.h> | #include <gmp.h> | ||||||
| #include <mpf2mpfr.h> | #include <mpf2mpfr.h> | ||||||
| #include <mpfr.h> | #include <mpfr.h> | ||||||
|  | #undef  __GMP_WITHIN_CONFIGURE | ||||||
|  | 
 | ||||||
| class bigfloat { | class bigfloat { | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
| @@ -90,8 +90,8 @@ class TwoLevelFlexiblePcg : public LinearFunction<Field> | |||||||
|   void operator() (const Field &src, Field &psi){ |   void operator() (const Field &src, Field &psi){ | ||||||
|   void operator() (const Field &src, Field &psi){ |   void operator() (const Field &src, Field &psi){ | ||||||
| 
 | 
 | ||||||
|     psi.checkerboard = src.checkerboard; |     psi.Checkerboard() = src.Checkerboard(); | ||||||
|     grid             = src._grid; |     grid             = src.Grid(); | ||||||
| 
 | 
 | ||||||
|     RealD f; |     RealD f; | ||||||
|     RealD rtzp,rtz,a,d,b; |     RealD rtzp,rtz,a,d,b; | ||||||
							
								
								
									
										694
									
								
								Grid/algorithms/iterative/BlockConjugateGradient.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										694
									
								
								Grid/algorithms/iterative/BlockConjugateGradient.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,694 @@ | |||||||
|  | /************************************************************************************* | ||||||
|  |  | ||||||
|  | Grid physics library, www.github.com/paboyle/Grid | ||||||
|  |  | ||||||
|  | Source file: ./lib/algorithms/iterative/BlockConjugateGradient.h | ||||||
|  |  | ||||||
|  | Copyright (C) 2017 | ||||||
|  |  | ||||||
|  | Author: Azusa Yamaguchi <ayamaguc@staffmail.ed.ac.uk> | ||||||
|  | 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 */ | ||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | NAMESPACE_BEGIN(Grid); | ||||||
|  |  | ||||||
|  | enum BlockCGtype { BlockCG, BlockCGrQ, CGmultiRHS, BlockCGVec, BlockCGrQVec }; | ||||||
|  |  | ||||||
|  | ////////////////////////////////////////////////////////////////////////// | ||||||
|  | // Block conjugate gradient. Dimension zero should be the block direction | ||||||
|  | ////////////////////////////////////////////////////////////////////////// | ||||||
|  | template <class Field> | ||||||
|  | class BlockConjugateGradient : public OperatorFunction<Field> { | ||||||
|  |  public: | ||||||
|  |  | ||||||
|  |   typedef typename Field::scalar_type scomplex; | ||||||
|  |  | ||||||
|  |   int blockDim ; | ||||||
|  |   int Nblock; | ||||||
|  |  | ||||||
|  |   BlockCGtype CGtype; | ||||||
|  |   bool ErrorOnNoConverge;  // throw an assert when the CG fails to converge. | ||||||
|  |                            // Defaults true. | ||||||
|  |   RealD Tolerance; | ||||||
|  |   Integer MaxIterations; | ||||||
|  |   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) | ||||||
|  |     : Tolerance(tol), CGtype(cgtype),   blockDim(_Orthog),  MaxIterations(maxit), ErrorOnNoConverge(err_on_no_conv),PrintInterval(100) | ||||||
|  |   {}; | ||||||
|  |  | ||||||
|  | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  | // Thin QR factorisation (google it) | ||||||
|  | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  |   //////////////////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  |   //Dimensions | ||||||
|  |   // R_{ferm x Nblock} =  Q_{ferm x Nblock} x  C_{Nblock x Nblock} -> ferm x Nblock | ||||||
|  |   // | ||||||
|  |   // Rdag R = m_rr = Herm = L L^dag        <-- Cholesky decomposition (LLT routine in Eigen) | ||||||
|  |   // | ||||||
|  |   //   Q  C = R => Q = R C^{-1} | ||||||
|  |   // | ||||||
|  |   // Want  Ident = Q^dag Q = C^{-dag} R^dag R C^{-1} = C^{-dag} L L^dag C^{-1} = 1_{Nblock x Nblock}  | ||||||
|  |   // | ||||||
|  |   // Set C = L^{dag}, and then Q^dag Q = ident  | ||||||
|  |   // | ||||||
|  |   // Checks: | ||||||
|  |   // Cdag C = Rdag R ; 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); | ||||||
|  |  | ||||||
|  |   // Force manifest hermitian to avoid rounding related | ||||||
|  |   m_rr = 0.5*(m_rr+m_rr.adjoint()); | ||||||
|  |  | ||||||
|  |   Eigen::MatrixXcd L    = m_rr.llt().matrixL();  | ||||||
|  |  | ||||||
|  |   C    = L.adjoint(); | ||||||
|  |   Cinv = C.inverse(); | ||||||
|  |   //////////////////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  |   // Q = R C^{-1} | ||||||
|  |   // | ||||||
|  |   // Q_j  = R_i Cinv(i,j)  | ||||||
|  |   // | ||||||
|  |   // NB maddMatrix conventions are Right multiplication X[j] a[j,i] already | ||||||
|  |   //////////////////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  |   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 | ||||||
|  | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  | void operator()(LinearOperatorBase<Field> &Linop, const Field &Src, Field &Psi)  | ||||||
|  | { | ||||||
|  |   if ( CGtype == BlockCGrQ ) { | ||||||
|  |     BlockCGrQsolve(Linop,Src,Psi); | ||||||
|  |   } else if (CGtype == CGmultiRHS ) { | ||||||
|  |     CGmultiRHSsolve(Linop,Src,Psi); | ||||||
|  |   } else { | ||||||
|  |     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: | ||||||
|  | //-------------------------- | ||||||
|  | // X is guess/Solution | ||||||
|  | // B is RHS | ||||||
|  | // Solve A X_i = B_i    ;        i refers to Nblock index | ||||||
|  | //////////////////////////////////////////////////////////////////////////// | ||||||
|  | void BlockCGrQsolve(LinearOperatorBase<Field> &Linop, const Field &B, Field &X)  | ||||||
|  | { | ||||||
|  |   int Orthog = blockDim; // First dimension is block dim; this is an assumption | ||||||
|  |   Nblock = B.Grid()->_fdimensions[Orthog]; | ||||||
|  | /* FAKE */ | ||||||
|  |   Nblock=8; | ||||||
|  |   std::cout<<GridLogMessage<<" Block Conjugate Gradient : Orthog "<<Orthog<<" Nblock "<<Nblock<<std::endl; | ||||||
|  |  | ||||||
|  |   X.Checkerboard() = B.Checkerboard(); | ||||||
|  |   conformable(X, B); | ||||||
|  |  | ||||||
|  |   Field tmp(B); | ||||||
|  |   Field Q(B); | ||||||
|  |   Field D(B); | ||||||
|  |   Field Z(B); | ||||||
|  |   Field AD(B); | ||||||
|  |  | ||||||
|  |   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); | ||||||
|  |  | ||||||
|  |   sliceNorm(ssq,B,Orthog); | ||||||
|  |   RealD sssum=0; | ||||||
|  |   for(int b=0;b<Nblock;b++) sssum+=ssq[b]; | ||||||
|  |  | ||||||
|  |   sliceNorm(residuals,B,Orthog); | ||||||
|  |   for(int b=0;b<Nblock;b++){ assert(std::isnan(residuals[b])==0); } | ||||||
|  |  | ||||||
|  |   sliceNorm(residuals,X,Orthog); | ||||||
|  |   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<<"BlockCGrQ algorithm initialisation " <<std::endl; | ||||||
|  |  | ||||||
|  |   //1.  QC = R = B-AX, D = Q     ; QC => Thin QR factorisation (google it) | ||||||
|  |   Linop.HermOp(X, AD); | ||||||
|  |   tmp = B - AD;   | ||||||
|  |  | ||||||
|  |   ThinQRfact (m_rr, m_C, m_Cinv, Q, tmp); | ||||||
|  |   D=Q; | ||||||
|  |  | ||||||
|  |   std::cout << GridLogMessage<<"BlockCGrQ 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(); | ||||||
|  |     Linop.HermOp(D, Z);       | ||||||
|  |     MatrixTimer.Stop(); | ||||||
|  |  | ||||||
|  |     //4. M  = [D^dag Z]^{-1} | ||||||
|  |     sliceInnerTimer.Start(); | ||||||
|  |     sliceInnerProductMatrix(m_DZ,D,Z,Orthog); | ||||||
|  |     sliceInnerTimer.Stop(); | ||||||
|  |     m_M       = m_DZ.inverse(); | ||||||
|  |      | ||||||
|  |     //5. X  = X + D MC | ||||||
|  |     m_tmp     = m_M * m_C; | ||||||
|  |     sliceMaddTimer.Start(); | ||||||
|  |     sliceMaddMatrix(X,m_tmp, D,X,Orthog);      | ||||||
|  |     sliceMaddTimer.Stop(); | ||||||
|  |  | ||||||
|  |     //6. QS = Q - ZM | ||||||
|  |     sliceMaddTimer.Start(); | ||||||
|  |     sliceMaddMatrix(tmp,m_M,Z,Q,Orthog,-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(); | ||||||
|  |     sliceMaddMatrix(D,m_tmp,D,Q,Orthog); | ||||||
|  |     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 << "\titeration "<<k<<" rr_sum "<<rrsum<<" ssq_sum "<< sssum | ||||||
|  | 	      <<" ave "<<std::sqrt(rrsum/sssum) << " max "<< 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; | ||||||
|  |  | ||||||
|  |       Linop.HermOp(X, AD); | ||||||
|  |       AD = AD-B; | ||||||
|  |       std::cout << GridLogMessage <<"\t True residual is " << std::sqrt(norm2(AD)/norm2(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; | ||||||
|  | } | ||||||
|  | ////////////////////////////////////////////////////////////////////////// | ||||||
|  | // multiRHS conjugate gradient. Dimension zero should be the block direction | ||||||
|  | // Use this for spread out across nodes | ||||||
|  | ////////////////////////////////////////////////////////////////////////// | ||||||
|  | void CGmultiRHSsolve(LinearOperatorBase<Field> &Linop, const Field &Src, Field &Psi)  | ||||||
|  | { | ||||||
|  |   int Orthog = blockDim; // First dimension is block dim | ||||||
|  |   Nblock = Src.Grid()->_fdimensions[Orthog]; | ||||||
|  |  | ||||||
|  |   std::cout<<GridLogMessage<<"MultiRHS Conjugate Gradient : Orthog "<<Orthog<<" Nblock "<<Nblock<<std::endl; | ||||||
|  |  | ||||||
|  |   Psi.Checkerboard() = Src.Checkerboard(); | ||||||
|  |   conformable(Psi, Src); | ||||||
|  |  | ||||||
|  |   Field P(Src); | ||||||
|  |   Field AP(Src); | ||||||
|  |   Field R(Src); | ||||||
|  |    | ||||||
|  |   std::vector<ComplexD> v_pAp(Nblock); | ||||||
|  |   std::vector<RealD> v_rr (Nblock); | ||||||
|  |   std::vector<RealD> v_rr_inv(Nblock); | ||||||
|  |   std::vector<RealD> v_alpha(Nblock); | ||||||
|  |   std::vector<RealD> v_beta(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); | ||||||
|  |  | ||||||
|  |   R = Src - AP;   | ||||||
|  |   P = R; | ||||||
|  |   sliceNorm(v_rr,R,Orthog); | ||||||
|  |  | ||||||
|  |   GridStopWatch sliceInnerTimer; | ||||||
|  |   GridStopWatch sliceMaddTimer; | ||||||
|  |   GridStopWatch sliceNormTimer; | ||||||
|  |   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(v_rr[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(); | ||||||
|  |     sliceInnerProductVector(v_pAp,P,AP,Orthog); | ||||||
|  |     sliceInnerTimer.Stop(); | ||||||
|  |     for(int b=0;b<Nblock;b++){ | ||||||
|  |       v_alpha[b] = v_rr[b]/real(v_pAp[b]); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // Psi, R update | ||||||
|  |     sliceMaddTimer.Start(); | ||||||
|  |     sliceMaddVector(Psi,v_alpha, P,Psi,Orthog);     // add alpha *  P to psi | ||||||
|  |     sliceMaddVector(R  ,v_alpha,AP,  R,Orthog,-1.0);// sub alpha * AP to resid | ||||||
|  |     sliceMaddTimer.Stop(); | ||||||
|  |  | ||||||
|  |     // Beta | ||||||
|  |     for(int b=0;b<Nblock;b++){ | ||||||
|  |       v_rr_inv[b] = 1.0/v_rr[b]; | ||||||
|  |     } | ||||||
|  |     sliceNormTimer.Start(); | ||||||
|  |     sliceNorm(v_rr,R,Orthog); | ||||||
|  |     sliceNormTimer.Stop(); | ||||||
|  |     for(int b=0;b<Nblock;b++){ | ||||||
|  |       v_beta[b] = v_rr_inv[b] *v_rr[b]; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // Search update | ||||||
|  |     sliceMaddTimer.Start(); | ||||||
|  |     sliceMaddVector(P,v_beta,P,R,Orthog); | ||||||
|  |     sliceMaddTimer.Stop(); | ||||||
|  |  | ||||||
|  |     /********************* | ||||||
|  |      * convergence monitor | ||||||
|  |      ********************* | ||||||
|  |      */ | ||||||
|  |     RealD max_resid=0; | ||||||
|  |     for(int b=0;b<Nblock;b++){ | ||||||
|  |       RealD rr = v_rr[b]/ssq[b]; | ||||||
|  |       if ( rr > max_resid ) max_resid = rr; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     if ( max_resid < Tolerance*Tolerance ) {  | ||||||
|  |  | ||||||
|  |       SolverTimer.Stop(); | ||||||
|  |  | ||||||
|  |       std::cout << GridLogMessage<<"MultiRHS solver converged in " <<k<<" iterations"<<std::endl; | ||||||
|  |       for(int b=0;b<Nblock;b++){ | ||||||
|  | 	std::cout << GridLogMessage<< "\t\tBlock "<<b<<" computed resid "<< std::sqrt(v_rr[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 << "\tTrue 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 << "\tNorm       " << sliceNormTimer.Elapsed() <<std::endl; | ||||||
|  |       std::cout << GridLogMessage << "\tMaddMatrix " << sliceMaddTimer.Elapsed()  <<std::endl; | ||||||
|  |  | ||||||
|  |  | ||||||
|  |       IterationsToComplete = k; | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |   } | ||||||
|  |   std::cout << GridLogMessage << "MultiRHSConjugateGradient did NOT converge" << std::endl; | ||||||
|  |  | ||||||
|  |   if (ErrorOnNoConverge) assert(0); | ||||||
|  |   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] + scomplex(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] += scomplex(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; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | NAMESPACE_END(Grid); | ||||||
|  |  | ||||||
| @@ -0,0 +1,248 @@ | |||||||
|  | /************************************************************************************* | ||||||
|  |  | ||||||
|  | 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: | ||||||
|  |   using OperatorFunction<Field>::operator(); | ||||||
|  |  | ||||||
|  |   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<ComplexD> y; | ||||||
|  |   std::vector<ComplexD> gamma; | ||||||
|  |   std::vector<ComplexD> c; | ||||||
|  |   std::vector<ComplexD> 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)); | ||||||
|  |  | ||||||
|  |     ComplexD scale = 1.0/gamma[0]; | ||||||
|  |     v[0] = scale * r; | ||||||
|  |  | ||||||
|  |     LinalgTimer.Stop(); | ||||||
|  |  | ||||||
|  |     for (int i=0; i<RestartLength; i++) { | ||||||
|  |  | ||||||
|  |       IterationCount++; | ||||||
|  |  | ||||||
|  |       arnoldiStep(LinOp, v, w, i); | ||||||
|  |  | ||||||
|  |       qrUpdate(i); | ||||||
|  |  | ||||||
|  |       cp = 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 - ComplexD(H(iter, i)) * v[i]; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     H(iter, iter + 1) = sqrt(norm2(w)); | ||||||
|  |     v[iter + 1] = ComplexD(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] * ComplexD(H(iter, i)) + c[i] * ComplexD(H(iter, i + 1)); | ||||||
|  |       H(iter, i)     = conjugate(c[i]) * ComplexD(H(iter, i)) + conjugate(s[i]) * ComplexD(H(iter, i + 1)); | ||||||
|  |       H(iter, i + 1) = tmp; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // Compute new Givens Rotation | ||||||
|  |     auto 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]     = conjugate(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] - ComplexD(H(k, i)) * y[k]; | ||||||
|  |       y[i] = y[i] / ComplexD(H(i, i)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     for (int i = 0; i <= iter; i++) | ||||||
|  |       psi = psi + v[i] * y[i]; | ||||||
|  |     CompSolutionTimer.Stop(); | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  | } | ||||||
|  | #endif | ||||||
| @@ -27,11 +27,11 @@ with this program; if not, write to the Free Software Foundation, Inc., | |||||||
| See the full license in the file "LICENSE" in the top level distribution | See the full license in the file "LICENSE" in the top level distribution | ||||||
| directory | directory | ||||||
| *************************************************************************************/ | *************************************************************************************/ | ||||||
| /*  END LEGAL */ | 			   /*  END LEGAL */ | ||||||
| #ifndef GRID_CONJUGATE_GRADIENT_H | #ifndef GRID_CONJUGATE_GRADIENT_H | ||||||
| #define GRID_CONJUGATE_GRADIENT_H | #define GRID_CONJUGATE_GRADIENT_H | ||||||
| 
 | 
 | ||||||
| namespace Grid { | NAMESPACE_BEGIN(Grid); | ||||||
| 
 | 
 | ||||||
| /////////////////////////////////////////////////////////////
 | /////////////////////////////////////////////////////////////
 | ||||||
| // Base classes for iterative processes based on operators
 | // Base classes for iterative processes based on operators
 | ||||||
| @@ -40,7 +40,10 @@ namespace Grid { | |||||||
| 
 | 
 | ||||||
| template <class Field> | template <class Field> | ||||||
| class ConjugateGradient : public OperatorFunction<Field> { | class ConjugateGradient : public OperatorFunction<Field> { | ||||||
|  public: | public: | ||||||
|  | 
 | ||||||
|  |   using OperatorFunction<Field>::operator(); | ||||||
|  | 
 | ||||||
|   bool ErrorOnNoConverge;  // throw an assert when the CG fails to converge.
 |   bool ErrorOnNoConverge;  // throw an assert when the CG fails to converge.
 | ||||||
|                            // Defaults true.
 |                            // Defaults true.
 | ||||||
|   RealD Tolerance; |   RealD Tolerance; | ||||||
| @@ -48,16 +51,18 @@ class ConjugateGradient : public OperatorFunction<Field> { | |||||||
|   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
 | ||||||
|    |    | ||||||
|   ConjugateGradient(RealD tol, Integer maxit, bool err_on_no_conv = true) |   ConjugateGradient(RealD tol, Integer maxit, bool err_on_no_conv = true) | ||||||
|       : Tolerance(tol), |     : Tolerance(tol), | ||||||
|         MaxIterations(maxit), |       MaxIterations(maxit), | ||||||
|         ErrorOnNoConverge(err_on_no_conv){}; |       ErrorOnNoConverge(err_on_no_conv){}; | ||||||
|  | 
 | ||||||
|  |   void operator()(LinearOperatorBase<Field> &Linop, const Field &src, Field &psi) { | ||||||
|  | 
 | ||||||
|  |     psi.Checkerboard() = src.Checkerboard(); | ||||||
| 
 | 
 | ||||||
|   void operator()(LinearOperatorBase<Field> &Linop, const Field &src, |  | ||||||
|                   Field &psi) { |  | ||||||
|     psi.checkerboard = src.checkerboard; |  | ||||||
|     conformable(psi, src); |     conformable(psi, src); | ||||||
| 
 | 
 | ||||||
|     RealD cp, c, a, d, b, ssq, qq, b_pred; |     RealD cp, c, a, d, b, ssq, qq; | ||||||
|  |     //RealD b_pred;
 | ||||||
| 
 | 
 | ||||||
|     Field p(src); |     Field p(src); | ||||||
|     Field mmp(src); |     Field mmp(src); | ||||||
| @@ -70,7 +75,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; | ||||||
| 
 | 
 | ||||||
| @@ -78,31 +82,29 @@ class ConjugateGradient : public OperatorFunction<Field> { | |||||||
|     cp = a; |     cp = a; | ||||||
|     ssq = norm2(src); |     ssq = norm2(src); | ||||||
| 
 | 
 | ||||||
|     std::cout << GridLogIterative << std::setprecision(4) |     std::cout << GridLogIterative << std::setprecision(8) << "ConjugateGradient: guess " << guess << std::endl; | ||||||
|               << "ConjugateGradient: guess " << guess << std::endl; |     std::cout << GridLogIterative << std::setprecision(8) << "ConjugateGradient:   src " << ssq << std::endl; | ||||||
|     std::cout << GridLogIterative << std::setprecision(4) |     std::cout << GridLogIterative << std::setprecision(8) << "ConjugateGradient:    mp " << d << std::endl; | ||||||
|               << "ConjugateGradient:   src " << ssq << std::endl; |     std::cout << GridLogIterative << std::setprecision(8) << "ConjugateGradient:   mmp " << b << std::endl; | ||||||
|     std::cout << GridLogIterative << std::setprecision(4) |     std::cout << GridLogIterative << std::setprecision(8) << "ConjugateGradient:  cp,r " << cp << std::endl; | ||||||
|               << "ConjugateGradient:    mp " << d << std::endl; |     std::cout << GridLogIterative << std::setprecision(8) << "ConjugateGradient:     p " << a << std::endl; | ||||||
|     std::cout << GridLogIterative << std::setprecision(4) |  | ||||||
|               << "ConjugateGradient:   mmp " << b << std::endl; |  | ||||||
|     std::cout << GridLogIterative << std::setprecision(4) |  | ||||||
|               << "ConjugateGradient:  cp,r " << cp << std::endl; |  | ||||||
|     std::cout << GridLogIterative << std::setprecision(4) |  | ||||||
|               << "ConjugateGradient:     p " << a << std::endl; |  | ||||||
| 
 | 
 | ||||||
|     RealD rsq = Tolerance * Tolerance * ssq; |     RealD rsq = Tolerance * Tolerance * ssq; | ||||||
| 
 | 
 | ||||||
|     // Check if guess is really REALLY good :)
 |     // Check if guess is really REALLY good :)
 | ||||||
|     if (cp <= rsq) { |     if (cp <= rsq) { | ||||||
|  |       std::cout << GridLogMessage << "ConjugateGradient guess is converged already " << std::endl; | ||||||
|  |       IterationsToComplete = 0;	 | ||||||
|       return; |       return; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     std::cout << GridLogIterative << std::setprecision(4) |     std::cout << GridLogIterative << std::setprecision(8) | ||||||
|               << "ConjugateGradient: k=0 residual " << cp << " target " << rsq |               << "ConjugateGradient: k=0 residual " << cp << " target " << rsq << std::endl; | ||||||
|               << std::endl; |  | ||||||
| 
 | 
 | ||||||
|     GridStopWatch LinalgTimer; |     GridStopWatch LinalgTimer; | ||||||
|  |     GridStopWatch InnerTimer; | ||||||
|  |     GridStopWatch AxpyNormTimer; | ||||||
|  |     GridStopWatch LinearCombTimer; | ||||||
|     GridStopWatch MatrixTimer; |     GridStopWatch MatrixTimer; | ||||||
|     GridStopWatch SolverTimer; |     GridStopWatch SolverTimer; | ||||||
| 
 | 
 | ||||||
| @@ -112,26 +114,35 @@ class ConjugateGradient : public OperatorFunction<Field> { | |||||||
|       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; |       auto psi_v = psi.View(); | ||||||
|       p = p * b + r; |       auto p_v   = p.View(); | ||||||
| 
 |       auto r_v   = r.View(); | ||||||
|  |       accelerator_for(ss,p_v.size(), Field::vector_object::Nsimd(),{ | ||||||
|  | 	  coalescedWrite(psi_v[ss], a      *  p_v(ss) + psi_v(ss)); | ||||||
|  | 	  coalescedWrite(p_v[ss]  , b      *  p_v(ss) + r_v  (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; | ||||||
| 
 | 
 | ||||||
|       // Stopping condition
 |       // Stopping condition
 | ||||||
|       if (cp <= rsq) { |       if (cp <= rsq) { | ||||||
| @@ -139,33 +150,36 @@ class ConjugateGradient : public OperatorFunction<Field> { | |||||||
|         Linop.HermOpAndNorm(psi, mmp, d, qq); |         Linop.HermOpAndNorm(psi, mmp, d, qq); | ||||||
|         p = mmp - src; |         p = mmp - src; | ||||||
| 
 | 
 | ||||||
|         RealD mmpnorm = sqrt(norm2(mmp)); |         RealD srcnorm = std::sqrt(norm2(src)); | ||||||
|         RealD psinorm = sqrt(norm2(psi)); |         RealD resnorm = std::sqrt(norm2(p)); | ||||||
|         RealD srcnorm = sqrt(norm2(src)); |  | ||||||
|         RealD resnorm = sqrt(norm2(p)); |  | ||||||
|         RealD true_residual = resnorm / srcnorm; |         RealD true_residual = resnorm / srcnorm; | ||||||
| 
 | 
 | ||||||
|         std::cout << GridLogMessage |         std::cout << GridLogMessage << "ConjugateGradient Converged on iteration " << k << std::endl; | ||||||
|                   << "ConjugateGradient: Converged on iteration " << k << std::endl; |         std::cout << GridLogMessage << "\tComputed residual " << std::sqrt(cp / ssq)<<std::endl; | ||||||
|         std::cout << GridLogMessage << "Computed residual " << sqrt(cp / ssq) | 	std::cout << GridLogMessage << "\tTrue residual " << true_residual<<std::endl; | ||||||
|                   << " true residual " << true_residual << " target " | 	std::cout << GridLogMessage << "\tTarget " << Tolerance << std::endl; | ||||||
|                   << Tolerance << std::endl; | 
 | ||||||
|         std::cout << GridLogMessage << "Time elapsed: Iterations " |         std::cout << GridLogMessage << "Time breakdown "<<std::endl; | ||||||
|                   << SolverTimer.Elapsed() << " Matrix  " | 	std::cout << GridLogMessage << "\tElapsed    " << SolverTimer.Elapsed() <<std::endl; | ||||||
|                   << MatrixTimer.Elapsed() << " Linalg " | 	std::cout << GridLogMessage << "\tMatrix     " << MatrixTimer.Elapsed() <<std::endl; | ||||||
|                   << LinalgTimer.Elapsed(); | 	std::cout << GridLogMessage << "\tLinalg     " << LinalgTimer.Elapsed() <<std::endl; | ||||||
|         std::cout << 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); | ||||||
|  | 
 | ||||||
| 	IterationsToComplete = k;	 | 	IterationsToComplete = k;	 | ||||||
|  | 
 | ||||||
|         return; |         return; | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|     std::cout << GridLogMessage << "ConjugateGradient did NOT converge" |     std::cout << GridLogMessage << "ConjugateGradient did NOT converge "<<k<<" / "<< MaxIterations<< std::endl; | ||||||
|               << std::endl; | 
 | ||||||
|     if (ErrorOnNoConverge) assert(0); |     if (ErrorOnNoConverge) assert(0); | ||||||
|     IterationsToComplete = k; |     IterationsToComplete = k; | ||||||
|  | 
 | ||||||
|   } |   } | ||||||
| }; | }; | ||||||
| } | NAMESPACE_END(Grid); | ||||||
| #endif | #endif | ||||||
							
								
								
									
										161
									
								
								Grid/algorithms/iterative/ConjugateGradientMixedPrec.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										161
									
								
								Grid/algorithms/iterative/ConjugateGradientMixedPrec.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,161 @@ | |||||||
|  | /************************************************************************************* | ||||||
|  |  | ||||||
|  |     Grid physics library, www.github.com/paboyle/Grid  | ||||||
|  |  | ||||||
|  |     Source file: ./lib/algorithms/iterative/ConjugateGradientMixedPrec.h | ||||||
|  |  | ||||||
|  |     Copyright (C) 2015 | ||||||
|  |  | ||||||
|  | Author: Christopher Kelly <ckelly@phys.columbia.edu> | ||||||
|  |  | ||||||
|  |     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_CONJUGATE_GRADIENT_MIXED_PREC_H | ||||||
|  | #define GRID_CONJUGATE_GRADIENT_MIXED_PREC_H | ||||||
|  |  | ||||||
|  | NAMESPACE_BEGIN(Grid); | ||||||
|  |  | ||||||
|  |   //Mixed precision restarted defect correction CG | ||||||
|  |   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 MixedPrecisionConjugateGradient : public LinearFunction<FieldD> { | ||||||
|  |   public:                                                 | ||||||
|  |     RealD   Tolerance; | ||||||
|  |     RealD   InnerTolerance; //Initial tolerance for inner CG. Defaults to Tolerance but can be changed | ||||||
|  |     Integer MaxInnerIterations; | ||||||
|  |     Integer MaxOuterIterations; | ||||||
|  |     GridBase* SinglePrecGrid; //Grid for single-precision fields | ||||||
|  |     RealD OuterLoopNormMult; //Stop the outer loop and move to a final double prec solve when the residual is OuterLoopNormMult * Tolerance | ||||||
|  |     LinearOperatorBase<FieldF> &Linop_f; | ||||||
|  |     LinearOperatorBase<FieldD> &Linop_d; | ||||||
|  |  | ||||||
|  |     Integer TotalInnerIterations; //Number of inner CG iterations | ||||||
|  |     Integer TotalOuterIterations; //Number of restarts | ||||||
|  |     Integer TotalFinalStepIterations; //Number of CG iterations in final patch-up step | ||||||
|  |  | ||||||
|  |     //Option to speed up *inner single precision* solves using a LinearFunction that produces a guess | ||||||
|  |     LinearFunction<FieldF> *guesser; | ||||||
|  |      | ||||||
|  |     MixedPrecisionConjugateGradient(RealD tol,  | ||||||
|  | 				    Integer maxinnerit,  | ||||||
|  | 				    Integer maxouterit,  | ||||||
|  | 				    GridBase* _sp_grid,  | ||||||
|  | 				    LinearOperatorBase<FieldF> &_Linop_f,  | ||||||
|  | 				    LinearOperatorBase<FieldD> &_Linop_d) : | ||||||
|  |       Linop_f(_Linop_f), Linop_d(_Linop_d), | ||||||
|  |       Tolerance(tol), InnerTolerance(tol), MaxInnerIterations(maxinnerit), MaxOuterIterations(maxouterit), SinglePrecGrid(_sp_grid), | ||||||
|  |       OuterLoopNormMult(100.), guesser(NULL){ }; | ||||||
|  |  | ||||||
|  |     void useGuesser(LinearFunction<FieldF> &g){ | ||||||
|  |       guesser = &g; | ||||||
|  |     } | ||||||
|  |    | ||||||
|  |   void operator() (const FieldD &src_d_in, FieldD &sol_d){ | ||||||
|  |     TotalInnerIterations = 0; | ||||||
|  | 	 | ||||||
|  |     GridStopWatch TotalTimer; | ||||||
|  |     TotalTimer.Start(); | ||||||
|  |      | ||||||
|  |     int cb = src_d_in.Checkerboard(); | ||||||
|  |     sol_d.Checkerboard() = cb; | ||||||
|  |      | ||||||
|  |     RealD src_norm = norm2(src_d_in); | ||||||
|  |     RealD stop = src_norm * Tolerance*Tolerance; | ||||||
|  |  | ||||||
|  |     GridBase* DoublePrecGrid = src_d_in.Grid(); | ||||||
|  |     FieldD tmp_d(DoublePrecGrid); | ||||||
|  |     tmp_d.Checkerboard() = cb; | ||||||
|  |      | ||||||
|  |     FieldD tmp2_d(DoublePrecGrid); | ||||||
|  |     tmp2_d.Checkerboard() = cb; | ||||||
|  |      | ||||||
|  |     FieldD src_d(DoublePrecGrid); | ||||||
|  |     src_d = src_d_in; //source for next inner iteration, computed from residual during operation | ||||||
|  |      | ||||||
|  |     RealD inner_tol = InnerTolerance; | ||||||
|  |      | ||||||
|  |     FieldF src_f(SinglePrecGrid); | ||||||
|  |     src_f.Checkerboard() = cb; | ||||||
|  |      | ||||||
|  |     FieldF sol_f(SinglePrecGrid); | ||||||
|  |     sol_f.Checkerboard() = cb; | ||||||
|  |      | ||||||
|  |     ConjugateGradient<FieldF> CG_f(inner_tol, MaxInnerIterations); | ||||||
|  |     CG_f.ErrorOnNoConverge = false; | ||||||
|  |  | ||||||
|  |     GridStopWatch InnerCGtimer; | ||||||
|  |  | ||||||
|  |     GridStopWatch PrecChangeTimer; | ||||||
|  |      | ||||||
|  |     Integer &outer_iter = TotalOuterIterations; //so it will be equal to the final iteration count | ||||||
|  |        | ||||||
|  |     for(outer_iter = 0; outer_iter < MaxOuterIterations; outer_iter++){ | ||||||
|  |       //Compute double precision rsd and also new RHS vector. | ||||||
|  |       Linop_d.HermOp(sol_d, tmp_d); | ||||||
|  |       RealD norm = axpy_norm(src_d, -1., tmp_d, src_d_in); //src_d is residual vector | ||||||
|  |        | ||||||
|  |       std::cout<<GridLogMessage<<"MixedPrecisionConjugateGradient: Outer iteration " <<outer_iter<<" residual "<< norm<< " target "<< stop<<std::endl; | ||||||
|  |  | ||||||
|  |       if(norm < OuterLoopNormMult * stop){ | ||||||
|  | 	std::cout<<GridLogMessage<<"MixedPrecisionConjugateGradient: Outer iteration converged on iteration " <<outer_iter <<std::endl; | ||||||
|  | 	break; | ||||||
|  |       } | ||||||
|  |       while(norm * inner_tol * inner_tol < stop) inner_tol *= 2;  // inner_tol = sqrt(stop/norm) ?? | ||||||
|  |  | ||||||
|  |       PrecChangeTimer.Start(); | ||||||
|  |       precisionChange(src_f, src_d); | ||||||
|  |       PrecChangeTimer.Stop(); | ||||||
|  |        | ||||||
|  |       sol_f = Zero(); | ||||||
|  |  | ||||||
|  |       //Optionally improve inner solver guess (eg using known eigenvectors) | ||||||
|  |       if(guesser != NULL) | ||||||
|  | 	(*guesser)(src_f, sol_f); | ||||||
|  |  | ||||||
|  |       //Inner CG | ||||||
|  |       CG_f.Tolerance = inner_tol; | ||||||
|  |       InnerCGtimer.Start(); | ||||||
|  |       CG_f(Linop_f, src_f, sol_f); | ||||||
|  |       InnerCGtimer.Stop(); | ||||||
|  |       TotalInnerIterations += CG_f.IterationsToComplete; | ||||||
|  |        | ||||||
|  |       //Convert sol back to double and add to double prec solution | ||||||
|  |       PrecChangeTimer.Start(); | ||||||
|  |       precisionChange(tmp_d, sol_f); | ||||||
|  |       PrecChangeTimer.Stop(); | ||||||
|  |        | ||||||
|  |       axpy(sol_d, 1.0, tmp_d, sol_d); | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     //Final trial CG | ||||||
|  |     std::cout<<GridLogMessage<<"MixedPrecisionConjugateGradient: Starting final patch-up double-precision solve"<<std::endl; | ||||||
|  |      | ||||||
|  |     ConjugateGradient<FieldD> CG_d(Tolerance, MaxInnerIterations); | ||||||
|  |     CG_d(Linop_d, src_d_in, sol_d); | ||||||
|  |     TotalFinalStepIterations = CG_d.IterationsToComplete; | ||||||
|  |  | ||||||
|  |     TotalTimer.Stop(); | ||||||
|  |     std::cout<<GridLogMessage<<"MixedPrecisionConjugateGradient: Inner CG iterations " << TotalInnerIterations << " Restarts " << TotalOuterIterations << " Final CG iterations " << TotalFinalStepIterations << std::endl; | ||||||
|  |     std::cout<<GridLogMessage<<"MixedPrecisionConjugateGradient: Total time " << TotalTimer.Elapsed() << " Precision change " << PrecChangeTimer.Elapsed() << " Inner CG total " << InnerCGtimer.Elapsed() << std::endl; | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | NAMESPACE_END(Grid); | ||||||
|  |  | ||||||
|  | #endif | ||||||
							
								
								
									
										325
									
								
								Grid/algorithms/iterative/ConjugateGradientMultiShift.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										325
									
								
								Grid/algorithms/iterative/ConjugateGradientMultiShift.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,325 @@ | |||||||
|  | /************************************************************************************* | ||||||
|  |  | ||||||
|  |     Grid physics library, www.github.com/paboyle/Grid  | ||||||
|  |  | ||||||
|  |     Source file: ./lib/algorithms/iterative/ConjugateGradientMultiShift.h | ||||||
|  |  | ||||||
|  |     Copyright (C) 2015 | ||||||
|  |  | ||||||
|  | Author: Azusa Yamaguchi <ayamaguc@staffmail.ed.ac.uk> | ||||||
|  | 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_CONJUGATE_MULTI_SHIFT_GRADIENT_H | ||||||
|  | #define GRID_CONJUGATE_MULTI_SHIFT_GRADIENT_H | ||||||
|  |  | ||||||
|  | NAMESPACE_BEGIN(Grid); | ||||||
|  |  | ||||||
|  | ///////////////////////////////////////////////////////////// | ||||||
|  | // Base classes for iterative processes based on operators | ||||||
|  | // single input vec, single output vec. | ||||||
|  | ///////////////////////////////////////////////////////////// | ||||||
|  |  | ||||||
|  | template<class Field>  | ||||||
|  | class ConjugateGradientMultiShift : public OperatorMultiFunction<Field>, | ||||||
|  | 				    public OperatorFunction<Field> | ||||||
|  | { | ||||||
|  | public:                                                 | ||||||
|  |  | ||||||
|  |   using OperatorFunction<Field>::operator(); | ||||||
|  |  | ||||||
|  |   RealD   Tolerance; | ||||||
|  |   Integer MaxIterations; | ||||||
|  |     Integer IterationsToComplete; //Number of iterations the CG took to finish. Filled in upon completion | ||||||
|  |   int verbose; | ||||||
|  |   MultiShiftFunction shifts; | ||||||
|  |  | ||||||
|  |   ConjugateGradientMultiShift(Integer maxit,MultiShiftFunction &_shifts) :  | ||||||
|  |     MaxIterations(maxit), | ||||||
|  |     shifts(_shifts) | ||||||
|  |   {  | ||||||
|  |     verbose=1; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   void operator() (LinearOperatorBase<Field> &Linop, const Field &src, Field &psi) | ||||||
|  |   { | ||||||
|  |     GridBase *grid = src.Grid(); | ||||||
|  |     int nshift = shifts.order; | ||||||
|  |     std::vector<Field> results(nshift,grid); | ||||||
|  |     (*this)(Linop,src,results,psi); | ||||||
|  |   } | ||||||
|  |   void operator() (LinearOperatorBase<Field> &Linop, const Field &src, std::vector<Field> &results, Field &psi) | ||||||
|  |   { | ||||||
|  |     int nshift = shifts.order; | ||||||
|  |  | ||||||
|  |     (*this)(Linop,src,results); | ||||||
|  |    | ||||||
|  |     psi = shifts.norm*src; | ||||||
|  |     for(int i=0;i<nshift;i++){ | ||||||
|  |       psi = psi + shifts.residues[i]*results[i]; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   void operator() (LinearOperatorBase<Field> &Linop, const Field &src, std::vector<Field> &psi) | ||||||
|  |   { | ||||||
|  |    | ||||||
|  |     GridBase *grid = src.Grid(); | ||||||
|  |    | ||||||
|  |     //////////////////////////////////////////////////////////////////////// | ||||||
|  |     // Convenience references to the info stored in "MultiShiftFunction" | ||||||
|  |     //////////////////////////////////////////////////////////////////////// | ||||||
|  |     int nshift = shifts.order; | ||||||
|  |  | ||||||
|  |     std::vector<RealD> &mass(shifts.poles); // Make references to array in "shifts" | ||||||
|  |     std::vector<RealD> &mresidual(shifts.tolerances); | ||||||
|  |     std::vector<RealD> alpha(nshift,1.0); | ||||||
|  |     std::vector<Field>   ps(nshift,grid);// Search directions | ||||||
|  |  | ||||||
|  |     assert(psi.size()==nshift); | ||||||
|  |     assert(mass.size()==nshift); | ||||||
|  |     assert(mresidual.size()==nshift); | ||||||
|  |    | ||||||
|  |     // dynamic sized arrays on stack; 2d is a pain with vector | ||||||
|  |     RealD  bs[nshift]; | ||||||
|  |     RealD  rsq[nshift]; | ||||||
|  |     RealD  z[nshift][2]; | ||||||
|  |     int     converged[nshift]; | ||||||
|  |    | ||||||
|  |     const int       primary =0; | ||||||
|  |    | ||||||
|  |     //Primary shift fields CG iteration | ||||||
|  |     RealD a,b,c,d; | ||||||
|  |     RealD cp,bp,qq; //prev | ||||||
|  |    | ||||||
|  |     // Matrix mult fields | ||||||
|  |     Field r(grid); | ||||||
|  |     Field p(grid); | ||||||
|  |     Field tmp(grid); | ||||||
|  |     Field mmp(grid); | ||||||
|  |    | ||||||
|  |     // Check lightest mass | ||||||
|  |     for(int s=0;s<nshift;s++){ | ||||||
|  |       assert( mass[s]>= mass[primary] ); | ||||||
|  |       converged[s]=0; | ||||||
|  |     } | ||||||
|  |    | ||||||
|  |     // Wire guess to zero | ||||||
|  |     // Residuals "r" are src | ||||||
|  |     // First search direction "p" is also src | ||||||
|  |     cp = norm2(src); | ||||||
|  |     for(int s=0;s<nshift;s++){ | ||||||
|  |       rsq[s] = cp * mresidual[s] * mresidual[s]; | ||||||
|  |       std::cout<<GridLogMessage<<"ConjugateGradientMultiShift: shift "<<s | ||||||
|  | 	       <<" target resid "<<rsq[s]<<std::endl; | ||||||
|  |       ps[s] = src; | ||||||
|  |     } | ||||||
|  |     // r and p for primary | ||||||
|  |     r=src; | ||||||
|  |     p=src; | ||||||
|  |    | ||||||
|  |     //MdagM+m[0] | ||||||
|  |     Linop.HermOpAndNorm(p,mmp,d,qq); | ||||||
|  |     axpy(mmp,mass[0],p,mmp); | ||||||
|  |     RealD rn = norm2(p); | ||||||
|  |     d += rn*mass[0]; | ||||||
|  |    | ||||||
|  |     // have verified that inner product of  | ||||||
|  |     // p and mmp is equal to d after this since | ||||||
|  |     // the d computation is tricky | ||||||
|  |     //  qq = real(innerProduct(p,mmp)); | ||||||
|  |     //  std::cout<<GridLogMessage << "debug equal ?  qq "<<qq<<" d "<< d<<std::endl; | ||||||
|  |    | ||||||
|  |     b = -cp /d; | ||||||
|  |    | ||||||
|  |     // Set up the various shift variables | ||||||
|  |     int       iz=0; | ||||||
|  |     z[0][1-iz] = 1.0; | ||||||
|  |     z[0][iz]   = 1.0; | ||||||
|  |     bs[0]      = b; | ||||||
|  |     for(int s=1;s<nshift;s++){ | ||||||
|  |       z[s][1-iz] = 1.0; | ||||||
|  |       z[s][iz]   = 1.0/( 1.0 - b*(mass[s]-mass[0])); | ||||||
|  |       bs[s]      = b*z[s][iz];  | ||||||
|  |     } | ||||||
|  |    | ||||||
|  |     // r += b[0] A.p[0] | ||||||
|  |     // c= norm(r) | ||||||
|  |     c=axpy_norm(r,b,mmp,r); | ||||||
|  |    | ||||||
|  |     for(int s=0;s<nshift;s++) { | ||||||
|  |       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 | ||||||
|  |     int k; | ||||||
|  |    | ||||||
|  |     for (k=1;k<=MaxIterations;k++){ | ||||||
|  |      | ||||||
|  |       a = c /cp; | ||||||
|  |     AXPYTimer.Start(); | ||||||
|  |       axpy(p,a,p,r); | ||||||
|  |     AXPYTimer.Stop(); | ||||||
|  |      | ||||||
|  |       // Note to self - direction ps is iterated seperately | ||||||
|  |       // for each shift. Does not appear to have any scope | ||||||
|  |       // for avoiding linear algebra in "single" case. | ||||||
|  |       //  | ||||||
|  |       // However SAME r is used. Could load "r" and update | ||||||
|  |       // ALL ps[s]. 2/3 Bandwidth saving | ||||||
|  |       // New Kernel: Load r, vector of coeffs, vector of pointers ps | ||||||
|  |     AXPYTimer.Start(); | ||||||
|  |       for(int s=0;s<nshift;s++){ | ||||||
|  | 	if ( ! converged[s] ) {  | ||||||
|  | 	  if (s==0){ | ||||||
|  | 	    axpy(ps[s],a,ps[s],r); | ||||||
|  | 	  } else{ | ||||||
|  | 	    RealD as =a *z[s][iz]*bs[s] /(z[s][1-iz]*b); | ||||||
|  | 	    axpby(ps[s],z[s][iz],as,r,ps[s]); | ||||||
|  | 	  } | ||||||
|  | 	} | ||||||
|  |       } | ||||||
|  |     AXPYTimer.Stop(); | ||||||
|  |      | ||||||
|  |       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)); | ||||||
|  |      | ||||||
|  |     MatrixTimer.Stop();   | ||||||
|  |  | ||||||
|  |     AXPYTimer.Start(); | ||||||
|  |       axpy(mmp,mass[0],p,mmp); | ||||||
|  |     AXPYTimer.Stop(); | ||||||
|  |       RealD rn = norm2(p); | ||||||
|  |       d += rn*mass[0]; | ||||||
|  |      | ||||||
|  |       bp=b; | ||||||
|  |       b=-cp/d; | ||||||
|  |      | ||||||
|  |     AXPYTimer.Start(); | ||||||
|  |       c=axpy_norm(r,b,mmp,r); | ||||||
|  |     AXPYTimer.Stop(); | ||||||
|  |  | ||||||
|  |       // Toggle the recurrence history | ||||||
|  |       bs[0] = b; | ||||||
|  |       iz = 1-iz; | ||||||
|  |     ShiftTimer.Start(); | ||||||
|  |       for(int s=1;s<nshift;s++){ | ||||||
|  | 	if((!converged[s])){ | ||||||
|  | 	  RealD z0 = z[s][1-iz]; | ||||||
|  | 	  RealD z1 = z[s][iz]; | ||||||
|  | 	  z[s][iz] = z0*z1*bp | ||||||
|  | 	    / (b*a*(z1-z0) + z1*bp*(1- (mass[s]-mass[0])*b));  | ||||||
|  | 	  bs[s] = b*z[s][iz]/z0; // NB sign  rel to Mike | ||||||
|  | 	} | ||||||
|  |       } | ||||||
|  |     ShiftTimer.Stop(); | ||||||
|  |      | ||||||
|  |       for(int s=0;s<nshift;s++){ | ||||||
|  | 	int ss = s; | ||||||
|  | 	// Scope for optimisation here in case of "single". | ||||||
|  | 	// Could load psi[0] and pull all ps[s] in. | ||||||
|  | 	//      if ( single ) ss=primary; | ||||||
|  | 	// Bandwith saving in single case is Ls * 3 -> 2+Ls, so ~ 3x saving | ||||||
|  | 	// Pipelined CG gain: | ||||||
|  | 	// | ||||||
|  | 	// New Kernel: Load r, vector of coeffs, vector of pointers ps | ||||||
|  | 	// New Kernel: Load psi[0], vector of coeffs, vector of pointers ps | ||||||
|  | 	// If can predict the coefficient bs then we can fuse these and avoid write reread cyce | ||||||
|  | 	//  on ps[s]. | ||||||
|  | 	// Before:  3 x npole  + 3 x npole | ||||||
|  | 	// After :  2 x npole (ps[s])        => 3x speed up of multishift CG. | ||||||
|  |        | ||||||
|  | 	if( (!converged[s]) ) {  | ||||||
|  | 	  axpy(psi[ss],-bs[s]*alpha[s],ps[s],psi[ss]); | ||||||
|  | 	} | ||||||
|  |       } | ||||||
|  |      | ||||||
|  |       // Convergence checks | ||||||
|  |       int all_converged = 1; | ||||||
|  |       for(int s=0;s<nshift;s++){ | ||||||
|  |        | ||||||
|  | 	if ( (!converged[s]) ){ | ||||||
|  | 	 | ||||||
|  | 	  RealD css  = c * z[s][iz]* z[s][iz]; | ||||||
|  | 	 | ||||||
|  | 	  if(css<rsq[s]){ | ||||||
|  | 	    if ( ! converged[s] ) | ||||||
|  | 	      std::cout<<GridLogMessage<<"ConjugateGradientMultiShift k="<<k<<" Shift "<<s<<" has converged"<<std::endl; | ||||||
|  | 	    converged[s]=1; | ||||||
|  | 	  } else { | ||||||
|  | 	    all_converged=0; | ||||||
|  | 	  } | ||||||
|  |  | ||||||
|  | 	} | ||||||
|  |       } | ||||||
|  |      | ||||||
|  |       if ( all_converged ){ | ||||||
|  |  | ||||||
|  |     SolverTimer.Stop(); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | 	std::cout<<GridLogMessage<< "CGMultiShift: All shifts have converged iteration "<<k<<std::endl; | ||||||
|  | 	std::cout<<GridLogMessage<< "CGMultiShift: Checking solutions"<<std::endl; | ||||||
|  |        | ||||||
|  | 	// Check answers  | ||||||
|  | 	for(int s=0; s < nshift; s++) {  | ||||||
|  | 	  Linop.HermOpAndNorm(psi[s],mmp,d,qq); | ||||||
|  | 	  axpy(tmp,mass[s],psi[s],mmp); | ||||||
|  | 	  axpy(r,-alpha[s],src,tmp); | ||||||
|  | 	  RealD rn = norm2(r); | ||||||
|  | 	  RealD cn = norm2(src); | ||||||
|  | 	  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; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |     | ||||||
|  |     } | ||||||
|  |     // ugly hack | ||||||
|  |     std::cout<<GridLogMessage<<"CG multi shift did not converge"<<std::endl; | ||||||
|  |     //  assert(0); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  | }; | ||||||
|  | NAMESPACE_END(Grid); | ||||||
|  | #endif | ||||||
							
								
								
									
										258
									
								
								Grid/algorithms/iterative/ConjugateGradientReliableUpdate.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										258
									
								
								Grid/algorithms/iterative/ConjugateGradientReliableUpdate.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,258 @@ | |||||||
|  | /************************************************************************************* | ||||||
|  |  | ||||||
|  |     Grid physics library, www.github.com/paboyle/Grid  | ||||||
|  |  | ||||||
|  |     Source file: ./lib/algorithms/iterative/ConjugateGradientReliableUpdate.h | ||||||
|  |  | ||||||
|  |     Copyright (C) 2015 | ||||||
|  |  | ||||||
|  | Author: Christopher Kelly <ckelly@phys.columbia.edu> | ||||||
|  |  | ||||||
|  |     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_CONJUGATE_GRADIENT_RELIABLE_UPDATE_H | ||||||
|  | #define GRID_CONJUGATE_GRADIENT_RELIABLE_UPDATE_H | ||||||
|  |  | ||||||
|  | NAMESPACE_BEGIN(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 ConjugateGradientReliableUpdate : public LinearFunction<FieldD> { | ||||||
|  | public: | ||||||
|  |   bool ErrorOnNoConverge;  // throw an assert when the CG fails to converge. | ||||||
|  |   // Defaults true. | ||||||
|  |   RealD Tolerance; | ||||||
|  |   Integer MaxIterations; | ||||||
|  |   Integer IterationsToComplete; //Number of iterations the CG took to finish. Filled in upon completion | ||||||
|  |   Integer ReliableUpdatesPerformed; | ||||||
|  |  | ||||||
|  |   bool DoFinalCleanup; //Final DP cleanup, defaults to true | ||||||
|  |   Integer IterationsToCleanup; //Final DP cleanup step iterations | ||||||
|  |      | ||||||
|  |   LinearOperatorBase<FieldF> &Linop_f; | ||||||
|  |   LinearOperatorBase<FieldD> &Linop_d; | ||||||
|  |   GridBase* SinglePrecGrid; | ||||||
|  |   RealD Delta; //reliable update parameter | ||||||
|  |  | ||||||
|  |   //Optional ability to switch to a different linear operator once the tolerance reaches a certain point. Useful for single/half -> single/single | ||||||
|  |   LinearOperatorBase<FieldF> *Linop_fallback; | ||||||
|  |   RealD fallback_transition_tol; | ||||||
|  |  | ||||||
|  |      | ||||||
|  |   ConjugateGradientReliableUpdate(RealD tol, Integer maxit, RealD _delta, GridBase* _sp_grid, LinearOperatorBase<FieldF> &_Linop_f, LinearOperatorBase<FieldD> &_Linop_d, bool err_on_no_conv = true) | ||||||
|  |     : Tolerance(tol), | ||||||
|  |       MaxIterations(maxit), | ||||||
|  |       Delta(_delta), | ||||||
|  |       Linop_f(_Linop_f), | ||||||
|  |       Linop_d(_Linop_d), | ||||||
|  |       SinglePrecGrid(_sp_grid), | ||||||
|  |       ErrorOnNoConverge(err_on_no_conv), | ||||||
|  |       DoFinalCleanup(true), | ||||||
|  |       Linop_fallback(NULL) | ||||||
|  |   {}; | ||||||
|  |  | ||||||
|  |   void setFallbackLinop(LinearOperatorBase<FieldF> &_Linop_fallback, const RealD _fallback_transition_tol){ | ||||||
|  |     Linop_fallback = &_Linop_fallback; | ||||||
|  |     fallback_transition_tol = _fallback_transition_tol;       | ||||||
|  |   } | ||||||
|  |      | ||||||
|  |   void operator()(const FieldD &src, FieldD &psi) { | ||||||
|  |     LinearOperatorBase<FieldF> *Linop_f_use = &Linop_f; | ||||||
|  |     bool using_fallback = false; | ||||||
|  |        | ||||||
|  |     psi.Checkerboard() = src.Checkerboard(); | ||||||
|  |     conformable(psi, src); | ||||||
|  |  | ||||||
|  |     RealD cp, c, a, d, b, ssq, qq, b_pred; | ||||||
|  |  | ||||||
|  |     FieldD p(src); | ||||||
|  |     FieldD mmp(src); | ||||||
|  |     FieldD r(src); | ||||||
|  |  | ||||||
|  |     // Initial residual computation & set up | ||||||
|  |     RealD guess = norm2(psi); | ||||||
|  |     assert(std::isnan(guess) == 0); | ||||||
|  |      | ||||||
|  |     Linop_d.HermOpAndNorm(psi, mmp, d, b); | ||||||
|  |      | ||||||
|  |     r = src - mmp; | ||||||
|  |     p = r; | ||||||
|  |  | ||||||
|  |     a = norm2(p); | ||||||
|  |     cp = a; | ||||||
|  |     ssq = norm2(src); | ||||||
|  |  | ||||||
|  |     std::cout << GridLogIterative << std::setprecision(4) << "ConjugateGradientReliableUpdate: guess " << guess << std::endl; | ||||||
|  |     std::cout << GridLogIterative << std::setprecision(4) << "ConjugateGradientReliableUpdate:   src " << ssq << std::endl; | ||||||
|  |     std::cout << GridLogIterative << std::setprecision(4) << "ConjugateGradientReliableUpdate:    mp " << d << std::endl; | ||||||
|  |     std::cout << GridLogIterative << std::setprecision(4) << "ConjugateGradientReliableUpdate:   mmp " << b << std::endl; | ||||||
|  |     std::cout << GridLogIterative << std::setprecision(4) << "ConjugateGradientReliableUpdate:  cp,r " << cp << std::endl; | ||||||
|  |     std::cout << GridLogIterative << std::setprecision(4) << "ConjugateGradientReliableUpdate:     p " << a << std::endl; | ||||||
|  |  | ||||||
|  |     RealD rsq = Tolerance * Tolerance * ssq; | ||||||
|  |  | ||||||
|  |     // Check if guess is really REALLY good :) | ||||||
|  |     if (cp <= rsq) { | ||||||
|  |       std::cout << GridLogMessage << "ConjugateGradientReliableUpdate guess was REALLY good\n"; | ||||||
|  |       std::cout << GridLogMessage << "\tComputed residual " << std::sqrt(cp / ssq)<<std::endl; | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     //Single prec initialization | ||||||
|  |     FieldF r_f(SinglePrecGrid); | ||||||
|  |     r_f.Checkerboard() = r.Checkerboard(); | ||||||
|  |     precisionChange(r_f, r); | ||||||
|  |  | ||||||
|  |     FieldF psi_f(r_f); | ||||||
|  |     psi_f = Zero(); | ||||||
|  |  | ||||||
|  |     FieldF p_f(r_f); | ||||||
|  |     FieldF mmp_f(r_f); | ||||||
|  |  | ||||||
|  |     RealD MaxResidSinceLastRelUp = cp; //initial residual     | ||||||
|  |      | ||||||
|  |     std::cout << GridLogIterative << std::setprecision(4) | ||||||
|  | 	      << "ConjugateGradient: k=0 residual " << cp << " target " << rsq << std::endl; | ||||||
|  |  | ||||||
|  |     GridStopWatch LinalgTimer; | ||||||
|  |     GridStopWatch MatrixTimer; | ||||||
|  |     GridStopWatch SolverTimer; | ||||||
|  |  | ||||||
|  |     SolverTimer.Start(); | ||||||
|  |     int k = 0; | ||||||
|  |     int l = 0; | ||||||
|  |      | ||||||
|  |     for (k = 1; k <= MaxIterations; k++) { | ||||||
|  |       c = cp; | ||||||
|  |  | ||||||
|  |       MatrixTimer.Start(); | ||||||
|  |       Linop_f_use->HermOpAndNorm(p_f, mmp_f, d, qq); | ||||||
|  |       MatrixTimer.Stop(); | ||||||
|  |  | ||||||
|  |       LinalgTimer.Start(); | ||||||
|  |  | ||||||
|  |       a = c / d; | ||||||
|  |       b_pred = a * (a * qq - d) / c; | ||||||
|  |  | ||||||
|  |       cp = axpy_norm(r_f, -a, mmp_f, r_f); | ||||||
|  |       b = cp / c; | ||||||
|  |  | ||||||
|  |       // Fuse these loops ; should be really easy | ||||||
|  |       psi_f = a * p_f + psi_f; | ||||||
|  |       //p_f = p_f * b + r_f; | ||||||
|  |  | ||||||
|  |       LinalgTimer.Stop(); | ||||||
|  |  | ||||||
|  |       std::cout << GridLogIterative << "ConjugateGradientReliableUpdate: Iteration " << k | ||||||
|  | 		<< " residual " << cp << " target " << rsq << 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; | ||||||
|  |  | ||||||
|  |       if(cp > MaxResidSinceLastRelUp){ | ||||||
|  | 	std::cout << GridLogIterative << "ConjugateGradientReliableUpdate: updating MaxResidSinceLastRelUp : " << MaxResidSinceLastRelUp << " -> " << cp << std::endl; | ||||||
|  | 	MaxResidSinceLastRelUp = cp; | ||||||
|  |       } | ||||||
|  | 	   | ||||||
|  |       // Stopping condition | ||||||
|  |       if (cp <= rsq) { | ||||||
|  | 	//Although not written in the paper, I assume that I have to add on the final solution | ||||||
|  | 	precisionChange(mmp, psi_f); | ||||||
|  | 	psi = psi + mmp; | ||||||
|  | 	 | ||||||
|  | 	 | ||||||
|  | 	SolverTimer.Stop(); | ||||||
|  | 	Linop_d.HermOpAndNorm(psi, mmp, d, qq); | ||||||
|  | 	p = mmp - src; | ||||||
|  |  | ||||||
|  | 	RealD srcnorm = std::sqrt(norm2(src)); | ||||||
|  | 	RealD resnorm = std::sqrt(norm2(p)); | ||||||
|  | 	RealD true_residual = resnorm / srcnorm; | ||||||
|  |  | ||||||
|  | 	std::cout << GridLogMessage << "ConjugateGradientReliableUpdate Converged on iteration " << k << " after " << l << " reliable updates" << std::endl; | ||||||
|  | 	std::cout << GridLogMessage << "\tComputed residual " << std::sqrt(cp / ssq)<<std::endl; | ||||||
|  | 	std::cout << GridLogMessage << "\tTrue residual " << true_residual<<std::endl; | ||||||
|  | 	std::cout << GridLogMessage << "\tTarget " << Tolerance << 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 << "\tLinalg     " << LinalgTimer.Elapsed() <<std::endl; | ||||||
|  |  | ||||||
|  | 	IterationsToComplete = k;	 | ||||||
|  | 	ReliableUpdatesPerformed = l; | ||||||
|  | 	   | ||||||
|  | 	if(DoFinalCleanup){ | ||||||
|  | 	  //Do a final CG to cleanup | ||||||
|  | 	  std::cout << GridLogMessage << "ConjugateGradientReliableUpdate performing final cleanup.\n"; | ||||||
|  | 	  ConjugateGradient<FieldD> CG(Tolerance,MaxIterations); | ||||||
|  | 	  CG.ErrorOnNoConverge = ErrorOnNoConverge; | ||||||
|  | 	  CG(Linop_d,src,psi); | ||||||
|  | 	  IterationsToCleanup = CG.IterationsToComplete; | ||||||
|  | 	} | ||||||
|  | 	else if (ErrorOnNoConverge) assert(true_residual / Tolerance < 10000.0); | ||||||
|  |  | ||||||
|  | 	std::cout << GridLogMessage << "ConjugateGradientReliableUpdate complete.\n"; | ||||||
|  | 	return; | ||||||
|  |       } | ||||||
|  |       else if(cp < Delta * MaxResidSinceLastRelUp) { //reliable update | ||||||
|  | 	std::cout << GridLogMessage << "ConjugateGradientReliableUpdate " | ||||||
|  | 		  << cp << "(residual) < " << Delta << "(Delta) * " << MaxResidSinceLastRelUp << "(MaxResidSinceLastRelUp) on iteration " << k << " : performing reliable update\n"; | ||||||
|  | 	precisionChange(mmp, psi_f); | ||||||
|  | 	psi = psi + mmp; | ||||||
|  |  | ||||||
|  | 	Linop_d.HermOpAndNorm(psi, mmp, d, qq); | ||||||
|  | 	r = src - mmp; | ||||||
|  |  | ||||||
|  | 	psi_f = Zero(); | ||||||
|  | 	precisionChange(r_f, r); | ||||||
|  | 	cp = norm2(r); | ||||||
|  | 	MaxResidSinceLastRelUp = cp; | ||||||
|  |  | ||||||
|  | 	b = cp/c; | ||||||
|  | 	   | ||||||
|  | 	std::cout << GridLogMessage << "ConjugateGradientReliableUpdate new residual " << cp << std::endl; | ||||||
|  | 	   | ||||||
|  | 	l = l+1; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       p_f = p_f * b + r_f; //update search vector after reliable update appears to help convergence | ||||||
|  |  | ||||||
|  |       if(!using_fallback && Linop_fallback != NULL && cp < fallback_transition_tol){ | ||||||
|  | 	std::cout << GridLogMessage << "ConjugateGradientReliableUpdate switching to fallback linear operator on iteration " << k << " at residual " << cp << std::endl; | ||||||
|  | 	Linop_f_use = Linop_fallback; | ||||||
|  | 	using_fallback = true; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  | 	 | ||||||
|  |     } | ||||||
|  |     std::cout << GridLogMessage << "ConjugateGradientReliableUpdate did NOT converge" | ||||||
|  | 	      << std::endl; | ||||||
|  |        | ||||||
|  |     if (ErrorOnNoConverge) assert(0); | ||||||
|  |     IterationsToComplete = k; | ||||||
|  |     ReliableUpdatesPerformed = l;       | ||||||
|  |   }     | ||||||
|  | }; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | NAMESPACE_END(Grid); | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | #endif | ||||||
							
								
								
									
										113
									
								
								Grid/algorithms/iterative/ConjugateResidual.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										113
									
								
								Grid/algorithms/iterative/ConjugateResidual.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,113 @@ | |||||||
|  | /************************************************************************************* | ||||||
|  |  | ||||||
|  |     Grid physics library, www.github.com/paboyle/Grid  | ||||||
|  |  | ||||||
|  |     Source file: ./lib/algorithms/iterative/ConjugateResidual.h | ||||||
|  |  | ||||||
|  |     Copyright (C) 2015 | ||||||
|  |  | ||||||
|  | Author: Azusa Yamaguchi <ayamaguc@staffmail.ed.ac.uk> | ||||||
|  | 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_CONJUGATE_RESIDUAL_H | ||||||
|  | #define GRID_CONJUGATE_RESIDUAL_H | ||||||
|  |  | ||||||
|  | NAMESPACE_BEGIN(Grid); | ||||||
|  |  | ||||||
|  | ///////////////////////////////////////////////////////////// | ||||||
|  | // Base classes for iterative processes based on operators | ||||||
|  | // single input vec, single output vec. | ||||||
|  | ///////////////////////////////////////////////////////////// | ||||||
|  |  | ||||||
|  | template<class Field>  | ||||||
|  | class ConjugateResidual : public OperatorFunction<Field> { | ||||||
|  | public:                                                 | ||||||
|  |   using OperatorFunction<Field>::operator(); | ||||||
|  |  | ||||||
|  |   RealD   Tolerance; | ||||||
|  |   Integer MaxIterations; | ||||||
|  |   int verbose; | ||||||
|  |  | ||||||
|  |   ConjugateResidual(RealD tol,Integer maxit) : Tolerance(tol), MaxIterations(maxit) {  | ||||||
|  |     verbose=0; | ||||||
|  |   }; | ||||||
|  |  | ||||||
|  |   void operator() (LinearOperatorBase<Field> &Linop,const Field &src, Field &psi){ | ||||||
|  |  | ||||||
|  |     RealD a, b; // c, d; | ||||||
|  |     RealD cp, ssq,rsq; | ||||||
|  |        | ||||||
|  |     RealD rAr, rAAr, rArp; | ||||||
|  |     RealD pAp, pAAp; | ||||||
|  |  | ||||||
|  |     GridBase *grid = src.Grid(); | ||||||
|  |     psi=Zero(); | ||||||
|  |     Field r(grid),  p(grid), Ap(grid), Ar(grid); | ||||||
|  |        | ||||||
|  |     r=src; | ||||||
|  |     p=src; | ||||||
|  |  | ||||||
|  |     Linop.HermOpAndNorm(p,Ap,pAp,pAAp); | ||||||
|  |     Linop.HermOpAndNorm(r,Ar,rAr,rAAr); | ||||||
|  |  | ||||||
|  |     cp =norm2(r); | ||||||
|  |     ssq=norm2(src); | ||||||
|  |     rsq=Tolerance*Tolerance*ssq; | ||||||
|  |  | ||||||
|  |     if (verbose) std::cout<<GridLogMessage<<"ConjugateResidual: iteration " <<0<<" residual "<<cp<< " target"<< rsq<<std::endl; | ||||||
|  |  | ||||||
|  |     for(int k=1;k<MaxIterations;k++){ | ||||||
|  |  | ||||||
|  |       a = rAr/pAAp; | ||||||
|  |  | ||||||
|  |       axpy(psi,a,p,psi); | ||||||
|  |  | ||||||
|  |       cp = axpy_norm(r,-a,Ap,r); | ||||||
|  |  | ||||||
|  |       rArp=rAr; | ||||||
|  |  | ||||||
|  |       Linop.HermOpAndNorm(r,Ar,rAr,rAAr); | ||||||
|  |  | ||||||
|  |       b   =rAr/rArp; | ||||||
|  |   | ||||||
|  |       axpy(p,b,p,r); | ||||||
|  |       pAAp=axpy_norm(Ap,b,Ap,Ar); | ||||||
|  | 	 | ||||||
|  |       if(verbose) std::cout<<GridLogMessage<<"ConjugateResidual: iteration " <<k<<" residual "<<cp<< " target"<< rsq<<std::endl; | ||||||
|  |  | ||||||
|  |       if(cp<rsq) { | ||||||
|  | 	Linop.HermOp(psi,Ap); | ||||||
|  | 	axpy(r,-1.0,src,Ap); | ||||||
|  | 	RealD true_resid = norm2(r)/ssq; | ||||||
|  | 	std::cout<<GridLogMessage<<"ConjugateResidual: Converged on iteration " <<k | ||||||
|  | 		 << " computed residual "<<std::sqrt(cp/ssq) | ||||||
|  | 		 << " true residual "<<std::sqrt(true_resid) | ||||||
|  | 		 << " target "       <<Tolerance <<std::endl; | ||||||
|  | 	return; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     std::cout<<GridLogMessage<<"ConjugateResidual did NOT converge"<<std::endl; | ||||||
|  |     assert(0); | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  | NAMESPACE_END(Grid); | ||||||
|  | #endif | ||||||
							
								
								
									
										108
									
								
								Grid/algorithms/iterative/Deflation.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										108
									
								
								Grid/algorithms/iterative/Deflation.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,108 @@ | |||||||
|  |     /************************************************************************************* | ||||||
|  |  | ||||||
|  |     Grid physics library, www.github.com/paboyle/Grid  | ||||||
|  |  | ||||||
|  |     Source file: ./lib/algorithms/iterative/ImplicitlyRestartedLanczos.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_DEFLATION_H | ||||||
|  | #define GRID_DEFLATION_H | ||||||
|  |  | ||||||
|  | namespace Grid {  | ||||||
|  |  | ||||||
|  | template<class Field> | ||||||
|  | class ZeroGuesser: public LinearFunction<Field> { | ||||||
|  | public: | ||||||
|  |     virtual void operator()(const Field &src, Field &guess) { guess = Zero(); }; | ||||||
|  | }; | ||||||
|  | template<class Field> | ||||||
|  | class DoNothingGuesser: public LinearFunction<Field> { | ||||||
|  | public: | ||||||
|  |   virtual void operator()(const Field &src, Field &guess) {  }; | ||||||
|  | }; | ||||||
|  | template<class Field> | ||||||
|  | class SourceGuesser: public LinearFunction<Field> { | ||||||
|  | public: | ||||||
|  |   virtual void operator()(const Field &src, Field &guess) { guess = src; }; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | //////////////////////////////// | ||||||
|  | // Fine grid deflation | ||||||
|  | //////////////////////////////// | ||||||
|  | template<class Field> | ||||||
|  | class DeflatedGuesser: public LinearFunction<Field> { | ||||||
|  | private: | ||||||
|  |   const std::vector<Field> &evec; | ||||||
|  |   const std::vector<RealD> &eval; | ||||||
|  |  | ||||||
|  | public: | ||||||
|  |  | ||||||
|  |   DeflatedGuesser(const std::vector<Field> & _evec,const std::vector<RealD> & _eval) : evec(_evec), eval(_eval) {}; | ||||||
|  |  | ||||||
|  |   virtual void operator()(const Field &src,Field &guess) { | ||||||
|  |     guess = Zero(); | ||||||
|  |     assert(evec.size()==eval.size()); | ||||||
|  |     auto N = evec.size(); | ||||||
|  |     for (int i=0;i<N;i++) { | ||||||
|  |       const Field& tmp = evec[i]; | ||||||
|  |       axpy(guess,TensorRemove(innerProduct(tmp,src)) / eval[i],tmp,guess); | ||||||
|  |     } | ||||||
|  |     guess.Checkerboard() = src.Checkerboard(); | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | template<class FineField, class CoarseField> | ||||||
|  | class LocalCoherenceDeflatedGuesser: public LinearFunction<FineField> { | ||||||
|  | private: | ||||||
|  |   const std::vector<FineField>   &subspace; | ||||||
|  |   const std::vector<CoarseField> &evec_coarse; | ||||||
|  |   const std::vector<RealD>       &eval_coarse; | ||||||
|  | public: | ||||||
|  |    | ||||||
|  |   LocalCoherenceDeflatedGuesser(const std::vector<FineField>   &_subspace, | ||||||
|  | 				const std::vector<CoarseField> &_evec_coarse, | ||||||
|  | 				const std::vector<RealD>       &_eval_coarse) | ||||||
|  |     : subspace(_subspace),  | ||||||
|  |       evec_coarse(_evec_coarse),  | ||||||
|  |       eval_coarse(_eval_coarse)   | ||||||
|  |   { | ||||||
|  |   } | ||||||
|  |    | ||||||
|  |   void operator()(const FineField &src,FineField &guess) {  | ||||||
|  |     int N = (int)evec_coarse.size(); | ||||||
|  |     CoarseField src_coarse(evec_coarse[0].Grid()); | ||||||
|  |     CoarseField guess_coarse(evec_coarse[0].Grid());    guess_coarse = Zero(); | ||||||
|  |     blockProject(src_coarse,src,subspace);     | ||||||
|  |     for (int i=0;i<N;i++) { | ||||||
|  |       const CoarseField & tmp = evec_coarse[i]; | ||||||
|  |       axpy(guess_coarse,TensorRemove(innerProduct(tmp,src_coarse)) / eval_coarse[i],tmp,guess_coarse); | ||||||
|  |     } | ||||||
|  |     blockPromote(guess_coarse,guess,subspace); | ||||||
|  |     guess.Checkerboard() = src.Checkerboard(); | ||||||
|  |   }; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | } | ||||||
|  | #endif | ||||||
| @@ -0,0 +1,258 @@ | |||||||
|  | /************************************************************************************* | ||||||
|  |  | ||||||
|  | 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: | ||||||
|  |   using OperatorFunction<Field>::operator(); | ||||||
|  |  | ||||||
|  |   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<ComplexD> y; | ||||||
|  |   std::vector<ComplexD> gamma; | ||||||
|  |   std::vector<ComplexD> c; | ||||||
|  |   std::vector<ComplexD> 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 = 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 - ComplexD(H(iter, i)) * v[i]; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     H(iter, iter + 1) = sqrt(norm2(w)); | ||||||
|  |     v[iter + 1] = ComplexD(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] * ComplexD(H(iter, i)) + c[i] * ComplexD(H(iter, i + 1)); | ||||||
|  |       H(iter, i)     = conjugate(c[i]) * ComplexD(H(iter, i)) + conjugate(s[i]) * ComplexD(H(iter, i + 1)); | ||||||
|  |       H(iter, i + 1) = tmp; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // Compute new Givens Rotation | ||||||
|  |     auto 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]     = conjugate(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] - ComplexD(H(k, i)) * y[k]; | ||||||
|  |       y[i] = y[i] / ComplexD(H(i, i)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     for (int i = 0; i <= iter; i++) | ||||||
|  |       psi = psi + z[i] * y[i]; | ||||||
|  |     CompSolutionTimer.Stop(); | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  | } | ||||||
|  | #endif | ||||||
							
								
								
									
										256
									
								
								Grid/algorithms/iterative/FlexibleGeneralisedMinimalResidual.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										256
									
								
								Grid/algorithms/iterative/FlexibleGeneralisedMinimalResidual.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,256 @@ | |||||||
|  | /************************************************************************************* | ||||||
|  |  | ||||||
|  | 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: | ||||||
|  |   using OperatorFunction<Field>::operator(); | ||||||
|  |  | ||||||
|  |   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<ComplexD> y; | ||||||
|  |   std::vector<ComplexD> gamma; | ||||||
|  |   std::vector<ComplexD> c; | ||||||
|  |   std::vector<ComplexD> 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 = 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 - ComplexD(H(iter, i)) * v[i]; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     H(iter, iter + 1) = sqrt(norm2(w)); | ||||||
|  |     v[iter + 1] = ComplexD(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] * ComplexD(H(iter, i)) + c[i] * ComplexD(H(iter, i + 1)); | ||||||
|  |       H(iter, i)     = conjugate(c[i]) * ComplexD(H(iter, i)) + conjugate(s[i]) * ComplexD(H(iter, i + 1)); | ||||||
|  |       H(iter, i + 1) = tmp; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // Compute new Givens Rotation | ||||||
|  |     auto 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]     = conjugate(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] - ComplexD(H(k, i)) * y[k]; | ||||||
|  |       y[i] = y[i] / ComplexD(H(i, i)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     for (int i = 0; i <= iter; i++) | ||||||
|  |       psi = psi + z[i] * y[i]; | ||||||
|  |     CompSolutionTimer.Stop(); | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  | } | ||||||
|  | #endif | ||||||
							
								
								
									
										244
									
								
								Grid/algorithms/iterative/GeneralisedMinimalResidual.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										244
									
								
								Grid/algorithms/iterative/GeneralisedMinimalResidual.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,244 @@ | |||||||
|  | /************************************************************************************* | ||||||
|  |  | ||||||
|  | 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: | ||||||
|  |   using OperatorFunction<Field>::operator(); | ||||||
|  |  | ||||||
|  |   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<ComplexD> y; | ||||||
|  |   std::vector<ComplexD> gamma; | ||||||
|  |   std::vector<ComplexD> c; | ||||||
|  |   std::vector<ComplexD> 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 = 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 - ComplexD(H(iter, i)) * v[i]; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     H(iter, iter + 1) = sqrt(norm2(w)); | ||||||
|  |     v[iter + 1] = ComplexD(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] * ComplexD(H(iter, i)) + c[i] * ComplexD(H(iter, i + 1)); | ||||||
|  |       H(iter, i)     = conjugate(c[i]) * ComplexD(H(iter, i)) + conjugate(s[i]) * ComplexD(H(iter, i + 1)); | ||||||
|  |       H(iter, i + 1) = tmp; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // Compute new Givens Rotation | ||||||
|  |     auto 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]     = conjugate(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] - ComplexD(H(k, i)) * y[k]; | ||||||
|  |       y[i] = y[i] / ComplexD(H(i, i)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     for (int i = 0; i <= iter; i++) | ||||||
|  |       psi = psi + v[i] * y[i]; | ||||||
|  |     CompSolutionTimer.Stop(); | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  | } | ||||||
|  | #endif | ||||||
							
								
								
									
										863
									
								
								Grid/algorithms/iterative/ImplicitlyRestartedLanczos.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										863
									
								
								Grid/algorithms/iterative/ImplicitlyRestartedLanczos.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,863 @@ | |||||||
|  |     /************************************************************************************* | ||||||
|  |  | ||||||
|  |     Grid physics library, www.github.com/paboyle/Grid  | ||||||
|  |  | ||||||
|  |     Source file: ./lib/algorithms/iterative/ImplicitlyRestartedLanczos.h | ||||||
|  |  | ||||||
|  |     Copyright (C) 2015 | ||||||
|  |  | ||||||
|  | Author: Peter Boyle <paboyle@ph.ed.ac.uk> | ||||||
|  | Author: paboyle <paboyle@ph.ed.ac.uk> | ||||||
|  | Author: Chulwoo Jung <chulwoo@bnl.gov> | ||||||
|  | Author: Christoph Lehner <clehner@bnl.gov> | ||||||
|  |  | ||||||
|  |     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_BIRL_H | ||||||
|  | #define GRID_BIRL_H | ||||||
|  |  | ||||||
|  | #include <string.h> //memset | ||||||
|  | //#include <zlib.h> | ||||||
|  | #include <sys/stat.h> | ||||||
|  |  | ||||||
|  | NAMESPACE_BEGIN(Grid);  | ||||||
|  |  | ||||||
|  |   //////////////////////////////////////////////////////// | ||||||
|  |   // Move following 100 LOC to lattice/Lattice_basis.h | ||||||
|  |   //////////////////////////////////////////////////////// | ||||||
|  | template<class Field> | ||||||
|  | void basisOrthogonalize(std::vector<Field> &basis,Field &w,int k)  | ||||||
|  | { | ||||||
|  |   for(int j=0; j<k; ++j){ | ||||||
|  |     auto ip = innerProduct(basis[j],w); | ||||||
|  |     w = w - ip*basis[j]; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | template<class Field> | ||||||
|  | void basisRotate(std::vector<Field> &basis,Eigen::MatrixXd& Qt,int j0, int j1, int k0,int k1,int Nm)  | ||||||
|  | { | ||||||
|  |   typedef decltype(basis[0].View()) View; | ||||||
|  |   auto tmp_v = basis[0].View(); | ||||||
|  |   std::vector<View> basis_v(basis.size(),tmp_v); | ||||||
|  |   typedef typename Field::vector_object vobj; | ||||||
|  |   GridBase* grid = basis[0].Grid(); | ||||||
|  |        | ||||||
|  |   for(int k=0;k<basis.size();k++){ | ||||||
|  |     basis_v[k] = basis[k].View(); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   thread_region | ||||||
|  |   { | ||||||
|  |     std::vector < vobj , commAllocator<vobj> > B(Nm); // Thread private | ||||||
|  |     thread_for_in_region(ss, grid->oSites(),{ | ||||||
|  |       for(int j=j0; j<j1; ++j) B[j]=0.; | ||||||
|  |        | ||||||
|  |       for(int j=j0; j<j1; ++j){ | ||||||
|  | 	for(int k=k0; k<k1; ++k){ | ||||||
|  | 	  B[j] +=Qt(j,k) * basis_v[k][ss]; | ||||||
|  | 	} | ||||||
|  |       } | ||||||
|  |       for(int j=j0; j<j1; ++j){ | ||||||
|  | 	basis_v[j][ss] = B[j]; | ||||||
|  |       } | ||||||
|  |     }); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Extract a single rotated vector | ||||||
|  | template<class Field> | ||||||
|  | void basisRotateJ(Field &result,std::vector<Field> &basis,Eigen::MatrixXd& Qt,int j, int k0,int k1,int Nm)  | ||||||
|  | { | ||||||
|  |   typedef typename Field::vector_object vobj; | ||||||
|  |   GridBase* grid = basis[0].Grid(); | ||||||
|  |  | ||||||
|  |   result.Checkerboard() = basis[0].Checkerboard(); | ||||||
|  |   auto result_v=result.View(); | ||||||
|  |   thread_for(ss, grid->oSites(),{ | ||||||
|  |     vobj B = Zero(); | ||||||
|  |     for(int k=k0; k<k1; ++k){ | ||||||
|  |       auto basis_k = basis[k].View(); | ||||||
|  |       B +=Qt(j,k) * basis_k[ss]; | ||||||
|  |     } | ||||||
|  |     result_v[ss] = B; | ||||||
|  |   }); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | template<class Field> | ||||||
|  | void basisReorderInPlace(std::vector<Field> &_v,std::vector<RealD>& sort_vals, std::vector<int>& idx)  | ||||||
|  | { | ||||||
|  |   int vlen = idx.size(); | ||||||
|  |  | ||||||
|  |   assert(vlen>=1); | ||||||
|  |   assert(vlen<=sort_vals.size()); | ||||||
|  |   assert(vlen<=_v.size()); | ||||||
|  |  | ||||||
|  |   for (size_t i=0;i<vlen;i++) { | ||||||
|  |  | ||||||
|  |     if (idx[i] != i) { | ||||||
|  |  | ||||||
|  |       ////////////////////////////////////// | ||||||
|  |       // idx[i] is a table of desired sources giving a permutation. | ||||||
|  |       // Swap v[i] with v[idx[i]]. | ||||||
|  |       // Find  j>i for which _vnew[j] = _vold[i], | ||||||
|  |       // track the move idx[j] => idx[i] | ||||||
|  |       // track the move idx[i] => i | ||||||
|  |       ////////////////////////////////////// | ||||||
|  |       size_t j; | ||||||
|  |       for (j=i;j<idx.size();j++) | ||||||
|  | 	if (idx[j]==i) | ||||||
|  | 	  break; | ||||||
|  |  | ||||||
|  |       assert(idx[i] > i);     assert(j!=idx.size());      assert(idx[j]==i); | ||||||
|  |  | ||||||
|  |       swap(_v[i],_v[idx[i]]); // should use vector move constructor, no data copy | ||||||
|  |       std::swap(sort_vals[i],sort_vals[idx[i]]); | ||||||
|  |  | ||||||
|  |       idx[j] = idx[i]; | ||||||
|  |       idx[i] = i; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | inline std::vector<int> basisSortGetIndex(std::vector<RealD>& sort_vals)  | ||||||
|  | { | ||||||
|  |   std::vector<int> idx(sort_vals.size()); | ||||||
|  |   std::iota(idx.begin(), idx.end(), 0); | ||||||
|  |  | ||||||
|  |   // sort indexes based on comparing values in v | ||||||
|  |   std::sort(idx.begin(), idx.end(), [&sort_vals](int i1, int i2) { | ||||||
|  |     return ::fabs(sort_vals[i1]) < ::fabs(sort_vals[i2]); | ||||||
|  |   }); | ||||||
|  |   return idx; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | template<class Field> | ||||||
|  | void basisSortInPlace(std::vector<Field> & _v,std::vector<RealD>& sort_vals, bool reverse)  | ||||||
|  | { | ||||||
|  |   std::vector<int> idx = basisSortGetIndex(sort_vals); | ||||||
|  |   if (reverse) | ||||||
|  |     std::reverse(idx.begin(), idx.end()); | ||||||
|  |    | ||||||
|  |   basisReorderInPlace(_v,sort_vals,idx); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // PAB: faster to compute the inner products first then fuse loops. | ||||||
|  | // If performance critical can improve. | ||||||
|  | template<class Field> | ||||||
|  | void basisDeflate(const std::vector<Field> &_v,const std::vector<RealD>& eval,const Field& src_orig,Field& result) { | ||||||
|  |   result = Zero(); | ||||||
|  |   assert(_v.size()==eval.size()); | ||||||
|  |   int N = (int)_v.size(); | ||||||
|  |   for (int i=0;i<N;i++) { | ||||||
|  |     Field& tmp = _v[i]; | ||||||
|  |     axpy(result,TensorRemove(innerProduct(tmp,src_orig)) / eval[i],tmp,result); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | ///////////////////////////////////////////////////////////// | ||||||
|  | // Implicitly restarted lanczos | ||||||
|  | ///////////////////////////////////////////////////////////// | ||||||
|  | template<class Field> class ImplicitlyRestartedLanczosTester  | ||||||
|  | { | ||||||
|  |  public: | ||||||
|  |   virtual int TestConvergence(int j,RealD resid,Field &evec, RealD &eval,RealD evalMaxApprox)=0; | ||||||
|  |   virtual int ReconstructEval(int j,RealD resid,Field &evec, RealD &eval,RealD evalMaxApprox)=0; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | enum IRLdiagonalisation {  | ||||||
|  |   IRLdiagonaliseWithDSTEGR, | ||||||
|  |   IRLdiagonaliseWithQR, | ||||||
|  |   IRLdiagonaliseWithEigen | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | template<class Field> class ImplicitlyRestartedLanczosHermOpTester  : public ImplicitlyRestartedLanczosTester<Field> | ||||||
|  | { | ||||||
|  |  public: | ||||||
|  |  | ||||||
|  |   LinearFunction<Field>       &_HermOp; | ||||||
|  |   ImplicitlyRestartedLanczosHermOpTester(LinearFunction<Field> &HermOp) : _HermOp(HermOp)  {  }; | ||||||
|  |   int ReconstructEval(int j,RealD resid,Field &B, RealD &eval,RealD evalMaxApprox) | ||||||
|  |   { | ||||||
|  |     return TestConvergence(j,resid,B,eval,evalMaxApprox); | ||||||
|  |   } | ||||||
|  |   int TestConvergence(int j,RealD eresid,Field &B, RealD &eval,RealD evalMaxApprox) | ||||||
|  |   { | ||||||
|  |     Field v(B); | ||||||
|  |     RealD eval_poly = eval; | ||||||
|  |     // Apply operator | ||||||
|  |     _HermOp(B,v); | ||||||
|  |  | ||||||
|  |     RealD vnum = real(innerProduct(B,v)); // HermOp. | ||||||
|  |     RealD vden = norm2(B); | ||||||
|  |     RealD vv0  = norm2(v); | ||||||
|  |     eval   = vnum/vden; | ||||||
|  |     v -= eval*B; | ||||||
|  |  | ||||||
|  |     RealD vv = norm2(v) / ::pow(evalMaxApprox,2.0); | ||||||
|  |  | ||||||
|  |     std::cout.precision(13); | ||||||
|  |     std::cout<<GridLogIRL  << "[" << std::setw(3)<<j<<"] " | ||||||
|  | 	     <<"eval = "<<std::setw(25)<< eval << " (" << eval_poly << ")" | ||||||
|  | 	     <<" |H B[i] - eval[i]B[i]|^2 / evalMaxApprox^2 " << std::setw(25) << vv | ||||||
|  | 	     <<std::endl; | ||||||
|  |  | ||||||
|  |     int conv=0; | ||||||
|  |     if( (vv<eresid*eresid) ) conv = 1; | ||||||
|  |  | ||||||
|  |     return conv; | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | template<class Field>  | ||||||
|  | class ImplicitlyRestartedLanczos { | ||||||
|  |  private: | ||||||
|  |   const RealD small = 1.0e-8; | ||||||
|  |   int MaxIter; | ||||||
|  |   int MinRestart; // Minimum number of restarts; only check for convergence after | ||||||
|  |   int Nstop;   // Number of evecs checked for convergence | ||||||
|  |   int Nk;      // Number of converged sought | ||||||
|  |   //  int Np;      // Np -- Number of spare vecs in krylov space //  == Nm - Nk | ||||||
|  |   int Nm;      // Nm -- total number of vectors | ||||||
|  |   IRLdiagonalisation diagonalisation; | ||||||
|  |   int orth_period; | ||||||
|  |      | ||||||
|  |   RealD OrthoTime; | ||||||
|  |   RealD eresid, betastp; | ||||||
|  |   //////////////////////////////// | ||||||
|  |   // Embedded objects | ||||||
|  |   //////////////////////////////// | ||||||
|  |   LinearFunction<Field>       &_PolyOp; | ||||||
|  |   LinearFunction<Field>       &_HermOp; | ||||||
|  |   ImplicitlyRestartedLanczosTester<Field> &_Tester; | ||||||
|  |   // Default tester provided (we need a ref to something in default case) | ||||||
|  |   ImplicitlyRestartedLanczosHermOpTester<Field> SimpleTester; | ||||||
|  |   ///////////////////////// | ||||||
|  |   // Constructor | ||||||
|  |   ///////////////////////// | ||||||
|  |    | ||||||
|  | public:        | ||||||
|  |  | ||||||
|  |   ////////////////////////////////////////////////////////////////// | ||||||
|  |   // PAB: | ||||||
|  |   ////////////////////////////////////////////////////////////////// | ||||||
|  |   // Too many options  & knobs.  | ||||||
|  |   // Eliminate: | ||||||
|  |   //   orth_period | ||||||
|  |   //   betastp | ||||||
|  |   //   MinRestart | ||||||
|  |   // | ||||||
|  |   // Do we really need orth_period | ||||||
|  |   // What is the theoretical basis & guarantees of betastp ? | ||||||
|  |   // Nstop=Nk viable? | ||||||
|  |   // MinRestart avoidable with new convergence test? | ||||||
|  |   // Could cut to PolyOp, HermOp, Tester, Nk, Nm, resid, maxiter (+diagonalisation) | ||||||
|  |   // HermOp could be eliminated if we dropped the Power method for max eval. | ||||||
|  |   // -- also: The eval, eval2, eval2_copy stuff is still unnecessarily unclear | ||||||
|  |   ////////////////////////////////////////////////////////////////// | ||||||
|  |  ImplicitlyRestartedLanczos(LinearFunction<Field> & PolyOp, | ||||||
|  | 			    LinearFunction<Field> & HermOp, | ||||||
|  | 			    ImplicitlyRestartedLanczosTester<Field> & Tester, | ||||||
|  | 			    int _Nstop, // sought vecs | ||||||
|  | 			    int _Nk, // sought vecs | ||||||
|  | 			    int _Nm, // spare vecs | ||||||
|  | 			    RealD _eresid, // resid in lmdue deficit  | ||||||
|  | 			    int _MaxIter, // Max iterations | ||||||
|  | 			    RealD _betastp=0.0, // if beta(k) < betastp: converged | ||||||
|  | 			    int _MinRestart=1, int _orth_period = 1, | ||||||
|  | 			    IRLdiagonalisation _diagonalisation= IRLdiagonaliseWithEigen) : | ||||||
|  |     SimpleTester(HermOp), _PolyOp(PolyOp),      _HermOp(HermOp), _Tester(Tester), | ||||||
|  |     Nstop(_Nstop)  ,      Nk(_Nk),      Nm(_Nm), | ||||||
|  |     eresid(_eresid),      betastp(_betastp), | ||||||
|  |     MaxIter(_MaxIter)  ,      MinRestart(_MinRestart), | ||||||
|  |     orth_period(_orth_period), diagonalisation(_diagonalisation)  { }; | ||||||
|  |  | ||||||
|  |     ImplicitlyRestartedLanczos(LinearFunction<Field> & PolyOp, | ||||||
|  | 			       LinearFunction<Field> & HermOp, | ||||||
|  | 			       int _Nstop, // sought vecs | ||||||
|  | 			       int _Nk, // sought vecs | ||||||
|  | 			       int _Nm, // spare vecs | ||||||
|  | 			       RealD _eresid, // resid in lmdue deficit  | ||||||
|  | 			       int _MaxIter, // Max iterations | ||||||
|  | 			       RealD _betastp=0.0, // if beta(k) < betastp: converged | ||||||
|  | 			       int _MinRestart=1, int _orth_period = 1, | ||||||
|  | 			       IRLdiagonalisation _diagonalisation= IRLdiagonaliseWithEigen) : | ||||||
|  |     SimpleTester(HermOp),  _PolyOp(PolyOp),      _HermOp(HermOp), _Tester(SimpleTester), | ||||||
|  |     Nstop(_Nstop)  ,      Nk(_Nk),      Nm(_Nm), | ||||||
|  |     eresid(_eresid),      betastp(_betastp), | ||||||
|  |     MaxIter(_MaxIter)  ,      MinRestart(_MinRestart), | ||||||
|  |     orth_period(_orth_period), diagonalisation(_diagonalisation)  { }; | ||||||
|  |  | ||||||
|  |   //////////////////////////////// | ||||||
|  |   // Helpers | ||||||
|  |   //////////////////////////////// | ||||||
|  |   template<typename T>  static RealD normalise(T& v)  | ||||||
|  |   { | ||||||
|  |     RealD nn = norm2(v); | ||||||
|  |     nn = std::sqrt(nn); | ||||||
|  |     v = v * (1.0/nn); | ||||||
|  |     return nn; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   void orthogonalize(Field& w, std::vector<Field>& evec,int k) | ||||||
|  |   { | ||||||
|  |     OrthoTime-=usecond()/1e6; | ||||||
|  |     basisOrthogonalize(evec,w,k); | ||||||
|  |     normalise(w); | ||||||
|  |     OrthoTime+=usecond()/1e6; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  | /* Rudy Arthur's thesis pp.137 | ||||||
|  | ------------------------ | ||||||
|  | Require: M > K P = M − K † | ||||||
|  | Compute the factorization AVM = VM HM + fM eM  | ||||||
|  | repeat | ||||||
|  |   Q=I | ||||||
|  |   for i = 1,...,P do | ||||||
|  |     QiRi =HM −θiI Q = QQi | ||||||
|  |     H M = Q †i H M Q i | ||||||
|  |   end for | ||||||
|  |   βK =HM(K+1,K) σK =Q(M,K) | ||||||
|  |   r=vK+1βK +rσK | ||||||
|  |   VK =VM(1:M)Q(1:M,1:K) | ||||||
|  |   HK =HM(1:K,1:K) | ||||||
|  |   →AVK =VKHK +fKe†K † Extend to an M = K + P step factorization AVM = VMHM + fMeM | ||||||
|  | until convergence | ||||||
|  | */ | ||||||
|  |   void calc(std::vector<RealD>& eval, std::vector<Field>& evec,  const Field& src, int& Nconv, bool reverse=false) | ||||||
|  |   { | ||||||
|  |     GridBase *grid = src.Grid(); | ||||||
|  |     assert(grid == evec[0].Grid()); | ||||||
|  |      | ||||||
|  |     GridLogIRL.TimingMode(1); | ||||||
|  |     std::cout << GridLogIRL <<"**************************************************************************"<< std::endl; | ||||||
|  |     std::cout << GridLogIRL <<" ImplicitlyRestartedLanczos::calc() starting iteration 0 /  "<< MaxIter<< std::endl; | ||||||
|  |     std::cout << GridLogIRL <<"**************************************************************************"<< std::endl; | ||||||
|  |     std::cout << GridLogIRL <<" -- seek   Nk    = " << Nk    <<" vectors"<< std::endl; | ||||||
|  |     std::cout << GridLogIRL <<" -- accept Nstop = " << Nstop <<" vectors"<< std::endl; | ||||||
|  |     std::cout << GridLogIRL <<" -- total  Nm    = " << Nm    <<" vectors"<< std::endl; | ||||||
|  |     std::cout << GridLogIRL <<" -- size of eval = " << eval.size() << std::endl; | ||||||
|  |     std::cout << GridLogIRL <<" -- size of evec = " << evec.size() << std::endl; | ||||||
|  |     if ( diagonalisation == IRLdiagonaliseWithDSTEGR ) { | ||||||
|  |       std::cout << GridLogIRL << "Diagonalisation is DSTEGR "<<std::endl; | ||||||
|  |     } else if ( diagonalisation == IRLdiagonaliseWithQR ) {  | ||||||
|  |       std::cout << GridLogIRL << "Diagonalisation is QR "<<std::endl; | ||||||
|  |     }  else if ( diagonalisation == IRLdiagonaliseWithEigen ) {  | ||||||
|  |       std::cout << GridLogIRL << "Diagonalisation is Eigen "<<std::endl; | ||||||
|  |     } | ||||||
|  |     std::cout << GridLogIRL <<"**************************************************************************"<< std::endl; | ||||||
|  | 	 | ||||||
|  |     assert(Nm <= evec.size() && Nm <= eval.size()); | ||||||
|  |      | ||||||
|  |     // quickly get an idea of the largest eigenvalue to more properly normalize the residuum | ||||||
|  |     RealD evalMaxApprox = 0.0; | ||||||
|  |     { | ||||||
|  |       auto src_n = src; | ||||||
|  |       auto tmp = src; | ||||||
|  |       const int _MAX_ITER_IRL_MEVAPP_ = 50; | ||||||
|  |       for (int i=0;i<_MAX_ITER_IRL_MEVAPP_;i++) { | ||||||
|  | 	normalise(src_n); | ||||||
|  | 	_HermOp(src_n,tmp); | ||||||
|  | 	RealD vnum = real(innerProduct(src_n,tmp)); // HermOp. | ||||||
|  | 	RealD vden = norm2(src_n); | ||||||
|  | 	RealD na = vnum/vden; | ||||||
|  | 	if (fabs(evalMaxApprox/na - 1.0) < 0.05) | ||||||
|  | 	  i=_MAX_ITER_IRL_MEVAPP_; | ||||||
|  | 	evalMaxApprox = na; | ||||||
|  | 	std::cout << GridLogIRL << " Approximation of largest eigenvalue: " << evalMaxApprox << std::endl; | ||||||
|  | 	src_n = tmp; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  | 	 | ||||||
|  |     std::vector<RealD> lme(Nm);   | ||||||
|  |     std::vector<RealD> lme2(Nm); | ||||||
|  |     std::vector<RealD> eval2(Nm); | ||||||
|  |     std::vector<RealD> eval2_copy(Nm); | ||||||
|  |     Eigen::MatrixXd Qt = Eigen::MatrixXd::Zero(Nm,Nm); | ||||||
|  |  | ||||||
|  |     Field f(grid); | ||||||
|  |     Field v(grid); | ||||||
|  |     int k1 = 1; | ||||||
|  |     int k2 = Nk; | ||||||
|  |     RealD beta_k; | ||||||
|  |  | ||||||
|  |     Nconv = 0; | ||||||
|  |    | ||||||
|  |     // Set initial vector | ||||||
|  |     evec[0] = src; | ||||||
|  |     normalise(evec[0]); | ||||||
|  | 	 | ||||||
|  |     // Initial Nk steps | ||||||
|  |     OrthoTime=0.; | ||||||
|  |     for(int k=0; k<Nk; ++k) step(eval,lme,evec,f,Nm,k); | ||||||
|  |     std::cout<<GridLogIRL <<"Initial "<< Nk <<"steps done "<<std::endl; | ||||||
|  |     std::cout<<GridLogIRL <<"Initial steps:OrthoTime "<<OrthoTime<< "seconds"<<std::endl; | ||||||
|  |  | ||||||
|  |     ////////////////////////////////// | ||||||
|  |     // Restarting loop begins | ||||||
|  |     ////////////////////////////////// | ||||||
|  |     int iter; | ||||||
|  |     for(iter = 0; iter<MaxIter; ++iter){ | ||||||
|  |        | ||||||
|  |       OrthoTime=0.; | ||||||
|  |  | ||||||
|  |       std::cout<< GridLogMessage <<" **********************"<< std::endl; | ||||||
|  |       std::cout<< GridLogMessage <<" Restart iteration = "<< iter << std::endl; | ||||||
|  |       std::cout<< GridLogMessage <<" **********************"<< std::endl; | ||||||
|  |  | ||||||
|  |       std::cout<<GridLogIRL <<" running "<<Nm-Nk <<" steps: "<<std::endl; | ||||||
|  |       for(int k=Nk; k<Nm; ++k) step(eval,lme,evec,f,Nm,k); | ||||||
|  |       f *= lme[Nm-1]; | ||||||
|  |  | ||||||
|  |       std::cout<<GridLogIRL <<" "<<Nm-Nk <<" steps done "<<std::endl; | ||||||
|  |       std::cout<<GridLogIRL <<"Initial steps:OrthoTime "<<OrthoTime<< "seconds"<<std::endl; | ||||||
|  | 	   | ||||||
|  |       ////////////////////////////////// | ||||||
|  |       // getting eigenvalues | ||||||
|  |       ////////////////////////////////// | ||||||
|  |       for(int k=0; k<Nm; ++k){ | ||||||
|  | 	eval2[k] = eval[k+k1-1]; | ||||||
|  | 	lme2[k] = lme[k+k1-1]; | ||||||
|  |       } | ||||||
|  |       Qt = Eigen::MatrixXd::Identity(Nm,Nm); | ||||||
|  |       diagonalize(eval2,lme2,Nm,Nm,Qt,grid); | ||||||
|  |       std::cout<<GridLogIRL <<" diagonalized "<<std::endl; | ||||||
|  |  | ||||||
|  |       ////////////////////////////////// | ||||||
|  |       // sorting | ||||||
|  |       ////////////////////////////////// | ||||||
|  |       eval2_copy = eval2; | ||||||
|  |       std::partial_sort(eval2.begin(),eval2.begin()+Nm,eval2.end(),std::greater<RealD>()); | ||||||
|  |       std::cout<<GridLogIRL <<" evals sorted "<<std::endl; | ||||||
|  |       const int chunk=8; | ||||||
|  |       for(int io=0; io<k2;io+=chunk){ | ||||||
|  | 	std::cout<<GridLogIRL << "eval "<< std::setw(3) << io ; | ||||||
|  | 	for(int ii=0;ii<chunk;ii++){ | ||||||
|  | 	  if ( (io+ii)<k2 ) | ||||||
|  | 	    std::cout<< " "<< std::setw(12)<< eval2[io+ii]; | ||||||
|  | 	} | ||||||
|  | 	std::cout << std::endl; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       ////////////////////////////////// | ||||||
|  |       // Implicitly shifted QR transformations | ||||||
|  |       ////////////////////////////////// | ||||||
|  |       Qt = Eigen::MatrixXd::Identity(Nm,Nm); | ||||||
|  |       for(int ip=k2; ip<Nm; ++ip){  | ||||||
|  | 	QR_decomp(eval,lme,Nm,Nm,Qt,eval2[ip],k1,Nm); | ||||||
|  |       } | ||||||
|  |       std::cout<<GridLogIRL <<"QR decomposed "<<std::endl; | ||||||
|  |  | ||||||
|  |       assert(k2<Nm);      assert(k2<Nm);      assert(k1>0); | ||||||
|  |  | ||||||
|  |       basisRotate(evec,Qt,k1-1,k2+1,0,Nm,Nm); /// big constraint on the basis | ||||||
|  |       std::cout<<GridLogIRL <<"basisRotated  by Qt *"<<k1-1<<","<<k2+1<<")"<<std::endl; | ||||||
|  |        | ||||||
|  |       //////////////////////////////////////////////////// | ||||||
|  |       // Compressed vector f and beta(k2) | ||||||
|  |       //////////////////////////////////////////////////// | ||||||
|  |       f *= Qt(k2-1,Nm-1); | ||||||
|  |       f += lme[k2-1] * evec[k2]; | ||||||
|  |       beta_k = norm2(f); | ||||||
|  |       beta_k = std::sqrt(beta_k); | ||||||
|  |       std::cout<<GridLogIRL<<" beta(k) = "<<beta_k<<std::endl; | ||||||
|  | 	   | ||||||
|  |       RealD betar = 1.0/beta_k; | ||||||
|  |       evec[k2] = betar * f; | ||||||
|  |       lme[k2-1] = beta_k; | ||||||
|  | 	   | ||||||
|  |       //////////////////////////////////////////////////// | ||||||
|  |       // Convergence test | ||||||
|  |       //////////////////////////////////////////////////// | ||||||
|  |       for(int k=0; k<Nm; ++k){     | ||||||
|  | 	eval2[k] = eval[k]; | ||||||
|  | 	lme2[k] = lme[k]; | ||||||
|  |       } | ||||||
|  |       Qt = Eigen::MatrixXd::Identity(Nm,Nm); | ||||||
|  |       diagonalize(eval2,lme2,Nk,Nm,Qt,grid); | ||||||
|  |       std::cout<<GridLogIRL <<" Diagonalized "<<std::endl; | ||||||
|  | 	   | ||||||
|  |       Nconv = 0; | ||||||
|  |       if (iter >= MinRestart) { | ||||||
|  |  | ||||||
|  | 	std::cout << GridLogIRL << "Test convergence: rotate subset of vectors to test convergence " << std::endl; | ||||||
|  |  | ||||||
|  | 	Field B(grid); B.Checkerboard() = evec[0].Checkerboard(); | ||||||
|  |  | ||||||
|  | 	//  power of two search pattern;  not every evalue in eval2 is assessed. | ||||||
|  | 	int allconv =1; | ||||||
|  | 	for(int jj = 1; jj<=Nstop; jj*=2){ | ||||||
|  | 	  int j = Nstop-jj; | ||||||
|  | 	  RealD e = eval2_copy[j]; // Discard the evalue | ||||||
|  | 	  basisRotateJ(B,evec,Qt,j,0,Nk,Nm);	     | ||||||
|  | 	  if( !_Tester.TestConvergence(j,eresid,B,e,evalMaxApprox) ) { | ||||||
|  | 	    allconv=0; | ||||||
|  | 	  } | ||||||
|  | 	} | ||||||
|  | 	// Do evec[0] for good measure | ||||||
|  | 	{  | ||||||
|  | 	  int j=0; | ||||||
|  | 	  RealD e = eval2_copy[0];  | ||||||
|  | 	  basisRotateJ(B,evec,Qt,j,0,Nk,Nm);	     | ||||||
|  | 	  if( !_Tester.TestConvergence(j,eresid,B,e,evalMaxApprox) ) allconv=0; | ||||||
|  | 	} | ||||||
|  | 	if ( allconv ) Nconv = Nstop; | ||||||
|  |  | ||||||
|  | 	// test if we converged, if so, terminate | ||||||
|  | 	std::cout<<GridLogIRL<<" #modes converged: >= "<<Nconv<<"/"<<Nstop<<std::endl; | ||||||
|  | 	//	if( Nconv>=Nstop || beta_k < betastp){ | ||||||
|  | 	if( Nconv>=Nstop){ | ||||||
|  | 	  goto converged; | ||||||
|  | 	} | ||||||
|  | 	   | ||||||
|  |       } else { | ||||||
|  | 	std::cout << GridLogIRL << "iter < MinRestart: do not yet test for convergence\n"; | ||||||
|  |       } // end of iter loop | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     std::cout<<GridLogError<<"\n NOT converged.\n"; | ||||||
|  |     abort(); | ||||||
|  | 	 | ||||||
|  |   converged: | ||||||
|  |     { | ||||||
|  |       Field B(grid); B.Checkerboard() = evec[0].Checkerboard(); | ||||||
|  |       basisRotate(evec,Qt,0,Nk,0,Nk,Nm);	     | ||||||
|  |       std::cout << GridLogIRL << " Rotated basis"<<std::endl; | ||||||
|  |       Nconv=0; | ||||||
|  |       ////////////////////////////////////////////////////////////////////// | ||||||
|  |       // Full final convergence test; unconditionally applied | ||||||
|  |       ////////////////////////////////////////////////////////////////////// | ||||||
|  |       for(int j = 0; j<=Nk; j++){ | ||||||
|  | 	B=evec[j]; | ||||||
|  | 	if( _Tester.ReconstructEval(j,eresid,B,eval2[j],evalMaxApprox) ) { | ||||||
|  | 	  Nconv++; | ||||||
|  | 	} | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       if ( Nconv < Nstop ) | ||||||
|  | 	std::cout << GridLogIRL << "Nconv ("<<Nconv<<") < Nstop ("<<Nstop<<")"<<std::endl; | ||||||
|  |  | ||||||
|  |       eval=eval2; | ||||||
|  |        | ||||||
|  |       //Keep only converged | ||||||
|  |       eval.resize(Nconv);// Nstop? | ||||||
|  |       evec.resize(Nconv,grid);// Nstop? | ||||||
|  |       basisSortInPlace(evec,eval,reverse); | ||||||
|  |        | ||||||
|  |     } | ||||||
|  |         | ||||||
|  |     std::cout << GridLogIRL <<"**************************************************************************"<< std::endl; | ||||||
|  |     std::cout << GridLogIRL << "ImplicitlyRestartedLanczos CONVERGED ; Summary :\n"; | ||||||
|  |     std::cout << GridLogIRL <<"**************************************************************************"<< std::endl; | ||||||
|  |     std::cout << GridLogIRL << " -- Iterations  = "<< iter   << "\n"; | ||||||
|  |     std::cout << GridLogIRL << " -- beta(k)     = "<< beta_k << "\n"; | ||||||
|  |     std::cout << GridLogIRL << " -- Nconv       = "<< Nconv  << "\n"; | ||||||
|  |     std::cout << GridLogIRL <<"**************************************************************************"<< std::endl; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |  private: | ||||||
|  | /* Saad PP. 195 | ||||||
|  | 1. Choose an initial vector v1 of 2-norm unity. Set β1 ≡ 0, v0 ≡ 0 | ||||||
|  | 2. For k = 1,2,...,m Do: | ||||||
|  | 3. wk:=Avk−βkv_{k−1}       | ||||||
|  | 4. αk:=(wk,vk)       //  | ||||||
|  | 5. wk:=wk−αkvk       // wk orthog vk  | ||||||
|  | 6. βk+1 := ∥wk∥2. If βk+1 = 0 then Stop | ||||||
|  | 7. vk+1 := wk/βk+1 | ||||||
|  | 8. EndDo | ||||||
|  |  */ | ||||||
|  |   void step(std::vector<RealD>& lmd, | ||||||
|  | 	    std::vector<RealD>& lme,  | ||||||
|  | 	    std::vector<Field>& evec, | ||||||
|  | 	    Field& w,int Nm,int k) | ||||||
|  |   { | ||||||
|  |     const RealD tiny = 1.0e-20; | ||||||
|  |     assert( k< Nm ); | ||||||
|  |  | ||||||
|  |     GridStopWatch gsw_op,gsw_o; | ||||||
|  |  | ||||||
|  |     Field& evec_k = evec[k]; | ||||||
|  |  | ||||||
|  |     _PolyOp(evec_k,w);    std::cout<<GridLogIRL << "PolyOp" <<std::endl; | ||||||
|  |  | ||||||
|  |     if(k>0) w -= lme[k-1] * evec[k-1]; | ||||||
|  |  | ||||||
|  |     ComplexD zalph = innerProduct(evec_k,w); // 4. αk:=(wk,vk) | ||||||
|  |     RealD     alph = real(zalph); | ||||||
|  |  | ||||||
|  |     w = w - alph * evec_k;// 5. wk:=wk−αkvk | ||||||
|  |  | ||||||
|  |     RealD beta = normalise(w); // 6. βk+1 := ∥wk∥2. If βk+1 = 0 then Stop | ||||||
|  |     // 7. vk+1 := wk/βk+1 | ||||||
|  |  | ||||||
|  |     lmd[k] = alph; | ||||||
|  |     lme[k] = beta; | ||||||
|  |  | ||||||
|  |     if (k>0 && k % orth_period == 0) { | ||||||
|  |       orthogonalize(w,evec,k); // orthonormalise | ||||||
|  |       std::cout<<GridLogIRL << "Orthogonalised " <<std::endl; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if(k < Nm-1) evec[k+1] = w; | ||||||
|  |  | ||||||
|  |     std::cout<<GridLogIRL << "alpha[" << k << "] = " << zalph << " beta[" << k << "] = "<<beta<<std::endl; | ||||||
|  |     if ( beta < tiny )  | ||||||
|  |       std::cout<<GridLogIRL << " beta is tiny "<<beta<<std::endl; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   void diagonalize_Eigen(std::vector<RealD>& lmd, std::vector<RealD>& lme,  | ||||||
|  | 			 int Nk, int Nm,   | ||||||
|  | 			 Eigen::MatrixXd & Qt, // Nm x Nm | ||||||
|  | 			 GridBase *grid) | ||||||
|  |   { | ||||||
|  |     Eigen::MatrixXd TriDiag = Eigen::MatrixXd::Zero(Nk,Nk); | ||||||
|  |  | ||||||
|  |     for(int i=0;i<Nk;i++)   TriDiag(i,i)   = lmd[i]; | ||||||
|  |     for(int i=0;i<Nk-1;i++) TriDiag(i,i+1) = lme[i]; | ||||||
|  |     for(int i=0;i<Nk-1;i++) TriDiag(i+1,i) = lme[i]; | ||||||
|  |      | ||||||
|  |     Eigen::SelfAdjointEigenSolver<Eigen::MatrixXd> eigensolver(TriDiag); | ||||||
|  |  | ||||||
|  |     for (int i = 0; i < Nk; i++) { | ||||||
|  |       lmd[Nk-1-i] = eigensolver.eigenvalues()(i); | ||||||
|  |     } | ||||||
|  |     for (int i = 0; i < Nk; i++) { | ||||||
|  |       for (int j = 0; j < Nk; j++) { | ||||||
|  | 	Qt(Nk-1-i,j) = eigensolver.eigenvectors()(j,i); | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   /////////////////////////////////////////////////////////////////////////// | ||||||
|  |   // File could end here if settle on Eigen ??? !!! | ||||||
|  |   /////////////////////////////////////////////////////////////////////////// | ||||||
|  |   void QR_decomp(std::vector<RealD>& lmd,   // Nm  | ||||||
|  | 		 std::vector<RealD>& lme,   // Nm  | ||||||
|  | 		 int Nk, int Nm,            // Nk, Nm | ||||||
|  | 		 Eigen::MatrixXd& Qt,       // Nm x Nm matrix | ||||||
|  | 		 RealD Dsh, int kmin, int kmax) | ||||||
|  |   { | ||||||
|  |     int k = kmin-1; | ||||||
|  |     RealD x; | ||||||
|  |      | ||||||
|  |     RealD Fden = 1.0/hypot(lmd[k]-Dsh,lme[k]); | ||||||
|  |     RealD c = ( lmd[k] -Dsh) *Fden; | ||||||
|  |     RealD s = -lme[k] *Fden; | ||||||
|  |        | ||||||
|  |     RealD tmpa1 = lmd[k]; | ||||||
|  |     RealD tmpa2 = lmd[k+1]; | ||||||
|  |     RealD tmpb  = lme[k]; | ||||||
|  |  | ||||||
|  |     lmd[k]   = c*c*tmpa1 +s*s*tmpa2 -2.0*c*s*tmpb; | ||||||
|  |     lmd[k+1] = s*s*tmpa1 +c*c*tmpa2 +2.0*c*s*tmpb; | ||||||
|  |     lme[k]   = c*s*(tmpa1-tmpa2) +(c*c-s*s)*tmpb; | ||||||
|  |     x        =-s*lme[k+1]; | ||||||
|  |     lme[k+1] = c*lme[k+1]; | ||||||
|  |        | ||||||
|  |     for(int i=0; i<Nk; ++i){ | ||||||
|  |       RealD Qtmp1 = Qt(k,i); | ||||||
|  |       RealD Qtmp2 = Qt(k+1,i); | ||||||
|  |       Qt(k,i)  = c*Qtmp1 - s*Qtmp2; | ||||||
|  |       Qt(k+1,i)= s*Qtmp1 + c*Qtmp2;  | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // Givens transformations | ||||||
|  |     for(int k = kmin; k < kmax-1; ++k){ | ||||||
|  |        | ||||||
|  |       RealD Fden = 1.0/hypot(x,lme[k-1]); | ||||||
|  |       RealD c = lme[k-1]*Fden; | ||||||
|  |       RealD s = - x*Fden; | ||||||
|  | 	 | ||||||
|  |       RealD tmpa1 = lmd[k]; | ||||||
|  |       RealD tmpa2 = lmd[k+1]; | ||||||
|  |       RealD tmpb  = lme[k]; | ||||||
|  |  | ||||||
|  |       lmd[k]   = c*c*tmpa1 +s*s*tmpa2 -2.0*c*s*tmpb; | ||||||
|  |       lmd[k+1] = s*s*tmpa1 +c*c*tmpa2 +2.0*c*s*tmpb; | ||||||
|  |       lme[k]   = c*s*(tmpa1-tmpa2) +(c*c-s*s)*tmpb; | ||||||
|  |       lme[k-1] = c*lme[k-1] -s*x; | ||||||
|  |  | ||||||
|  |       if(k != kmax-2){ | ||||||
|  | 	x = -s*lme[k+1]; | ||||||
|  | 	lme[k+1] = c*lme[k+1]; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       for(int i=0; i<Nk; ++i){ | ||||||
|  | 	RealD Qtmp1 = Qt(k,i); | ||||||
|  | 	RealD Qtmp2 = Qt(k+1,i); | ||||||
|  | 	Qt(k,i)     = c*Qtmp1 -s*Qtmp2; | ||||||
|  | 	Qt(k+1,i)   = s*Qtmp1 +c*Qtmp2; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   void diagonalize(std::vector<RealD>& lmd, std::vector<RealD>& lme,  | ||||||
|  | 		   int Nk, int Nm,    | ||||||
|  | 		   Eigen::MatrixXd & Qt, | ||||||
|  | 		   GridBase *grid) | ||||||
|  |   { | ||||||
|  |     Qt = Eigen::MatrixXd::Identity(Nm,Nm); | ||||||
|  |     if ( diagonalisation == IRLdiagonaliseWithDSTEGR ) { | ||||||
|  |       diagonalize_lapack(lmd,lme,Nk,Nm,Qt,grid); | ||||||
|  |     } else if ( diagonalisation == IRLdiagonaliseWithQR ) {  | ||||||
|  |       diagonalize_QR(lmd,lme,Nk,Nm,Qt,grid); | ||||||
|  |     }  else if ( diagonalisation == IRLdiagonaliseWithEigen ) {  | ||||||
|  |       diagonalize_Eigen(lmd,lme,Nk,Nm,Qt,grid); | ||||||
|  |     } else {  | ||||||
|  |       assert(0); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  | #ifdef USE_LAPACK | ||||||
|  | void LAPACK_dstegr(char *jobz, char *range, int *n, double *d, double *e, | ||||||
|  |                    double *vl, double *vu, int *il, int *iu, double *abstol, | ||||||
|  |                    int *m, double *w, double *z, int *ldz, int *isuppz, | ||||||
|  |                    double *work, int *lwork, int *iwork, int *liwork, | ||||||
|  |                    int *info); | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | void diagonalize_lapack(std::vector<RealD>& lmd, | ||||||
|  | 			std::vector<RealD>& lme,  | ||||||
|  | 			int Nk, int Nm,   | ||||||
|  | 			Eigen::MatrixXd& Qt, | ||||||
|  | 			GridBase *grid) | ||||||
|  | { | ||||||
|  | #ifdef USE_LAPACK | ||||||
|  |   const int size = Nm; | ||||||
|  |   int NN = Nk; | ||||||
|  |   double evals_tmp[NN]; | ||||||
|  |   double evec_tmp[NN][NN]; | ||||||
|  |   memset(evec_tmp[0],0,sizeof(double)*NN*NN); | ||||||
|  |   double DD[NN]; | ||||||
|  |   double EE[NN]; | ||||||
|  |   for (int i = 0; i< NN; i++) { | ||||||
|  |     for (int j = i - 1; j <= i + 1; j++) { | ||||||
|  |       if ( j < NN && j >= 0 ) { | ||||||
|  | 	if (i==j) DD[i] = lmd[i]; | ||||||
|  | 	if (i==j) evals_tmp[i] = lmd[i]; | ||||||
|  | 	if (j==(i-1)) EE[j] = lme[j]; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   int evals_found; | ||||||
|  |   int lwork = ( (18*NN) > (1+4*NN+NN*NN)? (18*NN):(1+4*NN+NN*NN)) ; | ||||||
|  |   int liwork =  3+NN*10 ; | ||||||
|  |   int iwork[liwork]; | ||||||
|  |   double work[lwork]; | ||||||
|  |   int isuppz[2*NN]; | ||||||
|  |   char jobz = 'V'; // calculate evals & evecs | ||||||
|  |   char range = 'I'; // calculate all evals | ||||||
|  |   //    char range = 'A'; // calculate all evals | ||||||
|  |   char uplo = 'U'; // refer to upper half of original matrix | ||||||
|  |   char compz = 'I'; // Compute eigenvectors of tridiagonal matrix | ||||||
|  |   int ifail[NN]; | ||||||
|  |   int info; | ||||||
|  |   int total = grid->_Nprocessors; | ||||||
|  |   int node  = grid->_processor; | ||||||
|  |   int interval = (NN/total)+1; | ||||||
|  |   double vl = 0.0, vu = 0.0; | ||||||
|  |   int il = interval*node+1 , iu = interval*(node+1); | ||||||
|  |   if (iu > NN)  iu=NN; | ||||||
|  |   double tol = 0.0; | ||||||
|  |   if (1) { | ||||||
|  |     memset(evals_tmp,0,sizeof(double)*NN); | ||||||
|  |     if ( il <= NN){ | ||||||
|  |       LAPACK_dstegr(&jobz, &range, &NN, | ||||||
|  | 		    (double*)DD, (double*)EE, | ||||||
|  | 		    &vl, &vu, &il, &iu, // these four are ignored if second parameteris 'A' | ||||||
|  | 		    &tol, // tolerance | ||||||
|  | 		    &evals_found, evals_tmp, (double*)evec_tmp, &NN, | ||||||
|  | 		    isuppz, | ||||||
|  | 		    work, &lwork, iwork, &liwork, | ||||||
|  | 		    &info); | ||||||
|  |       for (int i = iu-1; i>= il-1; i--){ | ||||||
|  | 	evals_tmp[i] = evals_tmp[i - (il-1)]; | ||||||
|  | 	if (il>1) evals_tmp[i-(il-1)]=0.; | ||||||
|  | 	for (int j = 0; j< NN; j++){ | ||||||
|  | 	  evec_tmp[i][j] = evec_tmp[i - (il-1)][j]; | ||||||
|  | 	  if (il>1) evec_tmp[i-(il-1)][j]=0.; | ||||||
|  | 	} | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |     { | ||||||
|  |       grid->GlobalSumVector(evals_tmp,NN); | ||||||
|  |       grid->GlobalSumVector((double*)evec_tmp,NN*NN); | ||||||
|  |     } | ||||||
|  |   }  | ||||||
|  |   // Safer to sort instead of just reversing it,  | ||||||
|  |   // but the document of the routine says evals are sorted in increasing order.  | ||||||
|  |   // qr gives evals in decreasing order. | ||||||
|  |   for(int i=0;i<NN;i++){ | ||||||
|  |     lmd [NN-1-i]=evals_tmp[i]; | ||||||
|  |     for(int j=0;j<NN;j++){ | ||||||
|  |       Qt((NN-1-i),j)=evec_tmp[i][j]; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | #else  | ||||||
|  |   assert(0); | ||||||
|  | #endif | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void diagonalize_QR(std::vector<RealD>& lmd, std::vector<RealD>& lme,  | ||||||
|  | 		    int Nk, int Nm,    | ||||||
|  | 		    Eigen::MatrixXd & Qt, | ||||||
|  | 		    GridBase *grid) | ||||||
|  | { | ||||||
|  |   int QRiter = 100*Nm; | ||||||
|  |   int kmin = 1; | ||||||
|  |   int kmax = Nk; | ||||||
|  |    | ||||||
|  |   // (this should be more sophisticated) | ||||||
|  |   for(int iter=0; iter<QRiter; ++iter){ | ||||||
|  |      | ||||||
|  |     // determination of 2x2 leading submatrix | ||||||
|  |     RealD dsub = lmd[kmax-1]-lmd[kmax-2]; | ||||||
|  |     RealD dd = std::sqrt(dsub*dsub + 4.0*lme[kmax-2]*lme[kmax-2]); | ||||||
|  |     RealD Dsh = 0.5*(lmd[kmax-2]+lmd[kmax-1] +dd*(dsub/fabs(dsub))); | ||||||
|  |     // (Dsh: shift) | ||||||
|  |      | ||||||
|  |     // transformation | ||||||
|  |     QR_decomp(lmd,lme,Nk,Nm,Qt,Dsh,kmin,kmax); // Nk, Nm | ||||||
|  |      | ||||||
|  |     // Convergence criterion (redef of kmin and kamx) | ||||||
|  |     for(int j=kmax-1; j>= kmin; --j){ | ||||||
|  |       RealD dds = fabs(lmd[j-1])+fabs(lmd[j]); | ||||||
|  |       if(fabs(lme[j-1])+dds > dds){ | ||||||
|  | 	kmax = j+1; | ||||||
|  | 	goto continued; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |     QRiter = iter; | ||||||
|  |     return; | ||||||
|  |      | ||||||
|  |   continued: | ||||||
|  |     for(int j=0; j<kmax-1; ++j){ | ||||||
|  |       RealD dds = fabs(lmd[j])+fabs(lmd[j+1]); | ||||||
|  |       if(fabs(lme[j])+dds > dds){ | ||||||
|  | 	kmin = j+1; | ||||||
|  | 	break; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   std::cout << GridLogError << "[QL method] Error - Too many iteration: "<<QRiter<<"\n"; | ||||||
|  |   abort(); | ||||||
|  | } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | NAMESPACE_END(Grid); | ||||||
|  | #endif | ||||||
							
								
								
									
										409
									
								
								Grid/algorithms/iterative/LocalCoherenceLanczos.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										409
									
								
								Grid/algorithms/iterative/LocalCoherenceLanczos.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,409 @@ | |||||||
|  | /************************************************************************************* | ||||||
|  |  | ||||||
|  |     Grid physics library, www.github.com/paboyle/Grid  | ||||||
|  |  | ||||||
|  |     Source file: ./lib/algorithms/iterative/LocalCoherenceLanczos.h | ||||||
|  |  | ||||||
|  |     Copyright (C) 2015 | ||||||
|  |  | ||||||
|  | Author: Christoph Lehner <clehner@bnl.gov> | ||||||
|  | Author: paboyle <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_LOCAL_COHERENCE_IRL_H | ||||||
|  | #define GRID_LOCAL_COHERENCE_IRL_H | ||||||
|  |  | ||||||
|  | NAMESPACE_BEGIN(Grid);  | ||||||
|  |  | ||||||
|  | struct LanczosParams : Serializable { | ||||||
|  | public: | ||||||
|  |   GRID_SERIALIZABLE_CLASS_MEMBERS(LanczosParams, | ||||||
|  | 				  ChebyParams, Cheby,/*Chebyshev*/ | ||||||
|  | 				  int, Nstop,    /*Vecs in Lanczos must converge Nstop < Nk < Nm*/ | ||||||
|  | 				  int, Nk,       /*Vecs in Lanczos seek converge*/ | ||||||
|  | 				  int, Nm,       /*Total vecs in Lanczos include restart*/ | ||||||
|  | 				  RealD, resid,  /*residual*/ | ||||||
|  |  				  int, MaxIt,  | ||||||
|  | 				  RealD, betastp,  /* ? */ | ||||||
|  | 				  int, MinRes);    // Must restart | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | struct LocalCoherenceLanczosParams : Serializable { | ||||||
|  | public: | ||||||
|  |   GRID_SERIALIZABLE_CLASS_MEMBERS(LocalCoherenceLanczosParams, | ||||||
|  | 				  bool, saveEvecs, | ||||||
|  | 				  bool, doFine, | ||||||
|  | 				  bool, doFineRead, | ||||||
|  | 				  bool, doCoarse, | ||||||
|  | 	       			  bool, doCoarseRead, | ||||||
|  | 				  LanczosParams, FineParams, | ||||||
|  | 				  LanczosParams, CoarseParams, | ||||||
|  | 				  ChebyParams,   Smoother, | ||||||
|  | 				  RealD        , coarse_relax_tol, | ||||||
|  | 				  std::vector<int>, blockSize, | ||||||
|  | 				  std::string, config, | ||||||
|  | 				  std::vector < ComplexD  >, omega, | ||||||
|  | 				  RealD, mass, | ||||||
|  | 				  RealD, M5); | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | // Duplicate functionality; ProjectedFunctionHermOp could be used with the trivial function | ||||||
|  | template<class Fobj,class CComplex,int nbasis> | ||||||
|  | class ProjectedHermOp : public LinearFunction<Lattice<iVector<CComplex,nbasis > > > { | ||||||
|  | public: | ||||||
|  |   typedef iVector<CComplex,nbasis >           CoarseSiteVector; | ||||||
|  |   typedef Lattice<CoarseSiteVector>           CoarseField; | ||||||
|  |   typedef Lattice<CComplex>   CoarseScalar; // used for inner products on fine field | ||||||
|  |   typedef Lattice<Fobj>          FineField; | ||||||
|  |  | ||||||
|  |   LinearOperatorBase<FineField> &_Linop; | ||||||
|  |   std::vector<FineField>        &subspace; | ||||||
|  |  | ||||||
|  |   ProjectedHermOp(LinearOperatorBase<FineField>& linop, std::vector<FineField> & _subspace) :  | ||||||
|  |     _Linop(linop), subspace(_subspace) | ||||||
|  |   {   | ||||||
|  |     assert(subspace.size() >0); | ||||||
|  |   }; | ||||||
|  |  | ||||||
|  |   void operator()(const CoarseField& in, CoarseField& out) { | ||||||
|  |     GridBase *FineGrid = subspace[0].Grid();     | ||||||
|  |     int   checkerboard = subspace[0].Checkerboard(); | ||||||
|  |  | ||||||
|  |     FineField fin (FineGrid);     fin.Checkerboard()= checkerboard; | ||||||
|  |     FineField fout(FineGrid);   fout.Checkerboard() = checkerboard; | ||||||
|  |  | ||||||
|  |     blockPromote(in,fin,subspace);       std::cout<<GridLogIRL<<"ProjectedHermop : Promote to fine"<<std::endl; | ||||||
|  |     _Linop.HermOp(fin,fout);                   std::cout<<GridLogIRL<<"ProjectedHermop : HermOp (fine) "<<std::endl; | ||||||
|  |     blockProject(out,fout,subspace);     std::cout<<GridLogIRL<<"ProjectedHermop : Project to coarse "<<std::endl; | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | template<class Fobj,class CComplex,int nbasis> | ||||||
|  | class ProjectedFunctionHermOp : public LinearFunction<Lattice<iVector<CComplex,nbasis > > > { | ||||||
|  | public: | ||||||
|  |   typedef iVector<CComplex,nbasis >           CoarseSiteVector; | ||||||
|  |   typedef Lattice<CoarseSiteVector>           CoarseField; | ||||||
|  |   typedef Lattice<CComplex>   CoarseScalar; // used for inner products on fine field | ||||||
|  |   typedef Lattice<Fobj>          FineField; | ||||||
|  |  | ||||||
|  |  | ||||||
|  |   OperatorFunction<FineField>   & _poly; | ||||||
|  |   LinearOperatorBase<FineField> &_Linop; | ||||||
|  |   std::vector<FineField>        &subspace; | ||||||
|  |  | ||||||
|  |   ProjectedFunctionHermOp(OperatorFunction<FineField> & poly, | ||||||
|  | 			  LinearOperatorBase<FineField>& linop,  | ||||||
|  | 			  std::vector<FineField> & _subspace) : | ||||||
|  |     _poly(poly), | ||||||
|  |     _Linop(linop), | ||||||
|  |     subspace(_subspace) | ||||||
|  |   {  }; | ||||||
|  |  | ||||||
|  |   void operator()(const CoarseField& in, CoarseField& out) { | ||||||
|  |  | ||||||
|  |     GridBase *FineGrid = subspace[0].Grid();     | ||||||
|  |     int   checkerboard = subspace[0].Checkerboard(); | ||||||
|  |  | ||||||
|  |     FineField fin (FineGrid); fin.Checkerboard() =checkerboard; | ||||||
|  |     FineField fout(FineGrid);fout.Checkerboard() =checkerboard; | ||||||
|  |      | ||||||
|  |     blockPromote(in,fin,subspace);             std::cout<<GridLogIRL<<"ProjectedFunctionHermop : Promote to fine"<<std::endl; | ||||||
|  |     _poly(_Linop,fin,fout);                    std::cout<<GridLogIRL<<"ProjectedFunctionHermop : Poly "<<std::endl; | ||||||
|  |     blockProject(out,fout,subspace);           std::cout<<GridLogIRL<<"ProjectedFunctionHermop : Project to coarse "<<std::endl; | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | template<class Fobj,class CComplex,int nbasis> | ||||||
|  | class ImplicitlyRestartedLanczosSmoothedTester  : public ImplicitlyRestartedLanczosTester<Lattice<iVector<CComplex,nbasis > > > | ||||||
|  | { | ||||||
|  | public: | ||||||
|  |   typedef iVector<CComplex,nbasis >           CoarseSiteVector; | ||||||
|  |   typedef Lattice<CoarseSiteVector>           CoarseField; | ||||||
|  |   typedef Lattice<CComplex>   CoarseScalar; // used for inner products on fine field | ||||||
|  |   typedef Lattice<Fobj>          FineField; | ||||||
|  |  | ||||||
|  |   LinearFunction<CoarseField> & _Poly; | ||||||
|  |   OperatorFunction<FineField>   & _smoother; | ||||||
|  |   LinearOperatorBase<FineField> &_Linop; | ||||||
|  |   RealD                             _coarse_relax_tol; | ||||||
|  |   std::vector<FineField>        &_subspace; | ||||||
|  |    | ||||||
|  |   ImplicitlyRestartedLanczosSmoothedTester(LinearFunction<CoarseField>   &Poly, | ||||||
|  | 					   OperatorFunction<FineField>   &smoother, | ||||||
|  | 					   LinearOperatorBase<FineField> &Linop, | ||||||
|  | 					   std::vector<FineField>        &subspace, | ||||||
|  | 					   RealD coarse_relax_tol=5.0e3)  | ||||||
|  |     : _smoother(smoother), _Linop(Linop), _Poly(Poly), _subspace(subspace), | ||||||
|  |       _coarse_relax_tol(coarse_relax_tol)   | ||||||
|  |   {    }; | ||||||
|  |  | ||||||
|  |   int TestConvergence(int j,RealD eresid,CoarseField &B, RealD &eval,RealD evalMaxApprox) | ||||||
|  |   { | ||||||
|  |     CoarseField v(B); | ||||||
|  |     RealD eval_poly = eval; | ||||||
|  |  | ||||||
|  |     // Apply operator | ||||||
|  |     _Poly(B,v); | ||||||
|  |  | ||||||
|  |     RealD vnum = real(innerProduct(B,v)); // HermOp. | ||||||
|  |     RealD vden = norm2(B); | ||||||
|  |     RealD vv0  = norm2(v); | ||||||
|  |     eval   = vnum/vden; | ||||||
|  |     v -= eval*B; | ||||||
|  |  | ||||||
|  |     RealD vv = norm2(v) / ::pow(evalMaxApprox,2.0); | ||||||
|  |  | ||||||
|  |     std::cout.precision(13); | ||||||
|  |     std::cout<<GridLogIRL  << "[" << std::setw(3)<<j<<"] " | ||||||
|  | 	     <<"eval = "<<std::setw(25)<< eval << " (" << eval_poly << ")" | ||||||
|  | 	     <<" |H B[i] - eval[i]B[i]|^2 / evalMaxApprox^2 " << std::setw(25) << vv | ||||||
|  | 	     <<std::endl; | ||||||
|  |  | ||||||
|  |     int conv=0; | ||||||
|  |     if( (vv<eresid*eresid) ) conv = 1; | ||||||
|  |     return conv; | ||||||
|  |   } | ||||||
|  |   int ReconstructEval(int j,RealD eresid,CoarseField &B, RealD &eval,RealD evalMaxApprox) | ||||||
|  |   { | ||||||
|  |     GridBase *FineGrid = _subspace[0].Grid();     | ||||||
|  |     int checkerboard   = _subspace[0].Checkerboard(); | ||||||
|  |     FineField fB(FineGrid);fB.Checkerboard() =checkerboard; | ||||||
|  |     FineField fv(FineGrid);fv.Checkerboard() =checkerboard; | ||||||
|  |  | ||||||
|  |     blockPromote(B,fv,_subspace);   | ||||||
|  |      | ||||||
|  |     _smoother(_Linop,fv,fB);  | ||||||
|  |  | ||||||
|  |     RealD eval_poly = eval; | ||||||
|  |     _Linop.HermOp(fB,fv); | ||||||
|  |  | ||||||
|  |     RealD vnum = real(innerProduct(fB,fv)); // HermOp. | ||||||
|  |     RealD vden = norm2(fB); | ||||||
|  |     RealD vv0  = norm2(fv); | ||||||
|  |     eval   = vnum/vden; | ||||||
|  |     fv -= eval*fB; | ||||||
|  |     RealD vv = norm2(fv) / ::pow(evalMaxApprox,2.0); | ||||||
|  |  | ||||||
|  |     std::cout.precision(13); | ||||||
|  |     std::cout<<GridLogIRL  << "[" << std::setw(3)<<j<<"] " | ||||||
|  | 	     <<"eval = "<<std::setw(25)<< eval << " (" << eval_poly << ")" | ||||||
|  | 	     <<" |H B[i] - eval[i]B[i]|^2 / evalMaxApprox^2 " << std::setw(25) << vv | ||||||
|  | 	     <<std::endl; | ||||||
|  |     if ( j > nbasis ) eresid = eresid*_coarse_relax_tol; | ||||||
|  |     if( (vv<eresid*eresid) ) return 1; | ||||||
|  |     return 0; | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | //////////////////////////////////////////// | ||||||
|  | // Make serializable Lanczos params | ||||||
|  | //////////////////////////////////////////// | ||||||
|  | template<class Fobj,class CComplex,int nbasis> | ||||||
|  | class LocalCoherenceLanczos  | ||||||
|  | { | ||||||
|  | public: | ||||||
|  |   typedef iVector<CComplex,nbasis >           CoarseSiteVector; | ||||||
|  |   typedef Lattice<CComplex>                   CoarseScalar; // used for inner products on fine field | ||||||
|  |   typedef Lattice<CoarseSiteVector>           CoarseField; | ||||||
|  |   typedef Lattice<Fobj>                       FineField; | ||||||
|  |  | ||||||
|  | protected: | ||||||
|  |   GridBase *_CoarseGrid; | ||||||
|  |   GridBase *_FineGrid; | ||||||
|  |   int _checkerboard; | ||||||
|  |   LinearOperatorBase<FineField>                 & _FineOp; | ||||||
|  |    | ||||||
|  |   std::vector<RealD>                              &evals_fine; | ||||||
|  |   std::vector<RealD>                              &evals_coarse;  | ||||||
|  |   std::vector<FineField>                          &subspace; | ||||||
|  |   std::vector<CoarseField>                        &evec_coarse; | ||||||
|  |  | ||||||
|  | private: | ||||||
|  |   std::vector<RealD>                              _evals_fine; | ||||||
|  |   std::vector<RealD>                              _evals_coarse;  | ||||||
|  |   std::vector<FineField>                          _subspace; | ||||||
|  |   std::vector<CoarseField>                        _evec_coarse; | ||||||
|  |  | ||||||
|  | public: | ||||||
|  |  | ||||||
|  |   LocalCoherenceLanczos(GridBase *FineGrid, | ||||||
|  | 			GridBase *CoarseGrid, | ||||||
|  | 			LinearOperatorBase<FineField> &FineOp, | ||||||
|  | 			int checkerboard) : | ||||||
|  |     _CoarseGrid(CoarseGrid), | ||||||
|  |     _FineGrid(FineGrid), | ||||||
|  |     _FineOp(FineOp), | ||||||
|  |     _checkerboard(checkerboard), | ||||||
|  |     evals_fine  (_evals_fine), | ||||||
|  |     evals_coarse(_evals_coarse), | ||||||
|  |     subspace    (_subspace), | ||||||
|  |     evec_coarse(_evec_coarse) | ||||||
|  |   { | ||||||
|  |     evals_fine.resize(0); | ||||||
|  |     evals_coarse.resize(0); | ||||||
|  |   }; | ||||||
|  |   ////////////////////////////////////////////////////////////////////////// | ||||||
|  |   // Alternate constructore, external storage for use by Hadrons module | ||||||
|  |   ////////////////////////////////////////////////////////////////////////// | ||||||
|  |   LocalCoherenceLanczos(GridBase *FineGrid, | ||||||
|  | 			GridBase *CoarseGrid, | ||||||
|  | 			LinearOperatorBase<FineField> &FineOp, | ||||||
|  | 			int checkerboard, | ||||||
|  | 			std::vector<FineField>   &ext_subspace, | ||||||
|  | 			std::vector<CoarseField> &ext_coarse, | ||||||
|  | 			std::vector<RealD>       &ext_eval_fine, | ||||||
|  | 			std::vector<RealD>       &ext_eval_coarse | ||||||
|  | 			) : | ||||||
|  |     _CoarseGrid(CoarseGrid), | ||||||
|  |     _FineGrid(FineGrid), | ||||||
|  |     _FineOp(FineOp), | ||||||
|  |     _checkerboard(checkerboard), | ||||||
|  |     evals_fine  (ext_eval_fine),  | ||||||
|  |     evals_coarse(ext_eval_coarse), | ||||||
|  |     subspace    (ext_subspace), | ||||||
|  |     evec_coarse (ext_coarse) | ||||||
|  |   { | ||||||
|  |     evals_fine.resize(0); | ||||||
|  |     evals_coarse.resize(0); | ||||||
|  |   }; | ||||||
|  |  | ||||||
|  |   void Orthogonalise(void ) { | ||||||
|  |     CoarseScalar InnerProd(_CoarseGrid); | ||||||
|  |     std::cout << GridLogMessage <<" Gramm-Schmidt pass 1"<<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)  | ||||||
|  |   { | ||||||
|  |     RealD nn = norm2(v); | ||||||
|  |     nn = ::sqrt(nn); | ||||||
|  |     v = v * (1.0/nn); | ||||||
|  |     return nn; | ||||||
|  |   } | ||||||
|  |   /* | ||||||
|  |   void fakeFine(void) | ||||||
|  |   { | ||||||
|  |     int Nk = nbasis; | ||||||
|  |     subspace.resize(Nk,_FineGrid); | ||||||
|  |     subspace[0]=1.0; | ||||||
|  |     subspace[0].Checkerboard()=_checkerboard; | ||||||
|  |     normalise(subspace[0]); | ||||||
|  |     PlainHermOp<FineField>    Op(_FineOp); | ||||||
|  |     for(int k=1;k<Nk;k++){ | ||||||
|  |       subspace[k].Checkerboard()=_checkerboard; | ||||||
|  |       Op(subspace[k-1],subspace[k]); | ||||||
|  |       normalise(subspace[k]); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   */ | ||||||
|  |  | ||||||
|  |   void testFine(RealD resid)  | ||||||
|  |   { | ||||||
|  |     assert(evals_fine.size() == nbasis); | ||||||
|  |     assert(subspace.size() == nbasis); | ||||||
|  |     PlainHermOp<FineField>    Op(_FineOp); | ||||||
|  |     ImplicitlyRestartedLanczosHermOpTester<FineField> SimpleTester(Op); | ||||||
|  |     for(int k=0;k<nbasis;k++){ | ||||||
|  |       assert(SimpleTester.ReconstructEval(k,resid,subspace[k],evals_fine[k],1.0)==1); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   void testCoarse(RealD resid,ChebyParams cheby_smooth,RealD relax)  | ||||||
|  |   { | ||||||
|  |     assert(evals_fine.size() == nbasis); | ||||||
|  |     assert(subspace.size() == nbasis); | ||||||
|  |     ////////////////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  |     // create a smoother and see if we can get a cheap convergence test and smooth inside the IRL | ||||||
|  |     ////////////////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  |     Chebyshev<FineField>                          ChebySmooth(cheby_smooth); | ||||||
|  |     ProjectedFunctionHermOp<Fobj,CComplex,nbasis> ChebyOp (ChebySmooth,_FineOp,subspace); | ||||||
|  |     ImplicitlyRestartedLanczosSmoothedTester<Fobj,CComplex,nbasis> ChebySmoothTester(ChebyOp,ChebySmooth,_FineOp,subspace,relax); | ||||||
|  |  | ||||||
|  |     for(int k=0;k<evec_coarse.size();k++){ | ||||||
|  |       if ( k < nbasis ) {  | ||||||
|  | 	assert(ChebySmoothTester.ReconstructEval(k,resid,evec_coarse[k],evals_coarse[k],1.0)==1); | ||||||
|  |       } else {  | ||||||
|  | 	assert(ChebySmoothTester.ReconstructEval(k,resid*relax,evec_coarse[k],evals_coarse[k],1.0)==1); | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   void calcFine(ChebyParams cheby_parms,int Nstop,int Nk,int Nm,RealD resid,  | ||||||
|  | 		RealD MaxIt, RealD betastp, int MinRes) | ||||||
|  |   { | ||||||
|  |     assert(nbasis<=Nm); | ||||||
|  |     Chebyshev<FineField>      Cheby(cheby_parms); | ||||||
|  |     FunctionHermOp<FineField> ChebyOp(Cheby,_FineOp); | ||||||
|  |     PlainHermOp<FineField>    Op(_FineOp); | ||||||
|  |  | ||||||
|  |     evals_fine.resize(Nm); | ||||||
|  |     subspace.resize(Nm,_FineGrid); | ||||||
|  |  | ||||||
|  |     ImplicitlyRestartedLanczos<FineField> IRL(ChebyOp,Op,Nstop,Nk,Nm,resid,MaxIt,betastp,MinRes); | ||||||
|  |  | ||||||
|  |     FineField src(_FineGrid);  | ||||||
|  |     typedef typename FineField::scalar_type Scalar; | ||||||
|  |     // src=1.0;  | ||||||
|  |     src=Scalar(1.0);  | ||||||
|  |     src.Checkerboard() = _checkerboard; | ||||||
|  |  | ||||||
|  |     int Nconv; | ||||||
|  |     IRL.calc(evals_fine,subspace,src,Nconv,false); | ||||||
|  |      | ||||||
|  |     // Shrink down to number saved | ||||||
|  |     assert(Nstop>=nbasis); | ||||||
|  |     assert(Nconv>=nbasis); | ||||||
|  |     evals_fine.resize(nbasis); | ||||||
|  |     subspace.resize(nbasis,_FineGrid); | ||||||
|  |   } | ||||||
|  |   void calcCoarse(ChebyParams cheby_op,ChebyParams cheby_smooth,RealD relax, | ||||||
|  | 		  int Nstop, int Nk, int Nm,RealD resid,  | ||||||
|  | 		  RealD MaxIt, RealD betastp, int MinRes) | ||||||
|  |   { | ||||||
|  |     Chebyshev<FineField>                          Cheby(cheby_op); | ||||||
|  |     ProjectedHermOp<Fobj,CComplex,nbasis>         Op(_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 | ||||||
|  |     ////////////////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  |  | ||||||
|  |     Chebyshev<FineField>                                           ChebySmooth(cheby_smooth); | ||||||
|  |     ImplicitlyRestartedLanczosSmoothedTester<Fobj,CComplex,nbasis> ChebySmoothTester(ChebyOp,ChebySmooth,_FineOp,subspace,relax); | ||||||
|  |  | ||||||
|  |     evals_coarse.resize(Nm); | ||||||
|  |     evec_coarse.resize(Nm,_CoarseGrid); | ||||||
|  |  | ||||||
|  |     CoarseField src(_CoarseGrid);     src=1.0;  | ||||||
|  |  | ||||||
|  |     ImplicitlyRestartedLanczos<CoarseField> IRL(ChebyOp,ChebyOp,ChebySmoothTester,Nstop,Nk,Nm,resid,MaxIt,betastp,MinRes); | ||||||
|  |     int Nconv=0; | ||||||
|  |     IRL.calc(evals_coarse,evec_coarse,src,Nconv,false); | ||||||
|  |     assert(Nconv>=Nstop); | ||||||
|  |     evals_coarse.resize(Nstop); | ||||||
|  |     evec_coarse.resize (Nstop,_CoarseGrid); | ||||||
|  |     for (int i=0;i<Nstop;i++){ | ||||||
|  |       std::cout << i << " Coarse eval = " << evals_coarse[i]  << std::endl; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | NAMESPACE_END(Grid); | ||||||
|  | #endif | ||||||
							
								
								
									
										157
									
								
								Grid/algorithms/iterative/MinimalResidual.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										157
									
								
								Grid/algorithms/iterative/MinimalResidual.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,157 @@ | |||||||
|  | /************************************************************************************* | ||||||
|  |  | ||||||
|  | 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: | ||||||
|  |   using OperatorFunction<Field>::operator(); | ||||||
|  |  | ||||||
|  |   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); | ||||||
|  |  | ||||||
|  |     ComplexD a, c; | ||||||
|  |     RealD    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:  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,276 @@ | |||||||
|  | /************************************************************************************* | ||||||
|  |  | ||||||
|  | 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: | ||||||
|  |  | ||||||
|  |   using OperatorFunction<FieldD>::operator(); | ||||||
|  |  | ||||||
|  |   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<ComplexD> y; | ||||||
|  |   std::vector<ComplexD> gamma; | ||||||
|  |   std::vector<ComplexD> c; | ||||||
|  |   std::vector<ComplexD> 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 = 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 - ComplexD(H(iter, i)) * v[i]; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     H(iter, iter + 1) = sqrt(norm2(w)); | ||||||
|  |     v[iter + 1] = ComplexD(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] * ComplexD(H(iter, i)) + c[i] * ComplexD(H(iter, i + 1)); | ||||||
|  |       H(iter, i)     = conjugate(c[i]) * ComplexD(H(iter, i)) + conjugate(s[i]) * ComplexD(H(iter, i + 1)); | ||||||
|  |       H(iter, i + 1) = tmp; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // Compute new Givens Rotation | ||||||
|  |     auto 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]     = conjugate(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] - ComplexD(H(k, i)) * y[k]; | ||||||
|  |       y[i] = y[i] / ComplexD(H(i, i)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     for (int i = 0; i <= iter; i++) | ||||||
|  |       psi = psi + z[i] * y[i]; | ||||||
|  |     CompSolutionTimer.Stop(); | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  | } | ||||||
|  | #endif | ||||||
| @@ -1,4 +1,4 @@ | |||||||
|     /*************************************************************************************
 | /*************************************************************************************
 | ||||||
| 
 | 
 | ||||||
|     Grid physics library, www.github.com/paboyle/Grid  |     Grid physics library, www.github.com/paboyle/Grid  | ||||||
| 
 | 
 | ||||||
| @@ -23,38 +23,38 @@ Author: Peter Boyle <paboyle@ph.ed.ac.uk> | |||||||
|     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||||||
| 
 | 
 | ||||||
|     See the full license in the file "LICENSE" in the top level distribution directory |     See the full license in the file "LICENSE" in the top level distribution directory | ||||||
|     *************************************************************************************/ | *************************************************************************************/ | ||||||
|     /*  END LEGAL */ | /*  END LEGAL */ | ||||||
| #ifndef GRID_NORMAL_EQUATIONS_H | #ifndef GRID_NORMAL_EQUATIONS_H | ||||||
| #define GRID_NORMAL_EQUATIONS_H | #define GRID_NORMAL_EQUATIONS_H | ||||||
| 
 | 
 | ||||||
| namespace Grid { | NAMESPACE_BEGIN(Grid); | ||||||
| 
 | 
 | ||||||
|   ///////////////////////////////////////////////////////////////////////////////////////////////////////
 | ///////////////////////////////////////////////////////////////////////////////////////////////////////
 | ||||||
|   // Take a matrix and form an NE solver calling a Herm solver
 | // Take a matrix and form an NE solver calling a Herm solver
 | ||||||
|   ///////////////////////////////////////////////////////////////////////////////////////////////////////
 | ///////////////////////////////////////////////////////////////////////////////////////////////////////
 | ||||||
|   template<class Field> class NormalEquations : public OperatorFunction<Field>{ | template<class Field> class NormalEquations : public OperatorFunction<Field>{ | ||||||
|   private: | private: | ||||||
|     SparseMatrixBase<Field> & _Matrix; |   SparseMatrixBase<Field> & _Matrix; | ||||||
|     OperatorFunction<Field> & _HermitianSolver; |   OperatorFunction<Field> & _HermitianSolver; | ||||||
| 
 | 
 | ||||||
|   public: | public: | ||||||
| 
 | 
 | ||||||
|     /////////////////////////////////////////////////////
 |   /////////////////////////////////////////////////////
 | ||||||
|     // Wrap the usual normal equations trick
 |   // Wrap the usual normal equations trick
 | ||||||
|     /////////////////////////////////////////////////////
 |   /////////////////////////////////////////////////////
 | ||||||
|   NormalEquations(SparseMatrixBase<Field> &Matrix, OperatorFunction<Field> &HermitianSolver)  |   NormalEquations(SparseMatrixBase<Field> &Matrix, OperatorFunction<Field> &HermitianSolver)  | ||||||
|     :  _Matrix(Matrix), _HermitianSolver(HermitianSolver) {};  |     :  _Matrix(Matrix), _HermitianSolver(HermitianSolver) {};  | ||||||
| 
 | 
 | ||||||
|     void operator() (const Field &in, Field &out){ |   void operator() (const Field &in, Field &out){ | ||||||
|   |   | ||||||
|       Field src(in._grid); |     Field src(in.Grid()); | ||||||
| 
 | 
 | ||||||
|       _Matrix.Mdag(in,src); |     _Matrix.Mdag(in,src); | ||||||
|       _HermitianSolver(src,out);  // Mdag M out = Mdag in
 |     _HermitianSolver(src,out);  // Mdag M out = Mdag in
 | ||||||
|   |   | ||||||
|     }      |   }      | ||||||
|   }; | }; | ||||||
| 
 | 
 | ||||||
| } | NAMESPACE_END(Grid); | ||||||
| #endif | #endif | ||||||
							
								
								
									
										45
									
								
								Grid/algorithms/iterative/PowerMethod.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								Grid/algorithms/iterative/PowerMethod.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,45 @@ | |||||||
|  | #pragma once | ||||||
|  | namespace Grid { | ||||||
|  | template<class Field> class PowerMethod   | ||||||
|  | {  | ||||||
|  |  public:  | ||||||
|  |  | ||||||
|  |   template<typename T>  static RealD normalise(T& v)  | ||||||
|  |   { | ||||||
|  |     RealD nn = norm2(v); | ||||||
|  |     nn = sqrt(nn); | ||||||
|  |     v = v * (1.0/nn); | ||||||
|  |     return nn; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   RealD operator()(LinearOperatorBase<Field> &HermOp, const Field &src)  | ||||||
|  |   {  | ||||||
|  |     GridBase *grid = src.Grid();  | ||||||
|  |      | ||||||
|  |     // quickly get an idea of the largest eigenvalue to more properly normalize the residuum  | ||||||
|  |     RealD evalMaxApprox = 0.0;  | ||||||
|  |     auto src_n = src;  | ||||||
|  |     auto tmp = src;  | ||||||
|  |     const int _MAX_ITER_EST_ = 50;  | ||||||
|  |  | ||||||
|  |     for (int i=0;i<_MAX_ITER_EST_;i++) {  | ||||||
|  |        | ||||||
|  |       normalise(src_n);  | ||||||
|  |       HermOp.HermOp(src_n,tmp);  | ||||||
|  |       RealD vnum = real(innerProduct(src_n,tmp)); // HermOp.  | ||||||
|  |       RealD vden = norm2(src_n);  | ||||||
|  |       RealD na = vnum/vden;  | ||||||
|  |        | ||||||
|  |       if ( (fabs(evalMaxApprox/na - 1.0) < 0.01) || (i==_MAX_ITER_EST_-1) ) {  | ||||||
|  |  	evalMaxApprox = na;  | ||||||
|  |  	return evalMaxApprox;  | ||||||
|  |       }  | ||||||
|  |       evalMaxApprox = na;  | ||||||
|  |       std::cout << GridLogMessage << " Approximation of largest eigenvalue: " << evalMaxApprox << std::endl; | ||||||
|  |       src_n = tmp; | ||||||
|  |     } | ||||||
|  |     assert(0); | ||||||
|  |     return 0; | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  | } | ||||||
							
								
								
									
										119
									
								
								Grid/algorithms/iterative/PrecConjugateResidual.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										119
									
								
								Grid/algorithms/iterative/PrecConjugateResidual.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,119 @@ | |||||||
|  | /************************************************************************************* | ||||||
|  |  | ||||||
|  |     Grid physics library, www.github.com/paboyle/Grid  | ||||||
|  |  | ||||||
|  |     Source file: ./lib/algorithms/iterative/PrecConjugateResidual.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_PREC_CONJUGATE_RESIDUAL_H | ||||||
|  | #define GRID_PREC_CONJUGATE_RESIDUAL_H | ||||||
|  |  | ||||||
|  | NAMESPACE_BEGIN(Grid); | ||||||
|  |  | ||||||
|  | ///////////////////////////////////////////////////////////// | ||||||
|  | // Base classes for iterative processes based on operators | ||||||
|  | // single input vec, single output vec. | ||||||
|  | ///////////////////////////////////////////////////////////// | ||||||
|  |  | ||||||
|  | template<class Field>  | ||||||
|  | class PrecConjugateResidual : public OperatorFunction<Field> { | ||||||
|  | public:                                                 | ||||||
|  |   RealD   Tolerance; | ||||||
|  |   Integer MaxIterations; | ||||||
|  |   int verbose; | ||||||
|  |   LinearFunction<Field> &Preconditioner; | ||||||
|  |  | ||||||
|  |   PrecConjugateResidual(RealD tol,Integer maxit,LinearFunction<Field> &Prec) : Tolerance(tol), MaxIterations(maxit),      Preconditioner(Prec) | ||||||
|  |   {  | ||||||
|  |     verbose=1; | ||||||
|  |   }; | ||||||
|  |  | ||||||
|  |   void operator() (LinearOperatorBase<Field> &Linop,const Field &src, Field &psi){ | ||||||
|  |  | ||||||
|  |     RealD a, b, c, d; | ||||||
|  |     RealD cp, ssq,rsq; | ||||||
|  |        | ||||||
|  |     RealD rAr, rAAr, rArp; | ||||||
|  |     RealD pAp, pAAp; | ||||||
|  |  | ||||||
|  |     GridBase *grid = src.Grid(); | ||||||
|  |     Field r(grid),  p(grid), Ap(grid), Ar(grid), z(grid); | ||||||
|  |        | ||||||
|  |     psi=zero; | ||||||
|  |     r  = src; | ||||||
|  |     Preconditioner(r,p); | ||||||
|  |  | ||||||
|  |        | ||||||
|  |  | ||||||
|  |     Linop.HermOpAndNorm(p,Ap,pAp,pAAp); | ||||||
|  |     Ar=Ap; | ||||||
|  |     rAr=pAp; | ||||||
|  |     rAAr=pAAp; | ||||||
|  |  | ||||||
|  |     cp =norm2(r); | ||||||
|  |     ssq=norm2(src); | ||||||
|  |     rsq=Tolerance*Tolerance*ssq; | ||||||
|  |  | ||||||
|  |     if (verbose) std::cout<<GridLogMessage<<"PrecConjugateResidual: iteration " <<0<<" residual "<<cp<< " target"<< rsq<<std::endl; | ||||||
|  |  | ||||||
|  |     for(int k=0;k<MaxIterations;k++){ | ||||||
|  |  | ||||||
|  |  | ||||||
|  |       Preconditioner(Ap,z); | ||||||
|  |       RealD rq= real(innerProduct(Ap,z));  | ||||||
|  |  | ||||||
|  |       a = rAr/rq; | ||||||
|  |  | ||||||
|  |       axpy(psi,a,p,psi); | ||||||
|  |       cp = axpy_norm(r,-a,z,r); | ||||||
|  |  | ||||||
|  |       rArp=rAr; | ||||||
|  |  | ||||||
|  |       Linop.HermOpAndNorm(r,Ar,rAr,rAAr); | ||||||
|  |  | ||||||
|  |       b   =rAr/rArp; | ||||||
|  |   | ||||||
|  |       axpy(p,b,p,r); | ||||||
|  |       pAAp=axpy_norm(Ap,b,Ap,Ar); | ||||||
|  | 	 | ||||||
|  |       if(verbose) std::cout<<GridLogMessage<<"PrecConjugateResidual: iteration " <<k<<" residual "<<cp<< " target"<< rsq<<std::endl; | ||||||
|  |  | ||||||
|  |       if(cp<rsq) { | ||||||
|  | 	Linop.HermOp(psi,Ap); | ||||||
|  | 	axpy(r,-1.0,src,Ap); | ||||||
|  | 	RealD true_resid = norm2(r)/ssq; | ||||||
|  | 	std::cout<<GridLogMessage<<"PrecConjugateResidual: Converged on iteration " <<k | ||||||
|  | 		 << " computed residual "<<sqrt(cp/ssq) | ||||||
|  | 		 << " true residual "<<sqrt(true_resid) | ||||||
|  | 		 << " target "       <<Tolerance <<std::endl; | ||||||
|  | 	return; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     std::cout<<GridLogMessage<<"PrecConjugateResidual did NOT converge"<<std::endl; | ||||||
|  |     assert(0); | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  | NAMESPACE_END(Grid); | ||||||
|  | #endif | ||||||
							
								
								
									
										243
									
								
								Grid/algorithms/iterative/PrecGeneralisedConjugateResidual.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										243
									
								
								Grid/algorithms/iterative/PrecGeneralisedConjugateResidual.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,243 @@ | |||||||
|  | /************************************************************************************* | ||||||
|  |  | ||||||
|  |     Grid physics library, www.github.com/paboyle/Grid  | ||||||
|  |  | ||||||
|  |     Source file: ./lib/algorithms/iterative/PrecGeneralisedConjugateResidual.h | ||||||
|  |  | ||||||
|  |     Copyright (C) 2015 | ||||||
|  |  | ||||||
|  | Author: Azusa Yamaguchi <ayamaguc@staffmail.ed.ac.uk> | ||||||
|  | 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_PREC_GCR_H | ||||||
|  | #define GRID_PREC_GCR_H | ||||||
|  |  | ||||||
|  | /////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  | //VPGCR Abe and Zhang, 2005. | ||||||
|  | //INTERNATIONAL JOURNAL OF NUMERICAL ANALYSIS AND MODELING | ||||||
|  | //Computing and Information Volume 2, Number 2, Pages 147-161 | ||||||
|  | //NB. Likely not original reference since they are focussing on a preconditioner variant. | ||||||
|  | //    but VPGCR was nicely written up in their paper | ||||||
|  | /////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  | NAMESPACE_BEGIN(Grid); | ||||||
|  |  | ||||||
|  | template<class Field> | ||||||
|  | class PrecGeneralisedConjugateResidual : public OperatorFunction<Field> { | ||||||
|  | public:                                                 | ||||||
|  |   using OperatorFunction<Field>::operator(); | ||||||
|  |  | ||||||
|  |   RealD   Tolerance; | ||||||
|  |   Integer MaxIterations; | ||||||
|  |   int verbose; | ||||||
|  |   int mmax; | ||||||
|  |   int nstep; | ||||||
|  |   int steps; | ||||||
|  |   GridStopWatch PrecTimer; | ||||||
|  |   GridStopWatch MatTimer; | ||||||
|  |   GridStopWatch LinalgTimer; | ||||||
|  |  | ||||||
|  |   LinearFunction<Field> &Preconditioner; | ||||||
|  |  | ||||||
|  |   PrecGeneralisedConjugateResidual(RealD tol,Integer maxit,LinearFunction<Field> &Prec,int _mmax,int _nstep) :  | ||||||
|  |     Tolerance(tol),  | ||||||
|  |     MaxIterations(maxit), | ||||||
|  |     Preconditioner(Prec), | ||||||
|  |     mmax(_mmax), | ||||||
|  |     nstep(_nstep) | ||||||
|  |   {  | ||||||
|  |     verbose=1; | ||||||
|  |   }; | ||||||
|  |  | ||||||
|  |   void operator() (LinearOperatorBase<Field> &Linop,const Field &src, Field &psi){ | ||||||
|  |  | ||||||
|  |     psi=Zero(); | ||||||
|  |     RealD cp, ssq,rsq; | ||||||
|  |     ssq=norm2(src); | ||||||
|  |     rsq=Tolerance*Tolerance*ssq; | ||||||
|  |        | ||||||
|  |     Field r(src.Grid()); | ||||||
|  |  | ||||||
|  |     PrecTimer.Reset(); | ||||||
|  |     MatTimer.Reset(); | ||||||
|  |     LinalgTimer.Reset(); | ||||||
|  |  | ||||||
|  |     GridStopWatch SolverTimer; | ||||||
|  |     SolverTimer.Start(); | ||||||
|  |  | ||||||
|  |     steps=0; | ||||||
|  |     for(int k=0;k<MaxIterations;k++){ | ||||||
|  |  | ||||||
|  |       cp=GCRnStep(Linop,src,psi,rsq); | ||||||
|  |  | ||||||
|  |       std::cout<<GridLogMessage<<"VPGCR("<<mmax<<","<<nstep<<") "<< steps <<" steps cp = "<<cp<<std::endl; | ||||||
|  |  | ||||||
|  |       if(cp<rsq) { | ||||||
|  |  | ||||||
|  | 	SolverTimer.Stop(); | ||||||
|  |  | ||||||
|  | 	Linop.HermOp(psi,r); | ||||||
|  | 	axpy(r,-1.0,src,r); | ||||||
|  | 	RealD tr = norm2(r); | ||||||
|  | 	std::cout<<GridLogMessage<<"PrecGeneralisedConjugateResidual: Converged on iteration " <<steps | ||||||
|  | 		 << " computed residual "<<sqrt(cp/ssq) | ||||||
|  | 		 << " true residual "    <<sqrt(tr/ssq) | ||||||
|  | 		 << " target "           <<Tolerance <<std::endl; | ||||||
|  |  | ||||||
|  | 	std::cout<<GridLogMessage<<"VPGCR Time elapsed: Total  "<< SolverTimer.Elapsed() <<std::endl; | ||||||
|  | 	std::cout<<GridLogMessage<<"VPGCR Time elapsed: Precon "<<   PrecTimer.Elapsed() <<std::endl; | ||||||
|  | 	std::cout<<GridLogMessage<<"VPGCR Time elapsed: Matrix "<<    MatTimer.Elapsed() <<std::endl; | ||||||
|  | 	std::cout<<GridLogMessage<<"VPGCR Time elapsed: Linalg "<< LinalgTimer.Elapsed() <<std::endl; | ||||||
|  | 	return; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |     } | ||||||
|  |     std::cout<<GridLogMessage<<"Variable Preconditioned GCR did not converge"<<std::endl; | ||||||
|  |     assert(0); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   RealD GCRnStep(LinearOperatorBase<Field> &Linop,const Field &src, Field &psi,RealD rsq){ | ||||||
|  |  | ||||||
|  |     RealD cp; | ||||||
|  |     RealD a, b; | ||||||
|  |     RealD zAz, zAAz; | ||||||
|  |     RealD rq; | ||||||
|  |  | ||||||
|  |     GridBase *grid = src.Grid(); | ||||||
|  |  | ||||||
|  |     Field r(grid); | ||||||
|  |     Field z(grid); | ||||||
|  |     Field tmp(grid); | ||||||
|  |     Field ttmp(grid); | ||||||
|  |     Field Az(grid); | ||||||
|  |  | ||||||
|  |     //////////////////////////////// | ||||||
|  |     // history for flexible orthog | ||||||
|  |     //////////////////////////////// | ||||||
|  |     std::vector<Field> q(mmax,grid); | ||||||
|  |     std::vector<Field> p(mmax,grid); | ||||||
|  |     std::vector<RealD> qq(mmax); | ||||||
|  |        | ||||||
|  |  | ||||||
|  |     ////////////////////////////////// | ||||||
|  |     // initial guess x0 is taken as nonzero. | ||||||
|  |     // r0=src-A x0 = src | ||||||
|  |     ////////////////////////////////// | ||||||
|  |     MatTimer.Start(); | ||||||
|  |     Linop.HermOpAndNorm(psi,Az,zAz,zAAz);  | ||||||
|  |     MatTimer.Stop(); | ||||||
|  |      | ||||||
|  |     LinalgTimer.Start(); | ||||||
|  |     r=src-Az; | ||||||
|  |     LinalgTimer.Stop(); | ||||||
|  |      | ||||||
|  |     ///////////////////// | ||||||
|  |     // p = Prec(r) | ||||||
|  |     ///////////////////// | ||||||
|  |     PrecTimer.Start(); | ||||||
|  |     Preconditioner(r,z); | ||||||
|  |     PrecTimer.Stop(); | ||||||
|  |  | ||||||
|  |     MatTimer.Start(); | ||||||
|  |     Linop.HermOp(z,tmp);  | ||||||
|  |     MatTimer.Stop(); | ||||||
|  |  | ||||||
|  |     LinalgTimer.Start(); | ||||||
|  |     ttmp=tmp; | ||||||
|  |     tmp=tmp-r; | ||||||
|  |     LinalgTimer.Stop(); | ||||||
|  |  | ||||||
|  |     /* | ||||||
|  |       std::cout<<GridLogMessage<<r<<std::endl; | ||||||
|  |       std::cout<<GridLogMessage<<z<<std::endl; | ||||||
|  |       std::cout<<GridLogMessage<<ttmp<<std::endl; | ||||||
|  |       std::cout<<GridLogMessage<<tmp<<std::endl; | ||||||
|  |     */ | ||||||
|  |  | ||||||
|  |     MatTimer.Start(); | ||||||
|  |     Linop.HermOpAndNorm(z,Az,zAz,zAAz);  | ||||||
|  |     MatTimer.Stop(); | ||||||
|  |  | ||||||
|  |     LinalgTimer.Start(); | ||||||
|  |     //p[0],q[0],qq[0]  | ||||||
|  |     p[0]= z; | ||||||
|  |     q[0]= Az; | ||||||
|  |     qq[0]= zAAz; | ||||||
|  |      | ||||||
|  |     cp =norm2(r); | ||||||
|  |     LinalgTimer.Stop(); | ||||||
|  |  | ||||||
|  |     for(int k=0;k<nstep;k++){ | ||||||
|  |  | ||||||
|  |       steps++; | ||||||
|  |  | ||||||
|  |       int kp     = k+1; | ||||||
|  |       int peri_k = k %mmax; | ||||||
|  |       int peri_kp= kp%mmax; | ||||||
|  |  | ||||||
|  |       LinalgTimer.Start(); | ||||||
|  |       rq= real(innerProduct(r,q[peri_k])); // what if rAr not real? | ||||||
|  |       a = rq/qq[peri_k]; | ||||||
|  |  | ||||||
|  |       axpy(psi,a,p[peri_k],psi);          | ||||||
|  |  | ||||||
|  |       cp = axpy_norm(r,-a,q[peri_k],r); | ||||||
|  |       LinalgTimer.Stop(); | ||||||
|  |  | ||||||
|  |       if((k==nstep-1)||(cp<rsq)){ | ||||||
|  | 	return cp; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       std::cout<<GridLogMessage<< " VPGCR_step["<<steps<<"]  resid " <<sqrt(cp/rsq)<<std::endl;  | ||||||
|  |  | ||||||
|  |       PrecTimer.Start(); | ||||||
|  |       Preconditioner(r,z);// solve Az = r | ||||||
|  |       PrecTimer.Stop(); | ||||||
|  |  | ||||||
|  |       MatTimer.Start(); | ||||||
|  |       Linop.HermOpAndNorm(z,Az,zAz,zAAz); | ||||||
|  |       Linop.HermOp(z,tmp); | ||||||
|  |       MatTimer.Stop(); | ||||||
|  |  | ||||||
|  |       LinalgTimer.Start(); | ||||||
|  |       tmp=tmp-r; | ||||||
|  |       std::cout<<GridLogMessage<< " Preconditioner resid " <<sqrt(norm2(tmp)/norm2(r))<<std::endl;  | ||||||
|  |  | ||||||
|  |       q[peri_kp]=Az; | ||||||
|  |       p[peri_kp]=z; | ||||||
|  |  | ||||||
|  |       int northog = ((kp)>(mmax-1))?(mmax-1):(kp);  // if more than mmax done, we orthog all mmax history. | ||||||
|  |       for(int back=0;back<northog;back++){ | ||||||
|  |  | ||||||
|  | 	int peri_back=(k-back)%mmax;   	  assert((k-back)>=0); | ||||||
|  |  | ||||||
|  | 	b=-real(innerProduct(q[peri_back],Az))/qq[peri_back]; | ||||||
|  | 	p[peri_kp]=p[peri_kp]+b*p[peri_back]; | ||||||
|  | 	q[peri_kp]=q[peri_kp]+b*q[peri_back]; | ||||||
|  |  | ||||||
|  |       } | ||||||
|  |       qq[peri_kp]=norm2(q[peri_kp]); // could use axpy_norm | ||||||
|  |       LinalgTimer.Stop(); | ||||||
|  |     } | ||||||
|  |     assert(0); // never reached | ||||||
|  |     return cp; | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  | NAMESPACE_END(Grid); | ||||||
|  | #endif | ||||||
							
								
								
									
										486
									
								
								Grid/algorithms/iterative/SchurRedBlack.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										486
									
								
								Grid/algorithms/iterative/SchurRedBlack.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,486 @@ | |||||||
|  |     /************************************************************************************* | ||||||
|  |  | ||||||
|  |     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; | ||||||
|  |     bool useSolnAsInitGuess; // if true user-supplied solution vector is used as initial guess for solver | ||||||
|  |   public: | ||||||
|  |  | ||||||
|  |     SchurRedBlackBase(OperatorFunction<Field> &HermitianRBSolver, const bool initSubGuess = false, | ||||||
|  |         const bool _solnAsInitGuess = false)  : | ||||||
|  |     _HermitianRBSolver(HermitianRBSolver), | ||||||
|  |     useSolnAsInitGuess(_solnAsInitGuess) | ||||||
|  |     {  | ||||||
|  |       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++){ | ||||||
|  |         if(useSolnAsInitGuess) { | ||||||
|  |           pickCheckerboard(Odd, sol_o[b], out[b]); | ||||||
|  |         } else { | ||||||
|  |           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 | ||||||
|  |       //////////////////////////////// | ||||||
|  |       if(useSolnAsInitGuess) { | ||||||
|  |         pickCheckerboard(Odd, sol_o, out); | ||||||
|  |       } else { | ||||||
|  |         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.  | ||||||
|  |     ///////////////////////////////////////////////////////////// | ||||||
|  |     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, | ||||||
|  |         const bool _solnAsInitGuess = false)  | ||||||
|  |       :    SchurRedBlackBase<Field> (HermitianRBSolver,initSubGuess,_solnAsInitGuess)  | ||||||
|  |     { | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     ////////////////////////////////////////////////////// | ||||||
|  |     // 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, | ||||||
|  |         const bool _solnAsInitGuess = false)   | ||||||
|  |       : SchurRedBlackBase<Field> (HermitianRBSolver,initSubGuess,_solnAsInitGuess) {}; | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     ////////////////////////////////////////////////////// | ||||||
|  |     // 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, | ||||||
|  |       const bool _solnAsInitGuess = false)   | ||||||
|  |     : SchurRedBlackBase<Field>(HermitianRBSolver,initSubGuess,_solnAsInitGuess) {}; | ||||||
|  |  | ||||||
|  |     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 | ||||||
							
								
								
									
										127
									
								
								Grid/allocator/AlignedAllocator.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										127
									
								
								Grid/allocator/AlignedAllocator.cc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,127 @@ | |||||||
|  | #include <Grid/GridCore.h> | ||||||
|  | #include <fcntl.h> | ||||||
|  |  | ||||||
|  | NAMESPACE_BEGIN(Grid); | ||||||
|  |  | ||||||
|  | MemoryStats *MemoryProfiler::stats = nullptr; | ||||||
|  | bool         MemoryProfiler::debug = false; | ||||||
|  |  | ||||||
|  | #ifdef POINTER_CACHE | ||||||
|  | int PointerCache::victim; | ||||||
|  |  | ||||||
|  | PointerCache::PointerCacheEntry PointerCache::Entries[PointerCache::Ncache]; | ||||||
|  |  | ||||||
|  | void *PointerCache::Insert(void *ptr,size_t bytes) { | ||||||
|  |  | ||||||
|  |   if (bytes < 4096 ) return ptr; | ||||||
|  |  | ||||||
|  | #ifdef GRID_OMP | ||||||
|  |   assert(omp_in_parallel()==0); | ||||||
|  | #endif  | ||||||
|  |  | ||||||
|  |   void * ret = NULL; | ||||||
|  |   int v = -1; | ||||||
|  |  | ||||||
|  |   for(int e=0;e<Ncache;e++) { | ||||||
|  |     if ( Entries[e].valid==0 ) { | ||||||
|  |       v=e;  | ||||||
|  |       break; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   if ( v==-1 ) { | ||||||
|  |     v=victim; | ||||||
|  |     victim = (victim+1)%Ncache; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   if ( Entries[v].valid ) { | ||||||
|  |     ret = Entries[v].address; | ||||||
|  |     Entries[v].valid = 0; | ||||||
|  |     Entries[v].address = NULL; | ||||||
|  |     Entries[v].bytes = 0; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   Entries[v].address=ptr; | ||||||
|  |   Entries[v].bytes  =bytes; | ||||||
|  |   Entries[v].valid  =1; | ||||||
|  |  | ||||||
|  |   return ret; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void *PointerCache::Lookup(size_t bytes) { | ||||||
|  |  | ||||||
|  |   if (bytes < 4096 ) return NULL; | ||||||
|  |  | ||||||
|  | #ifdef GRID_OMP | ||||||
|  |   assert(omp_in_parallel()==0); | ||||||
|  | #endif  | ||||||
|  |  | ||||||
|  |   for(int e=0;e<Ncache;e++){ | ||||||
|  |     if ( Entries[e].valid && ( Entries[e].bytes == bytes ) ) { | ||||||
|  |       Entries[e].valid = 0; | ||||||
|  |       return Entries[e].address; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   return NULL; | ||||||
|  | } | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | void check_huge_pages(void *Buf,uint64_t BYTES) | ||||||
|  | { | ||||||
|  | #ifdef __linux__ | ||||||
|  |   int fd = open("/proc/self/pagemap", O_RDONLY); | ||||||
|  |   assert(fd >= 0); | ||||||
|  |   const int page_size = 4096; | ||||||
|  |   uint64_t virt_pfn = (uint64_t)Buf / page_size; | ||||||
|  |   off_t offset = sizeof(uint64_t) * virt_pfn; | ||||||
|  |   uint64_t npages = (BYTES + page_size-1) / page_size; | ||||||
|  |   uint64_t pagedata[npages]; | ||||||
|  |   uint64_t ret = lseek(fd, offset, SEEK_SET); | ||||||
|  |   assert(ret == offset); | ||||||
|  |   ret = ::read(fd, pagedata, sizeof(uint64_t)*npages); | ||||||
|  |   assert(ret == sizeof(uint64_t) * npages); | ||||||
|  |   int nhugepages = npages / 512; | ||||||
|  |   int n4ktotal, nnothuge; | ||||||
|  |   n4ktotal = 0; | ||||||
|  |   nnothuge = 0; | ||||||
|  |   for (int i = 0; i < nhugepages; ++i) { | ||||||
|  |     uint64_t baseaddr = (pagedata[i*512] & 0x7fffffffffffffULL) * page_size; | ||||||
|  |     for (int j = 0; j < 512; ++j) { | ||||||
|  |       uint64_t pageaddr = (pagedata[i*512+j] & 0x7fffffffffffffULL) * page_size; | ||||||
|  |       ++n4ktotal; | ||||||
|  |       if (pageaddr != baseaddr + j * page_size) | ||||||
|  | 	++nnothuge; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   int rank = CartesianCommunicator::RankWorld(); | ||||||
|  |   printf("rank %d Allocated %d 4k pages, %d not in huge pages\n", rank, n4ktotal, nnothuge); | ||||||
|  | #endif | ||||||
|  | } | ||||||
|  |  | ||||||
|  | std::string sizeString(const size_t bytes) | ||||||
|  | { | ||||||
|  |   constexpr unsigned int bufSize = 256; | ||||||
|  |   const char             *suffixes[7] = {"", "K", "M", "G", "T", "P", "E"}; | ||||||
|  |   char                   buf[256]; | ||||||
|  |   size_t                 s     = 0; | ||||||
|  |   double                 count = bytes; | ||||||
|  |    | ||||||
|  |   while (count >= 1024 && s < 7) | ||||||
|  |     { | ||||||
|  |       s++; | ||||||
|  |       count /= 1024; | ||||||
|  |     } | ||||||
|  |   if (count - floor(count) == 0.0) | ||||||
|  |     { | ||||||
|  |       snprintf(buf, bufSize, "%d %sB", (int)count, suffixes[s]); | ||||||
|  |     } | ||||||
|  |   else | ||||||
|  |     { | ||||||
|  |       snprintf(buf, bufSize, "%.1f %sB", count, suffixes[s]); | ||||||
|  |     } | ||||||
|  |    | ||||||
|  |   return std::string(buf); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | NAMESPACE_END(Grid); | ||||||
|  |  | ||||||
							
								
								
									
										244
									
								
								Grid/allocator/AlignedAllocator.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										244
									
								
								Grid/allocator/AlignedAllocator.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,244 @@ | |||||||
|  | /************************************************************************************* | ||||||
|  |  | ||||||
|  |     Grid physics library, www.github.com/paboyle/Grid  | ||||||
|  |  | ||||||
|  |     Source file: ./lib/AlignedAllocator.h | ||||||
|  |  | ||||||
|  |     Copyright (C) 2015 | ||||||
|  |  | ||||||
|  | Author: Azusa Yamaguchi <ayamaguc@staffmail.ed.ac.uk> | ||||||
|  | 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_ALIGNED_ALLOCATOR_H | ||||||
|  | #define GRID_ALIGNED_ALLOCATOR_H | ||||||
|  |  | ||||||
|  | #ifdef HAVE_MALLOC_MALLOC_H | ||||||
|  | #include <malloc/malloc.h> | ||||||
|  | #endif | ||||||
|  | #ifdef HAVE_MALLOC_H | ||||||
|  | #include <malloc.h> | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #ifdef HAVE_MM_MALLOC_H | ||||||
|  | #include <mm_malloc.h> | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #define POINTER_CACHE | ||||||
|  | #define GRID_ALLOC_ALIGN (2*1024*1024) | ||||||
|  |  | ||||||
|  | NAMESPACE_BEGIN(Grid); | ||||||
|  |  | ||||||
|  | // Move control to configure.ac and Config.h? | ||||||
|  | #ifdef POINTER_CACHE | ||||||
|  | class PointerCache { | ||||||
|  | private: | ||||||
|  |  | ||||||
|  |   static const int Ncache=8; | ||||||
|  |   static int victim; | ||||||
|  |  | ||||||
|  |   typedef struct {  | ||||||
|  |     void *address; | ||||||
|  |     size_t bytes; | ||||||
|  |     int valid; | ||||||
|  |   } PointerCacheEntry; | ||||||
|  |      | ||||||
|  |   static PointerCacheEntry Entries[Ncache]; | ||||||
|  |  | ||||||
|  | public: | ||||||
|  |  | ||||||
|  |  | ||||||
|  |   static void *Insert(void *ptr,size_t bytes) ; | ||||||
|  |   static void *Lookup(size_t bytes) ; | ||||||
|  |  | ||||||
|  | }; | ||||||
|  | #endif   | ||||||
|  |  | ||||||
|  | std::string sizeString(size_t bytes); | ||||||
|  |  | ||||||
|  | struct MemoryStats | ||||||
|  | { | ||||||
|  |   size_t totalAllocated{0}, maxAllocated{0},  | ||||||
|  |     currentlyAllocated{0}, totalFreed{0}; | ||||||
|  | }; | ||||||
|  |      | ||||||
|  | class MemoryProfiler | ||||||
|  | { | ||||||
|  | public: | ||||||
|  |   static MemoryStats *stats; | ||||||
|  |   static bool        debug; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | #define memString(bytes) std::to_string(bytes) + " (" + sizeString(bytes) + ")" | ||||||
|  | #define profilerDebugPrint						\ | ||||||
|  |   if (MemoryProfiler::stats)						\ | ||||||
|  |     {									\ | ||||||
|  |       auto s = MemoryProfiler::stats;					\ | ||||||
|  |       std::cout << GridLogDebug << "[Memory debug] Stats " << MemoryProfiler::stats << std::endl; \ | ||||||
|  |       std::cout << GridLogDebug << "[Memory debug] total  : " << memString(s->totalAllocated) \ | ||||||
|  | 		<< std::endl;						\ | ||||||
|  |       std::cout << GridLogDebug << "[Memory debug] max    : " << memString(s->maxAllocated) \ | ||||||
|  | 		<< std::endl;						\ | ||||||
|  |       std::cout << GridLogDebug << "[Memory debug] current: " << memString(s->currentlyAllocated) \ | ||||||
|  | 		<< std::endl;						\ | ||||||
|  |       std::cout << GridLogDebug << "[Memory debug] freed  : " << memString(s->totalFreed) \ | ||||||
|  | 		<< std::endl;						\ | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | #define profilerAllocate(bytes)						\ | ||||||
|  |   if (MemoryProfiler::stats)						\ | ||||||
|  |     {									\ | ||||||
|  |       auto s = MemoryProfiler::stats;					\ | ||||||
|  |       s->totalAllocated     += (bytes);					\ | ||||||
|  |       s->currentlyAllocated += (bytes);					\ | ||||||
|  |       s->maxAllocated        = std::max(s->maxAllocated, s->currentlyAllocated); \ | ||||||
|  |     }									\ | ||||||
|  |   if (MemoryProfiler::debug)						\ | ||||||
|  |     {									\ | ||||||
|  |       std::cout << GridLogDebug << "[Memory debug] allocating " << memString(bytes) << std::endl; \ | ||||||
|  |       profilerDebugPrint;						\ | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | #define profilerFree(bytes)						\ | ||||||
|  |   if (MemoryProfiler::stats)						\ | ||||||
|  |     {									\ | ||||||
|  |       auto s = MemoryProfiler::stats;					\ | ||||||
|  |       s->totalFreed         += (bytes);					\ | ||||||
|  |       s->currentlyAllocated -= (bytes);					\ | ||||||
|  |     }									\ | ||||||
|  |   if (MemoryProfiler::debug)						\ | ||||||
|  |     {									\ | ||||||
|  |       std::cout << GridLogDebug << "[Memory debug] freeing " << memString(bytes) << std::endl; \ | ||||||
|  |       profilerDebugPrint;						\ | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | void check_huge_pages(void *Buf,uint64_t BYTES); | ||||||
|  |  | ||||||
|  | //////////////////////////////////////////////////////////////////// | ||||||
|  | // A lattice of something, but assume the something is SIMDized. | ||||||
|  | //////////////////////////////////////////////////////////////////// | ||||||
|  |  | ||||||
|  | template<typename _Tp> | ||||||
|  | class alignedAllocator { | ||||||
|  | public:  | ||||||
|  |   typedef std::size_t     size_type; | ||||||
|  |   typedef std::ptrdiff_t  difference_type; | ||||||
|  |   typedef _Tp*       pointer; | ||||||
|  |   typedef const _Tp* const_pointer; | ||||||
|  |   typedef _Tp&       reference; | ||||||
|  |   typedef const _Tp& const_reference; | ||||||
|  |   typedef _Tp        value_type; | ||||||
|  |  | ||||||
|  |   template<typename _Tp1>  struct rebind { typedef alignedAllocator<_Tp1> other; }; | ||||||
|  |   alignedAllocator() throw() { } | ||||||
|  |   alignedAllocator(const alignedAllocator&) throw() { } | ||||||
|  |   template<typename _Tp1> alignedAllocator(const alignedAllocator<_Tp1>&) throw() { } | ||||||
|  |   ~alignedAllocator() throw() { } | ||||||
|  |   pointer       address(reference __x)       const { return &__x; } | ||||||
|  |   size_type  max_size() const throw() { return size_t(-1) / sizeof(_Tp); } | ||||||
|  |  | ||||||
|  |   pointer allocate(size_type __n, const void* _p= 0) | ||||||
|  |   {  | ||||||
|  |     size_type bytes = __n*sizeof(_Tp); | ||||||
|  |     profilerAllocate(bytes); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | #ifdef POINTER_CACHE | ||||||
|  |     _Tp *ptr = (_Tp *) PointerCache::Lookup(bytes); | ||||||
|  | #else | ||||||
|  |     pointer ptr = nullptr; | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #ifdef GRID_NVCC | ||||||
|  |     //////////////////////////////////// | ||||||
|  |     // Unified (managed) memory | ||||||
|  |     //////////////////////////////////// | ||||||
|  |     if ( ptr == (_Tp *) NULL ) { | ||||||
|  |       auto err = cudaMallocManaged((void **)&ptr,bytes); | ||||||
|  |       if( err != cudaSuccess ) { | ||||||
|  | 	ptr = (_Tp *) NULL; | ||||||
|  | 	std::cerr << " cudaMallocManaged failed for " << bytes<<" bytes " <<cudaGetErrorString(err)<< std::endl; | ||||||
|  | 	assert(0); | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |     assert( ptr != (_Tp *)NULL); | ||||||
|  | #else  | ||||||
|  |     ////////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  |     // 2MB align; could make option probably doesn't need configurability | ||||||
|  |     ////////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  |   #ifdef HAVE_MM_MALLOC_H | ||||||
|  |     if ( ptr == (_Tp *) NULL ) ptr = (_Tp *) _mm_malloc(bytes,GRID_ALLOC_ALIGN); | ||||||
|  |   #else | ||||||
|  |     if ( ptr == (_Tp *) NULL ) ptr = (_Tp *) memalign(GRID_ALLOC_ALIGN,bytes); | ||||||
|  |   #endif | ||||||
|  |     assert( ptr != (_Tp *)NULL); | ||||||
|  |  | ||||||
|  |     ////////////////////////////////////////////////// | ||||||
|  |     // First touch optimise in threaded loop  | ||||||
|  |     ////////////////////////////////////////////////// | ||||||
|  |     uint64_t *cp = (uint64_t *)ptr; | ||||||
|  |     thread_for(n,bytes/sizeof(uint64_t), { // need only one touch per page | ||||||
|  |       cp[n]=0; | ||||||
|  |     }); | ||||||
|  | #endif | ||||||
|  |     return ptr; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   void deallocate(pointer __p, size_type __n) {  | ||||||
|  |     size_type bytes = __n * sizeof(_Tp); | ||||||
|  |  | ||||||
|  |     profilerFree(bytes); | ||||||
|  |  | ||||||
|  | #ifdef POINTER_CACHE | ||||||
|  |     pointer __freeme = (pointer)PointerCache::Insert((void *)__p,bytes); | ||||||
|  | #else  | ||||||
|  |     pointer __freeme = __p; | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #ifdef GRID_NVCC | ||||||
|  |     if ( __freeme ) cudaFree((void *)__freeme); | ||||||
|  | #else  | ||||||
|  |   #ifdef HAVE_MM_MALLOC_H | ||||||
|  |     if ( __freeme ) _mm_free((void *)__freeme);  | ||||||
|  |   #else | ||||||
|  |     if ( __freeme ) free((void *)__freeme); | ||||||
|  |   #endif | ||||||
|  | #endif | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   // FIXME: hack for the copy constructor, eventually it must be avoided | ||||||
|  |   void construct(pointer __p, const _Tp& __val) { new((void *)__p) _Tp(__val); }; | ||||||
|  |   //void construct(pointer __p, const _Tp& __val) { }; | ||||||
|  |   void construct(pointer __p) { }; | ||||||
|  |   void destroy(pointer __p) { }; | ||||||
|  | }; | ||||||
|  | template<typename _Tp>  inline bool operator==(const alignedAllocator<_Tp>&, const alignedAllocator<_Tp>&){ return true; } | ||||||
|  | template<typename _Tp>  inline bool operator!=(const alignedAllocator<_Tp>&, const alignedAllocator<_Tp>&){ return false; } | ||||||
|  |  | ||||||
|  | //////////////////////////////////////////////////////////////////////////////// | ||||||
|  | // Template typedefs | ||||||
|  | //////////////////////////////////////////////////////////////////////////////// | ||||||
|  | template<class T> using commAllocator = alignedAllocator<T>; | ||||||
|  | template<class T> using Vector     = std::vector<T,alignedAllocator<T> >;            | ||||||
|  | template<class T> using commVector = std::vector<T,alignedAllocator<T> >; | ||||||
|  | template<class T> using Matrix     = std::vector<std::vector<T,alignedAllocator<T> > >; | ||||||
|  |  | ||||||
|  | NAMESPACE_END(Grid); | ||||||
|  |  | ||||||
|  | #endif | ||||||
| @@ -1,4 +1,4 @@ | |||||||
|     /*************************************************************************************
 | /*************************************************************************************
 | ||||||
| 
 | 
 | ||||||
|     Grid physics library, www.github.com/paboyle/Grid  |     Grid physics library, www.github.com/paboyle/Grid  | ||||||
| 
 | 
 | ||||||
| @@ -23,8 +23,8 @@ Author: Peter Boyle <paboyle@ph.ed.ac.uk> | |||||||
|     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||||||
| 
 | 
 | ||||||
|     See the full license in the file "LICENSE" in the top level distribution directory |     See the full license in the file "LICENSE" in the top level distribution directory | ||||||
|     *************************************************************************************/ | *************************************************************************************/ | ||||||
|     /*  END LEGAL */ | /*  END LEGAL */ | ||||||
| #ifndef GRID_CARTESIAN_H | #ifndef GRID_CARTESIAN_H | ||||||
| #define GRID_CARTESIAN_H | #define GRID_CARTESIAN_H | ||||||
| 
 | 
 | ||||||
							
								
								
									
										290
									
								
								Grid/cartesian/Cartesian_base.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										290
									
								
								Grid/cartesian/Cartesian_base.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,290 @@ | |||||||
|  | /************************************************************************************* | ||||||
|  |  | ||||||
|  |     Grid physics library, www.github.com/paboyle/Grid  | ||||||
|  |  | ||||||
|  |     Source file: ./lib/cartesian/Cartesian_base.h | ||||||
|  |  | ||||||
|  |     Copyright (C) 2015 | ||||||
|  |  | ||||||
|  |     Author: Peter Boyle <paboyle@ph.ed.ac.uk> | ||||||
|  |     Author: paboyle <paboyle@ph.ed.ac.uk> | ||||||
|  |     Author: Guido Cossu <guido.cossu@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_CARTESIAN_BASE_H | ||||||
|  | #define GRID_CARTESIAN_BASE_H | ||||||
|  |  | ||||||
|  | NAMESPACE_BEGIN(Grid); | ||||||
|  |  | ||||||
|  | ////////////////////////////////////////////////////////////////////// | ||||||
|  | // Commicator provides information on the processor grid | ||||||
|  | ////////////////////////////////////////////////////////////////////// | ||||||
|  | //    unsigned long _ndimension; | ||||||
|  | //    Coordinate _processors; // processor grid | ||||||
|  | //    int              _processor;  // linear processor rank | ||||||
|  | //    Coordinate _processor_coor;  // linear processor rank | ||||||
|  | ////////////////////////////////////////////////////////////////////// | ||||||
|  | class GridBase : public CartesianCommunicator , public GridThread { | ||||||
|  |  | ||||||
|  | public: | ||||||
|  |   int dummy; | ||||||
|  |   // Give Lattice access | ||||||
|  |   template<class object> friend class Lattice; | ||||||
|  |  | ||||||
|  |   GridBase(const Coordinate & processor_grid) : CartesianCommunicator(processor_grid) {};  | ||||||
|  |  | ||||||
|  |   GridBase(const Coordinate & processor_grid, | ||||||
|  | 	   const CartesianCommunicator &parent, | ||||||
|  | 	   int &split_rank)  | ||||||
|  |     : CartesianCommunicator(processor_grid,parent,split_rank) {}; | ||||||
|  |  | ||||||
|  |   GridBase(const Coordinate & processor_grid, | ||||||
|  | 	   const CartesianCommunicator &parent)  | ||||||
|  |     : CartesianCommunicator(processor_grid,parent,dummy) {}; | ||||||
|  |  | ||||||
|  |   virtual ~GridBase() = default; | ||||||
|  |  | ||||||
|  |  | ||||||
|  |   // Physics Grid information. | ||||||
|  |   Coordinate _simd_layout;// Which dimensions get relayed out over simd lanes. | ||||||
|  |   Coordinate _fdimensions;// (full) Global dimensions of array prior to cb removal | ||||||
|  |   Coordinate _gdimensions;// Global dimensions of array after cb removal | ||||||
|  |   Coordinate _ldimensions;// local dimensions of array with processor images removed | ||||||
|  |   Coordinate _rdimensions;// Reduced local dimensions with simd lane images and processor images removed  | ||||||
|  |   Coordinate _ostride;    // Outer stride for each dimension | ||||||
|  |   Coordinate _istride;    // Inner stride i.e. within simd lane | ||||||
|  |   int _osites;                  // _isites*_osites = product(dimensions). | ||||||
|  |   int _isites; | ||||||
|  |   int _fsites;                  // _isites*_osites = product(dimensions). | ||||||
|  |   int _gsites; | ||||||
|  |   Coordinate _slice_block;// subslice information | ||||||
|  |   Coordinate _slice_stride; | ||||||
|  |   Coordinate _slice_nblock; | ||||||
|  |  | ||||||
|  |   Coordinate _lstart;     // local start of array in gcoors _processor_coor[d]*_ldimensions[d] | ||||||
|  |   Coordinate _lend  ;     // local end of array in gcoors   _processor_coor[d]*_ldimensions[d]+_ldimensions_[d]-1 | ||||||
|  |  | ||||||
|  |     bool _isCheckerBoarded;  | ||||||
|  |  | ||||||
|  | public: | ||||||
|  |  | ||||||
|  |   //////////////////////////////////////////////////////////////// | ||||||
|  |   // Checkerboarding interface is virtual and overridden by  | ||||||
|  |   // GridCartesian / GridRedBlackCartesian | ||||||
|  |   //////////////////////////////////////////////////////////////// | ||||||
|  |   virtual int CheckerBoarded(int dim)=0; | ||||||
|  |   virtual int CheckerBoard(const Coordinate &site)=0; | ||||||
|  |   virtual int CheckerBoardDestination(int source_cb,int shift,int dim)=0; | ||||||
|  |   virtual int CheckerBoardShift(int source_cb,int dim,int shift,int osite)=0; | ||||||
|  |   virtual int CheckerBoardShiftForCB(int source_cb,int dim,int shift,int cb)=0; | ||||||
|  |   virtual int CheckerBoardFromOindex (int Oindex)=0; | ||||||
|  |   virtual int CheckerBoardFromOindexTable (int Oindex)=0; | ||||||
|  |  | ||||||
|  |   ////////////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  |   // Local layout calculations | ||||||
|  |   ////////////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  |   // These routines are key. Subdivide the linearised cartesian index into | ||||||
|  |   //      "inner" index identifying which simd lane of object<vFcomplex> is associated with coord | ||||||
|  |   //      "outer" index identifying which element of _odata in class "Lattice" is associated with coord. | ||||||
|  |   // | ||||||
|  |   // Compared to, say, Blitz++ we simply need to store BOTH an inner stride and an outer | ||||||
|  |   // stride per dimension. The cost of evaluating the indexing information is doubled for an n-dimensional | ||||||
|  |   // coordinate. Note, however, for data parallel operations the "inner" indexing cost is not paid and all | ||||||
|  |   // lanes are operated upon simultaneously. | ||||||
|  |    | ||||||
|  |   virtual int oIndex(Coordinate &coor) | ||||||
|  |   { | ||||||
|  |     int idx=0; | ||||||
|  |     // Works with either global or local coordinates | ||||||
|  |     for(int d=0;d<_ndimension;d++) idx+=_ostride[d]*(coor[d]%_rdimensions[d]); | ||||||
|  |     return idx; | ||||||
|  |   } | ||||||
|  |   virtual int iIndex(Coordinate &lcoor) | ||||||
|  |   { | ||||||
|  |     int idx=0; | ||||||
|  |     for(int d=0;d<_ndimension;d++) idx+=_istride[d]*(lcoor[d]/_rdimensions[d]); | ||||||
|  |     return idx; | ||||||
|  |   } | ||||||
|  |   inline int oIndexReduced(Coordinate &ocoor) | ||||||
|  |   { | ||||||
|  |     int idx=0;  | ||||||
|  |     // ocoor is already reduced so can eliminate the modulo operation | ||||||
|  |     // for fast indexing and inline the routine | ||||||
|  |     for(int d=0;d<_ndimension;d++) idx+=_ostride[d]*ocoor[d]; | ||||||
|  |     return idx; | ||||||
|  |   } | ||||||
|  |   inline void oCoorFromOindex (Coordinate& coor,int Oindex){ | ||||||
|  |     Lexicographic::CoorFromIndex(coor,Oindex,_rdimensions); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   inline void InOutCoorToLocalCoor (Coordinate &ocoor, Coordinate &icoor, Coordinate &lcoor) { | ||||||
|  |     lcoor.resize(_ndimension); | ||||||
|  |     for (int d = 0; d < _ndimension; d++) | ||||||
|  |       lcoor[d] = ocoor[d] + _rdimensions[d] * icoor[d]; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   ////////////////////////////////////////////////////////// | ||||||
|  |   // SIMD lane addressing | ||||||
|  |   ////////////////////////////////////////////////////////// | ||||||
|  |   inline void iCoorFromIindex(Coordinate &coor,int lane) | ||||||
|  |   { | ||||||
|  |     Lexicographic::CoorFromIndex(coor,lane,_simd_layout); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   inline int PermuteDim(int dimension){ | ||||||
|  |     return _simd_layout[dimension]>1; | ||||||
|  |   } | ||||||
|  |   inline int PermuteType(int dimension){ | ||||||
|  |     int permute_type=0; | ||||||
|  |     // | ||||||
|  |     // Best way to encode this would be to present a mask  | ||||||
|  |     // for which simd dimensions are rotated, and the rotation | ||||||
|  |     // size. If there is only one simd dimension rotated, this is just  | ||||||
|  |     // a permute.  | ||||||
|  |     // | ||||||
|  |     // Cases: PermuteType == 1,2,4,8 | ||||||
|  |     // Distance should be either 0,1,2.. | ||||||
|  |     // | ||||||
|  |     if ( _simd_layout[dimension] > 2 ) {  | ||||||
|  |       for(int d=0;d<_ndimension;d++){ | ||||||
|  | 	if ( d != dimension ) assert ( (_simd_layout[d]==1)  ); | ||||||
|  |       } | ||||||
|  |       permute_type = RotateBit; // How to specify distance; this is not just direction. | ||||||
|  |       return permute_type; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     for(int d=_ndimension-1;d>dimension;d--){ | ||||||
|  |       if (_simd_layout[d]>1 ) permute_type++; | ||||||
|  |     } | ||||||
|  |     return permute_type; | ||||||
|  |   } | ||||||
|  |   //////////////////////////////////////////////////////////////// | ||||||
|  |   // Array sizing queries | ||||||
|  |   //////////////////////////////////////////////////////////////// | ||||||
|  |  | ||||||
|  |   inline int iSites(void) const { return _isites; }; | ||||||
|  |   inline int Nsimd(void)  const { return _isites; };// Synonymous with iSites | ||||||
|  |   inline int oSites(void) const { return _osites; }; | ||||||
|  |   inline int lSites(void) const { return _isites*_osites; };  | ||||||
|  |   inline int gSites(void) const { return _isites*_osites*_Nprocessors; };  | ||||||
|  |   inline int Nd    (void) const { return _ndimension;}; | ||||||
|  |  | ||||||
|  |   inline const Coordinate LocalStarts(void)             { return _lstart;    }; | ||||||
|  |   inline const Coordinate &FullDimensions(void)         { return _fdimensions;}; | ||||||
|  |   inline const Coordinate &GlobalDimensions(void)       { return _gdimensions;}; | ||||||
|  |   inline const Coordinate &LocalDimensions(void)        { return _ldimensions;}; | ||||||
|  |   inline const Coordinate &VirtualLocalDimensions(void) { return _ldimensions;}; | ||||||
|  |  | ||||||
|  |   //////////////////////////////////////////////////////////////// | ||||||
|  |   // Utility to print the full decomposition details  | ||||||
|  |   //////////////////////////////////////////////////////////////// | ||||||
|  |  | ||||||
|  |   void show_decomposition(){ | ||||||
|  |     std::cout << GridLogMessage << "\tFull Dimensions    : " << _fdimensions << std::endl; | ||||||
|  |     std::cout << GridLogMessage << "\tSIMD layout        : " << _simd_layout << std::endl; | ||||||
|  |     std::cout << GridLogMessage << "\tGlobal Dimensions  : " << _gdimensions << std::endl; | ||||||
|  |     std::cout << GridLogMessage << "\tLocal Dimensions   : " << _ldimensions << std::endl; | ||||||
|  |     std::cout << GridLogMessage << "\tReduced Dimensions : " << _rdimensions << std::endl; | ||||||
|  |     std::cout << GridLogMessage << "\tOuter strides      : " << _ostride << std::endl; | ||||||
|  |     std::cout << GridLogMessage << "\tInner strides      : " << _istride << std::endl; | ||||||
|  |     std::cout << GridLogMessage << "\tiSites             : " << _isites << std::endl; | ||||||
|  |     std::cout << GridLogMessage << "\toSites             : " << _osites << std::endl; | ||||||
|  |     std::cout << GridLogMessage << "\tlSites             : " << lSites() << std::endl;         | ||||||
|  |     std::cout << GridLogMessage << "\tgSites             : " << gSites() << std::endl; | ||||||
|  |     std::cout << GridLogMessage << "\tNd                 : " << _ndimension << std::endl;              | ||||||
|  |   }  | ||||||
|  |  | ||||||
|  |   //////////////////////////////////////////////////////////////// | ||||||
|  |   // Global addressing | ||||||
|  |   //////////////////////////////////////////////////////////////// | ||||||
|  |   void GlobalIndexToGlobalCoor(int gidx,Coordinate &gcoor){ | ||||||
|  |     assert(gidx< gSites()); | ||||||
|  |     Lexicographic::CoorFromIndex(gcoor,gidx,_gdimensions); | ||||||
|  |   } | ||||||
|  |   void LocalIndexToLocalCoor(int lidx,Coordinate &lcoor){ | ||||||
|  |     assert(lidx<lSites()); | ||||||
|  |     Lexicographic::CoorFromIndex(lcoor,lidx,_ldimensions); | ||||||
|  |   } | ||||||
|  |   void GlobalCoorToGlobalIndex(const Coordinate & gcoor,int & gidx){ | ||||||
|  |     gidx=0; | ||||||
|  |     int mult=1; | ||||||
|  |     for(int mu=0;mu<_ndimension;mu++) { | ||||||
|  |       gidx+=mult*gcoor[mu]; | ||||||
|  |       mult*=_gdimensions[mu]; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   void GlobalCoorToProcessorCoorLocalCoor(Coordinate &pcoor,Coordinate &lcoor,const Coordinate &gcoor) | ||||||
|  |   { | ||||||
|  |     pcoor.resize(_ndimension); | ||||||
|  |     lcoor.resize(_ndimension); | ||||||
|  |     for(int mu=0;mu<_ndimension;mu++){ | ||||||
|  |       int _fld  = _fdimensions[mu]/_processors[mu]; | ||||||
|  |       pcoor[mu] = gcoor[mu]/_fld; | ||||||
|  |       lcoor[mu] = gcoor[mu]%_fld; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   void GlobalCoorToRankIndex(int &rank, int &o_idx, int &i_idx ,const Coordinate &gcoor) | ||||||
|  |   { | ||||||
|  |     Coordinate pcoor; | ||||||
|  |     Coordinate lcoor; | ||||||
|  |     GlobalCoorToProcessorCoorLocalCoor(pcoor,lcoor,gcoor); | ||||||
|  |     rank = RankFromProcessorCoor(pcoor); | ||||||
|  |     /* | ||||||
|  |       Coordinate cblcoor(lcoor); | ||||||
|  |       for(int d=0;d<cblcoor.size();d++){ | ||||||
|  |       if( this->CheckerBoarded(d) ) { | ||||||
|  |       cblcoor[d] = lcoor[d]/2; | ||||||
|  |       } | ||||||
|  |       } | ||||||
|  |     */ | ||||||
|  |     i_idx= iIndex(lcoor); | ||||||
|  |     o_idx= oIndex(lcoor); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   void RankIndexToGlobalCoor(int rank, int o_idx, int i_idx , Coordinate &gcoor) | ||||||
|  |   { | ||||||
|  |     gcoor.resize(_ndimension); | ||||||
|  |     Coordinate coor(_ndimension); | ||||||
|  |  | ||||||
|  |     ProcessorCoorFromRank(rank,coor); | ||||||
|  |     for(int mu=0;mu<_ndimension;mu++) gcoor[mu] = _ldimensions[mu]*coor[mu]; | ||||||
|  |  | ||||||
|  |     iCoorFromIindex(coor,i_idx); | ||||||
|  |     for(int mu=0;mu<_ndimension;mu++) gcoor[mu] += _rdimensions[mu]*coor[mu]; | ||||||
|  |  | ||||||
|  |     oCoorFromOindex (coor,o_idx); | ||||||
|  |     for(int mu=0;mu<_ndimension;mu++) gcoor[mu] += coor[mu]; | ||||||
|  |        | ||||||
|  |   } | ||||||
|  |   void RankIndexCbToFullGlobalCoor(int rank, int o_idx, int i_idx, int cb,Coordinate &fcoor) | ||||||
|  |   { | ||||||
|  |     RankIndexToGlobalCoor(rank,o_idx,i_idx ,fcoor); | ||||||
|  |     if(CheckerBoarded(0)){ | ||||||
|  |       fcoor[0] = fcoor[0]*2+cb; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   void ProcessorCoorLocalCoorToGlobalCoor(Coordinate &Pcoor,Coordinate &Lcoor,Coordinate &gcoor) | ||||||
|  |   { | ||||||
|  |     gcoor.resize(_ndimension); | ||||||
|  |     for(int mu=0;mu<_ndimension;mu++) gcoor[mu] = Pcoor[mu]*_ldimensions[mu]+Lcoor[mu]; | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | NAMESPACE_END(Grid); | ||||||
|  | #endif | ||||||
							
								
								
									
										174
									
								
								Grid/cartesian/Cartesian_full.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										174
									
								
								Grid/cartesian/Cartesian_full.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,174 @@ | |||||||
|  | /************************************************************************************* | ||||||
|  |  | ||||||
|  |     Grid physics library, www.github.com/paboyle/Grid  | ||||||
|  |  | ||||||
|  |     Source file: ./lib/cartesian/Cartesian_full.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_CARTESIAN_FULL_H | ||||||
|  | #define GRID_CARTESIAN_FULL_H | ||||||
|  |  | ||||||
|  | NAMESPACE_BEGIN(Grid); | ||||||
|  |      | ||||||
|  | ///////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  | // Grid Support. | ||||||
|  | ///////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  |  | ||||||
|  | class GridCartesian: public GridBase { | ||||||
|  |  | ||||||
|  | public: | ||||||
|  |   int dummy; | ||||||
|  |   virtual int  CheckerBoardFromOindexTable (int Oindex) { | ||||||
|  |     return 0; | ||||||
|  |   } | ||||||
|  |   virtual int  CheckerBoardFromOindex (int Oindex) | ||||||
|  |   { | ||||||
|  |     return 0; | ||||||
|  |   } | ||||||
|  |   virtual int CheckerBoarded(int dim){ | ||||||
|  |     return 0; | ||||||
|  |   } | ||||||
|  |   virtual int CheckerBoard(const Coordinate &site){ | ||||||
|  |     return 0; | ||||||
|  |   } | ||||||
|  |   virtual int CheckerBoardDestination(int cb,int shift,int dim){ | ||||||
|  |     return 0; | ||||||
|  |   } | ||||||
|  |   virtual int CheckerBoardShiftForCB(int source_cb,int dim,int shift, int ocb){ | ||||||
|  |     return shift; | ||||||
|  |   } | ||||||
|  |   virtual int CheckerBoardShift(int source_cb,int dim,int shift, int osite){ | ||||||
|  |     return shift; | ||||||
|  |   } | ||||||
|  |   ///////////////////////////////////////////////////////////////////////// | ||||||
|  |   // Constructor takes a parent grid and possibly subdivides communicator. | ||||||
|  |   ///////////////////////////////////////////////////////////////////////// | ||||||
|  |   GridCartesian(const Coordinate &dimensions, | ||||||
|  | 		const Coordinate &simd_layout, | ||||||
|  | 		const Coordinate &processor_grid, | ||||||
|  | 		const GridCartesian &parent) : GridBase(processor_grid,parent,dummy) | ||||||
|  |   { | ||||||
|  |     Init(dimensions,simd_layout,processor_grid); | ||||||
|  |   } | ||||||
|  |   GridCartesian(const Coordinate &dimensions, | ||||||
|  | 		const Coordinate &simd_layout, | ||||||
|  | 		const Coordinate &processor_grid, | ||||||
|  | 		const GridCartesian &parent,int &split_rank) : GridBase(processor_grid,parent,split_rank) | ||||||
|  |   { | ||||||
|  |     Init(dimensions,simd_layout,processor_grid); | ||||||
|  |   } | ||||||
|  |   ///////////////////////////////////////////////////////////////////////// | ||||||
|  |   // Construct from comm world | ||||||
|  |   ///////////////////////////////////////////////////////////////////////// | ||||||
|  |   GridCartesian(const Coordinate &dimensions, | ||||||
|  | 		const Coordinate &simd_layout, | ||||||
|  | 		const Coordinate &processor_grid) : GridBase(processor_grid) | ||||||
|  |   { | ||||||
|  |     Init(dimensions,simd_layout,processor_grid); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   virtual ~GridCartesian() = default; | ||||||
|  |  | ||||||
|  |   void Init(const Coordinate &dimensions, | ||||||
|  | 	    const Coordinate &simd_layout, | ||||||
|  | 	    const Coordinate &processor_grid) | ||||||
|  |   { | ||||||
|  |     /////////////////////// | ||||||
|  |     // Grid information | ||||||
|  |     /////////////////////// | ||||||
|  |       _isCheckerBoarded = false; | ||||||
|  |     _ndimension = dimensions.size(); | ||||||
|  |  | ||||||
|  |     _fdimensions.resize(_ndimension); | ||||||
|  |     _gdimensions.resize(_ndimension); | ||||||
|  |     _ldimensions.resize(_ndimension); | ||||||
|  |     _rdimensions.resize(_ndimension); | ||||||
|  |     _simd_layout.resize(_ndimension); | ||||||
|  |     _lstart.resize(_ndimension); | ||||||
|  |     _lend.resize(_ndimension); | ||||||
|  |  | ||||||
|  |     _ostride.resize(_ndimension); | ||||||
|  |     _istride.resize(_ndimension); | ||||||
|  |  | ||||||
|  |     _fsites = _gsites = _osites = _isites = 1; | ||||||
|  |  | ||||||
|  |     for (int d = 0; d < _ndimension; d++) | ||||||
|  |       { | ||||||
|  |         _fdimensions[d] = dimensions[d];   // Global dimensions | ||||||
|  |         _gdimensions[d] = _fdimensions[d]; // Global dimensions | ||||||
|  |         _simd_layout[d] = simd_layout[d]; | ||||||
|  |         _fsites = _fsites * _fdimensions[d]; | ||||||
|  |         _gsites = _gsites * _gdimensions[d]; | ||||||
|  |  | ||||||
|  |         // Use a reduced simd grid | ||||||
|  |         _ldimensions[d] = _gdimensions[d] / _processors[d]; //local dimensions | ||||||
|  |         //std::cout << _ldimensions[d] << "  " << _gdimensions[d] << "  " << _processors[d] << std::endl; | ||||||
|  |         assert(_ldimensions[d] * _processors[d] == _gdimensions[d]); | ||||||
|  |  | ||||||
|  |         _rdimensions[d] = _ldimensions[d] / _simd_layout[d]; //overdecomposition | ||||||
|  |         assert(_rdimensions[d] * _simd_layout[d] == _ldimensions[d]); | ||||||
|  |  | ||||||
|  |         _lstart[d] = _processor_coor[d] * _ldimensions[d]; | ||||||
|  |         _lend[d] = _processor_coor[d] * _ldimensions[d] + _ldimensions[d] - 1; | ||||||
|  |         _osites *= _rdimensions[d]; | ||||||
|  |         _isites *= _simd_layout[d]; | ||||||
|  |  | ||||||
|  |         // Addressing support | ||||||
|  |         if (d == 0) | ||||||
|  | 	  { | ||||||
|  | 	    _ostride[d] = 1; | ||||||
|  | 	    _istride[d] = 1; | ||||||
|  | 	  } | ||||||
|  |         else | ||||||
|  | 	  { | ||||||
|  | 	    _ostride[d] = _ostride[d - 1] * _rdimensions[d - 1]; | ||||||
|  | 	    _istride[d] = _istride[d - 1] * _simd_layout[d - 1]; | ||||||
|  | 	  } | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |     /////////////////////// | ||||||
|  |     // subplane information | ||||||
|  |     /////////////////////// | ||||||
|  |     _slice_block.resize(_ndimension); | ||||||
|  |     _slice_stride.resize(_ndimension); | ||||||
|  |     _slice_nblock.resize(_ndimension); | ||||||
|  |  | ||||||
|  |     int block = 1; | ||||||
|  |     int nblock = 1; | ||||||
|  |     for (int d = 0; d < _ndimension; d++) | ||||||
|  |       nblock *= _rdimensions[d]; | ||||||
|  |  | ||||||
|  |     for (int d = 0; d < _ndimension; d++) | ||||||
|  |       { | ||||||
|  |         nblock /= _rdimensions[d]; | ||||||
|  |         _slice_block[d] = block; | ||||||
|  |         _slice_stride[d] = _ostride[d] * _rdimensions[d]; | ||||||
|  |         _slice_nblock[d] = nblock; | ||||||
|  |         block = block * _rdimensions[d]; | ||||||
|  |       } | ||||||
|  |   }; | ||||||
|  |  | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | NAMESPACE_END(Grid); | ||||||
|  | #endif | ||||||
							
								
								
									
										289
									
								
								Grid/cartesian/Cartesian_red_black.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										289
									
								
								Grid/cartesian/Cartesian_red_black.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,289 @@ | |||||||
|  | /************************************************************************************* | ||||||
|  |  | ||||||
|  |     Grid physics library, www.github.com/paboyle/Grid  | ||||||
|  |  | ||||||
|  |     Source file: ./lib/cartesian/Cartesian_red_black.h | ||||||
|  |  | ||||||
|  |     Copyright (C) 2015 | ||||||
|  |  | ||||||
|  | Author: Azusa Yamaguchi <ayamaguc@staffmail.ed.ac.uk> | ||||||
|  | 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_CARTESIAN_RED_BLACK_H | ||||||
|  | #define GRID_CARTESIAN_RED_BLACK_H | ||||||
|  |  | ||||||
|  | NAMESPACE_BEGIN(Grid); | ||||||
|  |  | ||||||
|  | static const int CbRed  =0; | ||||||
|  | static const int CbBlack=1; | ||||||
|  | static const int Even   =CbRed; | ||||||
|  | static const int Odd    =CbBlack; | ||||||
|  |      | ||||||
|  | // Specialise this for red black grids storing half the data like a chess board. | ||||||
|  | class GridRedBlackCartesian : public GridBase | ||||||
|  | { | ||||||
|  | public: | ||||||
|  |   Coordinate _checker_dim_mask; | ||||||
|  |   int              _checker_dim; | ||||||
|  |   std::vector<int> _checker_board; | ||||||
|  |  | ||||||
|  |   virtual int CheckerBoarded(int dim){ | ||||||
|  |     if( dim==_checker_dim) return 1; | ||||||
|  |     else return 0; | ||||||
|  |   } | ||||||
|  |   virtual int CheckerBoard(const Coordinate &site){ | ||||||
|  |     int linear=0; | ||||||
|  |     assert(site.size()==_ndimension); | ||||||
|  |     for(int d=0;d<_ndimension;d++){  | ||||||
|  |       if(_checker_dim_mask[d]) | ||||||
|  | 	linear=linear+site[d]; | ||||||
|  |     } | ||||||
|  |     return (linear&0x1); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   // Depending on the cb of site, we toggle source cb. | ||||||
|  |   // for block #b, element #e = (b, e) | ||||||
|  |   // we need  | ||||||
|  |   virtual int CheckerBoardShiftForCB(int source_cb,int dim,int shift,int ocb){ | ||||||
|  |     if(dim != _checker_dim) return shift; | ||||||
|  |  | ||||||
|  |     int fulldim =_fdimensions[dim]; | ||||||
|  |     shift = (shift+fulldim)%fulldim; | ||||||
|  |  | ||||||
|  |     // Probably faster with table lookup; | ||||||
|  |     // or by looping over x,y,z and multiply rather than computing checkerboard. | ||||||
|  | 	   | ||||||
|  |     if ( (source_cb+ocb)&1 ) { | ||||||
|  |       return (shift)/2; | ||||||
|  |     } else { | ||||||
|  |       return (shift+1)/2; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   virtual int  CheckerBoardFromOindexTable (int Oindex) { | ||||||
|  |     return _checker_board[Oindex]; | ||||||
|  |   } | ||||||
|  |   virtual int  CheckerBoardFromOindex (int Oindex) | ||||||
|  |   { | ||||||
|  |     Coordinate ocoor; | ||||||
|  |     oCoorFromOindex(ocoor,Oindex); | ||||||
|  |     return CheckerBoard(ocoor); | ||||||
|  |   } | ||||||
|  |   virtual int CheckerBoardShift(int source_cb,int dim,int shift,int osite){ | ||||||
|  |  | ||||||
|  |     if(dim != _checker_dim) return shift; | ||||||
|  |  | ||||||
|  |     int ocb=CheckerBoardFromOindex(osite); | ||||||
|  |        | ||||||
|  |     return CheckerBoardShiftForCB(source_cb,dim,shift,ocb); | ||||||
|  |   } | ||||||
|  |      | ||||||
|  |   virtual int CheckerBoardDestination(int source_cb,int shift,int dim){ | ||||||
|  |     if ( _checker_dim_mask[dim]  ) { | ||||||
|  |       // If _fdimensions[checker_dim] is odd, then shifting by 1 in other dims | ||||||
|  |       // does NOT cause a parity hop. | ||||||
|  |       int add=(dim==_checker_dim) ? 0 : _fdimensions[_checker_dim]; | ||||||
|  |       if ( (shift+add) &0x1) { | ||||||
|  | 	return 1-source_cb; | ||||||
|  |       } else { | ||||||
|  | 	return source_cb; | ||||||
|  |       } | ||||||
|  |     } else { | ||||||
|  |       return source_cb; | ||||||
|  |  | ||||||
|  |     } | ||||||
|  |   }; | ||||||
|  |  | ||||||
|  |   //////////////////////////////////////////////////////////// | ||||||
|  |   // Create Redblack from original grid; require full grid pointer ? | ||||||
|  |   //////////////////////////////////////////////////////////// | ||||||
|  |   GridRedBlackCartesian(const GridBase *base) : GridBase(base->_processors,*base) | ||||||
|  |   { | ||||||
|  |     int dims = base->_ndimension; | ||||||
|  |     Coordinate checker_dim_mask(dims,1); | ||||||
|  |     int checker_dim = 0; | ||||||
|  |     Init(base->_fdimensions,base->_simd_layout,base->_processors,checker_dim_mask,checker_dim); | ||||||
|  |   }; | ||||||
|  |  | ||||||
|  |   //////////////////////////////////////////////////////////// | ||||||
|  |   // Create redblack from original grid, with non-trivial checker dim mask | ||||||
|  |   //////////////////////////////////////////////////////////// | ||||||
|  |   GridRedBlackCartesian(const GridBase *base, | ||||||
|  | 			const Coordinate &checker_dim_mask, | ||||||
|  | 			int checker_dim | ||||||
|  | 			) :  GridBase(base->_processors,*base)  | ||||||
|  |   { | ||||||
|  |     Init(base->_fdimensions,base->_simd_layout,base->_processors,checker_dim_mask,checker_dim)  ; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   virtual ~GridRedBlackCartesian() = default; | ||||||
|  |  | ||||||
|  |   void Init(const Coordinate &dimensions, | ||||||
|  | 	    const Coordinate &simd_layout, | ||||||
|  | 	    const Coordinate &processor_grid, | ||||||
|  | 	    const Coordinate &checker_dim_mask, | ||||||
|  | 	    int checker_dim) | ||||||
|  |   { | ||||||
|  |  | ||||||
|  |       _isCheckerBoarded = true; | ||||||
|  |     _checker_dim = checker_dim; | ||||||
|  |     assert(checker_dim_mask[checker_dim] == 1); | ||||||
|  |     _ndimension = dimensions.size(); | ||||||
|  |     assert(checker_dim_mask.size() == _ndimension); | ||||||
|  |     assert(processor_grid.size() == _ndimension); | ||||||
|  |     assert(simd_layout.size() == _ndimension); | ||||||
|  |  | ||||||
|  |     _fdimensions.resize(_ndimension); | ||||||
|  |     _gdimensions.resize(_ndimension); | ||||||
|  |     _ldimensions.resize(_ndimension); | ||||||
|  |     _rdimensions.resize(_ndimension); | ||||||
|  |     _simd_layout.resize(_ndimension); | ||||||
|  |     _lstart.resize(_ndimension); | ||||||
|  |     _lend.resize(_ndimension); | ||||||
|  |  | ||||||
|  |     _ostride.resize(_ndimension); | ||||||
|  |     _istride.resize(_ndimension); | ||||||
|  |  | ||||||
|  |     _fsites = _gsites = _osites = _isites = 1; | ||||||
|  |  | ||||||
|  |     _checker_dim_mask = checker_dim_mask; | ||||||
|  |  | ||||||
|  |     for (int d = 0; d < _ndimension; d++) | ||||||
|  |       { | ||||||
|  |         _fdimensions[d] = dimensions[d]; | ||||||
|  |         _gdimensions[d] = _fdimensions[d]; | ||||||
|  |         _fsites = _fsites * _fdimensions[d]; | ||||||
|  |         _gsites = _gsites * _gdimensions[d]; | ||||||
|  |  | ||||||
|  |         if (d == _checker_dim) | ||||||
|  | 	  { | ||||||
|  | 	    assert((_gdimensions[d] & 0x1) == 0); | ||||||
|  | 	    _gdimensions[d] = _gdimensions[d] / 2; // Remove a checkerboard | ||||||
|  | 	    _gsites /= 2; | ||||||
|  | 	  } | ||||||
|  |         _ldimensions[d] = _gdimensions[d] / _processors[d]; | ||||||
|  |         assert(_ldimensions[d] * _processors[d] == _gdimensions[d]); | ||||||
|  |         _lstart[d] = _processor_coor[d] * _ldimensions[d]; | ||||||
|  |         _lend[d] = _processor_coor[d] * _ldimensions[d] + _ldimensions[d] - 1; | ||||||
|  |  | ||||||
|  |         // Use a reduced simd grid | ||||||
|  |         _simd_layout[d] = simd_layout[d]; | ||||||
|  |         _rdimensions[d] = _ldimensions[d] / _simd_layout[d]; // this is not checking if this is integer | ||||||
|  |         assert(_rdimensions[d] * _simd_layout[d] == _ldimensions[d]); | ||||||
|  |         assert(_rdimensions[d] > 0); | ||||||
|  |  | ||||||
|  |         // all elements of a simd vector must have same checkerboard. | ||||||
|  |         // If Ls vectorised, this must still be the case; e.g. dwf rb5d | ||||||
|  |         if (_simd_layout[d] > 1) | ||||||
|  | 	  { | ||||||
|  | 	    if (checker_dim_mask[d]) | ||||||
|  | 	      { | ||||||
|  | 		assert((_rdimensions[d] & 0x1) == 0); | ||||||
|  | 	      } | ||||||
|  | 	  } | ||||||
|  |  | ||||||
|  |         _osites *= _rdimensions[d]; | ||||||
|  |         _isites *= _simd_layout[d]; | ||||||
|  |  | ||||||
|  |         // Addressing support | ||||||
|  |         if (d == 0) | ||||||
|  | 	  { | ||||||
|  | 	    _ostride[d] = 1; | ||||||
|  | 	    _istride[d] = 1; | ||||||
|  | 	  } | ||||||
|  |         else | ||||||
|  | 	  { | ||||||
|  | 	    _ostride[d] = _ostride[d - 1] * _rdimensions[d - 1]; | ||||||
|  | 	    _istride[d] = _istride[d - 1] * _simd_layout[d - 1]; | ||||||
|  | 	  } | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |     //////////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  |     // subplane information | ||||||
|  |     //////////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  |     _slice_block.resize(_ndimension); | ||||||
|  |     _slice_stride.resize(_ndimension); | ||||||
|  |     _slice_nblock.resize(_ndimension); | ||||||
|  |  | ||||||
|  |     int block = 1; | ||||||
|  |     int nblock = 1; | ||||||
|  |     for (int d = 0; d < _ndimension; d++) | ||||||
|  |       nblock *= _rdimensions[d]; | ||||||
|  |  | ||||||
|  |     for (int d = 0; d < _ndimension; d++) | ||||||
|  |       { | ||||||
|  |         nblock /= _rdimensions[d]; | ||||||
|  |         _slice_block[d] = block; | ||||||
|  |         _slice_stride[d] = _ostride[d] * _rdimensions[d]; | ||||||
|  |         _slice_nblock[d] = nblock; | ||||||
|  |         block = block * _rdimensions[d]; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |     //////////////////////////////////////////////// | ||||||
|  |     // Create a checkerboard lookup table | ||||||
|  |     //////////////////////////////////////////////// | ||||||
|  |     int rvol = 1; | ||||||
|  |     for (int d = 0; d < _ndimension; d++) | ||||||
|  |       { | ||||||
|  |         rvol = rvol * _rdimensions[d]; | ||||||
|  |       } | ||||||
|  |     _checker_board.resize(rvol); | ||||||
|  |     for (int osite = 0; osite < _osites; osite++) | ||||||
|  |       { | ||||||
|  |         _checker_board[osite] = CheckerBoardFromOindex(osite); | ||||||
|  |       } | ||||||
|  |   }; | ||||||
|  |  | ||||||
|  | protected: | ||||||
|  |   virtual int oIndex(Coordinate &coor) | ||||||
|  |   { | ||||||
|  |     int idx = 0; | ||||||
|  |     for (int d = 0; d < _ndimension; d++) | ||||||
|  |       { | ||||||
|  |         if (d == _checker_dim) | ||||||
|  | 	  { | ||||||
|  | 	    idx += _ostride[d] * ((coor[d] / 2) % _rdimensions[d]); | ||||||
|  | 	  } | ||||||
|  |         else | ||||||
|  | 	  { | ||||||
|  | 	    idx += _ostride[d] * (coor[d] % _rdimensions[d]); | ||||||
|  | 	  } | ||||||
|  |       } | ||||||
|  |     return idx; | ||||||
|  |   }; | ||||||
|  |  | ||||||
|  |   virtual int iIndex(Coordinate &lcoor) | ||||||
|  |   { | ||||||
|  |     int idx = 0; | ||||||
|  |     for (int d = 0; d < _ndimension; d++) | ||||||
|  |       { | ||||||
|  |         if (d == _checker_dim) | ||||||
|  | 	  { | ||||||
|  | 	    idx += _istride[d] * (lcoor[d] / (2 * _rdimensions[d])); | ||||||
|  | 	  } | ||||||
|  |         else | ||||||
|  | 	  { | ||||||
|  | 	    idx += _istride[d] * (lcoor[d] / _rdimensions[d]); | ||||||
|  | 	  } | ||||||
|  |       } | ||||||
|  |     return idx; | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  | NAMESPACE_END(Grid); | ||||||
|  | #endif | ||||||
| @@ -1,4 +1,4 @@ | |||||||
|     /*************************************************************************************
 | /*************************************************************************************
 | ||||||
| 
 | 
 | ||||||
|     Grid physics library, www.github.com/paboyle/Grid  |     Grid physics library, www.github.com/paboyle/Grid  | ||||||
| 
 | 
 | ||||||
| @@ -23,11 +23,13 @@ Author: Peter Boyle <paboyle@ph.ed.ac.uk> | |||||||
|     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||||||
| 
 | 
 | ||||||
|     See the full license in the file "LICENSE" in the top level distribution directory |     See the full license in the file "LICENSE" in the top level distribution directory | ||||||
|     *************************************************************************************/ | *************************************************************************************/ | ||||||
|     /*  END LEGAL */ | /*  END LEGAL */ | ||||||
| #ifndef GRID_COMMUNICATOR_H | #ifndef GRID_COMMUNICATOR_H | ||||||
| #define GRID_COMMUNICATOR_H | #define GRID_COMMUNICATOR_H | ||||||
| 
 | 
 | ||||||
|  | #include <Grid/util/Coordinate.h> | ||||||
|  | #include <Grid/communicator/SharedMemory.h> | ||||||
| #include <Grid/communicator/Communicator_base.h> | #include <Grid/communicator/Communicator_base.h> | ||||||
| 
 | 
 | ||||||
| #endif | #endif | ||||||
							
								
								
									
										77
									
								
								Grid/communicator/Communicator_base.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										77
									
								
								Grid/communicator/Communicator_base.cc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,77 @@ | |||||||
|  | /************************************************************************************* | ||||||
|  |  | ||||||
|  |     Grid physics library, www.github.com/paboyle/Grid  | ||||||
|  |  | ||||||
|  |     Source file: ./lib/communicator/Communicator_none.cc | ||||||
|  |  | ||||||
|  |     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 */ | ||||||
|  | #include <Grid/GridCore.h> | ||||||
|  | #include <fcntl.h> | ||||||
|  | #include <unistd.h> | ||||||
|  | #include <limits.h> | ||||||
|  | #include <sys/mman.h> | ||||||
|  |  | ||||||
|  | NAMESPACE_BEGIN(Grid); | ||||||
|  |  | ||||||
|  | /////////////////////////////////////////////////////////////// | ||||||
|  | // Info that is setup once and indept of cartesian layout | ||||||
|  | /////////////////////////////////////////////////////////////// | ||||||
|  | CartesianCommunicator::CommunicatorPolicy_t   | ||||||
|  | CartesianCommunicator::CommunicatorPolicy= CartesianCommunicator::CommunicatorPolicyConcurrent; | ||||||
|  | int CartesianCommunicator::nCommThreads = -1; | ||||||
|  |  | ||||||
|  | ///////////////////////////////// | ||||||
|  | // Grid information queries | ||||||
|  | ///////////////////////////////// | ||||||
|  | int                      CartesianCommunicator::Dimensions(void)        { return _ndimension; }; | ||||||
|  | int                      CartesianCommunicator::IsBoss(void)            { return _processor==0; }; | ||||||
|  | int                      CartesianCommunicator::BossRank(void)          { return 0; }; | ||||||
|  | int                      CartesianCommunicator::ThisRank(void)          { return _processor; }; | ||||||
|  | const Coordinate & CartesianCommunicator::ThisProcessorCoor(void) { return _processor_coor; }; | ||||||
|  | const Coordinate & CartesianCommunicator::ProcessorGrid(void)     { return _processors; }; | ||||||
|  | int                      CartesianCommunicator::ProcessorCount(void)    { return _Nprocessors; }; | ||||||
|  |  | ||||||
|  | //////////////////////////////////////////////////////////////////////////////// | ||||||
|  | // very VERY rarely (Log, serial RNG) we need world without a grid | ||||||
|  | //////////////////////////////////////////////////////////////////////////////// | ||||||
|  |  | ||||||
|  | void CartesianCommunicator::GlobalSum(ComplexF &c) | ||||||
|  | { | ||||||
|  |   GlobalSumVector((float *)&c,2); | ||||||
|  | } | ||||||
|  | void CartesianCommunicator::GlobalSumVector(ComplexF *c,int N) | ||||||
|  | { | ||||||
|  |   GlobalSumVector((float *)c,2*N); | ||||||
|  | } | ||||||
|  | void CartesianCommunicator::GlobalSum(ComplexD &c) | ||||||
|  | { | ||||||
|  |   GlobalSumVector((double *)&c,2); | ||||||
|  | } | ||||||
|  | void CartesianCommunicator::GlobalSumVector(ComplexD *c,int N) | ||||||
|  | { | ||||||
|  |   GlobalSumVector((double *)c,2*N); | ||||||
|  | } | ||||||
|  |    | ||||||
|  | NAMESPACE_END(Grid); | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -1,5 +1,5 @@ | |||||||
| 
 | 
 | ||||||
|     /*************************************************************************************
 | /*************************************************************************************
 | ||||||
| 
 | 
 | ||||||
|     Grid physics library, www.github.com/paboyle/Grid  |     Grid physics library, www.github.com/paboyle/Grid  | ||||||
| 
 | 
 | ||||||
| @@ -24,112 +24,41 @@ Author: Peter Boyle <paboyle@ph.ed.ac.uk> | |||||||
|     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||||||
| 
 | 
 | ||||||
|     See the full license in the file "LICENSE" in the top level distribution directory |     See the full license in the file "LICENSE" in the top level distribution directory | ||||||
|     *************************************************************************************/ | *************************************************************************************/ | ||||||
|     /*  END LEGAL */ | /*  END LEGAL */ | ||||||
| #ifndef GRID_COMMUNICATOR_BASE_H | #ifndef GRID_COMMUNICATOR_BASE_H | ||||||
| #define GRID_COMMUNICATOR_BASE_H | #define GRID_COMMUNICATOR_BASE_H | ||||||
| 
 | 
 | ||||||
| ///////////////////////////////////
 | ///////////////////////////////////
 | ||||||
| // Processor layout information
 | // Processor layout information
 | ||||||
| ///////////////////////////////////
 | ///////////////////////////////////
 | ||||||
| #ifdef GRID_COMMS_MPI | #include <Grid/communicator/SharedMemory.h> | ||||||
| #include <mpi.h> |  | ||||||
| #endif |  | ||||||
| #ifdef GRID_COMMS_MPI3 |  | ||||||
| #include <mpi.h> |  | ||||||
| #endif |  | ||||||
| #ifdef GRID_COMMS_MPI3L |  | ||||||
| #include <mpi.h> |  | ||||||
| #endif |  | ||||||
| #ifdef GRID_COMMS_SHMEM |  | ||||||
| #include <mpp/shmem.h> |  | ||||||
| #endif |  | ||||||
| 
 | 
 | ||||||
| namespace Grid { | NAMESPACE_BEGIN(Grid); | ||||||
| 
 | 
 | ||||||
| class CartesianCommunicator { | class CartesianCommunicator : public SharedMemory { | ||||||
|   public:     |  | ||||||
| 
 | 
 | ||||||
|   // 65536 ranks per node adequate for now
 | public:     | ||||||
|   // 128MB shared memory for comms enought for 48^4 local vol comms
 |  | ||||||
|   // Give external control (command line override?) of this
 |  | ||||||
| 
 | 
 | ||||||
|   static const int      MAXLOG2RANKSPERNODE = 16;             |   ////////////////////////////////////////////
 | ||||||
|   static uint64_t MAX_MPI_SHM_BYTES; |   // Policies
 | ||||||
| 
 |   ////////////////////////////////////////////
 | ||||||
|   // Communicator should know nothing of the physics grid, only processor grid.
 |  | ||||||
|   int              _Nprocessors;     // How many in all
 |  | ||||||
|   std::vector<int> _processors;      // Which dimensions get relayed out over processors lanes.
 |  | ||||||
|   int              _processor;       // linear processor rank
 |  | ||||||
|   std::vector<int> _processor_coor;  // linear processor coordinate
 |  | ||||||
|   unsigned long _ndimension; |  | ||||||
| 
 |  | ||||||
| #if defined (GRID_COMMS_MPI) || defined (GRID_COMMS_MPI3) || defined (GRID_COMMS_MPI3L) |  | ||||||
|   static MPI_Comm communicator_world; |  | ||||||
|          MPI_Comm communicator; |  | ||||||
|   typedef MPI_Request CommsRequest_t; |  | ||||||
| #else  |  | ||||||
|   typedef int CommsRequest_t; |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
|   ////////////////////////////////////////////////////////////////////
 |  | ||||||
|   // Helper functionality for SHM Windows common to all other impls
 |  | ||||||
|   ////////////////////////////////////////////////////////////////////
 |  | ||||||
|   // Longer term; drop this in favour of a master / slave model with 
 |  | ||||||
|   // cartesian communicator on a subset of ranks, slave ranks controlled
 |  | ||||||
|   // by group leader with data xfer via shared memory
 |  | ||||||
|   ////////////////////////////////////////////////////////////////////
 |  | ||||||
| #ifdef GRID_COMMS_MPI3 |  | ||||||
| 
 |  | ||||||
|   static int ShmRank; |  | ||||||
|   static int ShmSize; |  | ||||||
|   static int GroupRank; |  | ||||||
|   static int GroupSize; |  | ||||||
|   static int WorldRank; |  | ||||||
|   static int WorldSize; |  | ||||||
| 
 |  | ||||||
|   std::vector<int>  WorldDims; |  | ||||||
|   std::vector<int>  GroupDims; |  | ||||||
|   std::vector<int>  ShmDims; |  | ||||||
|    |  | ||||||
|   std::vector<int> GroupCoor; |  | ||||||
|   std::vector<int> ShmCoor; |  | ||||||
|   std::vector<int> WorldCoor; |  | ||||||
| 
 |  | ||||||
|   static std::vector<int> GroupRanks;  |  | ||||||
|   static std::vector<int> MyGroup; |  | ||||||
|   static int ShmSetup; |  | ||||||
|   static MPI_Win ShmWindow;  |  | ||||||
|   static MPI_Comm ShmComm; |  | ||||||
|    |  | ||||||
|   std::vector<int>  LexicographicToWorldRank; |  | ||||||
|    |  | ||||||
|   static std::vector<void *> ShmCommBufs; |  | ||||||
| 
 |  | ||||||
| #else  |  | ||||||
|   static void ShmInitGeneric(void); |  | ||||||
|   static commVector<uint8_t> ShmBufStorageVector; |  | ||||||
| #endif  |  | ||||||
| 
 |  | ||||||
|   /////////////////////////////////
 |  | ||||||
|   // Grid information and queries
 |  | ||||||
|   // Implemented in Communicator_base.C
 |  | ||||||
|   /////////////////////////////////
 |  | ||||||
|   static void * ShmCommBuf; |  | ||||||
| 
 |  | ||||||
|   // Isend/Irecv/Wait, or Sendrecv blocking
 |  | ||||||
|   enum CommunicatorPolicy_t { CommunicatorPolicyConcurrent, CommunicatorPolicySequential }; |   enum CommunicatorPolicy_t { CommunicatorPolicyConcurrent, CommunicatorPolicySequential }; | ||||||
|   static CommunicatorPolicy_t CommunicatorPolicy; |   static CommunicatorPolicy_t CommunicatorPolicy; | ||||||
|   static void SetCommunicatorPolicy(CommunicatorPolicy_t policy ) { CommunicatorPolicy = policy; } |   static void SetCommunicatorPolicy(CommunicatorPolicy_t policy ) { CommunicatorPolicy = policy; } | ||||||
|  |   static int       nCommThreads; | ||||||
| 
 | 
 | ||||||
|   size_t heap_top; |   ////////////////////////////////////////////
 | ||||||
|   size_t heap_bytes; |   // Communicator should know nothing of the physics grid, only processor grid.
 | ||||||
| 
 |   ////////////////////////////////////////////
 | ||||||
|   void *ShmBufferSelf(void); |   int              _Nprocessors;     // How many in all
 | ||||||
|   void *ShmBuffer(int rank); |   Coordinate _processors;      // Which dimensions get relayed out over processors lanes.
 | ||||||
|   void *ShmBufferTranslate(int rank,void * local_p); |   int              _processor;       // linear processor rank
 | ||||||
|   void *ShmBufferMalloc(size_t bytes); |   Coordinate _processor_coor;  // linear processor coordinate
 | ||||||
|   void ShmBufferFreeAll(void) ; |   unsigned long    _ndimension; | ||||||
|  |   static Grid_MPI_Comm      communicator_world; | ||||||
|  |   Grid_MPI_Comm             communicator; | ||||||
|  |   std::vector<Grid_MPI_Comm> communicator_halo; | ||||||
|    |    | ||||||
|   ////////////////////////////////////////////////
 |   ////////////////////////////////////////////////
 | ||||||
|   // Must call in Grid startup
 |   // Must call in Grid startup
 | ||||||
| @@ -137,24 +66,38 @@ class CartesianCommunicator { | |||||||
|   static void Init(int *argc, char ***argv); |   static void Init(int *argc, char ***argv); | ||||||
| 
 | 
 | ||||||
|   ////////////////////////////////////////////////
 |   ////////////////////////////////////////////////
 | ||||||
|   // Constructor of any given grid
 |   // Constructors to sub-divide a parent communicator
 | ||||||
|  |   // and default to comm world
 | ||||||
|   ////////////////////////////////////////////////
 |   ////////////////////////////////////////////////
 | ||||||
|   CartesianCommunicator(const std::vector<int> &pdimensions_in); |   CartesianCommunicator(const Coordinate &processors,const CartesianCommunicator &parent,int &srank); | ||||||
|  |   CartesianCommunicator(const Coordinate &pdimensions_in); | ||||||
|  |   virtual ~CartesianCommunicator(); | ||||||
|  | 
 | ||||||
|  | private: | ||||||
|  | 
 | ||||||
|  |   ////////////////////////////////////////////////
 | ||||||
|  |   // Private initialise from an MPI communicator
 | ||||||
|  |   // Can use after an MPI_Comm_split, but hidden from user so private
 | ||||||
|  |   ////////////////////////////////////////////////
 | ||||||
|  |   void InitFromMPICommunicator(const Coordinate &processors, Grid_MPI_Comm communicator_base); | ||||||
|  | 
 | ||||||
|  | public: | ||||||
|  |    | ||||||
|    |    | ||||||
|   ////////////////////////////////////////////////////////////////////////////////////////
 |   ////////////////////////////////////////////////////////////////////////////////////////
 | ||||||
|   // Wraps MPI_Cart routines, or implements equivalent on other impls
 |   // Wraps MPI_Cart routines, or implements equivalent on other impls
 | ||||||
|   ////////////////////////////////////////////////////////////////////////////////////////
 |   ////////////////////////////////////////////////////////////////////////////////////////
 | ||||||
|   void ShiftedRanks(int dim,int shift,int & source, int & dest); |   void ShiftedRanks(int dim,int shift,int & source, int & dest); | ||||||
|   int  RankFromProcessorCoor(std::vector<int> &coor); |   int  RankFromProcessorCoor(Coordinate &coor); | ||||||
|   void ProcessorCoorFromRank(int rank,std::vector<int> &coor); |   void ProcessorCoorFromRank(int rank,Coordinate &coor); | ||||||
|    |    | ||||||
|  |   int                      Dimensions(void)        ; | ||||||
|   int                      IsBoss(void)            ; |   int                      IsBoss(void)            ; | ||||||
|   int                      BossRank(void)          ; |   int                      BossRank(void)          ; | ||||||
|   int                      ThisRank(void)          ; |   int                      ThisRank(void)          ; | ||||||
|   const std::vector<int> & ThisProcessorCoor(void) ; |   const Coordinate & ThisProcessorCoor(void) ; | ||||||
|   const std::vector<int> & ProcessorGrid(void)     ; |   const Coordinate & ProcessorGrid(void)     ; | ||||||
|   int                      ProcessorCount(void)    ; |   int                      ProcessorCount(void)    ; | ||||||
|   int                      NodeCount(void)    ; |  | ||||||
| 
 | 
 | ||||||
|   ////////////////////////////////////////////////////////////////////////////////
 |   ////////////////////////////////////////////////////////////////////////////////
 | ||||||
|   // very VERY rarely (Log, serial RNG) we need world without a grid
 |   // very VERY rarely (Log, serial RNG) we need world without a grid
 | ||||||
| @@ -175,6 +118,8 @@ class CartesianCommunicator { | |||||||
|   void GlobalSumVector(ComplexF *c,int N); |   void GlobalSumVector(ComplexF *c,int N); | ||||||
|   void GlobalSum(ComplexD &c); |   void GlobalSum(ComplexD &c); | ||||||
|   void GlobalSumVector(ComplexD *c,int N); |   void GlobalSumVector(ComplexD *c,int N); | ||||||
|  |   void GlobalXOR(uint32_t &); | ||||||
|  |   void GlobalXOR(uint64_t &); | ||||||
|    |    | ||||||
|   template<class obj> void GlobalSum(obj &o){ |   template<class obj> void GlobalSum(obj &o){ | ||||||
|     typedef typename obj::scalar_type scalar_type; |     typedef typename obj::scalar_type scalar_type; | ||||||
| @@ -207,14 +152,21 @@ class CartesianCommunicator { | |||||||
|    |    | ||||||
|   void SendToRecvFromComplete(std::vector<CommsRequest_t> &waitall); |   void SendToRecvFromComplete(std::vector<CommsRequest_t> &waitall); | ||||||
| 
 | 
 | ||||||
|   double StencilSendToRecvFromBegin(std::vector<CommsRequest_t> &list, |   double StencilSendToRecvFrom(void *xmit, | ||||||
| 				  void *xmit, | 			       int xmit_to_rank, | ||||||
| 				  int xmit_to_rank, | 			       void *recv, | ||||||
| 				  void *recv, | 			       int recv_from_rank, | ||||||
| 				  int recv_from_rank, | 			       int bytes,int dir); | ||||||
| 				  int bytes); |  | ||||||
| 
 | 
 | ||||||
|   void StencilSendToRecvFromComplete(std::vector<CommsRequest_t> &waitall); |   double StencilSendToRecvFromBegin(std::vector<CommsRequest_t> &list, | ||||||
|  | 				    void *xmit, | ||||||
|  | 				    int xmit_to_rank, | ||||||
|  | 				    void *recv, | ||||||
|  | 				    int recv_from_rank, | ||||||
|  | 				    int bytes,int dir); | ||||||
|  |    | ||||||
|  |    | ||||||
|  |   void StencilSendToRecvFromComplete(std::vector<CommsRequest_t> &waitall,int i); | ||||||
|   void StencilBarrier(void); |   void StencilBarrier(void); | ||||||
| 
 | 
 | ||||||
|   ////////////////////////////////////////////////////////////
 |   ////////////////////////////////////////////////////////////
 | ||||||
| @@ -227,12 +179,30 @@ class CartesianCommunicator { | |||||||
|   ////////////////////////////////////////////////////////////
 |   ////////////////////////////////////////////////////////////
 | ||||||
|   void Broadcast(int root,void* data, int bytes); |   void Broadcast(int root,void* data, int bytes); | ||||||
| 
 | 
 | ||||||
|  |   ////////////////////////////////////////////////////////////
 | ||||||
|  |   // All2All down one dimension
 | ||||||
|  |   ////////////////////////////////////////////////////////////
 | ||||||
|  |   template<class T> void AllToAll(int dim,std::vector<T> &in, std::vector<T> &out){ | ||||||
|  |     assert(dim>=0); | ||||||
|  |     assert(dim<_ndimension); | ||||||
|  |     assert(in.size()==out.size()); | ||||||
|  |     int numnode = _processors[dim]; | ||||||
|  |     uint64_t bytes=sizeof(T); | ||||||
|  |     uint64_t words=in.size()/numnode; | ||||||
|  |     assert(numnode * words == in.size()); | ||||||
|  |     assert(words < (1ULL<<31)); | ||||||
|  |     AllToAll(dim,(void *)&in[0],(void *)&out[0],words,bytes); | ||||||
|  |   } | ||||||
|  |   void AllToAll(int dim  ,void *in,void *out,uint64_t words,uint64_t bytes); | ||||||
|  |   void AllToAll(void  *in,void *out,uint64_t words         ,uint64_t bytes); | ||||||
|  |    | ||||||
|   template<class obj> void Broadcast(int root,obj &data) |   template<class obj> void Broadcast(int root,obj &data) | ||||||
|     { |   { | ||||||
|       Broadcast(root,(void *)&data,sizeof(data)); |     Broadcast(root,(void *)&data,sizeof(data)); | ||||||
|     }; |   } | ||||||
| 
 | 
 | ||||||
| };  | };  | ||||||
| } | 
 | ||||||
|  | NAMESPACE_END(Grid); | ||||||
| 
 | 
 | ||||||
| #endif | #endif | ||||||
							
								
								
									
										483
									
								
								Grid/communicator/Communicator_mpi3.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										483
									
								
								Grid/communicator/Communicator_mpi3.cc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,483 @@ | |||||||
|  | /************************************************************************************* | ||||||
|  |  | ||||||
|  |     Grid physics library, www.github.com/paboyle/Grid  | ||||||
|  |  | ||||||
|  |     Source file: ./lib/communicator/Communicator_mpi.cc | ||||||
|  |  | ||||||
|  |     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 */ | ||||||
|  | #include <Grid/GridCore.h> | ||||||
|  | #include <Grid/communicator/SharedMemory.h> | ||||||
|  |  | ||||||
|  | NAMESPACE_BEGIN(Grid); | ||||||
|  |  | ||||||
|  | Grid_MPI_Comm       CartesianCommunicator::communicator_world; | ||||||
|  |  | ||||||
|  | //////////////////////////////////////////// | ||||||
|  | // First initialise of comms system | ||||||
|  | //////////////////////////////////////////// | ||||||
|  | void CartesianCommunicator::Init(int *argc, char ***argv)  | ||||||
|  | { | ||||||
|  |  | ||||||
|  |   int flag; | ||||||
|  |   int provided; | ||||||
|  |  | ||||||
|  |   MPI_Initialized(&flag); // needed to coexist with other libs apparently | ||||||
|  |   if ( !flag ) { | ||||||
|  |     MPI_Init_thread(argc,argv,MPI_THREAD_MULTIPLE,&provided); | ||||||
|  |  | ||||||
|  |     //If only 1 comms thread we require any threading mode other than SINGLE, but for multiple comms threads we need MULTIPLE | ||||||
|  |     if( (nCommThreads == 1) && (provided == MPI_THREAD_SINGLE) ) { | ||||||
|  |       assert(0); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if( (nCommThreads > 1) && (provided != MPI_THREAD_MULTIPLE) ) { | ||||||
|  |       assert(0); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   // Never clean up as done once. | ||||||
|  |   MPI_Comm_dup (MPI_COMM_WORLD,&communicator_world); | ||||||
|  |  | ||||||
|  |   Grid_quiesce_nodes(); | ||||||
|  |   GlobalSharedMemory::Init(communicator_world); | ||||||
|  |   GlobalSharedMemory::SharedMemoryAllocate( | ||||||
|  | 		   GlobalSharedMemory::MAX_MPI_SHM_BYTES, | ||||||
|  | 		   GlobalSharedMemory::Hugepages); | ||||||
|  |   Grid_unquiesce_nodes(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /////////////////////////////////////////////////////////////////////////// | ||||||
|  | // Use cartesian communicators now even in MPI3 | ||||||
|  | /////////////////////////////////////////////////////////////////////////// | ||||||
|  | void CartesianCommunicator::ShiftedRanks(int dim,int shift,int &source,int &dest) | ||||||
|  | { | ||||||
|  |   int ierr=MPI_Cart_shift(communicator,dim,shift,&source,&dest); | ||||||
|  |   assert(ierr==0); | ||||||
|  | } | ||||||
|  | int CartesianCommunicator::RankFromProcessorCoor(Coordinate &coor) | ||||||
|  | { | ||||||
|  |   int rank; | ||||||
|  |   int ierr=MPI_Cart_rank  (communicator, &coor[0], &rank); | ||||||
|  |   assert(ierr==0); | ||||||
|  |   return rank; | ||||||
|  | } | ||||||
|  | void  CartesianCommunicator::ProcessorCoorFromRank(int rank, Coordinate &coor) | ||||||
|  | { | ||||||
|  |   coor.resize(_ndimension); | ||||||
|  |   int ierr=MPI_Cart_coords  (communicator, rank, _ndimension,&coor[0]); | ||||||
|  |   assert(ierr==0); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | //////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  | // Initialises from communicator_world | ||||||
|  | //////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  | CartesianCommunicator::CartesianCommunicator(const Coordinate &processors)  | ||||||
|  | { | ||||||
|  |   MPI_Comm optimal_comm; | ||||||
|  |   //////////////////////////////////////////////////// | ||||||
|  |   // Remap using the shared memory optimising routine | ||||||
|  |   // The remap creates a comm which must be freed | ||||||
|  |   //////////////////////////////////////////////////// | ||||||
|  |   GlobalSharedMemory::OptimalCommunicator    (processors,optimal_comm); | ||||||
|  |   InitFromMPICommunicator(processors,optimal_comm); | ||||||
|  |   SetCommunicator(optimal_comm); | ||||||
|  |   /////////////////////////////////////////////////// | ||||||
|  |   // Free the temp communicator | ||||||
|  |   /////////////////////////////////////////////////// | ||||||
|  |   MPI_Comm_free(&optimal_comm); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | ////////////////////////////////// | ||||||
|  | // Try to subdivide communicator | ||||||
|  | ////////////////////////////////// | ||||||
|  | CartesianCommunicator::CartesianCommunicator(const Coordinate &processors,const CartesianCommunicator &parent,int &srank)     | ||||||
|  | { | ||||||
|  |   _ndimension = processors.size();  assert(_ndimension>=1); | ||||||
|  |   int parent_ndimension = parent._ndimension; assert(_ndimension >= parent._ndimension); | ||||||
|  |   Coordinate parent_processor_coor(_ndimension,0); | ||||||
|  |   Coordinate parent_processors    (_ndimension,1); | ||||||
|  |  | ||||||
|  |   // Can make 5d grid from 4d etc... | ||||||
|  |   int pad = _ndimension-parent_ndimension; | ||||||
|  |   for(int d=0;d<parent_ndimension;d++){ | ||||||
|  |     parent_processor_coor[pad+d]=parent._processor_coor[d]; | ||||||
|  |     parent_processors    [pad+d]=parent._processors[d]; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   ////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  |   // split the communicator | ||||||
|  |   ////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  |   //  int Nparent = parent._processors ;  | ||||||
|  |   int Nparent; | ||||||
|  |   MPI_Comm_size(parent.communicator,&Nparent); | ||||||
|  |  | ||||||
|  |   int childsize=1; | ||||||
|  |   for(int d=0;d<processors.size();d++) { | ||||||
|  |     childsize *= processors[d]; | ||||||
|  |   } | ||||||
|  |   int Nchild = Nparent/childsize; | ||||||
|  |   assert (childsize * Nchild == Nparent); | ||||||
|  |  | ||||||
|  |   Coordinate ccoor(_ndimension); // coor within subcommunicator | ||||||
|  |   Coordinate scoor(_ndimension); // coor of split within parent | ||||||
|  |   Coordinate ssize(_ndimension); // coor of split within parent | ||||||
|  |  | ||||||
|  |   for(int d=0;d<_ndimension;d++){ | ||||||
|  |     ccoor[d] = parent_processor_coor[d] % processors[d]; | ||||||
|  |     scoor[d] = parent_processor_coor[d] / processors[d]; | ||||||
|  |     ssize[d] = parent_processors[d]     / processors[d]; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   // rank within subcomm ; srank is rank of subcomm within blocks of subcomms | ||||||
|  |   int crank;   | ||||||
|  |   // Mpi uses the reverse Lexico convention to us; so reversed routines called | ||||||
|  |   Lexicographic::IndexFromCoorReversed(ccoor,crank,processors); // processors is the split grid dimensions | ||||||
|  |   Lexicographic::IndexFromCoorReversed(scoor,srank,ssize);      // ssize is the number of split grids | ||||||
|  |  | ||||||
|  |   MPI_Comm comm_split; | ||||||
|  |   if ( Nchild > 1 ) {  | ||||||
|  |  | ||||||
|  |     //////////////////////////////////////////////////////////////// | ||||||
|  |     // Split the communicator | ||||||
|  |     //////////////////////////////////////////////////////////////// | ||||||
|  |     int ierr= MPI_Comm_split(parent.communicator,srank,crank,&comm_split); | ||||||
|  |     assert(ierr==0); | ||||||
|  |  | ||||||
|  |   } else { | ||||||
|  |     srank = 0; | ||||||
|  |     int ierr = MPI_Comm_dup (parent.communicator,&comm_split); | ||||||
|  |     assert(ierr==0); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   ////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  |   // Set up from the new split communicator | ||||||
|  |   ////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  |   InitFromMPICommunicator(processors,comm_split); | ||||||
|  |  | ||||||
|  |   ////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  |   // Take the right SHM buffers | ||||||
|  |   ////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  |   SetCommunicator(comm_split); | ||||||
|  |  | ||||||
|  |   /////////////////////////////////////////////// | ||||||
|  |   // Free the temp communicator  | ||||||
|  |   /////////////////////////////////////////////// | ||||||
|  |   MPI_Comm_free(&comm_split); | ||||||
|  |  | ||||||
|  |   if(0){  | ||||||
|  |     std::cout << " ndim " <<_ndimension<<" " << parent._ndimension << std::endl; | ||||||
|  |     for(int d=0;d<processors.size();d++){ | ||||||
|  |       std::cout << d<< " " << _processor_coor[d] <<" " <<  ccoor[d]<<std::endl; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   for(int d=0;d<processors.size();d++){ | ||||||
|  |     assert(_processor_coor[d] == ccoor[d] ); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void CartesianCommunicator::InitFromMPICommunicator(const Coordinate &processors, MPI_Comm communicator_base) | ||||||
|  | { | ||||||
|  |   //////////////////////////////////////////////////// | ||||||
|  |   // Creates communicator, and the communicator_halo | ||||||
|  |   //////////////////////////////////////////////////// | ||||||
|  |   _ndimension = processors.size(); | ||||||
|  |   _processor_coor.resize(_ndimension); | ||||||
|  |  | ||||||
|  |   ///////////////////////////////// | ||||||
|  |   // Count the requested nodes | ||||||
|  |   ///////////////////////////////// | ||||||
|  |   _Nprocessors=1; | ||||||
|  |   _processors = processors; | ||||||
|  |   for(int i=0;i<_ndimension;i++){ | ||||||
|  |     _Nprocessors*=_processors[i]; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   Coordinate periodic(_ndimension,1); | ||||||
|  |   MPI_Cart_create(communicator_base, _ndimension,&_processors[0],&periodic[0],0,&communicator); | ||||||
|  |   MPI_Comm_rank(communicator,&_processor); | ||||||
|  |   MPI_Cart_coords(communicator,_processor,_ndimension,&_processor_coor[0]); | ||||||
|  |  | ||||||
|  |   if ( 0 && (communicator_base != communicator_world) ) { | ||||||
|  |     std::cout << "InitFromMPICommunicator Cartesian communicator created with a non-world communicator"<<std::endl; | ||||||
|  |     std::cout << " new communicator rank "<<_processor<< " coor ["<<_ndimension<<"] "; | ||||||
|  |     for(int d=0;d<_processors.size();d++){ | ||||||
|  |       std::cout << _processor_coor[d]<<" "; | ||||||
|  |     } | ||||||
|  |     std::cout << std::endl; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   int Size; | ||||||
|  |   MPI_Comm_size(communicator,&Size); | ||||||
|  |  | ||||||
|  |   communicator_halo.resize (2*_ndimension); | ||||||
|  |   for(int i=0;i<_ndimension*2;i++){ | ||||||
|  |     MPI_Comm_dup(communicator,&communicator_halo[i]); | ||||||
|  |   } | ||||||
|  |   assert(Size==_Nprocessors); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | CartesianCommunicator::~CartesianCommunicator() | ||||||
|  | { | ||||||
|  |   int MPI_is_finalised; | ||||||
|  |   MPI_Finalized(&MPI_is_finalised); | ||||||
|  |   if (communicator && !MPI_is_finalised) { | ||||||
|  |     MPI_Comm_free(&communicator); | ||||||
|  |     for(int i=0;i<communicator_halo.size();i++){ | ||||||
|  |       MPI_Comm_free(&communicator_halo[i]); | ||||||
|  |     } | ||||||
|  |   }   | ||||||
|  | } | ||||||
|  | void CartesianCommunicator::GlobalSum(uint32_t &u){ | ||||||
|  |   int ierr=MPI_Allreduce(MPI_IN_PLACE,&u,1,MPI_UINT32_T,MPI_SUM,communicator); | ||||||
|  |   assert(ierr==0); | ||||||
|  | } | ||||||
|  | void CartesianCommunicator::GlobalSum(uint64_t &u){ | ||||||
|  |   int ierr=MPI_Allreduce(MPI_IN_PLACE,&u,1,MPI_UINT64_T,MPI_SUM,communicator); | ||||||
|  |   assert(ierr==0); | ||||||
|  | } | ||||||
|  | void CartesianCommunicator::GlobalXOR(uint32_t &u){ | ||||||
|  |   int ierr=MPI_Allreduce(MPI_IN_PLACE,&u,1,MPI_UINT32_T,MPI_BXOR,communicator); | ||||||
|  |   assert(ierr==0); | ||||||
|  | } | ||||||
|  | void CartesianCommunicator::GlobalXOR(uint64_t &u){ | ||||||
|  |   int ierr=MPI_Allreduce(MPI_IN_PLACE,&u,1,MPI_UINT64_T,MPI_BXOR,communicator); | ||||||
|  |   assert(ierr==0); | ||||||
|  | } | ||||||
|  | void CartesianCommunicator::GlobalSum(float &f){ | ||||||
|  |   int ierr=MPI_Allreduce(MPI_IN_PLACE,&f,1,MPI_FLOAT,MPI_SUM,communicator); | ||||||
|  |   assert(ierr==0); | ||||||
|  | } | ||||||
|  | void CartesianCommunicator::GlobalSumVector(float *f,int N) | ||||||
|  | { | ||||||
|  |   int ierr=MPI_Allreduce(MPI_IN_PLACE,f,N,MPI_FLOAT,MPI_SUM,communicator); | ||||||
|  |   assert(ierr==0); | ||||||
|  | } | ||||||
|  | void CartesianCommunicator::GlobalSum(double &d) | ||||||
|  | { | ||||||
|  |   int ierr = MPI_Allreduce(MPI_IN_PLACE,&d,1,MPI_DOUBLE,MPI_SUM,communicator); | ||||||
|  |   assert(ierr==0); | ||||||
|  | } | ||||||
|  | void CartesianCommunicator::GlobalSumVector(double *d,int N) | ||||||
|  | { | ||||||
|  |   int ierr = MPI_Allreduce(MPI_IN_PLACE,d,N,MPI_DOUBLE,MPI_SUM,communicator); | ||||||
|  |   assert(ierr==0); | ||||||
|  | } | ||||||
|  | // Basic Halo comms primitive | ||||||
|  | void CartesianCommunicator::SendToRecvFrom(void *xmit, | ||||||
|  | 					   int dest, | ||||||
|  | 					   void *recv, | ||||||
|  | 					   int from, | ||||||
|  | 					   int bytes) | ||||||
|  | { | ||||||
|  |   std::vector<CommsRequest_t> reqs(0); | ||||||
|  |   //    unsigned long  xcrc = crc32(0L, Z_NULL, 0); | ||||||
|  |   //    unsigned long  rcrc = crc32(0L, Z_NULL, 0); | ||||||
|  |   //    xcrc = crc32(xcrc,(unsigned char *)xmit,bytes); | ||||||
|  |   SendToRecvFromBegin(reqs,xmit,dest,recv,from,bytes); | ||||||
|  |   SendToRecvFromComplete(reqs); | ||||||
|  |   //    rcrc = crc32(rcrc,(unsigned char *)recv,bytes); | ||||||
|  |   //    printf("proc %d SendToRecvFrom %d bytes %lx %lx\n",_processor,bytes,xcrc,rcrc); | ||||||
|  | } | ||||||
|  | void CartesianCommunicator::SendRecvPacket(void *xmit, | ||||||
|  | 					   void *recv, | ||||||
|  | 					   int sender, | ||||||
|  | 					   int receiver, | ||||||
|  | 					   int bytes) | ||||||
|  | { | ||||||
|  |   MPI_Status stat; | ||||||
|  |   assert(sender != receiver); | ||||||
|  |   int tag = sender; | ||||||
|  |   if ( _processor == sender ) { | ||||||
|  |     MPI_Send(xmit, bytes, MPI_CHAR,receiver,tag,communicator); | ||||||
|  |   } | ||||||
|  |   if ( _processor == receiver ) {  | ||||||
|  |     MPI_Recv(recv, bytes, MPI_CHAR,sender,tag,communicator,&stat); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | // Basic Halo comms primitive | ||||||
|  | void CartesianCommunicator::SendToRecvFromBegin(std::vector<CommsRequest_t> &list, | ||||||
|  | 						void *xmit, | ||||||
|  | 						int dest, | ||||||
|  | 						void *recv, | ||||||
|  | 						int from, | ||||||
|  | 						int bytes) | ||||||
|  | { | ||||||
|  |   int myrank = _processor; | ||||||
|  |   int ierr; | ||||||
|  |  | ||||||
|  |   if ( CommunicatorPolicy == CommunicatorPolicyConcurrent ) {  | ||||||
|  |     MPI_Request xrq; | ||||||
|  |     MPI_Request rrq; | ||||||
|  |  | ||||||
|  |     ierr =MPI_Irecv(recv, bytes, MPI_CHAR,from,from,communicator,&rrq); | ||||||
|  |     ierr|=MPI_Isend(xmit, bytes, MPI_CHAR,dest,_processor,communicator,&xrq); | ||||||
|  |      | ||||||
|  |     assert(ierr==0); | ||||||
|  |     list.push_back(xrq); | ||||||
|  |     list.push_back(rrq); | ||||||
|  |   } else {  | ||||||
|  |     // Give the CPU to MPI immediately; can use threads to overlap optionally | ||||||
|  |     ierr=MPI_Sendrecv(xmit,bytes,MPI_CHAR,dest,myrank, | ||||||
|  | 		      recv,bytes,MPI_CHAR,from, from, | ||||||
|  | 		      communicator,MPI_STATUS_IGNORE); | ||||||
|  |     assert(ierr==0); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | double CartesianCommunicator::StencilSendToRecvFrom( void *xmit, | ||||||
|  | 						     int dest, | ||||||
|  | 						     void *recv, | ||||||
|  | 						     int from, | ||||||
|  | 						     int bytes,int dir) | ||||||
|  | { | ||||||
|  |   std::vector<CommsRequest_t> list; | ||||||
|  |   double offbytes = StencilSendToRecvFromBegin(list,xmit,dest,recv,from,bytes,dir); | ||||||
|  |   StencilSendToRecvFromComplete(list,dir); | ||||||
|  |   return offbytes; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | double CartesianCommunicator::StencilSendToRecvFromBegin(std::vector<CommsRequest_t> &list, | ||||||
|  | 							 void *xmit, | ||||||
|  | 							 int dest, | ||||||
|  | 							 void *recv, | ||||||
|  | 							 int from, | ||||||
|  | 							 int bytes,int dir) | ||||||
|  | { | ||||||
|  |   int ncomm  =communicator_halo.size();  | ||||||
|  |   int commdir=dir%ncomm; | ||||||
|  |  | ||||||
|  |   MPI_Request xrq; | ||||||
|  |   MPI_Request rrq; | ||||||
|  |  | ||||||
|  |   int ierr; | ||||||
|  |   int gdest = ShmRanks[dest]; | ||||||
|  |   int gfrom = ShmRanks[from]; | ||||||
|  |   int gme   = ShmRanks[_processor]; | ||||||
|  |  | ||||||
|  |   assert(dest != _processor); | ||||||
|  |   assert(from != _processor); | ||||||
|  |   assert(gme  == ShmRank); | ||||||
|  |   double off_node_bytes=0.0; | ||||||
|  |  | ||||||
|  |   if ( gfrom ==MPI_UNDEFINED) { | ||||||
|  |     ierr=MPI_Irecv(recv, bytes, MPI_CHAR,from,from,communicator_halo[commdir],&rrq); | ||||||
|  |     assert(ierr==0); | ||||||
|  |     list.push_back(rrq); | ||||||
|  |     off_node_bytes+=bytes; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   if ( gdest == MPI_UNDEFINED ) { | ||||||
|  |     ierr =MPI_Isend(xmit, bytes, MPI_CHAR,dest,_processor,communicator_halo[commdir],&xrq); | ||||||
|  |     assert(ierr==0); | ||||||
|  |     list.push_back(xrq); | ||||||
|  |     off_node_bytes+=bytes; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   if ( CommunicatorPolicy == CommunicatorPolicySequential ) {  | ||||||
|  |     this->StencilSendToRecvFromComplete(list,dir); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   return off_node_bytes; | ||||||
|  | } | ||||||
|  | void CartesianCommunicator::StencilSendToRecvFromComplete(std::vector<CommsRequest_t> &waitall,int dir) | ||||||
|  | { | ||||||
|  |   SendToRecvFromComplete(waitall); | ||||||
|  | } | ||||||
|  | void CartesianCommunicator::StencilBarrier(void) | ||||||
|  | { | ||||||
|  |   MPI_Barrier  (ShmComm); | ||||||
|  | } | ||||||
|  | void CartesianCommunicator::SendToRecvFromComplete(std::vector<CommsRequest_t> &list) | ||||||
|  | { | ||||||
|  |   int nreq=list.size(); | ||||||
|  |  | ||||||
|  |   if (nreq==0) return; | ||||||
|  |  | ||||||
|  |   std::vector<MPI_Status> status(nreq); | ||||||
|  |   int ierr = MPI_Waitall(nreq,&list[0],&status[0]); | ||||||
|  |   assert(ierr==0); | ||||||
|  |   list.resize(0); | ||||||
|  | } | ||||||
|  | void CartesianCommunicator::Barrier(void) | ||||||
|  | { | ||||||
|  |   int ierr = MPI_Barrier(communicator); | ||||||
|  |   assert(ierr==0); | ||||||
|  | } | ||||||
|  | void CartesianCommunicator::Broadcast(int root,void* data, int bytes) | ||||||
|  | { | ||||||
|  |   int ierr=MPI_Bcast(data, | ||||||
|  | 		     bytes, | ||||||
|  | 		     MPI_BYTE, | ||||||
|  | 		     root, | ||||||
|  | 		     communicator); | ||||||
|  |   assert(ierr==0); | ||||||
|  | } | ||||||
|  | int CartesianCommunicator::RankWorld(void){  | ||||||
|  |   int r;  | ||||||
|  |   MPI_Comm_rank(communicator_world,&r); | ||||||
|  |   return r; | ||||||
|  | } | ||||||
|  | void CartesianCommunicator::BroadcastWorld(int root,void* data, int bytes) | ||||||
|  | { | ||||||
|  |   int ierr= MPI_Bcast(data, | ||||||
|  | 		      bytes, | ||||||
|  | 		      MPI_BYTE, | ||||||
|  | 		      root, | ||||||
|  | 		      communicator_world); | ||||||
|  |   assert(ierr==0); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void CartesianCommunicator::AllToAll(int dim,void  *in,void *out,uint64_t words,uint64_t bytes) | ||||||
|  | { | ||||||
|  |   Coordinate row(_ndimension,1); | ||||||
|  |   assert(dim>=0 && dim<_ndimension); | ||||||
|  |  | ||||||
|  |   //  Split the communicator | ||||||
|  |   row[dim] = _processors[dim]; | ||||||
|  |  | ||||||
|  |   int me; | ||||||
|  |   CartesianCommunicator Comm(row,*this,me); | ||||||
|  |   Comm.AllToAll(in,out,words,bytes); | ||||||
|  | } | ||||||
|  | void CartesianCommunicator::AllToAll(void  *in,void *out,uint64_t words,uint64_t bytes) | ||||||
|  | { | ||||||
|  |   // MPI is a pain and uses "int" arguments | ||||||
|  |   // 64*64*64*128*16 == 500Million elements of data. | ||||||
|  |   // When 24*4 bytes multiples get 50x 10^9 >>> 2x10^9 Y2K bug. | ||||||
|  |   // (Turns up on 32^3 x 64 Gparity too) | ||||||
|  |   MPI_Datatype object; | ||||||
|  |   int iwords;  | ||||||
|  |   int ibytes; | ||||||
|  |   iwords = words; | ||||||
|  |   ibytes = bytes; | ||||||
|  |   assert(words == iwords); // safe to cast to int ? | ||||||
|  |   assert(bytes == ibytes); // safe to cast to int ? | ||||||
|  |   MPI_Type_contiguous(ibytes,MPI_BYTE,&object); | ||||||
|  |   MPI_Type_commit(&object); | ||||||
|  |   MPI_Alltoall(in,iwords,object,out,iwords,object,communicator); | ||||||
|  |   MPI_Type_free(&object); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | NAMESPACE_END(Grid); | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -1,4 +1,4 @@ | |||||||
|     /*************************************************************************************
 | /*************************************************************************************
 | ||||||
| 
 | 
 | ||||||
|     Grid physics library, www.github.com/paboyle/Grid  |     Grid physics library, www.github.com/paboyle/Grid  | ||||||
| 
 | 
 | ||||||
| @@ -23,25 +23,36 @@ Author: Peter Boyle <paboyle@ph.ed.ac.uk> | |||||||
|     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||||||
| 
 | 
 | ||||||
|     See the full license in the file "LICENSE" in the top level distribution directory |     See the full license in the file "LICENSE" in the top level distribution directory | ||||||
|     *************************************************************************************/ | *************************************************************************************/ | ||||||
|     /*  END LEGAL */ | /*  END LEGAL */ | ||||||
| #include <Grid/GridCore.h> | #include <Grid/GridCore.h> | ||||||
| 
 | 
 | ||||||
| namespace Grid { | NAMESPACE_BEGIN(Grid); | ||||||
| 
 | 
 | ||||||
| ///////////////////////////////////////////////////////////////////////////////////////////////////
 | ///////////////////////////////////////////////////////////////////////////////////////////////////
 | ||||||
| // Info that is setup once and indept of cartesian layout
 | // Info that is setup once and indept of cartesian layout
 | ||||||
| ///////////////////////////////////////////////////////////////////////////////////////////////////
 | ///////////////////////////////////////////////////////////////////////////////////////////////////
 | ||||||
|  | Grid_MPI_Comm       CartesianCommunicator::communicator_world; | ||||||
| 
 | 
 | ||||||
| void CartesianCommunicator::Init(int *argc, char *** arv) | void CartesianCommunicator::Init(int *argc, char *** arv) | ||||||
| { | { | ||||||
|   ShmInitGeneric(); |   GlobalSharedMemory::Init(communicator_world); | ||||||
|  |   GlobalSharedMemory::SharedMemoryAllocate( | ||||||
|  | 					   GlobalSharedMemory::MAX_MPI_SHM_BYTES, | ||||||
|  | 					   GlobalSharedMemory::Hugepages); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| CartesianCommunicator::CartesianCommunicator(const std::vector<int> &processors) | CartesianCommunicator::CartesianCommunicator(const Coordinate &processors,const CartesianCommunicator &parent,int &srank)  | ||||||
|  |   : CartesianCommunicator(processors)  | ||||||
|  | { | ||||||
|  |   srank=0; | ||||||
|  |   SetCommunicator(communicator_world); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | CartesianCommunicator::CartesianCommunicator(const Coordinate &processors) | ||||||
| { | { | ||||||
|   _processors = processors; |   _processors = processors; | ||||||
|   _ndimension = processors.size(); |   _ndimension = processors.size();  assert(_ndimension>=1); | ||||||
|   _processor_coor.resize(_ndimension); |   _processor_coor.resize(_ndimension); | ||||||
|    |    | ||||||
|   // Require 1^N processor grid for fake
 |   // Require 1^N processor grid for fake
 | ||||||
| @@ -51,14 +62,19 @@ CartesianCommunicator::CartesianCommunicator(const std::vector<int> &processors) | |||||||
|     assert(_processors[d]==1); |     assert(_processors[d]==1); | ||||||
|     _processor_coor[d] = 0; |     _processor_coor[d] = 0; | ||||||
|   } |   } | ||||||
|  |   SetCommunicator(communicator_world); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | CartesianCommunicator::~CartesianCommunicator(){} | ||||||
|  | 
 | ||||||
| void CartesianCommunicator::GlobalSum(float &){} | void CartesianCommunicator::GlobalSum(float &){} | ||||||
| void CartesianCommunicator::GlobalSumVector(float *,int N){} | void CartesianCommunicator::GlobalSumVector(float *,int N){} | ||||||
| void CartesianCommunicator::GlobalSum(double &){} | void CartesianCommunicator::GlobalSum(double &){} | ||||||
| void CartesianCommunicator::GlobalSum(uint32_t &){} | void CartesianCommunicator::GlobalSum(uint32_t &){} | ||||||
| void CartesianCommunicator::GlobalSum(uint64_t &){} | void CartesianCommunicator::GlobalSum(uint64_t &){} | ||||||
| void CartesianCommunicator::GlobalSumVector(double *,int N){} | void CartesianCommunicator::GlobalSumVector(double *,int N){} | ||||||
|  | void CartesianCommunicator::GlobalXOR(uint32_t &){} | ||||||
|  | void CartesianCommunicator::GlobalXOR(uint64_t &){} | ||||||
| 
 | 
 | ||||||
| void CartesianCommunicator::SendRecvPacket(void *xmit, | void CartesianCommunicator::SendRecvPacket(void *xmit, | ||||||
| 					   void *recv, | 					   void *recv, | ||||||
| @@ -93,19 +109,57 @@ void CartesianCommunicator::SendToRecvFromComplete(std::vector<CommsRequest_t> & | |||||||
| { | { | ||||||
|   assert(0); |   assert(0); | ||||||
| } | } | ||||||
|  | void CartesianCommunicator::AllToAll(int dim,void  *in,void *out,uint64_t words,uint64_t bytes) | ||||||
|  | { | ||||||
|  |   bcopy(in,out,bytes*words); | ||||||
|  | } | ||||||
|  | void CartesianCommunicator::AllToAll(void  *in,void *out,uint64_t words,uint64_t bytes) | ||||||
|  | { | ||||||
|  |   bcopy(in,out,bytes*words); | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
| int  CartesianCommunicator::RankWorld(void){return 0;} | int  CartesianCommunicator::RankWorld(void){return 0;} | ||||||
| void CartesianCommunicator::Barrier(void){} | void CartesianCommunicator::Barrier(void){} | ||||||
| void CartesianCommunicator::Broadcast(int root,void* data, int bytes) {} | void CartesianCommunicator::Broadcast(int root,void* data, int bytes) {} | ||||||
| void CartesianCommunicator::BroadcastWorld(int root,void* data, int bytes) { } | void CartesianCommunicator::BroadcastWorld(int root,void* data, int bytes) { } | ||||||
| int  CartesianCommunicator::RankFromProcessorCoor(std::vector<int> &coor) {  return 0;} | int  CartesianCommunicator::RankFromProcessorCoor(Coordinate &coor) {  return 0;} | ||||||
| void CartesianCommunicator::ProcessorCoorFromRank(int rank, std::vector<int> &coor){  coor = _processor_coor; } | void CartesianCommunicator::ProcessorCoorFromRank(int rank, Coordinate &coor){  coor = _processor_coor; } | ||||||
| void CartesianCommunicator::ShiftedRanks(int dim,int shift,int &source,int &dest) | void CartesianCommunicator::ShiftedRanks(int dim,int shift,int &source,int &dest) | ||||||
| { | { | ||||||
|   source =0; |   source =0; | ||||||
|   dest=0; |   dest=0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | double CartesianCommunicator::StencilSendToRecvFrom( void *xmit, | ||||||
|  | 						     int xmit_to_rank, | ||||||
|  | 						     void *recv, | ||||||
|  | 						     int recv_from_rank, | ||||||
|  | 						     int bytes, int dir) | ||||||
|  | { | ||||||
|  |   std::vector<CommsRequest_t> list; | ||||||
|  |   // Discard the "dir"
 | ||||||
|  |   SendToRecvFromBegin   (list,xmit,xmit_to_rank,recv,recv_from_rank,bytes); | ||||||
|  |   SendToRecvFromComplete(list); | ||||||
|  |   return 2.0*bytes; | ||||||
|  | } | ||||||
|  | double CartesianCommunicator::StencilSendToRecvFromBegin(std::vector<CommsRequest_t> &list, | ||||||
|  | 							 void *xmit, | ||||||
|  | 							 int xmit_to_rank, | ||||||
|  | 							 void *recv, | ||||||
|  | 							 int recv_from_rank, | ||||||
|  | 							 int bytes, int dir) | ||||||
|  | { | ||||||
|  |   // Discard the "dir"
 | ||||||
|  |   SendToRecvFromBegin(list,xmit,xmit_to_rank,recv,recv_from_rank,bytes); | ||||||
|  |   return 2.0*bytes; | ||||||
|  | } | ||||||
|  | void CartesianCommunicator::StencilSendToRecvFromComplete(std::vector<CommsRequest_t> &waitall,int dir) | ||||||
|  | { | ||||||
|  |   SendToRecvFromComplete(waitall); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void CartesianCommunicator::StencilBarrier(void){}; | ||||||
|  | 
 | ||||||
|  | NAMESPACE_END(Grid); | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
							
								
								
									
										94
									
								
								Grid/communicator/SharedMemory.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										94
									
								
								Grid/communicator/SharedMemory.cc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,94 @@ | |||||||
|  | /************************************************************************************* | ||||||
|  |  | ||||||
|  |     Grid physics library, www.github.com/paboyle/Grid  | ||||||
|  |  | ||||||
|  |     Source file: ./lib/communicator/SharedMemory.cc | ||||||
|  |  | ||||||
|  |     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 */ | ||||||
|  |  | ||||||
|  | #include <Grid/GridCore.h> | ||||||
|  |  | ||||||
|  | NAMESPACE_BEGIN(Grid);  | ||||||
|  |  | ||||||
|  | // static data | ||||||
|  |  | ||||||
|  | int                 GlobalSharedMemory::HPEhypercube = 1; | ||||||
|  | uint64_t            GlobalSharedMemory::MAX_MPI_SHM_BYTES   = 1024LL*1024LL*1024LL;  | ||||||
|  | int                 GlobalSharedMemory::Hugepages = 0; | ||||||
|  | int                 GlobalSharedMemory::_ShmSetup; | ||||||
|  | int                 GlobalSharedMemory::_ShmAlloc; | ||||||
|  | uint64_t            GlobalSharedMemory::_ShmAllocBytes; | ||||||
|  |  | ||||||
|  | std::vector<void *> GlobalSharedMemory::WorldShmCommBufs; | ||||||
|  |  | ||||||
|  | Grid_MPI_Comm       GlobalSharedMemory::WorldShmComm; | ||||||
|  | int                 GlobalSharedMemory::WorldShmRank; | ||||||
|  | int                 GlobalSharedMemory::WorldShmSize; | ||||||
|  | std::vector<int>    GlobalSharedMemory::WorldShmRanks; | ||||||
|  |  | ||||||
|  | Grid_MPI_Comm       GlobalSharedMemory::WorldComm; | ||||||
|  | int                 GlobalSharedMemory::WorldSize; | ||||||
|  | int                 GlobalSharedMemory::WorldRank; | ||||||
|  |  | ||||||
|  | int                 GlobalSharedMemory::WorldNodes; | ||||||
|  | int                 GlobalSharedMemory::WorldNode; | ||||||
|  |  | ||||||
|  | void GlobalSharedMemory::SharedMemoryFree(void) | ||||||
|  | { | ||||||
|  |   assert(_ShmAlloc); | ||||||
|  |   assert(_ShmAllocBytes>0); | ||||||
|  |   for(int r=0;r<WorldShmSize;r++){ | ||||||
|  |     munmap(WorldShmCommBufs[r],_ShmAllocBytes); | ||||||
|  |   } | ||||||
|  |   _ShmAlloc = 0; | ||||||
|  |   _ShmAllocBytes = 0; | ||||||
|  | } | ||||||
|  | ///////////////////////////////// | ||||||
|  | // Alloc, free shmem region | ||||||
|  | ///////////////////////////////// | ||||||
|  | void *SharedMemory::ShmBufferMalloc(size_t bytes){ | ||||||
|  |   //  bytes = (bytes+sizeof(vRealD))&(~(sizeof(vRealD)-1));// align up bytes | ||||||
|  |   void *ptr = (void *)heap_top; | ||||||
|  |   heap_top  += bytes; | ||||||
|  |   heap_bytes+= bytes; | ||||||
|  |   if (heap_bytes >= heap_size) { | ||||||
|  |     std::cout<< " ShmBufferMalloc exceeded shared heap size -- try increasing with --shm <MB> flag" <<std::endl; | ||||||
|  |     std::cout<< " Parameter specified in units of MB (megabytes) " <<std::endl; | ||||||
|  |     std::cout<< " Current value is " << (heap_size/(1024*1024)) <<std::endl; | ||||||
|  |     assert(heap_bytes<heap_size); | ||||||
|  |   } | ||||||
|  |   //std::cerr << "ShmBufferMalloc "<<std::hex<< ptr<<" - "<<((uint64_t)ptr+bytes)<<std::dec<<std::endl; | ||||||
|  |   return ptr; | ||||||
|  | } | ||||||
|  | void SharedMemory::ShmBufferFreeAll(void) {  | ||||||
|  |   heap_top  =(size_t)ShmBufferSelf(); | ||||||
|  |   heap_bytes=0; | ||||||
|  | } | ||||||
|  | void *SharedMemory::ShmBufferSelf(void) | ||||||
|  | { | ||||||
|  |   //std::cerr << "ShmBufferSelf "<<ShmRank<<" "<<std::hex<< ShmCommBufs[ShmRank] <<std::dec<<std::endl; | ||||||
|  |   return ShmCommBufs[ShmRank]; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | NAMESPACE_END(Grid);  | ||||||
|  |  | ||||||
							
								
								
									
										165
									
								
								Grid/communicator/SharedMemory.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										165
									
								
								Grid/communicator/SharedMemory.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,165 @@ | |||||||
|  | /************************************************************************************* | ||||||
|  |  | ||||||
|  |     Grid physics library, www.github.com/paboyle/Grid  | ||||||
|  |  | ||||||
|  |     Source file: ./lib/communicator/SharedMemory.cc | ||||||
|  |  | ||||||
|  |     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 */ | ||||||
|  | #pragma once  | ||||||
|  |  | ||||||
|  | #include <Grid/GridCore.h> | ||||||
|  |  | ||||||
|  | #if defined (GRID_COMMS_MPI3)  | ||||||
|  | #include <mpi.h> | ||||||
|  | #endif  | ||||||
|  | #include <semaphore.h> | ||||||
|  | #include <fcntl.h> | ||||||
|  | #include <unistd.h> | ||||||
|  | #include <limits.h> | ||||||
|  | #include <sys/types.h> | ||||||
|  | #include <sys/ipc.h> | ||||||
|  | #include <sys/shm.h> | ||||||
|  | #include <sys/mman.h> | ||||||
|  | #include <zlib.h> | ||||||
|  | #ifdef HAVE_NUMAIF_H | ||||||
|  | #include <numaif.h> | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | NAMESPACE_BEGIN(Grid); | ||||||
|  |  | ||||||
|  | #if defined (GRID_COMMS_MPI3)  | ||||||
|  | typedef MPI_Comm    Grid_MPI_Comm; | ||||||
|  | typedef MPI_Request CommsRequest_t; | ||||||
|  | #else  | ||||||
|  | typedef int CommsRequest_t; | ||||||
|  | typedef int Grid_MPI_Comm; | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | class GlobalSharedMemory { | ||||||
|  | private: | ||||||
|  |   static const int     MAXLOG2RANKSPERNODE = 16;             | ||||||
|  |  | ||||||
|  |  | ||||||
|  |   // Init once lock on the buffer allocation | ||||||
|  |   static int      _ShmSetup; | ||||||
|  |   static int      _ShmAlloc; | ||||||
|  |   static uint64_t _ShmAllocBytes; | ||||||
|  |  | ||||||
|  | public: | ||||||
|  |   /////////////////////////////////////// | ||||||
|  |   // HPE 8600 hypercube optimisation | ||||||
|  |   /////////////////////////////////////// | ||||||
|  |   static int HPEhypercube; | ||||||
|  |  | ||||||
|  |   static int      ShmSetup(void)      { return _ShmSetup; } | ||||||
|  |   static int      ShmAlloc(void)      { return _ShmAlloc; } | ||||||
|  |   static uint64_t ShmAllocBytes(void) { return _ShmAllocBytes; } | ||||||
|  |   static uint64_t      MAX_MPI_SHM_BYTES; | ||||||
|  |   static int           Hugepages; | ||||||
|  |  | ||||||
|  |   static std::vector<void *> WorldShmCommBufs; | ||||||
|  |  | ||||||
|  |   static Grid_MPI_Comm WorldComm; | ||||||
|  |   static int           WorldRank; | ||||||
|  |   static int           WorldSize; | ||||||
|  |  | ||||||
|  |   static Grid_MPI_Comm WorldShmComm; | ||||||
|  |   static int           WorldShmRank; | ||||||
|  |   static int           WorldShmSize; | ||||||
|  |  | ||||||
|  |   static int           WorldNodes; | ||||||
|  |   static int           WorldNode; | ||||||
|  |  | ||||||
|  |   static std::vector<int>  WorldShmRanks; | ||||||
|  |  | ||||||
|  |   ////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  |   // Create an optimal reordered communicator that makes MPI_Cart_create get it right | ||||||
|  |   ////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  |   static void Init(Grid_MPI_Comm comm); // Typically MPI_COMM_WORLD | ||||||
|  |   static void OptimalCommunicator            (const Coordinate &processors,Grid_MPI_Comm & optimal_comm);  // Turns MPI_COMM_WORLD into right layout for Cartesian | ||||||
|  |   static void OptimalCommunicatorHypercube   (const Coordinate &processors,Grid_MPI_Comm & optimal_comm);  // Turns MPI_COMM_WORLD into right layout for Cartesian | ||||||
|  |   static void OptimalCommunicatorSharedMemory(const Coordinate &processors,Grid_MPI_Comm & optimal_comm);  // Turns MPI_COMM_WORLD into right layout for Cartesian | ||||||
|  |   /////////////////////////////////////////////////// | ||||||
|  |   // Provide shared memory facilities off comm world | ||||||
|  |   /////////////////////////////////////////////////// | ||||||
|  |   static void SharedMemoryAllocate(uint64_t bytes, int flags); | ||||||
|  |   static void SharedMemoryFree(void); | ||||||
|  |   static void SharedMemoryCopy(void *dest,const void *src,size_t bytes); | ||||||
|  |   static void SharedMemoryZero(void *dest,size_t bytes); | ||||||
|  |  | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | ////////////////////////////// | ||||||
|  | // one per communicator | ||||||
|  | ////////////////////////////// | ||||||
|  | class SharedMemory  | ||||||
|  | { | ||||||
|  | private: | ||||||
|  |   static const int     MAXLOG2RANKSPERNODE = 16;             | ||||||
|  |  | ||||||
|  |   size_t heap_top; | ||||||
|  |   size_t heap_bytes; | ||||||
|  |   size_t heap_size; | ||||||
|  |  | ||||||
|  | protected: | ||||||
|  |  | ||||||
|  |   Grid_MPI_Comm    ShmComm; // for barriers | ||||||
|  |   int    ShmRank;  | ||||||
|  |   int    ShmSize; | ||||||
|  |   std::vector<void *> ShmCommBufs; | ||||||
|  |   std::vector<int>    ShmRanks;// Mapping comm ranks to Shm ranks | ||||||
|  |  | ||||||
|  | public: | ||||||
|  |   SharedMemory() {}; | ||||||
|  |   ~SharedMemory(); | ||||||
|  |   /////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  |   // set the buffers & sizes | ||||||
|  |   /////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  |   void SetCommunicator(Grid_MPI_Comm comm); | ||||||
|  |  | ||||||
|  |   //////////////////////////////////////////////////////////////////////// | ||||||
|  |   // For this instance ; disjoint buffer sets between splits if split grid | ||||||
|  |   //////////////////////////////////////////////////////////////////////// | ||||||
|  |   void ShmBarrier(void);  | ||||||
|  |  | ||||||
|  |   /////////////////////////////////////////////////// | ||||||
|  |   // Call on any instance | ||||||
|  |   /////////////////////////////////////////////////// | ||||||
|  |   void SharedMemoryTest(void); | ||||||
|  |    | ||||||
|  |   void *ShmBufferSelf(void); | ||||||
|  |   void *ShmBuffer    (int rank); | ||||||
|  |   void *ShmBufferTranslate(int rank,void * local_p); | ||||||
|  |   void *ShmBufferMalloc(size_t bytes); | ||||||
|  |   void  ShmBufferFreeAll(void) ; | ||||||
|  |    | ||||||
|  |   ////////////////////////////////////////////////////////////////////////// | ||||||
|  |   // Make info on Nodes & ranks and Shared memory available | ||||||
|  |   ////////////////////////////////////////////////////////////////////////// | ||||||
|  |   int NodeCount(void) { return GlobalSharedMemory::WorldNodes;}; | ||||||
|  |   int RankCount(void) { return GlobalSharedMemory::WorldSize;}; | ||||||
|  |  | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | NAMESPACE_END(Grid); | ||||||
|  |  | ||||||
							
								
								
									
										784
									
								
								Grid/communicator/SharedMemoryMPI.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										784
									
								
								Grid/communicator/SharedMemoryMPI.cc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,784 @@ | |||||||
|  | /************************************************************************************* | ||||||
|  |  | ||||||
|  |     Grid physics library, www.github.com/paboyle/Grid  | ||||||
|  |  | ||||||
|  |     Source file: ./lib/communicator/SharedMemory.cc | ||||||
|  |  | ||||||
|  |     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 */ | ||||||
|  |  | ||||||
|  | #include <Grid/GridCore.h> | ||||||
|  | #include <pwd.h> | ||||||
|  |  | ||||||
|  | #ifdef GRID_NVCC | ||||||
|  | #include <cuda_runtime_api.h> | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | NAMESPACE_BEGIN(Grid);  | ||||||
|  | #define header "SharedMemoryMpi: " | ||||||
|  | /*Construct from an MPI communicator*/ | ||||||
|  | void GlobalSharedMemory::Init(Grid_MPI_Comm comm) | ||||||
|  | { | ||||||
|  |   assert(_ShmSetup==0); | ||||||
|  |   WorldComm = comm; | ||||||
|  |   MPI_Comm_rank(WorldComm,&WorldRank); | ||||||
|  |   MPI_Comm_size(WorldComm,&WorldSize); | ||||||
|  |   // WorldComm, WorldSize, WorldRank | ||||||
|  |  | ||||||
|  |   ///////////////////////////////////////////////////////////////////// | ||||||
|  |   // Split into groups that can share memory | ||||||
|  |   ///////////////////////////////////////////////////////////////////// | ||||||
|  |   MPI_Comm_split_type(comm, MPI_COMM_TYPE_SHARED, 0, MPI_INFO_NULL,&WorldShmComm); | ||||||
|  |   MPI_Comm_rank(WorldShmComm     ,&WorldShmRank); | ||||||
|  |   MPI_Comm_size(WorldShmComm     ,&WorldShmSize); | ||||||
|  |  | ||||||
|  |   if ( WorldRank == 0) { | ||||||
|  |     std::cout << header " World communicator of size " <<WorldSize << std::endl;   | ||||||
|  |     std::cout << header " Node  communicator of size " <<WorldShmSize << std::endl; | ||||||
|  |   } | ||||||
|  |   // WorldShmComm, WorldShmSize, WorldShmRank | ||||||
|  |  | ||||||
|  |   // WorldNodes | ||||||
|  |   WorldNodes = WorldSize/WorldShmSize; | ||||||
|  |   assert( (WorldNodes * WorldShmSize) == WorldSize ); | ||||||
|  |  | ||||||
|  |   // FIXME: Check all WorldShmSize are the same ? | ||||||
|  |  | ||||||
|  |   ///////////////////////////////////////////////////////////////////// | ||||||
|  |   // find world ranks in our SHM group (i.e. which ranks are on our node) | ||||||
|  |   ///////////////////////////////////////////////////////////////////// | ||||||
|  |   MPI_Group WorldGroup, ShmGroup; | ||||||
|  |   MPI_Comm_group (WorldComm, &WorldGroup);  | ||||||
|  |   MPI_Comm_group (WorldShmComm, &ShmGroup); | ||||||
|  |  | ||||||
|  |   std::vector<int> world_ranks(WorldSize);   for(int r=0;r<WorldSize;r++) world_ranks[r]=r; | ||||||
|  |  | ||||||
|  |   WorldShmRanks.resize(WorldSize);  | ||||||
|  |   MPI_Group_translate_ranks (WorldGroup,WorldSize,&world_ranks[0],ShmGroup, &WorldShmRanks[0]);  | ||||||
|  |  | ||||||
|  |   /////////////////////////////////////////////////////////////////// | ||||||
|  |   // Identify who is in my group and nominate the leader | ||||||
|  |   /////////////////////////////////////////////////////////////////// | ||||||
|  |   int g=0; | ||||||
|  |   std::vector<int> MyGroup; | ||||||
|  |   MyGroup.resize(WorldShmSize); | ||||||
|  |   for(int rank=0;rank<WorldSize;rank++){ | ||||||
|  |     if(WorldShmRanks[rank]!=MPI_UNDEFINED){ | ||||||
|  |       assert(g<WorldShmSize); | ||||||
|  |       MyGroup[g++] = rank; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |    | ||||||
|  |   std::sort(MyGroup.begin(),MyGroup.end(),std::less<int>()); | ||||||
|  |   int myleader = MyGroup[0]; | ||||||
|  |    | ||||||
|  |   std::vector<int> leaders_1hot(WorldSize,0); | ||||||
|  |   std::vector<int> leaders_group(WorldNodes,0); | ||||||
|  |   leaders_1hot [ myleader ] = 1; | ||||||
|  |      | ||||||
|  |   /////////////////////////////////////////////////////////////////// | ||||||
|  |   // global sum leaders over comm world | ||||||
|  |   /////////////////////////////////////////////////////////////////// | ||||||
|  |   int ierr=MPI_Allreduce(MPI_IN_PLACE,&leaders_1hot[0],WorldSize,MPI_INT,MPI_SUM,WorldComm); | ||||||
|  |   assert(ierr==0); | ||||||
|  |  | ||||||
|  |   /////////////////////////////////////////////////////////////////// | ||||||
|  |   // find the group leaders world rank | ||||||
|  |   /////////////////////////////////////////////////////////////////// | ||||||
|  |   int group=0; | ||||||
|  |   for(int l=0;l<WorldSize;l++){ | ||||||
|  |     if(leaders_1hot[l]){ | ||||||
|  |       leaders_group[group++] = l; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   /////////////////////////////////////////////////////////////////// | ||||||
|  |   // Identify the node of the group in which I (and my leader) live | ||||||
|  |   /////////////////////////////////////////////////////////////////// | ||||||
|  |   WorldNode=-1; | ||||||
|  |   for(int g=0;g<WorldNodes;g++){ | ||||||
|  |     if (myleader == leaders_group[g]){ | ||||||
|  |       WorldNode=g; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   assert(WorldNode!=-1); | ||||||
|  |   _ShmSetup=1; | ||||||
|  | } | ||||||
|  | // Gray encode support  | ||||||
|  | int BinaryToGray (int  binary) { | ||||||
|  |   int gray = (binary>>1)^binary; | ||||||
|  |   return gray; | ||||||
|  | } | ||||||
|  | int Log2Size(int TwoToPower,int MAXLOG2) | ||||||
|  | { | ||||||
|  |   int log2size = -1; | ||||||
|  |   for(int i=0;i<=MAXLOG2;i++){ | ||||||
|  |     if ( (0x1<<i) == TwoToPower ) { | ||||||
|  |       log2size = i; | ||||||
|  |       break; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   return log2size; | ||||||
|  | } | ||||||
|  | void GlobalSharedMemory::OptimalCommunicator(const Coordinate &processors,Grid_MPI_Comm & optimal_comm) | ||||||
|  | { | ||||||
|  |   ////////////////////////////////////////////////////////////////////////////// | ||||||
|  |   // Look and see if it looks like an HPE 8600 based on hostname conventions | ||||||
|  |   ////////////////////////////////////////////////////////////////////////////// | ||||||
|  |   const int namelen = _POSIX_HOST_NAME_MAX; | ||||||
|  |   char name[namelen]; | ||||||
|  |   int R; | ||||||
|  |   int I; | ||||||
|  |   int N; | ||||||
|  |   gethostname(name,namelen); | ||||||
|  |   int nscan = sscanf(name,"r%di%dn%d",&R,&I,&N) ; | ||||||
|  |  | ||||||
|  |   if(nscan==3 && HPEhypercube ) OptimalCommunicatorHypercube(processors,optimal_comm); | ||||||
|  |   else                          OptimalCommunicatorSharedMemory(processors,optimal_comm); | ||||||
|  | } | ||||||
|  | void GlobalSharedMemory::OptimalCommunicatorHypercube(const Coordinate &processors,Grid_MPI_Comm & optimal_comm) | ||||||
|  | { | ||||||
|  |   //////////////////////////////////////////////////////////////// | ||||||
|  |   // 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.toVector(); | ||||||
|  |   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); | ||||||
|  | } | ||||||
|  | void GlobalSharedMemory::OptimalCommunicatorSharedMemory(const Coordinate &processors,Grid_MPI_Comm & optimal_comm) | ||||||
|  | { | ||||||
|  |   //////////////////////////////////////////////////////////////// | ||||||
|  |   // Assert power of two shm_size. | ||||||
|  |   //////////////////////////////////////////////////////////////// | ||||||
|  |   int log2size = Log2Size(WorldShmSize,MAXLOG2RANKSPERNODE); | ||||||
|  |   assert(log2size != -1); | ||||||
|  |  | ||||||
|  |   //////////////////////////////////////////////////////////////// | ||||||
|  |   // Identify subblock of ranks on node spreading across dims | ||||||
|  |   // in a maximally symmetrical way | ||||||
|  |   //////////////////////////////////////////////////////////////// | ||||||
|  |   int ndimension              = processors.size(); | ||||||
|  |   Coordinate processor_coor(ndimension); | ||||||
|  |   Coordinate WorldDims = processors; Coordinate ShmDims(ndimension,1);  Coordinate NodeDims (ndimension); | ||||||
|  |   Coordinate ShmCoor(ndimension);    Coordinate NodeCoor(ndimension);   Coordinate WorldCoor(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]; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   //////////////////////////////////////////////////////////////// | ||||||
|  |   // 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); | ||||||
|  |   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); | ||||||
|  | } | ||||||
|  | //////////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  | // SHMGET | ||||||
|  | //////////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  | #ifdef GRID_MPI3_SHMGET | ||||||
|  | void GlobalSharedMemory::SharedMemoryAllocate(uint64_t bytes, int flags) | ||||||
|  | { | ||||||
|  |   std::cout << header "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  %ld\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 | ||||||
|  | //////////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  | #ifdef GRID_NVCC | ||||||
|  | void GlobalSharedMemory::SharedMemoryAllocate(uint64_t bytes, int flags) | ||||||
|  | { | ||||||
|  |   void * ShmCommBuf ;  | ||||||
|  |   assert(_ShmSetup==1); | ||||||
|  |   assert(_ShmAlloc==0); | ||||||
|  |  | ||||||
|  |   ////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  |   // allocate the pointer array for shared windows for our group | ||||||
|  |   ////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  |   MPI_Barrier(WorldShmComm); | ||||||
|  |   WorldShmCommBufs.resize(WorldShmSize); | ||||||
|  |  | ||||||
|  |   ////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  |   // TODO/FIXME : NOT ALL NVLINK BOARDS have full Peer to peer connectivity. | ||||||
|  |   // The annoyance is that they have partial peer 2 peer. This occurs on the 8 GPU blades. | ||||||
|  |   // e.g. DGX1, supermicro board,  | ||||||
|  |   ////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  |   //  cudaDeviceGetP2PAttribute(&perfRank, cudaDevP2PAttrPerformanceRank, device1, device2); | ||||||
|  |   cudaSetDevice(WorldShmRank); | ||||||
|  |   /////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  |   // Each MPI rank should allocate our own buffer | ||||||
|  |   /////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  |   auto err =  cudaMalloc(&ShmCommBuf, bytes); | ||||||
|  |   if ( err !=  cudaSuccess) { | ||||||
|  |     std::cerr << " SharedMemoryMPI.cc cudaMallocManaged failed for " << bytes<<" bytes " <<cudaGetErrorString(err)<< std::endl; | ||||||
|  |     exit(EXIT_FAILURE);   | ||||||
|  |   } | ||||||
|  |   if (ShmCommBuf == (void *)NULL ) { | ||||||
|  |     std::cerr << " SharedMemoryMPI.cc cudaMallocManaged failed NULL pointer for " << bytes<<" bytes " << std::endl; | ||||||
|  |     exit(EXIT_FAILURE);   | ||||||
|  |   } | ||||||
|  |   if ( WorldRank == 0 ){ | ||||||
|  |     std::cout << header " SharedMemoryMPI.cc cudaMalloc "<< bytes << "bytes at "<< std::hex<< ShmCommBuf <<std::dec<<" for comms buffers " <<std::endl; | ||||||
|  |   } | ||||||
|  |   SharedMemoryZero(ShmCommBuf,bytes); | ||||||
|  |  | ||||||
|  |   /////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  |   // Loop over ranks/gpu's on our node | ||||||
|  |   /////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  |   for(int r=0;r<WorldShmSize;r++){ | ||||||
|  |      | ||||||
|  |     ////////////////////////////////////////////////// | ||||||
|  |     // If it is me, pass around the IPC access key | ||||||
|  |     ////////////////////////////////////////////////// | ||||||
|  |     cudaIpcMemHandle_t handle; | ||||||
|  |  | ||||||
|  |     if ( r==WorldShmRank ) {  | ||||||
|  |       err = cudaIpcGetMemHandle(&handle,ShmCommBuf); | ||||||
|  |       if ( err !=  cudaSuccess) { | ||||||
|  | 	std::cerr << " SharedMemoryMPI.cc cudaIpcGetMemHandle failed for rank" << r <<" "<<cudaGetErrorString(err)<< std::endl; | ||||||
|  | 	exit(EXIT_FAILURE); | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |     ////////////////////////////////////////////////// | ||||||
|  |     // Share this IPC handle across the Shm Comm | ||||||
|  |     ////////////////////////////////////////////////// | ||||||
|  |     {  | ||||||
|  |       int ierr=MPI_Bcast(&handle, | ||||||
|  | 			 sizeof(handle), | ||||||
|  | 			 MPI_BYTE, | ||||||
|  | 			 r, | ||||||
|  | 			 WorldShmComm); | ||||||
|  |       assert(ierr==0); | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /////////////////////////////////////////////////////////////// | ||||||
|  |     // If I am not the source, overwrite thisBuf with remote buffer | ||||||
|  |     /////////////////////////////////////////////////////////////// | ||||||
|  |     void * thisBuf = ShmCommBuf; | ||||||
|  |     if ( r!=WorldShmRank ) {  | ||||||
|  |       err = cudaIpcOpenMemHandle(&thisBuf,handle,cudaIpcMemLazyEnablePeerAccess); | ||||||
|  |       if ( err !=  cudaSuccess) { | ||||||
|  | 	std::cerr << " SharedMemoryMPI.cc cudaIpcOpenMemHandle failed for rank" << r <<" "<<cudaGetErrorString(err)<< std::endl; | ||||||
|  | 	exit(EXIT_FAILURE); | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |     /////////////////////////////////////////////////////////////// | ||||||
|  |     // Save a copy of the device buffers | ||||||
|  |     /////////////////////////////////////////////////////////////// | ||||||
|  |     WorldShmCommBufs[r] = thisBuf; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   _ShmAllocBytes=bytes; | ||||||
|  |   _ShmAlloc=1; | ||||||
|  | } | ||||||
|  | #else  | ||||||
|  | #ifdef GRID_MPI3_SHMMMAP | ||||||
|  | void GlobalSharedMemory::SharedMemoryAllocate(uint64_t bytes, int flags) | ||||||
|  | { | ||||||
|  |   std::cout << header "SharedMemoryAllocate "<< bytes<< " MMAP implementation "<< GRID_SHM_PATH <<std::endl; | ||||||
|  |   assert(_ShmSetup==1); | ||||||
|  |   assert(_ShmAlloc==0); | ||||||
|  |   ////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  |   // allocate the shared windows for our group | ||||||
|  |   ////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  |   MPI_Barrier(WorldShmComm); | ||||||
|  |   WorldShmCommBufs.resize(WorldShmSize); | ||||||
|  |    | ||||||
|  |   //////////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  |   // Hugetlbfs and others map filesystems as mappable huge pages | ||||||
|  |   //////////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  |   char shm_name [NAME_MAX]; | ||||||
|  |   for(int r=0;r<WorldShmSize;r++){ | ||||||
|  |      | ||||||
|  |     sprintf(shm_name,GRID_SHM_PATH "/Grid_mpi3_shm_%d_%d",WorldNode,r); | ||||||
|  |     int fd=open(shm_name,O_RDWR|O_CREAT,0666); | ||||||
|  |     if ( fd == -1) {  | ||||||
|  |       printf("open %s failed\n",shm_name); | ||||||
|  |       perror("open hugetlbfs"); | ||||||
|  |       exit(0); | ||||||
|  |     } | ||||||
|  |     int mmap_flag = MAP_SHARED ; | ||||||
|  | #ifdef MAP_POPULATE     | ||||||
|  |     mmap_flag|=MAP_POPULATE; | ||||||
|  | #endif | ||||||
|  | #ifdef MAP_HUGETLB | ||||||
|  |     if ( flags ) mmap_flag |= MAP_HUGETLB; | ||||||
|  | #endif | ||||||
|  |     void *ptr = (void *) mmap(NULL, bytes, PROT_READ | PROT_WRITE, mmap_flag,fd, 0);  | ||||||
|  |     if ( ptr == (void *)MAP_FAILED ) {     | ||||||
|  |       printf("mmap %s failed\n",shm_name); | ||||||
|  |       perror("failed mmap");      assert(0);     | ||||||
|  |     } | ||||||
|  |     assert(((uint64_t)ptr&0x3F)==0); | ||||||
|  |     close(fd); | ||||||
|  |     WorldShmCommBufs[r] =ptr; | ||||||
|  |     //    std::cout << header "Set WorldShmCommBufs["<<r<<"]="<<ptr<< "("<< bytes<< "bytes)"<<std::endl; | ||||||
|  |   } | ||||||
|  |   _ShmAlloc=1; | ||||||
|  |   _ShmAllocBytes  = bytes; | ||||||
|  | }; | ||||||
|  | #endif // MMAP | ||||||
|  |  | ||||||
|  | #ifdef GRID_MPI3_SHM_NONE | ||||||
|  | void GlobalSharedMemory::SharedMemoryAllocate(uint64_t bytes, int flags) | ||||||
|  | { | ||||||
|  |   std::cout << header "SharedMemoryAllocate "<< bytes<< " MMAP anonymous implementation "<<std::endl; | ||||||
|  |   assert(_ShmSetup==1); | ||||||
|  |   assert(_ShmAlloc==0); | ||||||
|  |   ////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  |   // allocate the shared windows for our group | ||||||
|  |   ////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  |   MPI_Barrier(WorldShmComm); | ||||||
|  |   WorldShmCommBufs.resize(WorldShmSize); | ||||||
|  |    | ||||||
|  |   //////////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  |   // Hugetlbf and others map filesystems as mappable huge pages | ||||||
|  |   //////////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  |   char shm_name [NAME_MAX]; | ||||||
|  |   assert(WorldShmSize == 1); | ||||||
|  |   for(int r=0;r<WorldShmSize;r++){ | ||||||
|  |      | ||||||
|  |     int fd=-1; | ||||||
|  |     int mmap_flag = MAP_SHARED |MAP_ANONYMOUS ; | ||||||
|  | #ifdef MAP_POPULATE     | ||||||
|  |     mmap_flag|=MAP_POPULATE; | ||||||
|  | #endif | ||||||
|  | #ifdef MAP_HUGETLB | ||||||
|  |     if ( flags ) mmap_flag |= MAP_HUGETLB; | ||||||
|  | #endif | ||||||
|  |     void *ptr = (void *) mmap(NULL, bytes, PROT_READ | PROT_WRITE, mmap_flag,fd, 0);  | ||||||
|  |     if ( ptr == (void *)MAP_FAILED ) {     | ||||||
|  |       printf("mmap %s failed\n",shm_name); | ||||||
|  |       perror("failed mmap");      assert(0);     | ||||||
|  |     } | ||||||
|  |     assert(((uint64_t)ptr&0x3F)==0); | ||||||
|  |     close(fd); | ||||||
|  |     WorldShmCommBufs[r] =ptr; | ||||||
|  |     //    std::cout << "Set WorldShmCommBufs["<<r<<"]="<<ptr<< "("<< bytes<< "bytes)"<<std::endl; | ||||||
|  |   } | ||||||
|  |   _ShmAlloc=1; | ||||||
|  |   _ShmAllocBytes  = bytes; | ||||||
|  | }; | ||||||
|  | #endif // MMAP | ||||||
|  |  | ||||||
|  | #ifdef GRID_MPI3_SHMOPEN | ||||||
|  | //////////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  | // POSIX SHMOPEN ; as far as I know Linux does not allow EXPLICIT HugePages with this case | ||||||
|  | // tmpfs (Larry Meadows says) does not support explicit huge page, and this is used for  | ||||||
|  | // the posix shm virtual file system | ||||||
|  | //////////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  | void GlobalSharedMemory::SharedMemoryAllocate(uint64_t bytes, int flags) | ||||||
|  | {  | ||||||
|  |   std::cout << header "SharedMemoryAllocate "<< bytes<< " SHMOPEN implementation "<<std::endl; | ||||||
|  |   assert(_ShmSetup==1); | ||||||
|  |   assert(_ShmAlloc==0);  | ||||||
|  |   MPI_Barrier(WorldShmComm); | ||||||
|  |   WorldShmCommBufs.resize(WorldShmSize); | ||||||
|  |  | ||||||
|  |   char shm_name [NAME_MAX]; | ||||||
|  |   if ( WorldShmRank == 0 ) { | ||||||
|  |     for(int r=0;r<WorldShmSize;r++){ | ||||||
|  | 	 | ||||||
|  |       size_t size = bytes; | ||||||
|  |        | ||||||
|  |       struct passwd *pw = getpwuid (getuid()); | ||||||
|  |       sprintf(shm_name,"/Grid_%s_mpi3_shm_%d_%d",pw->pw_name,WorldNode,r); | ||||||
|  |        | ||||||
|  |       shm_unlink(shm_name); | ||||||
|  |       int fd=shm_open(shm_name,O_RDWR|O_CREAT,0666); | ||||||
|  |       if ( fd < 0 ) {	perror("failed shm_open");	assert(0);      } | ||||||
|  |       ftruncate(fd, size); | ||||||
|  | 	 | ||||||
|  |       int mmap_flag = MAP_SHARED; | ||||||
|  | #ifdef MAP_POPULATE  | ||||||
|  |       mmap_flag |= MAP_POPULATE; | ||||||
|  | #endif | ||||||
|  | #ifdef MAP_HUGETLB | ||||||
|  |       if (flags) mmap_flag |= MAP_HUGETLB; | ||||||
|  | #endif | ||||||
|  |       void * ptr =  mmap(NULL,size, PROT_READ | PROT_WRITE, mmap_flag, fd, 0); | ||||||
|  |        | ||||||
|  |       //      std::cout << "Set WorldShmCommBufs["<<r<<"]="<<ptr<< "("<< size<< "bytes)"<<std::endl; | ||||||
|  |       if ( ptr == (void * )MAP_FAILED ) {        | ||||||
|  | 	perror("failed mmap");      | ||||||
|  | 	assert(0);     | ||||||
|  |       } | ||||||
|  |       assert(((uint64_t)ptr&0x3F)==0); | ||||||
|  |        | ||||||
|  |       WorldShmCommBufs[r] =ptr; | ||||||
|  |       close(fd); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   MPI_Barrier(WorldShmComm); | ||||||
|  |    | ||||||
|  |   if ( WorldShmRank != 0 ) {  | ||||||
|  |     for(int r=0;r<WorldShmSize;r++){ | ||||||
|  |  | ||||||
|  |       size_t size = bytes ; | ||||||
|  |        | ||||||
|  |       struct passwd *pw = getpwuid (getuid()); | ||||||
|  |       sprintf(shm_name,"/Grid_%s_mpi3_shm_%d_%d",pw->pw_name,WorldNode,r); | ||||||
|  |        | ||||||
|  |       int fd=shm_open(shm_name,O_RDWR,0666); | ||||||
|  |       if ( fd<0 ) {	perror("failed shm_open");	assert(0);      } | ||||||
|  |        | ||||||
|  |       void * ptr =  mmap(NULL,size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); | ||||||
|  |       if ( ptr == MAP_FAILED ) {       perror("failed mmap");      assert(0);    } | ||||||
|  |       assert(((uint64_t)ptr&0x3F)==0); | ||||||
|  |       WorldShmCommBufs[r] =ptr; | ||||||
|  |  | ||||||
|  |       close(fd); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   _ShmAlloc=1; | ||||||
|  |   _ShmAllocBytes = bytes; | ||||||
|  | } | ||||||
|  | #endif | ||||||
|  | #endif // End NVCC case for GPU device buffers | ||||||
|  |  | ||||||
|  | ///////////////////////////////////////////////////////////////////////// | ||||||
|  | // Routines accessing shared memory should route through for GPU safety | ||||||
|  | ///////////////////////////////////////////////////////////////////////// | ||||||
|  | void GlobalSharedMemory::SharedMemoryZero(void *dest,size_t bytes) | ||||||
|  | { | ||||||
|  | #ifdef GRID_NVCC | ||||||
|  |   cudaMemset(dest,0,bytes); | ||||||
|  | #else | ||||||
|  |   bzero(dest,bytes); | ||||||
|  | #endif | ||||||
|  | } | ||||||
|  | void GlobalSharedMemory::SharedMemoryCopy(void *dest,const void *src,size_t bytes) | ||||||
|  | { | ||||||
|  | #ifdef GRID_NVCC | ||||||
|  |   cudaMemcpy(dest,src,bytes,cudaMemcpyDefault); | ||||||
|  | #else    | ||||||
|  |   bcopy(src,dest,bytes); | ||||||
|  | #endif | ||||||
|  | } | ||||||
|  | //////////////////////////////////////////////////////// | ||||||
|  | // Global shared functionality finished | ||||||
|  | // Now move to per communicator functionality | ||||||
|  | //////////////////////////////////////////////////////// | ||||||
|  | void SharedMemory::SetCommunicator(Grid_MPI_Comm comm) | ||||||
|  | { | ||||||
|  |   int rank, size; | ||||||
|  |   MPI_Comm_rank(comm,&rank); | ||||||
|  |   MPI_Comm_size(comm,&size); | ||||||
|  |   ShmRanks.resize(size); | ||||||
|  |  | ||||||
|  |   ///////////////////////////////////////////////////////////////////// | ||||||
|  |   // Split into groups that can share memory | ||||||
|  |   ///////////////////////////////////////////////////////////////////// | ||||||
|  |   MPI_Comm_split_type(comm, MPI_COMM_TYPE_SHARED, 0, MPI_INFO_NULL,&ShmComm); | ||||||
|  |   MPI_Comm_rank(ShmComm     ,&ShmRank); | ||||||
|  |   MPI_Comm_size(ShmComm     ,&ShmSize); | ||||||
|  |   ShmCommBufs.resize(ShmSize); | ||||||
|  |  | ||||||
|  |   ////////////////////////////////////////////////////////////////////// | ||||||
|  |   // Map ShmRank to WorldShmRank and use the right buffer | ||||||
|  |   ////////////////////////////////////////////////////////////////////// | ||||||
|  |   assert (GlobalSharedMemory::ShmAlloc()==1); | ||||||
|  |   heap_size = GlobalSharedMemory::ShmAllocBytes(); | ||||||
|  |   for(int r=0;r<ShmSize;r++){ | ||||||
|  |  | ||||||
|  |     uint32_t wsr = (r==ShmRank) ? GlobalSharedMemory::WorldShmRank : 0 ; | ||||||
|  |  | ||||||
|  |     MPI_Allreduce(MPI_IN_PLACE,&wsr,1,MPI_UINT32_T,MPI_SUM,ShmComm); | ||||||
|  |  | ||||||
|  |     ShmCommBufs[r] = GlobalSharedMemory::WorldShmCommBufs[wsr]; | ||||||
|  |   } | ||||||
|  |   ShmBufferFreeAll(); | ||||||
|  |  | ||||||
|  |   ///////////////////////////////////////////////////////////////////// | ||||||
|  |   // find comm ranks in our SHM group (i.e. which ranks are on our node) | ||||||
|  |   ///////////////////////////////////////////////////////////////////// | ||||||
|  |   MPI_Group FullGroup, ShmGroup; | ||||||
|  |   MPI_Comm_group (comm   , &FullGroup);  | ||||||
|  |   MPI_Comm_group (ShmComm, &ShmGroup); | ||||||
|  |  | ||||||
|  |   std::vector<int> ranks(size);   for(int r=0;r<size;r++) ranks[r]=r; | ||||||
|  |   MPI_Group_translate_ranks (FullGroup,size,&ranks[0],ShmGroup, &ShmRanks[0]);  | ||||||
|  |  | ||||||
|  |   SharedMemoryTest(); | ||||||
|  | } | ||||||
|  | ////////////////////////////////////////////////////////////////// | ||||||
|  | // On node barrier | ||||||
|  | ////////////////////////////////////////////////////////////////// | ||||||
|  | void SharedMemory::ShmBarrier(void) | ||||||
|  | { | ||||||
|  |   MPI_Barrier  (ShmComm); | ||||||
|  | } | ||||||
|  | ////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  | // Test the shared memory is working | ||||||
|  | ////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  | void SharedMemory::SharedMemoryTest(void) | ||||||
|  | { | ||||||
|  |   ShmBarrier(); | ||||||
|  |   uint64_t check[3]; | ||||||
|  |   uint64_t magic = 0x5A5A5A; | ||||||
|  |   if ( ShmRank == 0 ) { | ||||||
|  |     for(uint64_t r=0;r<ShmSize;r++){ | ||||||
|  |        check[0]=GlobalSharedMemory::WorldNode; | ||||||
|  |        check[1]=r; | ||||||
|  |        check[2]=magic; | ||||||
|  |        GlobalSharedMemory::SharedMemoryCopy( ShmCommBufs[r], check, 3*sizeof(uint64_t)); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   ShmBarrier(); | ||||||
|  |   for(uint64_t r=0;r<ShmSize;r++){ | ||||||
|  |     ShmBarrier(); | ||||||
|  |     GlobalSharedMemory::SharedMemoryCopy(check,ShmCommBufs[r], 3*sizeof(uint64_t)); | ||||||
|  |     ShmBarrier(); | ||||||
|  |     assert(check[0]==GlobalSharedMemory::WorldNode); | ||||||
|  |     assert(check[1]==r); | ||||||
|  |     assert(check[2]==magic); | ||||||
|  |     ShmBarrier(); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void *SharedMemory::ShmBuffer(int rank) | ||||||
|  | { | ||||||
|  |   int gpeer = ShmRanks[rank]; | ||||||
|  |   if (gpeer == MPI_UNDEFINED){ | ||||||
|  |     return NULL; | ||||||
|  |   } else {  | ||||||
|  |     return ShmCommBufs[gpeer]; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | void *SharedMemory::ShmBufferTranslate(int rank,void * local_p) | ||||||
|  | { | ||||||
|  |   int gpeer = ShmRanks[rank]; | ||||||
|  |   assert(gpeer!=ShmRank); // never send to self | ||||||
|  |   if (gpeer == MPI_UNDEFINED){ | ||||||
|  |     return NULL; | ||||||
|  |   } else {  | ||||||
|  |     uint64_t offset = (uint64_t)local_p - (uint64_t)ShmCommBufs[ShmRank]; | ||||||
|  |     uint64_t remote = (uint64_t)ShmCommBufs[gpeer]+offset; | ||||||
|  |     return (void *) remote; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | SharedMemory::~SharedMemory() | ||||||
|  | { | ||||||
|  |   int MPI_is_finalised;  MPI_Finalized(&MPI_is_finalised); | ||||||
|  |   if ( !MPI_is_finalised ) {  | ||||||
|  |     MPI_Comm_free(&ShmComm); | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | NAMESPACE_END(Grid);  | ||||||
|  |  | ||||||
							
								
								
									
										129
									
								
								Grid/communicator/SharedMemoryNone.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										129
									
								
								Grid/communicator/SharedMemoryNone.cc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,129 @@ | |||||||
|  | /************************************************************************************* | ||||||
|  |  | ||||||
|  |     Grid physics library, www.github.com/paboyle/Grid  | ||||||
|  |  | ||||||
|  |     Source file: ./lib/communicator/SharedMemory.cc | ||||||
|  |  | ||||||
|  |     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 */ | ||||||
|  |  | ||||||
|  | #include <Grid/GridCore.h> | ||||||
|  |  | ||||||
|  | NAMESPACE_BEGIN(Grid);  | ||||||
|  |  | ||||||
|  | /*Construct from an MPI communicator*/ | ||||||
|  | void GlobalSharedMemory::Init(Grid_MPI_Comm comm) | ||||||
|  | { | ||||||
|  |   assert(_ShmSetup==0); | ||||||
|  |   WorldComm = 0; | ||||||
|  |   WorldRank = 0; | ||||||
|  |   WorldSize = 1; | ||||||
|  |   WorldShmComm = 0 ; | ||||||
|  |   WorldShmRank = 0 ; | ||||||
|  |   WorldShmSize = 1 ; | ||||||
|  |   WorldNodes   = 1 ; | ||||||
|  |   WorldNode    = 0 ; | ||||||
|  |   WorldShmRanks.resize(WorldSize); WorldShmRanks[0] = 0; | ||||||
|  |   WorldShmCommBufs.resize(1); | ||||||
|  |   _ShmSetup=1; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void GlobalSharedMemory::OptimalCommunicator(const Coordinate &processors,Grid_MPI_Comm & optimal_comm) | ||||||
|  | { | ||||||
|  |   optimal_comm = WorldComm; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | //////////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  | // Hugetlbfs mapping intended, use anonymous mmap | ||||||
|  | //////////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  | void GlobalSharedMemory::SharedMemoryAllocate(uint64_t bytes, int flags) | ||||||
|  | { | ||||||
|  |   void * ShmCommBuf ;  | ||||||
|  |   assert(_ShmSetup==1); | ||||||
|  |   assert(_ShmAlloc==0); | ||||||
|  |   int mmap_flag =0; | ||||||
|  | #ifdef MAP_ANONYMOUS | ||||||
|  |   mmap_flag = mmap_flag| MAP_SHARED | MAP_ANONYMOUS; | ||||||
|  | #endif | ||||||
|  | #ifdef MAP_ANON | ||||||
|  |   mmap_flag = mmap_flag| MAP_SHARED | MAP_ANON; | ||||||
|  | #endif | ||||||
|  | #ifdef MAP_HUGETLB | ||||||
|  |   if ( flags ) mmap_flag |= MAP_HUGETLB; | ||||||
|  | #endif | ||||||
|  |   ShmCommBuf =(void *) mmap(NULL, bytes, PROT_READ | PROT_WRITE, mmap_flag, -1, 0);  | ||||||
|  |   if (ShmCommBuf == (void *)MAP_FAILED) { | ||||||
|  |     perror("mmap failed "); | ||||||
|  |     exit(EXIT_FAILURE);   | ||||||
|  |   } | ||||||
|  | #ifdef MADV_HUGEPAGE | ||||||
|  |   if (!Hugepages ) madvise(ShmCommBuf,bytes,MADV_HUGEPAGE); | ||||||
|  | #endif | ||||||
|  |   bzero(ShmCommBuf,bytes); | ||||||
|  |   WorldShmCommBufs[0] = ShmCommBuf; | ||||||
|  |   _ShmAllocBytes=bytes; | ||||||
|  |   _ShmAlloc=1; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | //////////////////////////////////////////////////////// | ||||||
|  | // Global shared functionality finished | ||||||
|  | // Now move to per communicator functionality | ||||||
|  | //////////////////////////////////////////////////////// | ||||||
|  | void SharedMemory::SetCommunicator(Grid_MPI_Comm comm) | ||||||
|  | { | ||||||
|  |   assert(GlobalSharedMemory::ShmAlloc()==1); | ||||||
|  |   ShmRanks.resize(1); | ||||||
|  |   ShmCommBufs.resize(1); | ||||||
|  |   ShmRanks[0] = 0; | ||||||
|  |   ShmRank     = 0; | ||||||
|  |   ShmSize     = 1; | ||||||
|  |   ////////////////////////////////////////////////////////////////////// | ||||||
|  |   // Map ShmRank to WorldShmRank and use the right buffer | ||||||
|  |   ////////////////////////////////////////////////////////////////////// | ||||||
|  |   ShmCommBufs[0] = GlobalSharedMemory::WorldShmCommBufs[0]; | ||||||
|  |   heap_size      = GlobalSharedMemory::ShmAllocBytes(); | ||||||
|  |   ShmBufferFreeAll(); | ||||||
|  |   return; | ||||||
|  | } | ||||||
|  | ////////////////////////////////////////////////////////////////// | ||||||
|  | // On node barrier | ||||||
|  | ////////////////////////////////////////////////////////////////// | ||||||
|  | void SharedMemory::ShmBarrier(void){ return ; } | ||||||
|  |  | ||||||
|  | ////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  | // Test the shared memory is working | ||||||
|  | ////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  | void SharedMemory::SharedMemoryTest(void) { return; } | ||||||
|  |  | ||||||
|  | void *SharedMemory::ShmBuffer(int rank) | ||||||
|  | { | ||||||
|  |   return NULL; | ||||||
|  | } | ||||||
|  | void *SharedMemory::ShmBufferTranslate(int rank,void * local_p) | ||||||
|  | { | ||||||
|  |   return NULL; | ||||||
|  | } | ||||||
|  | SharedMemory::~SharedMemory() | ||||||
|  | {}; | ||||||
|  |  | ||||||
|  | NAMESPACE_END(Grid);  | ||||||
|  |  | ||||||
| @@ -1,4 +1,4 @@ | |||||||
|     /*************************************************************************************
 | /*************************************************************************************
 | ||||||
| 
 | 
 | ||||||
|     Grid physics library, www.github.com/paboyle/Grid  |     Grid physics library, www.github.com/paboyle/Grid  | ||||||
| 
 | 
 | ||||||
| @@ -23,8 +23,8 @@ Author: Peter Boyle <paboyle@ph.ed.ac.uk> | |||||||
|     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||||||
| 
 | 
 | ||||||
|     See the full license in the file "LICENSE" in the top level distribution directory |     See the full license in the file "LICENSE" in the top level distribution directory | ||||||
|     *************************************************************************************/ | *************************************************************************************/ | ||||||
|     /*  END LEGAL */ | /*  END LEGAL */ | ||||||
| #ifndef _GRID_CSHIFT_H_ | #ifndef _GRID_CSHIFT_H_ | ||||||
| #define _GRID_CSHIFT_H_ | #define _GRID_CSHIFT_H_ | ||||||
| 
 | 
 | ||||||
| @@ -42,7 +42,7 @@ Author: Peter Boyle <paboyle@ph.ed.ac.uk> | |||||||
| #include <Grid/cshift/Cshift_mpi.h> | #include <Grid/cshift/Cshift_mpi.h> | ||||||
| #endif  | #endif  | ||||||
| 
 | 
 | ||||||
| #ifdef GRID_COMMS_MPI3L | #ifdef GRID_COMMS_MPIT | ||||||
| #include <Grid/cshift/Cshift_mpi.h> | #include <Grid/cshift/Cshift_mpi.h> | ||||||
| #endif  | #endif  | ||||||
| 
 | 
 | ||||||
							
								
								
									
										397
									
								
								Grid/cshift/Cshift_common.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										397
									
								
								Grid/cshift/Cshift_common.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,397 @@ | |||||||
|  | /************************************************************************************* | ||||||
|  |  | ||||||
|  |     Grid physics library, www.github.com/paboyle/Grid  | ||||||
|  |  | ||||||
|  |     Source file: ./lib/cshift/Cshift_common.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 */ | ||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | NAMESPACE_BEGIN(Grid); | ||||||
|  |  | ||||||
|  | /////////////////////////////////////////////////////////////////// | ||||||
|  | // Gather for when there is no need to SIMD split  | ||||||
|  | /////////////////////////////////////////////////////////////////// | ||||||
|  | template<class vobj> void  | ||||||
|  | Gather_plane_simple (const Lattice<vobj> &rhs,commVector<vobj> &buffer,int dimension,int plane,int cbmask, int off=0) | ||||||
|  | { | ||||||
|  |   int rd = rhs.Grid()->_rdimensions[dimension]; | ||||||
|  |  | ||||||
|  |   if ( !rhs.Grid()->CheckerBoarded(dimension) ) { | ||||||
|  |     cbmask = 0x3; | ||||||
|  |   } | ||||||
|  |    | ||||||
|  |   int so=plane*rhs.Grid()->_ostride[dimension]; // base offset for start of plane  | ||||||
|  |   int e1=rhs.Grid()->_slice_nblock[dimension]; | ||||||
|  |   int e2=rhs.Grid()->_slice_block[dimension]; | ||||||
|  |   int ent = 0; | ||||||
|  |  | ||||||
|  |   static Vector<std::pair<int,int> > table; table.resize(e1*e2); | ||||||
|  |   int stride=rhs.Grid()->_slice_stride[dimension]; | ||||||
|  |  | ||||||
|  |   auto rhs_v = rhs.View(); | ||||||
|  |   if ( cbmask == 0x3 ) {  | ||||||
|  |     for(int n=0;n<e1;n++){ | ||||||
|  |       for(int b=0;b<e2;b++){ | ||||||
|  | 	int o  = n*stride; | ||||||
|  | 	int bo = n*e2; | ||||||
|  | 	table[ent++] = std::pair<int,int>(off+bo+b,so+o+b); | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } else {  | ||||||
|  |      int bo=0; | ||||||
|  |      for(int n=0;n<e1;n++){ | ||||||
|  |        for(int b=0;b<e2;b++){ | ||||||
|  | 	 int o  = n*stride; | ||||||
|  | 	 int ocb=1<<rhs.Grid()->CheckerBoardFromOindex(o+b); | ||||||
|  | 	 if ( ocb &cbmask ) { | ||||||
|  | 	   table[ent++]=std::pair<int,int> (off+bo++,so+o+b); | ||||||
|  | 	 } | ||||||
|  |        } | ||||||
|  |      } | ||||||
|  |   } | ||||||
|  |   thread_for(i,ent,{ | ||||||
|  |     buffer[table[i].first]=rhs_v[table[i].second]; | ||||||
|  |   }); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /////////////////////////////////////////////////////////////////// | ||||||
|  | // Gather for when there *is* need to SIMD split  | ||||||
|  | /////////////////////////////////////////////////////////////////// | ||||||
|  | template<class vobj> void  | ||||||
|  | Gather_plane_extract(const Lattice<vobj> &rhs, | ||||||
|  | 		     ExtractPointerArray<typename vobj::scalar_object> pointers, | ||||||
|  | 		     int dimension,int plane,int cbmask) | ||||||
|  | { | ||||||
|  |   int rd = rhs.Grid()->_rdimensions[dimension]; | ||||||
|  |  | ||||||
|  |   if ( !rhs.Grid()->CheckerBoarded(dimension) ) { | ||||||
|  |     cbmask = 0x3; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   int so  = plane*rhs.Grid()->_ostride[dimension]; // base offset for start of plane  | ||||||
|  |  | ||||||
|  |   int e1=rhs.Grid()->_slice_nblock[dimension]; | ||||||
|  |   int e2=rhs.Grid()->_slice_block[dimension]; | ||||||
|  |   int n1=rhs.Grid()->_slice_stride[dimension]; | ||||||
|  |  | ||||||
|  |   auto rhs_v = rhs.View(); | ||||||
|  |   if ( cbmask ==0x3){ | ||||||
|  |     thread_for_collapse(2,n,e1,{ | ||||||
|  |       for(int b=0;b<e2;b++){ | ||||||
|  |  | ||||||
|  | 	int o      =   n*n1; | ||||||
|  | 	int offset = b+n*e2; | ||||||
|  | 	 | ||||||
|  | 	vobj temp =rhs_v[so+o+b]; | ||||||
|  | 	extract<vobj>(temp,pointers,offset); | ||||||
|  |       } | ||||||
|  |     }); | ||||||
|  |   } else {  | ||||||
|  |  | ||||||
|  |     // Case of SIMD split AND checker dim cannot currently be hit, except in  | ||||||
|  |     // Test_cshift_red_black code. | ||||||
|  |     std::cout << " Dense packed buffer WARNING " <<std::endl; | ||||||
|  |     thread_for_collapse(2,n,e1,{ | ||||||
|  |       for(int b=0;b<e2;b++){ | ||||||
|  |  | ||||||
|  | 	int o=n*n1; | ||||||
|  | 	int ocb=1<<rhs.Grid()->CheckerBoardFromOindex(o+b); | ||||||
|  | 	int offset = b+n*e2; | ||||||
|  |  | ||||||
|  | 	if ( ocb & cbmask ) { | ||||||
|  | 	  vobj temp =rhs_v[so+o+b]; | ||||||
|  | 	  extract<vobj>(temp,pointers,offset); | ||||||
|  | 	} | ||||||
|  |       } | ||||||
|  |     }); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | ////////////////////////////////////////////////////// | ||||||
|  | // Scatter for when there is no need to SIMD split | ||||||
|  | ////////////////////////////////////////////////////// | ||||||
|  | template<class vobj> void Scatter_plane_simple (Lattice<vobj> &rhs,commVector<vobj> &buffer, int dimension,int plane,int cbmask) | ||||||
|  | { | ||||||
|  |   int rd = rhs.Grid()->_rdimensions[dimension]; | ||||||
|  |  | ||||||
|  |   if ( !rhs.Grid()->CheckerBoarded(dimension) ) { | ||||||
|  |     cbmask=0x3; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   int so  = plane*rhs.Grid()->_ostride[dimension]; // base offset for start of plane  | ||||||
|  |      | ||||||
|  |   int e1=rhs.Grid()->_slice_nblock[dimension]; | ||||||
|  |   int e2=rhs.Grid()->_slice_block[dimension]; | ||||||
|  |   int stride=rhs.Grid()->_slice_stride[dimension]; | ||||||
|  |  | ||||||
|  |   static std::vector<std::pair<int,int> > table; table.resize(e1*e2); | ||||||
|  |   int ent    =0; | ||||||
|  |  | ||||||
|  |   if ( cbmask ==0x3 ) { | ||||||
|  |  | ||||||
|  |     for(int n=0;n<e1;n++){ | ||||||
|  |       for(int b=0;b<e2;b++){ | ||||||
|  | 	int o   =n*rhs.Grid()->_slice_stride[dimension]; | ||||||
|  | 	int bo  =n*rhs.Grid()->_slice_block[dimension]; | ||||||
|  | 	table[ent++] = std::pair<int,int>(so+o+b,bo+b); | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |   } else {  | ||||||
|  |     int bo=0; | ||||||
|  |     for(int n=0;n<e1;n++){ | ||||||
|  |       for(int b=0;b<e2;b++){ | ||||||
|  | 	int o   =n*rhs.Grid()->_slice_stride[dimension]; | ||||||
|  | 	int ocb=1<<rhs.Grid()->CheckerBoardFromOindex(o+b);// Could easily be a table lookup | ||||||
|  | 	if ( ocb & cbmask ) { | ||||||
|  | 	  table[ent++]=std::pair<int,int> (so+o+b,bo++); | ||||||
|  | 	} | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |    | ||||||
|  |   auto rhs_v = rhs.View(); | ||||||
|  |   thread_for(i,ent,{ | ||||||
|  |     rhs_v[table[i].first]=buffer[table[i].second]; | ||||||
|  |   }); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | ////////////////////////////////////////////////////// | ||||||
|  | // Scatter for when there *is* need to SIMD split | ||||||
|  | ////////////////////////////////////////////////////// | ||||||
|  | template<class vobj> void Scatter_plane_merge(Lattice<vobj> &rhs,ExtractPointerArray<typename vobj::scalar_object> pointers,int dimension,int plane,int cbmask) | ||||||
|  | { | ||||||
|  |   int rd = rhs.Grid()->_rdimensions[dimension]; | ||||||
|  |  | ||||||
|  |   if ( !rhs.Grid()->CheckerBoarded(dimension) ) { | ||||||
|  |     cbmask=0x3; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   int so  = plane*rhs.Grid()->_ostride[dimension]; // base offset for start of plane  | ||||||
|  |      | ||||||
|  |   int e1=rhs.Grid()->_slice_nblock[dimension]; | ||||||
|  |   int e2=rhs.Grid()->_slice_block[dimension]; | ||||||
|  |  | ||||||
|  |   if(cbmask ==0x3 ) { | ||||||
|  |     auto rhs_v = rhs.View(); | ||||||
|  |     thread_for_collapse(2,n,e1,{ | ||||||
|  |       for(int b=0;b<e2;b++){ | ||||||
|  | 	int o      = n*rhs.Grid()->_slice_stride[dimension]; | ||||||
|  | 	int offset = b+n*rhs.Grid()->_slice_block[dimension]; | ||||||
|  | 	merge(rhs_v[so+o+b],pointers,offset); | ||||||
|  |       } | ||||||
|  |     }); | ||||||
|  |   } else {  | ||||||
|  |  | ||||||
|  |     // Case of SIMD split AND checker dim cannot currently be hit, except in  | ||||||
|  |     // Test_cshift_red_black code. | ||||||
|  |     //    std::cout << "Scatter_plane merge assert(0); think this is buggy FIXME "<< std::endl;// think this is buggy FIXME | ||||||
|  |     std::cout<<" Unthreaded warning -- buffer is not densely packed ??"<<std::endl; | ||||||
|  |     auto rhs_v = rhs.View(); | ||||||
|  |     for(int n=0;n<e1;n++){ | ||||||
|  |       for(int b=0;b<e2;b++){ | ||||||
|  | 	int o      = n*rhs.Grid()->_slice_stride[dimension]; | ||||||
|  | 	int offset = b+n*rhs.Grid()->_slice_block[dimension]; | ||||||
|  | 	int ocb=1<<rhs.Grid()->CheckerBoardFromOindex(o+b); | ||||||
|  | 	if ( ocb&cbmask ) { | ||||||
|  | 	  merge(rhs_v[so+o+b],pointers,offset); | ||||||
|  | 	} | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | ////////////////////////////////////////////////////// | ||||||
|  | // local to node block strided copies | ||||||
|  | ////////////////////////////////////////////////////// | ||||||
|  | template<class vobj> void Copy_plane(Lattice<vobj>& lhs,const Lattice<vobj> &rhs, int dimension,int lplane,int rplane,int cbmask) | ||||||
|  | { | ||||||
|  |   int rd = rhs.Grid()->_rdimensions[dimension]; | ||||||
|  |  | ||||||
|  |   if ( !rhs.Grid()->CheckerBoarded(dimension) ) { | ||||||
|  |     cbmask=0x3; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   int ro  = rplane*rhs.Grid()->_ostride[dimension]; // base offset for start of plane  | ||||||
|  |   int lo  = lplane*lhs.Grid()->_ostride[dimension]; // base offset for start of plane  | ||||||
|  |  | ||||||
|  |   int e1=rhs.Grid()->_slice_nblock[dimension]; // clearly loop invariant for icpc | ||||||
|  |   int e2=rhs.Grid()->_slice_block[dimension]; | ||||||
|  |   int stride = rhs.Grid()->_slice_stride[dimension]; | ||||||
|  |   static std::vector<std::pair<int,int> > table; table.resize(e1*e2); | ||||||
|  |   int ent=0; | ||||||
|  |  | ||||||
|  |   if(cbmask == 0x3 ){ | ||||||
|  |     for(int n=0;n<e1;n++){ | ||||||
|  |       for(int b=0;b<e2;b++){ | ||||||
|  |         int o =n*stride+b; | ||||||
|  | 	table[ent++] = std::pair<int,int>(lo+o,ro+o); | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } else {  | ||||||
|  |     for(int n=0;n<e1;n++){ | ||||||
|  |       for(int b=0;b<e2;b++){ | ||||||
|  |         int o =n*stride+b; | ||||||
|  |         int ocb=1<<lhs.Grid()->CheckerBoardFromOindex(o); | ||||||
|  |         if ( ocb&cbmask ) { | ||||||
|  | 	  table[ent++] = std::pair<int,int>(lo+o,ro+o); | ||||||
|  | 	} | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   auto rhs_v = rhs.View(); | ||||||
|  |   auto lhs_v = lhs.View(); | ||||||
|  |   thread_for(i,ent,{ | ||||||
|  |     lhs_v[table[i].first]=rhs_v[table[i].second]; | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  | } | ||||||
|  |  | ||||||
|  | template<class vobj> void Copy_plane_permute(Lattice<vobj>& lhs,const Lattice<vobj> &rhs, int dimension,int lplane,int rplane,int cbmask,int permute_type) | ||||||
|  | { | ||||||
|  |   | ||||||
|  |   int rd = rhs.Grid()->_rdimensions[dimension]; | ||||||
|  |  | ||||||
|  |   if ( !rhs.Grid()->CheckerBoarded(dimension) ) { | ||||||
|  |     cbmask=0x3; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   int ro  = rplane*rhs.Grid()->_ostride[dimension]; // base offset for start of plane  | ||||||
|  |   int lo  = lplane*lhs.Grid()->_ostride[dimension]; // base offset for start of plane  | ||||||
|  |  | ||||||
|  |   int e1=rhs.Grid()->_slice_nblock[dimension]; | ||||||
|  |   int e2=rhs.Grid()->_slice_block [dimension]; | ||||||
|  |   int stride = rhs.Grid()->_slice_stride[dimension]; | ||||||
|  |  | ||||||
|  |   static std::vector<std::pair<int,int> > table;  table.resize(e1*e2); | ||||||
|  |   int ent=0; | ||||||
|  |  | ||||||
|  |   if ( cbmask == 0x3 ) { | ||||||
|  |     for(int n=0;n<e1;n++){ | ||||||
|  |     for(int b=0;b<e2;b++){ | ||||||
|  |       int o  =n*stride; | ||||||
|  |       table[ent++] = std::pair<int,int>(lo+o+b,ro+o+b); | ||||||
|  |     }} | ||||||
|  |   } else { | ||||||
|  |     for(int n=0;n<e1;n++){ | ||||||
|  |     for(int b=0;b<e2;b++){ | ||||||
|  |       int o  =n*stride; | ||||||
|  |       int ocb=1<<lhs.Grid()->CheckerBoardFromOindex(o+b); | ||||||
|  |       if ( ocb&cbmask ) table[ent++] = std::pair<int,int>(lo+o+b,ro+o+b); | ||||||
|  |     }} | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   auto rhs_v = rhs.View(); | ||||||
|  |   auto lhs_v = lhs.View(); | ||||||
|  |   thread_for(i,ent,{ | ||||||
|  |     permute(lhs_v[table[i].first],rhs_v[table[i].second],permute_type); | ||||||
|  |   }); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | ////////////////////////////////////////////////////// | ||||||
|  | // Local to node Cshift | ||||||
|  | ////////////////////////////////////////////////////// | ||||||
|  | template<class vobj> void Cshift_local(Lattice<vobj>& ret,const Lattice<vobj> &rhs,int dimension,int shift) | ||||||
|  | { | ||||||
|  |   int sshift[2]; | ||||||
|  |  | ||||||
|  |   sshift[0] = rhs.Grid()->CheckerBoardShiftForCB(rhs.Checkerboard(),dimension,shift,Even); | ||||||
|  |   sshift[1] = rhs.Grid()->CheckerBoardShiftForCB(rhs.Checkerboard(),dimension,shift,Odd); | ||||||
|  |  | ||||||
|  |   if ( sshift[0] == sshift[1] ) { | ||||||
|  |     Cshift_local(ret,rhs,dimension,shift,0x3); | ||||||
|  |   } else { | ||||||
|  |     Cshift_local(ret,rhs,dimension,shift,0x1);// if checkerboard is unfavourable take two passes | ||||||
|  |     Cshift_local(ret,rhs,dimension,shift,0x2);// both with block stride loop iteration | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | template<class vobj> void Cshift_local(Lattice<vobj> &ret,const Lattice<vobj> &rhs,int dimension,int shift,int cbmask) | ||||||
|  | { | ||||||
|  |   GridBase *grid = rhs.Grid(); | ||||||
|  |   int fd = grid->_fdimensions[dimension]; | ||||||
|  |   int rd = grid->_rdimensions[dimension]; | ||||||
|  |   int ld = grid->_ldimensions[dimension]; | ||||||
|  |   int gd = grid->_gdimensions[dimension]; | ||||||
|  |   int ly = grid->_simd_layout[dimension]; | ||||||
|  |  | ||||||
|  |   // Map to always positive shift modulo global full dimension. | ||||||
|  |   shift = (shift+fd)%fd; | ||||||
|  |  | ||||||
|  |   // the permute type | ||||||
|  |   ret.Checkerboard() = grid->CheckerBoardDestination(rhs.Checkerboard(),shift,dimension); | ||||||
|  |   int permute_dim =grid->PermuteDim(dimension); | ||||||
|  |   int permute_type=grid->PermuteType(dimension); | ||||||
|  |   int permute_type_dist; | ||||||
|  |  | ||||||
|  |   for(int x=0;x<rd;x++){        | ||||||
|  |  | ||||||
|  |     //    int o   = 0; | ||||||
|  |     int bo  = x * grid->_ostride[dimension]; | ||||||
|  |     int cb= (cbmask==0x2)? Odd : Even; | ||||||
|  |  | ||||||
|  |     int sshift = grid->CheckerBoardShiftForCB(rhs.Checkerboard(),dimension,shift,cb); | ||||||
|  |     int sx     = (x+sshift)%rd; | ||||||
|  |      | ||||||
|  |     // wrap is whether sshift > rd. | ||||||
|  |     //  num is sshift mod rd. | ||||||
|  |     //  | ||||||
|  |     //  shift 7 | ||||||
|  |     // | ||||||
|  |     //  XoXo YcYc  | ||||||
|  |     //  oXoX cYcY | ||||||
|  |     //  XoXo YcYc | ||||||
|  |     //  oXoX cYcY | ||||||
|  |     // | ||||||
|  |     //  sshift --  | ||||||
|  |     // | ||||||
|  |     //  XX YY ; 3 | ||||||
|  |     //  XX YY ; 0 | ||||||
|  |     //  XX YY ; 3 | ||||||
|  |     //  XX YY ; 0 | ||||||
|  |     // | ||||||
|  |     int permute_slice=0; | ||||||
|  |     if(permute_dim){ | ||||||
|  |       int wrap = sshift/rd; wrap=wrap % ly; | ||||||
|  |       int  num = sshift%rd; | ||||||
|  |  | ||||||
|  |       if ( x< rd-num ) permute_slice=wrap; | ||||||
|  |       else permute_slice = (wrap+1)%ly; | ||||||
|  |  | ||||||
|  |       if ( (ly>2) && (permute_slice) ) { | ||||||
|  | 	assert(permute_type & RotateBit); | ||||||
|  | 	permute_type_dist = permute_type|permute_slice; | ||||||
|  |       } else { | ||||||
|  | 	permute_type_dist = permute_type; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if ( permute_slice ) Copy_plane_permute(ret,rhs,dimension,x,sx,cbmask,permute_type_dist); | ||||||
|  |     else                 Copy_plane(ret,rhs,dimension,x,sx,cbmask);  | ||||||
|  |    | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | NAMESPACE_END(Grid); | ||||||
|  |  | ||||||
| @@ -1,4 +1,4 @@ | |||||||
|     /*************************************************************************************
 | /*************************************************************************************
 | ||||||
| 
 | 
 | ||||||
|     Grid physics library, www.github.com/paboyle/Grid  |     Grid physics library, www.github.com/paboyle/Grid  | ||||||
| 
 | 
 | ||||||
| @@ -24,43 +24,43 @@ Author: paboyle <paboyle@ph.ed.ac.uk> | |||||||
|     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||||||
| 
 | 
 | ||||||
|     See the full license in the file "LICENSE" in the top level distribution directory |     See the full license in the file "LICENSE" in the top level distribution directory | ||||||
|     *************************************************************************************/ | *************************************************************************************/ | ||||||
|     /*  END LEGAL */ | /*  END LEGAL */ | ||||||
| #ifndef _GRID_CSHIFT_MPI_H_ | #ifndef _GRID_CSHIFT_MPI_H_ | ||||||
| #define _GRID_CSHIFT_MPI_H_ | #define _GRID_CSHIFT_MPI_H_ | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| namespace Grid {  | NAMESPACE_BEGIN(Grid);  | ||||||
| 
 | 
 | ||||||
| template<class vobj> Lattice<vobj> Cshift(const Lattice<vobj> &rhs,int dimension,int shift) | template<class vobj> Lattice<vobj> Cshift(const Lattice<vobj> &rhs,int dimension,int shift) | ||||||
| { | { | ||||||
|   typedef typename vobj::vector_type vector_type; |   typedef typename vobj::vector_type vector_type; | ||||||
|   typedef typename vobj::scalar_type scalar_type; |   typedef typename vobj::scalar_type scalar_type; | ||||||
| 
 | 
 | ||||||
|   Lattice<vobj> ret(rhs._grid);  |   Lattice<vobj> ret(rhs.Grid());  | ||||||
|    |    | ||||||
|   int fd = rhs._grid->_fdimensions[dimension]; |   int fd = rhs.Grid()->_fdimensions[dimension]; | ||||||
|   int rd = rhs._grid->_rdimensions[dimension]; |   int rd = rhs.Grid()->_rdimensions[dimension]; | ||||||
| 
 | 
 | ||||||
|   // Map to always positive shift modulo global full dimension.
 |   // Map to always positive shift modulo global full dimension.
 | ||||||
|   shift = (shift+fd)%fd; |   shift = (shift+fd)%fd; | ||||||
| 
 | 
 | ||||||
|   ret.checkerboard = rhs._grid->CheckerBoardDestination(rhs.checkerboard,shift,dimension); |   ret.Checkerboard() = rhs.Grid()->CheckerBoardDestination(rhs.Checkerboard(),shift,dimension); | ||||||
|          |          | ||||||
|   // the permute type
 |   // the permute type
 | ||||||
|   int simd_layout     = rhs._grid->_simd_layout[dimension]; |   int simd_layout     = rhs.Grid()->_simd_layout[dimension]; | ||||||
|   int comm_dim        = rhs._grid->_processors[dimension] >1 ; |   int comm_dim        = rhs.Grid()->_processors[dimension] >1 ; | ||||||
|   int splice_dim      = rhs._grid->_simd_layout[dimension]>1 && (comm_dim); |   int splice_dim      = rhs.Grid()->_simd_layout[dimension]>1 && (comm_dim); | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|   if ( !comm_dim ) { |   if ( !comm_dim ) { | ||||||
|     //    std::cout << "Cshift_local" <<std::endl;
 |     //std::cout << "CSHIFT: Cshift_local" <<std::endl;
 | ||||||
|     Cshift_local(ret,rhs,dimension,shift); // Handles checkerboarding
 |     Cshift_local(ret,rhs,dimension,shift); // Handles checkerboarding
 | ||||||
|   } else if ( splice_dim ) { |   } else if ( splice_dim ) { | ||||||
|     //    std::cout << "Cshift_comms_simd" <<std::endl;
 |     //std::cout << "CSHIFT: Cshift_comms_simd call - splice_dim = " << splice_dim << " shift " << shift << " dimension = " << dimension << std::endl;
 | ||||||
|     Cshift_comms_simd(ret,rhs,dimension,shift); |     Cshift_comms_simd(ret,rhs,dimension,shift); | ||||||
|   } else { |   } else { | ||||||
|     //    std::cout << "Cshift_comms" <<std::endl;
 |     //std::cout << "CSHIFT: Cshift_comms" <<std::endl;
 | ||||||
|     Cshift_comms(ret,rhs,dimension,shift); |     Cshift_comms(ret,rhs,dimension,shift); | ||||||
|   } |   } | ||||||
|   return ret; |   return ret; | ||||||
| @@ -70,10 +70,10 @@ template<class vobj> void Cshift_comms(Lattice<vobj>& ret,const Lattice<vobj> &r | |||||||
| { | { | ||||||
|   int sshift[2]; |   int sshift[2]; | ||||||
| 
 | 
 | ||||||
|   sshift[0] = rhs._grid->CheckerBoardShiftForCB(rhs.checkerboard,dimension,shift,Even); |   sshift[0] = rhs.Grid()->CheckerBoardShiftForCB(rhs.Checkerboard(),dimension,shift,Even); | ||||||
|   sshift[1] = rhs._grid->CheckerBoardShiftForCB(rhs.checkerboard,dimension,shift,Odd); |   sshift[1] = rhs.Grid()->CheckerBoardShiftForCB(rhs.Checkerboard(),dimension,shift,Odd); | ||||||
| 
 | 
 | ||||||
|   //  std::cout << "Cshift_comms dim "<<dimension<<"cb "<<rhs.checkerboard<<"shift "<<shift<<" sshift " << sshift[0]<<" "<<sshift[1]<<std::endl;
 |   //  std::cout << "Cshift_comms dim "<<dimension<<"cb "<<rhs.Checkerboard()<<"shift "<<shift<<" sshift " << sshift[0]<<" "<<sshift[1]<<std::endl;
 | ||||||
|   if ( sshift[0] == sshift[1] ) { |   if ( sshift[0] == sshift[1] ) { | ||||||
|     //    std::cout << "Single pass Cshift_comms" <<std::endl;
 |     //    std::cout << "Single pass Cshift_comms" <<std::endl;
 | ||||||
|     Cshift_comms(ret,rhs,dimension,shift,0x3); |     Cshift_comms(ret,rhs,dimension,shift,0x3); | ||||||
| @@ -88,12 +88,15 @@ template<class vobj> void Cshift_comms_simd(Lattice<vobj>& ret,const Lattice<vob | |||||||
| { | { | ||||||
|   int sshift[2]; |   int sshift[2]; | ||||||
| 
 | 
 | ||||||
|   sshift[0] = rhs._grid->CheckerBoardShiftForCB(rhs.checkerboard,dimension,shift,Even); |   sshift[0] = rhs.Grid()->CheckerBoardShiftForCB(rhs.Checkerboard(),dimension,shift,Even); | ||||||
|   sshift[1] = rhs._grid->CheckerBoardShiftForCB(rhs.checkerboard,dimension,shift,Odd); |   sshift[1] = rhs.Grid()->CheckerBoardShiftForCB(rhs.Checkerboard(),dimension,shift,Odd); | ||||||
| 
 | 
 | ||||||
|  |   //std::cout << "Cshift_comms_simd dim "<<dimension<<"cb "<<rhs.checkerboard<<"shift "<<shift<<" sshift " << sshift[0]<<" "<<sshift[1]<<std::endl;
 | ||||||
|   if ( sshift[0] == sshift[1] ) { |   if ( sshift[0] == sshift[1] ) { | ||||||
|  |     //std::cout << "Single pass Cshift_comms" <<std::endl;
 | ||||||
|     Cshift_comms_simd(ret,rhs,dimension,shift,0x3); |     Cshift_comms_simd(ret,rhs,dimension,shift,0x3); | ||||||
|   } else { |   } else { | ||||||
|  |     //std::cout << "Two pass Cshift_comms" <<std::endl;
 | ||||||
|     Cshift_comms_simd(ret,rhs,dimension,shift,0x1);// if checkerboard is unfavourable take two passes
 |     Cshift_comms_simd(ret,rhs,dimension,shift,0x1);// if checkerboard is unfavourable take two passes
 | ||||||
|     Cshift_comms_simd(ret,rhs,dimension,shift,0x2);// both with block stride loop iteration
 |     Cshift_comms_simd(ret,rhs,dimension,shift,0x2);// both with block stride loop iteration
 | ||||||
|   } |   } | ||||||
| @@ -104,25 +107,25 @@ template<class vobj> void Cshift_comms(Lattice<vobj> &ret,const Lattice<vobj> &r | |||||||
|   typedef typename vobj::vector_type vector_type; |   typedef typename vobj::vector_type vector_type; | ||||||
|   typedef typename vobj::scalar_type scalar_type; |   typedef typename vobj::scalar_type scalar_type; | ||||||
| 
 | 
 | ||||||
|   GridBase *grid=rhs._grid; |   GridBase *grid=rhs.Grid(); | ||||||
|   Lattice<vobj> temp(rhs._grid); |   Lattice<vobj> temp(rhs.Grid()); | ||||||
| 
 | 
 | ||||||
|   int fd              = rhs._grid->_fdimensions[dimension]; |   int fd              = rhs.Grid()->_fdimensions[dimension]; | ||||||
|   int rd              = rhs._grid->_rdimensions[dimension]; |   int rd              = rhs.Grid()->_rdimensions[dimension]; | ||||||
|   int pd              = rhs._grid->_processors[dimension]; |   int pd              = rhs.Grid()->_processors[dimension]; | ||||||
|   int simd_layout     = rhs._grid->_simd_layout[dimension]; |   int simd_layout     = rhs.Grid()->_simd_layout[dimension]; | ||||||
|   int comm_dim        = rhs._grid->_processors[dimension] >1 ; |   int comm_dim        = rhs.Grid()->_processors[dimension] >1 ; | ||||||
|   assert(simd_layout==1); |   assert(simd_layout==1); | ||||||
|   assert(comm_dim==1); |   assert(comm_dim==1); | ||||||
|   assert(shift>=0); |   assert(shift>=0); | ||||||
|   assert(shift<fd); |   assert(shift<fd); | ||||||
|    |    | ||||||
|   int buffer_size = rhs._grid->_slice_nblock[dimension]*rhs._grid->_slice_block[dimension]; |   int buffer_size = rhs.Grid()->_slice_nblock[dimension]*rhs.Grid()->_slice_block[dimension]; | ||||||
|   commVector<vobj> send_buf(buffer_size); |   commVector<vobj> send_buf(buffer_size); | ||||||
|   commVector<vobj> recv_buf(buffer_size); |   commVector<vobj> recv_buf(buffer_size); | ||||||
| 
 | 
 | ||||||
|   int cb= (cbmask==0x2)? Odd : Even; |   int cb= (cbmask==0x2)? Odd : Even; | ||||||
|   int sshift= rhs._grid->CheckerBoardShiftForCB(rhs.checkerboard,dimension,shift,cb); |   int sshift= rhs.Grid()->CheckerBoardShiftForCB(rhs.Checkerboard(),dimension,shift,cb); | ||||||
| 
 | 
 | ||||||
|   for(int x=0;x<rd;x++){        |   for(int x=0;x<rd;x++){        | ||||||
| 
 | 
 | ||||||
| @@ -142,7 +145,7 @@ template<class vobj> void Cshift_comms(Lattice<vobj> &ret,const Lattice<vobj> &r | |||||||
| 
 | 
 | ||||||
|       Gather_plane_simple (rhs,send_buf,dimension,sx,cbmask); |       Gather_plane_simple (rhs,send_buf,dimension,sx,cbmask); | ||||||
| 
 | 
 | ||||||
|       int rank           = grid->_processor; |       //      int rank           = grid->_processor;
 | ||||||
|       int recv_from_rank; |       int recv_from_rank; | ||||||
|       int xmit_to_rank; |       int xmit_to_rank; | ||||||
|       grid->ShiftedRanks(dimension,comm_proc,xmit_to_rank,recv_from_rank); |       grid->ShiftedRanks(dimension,comm_proc,xmit_to_rank,recv_from_rank); | ||||||
| @@ -154,13 +157,7 @@ template<class vobj> void Cshift_comms(Lattice<vobj> &ret,const Lattice<vobj> &r | |||||||
| 			   recv_from_rank, | 			   recv_from_rank, | ||||||
| 			   bytes); | 			   bytes); | ||||||
|       grid->Barrier(); |       grid->Barrier(); | ||||||
|       /*
 | 
 | ||||||
|       for(int i=0;i<send_buf.size();i++){ |  | ||||||
| 	assert(recv_buf.size()==buffer_size); |  | ||||||
| 	assert(send_buf.size()==buffer_size); |  | ||||||
| 	std::cout << "SendRecv_Cshift_comms ["<<i<<" "<< dimension<<"] snd "<<send_buf[i]<<" rcv " << recv_buf[i] << "  0x" << cbmask<<std::endl; |  | ||||||
|       } |  | ||||||
|       */ |  | ||||||
|       Scatter_plane_simple (ret,recv_buf,dimension,x,cbmask); |       Scatter_plane_simple (ret,recv_buf,dimension,x,cbmask); | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| @@ -168,7 +165,7 @@ template<class vobj> void Cshift_comms(Lattice<vobj> &ret,const Lattice<vobj> &r | |||||||
| 
 | 
 | ||||||
| template<class vobj> void  Cshift_comms_simd(Lattice<vobj> &ret,const Lattice<vobj> &rhs,int dimension,int shift,int cbmask) | template<class vobj> void  Cshift_comms_simd(Lattice<vobj> &ret,const Lattice<vobj> &rhs,int dimension,int shift,int cbmask) | ||||||
| { | { | ||||||
|   GridBase *grid=rhs._grid; |   GridBase *grid=rhs.Grid(); | ||||||
|   const int Nsimd = grid->Nsimd(); |   const int Nsimd = grid->Nsimd(); | ||||||
|   typedef typename vobj::vector_type vector_type; |   typedef typename vobj::vector_type vector_type; | ||||||
|   typedef typename vobj::scalar_object scalar_object; |   typedef typename vobj::scalar_object scalar_object; | ||||||
| @@ -181,6 +178,10 @@ template<class vobj> void  Cshift_comms_simd(Lattice<vobj> &ret,const Lattice<vo | |||||||
|   int simd_layout     = grid->_simd_layout[dimension]; |   int simd_layout     = grid->_simd_layout[dimension]; | ||||||
|   int comm_dim        = grid->_processors[dimension] >1 ; |   int comm_dim        = grid->_processors[dimension] >1 ; | ||||||
| 
 | 
 | ||||||
|  |   //std::cout << "Cshift_comms_simd dim "<< dimension << " fd "<<fd<<" rd "<<rd
 | ||||||
|  |   //    << " ld "<<ld<<" pd " << pd<<" simd_layout "<<simd_layout 
 | ||||||
|  |   //    << " comm_dim " << comm_dim << " cbmask " << cbmask <<std::endl;
 | ||||||
|  | 
 | ||||||
|   assert(comm_dim==1); |   assert(comm_dim==1); | ||||||
|   assert(simd_layout==2); |   assert(simd_layout==2); | ||||||
|   assert(shift>=0); |   assert(shift>=0); | ||||||
| @@ -192,21 +193,21 @@ template<class vobj> void  Cshift_comms_simd(Lattice<vobj> &ret,const Lattice<vo | |||||||
|   // Simd direction uses an extract/merge pair
 |   // Simd direction uses an extract/merge pair
 | ||||||
|   ///////////////////////////////////////////////
 |   ///////////////////////////////////////////////
 | ||||||
|   int buffer_size = grid->_slice_nblock[dimension]*grid->_slice_block[dimension]; |   int buffer_size = grid->_slice_nblock[dimension]*grid->_slice_block[dimension]; | ||||||
|   int words = sizeof(vobj)/sizeof(vector_type); |   //  int words = sizeof(vobj)/sizeof(vector_type);
 | ||||||
| 
 | 
 | ||||||
|   std::vector<commVector<scalar_object> >   send_buf_extract(Nsimd,commVector<scalar_object>(buffer_size) ); |   std::vector<commVector<scalar_object> >   send_buf_extract(Nsimd,commVector<scalar_object>(buffer_size) ); | ||||||
|   std::vector<commVector<scalar_object> >   recv_buf_extract(Nsimd,commVector<scalar_object>(buffer_size) ); |   std::vector<commVector<scalar_object> >   recv_buf_extract(Nsimd,commVector<scalar_object>(buffer_size) ); | ||||||
| 
 | 
 | ||||||
|   int bytes = buffer_size*sizeof(scalar_object); |   int bytes = buffer_size*sizeof(scalar_object); | ||||||
| 
 | 
 | ||||||
|   std::vector<scalar_object *>  pointers(Nsimd); // 
 |   ExtractPointerArray<scalar_object>  pointers(Nsimd); // 
 | ||||||
|   std::vector<scalar_object *> rpointers(Nsimd); // received pointers
 |   ExtractPointerArray<scalar_object> rpointers(Nsimd); // received pointers
 | ||||||
| 
 | 
 | ||||||
|   ///////////////////////////////////////////
 |   ///////////////////////////////////////////
 | ||||||
|   // Work out what to send where
 |   // Work out what to send where
 | ||||||
|   ///////////////////////////////////////////
 |   ///////////////////////////////////////////
 | ||||||
|   int cb    = (cbmask==0x2)? Odd : Even; |   int cb    = (cbmask==0x2)? Odd : Even; | ||||||
|   int sshift= grid->CheckerBoardShiftForCB(rhs.checkerboard,dimension,shift,cb); |   int sshift= grid->CheckerBoardShiftForCB(rhs.Checkerboard(),dimension,shift,cb); | ||||||
| 
 | 
 | ||||||
|   // loop over outer coord planes orthog to dim
 |   // loop over outer coord planes orthog to dim
 | ||||||
|   for(int x=0;x<rd;x++){        |   for(int x=0;x<rd;x++){        | ||||||
| @@ -246,13 +247,6 @@ template<class vobj> void  Cshift_comms_simd(Lattice<vobj> &ret,const Lattice<vo | |||||||
| 			     (void *)&recv_buf_extract[i][0], | 			     (void *)&recv_buf_extract[i][0], | ||||||
| 			     recv_from_rank, | 			     recv_from_rank, | ||||||
| 			     bytes); | 			     bytes); | ||||||
| 	/*
 |  | ||||||
| 	for(int w=0;w<recv_buf_extract[i].size();w++){ |  | ||||||
| 	  assert(recv_buf_extract[i].size()==buffer_size); |  | ||||||
| 	  assert(send_buf_extract[i].size()==buffer_size); |  | ||||||
| 	  std::cout << "SendRecv_Cshift_comms ["<<w<<" "<< dimension<<"] recv "<<recv_buf_extract[i][w]<<" send " << send_buf_extract[nbr_lane][w]  << cbmask<<std::endl; |  | ||||||
| 	} |  | ||||||
| 	*/	 |  | ||||||
| 	grid->Barrier(); | 	grid->Barrier(); | ||||||
| 	rpointers[i] = &recv_buf_extract[i][0]; | 	rpointers[i] = &recv_buf_extract[i][0]; | ||||||
|       } else {  |       } else {  | ||||||
| @@ -263,6 +257,8 @@ template<class vobj> void  Cshift_comms_simd(Lattice<vobj> &ret,const Lattice<vo | |||||||
|     Scatter_plane_merge(ret,rpointers,dimension,x,cbmask); |     Scatter_plane_merge(ret,rpointers,dimension,x,cbmask); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  } |  | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | NAMESPACE_END(Grid);  | ||||||
|  | 
 | ||||||
| #endif | #endif | ||||||
| @@ -1,4 +1,4 @@ | |||||||
|     /*************************************************************************************
 | /*************************************************************************************
 | ||||||
| 
 | 
 | ||||||
|     Grid physics library, www.github.com/paboyle/Grid  |     Grid physics library, www.github.com/paboyle/Grid  | ||||||
| 
 | 
 | ||||||
| @@ -23,17 +23,18 @@ Author: Peter Boyle <paboyle@ph.ed.ac.uk> | |||||||
|     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||||||
| 
 | 
 | ||||||
|     See the full license in the file "LICENSE" in the top level distribution directory |     See the full license in the file "LICENSE" in the top level distribution directory | ||||||
|     *************************************************************************************/ | *************************************************************************************/ | ||||||
|     /*  END LEGAL */ | /*  END LEGAL */ | ||||||
| #ifndef _GRID_CSHIFT_NONE_H_ | #ifndef _GRID_CSHIFT_NONE_H_ | ||||||
| #define _GRID_CSHIFT_NONE_H_ | #define _GRID_CSHIFT_NONE_H_ | ||||||
| namespace Grid { | NAMESPACE_BEGIN(Grid); | ||||||
| template<class vobj> Lattice<vobj> Cshift(const Lattice<vobj> &rhs,int dimension,int shift) | template<class vobj> Lattice<vobj> Cshift(const Lattice<vobj> &rhs,int dimension,int shift) | ||||||
| { | { | ||||||
|   Lattice<vobj> ret(rhs._grid); |   Lattice<vobj> ret(rhs.Grid()); | ||||||
|   ret.checkerboard = rhs._grid->CheckerBoardDestination(rhs.checkerboard,shift,dimension); |   ret.Checkerboard() = rhs.Grid()->CheckerBoardDestination(rhs.Checkerboard(),shift,dimension); | ||||||
|   Cshift_local(ret,rhs,dimension,shift); |   Cshift_local(ret,rhs,dimension,shift); | ||||||
|   return ret; |   return ret; | ||||||
| } | } | ||||||
| } | NAMESPACE_END(Grid); | ||||||
|  | 
 | ||||||
| #endif | #endif | ||||||
							
								
								
									
										18922
									
								
								Grid/json/json.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18922
									
								
								Grid/json/json.hpp
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -25,9 +25,22 @@ Author: Peter Boyle <paboyle@ph.ed.ac.uk> | |||||||
|     See the full license in the file "LICENSE" in the top level distribution directory |     See the full license in the file "LICENSE" in the top level distribution directory | ||||||
|     *************************************************************************************/ |     *************************************************************************************/ | ||||||
|     /*  END LEGAL */ |     /*  END LEGAL */ | ||||||
| #ifndef GRID_LATTICE_H | #pragma once | ||||||
| #define GRID_LATTICE_H |  | ||||||
| 
 |  | ||||||
| #include <Grid/lattice/Lattice_base.h> | #include <Grid/lattice/Lattice_base.h> | ||||||
|  | #include <Grid/lattice/Lattice_conformable.h> | ||||||
|  | #include <Grid/lattice/Lattice_ET.h> | ||||||
|  | #include <Grid/lattice/Lattice_arith.h> | ||||||
|  | #include <Grid/lattice/Lattice_trace.h> | ||||||
|  | #include <Grid/lattice/Lattice_transpose.h> | ||||||
|  | #include <Grid/lattice/Lattice_local.h> | ||||||
|  | #include <Grid/lattice/Lattice_reduction.h> | ||||||
|  | #include <Grid/lattice/Lattice_peekpoke.h> | ||||||
|  | #include <Grid/lattice/Lattice_reality.h> | ||||||
|  | #include <Grid/lattice/Lattice_comparison_utils.h> | ||||||
|  | #include <Grid/lattice/Lattice_comparison.h> | ||||||
|  | #include <Grid/lattice/Lattice_coordinate.h> | ||||||
|  | //#include <Grid/lattice/Lattice_where.h>
 | ||||||
|  | #include <Grid/lattice/Lattice_rng.h> | ||||||
|  | #include <Grid/lattice/Lattice_unary.h> | ||||||
|  | #include <Grid/lattice/Lattice_transfer.h> | ||||||
| 
 | 
 | ||||||
| #endif |  | ||||||
							
								
								
									
										407
									
								
								Grid/lattice/Lattice_ET.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										407
									
								
								Grid/lattice/Lattice_ET.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,407 @@ | |||||||
|  | /************************************************************************************* | ||||||
|  |  | ||||||
|  | Grid physics library, www.github.com/paboyle/Grid | ||||||
|  |  | ||||||
|  | Source file: ./lib/lattice/Lattice_ET.h | ||||||
|  |  | ||||||
|  | Copyright (C) 2015 | ||||||
|  |  | ||||||
|  | Author: Azusa Yamaguchi <ayamaguc@staffmail.ed.ac.uk> | ||||||
|  | Author: Peter Boyle <paboyle@ph.ed.ac.uk> | ||||||
|  | Author: neo <cossu@post.kek.jp> | ||||||
|  |  | ||||||
|  | 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_LATTICE_ET_H | ||||||
|  | #define GRID_LATTICE_ET_H | ||||||
|  |  | ||||||
|  | #include <iostream> | ||||||
|  | #include <tuple> | ||||||
|  | #include <typeinfo> | ||||||
|  | #include <vector> | ||||||
|  |  | ||||||
|  | NAMESPACE_BEGIN(Grid); | ||||||
|  |  | ||||||
|  | //////////////////////////////////////////////////// | ||||||
|  | // Predicated where support | ||||||
|  | //////////////////////////////////////////////////// | ||||||
|  | template <class iobj, class vobj, class robj> | ||||||
|  | accelerator_inline vobj predicatedWhere(const iobj &predicate, const vobj &iftrue, | ||||||
|  |                             const robj &iffalse) { | ||||||
|  |   typename std::remove_const<vobj>::type ret; | ||||||
|  |  | ||||||
|  |   typedef typename vobj::scalar_object scalar_object; | ||||||
|  |   typedef typename vobj::scalar_type scalar_type; | ||||||
|  |   typedef typename vobj::vector_type vector_type; | ||||||
|  |  | ||||||
|  |   const int Nsimd = vobj::vector_type::Nsimd(); | ||||||
|  |  | ||||||
|  |   ExtractBuffer<Integer> mask(Nsimd); | ||||||
|  |   ExtractBuffer<scalar_object> truevals(Nsimd); | ||||||
|  |   ExtractBuffer<scalar_object> falsevals(Nsimd); | ||||||
|  |  | ||||||
|  |   extract(iftrue, truevals); | ||||||
|  |   extract(iffalse, falsevals); | ||||||
|  |   extract<vInteger, Integer>(TensorRemove(predicate), mask); | ||||||
|  |  | ||||||
|  |   for (int s = 0; s < Nsimd; s++) { | ||||||
|  |     if (mask[s]) falsevals[s] = truevals[s]; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   merge(ret, falsevals); | ||||||
|  |   return ret; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | ///////////////////////////////////////////////////// | ||||||
|  | //Specialization of getVectorType for lattices | ||||||
|  | ///////////////////////////////////////////////////// | ||||||
|  | template<typename T> | ||||||
|  | struct getVectorType<Lattice<T> >{ | ||||||
|  |   typedef typename Lattice<T>::vector_object type; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | //////////////////////////////////////////// | ||||||
|  | //--  recursive evaluation of expressions; -- | ||||||
|  | // handle leaves of syntax tree | ||||||
|  | /////////////////////////////////////////////////// | ||||||
|  | template<class sobj> accelerator_inline  | ||||||
|  | sobj eval(const uint64_t ss, const sobj &arg) | ||||||
|  | { | ||||||
|  |   return arg; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | template <class lobj> accelerator_inline  | ||||||
|  | const lobj & eval(const uint64_t ss, const LatticeView<lobj> &arg)  | ||||||
|  | { | ||||||
|  |   return arg[ss]; | ||||||
|  | } | ||||||
|  | template <class lobj> accelerator_inline  | ||||||
|  | const lobj & eval(const uint64_t ss, const Lattice<lobj> &arg)  | ||||||
|  | { | ||||||
|  |   auto view = arg.View(); | ||||||
|  |   return view[ss]; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /////////////////////////////////////////////////// | ||||||
|  | // handle nodes in syntax tree- eval one operand | ||||||
|  | /////////////////////////////////////////////////// | ||||||
|  | template <typename Op, typename T1> accelerator_inline  | ||||||
|  | auto eval(const uint64_t ss, const LatticeUnaryExpression<Op, T1> &expr)   | ||||||
|  |   -> decltype(expr.op.func( eval(ss, expr.arg1))) | ||||||
|  | { | ||||||
|  |   return expr.op.func( eval(ss, expr.arg1) ); | ||||||
|  | } | ||||||
|  | /////////////////////// | ||||||
|  | // eval two operands | ||||||
|  | /////////////////////// | ||||||
|  | template <typename Op, typename T1, typename T2> accelerator_inline | ||||||
|  | auto eval(const uint64_t ss, const LatticeBinaryExpression<Op, T1, T2> &expr)   | ||||||
|  |   -> decltype(expr.op.func( eval(ss,expr.arg1),eval(ss,expr.arg2))) | ||||||
|  | { | ||||||
|  |   return expr.op.func( eval(ss,expr.arg1), eval(ss,expr.arg2) ); | ||||||
|  | } | ||||||
|  | /////////////////////// | ||||||
|  | // eval three operands | ||||||
|  | /////////////////////// | ||||||
|  | template <typename Op, typename T1, typename T2, typename T3> accelerator_inline | ||||||
|  | auto eval(const uint64_t ss, const LatticeTrinaryExpression<Op, T1, T2, T3> &expr)   | ||||||
|  |   -> decltype(expr.op.func(eval(ss, expr.arg1), eval(ss, expr.arg2), eval(ss, expr.arg3))) | ||||||
|  | { | ||||||
|  |   return expr.op.func(eval(ss, expr.arg1), eval(ss, expr.arg2), eval(ss, expr.arg3)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | ////////////////////////////////////////////////////////////////////////// | ||||||
|  | // Obtain the grid from an expression, ensuring conformable. This must follow a | ||||||
|  | // tree recursion; must retain grid pointer in the LatticeView class which sucks | ||||||
|  | // Use a different method, and make it void *. | ||||||
|  | // Perhaps a conformable method. | ||||||
|  | ////////////////////////////////////////////////////////////////////////// | ||||||
|  | template <class T1,typename std::enable_if<is_lattice<T1>::value, T1>::type * = nullptr> | ||||||
|  | accelerator_inline void GridFromExpression(GridBase *&grid, const T1 &lat)  // Lattice leaf | ||||||
|  | { | ||||||
|  |   lat.Conformable(grid); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | template <class T1,typename std::enable_if<!is_lattice<T1>::value, T1>::type * = nullptr> | ||||||
|  | accelerator_inline  | ||||||
|  | void GridFromExpression(GridBase *&grid,const T1 ¬lat)  // non-lattice leaf | ||||||
|  | {} | ||||||
|  |  | ||||||
|  | template <typename Op, typename T1> | ||||||
|  | accelerator_inline  | ||||||
|  | void GridFromExpression(GridBase *&grid,const LatticeUnaryExpression<Op, T1> &expr)  | ||||||
|  | { | ||||||
|  |   GridFromExpression(grid, expr.arg1);  // recurse | ||||||
|  | } | ||||||
|  |  | ||||||
|  | template <typename Op, typename T1, typename T2> | ||||||
|  | accelerator_inline  | ||||||
|  | void GridFromExpression(GridBase *&grid, const LatticeBinaryExpression<Op, T1, T2> &expr)  | ||||||
|  | { | ||||||
|  |   GridFromExpression(grid, expr.arg1);  // recurse | ||||||
|  |   GridFromExpression(grid, expr.arg2); | ||||||
|  | } | ||||||
|  | template <typename Op, typename T1, typename T2, typename T3> | ||||||
|  | accelerator_inline  | ||||||
|  | void GridFromExpression(GridBase *&grid, const LatticeTrinaryExpression<Op, T1, T2, T3> &expr)  | ||||||
|  | { | ||||||
|  |   GridFromExpression(grid, expr.arg1);  // recurse | ||||||
|  |   GridFromExpression(grid, expr.arg2);  // recurse | ||||||
|  |   GridFromExpression(grid, expr.arg3);  // recurse | ||||||
|  | } | ||||||
|  |  | ||||||
|  | ////////////////////////////////////////////////////////////////////////// | ||||||
|  | // Obtain the CB from an expression, ensuring conformable. This must follow a | ||||||
|  | // tree recursion | ||||||
|  | ////////////////////////////////////////////////////////////////////////// | ||||||
|  | template <class T1,typename std::enable_if<is_lattice<T1>::value, T1>::type * = nullptr> | ||||||
|  | inline void CBFromExpression(int &cb, const T1 &lat)  // Lattice leaf | ||||||
|  | { | ||||||
|  |   if ((cb == Odd) || (cb == Even)) { | ||||||
|  |     assert(cb == lat.Checkerboard()); | ||||||
|  |   } | ||||||
|  |   cb = lat.Checkerboard(); | ||||||
|  | } | ||||||
|  | template <class T1,typename std::enable_if<!is_lattice<T1>::value, T1>::type * = nullptr> | ||||||
|  | inline void CBFromExpression(int &cb, const T1 ¬lat)  // non-lattice leaf | ||||||
|  | { | ||||||
|  | } | ||||||
|  |  | ||||||
|  | template <typename Op, typename T1> inline  | ||||||
|  | void CBFromExpression(int &cb,const LatticeUnaryExpression<Op, T1> &expr)  | ||||||
|  | { | ||||||
|  |   CBFromExpression(cb, expr.arg1);  // recurse AST | ||||||
|  | } | ||||||
|  |  | ||||||
|  | template <typename Op, typename T1, typename T2> inline  | ||||||
|  | void CBFromExpression(int &cb,const LatticeBinaryExpression<Op, T1, T2> &expr)  | ||||||
|  | { | ||||||
|  |   CBFromExpression(cb, expr.arg1);  // recurse AST | ||||||
|  |   CBFromExpression(cb, expr.arg2);  // recurse AST | ||||||
|  | } | ||||||
|  | template <typename Op, typename T1, typename T2, typename T3> | ||||||
|  | inline void CBFromExpression(int &cb, const LatticeTrinaryExpression<Op, T1, T2, T3> &expr)  | ||||||
|  | { | ||||||
|  |   CBFromExpression(cb, expr.arg1);  // recurse AST | ||||||
|  |   CBFromExpression(cb, expr.arg2);  // recurse AST | ||||||
|  |   CBFromExpression(cb, expr.arg3);  // recurse AST | ||||||
|  | } | ||||||
|  |  | ||||||
|  | //////////////////////////////////////////// | ||||||
|  | // Unary operators and funcs | ||||||
|  | //////////////////////////////////////////// | ||||||
|  | #define GridUnopClass(name, ret)					\ | ||||||
|  |   template <class arg>							\ | ||||||
|  |   struct name {								\ | ||||||
|  |     static auto accelerator_inline func(const arg a) -> decltype(ret) { return ret; } \ | ||||||
|  |   }; | ||||||
|  |  | ||||||
|  | GridUnopClass(UnarySub, -a); | ||||||
|  | GridUnopClass(UnaryNot, Not(a)); | ||||||
|  | GridUnopClass(UnaryAdj, adj(a)); | ||||||
|  | GridUnopClass(UnaryConj, conjugate(a)); | ||||||
|  | GridUnopClass(UnaryTrace, trace(a)); | ||||||
|  | GridUnopClass(UnaryTranspose, transpose(a)); | ||||||
|  | GridUnopClass(UnaryTa, Ta(a)); | ||||||
|  | GridUnopClass(UnaryProjectOnGroup, ProjectOnGroup(a)); | ||||||
|  | GridUnopClass(UnaryReal, real(a)); | ||||||
|  | GridUnopClass(UnaryImag, imag(a)); | ||||||
|  | GridUnopClass(UnaryToReal, toReal(a)); | ||||||
|  | GridUnopClass(UnaryToComplex, toComplex(a)); | ||||||
|  | GridUnopClass(UnaryTimesI, timesI(a)); | ||||||
|  | GridUnopClass(UnaryTimesMinusI, timesMinusI(a)); | ||||||
|  | GridUnopClass(UnaryAbs, abs(a)); | ||||||
|  | GridUnopClass(UnarySqrt, sqrt(a)); | ||||||
|  | GridUnopClass(UnaryRsqrt, rsqrt(a)); | ||||||
|  | GridUnopClass(UnarySin, sin(a)); | ||||||
|  | GridUnopClass(UnaryCos, cos(a)); | ||||||
|  | GridUnopClass(UnaryAsin, asin(a)); | ||||||
|  | GridUnopClass(UnaryAcos, acos(a)); | ||||||
|  | GridUnopClass(UnaryLog, log(a)); | ||||||
|  | GridUnopClass(UnaryExp, exp(a)); | ||||||
|  |  | ||||||
|  | //////////////////////////////////////////// | ||||||
|  | // Binary operators | ||||||
|  | //////////////////////////////////////////// | ||||||
|  | #define GridBinOpClass(name, combination)			\ | ||||||
|  |   template <class left, class right>				\ | ||||||
|  |   struct name {							\ | ||||||
|  |     static auto accelerator_inline				\ | ||||||
|  |     func(const left &lhs, const right &rhs)			\ | ||||||
|  |       -> decltype(combination) const				\ | ||||||
|  |     {								\ | ||||||
|  |       return combination;					\ | ||||||
|  |     }								\ | ||||||
|  |   }; | ||||||
|  |  | ||||||
|  | GridBinOpClass(BinaryAdd, lhs + rhs); | ||||||
|  | GridBinOpClass(BinarySub, lhs - rhs); | ||||||
|  | GridBinOpClass(BinaryMul, lhs *rhs); | ||||||
|  | GridBinOpClass(BinaryDiv, lhs /rhs); | ||||||
|  | GridBinOpClass(BinaryAnd, lhs &rhs); | ||||||
|  | GridBinOpClass(BinaryOr, lhs | rhs); | ||||||
|  | GridBinOpClass(BinaryAndAnd, lhs &&rhs); | ||||||
|  | GridBinOpClass(BinaryOrOr, lhs || rhs); | ||||||
|  |  | ||||||
|  | //////////////////////////////////////////////////// | ||||||
|  | // Trinary conditional op | ||||||
|  | //////////////////////////////////////////////////// | ||||||
|  | #define GridTrinOpClass(name, combination)				\ | ||||||
|  |   template <class predicate, class left, class right>			\ | ||||||
|  |   struct name {								\ | ||||||
|  |     static auto accelerator_inline					\ | ||||||
|  |     func(const predicate &pred, const left &lhs, const right &rhs)	\ | ||||||
|  |       -> decltype(combination) const					\ | ||||||
|  |     {									\ | ||||||
|  |       return combination;						\ | ||||||
|  |     }									\ | ||||||
|  |   }; | ||||||
|  |  | ||||||
|  | GridTrinOpClass(TrinaryWhere, | ||||||
|  | 		(predicatedWhere<predicate,  | ||||||
|  | 		 typename std::remove_reference<left>::type, | ||||||
|  | 		 typename std::remove_reference<right>::type>(pred, lhs,rhs))); | ||||||
|  |  | ||||||
|  | //////////////////////////////////////////// | ||||||
|  | // Operator syntactical glue | ||||||
|  | //////////////////////////////////////////// | ||||||
|  |  | ||||||
|  | #define GRID_UNOP(name)   name<decltype(eval(0, arg))> | ||||||
|  | #define GRID_BINOP(name)  name<decltype(eval(0, lhs)), decltype(eval(0, rhs))> | ||||||
|  | #define GRID_TRINOP(name) name<decltype(eval(0, pred)), decltype(eval(0, lhs)), decltype(eval(0, rhs))> | ||||||
|  |  | ||||||
|  | #define GRID_DEF_UNOP(op, name)						\ | ||||||
|  |   template <typename T1, typename std::enable_if<is_lattice<T1>::value||is_lattice_expr<T1>::value,T1>::type * = nullptr> \ | ||||||
|  |   inline auto op(const T1 &arg) ->decltype(LatticeUnaryExpression<GRID_UNOP(name),T1>(GRID_UNOP(name)(), arg)) \ | ||||||
|  |   {									\ | ||||||
|  |     return     LatticeUnaryExpression<GRID_UNOP(name),T1>(GRID_UNOP(name)(), arg); \ | ||||||
|  |   } | ||||||
|  |  | ||||||
|  | #define GRID_BINOP_LEFT(op, name)					\ | ||||||
|  |   template <typename T1, typename T2,					\ | ||||||
|  |             typename std::enable_if<is_lattice<T1>::value||is_lattice_expr<T1>::value,T1>::type * = nullptr> \ | ||||||
|  |   inline auto op(const T1 &lhs, const T2 &rhs)				\ | ||||||
|  |     ->decltype(LatticeBinaryExpression<GRID_BINOP(name),T1,T2>(GRID_BINOP(name)(),lhs,rhs)) \ | ||||||
|  |   {									\ | ||||||
|  |     return     LatticeBinaryExpression<GRID_BINOP(name),T1,T2>(GRID_BINOP(name)(),lhs,rhs);\ | ||||||
|  |   } | ||||||
|  |  | ||||||
|  | #define GRID_BINOP_RIGHT(op, name)					\ | ||||||
|  |   template <typename T1, typename T2,					\ | ||||||
|  |             typename std::enable_if<!is_lattice<T1>::value&&!is_lattice_expr<T1>::value,T1>::type * = nullptr, \ | ||||||
|  |             typename std::enable_if< is_lattice<T2>::value|| is_lattice_expr<T2>::value,T2>::type * = nullptr> \ | ||||||
|  |   inline auto op(const T1 &lhs, const T2 &rhs)				\ | ||||||
|  |     ->decltype(LatticeBinaryExpression<GRID_BINOP(name),T1,T2>(GRID_BINOP(name)(),lhs, rhs)) \ | ||||||
|  |   {									\ | ||||||
|  |     return     LatticeBinaryExpression<GRID_BINOP(name),T1,T2>(GRID_BINOP(name)(),lhs, rhs); \ | ||||||
|  |   } | ||||||
|  |  | ||||||
|  | #define GRID_DEF_BINOP(op, name)		\ | ||||||
|  |   GRID_BINOP_LEFT(op, name);			\ | ||||||
|  |   GRID_BINOP_RIGHT(op, name); | ||||||
|  |  | ||||||
|  | #define GRID_DEF_TRINOP(op, name)					\ | ||||||
|  |   template <typename T1, typename T2, typename T3>			\ | ||||||
|  |   inline auto op(const T1 &pred, const T2 &lhs, const T3 &rhs)		\ | ||||||
|  |     ->decltype(LatticeTrinaryExpression<GRID_TRINOP(name),T1,T2,T3>(GRID_TRINOP(name)(),pred, lhs, rhs)) \ | ||||||
|  |   {									\ | ||||||
|  |     return LatticeTrinaryExpression<GRID_TRINOP(name),T1,T2,T3>(GRID_TRINOP(name)(),pred, lhs, rhs); \ | ||||||
|  |   } | ||||||
|  |  | ||||||
|  | //////////////////////// | ||||||
|  | // Operator definitions | ||||||
|  | //////////////////////// | ||||||
|  | GRID_DEF_UNOP(operator-, UnarySub); | ||||||
|  | GRID_DEF_UNOP(Not, UnaryNot); | ||||||
|  | GRID_DEF_UNOP(operator!, UnaryNot); | ||||||
|  | GRID_DEF_UNOP(adj, UnaryAdj); | ||||||
|  | GRID_DEF_UNOP(conjugate, UnaryConj); | ||||||
|  | GRID_DEF_UNOP(trace, UnaryTrace); | ||||||
|  | GRID_DEF_UNOP(transpose, UnaryTranspose); | ||||||
|  | GRID_DEF_UNOP(Ta, UnaryTa); | ||||||
|  | GRID_DEF_UNOP(ProjectOnGroup, UnaryProjectOnGroup); | ||||||
|  | GRID_DEF_UNOP(real, UnaryReal); | ||||||
|  | GRID_DEF_UNOP(imag, UnaryImag); | ||||||
|  | GRID_DEF_UNOP(toReal, UnaryToReal); | ||||||
|  | GRID_DEF_UNOP(toComplex, UnaryToComplex); | ||||||
|  | GRID_DEF_UNOP(timesI, UnaryTimesI); | ||||||
|  | GRID_DEF_UNOP(timesMinusI, UnaryTimesMinusI); | ||||||
|  | GRID_DEF_UNOP(abs, UnaryAbs);  // abs overloaded in cmath C++98; DON'T do the | ||||||
|  |                                // abs-fabs-dabs-labs thing | ||||||
|  | GRID_DEF_UNOP(sqrt, UnarySqrt); | ||||||
|  | GRID_DEF_UNOP(rsqrt, UnaryRsqrt); | ||||||
|  | GRID_DEF_UNOP(sin, UnarySin); | ||||||
|  | GRID_DEF_UNOP(cos, UnaryCos); | ||||||
|  | GRID_DEF_UNOP(asin, UnaryAsin); | ||||||
|  | GRID_DEF_UNOP(acos, UnaryAcos); | ||||||
|  | GRID_DEF_UNOP(log, UnaryLog); | ||||||
|  | GRID_DEF_UNOP(exp, UnaryExp); | ||||||
|  |  | ||||||
|  | GRID_DEF_BINOP(operator+, BinaryAdd); | ||||||
|  | GRID_DEF_BINOP(operator-, BinarySub); | ||||||
|  | GRID_DEF_BINOP(operator*, BinaryMul); | ||||||
|  | GRID_DEF_BINOP(operator/, BinaryDiv); | ||||||
|  |  | ||||||
|  | GRID_DEF_BINOP(operator&, BinaryAnd); | ||||||
|  | GRID_DEF_BINOP(operator|, BinaryOr); | ||||||
|  | GRID_DEF_BINOP(operator&&, BinaryAndAnd); | ||||||
|  | GRID_DEF_BINOP(operator||, BinaryOrOr); | ||||||
|  |  | ||||||
|  | GRID_DEF_TRINOP(where, TrinaryWhere); | ||||||
|  |  | ||||||
|  | ///////////////////////////////////////////////////////////// | ||||||
|  | // Closure convenience to force expression to evaluate | ||||||
|  | ///////////////////////////////////////////////////////////// | ||||||
|  | template <class Op, class T1> | ||||||
|  | auto closure(const LatticeUnaryExpression<Op, T1> &expr) | ||||||
|  |   -> Lattice<decltype(expr.op.func(eval(0, expr.arg1)))>  | ||||||
|  | { | ||||||
|  |   Lattice<decltype(expr.op.func(eval(0, expr.arg1)))> ret(expr); | ||||||
|  |   return ret; | ||||||
|  | } | ||||||
|  | template <class Op, class T1, class T2> | ||||||
|  | auto closure(const LatticeBinaryExpression<Op, T1, T2> &expr) | ||||||
|  |   -> Lattice<decltype(expr.op.func(eval(0, expr.arg1),eval(0, expr.arg2)))>  | ||||||
|  | { | ||||||
|  |   Lattice<decltype(expr.op.func(eval(0, expr.arg1),eval(0, expr.arg2)))> ret(expr); | ||||||
|  |   return ret; | ||||||
|  | } | ||||||
|  | template <class Op, class T1, class T2, class T3> | ||||||
|  | auto closure(const LatticeTrinaryExpression<Op, T1, T2, T3> &expr) | ||||||
|  |   -> Lattice<decltype(expr.op.func(eval(0, expr.arg1), | ||||||
|  | 				   eval(0, expr.arg2), | ||||||
|  | 				   eval(0, expr.arg3)))>  | ||||||
|  | { | ||||||
|  |   Lattice<decltype(expr.op.func(eval(0, expr.arg1), | ||||||
|  | 				eval(0, expr.arg2), | ||||||
|  | 				eval(0, expr.arg3)))>  ret(expr); | ||||||
|  |   return ret; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #undef GRID_UNOP | ||||||
|  | #undef GRID_BINOP | ||||||
|  | #undef GRID_TRINOP | ||||||
|  |  | ||||||
|  | #undef GRID_DEF_UNOP | ||||||
|  | #undef GRID_DEF_BINOP | ||||||
|  | #undef GRID_DEF_TRINOP | ||||||
|  |  | ||||||
|  | NAMESPACE_END(Grid); | ||||||
|  |  | ||||||
|  | #endif | ||||||
							
								
								
									
										257
									
								
								Grid/lattice/Lattice_arith.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										257
									
								
								Grid/lattice/Lattice_arith.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,257 @@ | |||||||
|  | /************************************************************************************* | ||||||
|  |  | ||||||
|  |     Grid physics library, www.github.com/paboyle/Grid  | ||||||
|  |  | ||||||
|  |     Source file: ./lib/lattice/Lattice_arith.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_LATTICE_ARITH_H | ||||||
|  | #define GRID_LATTICE_ARITH_H | ||||||
|  |  | ||||||
|  | NAMESPACE_BEGIN(Grid); | ||||||
|  |  | ||||||
|  | ////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  | //  avoid copy back routines for mult, mac, sub, add | ||||||
|  | ////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  | template<class obj1,class obj2,class obj3> inline | ||||||
|  | void mult(Lattice<obj1> &ret,const Lattice<obj2> &lhs,const Lattice<obj3> &rhs){ | ||||||
|  |   ret.Checkerboard() = lhs.Checkerboard(); | ||||||
|  |   auto ret_v = ret.View(); | ||||||
|  |   auto lhs_v = lhs.View(); | ||||||
|  |   auto rhs_v = rhs.View(); | ||||||
|  |   conformable(ret,rhs); | ||||||
|  |   conformable(lhs,rhs); | ||||||
|  |   accelerator_for(ss,lhs_v.size(),obj1::Nsimd(),{ | ||||||
|  |     decltype(coalescedRead(obj1())) tmp; | ||||||
|  |     auto lhs_t = lhs_v(ss); | ||||||
|  |     auto rhs_t = rhs_v(ss); | ||||||
|  |     mult(&tmp,&lhs_t,&rhs_t); | ||||||
|  |     coalescedWrite(ret_v[ss],tmp); | ||||||
|  |   }); | ||||||
|  | } | ||||||
|  |    | ||||||
|  | template<class obj1,class obj2,class obj3> inline | ||||||
|  | void mac(Lattice<obj1> &ret,const Lattice<obj2> &lhs,const Lattice<obj3> &rhs){ | ||||||
|  |   ret.Checkerboard() = lhs.Checkerboard(); | ||||||
|  |   conformable(ret,rhs); | ||||||
|  |   conformable(lhs,rhs); | ||||||
|  |   auto ret_v = ret.View(); | ||||||
|  |   auto lhs_v = lhs.View(); | ||||||
|  |   auto rhs_v = rhs.View(); | ||||||
|  |   accelerator_for(ss,lhs_v.size(),obj1::Nsimd(),{ | ||||||
|  |     decltype(coalescedRead(obj1())) tmp; | ||||||
|  |     auto lhs_t=lhs_v(ss); | ||||||
|  |     auto rhs_t=rhs_v(ss); | ||||||
|  |     mac(&tmp,&lhs_t,&rhs_t); | ||||||
|  |     coalescedWrite(ret_v[ss],tmp); | ||||||
|  |   }); | ||||||
|  | } | ||||||
|  |    | ||||||
|  | template<class obj1,class obj2,class obj3> inline | ||||||
|  | void sub(Lattice<obj1> &ret,const Lattice<obj2> &lhs,const Lattice<obj3> &rhs){ | ||||||
|  |   ret.Checkerboard() = lhs.Checkerboard(); | ||||||
|  |   conformable(ret,rhs); | ||||||
|  |   conformable(lhs,rhs); | ||||||
|  |   auto ret_v = ret.View(); | ||||||
|  |   auto lhs_v = lhs.View(); | ||||||
|  |   auto rhs_v = rhs.View(); | ||||||
|  |   accelerator_for(ss,lhs_v.size(),obj1::Nsimd(),{ | ||||||
|  |     decltype(coalescedRead(obj1())) tmp; | ||||||
|  |     auto lhs_t=lhs_v(ss); | ||||||
|  |     auto rhs_t=rhs_v(ss); | ||||||
|  |     sub(&tmp,&lhs_t,&rhs_t); | ||||||
|  |     coalescedWrite(ret_v[ss],tmp); | ||||||
|  |   }); | ||||||
|  | } | ||||||
|  | template<class obj1,class obj2,class obj3> inline | ||||||
|  | void add(Lattice<obj1> &ret,const Lattice<obj2> &lhs,const Lattice<obj3> &rhs){ | ||||||
|  |   ret.Checkerboard() = lhs.Checkerboard(); | ||||||
|  |   conformable(ret,rhs); | ||||||
|  |   conformable(lhs,rhs); | ||||||
|  |   auto ret_v = ret.View(); | ||||||
|  |   auto lhs_v = lhs.View(); | ||||||
|  |   auto rhs_v = rhs.View(); | ||||||
|  |   accelerator_for(ss,lhs_v.size(),obj1::Nsimd(),{ | ||||||
|  |     decltype(coalescedRead(obj1())) tmp; | ||||||
|  |     auto lhs_t=lhs_v(ss); | ||||||
|  |     auto rhs_t=rhs_v(ss); | ||||||
|  |     add(&tmp,&lhs_t,&rhs_t); | ||||||
|  |     coalescedWrite(ret_v[ss],tmp); | ||||||
|  |   }); | ||||||
|  | } | ||||||
|  |    | ||||||
|  | ////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  | //  avoid copy back routines for mult, mac, sub, add | ||||||
|  | ////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  | template<class obj1,class obj2,class obj3> inline | ||||||
|  | void mult(Lattice<obj1> &ret,const Lattice<obj2> &lhs,const obj3 &rhs){ | ||||||
|  |   ret.Checkerboard() = lhs.Checkerboard(); | ||||||
|  |   conformable(lhs,ret); | ||||||
|  |   auto ret_v = ret.View(); | ||||||
|  |   auto lhs_v = lhs.View(); | ||||||
|  |   accelerator_for(ss,lhs_v.size(),obj1::Nsimd(),{ | ||||||
|  |     decltype(coalescedRead(obj1())) tmp; | ||||||
|  |     mult(&tmp,&lhs_v(ss),&rhs); | ||||||
|  |     coalescedWrite(ret_v[ss],tmp); | ||||||
|  |   }); | ||||||
|  | } | ||||||
|  |    | ||||||
|  | template<class obj1,class obj2,class obj3> inline | ||||||
|  | void mac(Lattice<obj1> &ret,const Lattice<obj2> &lhs,const obj3 &rhs){ | ||||||
|  |   ret.Checkerboard() = lhs.Checkerboard(); | ||||||
|  |   conformable(ret,lhs); | ||||||
|  |   auto ret_v = ret.View(); | ||||||
|  |   auto lhs_v = lhs.View(); | ||||||
|  |   accelerator_for(ss,lhs_v.size(),obj1::Nsimd(),{ | ||||||
|  |     decltype(coalescedRead(obj1())) tmp; | ||||||
|  |     auto lhs_t=lhs_v(ss); | ||||||
|  |     mac(&tmp,&lhs_t,&rhs); | ||||||
|  |     coalescedWrite(ret_v[ss],tmp); | ||||||
|  |   }); | ||||||
|  | } | ||||||
|  |    | ||||||
|  | template<class obj1,class obj2,class obj3> inline | ||||||
|  | void sub(Lattice<obj1> &ret,const Lattice<obj2> &lhs,const obj3 &rhs){ | ||||||
|  |   ret.Checkerboard() = lhs.Checkerboard(); | ||||||
|  |   conformable(ret,lhs); | ||||||
|  |   auto ret_v = ret.View(); | ||||||
|  |   auto lhs_v = lhs.View(); | ||||||
|  |   accelerator_for(ss,lhs_v.size(),obj1::Nsimd(),{ | ||||||
|  |     decltype(coalescedRead(obj1())) tmp; | ||||||
|  |     auto lhs_t=lhs_v(ss); | ||||||
|  |     sub(&tmp,&lhs_t,&rhs); | ||||||
|  |     coalescedWrite(ret_v[ss],tmp); | ||||||
|  |   }); | ||||||
|  | } | ||||||
|  | template<class obj1,class obj2,class obj3> inline | ||||||
|  | void add(Lattice<obj1> &ret,const Lattice<obj2> &lhs,const obj3 &rhs){ | ||||||
|  |   ret.Checkerboard() = lhs.Checkerboard(); | ||||||
|  |   conformable(lhs,ret); | ||||||
|  |   auto ret_v = ret.View(); | ||||||
|  |   auto lhs_v = lhs.View(); | ||||||
|  |   accelerator_for(ss,lhs_v.size(),obj1::Nsimd(),{ | ||||||
|  |     decltype(coalescedRead(obj1())) tmp; | ||||||
|  |     auto lhs_t=lhs_v(ss); | ||||||
|  |     add(&tmp,&lhs_t,&rhs); | ||||||
|  |     coalescedWrite(ret_v[ss],tmp); | ||||||
|  |   }); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | ////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  | //  avoid copy back routines for mult, mac, sub, add | ||||||
|  | ////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  | template<class obj1,class obj2,class obj3> inline | ||||||
|  | void mult(Lattice<obj1> &ret,const obj2 &lhs,const Lattice<obj3> &rhs){ | ||||||
|  |   ret.Checkerboard() = rhs.Checkerboard(); | ||||||
|  |   conformable(ret,rhs); | ||||||
|  |   auto ret_v = ret.View(); | ||||||
|  |   auto rhs_v = lhs.View(); | ||||||
|  |   accelerator_for(ss,rhs_v.size(),obj1::Nsimd(),{ | ||||||
|  |     decltype(coalescedRead(obj1())) tmp; | ||||||
|  |     auto rhs_t=rhs_v(ss); | ||||||
|  |     mult(&tmp,&lhs,&rhs_t); | ||||||
|  |     coalescedWrite(ret_v[ss],tmp); | ||||||
|  |   }); | ||||||
|  | } | ||||||
|  |    | ||||||
|  | template<class obj1,class obj2,class obj3> inline | ||||||
|  | void mac(Lattice<obj1> &ret,const obj2 &lhs,const Lattice<obj3> &rhs){ | ||||||
|  |   ret.Checkerboard() = rhs.Checkerboard(); | ||||||
|  |   conformable(ret,rhs); | ||||||
|  |   auto ret_v = ret.View(); | ||||||
|  |   auto rhs_v = lhs.View(); | ||||||
|  |   accelerator_for(ss,rhs_v.size(),obj1::Nsimd(),{ | ||||||
|  |     decltype(coalescedRead(obj1())) tmp; | ||||||
|  |     auto rhs_t=rhs_v(ss); | ||||||
|  |     mac(&tmp,&lhs,&rhs_t); | ||||||
|  |     coalescedWrite(ret_v[ss],tmp); | ||||||
|  |   }); | ||||||
|  | } | ||||||
|  |    | ||||||
|  | template<class obj1,class obj2,class obj3> inline | ||||||
|  | void sub(Lattice<obj1> &ret,const obj2 &lhs,const Lattice<obj3> &rhs){ | ||||||
|  |   ret.Checkerboard() = rhs.Checkerboard(); | ||||||
|  |   conformable(ret,rhs); | ||||||
|  |   auto ret_v = ret.View(); | ||||||
|  |   auto rhs_v = lhs.View(); | ||||||
|  |   accelerator_for(ss,rhs_v.size(),obj1::Nsimd(),{ | ||||||
|  |     decltype(coalescedRead(obj1())) tmp; | ||||||
|  |     auto rhs_t=rhs_v(ss); | ||||||
|  |     sub(&tmp,&lhs,&rhs_t); | ||||||
|  |     coalescedWrite(ret_v[ss],tmp); | ||||||
|  |   }); | ||||||
|  | } | ||||||
|  | template<class obj1,class obj2,class obj3> inline | ||||||
|  | void add(Lattice<obj1> &ret,const obj2 &lhs,const Lattice<obj3> &rhs){ | ||||||
|  |   ret.Checkerboard() = rhs.Checkerboard(); | ||||||
|  |   conformable(ret,rhs); | ||||||
|  |   auto ret_v = ret.View(); | ||||||
|  |   auto rhs_v = lhs.View(); | ||||||
|  |   accelerator_for(ss,rhs_v.size(),obj1::Nsimd(),{ | ||||||
|  |     decltype(coalescedRead(obj1())) tmp; | ||||||
|  |     auto rhs_t=rhs_v(ss); | ||||||
|  |     add(&tmp,&lhs,&rhs_t); | ||||||
|  |     coalescedWrite(ret_v[ss],tmp); | ||||||
|  |   }); | ||||||
|  | } | ||||||
|  |    | ||||||
|  | template<class sobj,class vobj> inline | ||||||
|  | void axpy(Lattice<vobj> &ret,sobj a,const Lattice<vobj> &x,const Lattice<vobj> &y){ | ||||||
|  |   ret.Checkerboard() = x.Checkerboard(); | ||||||
|  |   conformable(ret,x); | ||||||
|  |   conformable(x,y); | ||||||
|  |   auto ret_v = ret.View(); | ||||||
|  |   auto x_v = x.View(); | ||||||
|  |   auto y_v = y.View(); | ||||||
|  |   accelerator_for(ss,x_v.size(),vobj::Nsimd(),{ | ||||||
|  |     auto tmp = a*x_v(ss)+y_v(ss); | ||||||
|  |     coalescedWrite(ret_v[ss],tmp); | ||||||
|  |   }); | ||||||
|  | } | ||||||
|  | template<class sobj,class vobj> inline | ||||||
|  | void axpby(Lattice<vobj> &ret,sobj a,sobj b,const Lattice<vobj> &x,const Lattice<vobj> &y){ | ||||||
|  |   ret.Checkerboard() = x.Checkerboard(); | ||||||
|  |   conformable(ret,x); | ||||||
|  |   conformable(x,y); | ||||||
|  |   auto ret_v = ret.View(); | ||||||
|  |   auto x_v = x.View(); | ||||||
|  |   auto y_v = y.View(); | ||||||
|  |   accelerator_for(ss,x_v.size(),vobj::Nsimd(),{ | ||||||
|  |     auto tmp = a*x_v(ss)+b*y_v(ss); | ||||||
|  |     coalescedWrite(ret_v[ss],tmp); | ||||||
|  |   }); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | template<class sobj,class vobj> inline | ||||||
|  | RealD axpy_norm(Lattice<vobj> &ret,sobj a,const Lattice<vobj> &x,const Lattice<vobj> &y) | ||||||
|  | { | ||||||
|  |     return axpy_norm_fast(ret,a,x,y); | ||||||
|  | } | ||||||
|  | template<class sobj,class vobj> inline | ||||||
|  | RealD axpby_norm(Lattice<vobj> &ret,sobj a,sobj b,const Lattice<vobj> &x,const Lattice<vobj> &y) | ||||||
|  | { | ||||||
|  |     return axpby_norm_fast(ret,a,b,x,y); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | NAMESPACE_END(Grid); | ||||||
|  | #endif | ||||||
							
								
								
									
										466
									
								
								Grid/lattice/Lattice_base.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										466
									
								
								Grid/lattice/Lattice_base.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,466 @@ | |||||||
|  | /************************************************************************************* | ||||||
|  |  | ||||||
|  | Grid physics library, www.github.com/paboyle/Grid | ||||||
|  |  | ||||||
|  | Source file: ./lib/lattice/Lattice_base.h | ||||||
|  |  | ||||||
|  | Copyright (C) 2015 | ||||||
|  |  | ||||||
|  | Author: Azusa Yamaguchi <ayamaguc@staffmail.ed.ac.uk> | ||||||
|  | Author: Peter Boyle <paboyle@ph.ed.ac.uk> | ||||||
|  | Author: paboyle <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 */ | ||||||
|  | #pragma once  | ||||||
|  |  | ||||||
|  | #define STREAMING_STORES | ||||||
|  |  | ||||||
|  | NAMESPACE_BEGIN(Grid); | ||||||
|  |  | ||||||
|  | extern int GridCshiftPermuteMap[4][16]; | ||||||
|  |  | ||||||
|  | /////////////////////////////////////////////////////////////////// | ||||||
|  | // Base class which can be used by traits to pick up behaviour | ||||||
|  | /////////////////////////////////////////////////////////////////// | ||||||
|  | class LatticeBase {}; | ||||||
|  |  | ||||||
|  | ///////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  | // Conformable checks; same instance of Grid required | ||||||
|  | ///////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  | void accelerator_inline conformable(GridBase *lhs,GridBase *rhs) | ||||||
|  | { | ||||||
|  |   assert(lhs == rhs); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | //////////////////////////////////////////////////////////////////////////// | ||||||
|  | // Minimal base class containing only data valid to access from accelerator | ||||||
|  | // _odata will be a managed pointer in CUDA | ||||||
|  | //////////////////////////////////////////////////////////////////////////// | ||||||
|  | // Force access to lattice through a view object. | ||||||
|  | // prevents writing of code that will not offload to GPU, but perhaps annoyingly | ||||||
|  | // strict since host could could in principle direct access through the lattice object | ||||||
|  | // Need to decide programming model. | ||||||
|  | #define LATTICE_VIEW_STRICT | ||||||
|  | template<class vobj> class LatticeAccelerator : public LatticeBase | ||||||
|  | { | ||||||
|  | protected: | ||||||
|  |   GridBase *_grid; | ||||||
|  |   int checkerboard; | ||||||
|  |   vobj     *_odata;    // A managed pointer | ||||||
|  |   uint64_t _odata_size;     | ||||||
|  | public: | ||||||
|  |   accelerator_inline LatticeAccelerator() : checkerboard(0), _odata(nullptr), _odata_size(0), _grid(nullptr) { };  | ||||||
|  |   accelerator_inline uint64_t oSites(void) const { return _odata_size; }; | ||||||
|  |   accelerator_inline int  Checkerboard(void) const { return checkerboard; }; | ||||||
|  |   accelerator_inline int &Checkerboard(void) { return this->checkerboard; }; // can assign checkerboard on a container, not a view | ||||||
|  |   accelerator_inline void Conformable(GridBase * &grid) const | ||||||
|  |   {  | ||||||
|  |     if (grid) conformable(grid, _grid); | ||||||
|  |     else      grid = _grid; | ||||||
|  |   }; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | ///////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  | // A View class which provides accessor to the data. | ||||||
|  | // This will be safe to call from accelerator_for and is trivially copy constructible | ||||||
|  | // The copy constructor for this will need to be used by device lambda functions | ||||||
|  | ///////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  | template<class vobj>  | ||||||
|  | class LatticeView : public LatticeAccelerator<vobj> | ||||||
|  | { | ||||||
|  | public: | ||||||
|  |  | ||||||
|  |  | ||||||
|  |   // Rvalue | ||||||
|  | #ifdef __CUDA_ARCH__ | ||||||
|  |   accelerator_inline const typename vobj::scalar_object operator()(size_t i) const { return coalescedRead(this->_odata[i]); } | ||||||
|  | #else  | ||||||
|  |   accelerator_inline const vobj & operator()(size_t i) const { return this->_odata[i]; } | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  |   accelerator_inline const vobj & operator[](size_t i) const { return this->_odata[i]; }; | ||||||
|  |   accelerator_inline vobj       & operator[](size_t i)       { return this->_odata[i]; }; | ||||||
|  |  | ||||||
|  |   accelerator_inline uint64_t begin(void) const { return 0;}; | ||||||
|  |   accelerator_inline uint64_t end(void)   const { return this->_odata_size; }; | ||||||
|  |   accelerator_inline uint64_t size(void)  const { return this->_odata_size; }; | ||||||
|  |  | ||||||
|  |   LatticeView(const LatticeAccelerator<vobj> &refer_to_me) : LatticeAccelerator<vobj> (refer_to_me) | ||||||
|  |   { | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | ///////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  | // Lattice expression types used by ET to assemble the AST | ||||||
|  | //  | ||||||
|  | // Need to be able to detect code paths according to the whether a lattice object or not | ||||||
|  | // so introduce some trait type things | ||||||
|  | ///////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  |  | ||||||
|  | class LatticeExpressionBase {}; | ||||||
|  |  | ||||||
|  | template <typename T> using is_lattice = std::is_base_of<LatticeBase, T>; | ||||||
|  | template <typename T> using is_lattice_expr = std::is_base_of<LatticeExpressionBase,T >; | ||||||
|  |  | ||||||
|  | template<class T, bool isLattice> struct ViewMapBase { typedef T Type; }; | ||||||
|  | template<class T>                 struct ViewMapBase<T,true> { typedef LatticeView<typename T::vector_object> Type; }; | ||||||
|  | template<class T> using ViewMap = ViewMapBase<T,std::is_base_of<LatticeBase, T>::value >; | ||||||
|  |  | ||||||
|  | template <typename Op, typename _T1>                            | ||||||
|  | class LatticeUnaryExpression : public  LatticeExpressionBase  | ||||||
|  | { | ||||||
|  | public: | ||||||
|  |   typedef typename ViewMap<_T1>::Type T1; | ||||||
|  |   Op op; | ||||||
|  |   T1 arg1; | ||||||
|  |   LatticeUnaryExpression(Op _op,const _T1 &_arg1) : op(_op), arg1(_arg1) {}; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | template <typename Op, typename _T1, typename _T2>               | ||||||
|  | class LatticeBinaryExpression : public LatticeExpressionBase  | ||||||
|  | { | ||||||
|  | public: | ||||||
|  |   typedef typename ViewMap<_T1>::Type T1; | ||||||
|  |   typedef typename ViewMap<_T2>::Type T2; | ||||||
|  |   Op op; | ||||||
|  |   T1 arg1; | ||||||
|  |   T2 arg2; | ||||||
|  |   LatticeBinaryExpression(Op _op,const _T1 &_arg1,const _T2 &_arg2) : op(_op), arg1(_arg1), arg2(_arg2) {}; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | template <typename Op, typename _T1, typename _T2, typename _T3>  | ||||||
|  | class LatticeTrinaryExpression : public LatticeExpressionBase  | ||||||
|  | { | ||||||
|  | public: | ||||||
|  |   typedef typename ViewMap<_T1>::Type T1; | ||||||
|  |   typedef typename ViewMap<_T2>::Type T2; | ||||||
|  |   typedef typename ViewMap<_T3>::Type T3; | ||||||
|  |   Op op; | ||||||
|  |   T1 arg1; | ||||||
|  |   T2 arg2; | ||||||
|  |   T3 arg3; | ||||||
|  |   LatticeTrinaryExpression(Op _op,const _T1 &_arg1,const _T2 &_arg2,const _T3 &_arg3) : op(_op), arg1(_arg1), arg2(_arg2), arg3(_arg3) {}; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | ///////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  | // The real lattice class, with normal copy and assignment semantics. | ||||||
|  | // This contains extra (host resident) grid pointer data that may be accessed by host code | ||||||
|  | ///////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  | template<class vobj> | ||||||
|  | class Lattice : public LatticeAccelerator<vobj> | ||||||
|  | { | ||||||
|  | public: | ||||||
|  |   GridBase *Grid(void) const { return this->_grid; } | ||||||
|  |   /////////////////////////////////////////////////// | ||||||
|  |   // Member types | ||||||
|  |   /////////////////////////////////////////////////// | ||||||
|  |   typedef typename vobj::scalar_type scalar_type; | ||||||
|  |   typedef typename vobj::vector_type vector_type; | ||||||
|  |   typedef vobj vector_object; | ||||||
|  |  | ||||||
|  | private: | ||||||
|  |   void dealloc(void) | ||||||
|  |   { | ||||||
|  |     alignedAllocator<vobj> alloc; | ||||||
|  |     if( this->_odata_size ) { | ||||||
|  |       alloc.deallocate(this->_odata,this->_odata_size); | ||||||
|  |       this->_odata=nullptr; | ||||||
|  |       this->_odata_size=0; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   void resize(uint64_t size) | ||||||
|  |   { | ||||||
|  |     alignedAllocator<vobj> alloc; | ||||||
|  |     if ( this->_odata_size != size ) { | ||||||
|  |       dealloc(); | ||||||
|  |     } | ||||||
|  |     this->_odata_size = size; | ||||||
|  |     if ( size )  | ||||||
|  |       this->_odata      = alloc.allocate(this->_odata_size); | ||||||
|  |     else  | ||||||
|  |       this->_odata      = nullptr; | ||||||
|  |   } | ||||||
|  | public: | ||||||
|  |   ///////////////////////////////////////////////////////////////////////////////// | ||||||
|  |   // Return a view object that may be dereferenced in site loops. | ||||||
|  |   // The view is trivially copy constructible and may be copied to an accelerator device | ||||||
|  |   // in device lambdas | ||||||
|  |   ///////////////////////////////////////////////////////////////////////////////// | ||||||
|  |   LatticeView<vobj> View (void) const  | ||||||
|  |   { | ||||||
|  |     LatticeView<vobj> accessor(*( (LatticeAccelerator<vobj> *) this)); | ||||||
|  |     return accessor; | ||||||
|  |   } | ||||||
|  |    | ||||||
|  |   ~Lattice() {  | ||||||
|  |     if ( this->_odata_size ) { | ||||||
|  |       dealloc(); | ||||||
|  |     } | ||||||
|  |    } | ||||||
|  |   //////////////////////////////////////////////////////////////////////////////// | ||||||
|  |   // Expression Template closure support | ||||||
|  |   //////////////////////////////////////////////////////////////////////////////// | ||||||
|  |   template <typename Op, typename T1> inline Lattice<vobj> & operator=(const LatticeUnaryExpression<Op,T1> &expr) | ||||||
|  |   { | ||||||
|  |     GridBase *egrid(nullptr); | ||||||
|  |     GridFromExpression(egrid,expr); | ||||||
|  |     assert(egrid!=nullptr); | ||||||
|  |     conformable(this->_grid,egrid); | ||||||
|  |  | ||||||
|  |     int cb=-1; | ||||||
|  |     CBFromExpression(cb,expr); | ||||||
|  |     assert( (cb==Odd) || (cb==Even)); | ||||||
|  |     this->checkerboard=cb; | ||||||
|  |  | ||||||
|  |     auto me  = View(); | ||||||
|  |     accelerator_for(ss,me.size(),1,{ | ||||||
|  |       auto tmp = eval(ss,expr); | ||||||
|  |       vstream(me[ss],tmp); | ||||||
|  |     }); | ||||||
|  |     return *this; | ||||||
|  |   } | ||||||
|  |   template <typename Op, typename T1,typename T2> inline Lattice<vobj> & operator=(const LatticeBinaryExpression<Op,T1,T2> &expr) | ||||||
|  |   { | ||||||
|  |     GridBase *egrid(nullptr); | ||||||
|  |     GridFromExpression(egrid,expr); | ||||||
|  |     assert(egrid!=nullptr); | ||||||
|  |     conformable(this->_grid,egrid); | ||||||
|  |  | ||||||
|  |     int cb=-1; | ||||||
|  |     CBFromExpression(cb,expr); | ||||||
|  |     assert( (cb==Odd) || (cb==Even)); | ||||||
|  |     this->checkerboard=cb; | ||||||
|  |  | ||||||
|  |     auto me  = View(); | ||||||
|  |     accelerator_for(ss,me.size(),1,{ | ||||||
|  |       auto tmp = eval(ss,expr); | ||||||
|  |       vstream(me[ss],tmp); | ||||||
|  |     }); | ||||||
|  |     return *this; | ||||||
|  |   } | ||||||
|  |   template <typename Op, typename T1,typename T2,typename T3> inline Lattice<vobj> & operator=(const LatticeTrinaryExpression<Op,T1,T2,T3> &expr) | ||||||
|  |   { | ||||||
|  |     GridBase *egrid(nullptr); | ||||||
|  |     GridFromExpression(egrid,expr); | ||||||
|  |     assert(egrid!=nullptr); | ||||||
|  |     conformable(this->_grid,egrid); | ||||||
|  |  | ||||||
|  |     int cb=-1; | ||||||
|  |     CBFromExpression(cb,expr); | ||||||
|  |     assert( (cb==Odd) || (cb==Even)); | ||||||
|  |     this->checkerboard=cb; | ||||||
|  |     auto me  = View(); | ||||||
|  |     accelerator_for(ss,me.size(),1,{ | ||||||
|  |       auto tmp = eval(ss,expr); | ||||||
|  |       vstream(me[ss],tmp); | ||||||
|  |     }); | ||||||
|  |     return *this; | ||||||
|  |   } | ||||||
|  |   //GridFromExpression is tricky to do | ||||||
|  |   template<class Op,class T1> | ||||||
|  |   Lattice(const LatticeUnaryExpression<Op,T1> & expr) { | ||||||
|  |     this->_grid = nullptr; | ||||||
|  |     GridFromExpression(this->_grid,expr); | ||||||
|  |     assert(this->_grid!=nullptr); | ||||||
|  |  | ||||||
|  |     int cb=-1; | ||||||
|  |     CBFromExpression(cb,expr); | ||||||
|  |     assert( (cb==Odd) || (cb==Even)); | ||||||
|  |     this->checkerboard=cb; | ||||||
|  |  | ||||||
|  |     resize(this->_grid->oSites()); | ||||||
|  |  | ||||||
|  |     *this = expr; | ||||||
|  |   } | ||||||
|  |   template<class Op,class T1, class T2> | ||||||
|  |   Lattice(const LatticeBinaryExpression<Op,T1,T2> & expr) { | ||||||
|  |     this->_grid = nullptr; | ||||||
|  |     GridFromExpression(this->_grid,expr); | ||||||
|  |     assert(this->_grid!=nullptr); | ||||||
|  |  | ||||||
|  |     int cb=-1; | ||||||
|  |     CBFromExpression(cb,expr); | ||||||
|  |     assert( (cb==Odd) || (cb==Even)); | ||||||
|  |     this->checkerboard=cb; | ||||||
|  |  | ||||||
|  |     resize(this->_grid->oSites()); | ||||||
|  |  | ||||||
|  |     *this = expr; | ||||||
|  |   } | ||||||
|  |   template<class Op,class T1, class T2, class T3> | ||||||
|  |   Lattice(const LatticeTrinaryExpression<Op,T1,T2,T3> & expr) { | ||||||
|  |     this->_grid = nullptr; | ||||||
|  |     GridFromExpression(this->_grid,expr); | ||||||
|  |     assert(this->_grid!=nullptr); | ||||||
|  |  | ||||||
|  |     int cb=-1; | ||||||
|  |     CBFromExpression(cb,expr); | ||||||
|  |     assert( (cb==Odd) || (cb==Even)); | ||||||
|  |     this->checkerboard=cb; | ||||||
|  |  | ||||||
|  |     resize(this->_grid->oSites()); | ||||||
|  |  | ||||||
|  |     *this = expr; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   template<class sobj> inline Lattice<vobj> & operator = (const sobj & r){ | ||||||
|  |     auto me  = View(); | ||||||
|  |     thread_for(ss,me.size(),{ | ||||||
|  |       me[ss] = r; | ||||||
|  |     }); | ||||||
|  |     return *this; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   ////////////////////////////////////////////////////////////////// | ||||||
|  |   // Follow rule of five, with Constructor requires "grid" passed | ||||||
|  |   // to user defined constructor | ||||||
|  |   /////////////////////////////////////////// | ||||||
|  |   // user defined constructor | ||||||
|  |   /////////////////////////////////////////// | ||||||
|  |   Lattice(GridBase *grid) {  | ||||||
|  |     this->_grid = grid; | ||||||
|  |     resize(this->_grid->oSites()); | ||||||
|  |     assert((((uint64_t)&this->_odata[0])&0xF) ==0); | ||||||
|  |     this->checkerboard=0; | ||||||
|  |   } | ||||||
|  |    | ||||||
|  |   //  virtual ~Lattice(void) = default; | ||||||
|  |      | ||||||
|  |   void reset(GridBase* grid) { | ||||||
|  |     if (this->_grid != grid) { | ||||||
|  |       this->_grid = grid; | ||||||
|  |       this->_odata.resize(grid->oSites()); | ||||||
|  |       this->checkerboard = 0; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   /////////////////////////////////////////// | ||||||
|  |   // copy constructor | ||||||
|  |   /////////////////////////////////////////// | ||||||
|  |   Lattice(const Lattice& r){  | ||||||
|  |     //    std::cout << "Lattice constructor(const Lattice &) "<<this<<std::endl;  | ||||||
|  |     this->_grid = r.Grid(); | ||||||
|  |     resize(this->_grid->oSites()); | ||||||
|  |     *this = r; | ||||||
|  |   } | ||||||
|  |   /////////////////////////////////////////// | ||||||
|  |   // move constructor | ||||||
|  |   /////////////////////////////////////////// | ||||||
|  |   Lattice(Lattice && r){  | ||||||
|  |     this->_grid = r.Grid(); | ||||||
|  |     this->_odata      = r._odata; | ||||||
|  |     this->_odata_size = r._odata_size; | ||||||
|  |     this->checkerboard= r.Checkerboard(); | ||||||
|  |     r._odata      = nullptr; | ||||||
|  |     r._odata_size = 0; | ||||||
|  |   } | ||||||
|  |   /////////////////////////////////////////// | ||||||
|  |   // assignment template | ||||||
|  |   /////////////////////////////////////////// | ||||||
|  |   template<class robj> inline Lattice<vobj> & operator = (const Lattice<robj> & r){ | ||||||
|  |     typename std::enable_if<!std::is_same<robj,vobj>::value,int>::type i=0; | ||||||
|  |     conformable(*this,r); | ||||||
|  |     this->checkerboard = r.Checkerboard(); | ||||||
|  |     auto me =   View(); | ||||||
|  |     auto him= r.View(); | ||||||
|  |     accelerator_for(ss,me.size(),vobj::Nsimd(),{ | ||||||
|  |       coalescedWrite(me[ss],him(ss)); | ||||||
|  |     }); | ||||||
|  |     return *this; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   /////////////////////////////////////////// | ||||||
|  |   // Copy assignment  | ||||||
|  |   /////////////////////////////////////////// | ||||||
|  |   inline Lattice<vobj> & operator = (const Lattice<vobj> & r){ | ||||||
|  |     this->checkerboard = r.Checkerboard(); | ||||||
|  |     conformable(*this,r); | ||||||
|  |     auto me =   View(); | ||||||
|  |     auto him= r.View(); | ||||||
|  |     accelerator_for(ss,me.size(),vobj::Nsimd(),{ | ||||||
|  |       coalescedWrite(me[ss],him(ss)); | ||||||
|  |     }); | ||||||
|  |     return *this; | ||||||
|  |   } | ||||||
|  |   /////////////////////////////////////////// | ||||||
|  |   // Move assignment possible if same type | ||||||
|  |   /////////////////////////////////////////// | ||||||
|  |   inline Lattice<vobj> & operator = (Lattice<vobj> && r){ | ||||||
|  |  | ||||||
|  |     resize(0); // deletes if appropriate | ||||||
|  |     this->_grid       = r.Grid(); | ||||||
|  |     this->_odata      = r._odata; | ||||||
|  |     this->_odata_size = r._odata_size; | ||||||
|  |     this->checkerboard= r.Checkerboard(); | ||||||
|  |  | ||||||
|  |     r._odata      = nullptr; | ||||||
|  |     r._odata_size = 0; | ||||||
|  |      | ||||||
|  |     return *this; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   ///////////////////////////////////////////////////////////////////////////// | ||||||
|  |   // *=,+=,-= operators inherit behvour from correspond */+/- operation | ||||||
|  |   ///////////////////////////////////////////////////////////////////////////// | ||||||
|  |   template<class T> inline Lattice<vobj> &operator *=(const T &r) { | ||||||
|  |     *this = (*this)*r; | ||||||
|  |     return *this; | ||||||
|  |   } | ||||||
|  |    | ||||||
|  |   template<class T> inline Lattice<vobj> &operator -=(const T &r) { | ||||||
|  |     *this = (*this)-r; | ||||||
|  |     return *this; | ||||||
|  |   } | ||||||
|  |   template<class T> inline Lattice<vobj> &operator +=(const T &r) { | ||||||
|  |     *this = (*this)+r; | ||||||
|  |     return *this; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   friend inline void swap(Lattice &l, Lattice &r) {  | ||||||
|  |     conformable(l,r); | ||||||
|  |     LatticeAccelerator<vobj> tmp; | ||||||
|  |     LatticeAccelerator<vobj> *lp = (LatticeAccelerator<vobj> *)&l; | ||||||
|  |     LatticeAccelerator<vobj> *rp = (LatticeAccelerator<vobj> *)&r; | ||||||
|  |     tmp = *lp;    *lp=*rp;    *rp=tmp; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  | }; // class Lattice | ||||||
|  |  | ||||||
|  | template<class vobj> std::ostream& operator<< (std::ostream& stream, const Lattice<vobj> &o){ | ||||||
|  |   typedef typename vobj::scalar_object sobj; | ||||||
|  |   for(int g=0;g<o.Grid()->_gsites;g++){ | ||||||
|  |  | ||||||
|  |     Coordinate gcoor; | ||||||
|  |     o.Grid()->GlobalIndexToGlobalCoor(g,gcoor); | ||||||
|  |  | ||||||
|  |     sobj ss; | ||||||
|  |     peekSite(ss,o,gcoor); | ||||||
|  |     stream<<"["; | ||||||
|  |     for(int d=0;d<gcoor.size();d++){ | ||||||
|  |       stream<<gcoor[d]; | ||||||
|  |       if(d!=gcoor.size()-1) stream<<","; | ||||||
|  |     } | ||||||
|  |     stream<<"]\t"; | ||||||
|  |     stream<<ss<<std::endl; | ||||||
|  |   } | ||||||
|  |   return stream; | ||||||
|  | } | ||||||
|  |    | ||||||
|  | NAMESPACE_END(Grid); | ||||||
|  |  | ||||||
							
								
								
									
										207
									
								
								Grid/lattice/Lattice_comparison.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										207
									
								
								Grid/lattice/Lattice_comparison.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,207 @@ | |||||||
|  | /************************************************************************************* | ||||||
|  |  | ||||||
|  |     Grid physics library, www.github.com/paboyle/Grid  | ||||||
|  |  | ||||||
|  |     Source file: ./lib/lattice/Lattice_comparison.h | ||||||
|  |  | ||||||
|  |     Copyright (C) 2015 | ||||||
|  |  | ||||||
|  | Author: Azusa Yamaguchi <ayamaguc@staffmail.ed.ac.uk> | ||||||
|  | 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_LATTICE_COMPARISON_H | ||||||
|  | #define GRID_LATTICE_COMPARISON_H | ||||||
|  |  | ||||||
|  | NAMESPACE_BEGIN(Grid); | ||||||
|  |  | ||||||
|  | ////////////////////////////////////////////////////////////////////////// | ||||||
|  | // relational operators | ||||||
|  | //  | ||||||
|  | // Support <,>,<=,>=,==,!= | ||||||
|  | // | ||||||
|  | //Query supporting bitwise &, |, ^, ! | ||||||
|  | //Query supporting logical &&, ||,  | ||||||
|  | ////////////////////////////////////////////////////////////////////////// | ||||||
|  |  | ||||||
|  | typedef iScalar<vInteger> vPredicate ; | ||||||
|  |  | ||||||
|  | /* | ||||||
|  | template <class iobj, class vobj, class robj> accelerator_inline  | ||||||
|  | vobj predicatedWhere(const iobj &predicate, const vobj &iftrue, const robj &iffalse)  | ||||||
|  | { | ||||||
|  |   typename std::remove_const<vobj>::type ret; | ||||||
|  |  | ||||||
|  |   typedef typename vobj::scalar_object scalar_object; | ||||||
|  |   typedef typename vobj::scalar_type scalar_type; | ||||||
|  |   typedef typename vobj::vector_type vector_type; | ||||||
|  |  | ||||||
|  |   const int Nsimd = vobj::vector_type::Nsimd(); | ||||||
|  |  | ||||||
|  |   ExtractBuffer<Integer> mask(Nsimd); | ||||||
|  |   ExtractBuffer<scalar_object> truevals(Nsimd); | ||||||
|  |   ExtractBuffer<scalar_object> falsevals(Nsimd); | ||||||
|  |  | ||||||
|  |   extract(iftrue, truevals); | ||||||
|  |   extract(iffalse, falsevals); | ||||||
|  |   extract<vInteger, Integer>(TensorRemove(predicate), mask); | ||||||
|  |  | ||||||
|  |   for (int s = 0; s < Nsimd; s++) { | ||||||
|  |     if (mask[s]) falsevals[s] = truevals[s]; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   merge(ret, falsevals); | ||||||
|  |   return ret; | ||||||
|  | } | ||||||
|  | */ | ||||||
|  | ////////////////////////////////////////////////////////////////////////// | ||||||
|  | // compare lattice to lattice | ||||||
|  | ////////////////////////////////////////////////////////////////////////// | ||||||
|  |  | ||||||
|  | template<class vfunctor,class lobj,class robj>   | ||||||
|  | inline Lattice<vPredicate> LLComparison(vfunctor op,const Lattice<lobj> &lhs,const Lattice<robj> &rhs) | ||||||
|  | { | ||||||
|  |   Lattice<vPredicate> ret(rhs.Grid()); | ||||||
|  |   auto lhs_v = lhs.View(); | ||||||
|  |   auto rhs_v = rhs.View(); | ||||||
|  |   auto ret_v = ret.View(); | ||||||
|  |   thread_for( ss, rhs_v.size(), { | ||||||
|  |       ret_v[ss]=op(lhs_v[ss],rhs_v[ss]); | ||||||
|  |   }); | ||||||
|  |   return ret; | ||||||
|  | } | ||||||
|  | ////////////////////////////////////////////////////////////////////////// | ||||||
|  | // compare lattice to scalar | ||||||
|  | ////////////////////////////////////////////////////////////////////////// | ||||||
|  | template<class vfunctor,class lobj,class robj>  | ||||||
|  | inline Lattice<vPredicate> LSComparison(vfunctor op,const Lattice<lobj> &lhs,const robj &rhs) | ||||||
|  | { | ||||||
|  |   Lattice<vPredicate> ret(lhs.Grid()); | ||||||
|  |   auto lhs_v = lhs.View(); | ||||||
|  |   auto ret_v = ret.View(); | ||||||
|  |   thread_for( ss, lhs_v.size(), { | ||||||
|  |     ret_v[ss]=op(lhs_v[ss],rhs); | ||||||
|  |   }); | ||||||
|  |   return ret; | ||||||
|  | } | ||||||
|  | ////////////////////////////////////////////////////////////////////////// | ||||||
|  | // compare scalar to lattice | ||||||
|  | ////////////////////////////////////////////////////////////////////////// | ||||||
|  | template<class vfunctor,class lobj,class robj>  | ||||||
|  | inline Lattice<vPredicate> SLComparison(vfunctor op,const lobj &lhs,const Lattice<robj> &rhs) | ||||||
|  | { | ||||||
|  |   Lattice<vPredicate> ret(rhs.Grid()); | ||||||
|  |   auto rhs_v = rhs.View(); | ||||||
|  |   auto ret_v = ret.View(); | ||||||
|  |   thread_for( ss, rhs_v.size(), { | ||||||
|  |     ret_v[ss]=op(lhs,rhs_v[ss]); | ||||||
|  |   }); | ||||||
|  |   return ret; | ||||||
|  | } | ||||||
|  |    | ||||||
|  | ////////////////////////////////////////////////////////////////////////// | ||||||
|  | // Map to functors | ||||||
|  | ////////////////////////////////////////////////////////////////////////// | ||||||
|  | // Less than | ||||||
|  | template<class lobj,class robj> | ||||||
|  | inline Lattice<vPredicate> operator < (const Lattice<lobj> & lhs, const Lattice<robj> & rhs) { | ||||||
|  |   return LLComparison(vlt<lobj,robj>(),lhs,rhs); | ||||||
|  | } | ||||||
|  | template<class lobj,class robj> | ||||||
|  | inline Lattice<vPredicate> operator < (const Lattice<lobj> & lhs, const robj & rhs) { | ||||||
|  |   return LSComparison(vlt<lobj,robj>(),lhs,rhs); | ||||||
|  | } | ||||||
|  | template<class lobj,class robj> | ||||||
|  | inline Lattice<vPredicate> operator < (const lobj & lhs, const Lattice<robj> & rhs) { | ||||||
|  |   return SLComparison(vlt<lobj,robj>(),lhs,rhs); | ||||||
|  | } | ||||||
|  |    | ||||||
|  | // Less than equal | ||||||
|  | template<class lobj,class robj> | ||||||
|  | inline Lattice<vPredicate> operator <= (const Lattice<lobj> & lhs, const Lattice<robj> & rhs) { | ||||||
|  |   return LLComparison(vle<lobj,robj>(),lhs,rhs); | ||||||
|  | } | ||||||
|  | template<class lobj,class robj> | ||||||
|  | inline Lattice<vPredicate> operator <= (const Lattice<lobj> & lhs, const robj & rhs) { | ||||||
|  |   return LSComparison(vle<lobj,robj>(),lhs,rhs); | ||||||
|  | } | ||||||
|  | template<class lobj,class robj> | ||||||
|  | inline Lattice<vPredicate> operator <= (const lobj & lhs, const Lattice<robj> & rhs) { | ||||||
|  |   return SLComparison(vle<lobj,robj>(),lhs,rhs); | ||||||
|  | } | ||||||
|  |    | ||||||
|  | // Greater than  | ||||||
|  | template<class lobj,class robj> | ||||||
|  | inline Lattice<vPredicate> operator > (const Lattice<lobj> & lhs, const Lattice<robj> & rhs) { | ||||||
|  |   return LLComparison(vgt<lobj,robj>(),lhs,rhs); | ||||||
|  | } | ||||||
|  | template<class lobj,class robj> | ||||||
|  | inline Lattice<vPredicate> operator > (const Lattice<lobj> & lhs, const robj & rhs) { | ||||||
|  |   return LSComparison(vgt<lobj,robj>(),lhs,rhs); | ||||||
|  | } | ||||||
|  | template<class lobj,class robj> | ||||||
|  | inline Lattice<vPredicate> operator > (const lobj & lhs, const Lattice<robj> & rhs) { | ||||||
|  |   return SLComparison(vgt<lobj,robj>(),lhs,rhs); | ||||||
|  | } | ||||||
|  |    | ||||||
|  |    | ||||||
|  | // Greater than equal | ||||||
|  | template<class lobj,class robj> | ||||||
|  | inline Lattice<vPredicate> operator >= (const Lattice<lobj> & lhs, const Lattice<robj> & rhs) { | ||||||
|  |   return LLComparison(vge<lobj,robj>(),lhs,rhs); | ||||||
|  | } | ||||||
|  | template<class lobj,class robj> | ||||||
|  | inline Lattice<vPredicate> operator >= (const Lattice<lobj> & lhs, const robj & rhs) { | ||||||
|  |   return LSComparison(vge<lobj,robj>(),lhs,rhs); | ||||||
|  | } | ||||||
|  | template<class lobj,class robj> | ||||||
|  | inline Lattice<vPredicate> operator >= (const lobj & lhs, const Lattice<robj> & rhs) { | ||||||
|  |   return SLComparison(vge<lobj,robj>(),lhs,rhs); | ||||||
|  | } | ||||||
|  |     | ||||||
|  | // equal | ||||||
|  | template<class lobj,class robj> | ||||||
|  | inline Lattice<vPredicate> operator == (const Lattice<lobj> & lhs, const Lattice<robj> & rhs) { | ||||||
|  |   return LLComparison(veq<lobj,robj>(),lhs,rhs); | ||||||
|  | } | ||||||
|  | template<class lobj,class robj> | ||||||
|  | inline Lattice<vPredicate> operator == (const Lattice<lobj> & lhs, const robj & rhs) { | ||||||
|  |   return LSComparison(veq<lobj,robj>(),lhs,rhs); | ||||||
|  | } | ||||||
|  | template<class lobj,class robj> | ||||||
|  | inline Lattice<vPredicate> operator == (const lobj & lhs, const Lattice<robj> & rhs) { | ||||||
|  |   return SLComparison(veq<lobj,robj>(),lhs,rhs); | ||||||
|  | } | ||||||
|  |     | ||||||
|  |     | ||||||
|  | // not equal | ||||||
|  | template<class lobj,class robj> | ||||||
|  | inline Lattice<vPredicate> operator != (const Lattice<lobj> & lhs, const Lattice<robj> & rhs) { | ||||||
|  |   return LLComparison(vne<lobj,robj>(),lhs,rhs); | ||||||
|  | } | ||||||
|  | template<class lobj,class robj> | ||||||
|  | inline Lattice<vPredicate> operator != (const Lattice<lobj> & lhs, const robj & rhs) { | ||||||
|  |   return LSComparison(vne<lobj,robj>(),lhs,rhs); | ||||||
|  | } | ||||||
|  | template<class lobj,class robj> | ||||||
|  | inline Lattice<vPredicate> operator != (const lobj & lhs, const Lattice<robj> & rhs) { | ||||||
|  |   return SLComparison(vne<lobj,robj>(),lhs,rhs); | ||||||
|  | } | ||||||
|  | NAMESPACE_END(Grid); | ||||||
|  | #endif | ||||||
| @@ -26,10 +26,10 @@ Author: Peter Boyle <paboyle@ph.ed.ac.uk> | |||||||
|     See the full license in the file "LICENSE" in the top level distribution directory |     See the full license in the file "LICENSE" in the top level distribution directory | ||||||
|     *************************************************************************************/ |     *************************************************************************************/ | ||||||
|     /*  END LEGAL */ |     /*  END LEGAL */ | ||||||
| #ifndef GRID_COMPARISON_H |  | ||||||
| #define GRID_COMPARISON_H |  | ||||||
| 
 | 
 | ||||||
| namespace Grid { | #pragma once | ||||||
|  | 
 | ||||||
|  | NAMESPACE_BEGIN(Grid); | ||||||
| 
 | 
 | ||||||
|   /////////////////////////////////////////
 |   /////////////////////////////////////////
 | ||||||
|   // This implementation is a bit poor.
 |   // This implementation is a bit poor.
 | ||||||
| @@ -44,42 +44,42 @@ namespace Grid { | |||||||
|   //
 |   //
 | ||||||
|   template<class lobj,class robj> class veq { |   template<class lobj,class robj> class veq { | ||||||
|   public: |   public: | ||||||
|     vInteger operator()(const lobj &lhs, const robj &rhs) |     accelerator vInteger operator()(const lobj &lhs, const robj &rhs) | ||||||
|     {  |     {  | ||||||
|       return (lhs) == (rhs); |       return (lhs) == (rhs); | ||||||
|     } |     } | ||||||
|   }; |   }; | ||||||
|   template<class lobj,class robj> class vne { |   template<class lobj,class robj> class vne { | ||||||
|   public: |   public: | ||||||
|     vInteger operator()(const lobj &lhs, const robj &rhs) |     accelerator vInteger operator()(const lobj &lhs, const robj &rhs) | ||||||
|     {  |     {  | ||||||
|       return (lhs) != (rhs); |       return (lhs) != (rhs); | ||||||
|     } |     } | ||||||
|   }; |   }; | ||||||
|   template<class lobj,class robj> class vlt { |   template<class lobj,class robj> class vlt { | ||||||
|   public: |   public: | ||||||
|     vInteger operator()(const lobj &lhs, const robj &rhs) |     accelerator vInteger operator()(const lobj &lhs, const robj &rhs) | ||||||
|     {  |     {  | ||||||
|       return (lhs) < (rhs); |       return (lhs) < (rhs); | ||||||
|     } |     } | ||||||
|   }; |   }; | ||||||
|   template<class lobj,class robj> class vle { |   template<class lobj,class robj> class vle { | ||||||
|   public: |   public: | ||||||
|     vInteger operator()(const lobj &lhs, const robj &rhs) |     accelerator vInteger operator()(const lobj &lhs, const robj &rhs) | ||||||
|     {  |     {  | ||||||
|       return (lhs) <= (rhs); |       return (lhs) <= (rhs); | ||||||
|     } |     } | ||||||
|   }; |   }; | ||||||
|   template<class lobj,class robj> class vgt { |   template<class lobj,class robj> class vgt { | ||||||
|   public: |   public: | ||||||
|     vInteger operator()(const lobj &lhs, const robj &rhs) |     accelerator vInteger operator()(const lobj &lhs, const robj &rhs) | ||||||
|     {  |     {  | ||||||
|       return (lhs) > (rhs); |       return (lhs) > (rhs); | ||||||
|     } |     } | ||||||
|   }; |   }; | ||||||
|   template<class lobj,class robj> class vge { |   template<class lobj,class robj> class vge { | ||||||
|     public: |     public: | ||||||
|     vInteger operator()(const lobj &lhs, const robj &rhs) |     accelerator vInteger operator()(const lobj &lhs, const robj &rhs) | ||||||
|     {  |     {  | ||||||
|       return (lhs) >= (rhs); |       return (lhs) >= (rhs); | ||||||
|     } |     } | ||||||
| @@ -88,42 +88,42 @@ namespace Grid { | |||||||
|   // Generic list of functors
 |   // Generic list of functors
 | ||||||
|   template<class lobj,class robj> class seq { |   template<class lobj,class robj> class seq { | ||||||
|   public: |   public: | ||||||
|     Integer operator()(const lobj &lhs, const robj &rhs) |     accelerator Integer operator()(const lobj &lhs, const robj &rhs) | ||||||
|     {  |     {  | ||||||
|       return (lhs) == (rhs); |       return (lhs) == (rhs); | ||||||
|     } |     } | ||||||
|   }; |   }; | ||||||
|   template<class lobj,class robj> class sne { |   template<class lobj,class robj> class sne { | ||||||
|   public: |   public: | ||||||
|     Integer operator()(const lobj &lhs, const robj &rhs) |     accelerator Integer operator()(const lobj &lhs, const robj &rhs) | ||||||
|     {  |     {  | ||||||
|       return (lhs) != (rhs); |       return (lhs) != (rhs); | ||||||
|     } |     } | ||||||
|   }; |   }; | ||||||
|   template<class lobj,class robj> class slt { |   template<class lobj,class robj> class slt { | ||||||
|   public: |   public: | ||||||
|     Integer operator()(const lobj &lhs, const robj &rhs) |     accelerator Integer operator()(const lobj &lhs, const robj &rhs) | ||||||
|     {  |     {  | ||||||
|       return (lhs) < (rhs); |       return (lhs) < (rhs); | ||||||
|     } |     } | ||||||
|   }; |   }; | ||||||
|   template<class lobj,class robj> class sle { |   template<class lobj,class robj> class sle { | ||||||
|   public: |   public: | ||||||
|     Integer operator()(const lobj &lhs, const robj &rhs) |     accelerator Integer operator()(const lobj &lhs, const robj &rhs) | ||||||
|     {  |     {  | ||||||
|       return (lhs) <= (rhs); |       return (lhs) <= (rhs); | ||||||
|     } |     } | ||||||
|   }; |   }; | ||||||
|   template<class lobj,class robj> class sgt { |   template<class lobj,class robj> class sgt { | ||||||
|   public: |   public: | ||||||
|     Integer operator()(const lobj &lhs, const robj &rhs) |     accelerator Integer operator()(const lobj &lhs, const robj &rhs) | ||||||
|     {  |     {  | ||||||
|       return (lhs) > (rhs); |       return (lhs) > (rhs); | ||||||
|     } |     } | ||||||
|   }; |   }; | ||||||
|   template<class lobj,class robj> class sge { |   template<class lobj,class robj> class sge { | ||||||
|   public: |   public: | ||||||
|     Integer operator()(const lobj &lhs, const robj &rhs) |     accelerator Integer operator()(const lobj &lhs, const robj &rhs) | ||||||
|     {  |     {  | ||||||
|       return (lhs) >= (rhs); |       return (lhs) >= (rhs); | ||||||
|     } |     } | ||||||
| @@ -133,12 +133,12 @@ namespace Grid { | |||||||
|   // Integer and real get extra relational functions.
 |   // Integer and real get extra relational functions.
 | ||||||
|   //////////////////////////////////////////////////////////////////////////////////////////////////////
 |   //////////////////////////////////////////////////////////////////////////////////////////////////////
 | ||||||
|   template<class sfunctor, class vsimd,IfNotComplex<vsimd> = 0>  |   template<class sfunctor, class vsimd,IfNotComplex<vsimd> = 0>  | ||||||
|     inline vInteger Comparison(sfunctor sop,const vsimd & lhs, const vsimd & rhs) |     accelerator_inline vInteger Comparison(sfunctor sop,const vsimd & lhs, const vsimd & rhs) | ||||||
|     { |     { | ||||||
|       typedef typename vsimd::scalar_type scalar; |       typedef typename vsimd::scalar_type scalar; | ||||||
|       std::vector<scalar> vlhs(vsimd::Nsimd());   // Use functors to reduce this to single implementation
 |       ExtractBuffer<scalar> vlhs(vsimd::Nsimd());   // Use functors to reduce this to single implementation
 | ||||||
|       std::vector<scalar> vrhs(vsimd::Nsimd()); |       ExtractBuffer<scalar> vrhs(vsimd::Nsimd()); | ||||||
|       std::vector<Integer> vpred(vsimd::Nsimd()); |       ExtractBuffer<Integer> vpred(vsimd::Nsimd()); | ||||||
|       vInteger ret; |       vInteger ret; | ||||||
|       extract<vsimd,scalar>(lhs,vlhs); |       extract<vsimd,scalar>(lhs,vlhs); | ||||||
|       extract<vsimd,scalar>(rhs,vrhs); |       extract<vsimd,scalar>(rhs,vrhs); | ||||||
| @@ -150,11 +150,11 @@ namespace Grid { | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|   template<class sfunctor, class vsimd,IfNotComplex<vsimd> = 0>  |   template<class sfunctor, class vsimd,IfNotComplex<vsimd> = 0>  | ||||||
|     inline vInteger Comparison(sfunctor sop,const vsimd & lhs, const typename vsimd::scalar_type & rhs) |     accelerator_inline vInteger Comparison(sfunctor sop,const vsimd & lhs, const typename vsimd::scalar_type & rhs) | ||||||
|     { |     { | ||||||
|       typedef typename vsimd::scalar_type scalar; |       typedef typename vsimd::scalar_type scalar; | ||||||
|       std::vector<scalar> vlhs(vsimd::Nsimd());   // Use functors to reduce this to single implementation
 |       ExtractBuffer<scalar> vlhs(vsimd::Nsimd());   // Use functors to reduce this to single implementation
 | ||||||
|       std::vector<Integer> vpred(vsimd::Nsimd()); |       ExtractBuffer<Integer> vpred(vsimd::Nsimd()); | ||||||
|       vInteger ret; |       vInteger ret; | ||||||
|       extract<vsimd,scalar>(lhs,vlhs); |       extract<vsimd,scalar>(lhs,vlhs); | ||||||
|       for(int s=0;s<vsimd::Nsimd();s++){ |       for(int s=0;s<vsimd::Nsimd();s++){ | ||||||
| @@ -165,11 +165,11 @@ namespace Grid { | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|   template<class sfunctor, class vsimd,IfNotComplex<vsimd> = 0>  |   template<class sfunctor, class vsimd,IfNotComplex<vsimd> = 0>  | ||||||
|     inline vInteger Comparison(sfunctor sop,const typename vsimd::scalar_type & lhs, const vsimd & rhs) |     accelerator_inline vInteger Comparison(sfunctor sop,const typename vsimd::scalar_type & lhs, const vsimd & rhs) | ||||||
|     { |     { | ||||||
|       typedef typename vsimd::scalar_type scalar; |       typedef typename vsimd::scalar_type scalar; | ||||||
|       std::vector<scalar> vrhs(vsimd::Nsimd());   // Use functors to reduce this to single implementation
 |       ExtractBuffer<scalar> vrhs(vsimd::Nsimd());   // Use functors to reduce this to single implementation
 | ||||||
|       std::vector<Integer> vpred(vsimd::Nsimd()); |       ExtractBuffer<Integer> vpred(vsimd::Nsimd()); | ||||||
|       vInteger ret; |       vInteger ret; | ||||||
|       extract<vsimd,scalar>(rhs,vrhs); |       extract<vsimd,scalar>(rhs,vrhs); | ||||||
|       for(int s=0;s<vsimd::Nsimd();s++){ |       for(int s=0;s<vsimd::Nsimd();s++){ | ||||||
| @@ -179,52 +179,54 @@ namespace Grid { | |||||||
|       return ret; |       return ret; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| #define DECLARE_RELATIONAL(op,functor) \ | #define DECLARE_RELATIONAL_EQ(op,functor) \ | ||||||
|   template<class vsimd,IfSimd<vsimd> = 0>\ |   template<class vsimd,IfSimd<vsimd> = 0>\ | ||||||
|     inline vInteger operator op (const vsimd & lhs, const vsimd & rhs)\ |     accelerator_inline vInteger operator op (const vsimd & lhs, const vsimd & rhs)\ | ||||||
|     {\ |     {\ | ||||||
|       typedef typename vsimd::scalar_type scalar;\ |       typedef typename vsimd::scalar_type scalar;\ | ||||||
|       return Comparison(functor<scalar,scalar>(),lhs,rhs);\ |       return Comparison(functor<scalar,scalar>(),lhs,rhs);\ | ||||||
|     }\ |     }\ | ||||||
|   template<class vsimd,IfSimd<vsimd> = 0>\ |   template<class vsimd,IfSimd<vsimd> = 0>\ | ||||||
|     inline vInteger operator op (const vsimd & lhs, const typename vsimd::scalar_type & rhs) \ |     accelerator_inline vInteger operator op (const vsimd & lhs, const typename vsimd::scalar_type & rhs) \ | ||||||
|     {\ |     {\ | ||||||
|       typedef typename vsimd::scalar_type scalar;\ |       typedef typename vsimd::scalar_type scalar;\ | ||||||
|       return Comparison(functor<scalar,scalar>(),lhs,rhs);\ |       return Comparison(functor<scalar,scalar>(),lhs,rhs);\ | ||||||
|     }\ |     }\ | ||||||
|   template<class vsimd,IfSimd<vsimd> = 0>\ |   template<class vsimd,IfSimd<vsimd> = 0>\ | ||||||
|     inline vInteger operator op (const typename vsimd::scalar_type & lhs, const vsimd & rhs) \ |     accelerator_inline vInteger operator op (const typename vsimd::scalar_type & lhs, const vsimd & rhs) \ | ||||||
|     {\ |     {\ | ||||||
|       typedef typename vsimd::scalar_type scalar;\ |       typedef typename vsimd::scalar_type scalar;\ | ||||||
|       return Comparison(functor<scalar,scalar>(),lhs,rhs);\ |       return Comparison(functor<scalar,scalar>(),lhs,rhs);\ | ||||||
|     }\ |     }\ | ||||||
|   template<class vsimd>\ |   template<class vsimd>\ | ||||||
|     inline vInteger operator op(const iScalar<vsimd> &lhs,const iScalar<vsimd> &rhs)\ |     accelerator_inline vInteger operator op(const iScalar<vsimd> &lhs,const typename vsimd::scalar_type &rhs) \ | ||||||
|     {									\ |  | ||||||
|       return lhs._internal op rhs._internal;				\ |  | ||||||
|     }									\ |  | ||||||
|   template<class vsimd>\ |  | ||||||
|     inline vInteger operator op(const iScalar<vsimd> &lhs,const typename vsimd::scalar_type &rhs) \ |  | ||||||
|     {									\ |     {									\ | ||||||
|       return lhs._internal op rhs;					\ |       return lhs._internal op rhs;					\ | ||||||
|     }									\ |     }									\ | ||||||
|   template<class vsimd>\ |   template<class vsimd>\ | ||||||
|     inline vInteger operator op(const typename vsimd::scalar_type &lhs,const iScalar<vsimd> &rhs) \ |     accelerator_inline vInteger operator op(const typename vsimd::scalar_type &lhs,const iScalar<vsimd> &rhs) \ | ||||||
|     {									\ |     {									\ | ||||||
|       return lhs op rhs._internal;					\ |       return lhs op rhs._internal;					\ | ||||||
|     }									 |     }									\ | ||||||
| 
 | 
 | ||||||
|  | #define DECLARE_RELATIONAL(op,functor) \ | ||||||
|  |   DECLARE_RELATIONAL_EQ(op,functor)    \ | ||||||
|  |   template<class vsimd>\ | ||||||
|  |     accelerator_inline vInteger operator op(const iScalar<vsimd> &lhs,const iScalar<vsimd> &rhs)\ | ||||||
|  |     {									\ | ||||||
|  |       return lhs._internal op rhs._internal;				\ | ||||||
|  |     }									 | ||||||
| 
 | 
 | ||||||
| DECLARE_RELATIONAL(<,slt); | DECLARE_RELATIONAL(<,slt); | ||||||
| DECLARE_RELATIONAL(<=,sle); | DECLARE_RELATIONAL(<=,sle); | ||||||
| DECLARE_RELATIONAL(>,sgt); | DECLARE_RELATIONAL(>,sgt); | ||||||
| DECLARE_RELATIONAL(>=,sge); | DECLARE_RELATIONAL(>=,sge); | ||||||
| DECLARE_RELATIONAL(==,seq); | DECLARE_RELATIONAL_EQ(==,seq); | ||||||
| DECLARE_RELATIONAL(!=,sne); | DECLARE_RELATIONAL(!=,sne); | ||||||
| 
 | 
 | ||||||
| #undef DECLARE_RELATIONAL | #undef DECLARE_RELATIONAL | ||||||
| 
 | 
 | ||||||
| } | NAMESPACE_END(Grid); | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| #endif |  | ||||||
| @@ -1,4 +1,4 @@ | |||||||
|     /*************************************************************************************
 | /*************************************************************************************
 | ||||||
| 
 | 
 | ||||||
|     Grid physics library, www.github.com/paboyle/Grid  |     Grid physics library, www.github.com/paboyle/Grid  | ||||||
| 
 | 
 | ||||||
| @@ -23,18 +23,18 @@ Author: Peter Boyle <paboyle@ph.ed.ac.uk> | |||||||
|     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||||||
| 
 | 
 | ||||||
|     See the full license in the file "LICENSE" in the top level distribution directory |     See the full license in the file "LICENSE" in the top level distribution directory | ||||||
|     *************************************************************************************/ | *************************************************************************************/ | ||||||
|     /*  END LEGAL */ | /*  END LEGAL */ | ||||||
| #ifndef GRID_LATTICE_CONFORMABLE_H | #ifndef GRID_LATTICE_CONFORMABLE_H | ||||||
| #define GRID_LATTICE_CONFORMABLE_H | #define GRID_LATTICE_CONFORMABLE_H | ||||||
| 
 | 
 | ||||||
| namespace Grid { | NAMESPACE_BEGIN(Grid); | ||||||
| 
 |  | ||||||
|     template<class obj1,class obj2> void conformable(const Lattice<obj1> &lhs,const Lattice<obj2> &rhs) |  | ||||||
|     { |  | ||||||
|         assert(lhs._grid == rhs._grid); |  | ||||||
|         assert(lhs.checkerboard == rhs.checkerboard); |  | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|  | template<class obj1,class obj2> void conformable(const Lattice<obj1> &lhs,const Lattice<obj2> &rhs) | ||||||
|  | { | ||||||
|  |   assert(lhs.Grid() == rhs.Grid()); | ||||||
|  |   assert(lhs.Checkerboard() == rhs.Checkerboard()); | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | NAMESPACE_END(Grid); | ||||||
| #endif | #endif | ||||||
							
								
								
									
										74
									
								
								Grid/lattice/Lattice_coordinate.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								Grid/lattice/Lattice_coordinate.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,74 @@ | |||||||
|  | /************************************************************************************* | ||||||
|  |  | ||||||
|  |     Grid physics library, www.github.com/paboyle/Grid  | ||||||
|  |  | ||||||
|  |     Source file: ./lib/lattice/Lattice_coordinate.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 */ | ||||||
|  | #pragma once  | ||||||
|  |  | ||||||
|  | NAMESPACE_BEGIN(Grid); | ||||||
|  |  | ||||||
|  | template<class iobj> inline void LatticeCoordinate(Lattice<iobj> &l,int mu) | ||||||
|  | { | ||||||
|  |   typedef typename iobj::scalar_type scalar_type; | ||||||
|  |   typedef typename iobj::vector_type vector_type; | ||||||
|  |  | ||||||
|  |   GridBase *grid = l.Grid(); | ||||||
|  |   int Nsimd = grid->iSites(); | ||||||
|  |  | ||||||
|  |   Coordinate gcoor; | ||||||
|  |   ExtractBuffer<scalar_type> mergebuf(Nsimd); | ||||||
|  |  | ||||||
|  |   vector_type vI; | ||||||
|  |   auto l_v = l.View(); | ||||||
|  |   for(int o=0;o<grid->oSites();o++){ | ||||||
|  |     for(int i=0;i<grid->iSites();i++){ | ||||||
|  |       grid->RankIndexToGlobalCoor(grid->ThisRank(),o,i,gcoor); | ||||||
|  |       mergebuf[i]=(Integer)gcoor[mu]; | ||||||
|  |     } | ||||||
|  |     merge<vector_type,scalar_type>(vI,mergebuf); | ||||||
|  |     l_v[o]=vI; | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | // LatticeCoordinate(); | ||||||
|  | // FIXME for debug; deprecate this; made obscelete by  | ||||||
|  | template<class vobj> void lex_sites(Lattice<vobj> &l){ | ||||||
|  |   auto l_v = l.View(); | ||||||
|  |   Real *v_ptr = (Real *)&l_v[0]; | ||||||
|  |   size_t o_len = l.Grid()->oSites(); | ||||||
|  |   size_t v_len = sizeof(vobj)/sizeof(vRealF); | ||||||
|  |   size_t vec_len = vRealF::Nsimd(); | ||||||
|  |  | ||||||
|  |   for(int i=0;i<o_len;i++){ | ||||||
|  |     for(int j=0;j<v_len;j++){ | ||||||
|  |       for(int vv=0;vv<vec_len;vv+=2){ | ||||||
|  | 	v_ptr[i*v_len*vec_len+j*vec_len+vv  ]= i+vv*500; | ||||||
|  | 	v_ptr[i*v_len*vec_len+j*vec_len+vv+1]= i+vv*500; | ||||||
|  |       } | ||||||
|  |     }} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | NAMESPACE_END(Grid); | ||||||
|  |  | ||||||
							
								
								
									
										87
									
								
								Grid/lattice/Lattice_local.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										87
									
								
								Grid/lattice/Lattice_local.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,87 @@ | |||||||
|  | /************************************************************************************* | ||||||
|  |  | ||||||
|  |     Grid physics library, www.github.com/paboyle/Grid  | ||||||
|  |  | ||||||
|  |     Source file: ./lib/lattice/Lattice_local.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_LATTICE_LOCALREDUCTION_H | ||||||
|  | #define GRID_LATTICE_LOCALREDUCTION_H | ||||||
|  |  | ||||||
|  | /////////////////////////////////////////////// | ||||||
|  | // localInner, localNorm, outerProduct | ||||||
|  | /////////////////////////////////////////////// | ||||||
|  |  | ||||||
|  | NAMESPACE_BEGIN(Grid); | ||||||
|  |  | ||||||
|  | ///////////////////////////////////////////////////// | ||||||
|  | // Non site, reduced locally reduced routines | ||||||
|  | ///////////////////////////////////////////////////// | ||||||
|  |    | ||||||
|  | // localNorm2, | ||||||
|  | template<class vobj> | ||||||
|  | inline auto localNorm2 (const Lattice<vobj> &rhs)-> Lattice<typename vobj::tensor_reduced> | ||||||
|  | { | ||||||
|  |   Lattice<typename vobj::tensor_reduced> ret(rhs.Grid()); | ||||||
|  |   auto rhs_v = rhs.View(); | ||||||
|  |   auto ret_v = ret.View(); | ||||||
|  |   accelerator_for(ss,rhs_v.size(),vobj::Nsimd(),{ | ||||||
|  |     coalescedWrite(ret_v[ss],innerProduct(rhs_v(ss),rhs_v(ss))); | ||||||
|  |   }); | ||||||
|  |   return ret; | ||||||
|  | } | ||||||
|  |    | ||||||
|  | // localInnerProduct | ||||||
|  | template<class vobj> | ||||||
|  | inline auto localInnerProduct (const Lattice<vobj> &lhs,const Lattice<vobj> &rhs) -> Lattice<typename vobj::tensor_reduced> | ||||||
|  | { | ||||||
|  |   Lattice<typename vobj::tensor_reduced> ret(rhs.Grid()); | ||||||
|  |   auto lhs_v = lhs.View(); | ||||||
|  |   auto rhs_v = rhs.View(); | ||||||
|  |   auto ret_v = ret.View(); | ||||||
|  |   accelerator_for(ss,rhs_v.size(),vobj::Nsimd(),{ | ||||||
|  |     coalescedWrite(ret_v[ss],innerProduct(lhs_v(ss),rhs_v(ss))); | ||||||
|  |   }); | ||||||
|  |   return ret; | ||||||
|  | } | ||||||
|  |    | ||||||
|  | // outerProduct Scalar x Scalar -> Scalar | ||||||
|  | //              Vector x Vector -> Matrix | ||||||
|  | template<class ll,class rr> | ||||||
|  | inline auto outerProduct (const Lattice<ll> &lhs,const Lattice<rr> &rhs) -> Lattice<decltype(outerProduct(ll(),rr()))> | ||||||
|  | { | ||||||
|  |   typedef decltype(coalescedRead(ll())) sll; | ||||||
|  |   typedef decltype(coalescedRead(rr())) srr; | ||||||
|  |   Lattice<decltype(outerProduct(ll(),rr()))> ret(rhs.Grid()); | ||||||
|  |   auto lhs_v = lhs.View(); | ||||||
|  |   auto rhs_v = rhs.View(); | ||||||
|  |   auto ret_v = ret.View(); | ||||||
|  |   accelerator_for(ss,rhs_v.size(),1,{ | ||||||
|  |     // FIXME had issues with scalar version of outer  | ||||||
|  |     // Use vector [] operator and don't read coalesce this loop | ||||||
|  |     ret_v[ss]=outerProduct(lhs_v[ss],rhs_v[ss]); | ||||||
|  |   }); | ||||||
|  |   return ret; | ||||||
|  | } | ||||||
|  | NAMESPACE_END(Grid); | ||||||
|  | #endif | ||||||
							
								
								
									
										202
									
								
								Grid/lattice/Lattice_matrix_reduction.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										202
									
								
								Grid/lattice/Lattice_matrix_reduction.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,202 @@ | |||||||
|  | /************************************************************************************* | ||||||
|  |     Grid physics library, www.github.com/paboyle/Grid  | ||||||
|  |     Source file: ./lib/lattice/Lattice_reduction.h | ||||||
|  |     Copyright (C) 2015 | ||||||
|  | Author: Azusa Yamaguchi <ayamaguc@staffmail.ed.ac.uk> | ||||||
|  | Author: Peter Boyle <paboyle@ph.ed.ac.uk> | ||||||
|  | Author: paboyle <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 */ | ||||||
|  | #pragma once  | ||||||
|  | #include <Grid/Grid_Eigen_Dense.h> | ||||||
|  |  | ||||||
|  | #ifdef GRID_WARN_SUBOPTIMAL | ||||||
|  | #warning "Optimisation alert all these reduction loops are NOT threaded " | ||||||
|  | #endif      | ||||||
|  |  | ||||||
|  | NAMESPACE_BEGIN(Grid); | ||||||
|  |  | ||||||
|  | template<class vobj> | ||||||
|  | static void sliceMaddMatrix (Lattice<vobj> &R,Eigen::MatrixXcd &aa,const Lattice<vobj> &X,const Lattice<vobj> &Y,int Orthog,RealD scale=1.0)  | ||||||
|  | {     | ||||||
|  |   typedef typename vobj::scalar_object sobj; | ||||||
|  |   typedef typename vobj::scalar_type scalar_type; | ||||||
|  |   typedef typename vobj::vector_type vector_type; | ||||||
|  |  | ||||||
|  |   int Nblock = X.Grid()->GlobalDimensions()[Orthog]; | ||||||
|  |  | ||||||
|  |   GridBase *FullGrid  = X.Grid(); | ||||||
|  |   //  GridBase *SliceGrid = makeSubSliceGrid(FullGrid,Orthog); | ||||||
|  |  | ||||||
|  |   //  Lattice<vobj> Xslice(SliceGrid); | ||||||
|  |   //  Lattice<vobj> Rslice(SliceGrid); | ||||||
|  |  | ||||||
|  |   assert( FullGrid->_simd_layout[Orthog]==1); | ||||||
|  |  | ||||||
|  |   //FIXME package in a convenient iterator | ||||||
|  |   //Should loop over a plane orthogonal to direction "Orthog" | ||||||
|  |   int stride=FullGrid->_slice_stride[Orthog]; | ||||||
|  |   int block =FullGrid->_slice_block [Orthog]; | ||||||
|  |   int nblock=FullGrid->_slice_nblock[Orthog]; | ||||||
|  |   int ostride=FullGrid->_ostride[Orthog]; | ||||||
|  |   auto X_v = X.View(); | ||||||
|  |   auto Y_v = Y.View(); | ||||||
|  |   auto R_v = R.View(); | ||||||
|  |   thread_region | ||||||
|  |   { | ||||||
|  |     std::vector<vobj> s_x(Nblock); | ||||||
|  |  | ||||||
|  |     thread_loop_collapse2( (int n=0;n<nblock;n++),{ | ||||||
|  |       for(int b=0;b<block;b++){ | ||||||
|  | 	int o  = n*stride + b; | ||||||
|  |  | ||||||
|  | 	for(int i=0;i<Nblock;i++){ | ||||||
|  | 	  s_x[i] = X_v[o+i*ostride]; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	vobj dot; | ||||||
|  | 	for(int i=0;i<Nblock;i++){ | ||||||
|  | 	  dot = Y_v[o+i*ostride]; | ||||||
|  | 	  for(int j=0;j<Nblock;j++){ | ||||||
|  | 	    dot = dot + s_x[j]*(scale*aa(j,i)); | ||||||
|  | 	  } | ||||||
|  | 	  R_v[o+i*ostride]=dot; | ||||||
|  | 	} | ||||||
|  |       }}); | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | template<class vobj> | ||||||
|  | static void sliceMulMatrix (Lattice<vobj> &R,Eigen::MatrixXcd &aa,const Lattice<vobj> &X,int Orthog,RealD scale=1.0)  | ||||||
|  | {     | ||||||
|  |   typedef typename vobj::scalar_object sobj; | ||||||
|  |   typedef typename vobj::scalar_type scalar_type; | ||||||
|  |   typedef typename vobj::vector_type vector_type; | ||||||
|  |  | ||||||
|  |   int Nblock = X.Grid()->GlobalDimensions()[Orthog]; | ||||||
|  |  | ||||||
|  |   GridBase *FullGrid  = X.Grid(); | ||||||
|  |   assert( FullGrid->_simd_layout[Orthog]==1); | ||||||
|  |  | ||||||
|  |   //FIXME package in a convenient iterator | ||||||
|  |   //Should loop over a plane orthogonal to direction "Orthog" | ||||||
|  |   int stride=FullGrid->_slice_stride[Orthog]; | ||||||
|  |   int block =FullGrid->_slice_block [Orthog]; | ||||||
|  |   int nblock=FullGrid->_slice_nblock[Orthog]; | ||||||
|  |   int ostride=FullGrid->_ostride[Orthog]; | ||||||
|  |  | ||||||
|  |   auto X_v = X.View(); | ||||||
|  |   auto R_v = R.View(); | ||||||
|  |  | ||||||
|  |   thread_region | ||||||
|  |   { | ||||||
|  |     std::vector<vobj> s_x(Nblock); | ||||||
|  |      | ||||||
|  |     thread_loop_collapse2( (int n=0;n<nblock;n++),{ | ||||||
|  |       for(int b=0;b<block;b++){ | ||||||
|  | 	int o  = n*stride + b; | ||||||
|  |  | ||||||
|  | 	for(int i=0;i<Nblock;i++){ | ||||||
|  | 	  s_x[i] = X_v[o+i*ostride]; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	vobj dot; | ||||||
|  | 	for(int i=0;i<Nblock;i++){ | ||||||
|  | 	  dot = s_x[0]*(scale*aa(0,i)); | ||||||
|  | 	  for(int j=1;j<Nblock;j++){ | ||||||
|  | 	    dot = dot + s_x[j]*(scale*aa(j,i)); | ||||||
|  | 	  } | ||||||
|  | 	  R_v[o+i*ostride]=dot; | ||||||
|  | 	} | ||||||
|  |     }}); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  | }; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | template<class vobj> | ||||||
|  | static void sliceInnerProductMatrix(  Eigen::MatrixXcd &mat, const Lattice<vobj> &lhs,const Lattice<vobj> &rhs,int Orthog)  | ||||||
|  | { | ||||||
|  |   typedef typename vobj::scalar_object sobj; | ||||||
|  |   typedef typename vobj::scalar_type scalar_type; | ||||||
|  |   typedef typename vobj::vector_type vector_type; | ||||||
|  |    | ||||||
|  |   GridBase *FullGrid  = lhs.Grid(); | ||||||
|  |   //  GridBase *SliceGrid = makeSubSliceGrid(FullGrid,Orthog); | ||||||
|  |    | ||||||
|  |   int Nblock = FullGrid->GlobalDimensions()[Orthog]; | ||||||
|  |    | ||||||
|  |   //  Lattice<vobj> Lslice(SliceGrid); | ||||||
|  |   //  Lattice<vobj> Rslice(SliceGrid); | ||||||
|  |    | ||||||
|  |   mat = Eigen::MatrixXcd::Zero(Nblock,Nblock); | ||||||
|  |  | ||||||
|  |   assert( FullGrid->_simd_layout[Orthog]==1); | ||||||
|  |   //  int nh =  FullGrid->_ndimension; | ||||||
|  |   //  int nl = SliceGrid->_ndimension; | ||||||
|  |   //  int nl = nh-1; | ||||||
|  |  | ||||||
|  |   //FIXME package in a convenient iterator | ||||||
|  |   //Should loop over a plane orthogonal to direction "Orthog" | ||||||
|  |   int stride=FullGrid->_slice_stride[Orthog]; | ||||||
|  |   int block =FullGrid->_slice_block [Orthog]; | ||||||
|  |   int nblock=FullGrid->_slice_nblock[Orthog]; | ||||||
|  |   int ostride=FullGrid->_ostride[Orthog]; | ||||||
|  |  | ||||||
|  |   typedef typename vobj::vector_typeD vector_typeD; | ||||||
|  |   auto lhs_v = lhs.View(); | ||||||
|  |   auto rhs_v = rhs.View(); | ||||||
|  |   thread_region { | ||||||
|  |     std::vector<vobj> Left(Nblock); | ||||||
|  |     std::vector<vobj> Right(Nblock); | ||||||
|  |     Eigen::MatrixXcd  mat_thread = Eigen::MatrixXcd::Zero(Nblock,Nblock); | ||||||
|  |  | ||||||
|  |     thread_loop_collapse2((int n=0;n<nblock;n++),{ | ||||||
|  |       for(int b=0;b<block;b++){ | ||||||
|  |  | ||||||
|  | 	int o  = n*stride + b; | ||||||
|  |  | ||||||
|  | 	for(int i=0;i<Nblock;i++){ | ||||||
|  | 	  Left [i] = lhs_v[o+i*ostride]; | ||||||
|  | 	  Right[i] = rhs_v[o+i*ostride]; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	for(int i=0;i<Nblock;i++){ | ||||||
|  | 	  for(int j=0;j<Nblock;j++){ | ||||||
|  | 	    auto tmp = innerProduct(Left[i],Right[j]); | ||||||
|  | 	    auto rtmp = TensorRemove(tmp); | ||||||
|  | 	    ComplexD z = Reduce(rtmp); | ||||||
|  | 	    mat_thread(i,j) += std::complex<double>(real(z),imag(z)); | ||||||
|  | 	  }} | ||||||
|  |     }}); | ||||||
|  |     thread_critical { | ||||||
|  |       mat += mat_thread; | ||||||
|  |     }   | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   for(int i=0;i<Nblock;i++){ | ||||||
|  |     for(int j=0;j<Nblock;j++){ | ||||||
|  |       ComplexD sum = mat(i,j); | ||||||
|  |       FullGrid->GlobalSum(sum); | ||||||
|  |       mat(i,j)=sum; | ||||||
|  |     }} | ||||||
|  |  | ||||||
|  |   return; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | NAMESPACE_END(Grid); | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
							
								
								
									
										217
									
								
								Grid/lattice/Lattice_peekpoke.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										217
									
								
								Grid/lattice/Lattice_peekpoke.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,217 @@ | |||||||
|  | /************************************************************************************* | ||||||
|  |  | ||||||
|  |     Grid physics library, www.github.com/paboyle/Grid  | ||||||
|  |  | ||||||
|  |     Source file: ./lib/lattice/Lattice_peekpoke.h | ||||||
|  |  | ||||||
|  |     Copyright (C) 2015 | ||||||
|  |  | ||||||
|  | Author: Azusa Yamaguchi <ayamaguc@staffmail.ed.ac.uk> | ||||||
|  | Author: Peter Boyle <paboyle@ph.ed.ac.uk> | ||||||
|  | Author: Peter Boyle <peterboyle@Peters-MacBook-Pro-2.local> | ||||||
|  |  | ||||||
|  |     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_LATTICE_PEEK_H | ||||||
|  | #define GRID_LATTICE_PEEK_H | ||||||
|  |  | ||||||
|  | /////////////////////////////////////////////// | ||||||
|  | // Peeking and poking around | ||||||
|  | /////////////////////////////////////////////// | ||||||
|  |  | ||||||
|  | NAMESPACE_BEGIN(Grid); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | // FIXME accelerator_loop and accelerator_inline these | ||||||
|  | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  | // Peek internal indices of a Lattice object | ||||||
|  | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  | template<int Index,class vobj>  | ||||||
|  | auto PeekIndex(const Lattice<vobj> &lhs,int i) -> Lattice<decltype(peekIndex<Index>(vobj(),i))> | ||||||
|  | { | ||||||
|  |   Lattice<decltype(peekIndex<Index>(vobj(),i))> ret(lhs.Grid()); | ||||||
|  |   ret.Checkerboard()=lhs.Checkerboard(); | ||||||
|  |   auto ret_v = ret.View(); | ||||||
|  |   auto lhs_v = lhs.View(); | ||||||
|  |   thread_for( ss, lhs_v.size(), { | ||||||
|  |     ret_v[ss] = peekIndex<Index>(lhs_v[ss],i); | ||||||
|  |   }); | ||||||
|  |   return ret; | ||||||
|  | }; | ||||||
|  | template<int Index,class vobj>  | ||||||
|  | auto PeekIndex(const Lattice<vobj> &lhs,int i,int j) -> Lattice<decltype(peekIndex<Index>(vobj(),i,j))> | ||||||
|  | { | ||||||
|  |   Lattice<decltype(peekIndex<Index>(vobj(),i,j))> ret(lhs.Grid()); | ||||||
|  |   ret.Checkerboard()=lhs.Checkerboard(); | ||||||
|  |   auto ret_v = ret.View(); | ||||||
|  |   auto lhs_v = lhs.View(); | ||||||
|  |   thread_for( ss, lhs_v.size(), { | ||||||
|  |     ret_v[ss] = peekIndex<Index>(lhs_v[ss],i,j); | ||||||
|  |   }); | ||||||
|  |   return ret; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  | // Poke internal indices of a Lattice object | ||||||
|  | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  | template<int Index,class vobj>   | ||||||
|  | void PokeIndex(Lattice<vobj> &lhs,const Lattice<decltype(peekIndex<Index>(vobj(),0))> & rhs,int i) | ||||||
|  | { | ||||||
|  |   auto rhs_v = rhs.View(); | ||||||
|  |   auto lhs_v = lhs.View(); | ||||||
|  |   thread_for( ss, lhs_v.size(), { | ||||||
|  |     pokeIndex<Index>(lhs_v[ss],rhs_v[ss],i); | ||||||
|  |   }); | ||||||
|  | } | ||||||
|  | template<int Index,class vobj>  | ||||||
|  | void PokeIndex(Lattice<vobj> &lhs,const Lattice<decltype(peekIndex<Index>(vobj(),0,0))> & rhs,int i,int j) | ||||||
|  | { | ||||||
|  |   auto rhs_v = rhs.View(); | ||||||
|  |   auto lhs_v = lhs.View(); | ||||||
|  |   thread_for( ss, lhs_v.size(), { | ||||||
|  |     pokeIndex<Index>(lhs_v[ss],rhs_v[ss],i,j); | ||||||
|  |   }); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | ////////////////////////////////////////////////////// | ||||||
|  | // Poke a scalar object into the SIMD array | ||||||
|  | ////////////////////////////////////////////////////// | ||||||
|  | template<class vobj,class sobj>  | ||||||
|  | void pokeSite(const sobj &s,Lattice<vobj> &l,const Coordinate &site){ | ||||||
|  |  | ||||||
|  |   GridBase *grid=l.Grid(); | ||||||
|  |  | ||||||
|  |   typedef typename vobj::scalar_type scalar_type; | ||||||
|  |   typedef typename vobj::vector_type vector_type; | ||||||
|  |  | ||||||
|  |   int Nsimd = grid->Nsimd(); | ||||||
|  |  | ||||||
|  |   assert( l.Checkerboard()== l.Grid()->CheckerBoard(site)); | ||||||
|  |   assert( sizeof(sobj)*Nsimd == sizeof(vobj)); | ||||||
|  |  | ||||||
|  |   int rank,odx,idx; | ||||||
|  |   // Optional to broadcast from node 0. | ||||||
|  |   grid->GlobalCoorToRankIndex(rank,odx,idx,site); | ||||||
|  |   grid->Broadcast(grid->BossRank(),s); | ||||||
|  |  | ||||||
|  |   // extract-modify-merge cycle is easiest way and this is not perf critical | ||||||
|  |   ExtractBuffer<sobj> buf(Nsimd); | ||||||
|  |   auto l_v = l.View(); | ||||||
|  |   if ( rank == grid->ThisRank() ) { | ||||||
|  |     extract(l_v[odx],buf); | ||||||
|  |     buf[idx] = s; | ||||||
|  |     merge(l_v[odx],buf); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   return; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ////////////////////////////////////////////////////////// | ||||||
|  | // Peek a scalar object from the SIMD array | ||||||
|  | ////////////////////////////////////////////////////////// | ||||||
|  | template<class vobj,class sobj> | ||||||
|  | void peekSite(sobj &s,const Lattice<vobj> &l,const Coordinate &site){ | ||||||
|  |          | ||||||
|  |   GridBase *grid=l.Grid(); | ||||||
|  |  | ||||||
|  |   typedef typename vobj::scalar_type scalar_type; | ||||||
|  |   typedef typename vobj::vector_type vector_type; | ||||||
|  |  | ||||||
|  |   int Nsimd = grid->Nsimd(); | ||||||
|  |  | ||||||
|  |   assert( l.Checkerboard() == l.Grid()->CheckerBoard(site)); | ||||||
|  |  | ||||||
|  |   int rank,odx,idx; | ||||||
|  |   grid->GlobalCoorToRankIndex(rank,odx,idx,site); | ||||||
|  |  | ||||||
|  |   ExtractBuffer<sobj> buf(Nsimd); | ||||||
|  |   auto l_v = l.View(); | ||||||
|  |   extract(l_v[odx],buf); | ||||||
|  |  | ||||||
|  |   s = buf[idx]; | ||||||
|  |  | ||||||
|  |   grid->Broadcast(rank,s); | ||||||
|  |  | ||||||
|  |   return; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ////////////////////////////////////////////////////////// | ||||||
|  | // Peek a scalar object from the SIMD array | ||||||
|  | ////////////////////////////////////////////////////////// | ||||||
|  | template<class vobj,class sobj> | ||||||
|  | void peekLocalSite(sobj &s,const Lattice<vobj> &l,Coordinate &site){ | ||||||
|  |          | ||||||
|  |   GridBase *grid = l.Grid(); | ||||||
|  |  | ||||||
|  |   typedef typename vobj::scalar_type scalar_type; | ||||||
|  |   typedef typename vobj::vector_type vector_type; | ||||||
|  |  | ||||||
|  |   int Nsimd = grid->Nsimd(); | ||||||
|  |  | ||||||
|  |   assert( l.Checkerboard()== l.Grid()->CheckerBoard(site)); | ||||||
|  |   assert( sizeof(sobj)*Nsimd == sizeof(vobj)); | ||||||
|  |  | ||||||
|  |   static const int words=sizeof(vobj)/sizeof(vector_type); | ||||||
|  |   int odx,idx; | ||||||
|  |   idx= grid->iIndex(site); | ||||||
|  |   odx= grid->oIndex(site); | ||||||
|  |    | ||||||
|  |   auto l_v = l.View(); | ||||||
|  |   scalar_type * vp = (scalar_type *)&l_v[odx]; | ||||||
|  |   scalar_type * pt = (scalar_type *)&s; | ||||||
|  |        | ||||||
|  |   for(int w=0;w<words;w++){ | ||||||
|  |     pt[w] = vp[idx+w*Nsimd]; | ||||||
|  |   } | ||||||
|  |        | ||||||
|  |   return; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | template<class vobj,class sobj> | ||||||
|  | void pokeLocalSite(const sobj &s,Lattice<vobj> &l,Coordinate &site){ | ||||||
|  |  | ||||||
|  |   GridBase *grid=l.Grid(); | ||||||
|  |  | ||||||
|  |   typedef typename vobj::scalar_type scalar_type; | ||||||
|  |   typedef typename vobj::vector_type vector_type; | ||||||
|  |  | ||||||
|  |   int Nsimd = grid->Nsimd(); | ||||||
|  |  | ||||||
|  |   assert( l.Checkerboard()== l.Grid()->CheckerBoard(site)); | ||||||
|  |   assert( sizeof(sobj)*Nsimd == sizeof(vobj)); | ||||||
|  |  | ||||||
|  |   static const int words=sizeof(vobj)/sizeof(vector_type); | ||||||
|  |   int odx,idx; | ||||||
|  |   idx= grid->iIndex(site); | ||||||
|  |   odx= grid->oIndex(site); | ||||||
|  |  | ||||||
|  |   auto l_v = l.View(); | ||||||
|  |   scalar_type * vp = (scalar_type *)&l_v[odx]; | ||||||
|  |   scalar_type * pt = (scalar_type *)&s; | ||||||
|  |   for(int w=0;w<words;w++){ | ||||||
|  |     vp[idx+w*Nsimd] = pt[w]; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   return; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | NAMESPACE_END(Grid); | ||||||
|  | #endif | ||||||
|  |  | ||||||
| @@ -1,4 +1,4 @@ | |||||||
|     /*************************************************************************************
 | /*************************************************************************************
 | ||||||
| 
 | 
 | ||||||
|     Grid physics library, www.github.com/paboyle/Grid  |     Grid physics library, www.github.com/paboyle/Grid  | ||||||
| 
 | 
 | ||||||
| @@ -25,8 +25,8 @@ Author: neo <cossu@post.kek.jp> | |||||||
|     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||||||
| 
 | 
 | ||||||
|     See the full license in the file "LICENSE" in the top level distribution directory |     See the full license in the file "LICENSE" in the top level distribution directory | ||||||
|     *************************************************************************************/ | *************************************************************************************/ | ||||||
|     /*  END LEGAL */ | /*  END LEGAL */ | ||||||
| #ifndef GRID_LATTICE_REALITY_H | #ifndef GRID_LATTICE_REALITY_H | ||||||
| #define GRID_LATTICE_REALITY_H | #define GRID_LATTICE_REALITY_H | ||||||
| 
 | 
 | ||||||
| @@ -36,22 +36,28 @@ Author: neo <cossu@post.kek.jp> | |||||||
| // The choice of burying complex in the SIMD
 | // The choice of burying complex in the SIMD
 | ||||||
| // is making the use of "real" and "imag" very cumbersome
 | // is making the use of "real" and "imag" very cumbersome
 | ||||||
| 
 | 
 | ||||||
| namespace Grid { | NAMESPACE_BEGIN(Grid); | ||||||
| 
 | 
 | ||||||
|     template<class vobj> inline Lattice<vobj> adj(const Lattice<vobj> &lhs){ | template<class vobj> inline Lattice<vobj> adj(const Lattice<vobj> &lhs){ | ||||||
|         Lattice<vobj> ret(lhs._grid); |   Lattice<vobj> ret(lhs.Grid()); | ||||||
| 	parallel_for(int ss=0;ss<lhs._grid->oSites();ss++){ |   auto lhs_v = lhs.View(); | ||||||
|             ret._odata[ss] = adj(lhs._odata[ss]); |   auto ret_v = ret.View(); | ||||||
|         } |   accelerator_for( ss, lhs_v.size(), vobj::Nsimd(), { | ||||||
|         return ret; |     coalescedWrite(ret_v[ss], adj(lhs_v(ss))); | ||||||
|     }; |   }); | ||||||
|  |   return ret; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | template<class vobj> inline Lattice<vobj> conjugate(const Lattice<vobj> &lhs){ | ||||||
|  |   Lattice<vobj> ret(lhs.Grid()); | ||||||
|  |   auto lhs_v = lhs.View(); | ||||||
|  |   auto ret_v = ret.View(); | ||||||
|  |   accelerator_for( ss, lhs_v.size(), vobj::Nsimd(), { | ||||||
|  |     coalescedWrite( ret_v[ss] , conjugate(lhs_v(ss))); | ||||||
|  |   }); | ||||||
|  |   return ret; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | NAMESPACE_END(Grid); | ||||||
| 
 | 
 | ||||||
|     template<class vobj> inline Lattice<vobj> conjugate(const Lattice<vobj> &lhs){ |  | ||||||
|         Lattice<vobj> ret(lhs._grid); |  | ||||||
| 	parallel_for(int ss=0;ss<lhs._grid->oSites();ss++){ |  | ||||||
| 	  ret._odata[ss] = conjugate(lhs._odata[ss]); |  | ||||||
|         } |  | ||||||
|         return ret; |  | ||||||
|     }; |  | ||||||
| } |  | ||||||
| #endif | #endif | ||||||
							
								
								
									
										787
									
								
								Grid/lattice/Lattice_reduction.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										787
									
								
								Grid/lattice/Lattice_reduction.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,787 @@ | |||||||
|  | /************************************************************************************* | ||||||
|  |     Grid physics library, www.github.com/paboyle/Grid  | ||||||
|  |     Source file: ./lib/lattice/Lattice_reduction.h | ||||||
|  |     Copyright (C) 2015 | ||||||
|  | Author: Azusa Yamaguchi <ayamaguc@staffmail.ed.ac.uk> | ||||||
|  | Author: Peter Boyle <paboyle@ph.ed.ac.uk> | ||||||
|  | Author: paboyle <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 */ | ||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #include <Grid/Grid_Eigen_Dense.h> | ||||||
|  |  | ||||||
|  |  | ||||||
|  | #ifdef GRID_NVCC | ||||||
|  | #include <Grid/lattice/Lattice_reduction_gpu.h> | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | NAMESPACE_BEGIN(Grid); | ||||||
|  |  | ||||||
|  | ////////////////////////////////////////////////////// | ||||||
|  | // FIXME this should promote to double and accumulate | ||||||
|  | ////////////////////////////////////////////////////// | ||||||
|  | template<class vobj> | ||||||
|  | inline typename vobj::scalar_object sum_cpu(const vobj *arg, Integer osites) | ||||||
|  | { | ||||||
|  |   typedef typename vobj::scalar_object  sobj; | ||||||
|  |  | ||||||
|  |   const int Nsimd = vobj::Nsimd(); | ||||||
|  |   const int nthread = GridThread::GetThreads(); | ||||||
|  |  | ||||||
|  |   Vector<sobj> sumarray(nthread); | ||||||
|  |   for(int i=0;i<nthread;i++){ | ||||||
|  |     sumarray[i]=Zero(); | ||||||
|  |   } | ||||||
|  |    | ||||||
|  |   thread_for(thr,nthread, { | ||||||
|  |     int nwork, mywork, myoff; | ||||||
|  |     nwork = osites; | ||||||
|  |     GridThread::GetWork(nwork,thr,mywork,myoff); | ||||||
|  |     vobj vvsum=Zero(); | ||||||
|  |     for(int ss=myoff;ss<mywork+myoff; ss++){ | ||||||
|  |       vvsum = vvsum + arg[ss]; | ||||||
|  |     } | ||||||
|  |     sumarray[thr]=Reduce(vvsum); | ||||||
|  |   }); | ||||||
|  |    | ||||||
|  |   sobj ssum=Zero();  // sum across threads | ||||||
|  |   for(int i=0;i<nthread;i++){ | ||||||
|  |     ssum = ssum+sumarray[i]; | ||||||
|  |   }  | ||||||
|  |    | ||||||
|  |   return ssum; | ||||||
|  | } | ||||||
|  | template<class vobj> | ||||||
|  | inline typename vobj::scalar_object sum(const vobj *arg, Integer osites) | ||||||
|  | { | ||||||
|  | #ifdef GRID_NVCC | ||||||
|  |   return sum_gpu(arg,osites); | ||||||
|  | #else | ||||||
|  |   return sum_cpu(arg,osites); | ||||||
|  | #endif   | ||||||
|  | } | ||||||
|  | template<class vobj> | ||||||
|  | inline typename vobj::scalar_object sum(const Lattice<vobj> &arg) | ||||||
|  | { | ||||||
|  |   auto arg_v = arg.View(); | ||||||
|  |   Integer osites = arg.Grid()->oSites(); | ||||||
|  |   auto ssum= sum(&arg_v[0],osites); | ||||||
|  |   arg.Grid()->GlobalSum(ssum); | ||||||
|  |   return ssum; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  | // Deterministic Reduction operations | ||||||
|  | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  | template<class vobj> inline RealD norm2(const Lattice<vobj> &arg){ | ||||||
|  |   ComplexD nrm = innerProduct(arg,arg); | ||||||
|  |   return real(nrm);  | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Double inner product | ||||||
|  | template<class vobj> | ||||||
|  | inline ComplexD innerProduct(const Lattice<vobj> &left,const Lattice<vobj> &right) | ||||||
|  | { | ||||||
|  |   typedef typename vobj::scalar_type scalar_type; | ||||||
|  |   typedef typename vobj::vector_typeD vector_type; | ||||||
|  |   ComplexD  nrm; | ||||||
|  |    | ||||||
|  |   GridBase *grid = left.Grid(); | ||||||
|  |    | ||||||
|  |   // Might make all code paths go this way. | ||||||
|  |   auto left_v = left.View(); | ||||||
|  |   auto right_v=right.View(); | ||||||
|  |  | ||||||
|  |   const uint64_t nsimd = grid->Nsimd(); | ||||||
|  |   const uint64_t sites = grid->oSites(); | ||||||
|  |    | ||||||
|  | #ifdef GRID_NVCC | ||||||
|  |   // GPU - SIMT lane compliance... | ||||||
|  |   typedef decltype(innerProduct(left_v[0],right_v[0])) inner_t; | ||||||
|  |   Vector<inner_t> inner_tmp(sites); | ||||||
|  |   auto inner_tmp_v = &inner_tmp[0]; | ||||||
|  |    | ||||||
|  |  | ||||||
|  |   accelerator_for( ss, sites, nsimd,{ | ||||||
|  |       auto x_l = left_v(ss); | ||||||
|  |       auto y_l = right_v(ss); | ||||||
|  |       coalescedWrite(inner_tmp_v[ss],innerProduct(x_l,y_l)); | ||||||
|  |   }) | ||||||
|  |  | ||||||
|  |   // This is in single precision and fails some tests | ||||||
|  |   // Need a sumD that sums in double | ||||||
|  |   nrm = TensorRemove(sumD_gpu(inner_tmp_v,sites));   | ||||||
|  | #else | ||||||
|  |   // CPU  | ||||||
|  |   typedef decltype(innerProductD(left_v[0],right_v[0])) inner_t; | ||||||
|  |   Vector<inner_t> inner_tmp(sites); | ||||||
|  |   auto inner_tmp_v = &inner_tmp[0]; | ||||||
|  |    | ||||||
|  |   accelerator_for( ss, sites, nsimd,{ | ||||||
|  |       auto x_l = left_v[ss]; | ||||||
|  |       auto y_l = right_v[ss]; | ||||||
|  |       inner_tmp_v[ss]=innerProductD(x_l,y_l); | ||||||
|  |   }) | ||||||
|  |   nrm = TensorRemove(sum(inner_tmp_v,sites)); | ||||||
|  | #endif | ||||||
|  |   grid->GlobalSum(nrm); | ||||||
|  |  | ||||||
|  |   return nrm; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | ///////////////////////// | ||||||
|  | // 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)  | ||||||
|  | { | ||||||
|  |   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(); | ||||||
|  |  | ||||||
|  |   auto x_v=x.View(); | ||||||
|  |   auto y_v=y.View(); | ||||||
|  |   auto z_v=z.View(); | ||||||
|  |  | ||||||
|  |   const uint64_t nsimd = grid->Nsimd(); | ||||||
|  |   const uint64_t sites = grid->oSites(); | ||||||
|  |    | ||||||
|  | #ifdef GRID_NVCC | ||||||
|  |   // GPU | ||||||
|  |   typedef decltype(innerProduct(x_v[0],y_v[0])) inner_t; | ||||||
|  |   Vector<inner_t> inner_tmp(sites); | ||||||
|  |   auto inner_tmp_v = &inner_tmp[0]; | ||||||
|  |  | ||||||
|  |   accelerator_for( ss, sites, nsimd,{ | ||||||
|  |       auto tmp = a*x_v(ss)+b*y_v(ss); | ||||||
|  |       coalescedWrite(inner_tmp_v[ss],innerProduct(tmp,tmp)); | ||||||
|  |       coalescedWrite(z_v[ss],tmp); | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   nrm = real(TensorRemove(sumD_gpu(inner_tmp_v,sites))); | ||||||
|  | #else | ||||||
|  |   // CPU  | ||||||
|  |   typedef decltype(innerProductD(x_v[0],y_v[0])) inner_t; | ||||||
|  |   Vector<inner_t> inner_tmp(sites); | ||||||
|  |   auto inner_tmp_v = &inner_tmp[0]; | ||||||
|  |    | ||||||
|  |   accelerator_for( ss, sites, nsimd,{ | ||||||
|  |       auto tmp = a*x_v(ss)+b*y_v(ss); | ||||||
|  |       inner_tmp_v[ss]=innerProductD(tmp,tmp); | ||||||
|  |       z_v[ss]=tmp; | ||||||
|  |   }); | ||||||
|  |   // Already promoted to double | ||||||
|  |   nrm = real(TensorRemove(sum(inner_tmp_v,sites))); | ||||||
|  | #endif | ||||||
|  |   grid->GlobalSum(nrm); | ||||||
|  |   return nrm;  | ||||||
|  | } | ||||||
|  |  | ||||||
|  |   | ||||||
|  | template<class Op,class T1> | ||||||
|  | inline auto sum(const LatticeUnaryExpression<Op,T1> & expr) | ||||||
|  |   ->typename decltype(expr.op.func(eval(0,expr.arg1)))::scalar_object | ||||||
|  | { | ||||||
|  |   return sum(closure(expr)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | template<class Op,class T1,class T2> | ||||||
|  | inline auto sum(const LatticeBinaryExpression<Op,T1,T2> & expr) | ||||||
|  |       ->typename decltype(expr.op.func(eval(0,expr.arg1),eval(0,expr.arg2)))::scalar_object | ||||||
|  | { | ||||||
|  |   return sum(closure(expr)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | template<class Op,class T1,class T2,class T3> | ||||||
|  | inline auto sum(const LatticeTrinaryExpression<Op,T1,T2,T3> & expr) | ||||||
|  |   ->typename decltype(expr.op.func(eval(0,expr.arg1), | ||||||
|  | 				      eval(0,expr.arg2), | ||||||
|  | 				      eval(0,expr.arg3) | ||||||
|  | 				      ))::scalar_object | ||||||
|  | { | ||||||
|  |   return sum(closure(expr)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | ////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  | // sliceSum, sliceInnerProduct, sliceAxpy, sliceNorm etc... | ||||||
|  | ////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  |  | ||||||
|  | template<class vobj> inline void sliceSum(const Lattice<vobj> &Data,std::vector<typename vobj::scalar_object> &result,int orthogdim) | ||||||
|  | { | ||||||
|  |   /////////////////////////////////////////////////////// | ||||||
|  |   // FIXME precision promoted summation | ||||||
|  |   // may be important for correlation functions | ||||||
|  |   // But easily avoided by using double precision fields | ||||||
|  |   /////////////////////////////////////////////////////// | ||||||
|  |   typedef typename vobj::scalar_object sobj; | ||||||
|  |   GridBase  *grid = Data.Grid(); | ||||||
|  |   assert(grid!=NULL); | ||||||
|  |  | ||||||
|  |   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]; | ||||||
|  |  | ||||||
|  |   Vector<vobj> lvSum(rd); // will locally sum vectors first | ||||||
|  |   Vector<sobj> lsSum(ld,Zero());                    // sum across these down to scalars | ||||||
|  |   ExtractBuffer<sobj> extracted(Nsimd);                  // splitting the SIMD | ||||||
|  |  | ||||||
|  |   result.resize(fd); // And then global sum to return the same vector to every node  | ||||||
|  |   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]; | ||||||
|  |  | ||||||
|  |   // sum over reduced dimension planes, breaking out orthog dir | ||||||
|  |   // Parallel over orthog direction | ||||||
|  |   auto Data_v=Data.View(); | ||||||
|  |   thread_for( r,rd, { | ||||||
|  |     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; | ||||||
|  | 	lvSum[r]=lvSum[r]+Data_v[ss]; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   // Sum across simd lanes in the plane, breaking out orthog dir. | ||||||
|  |   Coordinate icoor(Nd); | ||||||
|  |  | ||||||
|  |   for(int rt=0;rt<rd;rt++){ | ||||||
|  |  | ||||||
|  |     extract(lvSum[rt],extracted); | ||||||
|  |  | ||||||
|  |     for(int idx=0;idx<Nsimd;idx++){ | ||||||
|  |  | ||||||
|  |       grid->iCoorFromIindex(icoor,idx); | ||||||
|  |  | ||||||
|  |       int ldx =rt+icoor[orthogdim]*rd; | ||||||
|  |  | ||||||
|  |       lsSum[ldx]=lsSum[ldx]+extracted[idx]; | ||||||
|  |  | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |    | ||||||
|  |   // sum over nodes. | ||||||
|  |   sobj gsum; | ||||||
|  |   for(int t=0;t<fd;t++){ | ||||||
|  |     int pt = t/ld; // processor plane | ||||||
|  |     int lt = t%ld; | ||||||
|  |     if ( pt == grid->_processor_coor[orthogdim] ) { | ||||||
|  |       gsum=lsSum[lt]; | ||||||
|  |     } else { | ||||||
|  |       gsum=Zero(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     grid->GlobalSum(gsum); | ||||||
|  |  | ||||||
|  |     result[t]=gsum; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | 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; | ||||||
|  |  | ||||||
|  |   Vector<vector_type> lvSum(rd); // will locally sum vectors first | ||||||
|  |   lsSum.resize(ld,scalar_type(0.0));                    // sum across these down to scalars | ||||||
|  |   ExtractBuffer<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; | ||||||
|  |   auto l_v=lhs.View(); | ||||||
|  |   auto r_v=rhs.View(); | ||||||
|  |   thread_for( r,rd,{ | ||||||
|  |  | ||||||
|  |     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(l_v[ss], r_v[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. | ||||||
|  |   Coordinate 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> | ||||||
|  | static void sliceInnerProductVector( std::vector<ComplexD> & result, const Lattice<vobj> &lhs,const Lattice<vobj> &rhs,int orthogdim)  | ||||||
|  | { | ||||||
|  |   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]; | ||||||
|  |  | ||||||
|  |   Vector<vector_type> lvSum(rd); // will locally sum vectors first | ||||||
|  |   Vector<scalar_type > lsSum(ld,scalar_type(0.0));                    // sum across these down to scalars | ||||||
|  |   ExtractBuffer<iScalar<scalar_type> > extracted(Nsimd);   // splitting the SIMD   | ||||||
|  |  | ||||||
|  |   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]; | ||||||
|  |  | ||||||
|  |   auto lhv=lhs.View(); | ||||||
|  |   auto rhv=rhs.View(); | ||||||
|  |   thread_for( r,rd,{ | ||||||
|  |  | ||||||
|  |     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; | ||||||
|  | 	vector_type vv = TensorRemove(innerProduct(lhv[ss],rhv[ss])); | ||||||
|  | 	lvSum[r]=lvSum[r]+vv; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   // Sum across simd lanes in the plane, breaking out orthog dir. | ||||||
|  |   Coordinate 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; | ||||||
|  |  | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |    | ||||||
|  |   // sum over nodes. | ||||||
|  |   scalar_type gsum; | ||||||
|  |   for(int t=0;t<fd;t++){ | ||||||
|  |     int pt = t/ld; // processor plane | ||||||
|  |     int lt = t%ld; | ||||||
|  |     if ( pt == grid->_processor_coor[orthogdim] ) { | ||||||
|  |       gsum=lsSum[lt]; | ||||||
|  |     } else { | ||||||
|  |       gsum=scalar_type(0.0); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     grid->GlobalSum(gsum); | ||||||
|  |  | ||||||
|  |     result[t]=gsum; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | template<class vobj> | ||||||
|  | static void sliceNorm (std::vector<RealD> &sn,const Lattice<vobj> &rhs,int Orthog)  | ||||||
|  | { | ||||||
|  |   typedef typename vobj::scalar_object sobj; | ||||||
|  |   typedef typename vobj::scalar_type scalar_type; | ||||||
|  |   typedef typename vobj::vector_type vector_type; | ||||||
|  |    | ||||||
|  |   int Nblock = rhs.Grid()->GlobalDimensions()[Orthog]; | ||||||
|  |   std::vector<ComplexD> ip(Nblock); | ||||||
|  |   sn.resize(Nblock); | ||||||
|  |    | ||||||
|  |   sliceInnerProductVector(ip,rhs,rhs,Orthog); | ||||||
|  |   for(int ss=0;ss<Nblock;ss++){ | ||||||
|  |     sn[ss] = real(ip[ss]); | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | template<class vobj> | ||||||
|  | static void sliceMaddVector(Lattice<vobj> &R,std::vector<RealD> &a,const Lattice<vobj> &X,const Lattice<vobj> &Y, | ||||||
|  | 			    int orthogdim,RealD scale=1.0)  | ||||||
|  | {     | ||||||
|  |   typedef typename vobj::scalar_object sobj; | ||||||
|  |   typedef typename vobj::scalar_type scalar_type; | ||||||
|  |   typedef typename vobj::vector_type vector_type; | ||||||
|  |   typedef typename vobj::tensor_reduced tensor_reduced; | ||||||
|  |    | ||||||
|  |   scalar_type zscale(scale); | ||||||
|  |  | ||||||
|  |   GridBase *grid  = X.Grid(); | ||||||
|  |  | ||||||
|  |   int Nsimd  =grid->Nsimd(); | ||||||
|  |   int Nblock =grid->GlobalDimensions()[orthogdim]; | ||||||
|  |  | ||||||
|  |   int fd     =grid->_fdimensions[orthogdim]; | ||||||
|  |   int ld     =grid->_ldimensions[orthogdim]; | ||||||
|  |   int rd     =grid->_rdimensions[orthogdim]; | ||||||
|  |  | ||||||
|  |   int e1     =grid->_slice_nblock[orthogdim]; | ||||||
|  |   int e2     =grid->_slice_block [orthogdim]; | ||||||
|  |   int stride =grid->_slice_stride[orthogdim]; | ||||||
|  |  | ||||||
|  |   Coordinate icoor; | ||||||
|  |   for(int r=0;r<rd;r++){ | ||||||
|  |  | ||||||
|  |     int so=r*grid->_ostride[orthogdim]; // base offset for start of plane  | ||||||
|  |  | ||||||
|  |     vector_type    av; | ||||||
|  |  | ||||||
|  |     for(int l=0;l<Nsimd;l++){ | ||||||
|  |       grid->iCoorFromIindex(icoor,l); | ||||||
|  |       int ldx =r+icoor[orthogdim]*rd; | ||||||
|  |       scalar_type *as =(scalar_type *)&av; | ||||||
|  |       as[l] = scalar_type(a[ldx])*zscale; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     tensor_reduced at; at=av; | ||||||
|  |  | ||||||
|  |     auto Rv=R.View(); | ||||||
|  |     auto Xv=X.View(); | ||||||
|  |     auto Yv=Y.View(); | ||||||
|  |     thread_for_collapse(2, n, e1, { | ||||||
|  |       for(int b=0;b<e2;b++){ | ||||||
|  | 	int ss= so+n*stride+b; | ||||||
|  | 	Rv[ss] = at*Xv[ss]+Yv[ss]; | ||||||
|  |       } | ||||||
|  |     }); | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | /* | ||||||
|  | inline GridBase         *makeSubSliceGrid(const GridBase *BlockSolverGrid,int Orthog) | ||||||
|  | { | ||||||
|  |   int NN    = BlockSolverGrid->_ndimension; | ||||||
|  |   int nsimd = BlockSolverGrid->Nsimd(); | ||||||
|  |    | ||||||
|  |   std::vector<int> latt_phys(0); | ||||||
|  |   std::vector<int> simd_phys(0); | ||||||
|  |   std::vector<int>  mpi_phys(0); | ||||||
|  |    | ||||||
|  |   for(int d=0;d<NN;d++){ | ||||||
|  |     if( d!=Orthog ) {  | ||||||
|  |       latt_phys.push_back(BlockSolverGrid->_fdimensions[d]); | ||||||
|  |       simd_phys.push_back(BlockSolverGrid->_simd_layout[d]); | ||||||
|  |       mpi_phys.push_back(BlockSolverGrid->_processors[d]); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   return (GridBase *)new GridCartesian(latt_phys,simd_phys,mpi_phys);  | ||||||
|  | } | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | template<class vobj> | ||||||
|  | static void sliceMaddMatrix (Lattice<vobj> &R,Eigen::MatrixXcd &aa,const Lattice<vobj> &X,const Lattice<vobj> &Y,int Orthog,RealD scale=1.0)  | ||||||
|  | {     | ||||||
|  |   typedef typename vobj::scalar_object sobj; | ||||||
|  |   typedef typename vobj::scalar_type scalar_type; | ||||||
|  |   typedef typename vobj::vector_type vector_type; | ||||||
|  |  | ||||||
|  |   int Nblock = X.Grid()->GlobalDimensions()[Orthog]; | ||||||
|  |  | ||||||
|  |   GridBase *FullGrid  = X.Grid(); | ||||||
|  |   //  GridBase *SliceGrid = makeSubSliceGrid(FullGrid,Orthog); | ||||||
|  |  | ||||||
|  |   //  Lattice<vobj> Xslice(SliceGrid); | ||||||
|  |   //  Lattice<vobj> Rslice(SliceGrid); | ||||||
|  |  | ||||||
|  |   assert( FullGrid->_simd_layout[Orthog]==1); | ||||||
|  |   //  int nh =  FullGrid->_ndimension; | ||||||
|  |   //  int nl = SliceGrid->_ndimension; | ||||||
|  |   //  int nl = nh-1; | ||||||
|  |  | ||||||
|  |   //FIXME package in a convenient iterator | ||||||
|  |   //Should loop over a plane orthogonal to direction "Orthog" | ||||||
|  |   int stride=FullGrid->_slice_stride[Orthog]; | ||||||
|  |   int block =FullGrid->_slice_block [Orthog]; | ||||||
|  |   int nblock=FullGrid->_slice_nblock[Orthog]; | ||||||
|  |   int ostride=FullGrid->_ostride[Orthog]; | ||||||
|  |  | ||||||
|  |   auto X_v=X.View(); | ||||||
|  |   auto Y_v=Y.View(); | ||||||
|  |   auto R_v=R.View(); | ||||||
|  |   thread_region | ||||||
|  |   { | ||||||
|  |     Vector<vobj> s_x(Nblock); | ||||||
|  |  | ||||||
|  |     thread_for_collapse_in_region(2, n,nblock, { | ||||||
|  |      for(int b=0;b<block;b++){ | ||||||
|  |       int o  = n*stride + b; | ||||||
|  |  | ||||||
|  |       for(int i=0;i<Nblock;i++){ | ||||||
|  | 	s_x[i] = X_v[o+i*ostride]; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       vobj dot; | ||||||
|  |       for(int i=0;i<Nblock;i++){ | ||||||
|  | 	dot = Y_v[o+i*ostride]; | ||||||
|  | 	for(int j=0;j<Nblock;j++){ | ||||||
|  | 	  dot = dot + s_x[j]*(scale*aa(j,i)); | ||||||
|  | 	} | ||||||
|  | 	R_v[o+i*ostride]=dot; | ||||||
|  |       } | ||||||
|  |     }}); | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | template<class vobj> | ||||||
|  | static void sliceMulMatrix (Lattice<vobj> &R,Eigen::MatrixXcd &aa,const Lattice<vobj> &X,int Orthog,RealD scale=1.0)  | ||||||
|  | {     | ||||||
|  |   typedef typename vobj::scalar_object sobj; | ||||||
|  |   typedef typename vobj::scalar_type scalar_type; | ||||||
|  |   typedef typename vobj::vector_type vector_type; | ||||||
|  |  | ||||||
|  |   int Nblock = X.Grid()->GlobalDimensions()[Orthog]; | ||||||
|  |  | ||||||
|  |   GridBase *FullGrid  = X.Grid(); | ||||||
|  |   //  GridBase *SliceGrid = makeSubSliceGrid(FullGrid,Orthog); | ||||||
|  |   //  Lattice<vobj> Xslice(SliceGrid); | ||||||
|  |   //  Lattice<vobj> Rslice(SliceGrid); | ||||||
|  |  | ||||||
|  |   assert( FullGrid->_simd_layout[Orthog]==1); | ||||||
|  |   //  int nh =  FullGrid->_ndimension; | ||||||
|  |   //  int nl = SliceGrid->_ndimension; | ||||||
|  |   //  int nl=1; | ||||||
|  |  | ||||||
|  |   //FIXME package in a convenient iterator | ||||||
|  |   //Should loop over a plane orthogonal to direction "Orthog" | ||||||
|  |   int stride=FullGrid->_slice_stride[Orthog]; | ||||||
|  |   int block =FullGrid->_slice_block [Orthog]; | ||||||
|  |   int nblock=FullGrid->_slice_nblock[Orthog]; | ||||||
|  |   int ostride=FullGrid->_ostride[Orthog]; | ||||||
|  |   auto R_v = R.View(); | ||||||
|  |   auto X_v = X.View(); | ||||||
|  |   thread_region | ||||||
|  |   { | ||||||
|  |     std::vector<vobj> s_x(Nblock); | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     thread_for_collapse_in_region( 2 ,n,nblock,{ | ||||||
|  |     for(int b=0;b<block;b++){ | ||||||
|  |       int o  = n*stride + b; | ||||||
|  |  | ||||||
|  |       for(int i=0;i<Nblock;i++){ | ||||||
|  | 	s_x[i] = X_v[o+i*ostride]; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       vobj dot; | ||||||
|  |       for(int i=0;i<Nblock;i++){ | ||||||
|  | 	dot = s_x[0]*(scale*aa(0,i)); | ||||||
|  | 	for(int j=1;j<Nblock;j++){ | ||||||
|  | 	  dot = dot + s_x[j]*(scale*aa(j,i)); | ||||||
|  | 	} | ||||||
|  | 	R_v[o+i*ostride]=dot; | ||||||
|  |       } | ||||||
|  |     }}); | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | template<class vobj> | ||||||
|  | static void sliceInnerProductMatrix(  Eigen::MatrixXcd &mat, const Lattice<vobj> &lhs,const Lattice<vobj> &rhs,int Orthog)  | ||||||
|  | { | ||||||
|  |   typedef typename vobj::scalar_object sobj; | ||||||
|  |   typedef typename vobj::scalar_type scalar_type; | ||||||
|  |   typedef typename vobj::vector_type vector_type; | ||||||
|  |    | ||||||
|  |   GridBase *FullGrid  = lhs.Grid(); | ||||||
|  |   //  GridBase *SliceGrid = makeSubSliceGrid(FullGrid,Orthog); | ||||||
|  |    | ||||||
|  |   int Nblock = FullGrid->GlobalDimensions()[Orthog]; | ||||||
|  |    | ||||||
|  |   //  Lattice<vobj> Lslice(SliceGrid); | ||||||
|  |   //  Lattice<vobj> Rslice(SliceGrid); | ||||||
|  |    | ||||||
|  |   mat = Eigen::MatrixXcd::Zero(Nblock,Nblock); | ||||||
|  |  | ||||||
|  |   assert( FullGrid->_simd_layout[Orthog]==1); | ||||||
|  |   //  int nh =  FullGrid->_ndimension; | ||||||
|  |   //  int nl = SliceGrid->_ndimension; | ||||||
|  |   //  int nl = nh-1; | ||||||
|  |  | ||||||
|  |   //FIXME package in a convenient iterator | ||||||
|  |   //Should loop over a plane orthogonal to direction "Orthog" | ||||||
|  |   int stride=FullGrid->_slice_stride[Orthog]; | ||||||
|  |   int block =FullGrid->_slice_block [Orthog]; | ||||||
|  |   int nblock=FullGrid->_slice_nblock[Orthog]; | ||||||
|  |   int ostride=FullGrid->_ostride[Orthog]; | ||||||
|  |  | ||||||
|  |   typedef typename vobj::vector_typeD vector_typeD; | ||||||
|  |  | ||||||
|  |   auto lhs_v=lhs.View(); | ||||||
|  |   auto rhs_v=rhs.View(); | ||||||
|  |   thread_region | ||||||
|  |   { | ||||||
|  |     std::vector<vobj> Left(Nblock); | ||||||
|  |     std::vector<vobj> Right(Nblock); | ||||||
|  |     Eigen::MatrixXcd  mat_thread = Eigen::MatrixXcd::Zero(Nblock,Nblock); | ||||||
|  |  | ||||||
|  |     thread_for_collapse_in_region( 2, n,nblock,{ | ||||||
|  |     for(int b=0;b<block;b++){ | ||||||
|  |  | ||||||
|  |       int o  = n*stride + b; | ||||||
|  |  | ||||||
|  |       for(int i=0;i<Nblock;i++){ | ||||||
|  | 	Left [i] = lhs_v[o+i*ostride]; | ||||||
|  | 	Right[i] = rhs_v[o+i*ostride]; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       for(int i=0;i<Nblock;i++){ | ||||||
|  |       for(int j=0;j<Nblock;j++){ | ||||||
|  | 	auto tmp = innerProduct(Left[i],Right[j]); | ||||||
|  | 	auto rtmp = TensorRemove(tmp); | ||||||
|  | 	auto red  =  Reduce(rtmp); | ||||||
|  | 	mat_thread(i,j) += std::complex<double>(real(red),imag(red)); | ||||||
|  |       }} | ||||||
|  |     }}); | ||||||
|  |     thread_critical | ||||||
|  |     { | ||||||
|  |       mat += mat_thread; | ||||||
|  |     }   | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   for(int i=0;i<Nblock;i++){ | ||||||
|  |   for(int j=0;j<Nblock;j++){ | ||||||
|  |     ComplexD sum = mat(i,j); | ||||||
|  |     FullGrid->GlobalSum(sum); | ||||||
|  |     mat(i,j)=sum; | ||||||
|  |   }} | ||||||
|  |  | ||||||
|  |   return; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | NAMESPACE_END(Grid); | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
							
								
								
									
										226
									
								
								Grid/lattice/Lattice_reduction_gpu.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										226
									
								
								Grid/lattice/Lattice_reduction_gpu.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,226 @@ | |||||||
|  | NAMESPACE_BEGIN(Grid); | ||||||
|  |  | ||||||
|  | #define WARP_SIZE 32 | ||||||
|  | extern cudaDeviceProp *gpu_props; | ||||||
|  | __device__ unsigned int retirementCount = 0; | ||||||
|  |  | ||||||
|  | template <class Iterator> | ||||||
|  | unsigned int nextPow2(Iterator x) { | ||||||
|  |   --x; | ||||||
|  |   x |= x >> 1; | ||||||
|  |   x |= x >> 2; | ||||||
|  |   x |= x >> 4; | ||||||
|  |   x |= x >> 8; | ||||||
|  |   x |= x >> 16; | ||||||
|  |   return ++x; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | template <class Iterator> | ||||||
|  | void getNumBlocksAndThreads(const Iterator n, const size_t sizeofsobj, Iterator &threads, Iterator &blocks) { | ||||||
|  |    | ||||||
|  |   int device; | ||||||
|  |   cudaGetDevice(&device); | ||||||
|  |    | ||||||
|  |   Iterator warpSize            = gpu_props[device].warpSize; | ||||||
|  |   Iterator sharedMemPerBlock   = gpu_props[device].sharedMemPerBlock; | ||||||
|  |   Iterator maxThreadsPerBlock  = gpu_props[device].maxThreadsPerBlock; | ||||||
|  |   Iterator multiProcessorCount = gpu_props[device].multiProcessorCount; | ||||||
|  |    | ||||||
|  |   std::cout << GridLogDebug << "GPU has:" << std::endl; | ||||||
|  |   std::cout << GridLogDebug << "\twarpSize            = " << warpSize << std::endl; | ||||||
|  |   std::cout << GridLogDebug << "\tsharedMemPerBlock   = " << sharedMemPerBlock << std::endl; | ||||||
|  |   std::cout << GridLogDebug << "\tmaxThreadsPerBlock  = " << maxThreadsPerBlock << std::endl; | ||||||
|  |   std::cout << GridLogDebug << "\tmaxThreadsPerBlock  = " << warpSize << std::endl; | ||||||
|  |   std::cout << GridLogDebug << "\tmultiProcessorCount = " << multiProcessorCount << std::endl; | ||||||
|  |    | ||||||
|  |   if (warpSize != WARP_SIZE) { | ||||||
|  |     std::cout << GridLogError << "The warp size of the GPU in use does not match the warp size set when compiling Grid." << std::endl; | ||||||
|  |     exit(EXIT_FAILURE); | ||||||
|  |   } | ||||||
|  |    | ||||||
|  |   // let the number of threads in a block be a multiple of 2, starting from warpSize | ||||||
|  |   threads = warpSize; | ||||||
|  |   while( 2*threads*sizeofsobj < sharedMemPerBlock && 2*threads <= maxThreadsPerBlock ) threads *= 2; | ||||||
|  |   // keep all the streaming multiprocessors busy | ||||||
|  |   blocks = nextPow2(multiProcessorCount); | ||||||
|  |    | ||||||
|  | } | ||||||
|  |  | ||||||
|  | template <class sobj, class Iterator> | ||||||
|  | __device__ void reduceBlock(volatile sobj *sdata, sobj mySum, const Iterator tid) { | ||||||
|  |    | ||||||
|  |   Iterator blockSize = blockDim.x; | ||||||
|  |    | ||||||
|  |   // cannot use overloaded operators for sobj as they are not volatile-qualified | ||||||
|  |   memcpy((void *)&sdata[tid], (void *)&mySum, sizeof(sobj)); | ||||||
|  |   __syncwarp(); | ||||||
|  |    | ||||||
|  |   const Iterator VEC = WARP_SIZE; | ||||||
|  |   const Iterator vid = tid & (VEC-1); | ||||||
|  |    | ||||||
|  |   sobj beta, temp; | ||||||
|  |   memcpy((void *)&beta, (void *)&mySum, sizeof(sobj)); | ||||||
|  |    | ||||||
|  |   for (int i = VEC/2; i > 0; i>>=1) { | ||||||
|  |     if (vid < i) { | ||||||
|  |       memcpy((void *)&temp, (void *)&sdata[tid+i], sizeof(sobj)); | ||||||
|  |       beta += temp; | ||||||
|  |       memcpy((void *)&sdata[tid], (void *)&beta, sizeof(sobj)); | ||||||
|  |     } | ||||||
|  |     __syncwarp(); | ||||||
|  |   } | ||||||
|  |   __syncthreads(); | ||||||
|  |    | ||||||
|  |   if (threadIdx.x == 0) { | ||||||
|  |     beta  = Zero(); | ||||||
|  |     for (Iterator i = 0; i < blockSize; i += VEC) { | ||||||
|  |       memcpy((void *)&temp, (void *)&sdata[i], sizeof(sobj)); | ||||||
|  |       beta  += temp; | ||||||
|  |     } | ||||||
|  |     memcpy((void *)&sdata[0], (void *)&beta, sizeof(sobj)); | ||||||
|  |   } | ||||||
|  |   __syncthreads(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | template <class vobj, class sobj, class Iterator> | ||||||
|  | __device__ void reduceBlocks(const vobj *g_idata, sobj *g_odata, Iterator n)  | ||||||
|  | { | ||||||
|  |   constexpr Iterator nsimd = vobj::Nsimd(); | ||||||
|  |    | ||||||
|  |   Iterator blockSize = blockDim.x; | ||||||
|  |    | ||||||
|  |   // force shared memory alignment | ||||||
|  |   extern __shared__ __align__(COALESCE_GRANULARITY) unsigned char shmem_pointer[]; | ||||||
|  |   // it's not possible to have two extern __shared__ arrays with same name | ||||||
|  |   // but different types in different scopes -- need to cast each time | ||||||
|  |   sobj *sdata = (sobj *)shmem_pointer; | ||||||
|  |    | ||||||
|  |   // first level of reduction, | ||||||
|  |   // each thread writes result in mySum | ||||||
|  |   Iterator tid = threadIdx.x; | ||||||
|  |   Iterator i = blockIdx.x*(blockSize*2) + threadIdx.x; | ||||||
|  |   Iterator gridSize = blockSize*2*gridDim.x; | ||||||
|  |   sobj mySum = Zero(); | ||||||
|  |    | ||||||
|  |   while (i < n) { | ||||||
|  |     Iterator lane = i % nsimd; | ||||||
|  |     Iterator ss   = i / nsimd; | ||||||
|  |     auto tmp = extractLane(lane,g_idata[ss]); | ||||||
|  |     sobj tmpD; | ||||||
|  |     tmpD=tmp; | ||||||
|  |     mySum   +=tmpD; | ||||||
|  |      | ||||||
|  |     if (i + blockSize < n) { | ||||||
|  |       lane = (i+blockSize) % nsimd; | ||||||
|  |       ss   = (i+blockSize) / nsimd; | ||||||
|  |       tmp = extractLane(lane,g_idata[ss]); | ||||||
|  |       tmpD = tmp; | ||||||
|  |       mySum += tmpD; | ||||||
|  |     } | ||||||
|  |     i += gridSize; | ||||||
|  |   } | ||||||
|  |    | ||||||
|  |   // copy mySum to shared memory and perform | ||||||
|  |   // reduction for all threads in this block | ||||||
|  |   reduceBlock(sdata, mySum, tid); | ||||||
|  |   if (tid == 0) g_odata[blockIdx.x] = sdata[0]; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | template <class vobj, class sobj,class Iterator> | ||||||
|  | __global__ void reduceKernel(const vobj *lat, sobj *buffer, Iterator n) { | ||||||
|  |    | ||||||
|  |   Iterator blockSize = blockDim.x; | ||||||
|  |    | ||||||
|  |   // perform reduction for this block and | ||||||
|  |   // write result to global memory buffer | ||||||
|  |   reduceBlocks(lat, buffer, n); | ||||||
|  |    | ||||||
|  |   if (gridDim.x > 1) { | ||||||
|  |      | ||||||
|  |     const Iterator tid = threadIdx.x; | ||||||
|  |     __shared__ bool amLast; | ||||||
|  |     // force shared memory alignment | ||||||
|  |     extern __shared__ __align__(COALESCE_GRANULARITY) unsigned char shmem_pointer[]; | ||||||
|  |     // it's not possible to have two extern __shared__ arrays with same name | ||||||
|  |     // but different types in different scopes -- need to cast each time | ||||||
|  |     sobj *smem = (sobj *)shmem_pointer; | ||||||
|  |      | ||||||
|  |     // wait until all outstanding memory instructions in this thread are finished | ||||||
|  |     __threadfence(); | ||||||
|  |      | ||||||
|  |     if (tid==0) { | ||||||
|  |       unsigned int ticket = atomicInc(&retirementCount, gridDim.x); | ||||||
|  |       // true if this block is the last block to be done | ||||||
|  |       amLast = (ticket == gridDim.x-1); | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     // each thread must read the correct value of amLast | ||||||
|  |     __syncthreads(); | ||||||
|  |      | ||||||
|  |     if (amLast) { | ||||||
|  |       // reduce buffer[0], ..., buffer[gridDim.x-1] | ||||||
|  |       Iterator i = tid; | ||||||
|  |       sobj mySum = Zero(); | ||||||
|  |        | ||||||
|  |       while (i < gridDim.x) { | ||||||
|  |         mySum += buffer[i]; | ||||||
|  |         i += blockSize; | ||||||
|  |       } | ||||||
|  |        | ||||||
|  |       reduceBlock(smem, mySum, tid); | ||||||
|  |        | ||||||
|  |       if (tid==0) { | ||||||
|  |         buffer[0] = smem[0]; | ||||||
|  |         // reset count variable | ||||||
|  |         retirementCount = 0; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | ///////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  | // Possibly promote to double and sum | ||||||
|  | ///////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  | template <class vobj> | ||||||
|  | inline typename vobj::scalar_objectD sumD_gpu(const vobj *lat, Integer osites)  | ||||||
|  | { | ||||||
|  |   typedef typename vobj::scalar_objectD sobj; | ||||||
|  |   typedef decltype(lat) Iterator; | ||||||
|  |    | ||||||
|  |   Integer nsimd= vobj::Nsimd(); | ||||||
|  |   Integer size = osites*nsimd; | ||||||
|  |  | ||||||
|  |   Integer numThreads, numBlocks; | ||||||
|  |   getNumBlocksAndThreads(size, sizeof(sobj), numThreads, numBlocks); | ||||||
|  |   Integer smemSize = numThreads * sizeof(sobj); | ||||||
|  |  | ||||||
|  |   Vector<sobj> buffer(numBlocks); | ||||||
|  |   sobj *buffer_v = &buffer[0]; | ||||||
|  |    | ||||||
|  |   reduceKernel<<< numBlocks, numThreads, smemSize >>>(lat, buffer_v, size); | ||||||
|  |   cudaDeviceSynchronize(); | ||||||
|  |    | ||||||
|  |   cudaError err = cudaGetLastError(); | ||||||
|  |   if ( cudaSuccess != err ) { | ||||||
|  |     printf("Cuda error %s\n",cudaGetErrorString( err )); | ||||||
|  |     exit(0); | ||||||
|  |   } | ||||||
|  |   auto result = buffer_v[0]; | ||||||
|  |   return result; | ||||||
|  | } | ||||||
|  | ///////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  | // Return as same precision as input performing reduction in double precision though | ||||||
|  | ///////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  | template <class vobj> | ||||||
|  | inline typename vobj::scalar_object sum_gpu(const vobj *lat, Integer osites)  | ||||||
|  | { | ||||||
|  |   typedef typename vobj::scalar_object sobj; | ||||||
|  |   sobj result; | ||||||
|  |   result = sumD_gpu(lat,osites); | ||||||
|  |   return result; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | NAMESPACE_END(Grid); | ||||||
							
								
								
									
										525
									
								
								Grid/lattice/Lattice_rng.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										525
									
								
								Grid/lattice/Lattice_rng.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,525 @@ | |||||||
|  | /************************************************************************************* | ||||||
|  |  | ||||||
|  |     Grid physics library, www.github.com/paboyle/Grid  | ||||||
|  |  | ||||||
|  |     Source file: ./lib/lattice/Lattice_rng.h | ||||||
|  |  | ||||||
|  |     Copyright (C) 2015 | ||||||
|  |  | ||||||
|  |     Author: Peter Boyle <paboyle@ph.ed.ac.uk> | ||||||
|  |     Author: Guido Cossu <guido.cossu@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_LATTICE_RNG_H | ||||||
|  | #define GRID_LATTICE_RNG_H | ||||||
|  |  | ||||||
|  | #include <random> | ||||||
|  |  | ||||||
|  | #ifdef RNG_SITMO | ||||||
|  | #include <Grid/sitmo_rng/sitmo_prng_engine.hpp> | ||||||
|  | #endif  | ||||||
|  |  | ||||||
|  | #if defined(RNG_SITMO) | ||||||
|  | #define RNG_FAST_DISCARD | ||||||
|  | #else  | ||||||
|  | #undef  RNG_FAST_DISCARD | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | NAMESPACE_BEGIN(Grid); | ||||||
|  |  | ||||||
|  | ////////////////////////////////////////////////////////////// | ||||||
|  | // Allow the RNG state to be less dense than the fine grid | ||||||
|  | ////////////////////////////////////////////////////////////// | ||||||
|  | inline int RNGfillable(GridBase *coarse,GridBase *fine) | ||||||
|  | { | ||||||
|  |  | ||||||
|  |   int rngdims = coarse->_ndimension; | ||||||
|  |  | ||||||
|  |   // trivially extended in higher dims, with locality guaranteeing RNG state is local to node | ||||||
|  |   int lowerdims   = fine->_ndimension - coarse->_ndimension; | ||||||
|  |   assert(lowerdims >= 0); | ||||||
|  |   for(int d=0;d<lowerdims;d++){ | ||||||
|  |     assert(fine->_simd_layout[d]==1); | ||||||
|  |     assert(fine->_processors[d]==1); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   int multiplicity=1; | ||||||
|  |   for(int d=0;d<lowerdims;d++){ | ||||||
|  |     multiplicity=multiplicity*fine->_rdimensions[d]; | ||||||
|  |   } | ||||||
|  |   // local and global volumes subdivide cleanly after SIMDization | ||||||
|  |   for(int d=0;d<rngdims;d++){ | ||||||
|  |     int fd= d+lowerdims; | ||||||
|  |     assert(coarse->_processors[d]  == fine->_processors[fd]); | ||||||
|  |     assert(coarse->_simd_layout[d] == fine->_simd_layout[fd]); | ||||||
|  |     assert(((fine->_rdimensions[fd] / coarse->_rdimensions[d])* coarse->_rdimensions[d])==fine->_rdimensions[fd]);  | ||||||
|  |  | ||||||
|  |     multiplicity = multiplicity *fine->_rdimensions[fd] / coarse->_rdimensions[d];  | ||||||
|  |   } | ||||||
|  |   return multiplicity; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |    | ||||||
|  | // merge of April 11 2017 | ||||||
|  | // this function is necessary for the LS vectorised field | ||||||
|  | inline int RNGfillable_general(GridBase *coarse,GridBase *fine) | ||||||
|  | { | ||||||
|  |   int rngdims = coarse->_ndimension; | ||||||
|  |      | ||||||
|  |   // trivially extended in higher dims, with locality guaranteeing RNG state is local to node | ||||||
|  |   int lowerdims   = fine->_ndimension - coarse->_ndimension;  assert(lowerdims >= 0); | ||||||
|  |   // assumes that the higher dimensions are not using more processors | ||||||
|  |   // all further divisions are local | ||||||
|  |   for(int d=0;d<lowerdims;d++) assert(fine->_processors[d]==1); | ||||||
|  |   for(int d=0;d<rngdims;d++) assert(coarse->_processors[d] == fine->_processors[d+lowerdims]); | ||||||
|  |  | ||||||
|  |   // then divide the number of local sites | ||||||
|  |   // check that the total number of sims agree, meanse the iSites are the same | ||||||
|  |   assert(fine->Nsimd() == coarse->Nsimd()); | ||||||
|  |  | ||||||
|  |   // check that the two grids divide cleanly | ||||||
|  |   assert( (fine->lSites() / coarse->lSites() ) * coarse->lSites() == fine->lSites() ); | ||||||
|  |  | ||||||
|  |   return fine->lSites() / coarse->lSites(); | ||||||
|  | } | ||||||
|  |    | ||||||
|  | // real scalars are one component | ||||||
|  | template<class scalar,class distribution,class generator>  | ||||||
|  | void fillScalar(scalar &s,distribution &dist,generator & gen) | ||||||
|  | { | ||||||
|  |   s=dist(gen); | ||||||
|  | } | ||||||
|  | template<class distribution,class generator>  | ||||||
|  | void fillScalar(ComplexF &s,distribution &dist, generator &gen) | ||||||
|  | { | ||||||
|  |   //  s=ComplexF(dist(gen),dist(gen)); | ||||||
|  |   s.real(dist(gen)); | ||||||
|  |   s.imag(dist(gen)); | ||||||
|  | } | ||||||
|  | template<class distribution,class generator>  | ||||||
|  | void fillScalar(ComplexD &s,distribution &dist,generator &gen) | ||||||
|  | { | ||||||
|  |   //  s=ComplexD(dist(gen),dist(gen)); | ||||||
|  |   s.real(dist(gen)); | ||||||
|  |   s.imag(dist(gen)); | ||||||
|  | } | ||||||
|  |    | ||||||
|  | class GridRNGbase { | ||||||
|  | public: | ||||||
|  |   // One generator per site. | ||||||
|  |   // Uniform and Gaussian distributions from these generators. | ||||||
|  | #ifdef RNG_RANLUX | ||||||
|  |   typedef std::ranlux48 RngEngine; | ||||||
|  |   typedef uint64_t      RngStateType; | ||||||
|  |   static const int RngStateCount = 15; | ||||||
|  | #endif  | ||||||
|  | #ifdef RNG_MT19937  | ||||||
|  |   typedef std::mt19937 RngEngine; | ||||||
|  |   typedef uint32_t     RngStateType; | ||||||
|  |   static const int     RngStateCount = std::mt19937::state_size; | ||||||
|  | #endif | ||||||
|  | #ifdef RNG_SITMO | ||||||
|  |   typedef sitmo::prng_engine 	RngEngine; | ||||||
|  |   typedef uint64_t    	RngStateType; | ||||||
|  |   static const int    	RngStateCount = 13; | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  |   std::vector<RngEngine>                             _generators; | ||||||
|  |   std::vector<std::uniform_real_distribution<RealD> > _uniform; | ||||||
|  |   std::vector<std::normal_distribution<RealD> >       _gaussian; | ||||||
|  |   std::vector<std::discrete_distribution<int32_t> >   _bernoulli; | ||||||
|  |   std::vector<std::uniform_int_distribution<uint32_t> > _uid; | ||||||
|  |  | ||||||
|  |   /////////////////////// | ||||||
|  |   // support for parallel init | ||||||
|  |   /////////////////////// | ||||||
|  | #ifdef RNG_FAST_DISCARD | ||||||
|  |   static void Skip(RngEngine &eng,uint64_t site) | ||||||
|  |   { | ||||||
|  |     ///////////////////////////////////////////////////////////////////////////////////// | ||||||
|  |     // Skip by 2^40 elements between successive lattice sites | ||||||
|  |     // This goes by 10^12. | ||||||
|  |     // Consider quenched updating; likely never exceeding rate of 1000 sweeps | ||||||
|  |     // per second on any machine. This gives us of order 10^9 seconds, or 100 years | ||||||
|  |     // skip ahead. | ||||||
|  |     // For HMC unlikely to go at faster than a solve per second, and  | ||||||
|  |     // tens of seconds per trajectory so this is clean in all reasonable cases, | ||||||
|  |     // and margin of safety is orders of magnitude. | ||||||
|  |     // 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 | ||||||
|  |     const int shift = 30; | ||||||
|  |  | ||||||
|  |     //////////////////////////////////////////////////////////////////// | ||||||
|  |     // Weird compiler bug in Intel 2018.1 under O3 was generating 32bit and not 64 bit left shift. | ||||||
|  |     //////////////////////////////////////////////////////////////////// | ||||||
|  |     volatile uint64_t skip = site; | ||||||
|  |  | ||||||
|  |     skip = skip<<shift; | ||||||
|  |  | ||||||
|  |     assert((skip >> shift)==site); // check for overflow | ||||||
|  |  | ||||||
|  |     eng.discard(skip); | ||||||
|  |     //      std::cout << " Engine  " <<site << " state " <<eng<<std::endl; | ||||||
|  |   }  | ||||||
|  | #endif | ||||||
|  |   static RngEngine Reseed(RngEngine &eng) | ||||||
|  |   { | ||||||
|  |     std::vector<uint32_t> newseed; | ||||||
|  |     std::uniform_int_distribution<uint32_t> uid; | ||||||
|  |     return Reseed(eng,newseed,uid); | ||||||
|  |   } | ||||||
|  |   static RngEngine Reseed(RngEngine &eng,std::vector<uint32_t> & newseed, | ||||||
|  | 			  std::uniform_int_distribution<uint32_t> &uid) | ||||||
|  |   { | ||||||
|  |     const int reseeds=4; | ||||||
|  |        | ||||||
|  |     newseed.resize(reseeds); | ||||||
|  |     for(int i=0;i<reseeds;i++){ | ||||||
|  |       newseed[i] = uid(eng); | ||||||
|  |     } | ||||||
|  |     std::seed_seq sseq(newseed.begin(),newseed.end()); | ||||||
|  |     return RngEngine(sseq); | ||||||
|  |   }     | ||||||
|  |  | ||||||
|  |   void GetState(std::vector<RngStateType> & saved,RngEngine &eng) { | ||||||
|  |     saved.resize(RngStateCount); | ||||||
|  |     std::stringstream ss; | ||||||
|  |     ss<<eng; | ||||||
|  |     ss.seekg(0,ss.beg); | ||||||
|  |     for(int i=0;i<RngStateCount;i++){ | ||||||
|  |       ss>>saved[i]; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   void GetState(std::vector<RngStateType> & saved,int gen) { | ||||||
|  |     GetState(saved,_generators[gen]); | ||||||
|  |   } | ||||||
|  |   void SetState(std::vector<RngStateType> & saved,RngEngine &eng){ | ||||||
|  |     assert(saved.size()==RngStateCount); | ||||||
|  |     std::stringstream ss; | ||||||
|  |     for(int i=0;i<RngStateCount;i++){ | ||||||
|  |       ss<< saved[i]<<" "; | ||||||
|  |     } | ||||||
|  |     ss.seekg(0,ss.beg); | ||||||
|  |     ss>>eng; | ||||||
|  |   } | ||||||
|  |   void SetState(std::vector<RngStateType> & saved,int gen){ | ||||||
|  |     SetState(saved,_generators[gen]); | ||||||
|  |   } | ||||||
|  |   void SetEngine(RngEngine &Eng, int gen){ | ||||||
|  |     _generators[gen]=Eng; | ||||||
|  |   } | ||||||
|  |   void GetEngine(RngEngine &Eng, int gen){ | ||||||
|  |     Eng=_generators[gen]; | ||||||
|  |   } | ||||||
|  |   template<class source> void Seed(source &src, int gen) | ||||||
|  |   { | ||||||
|  |     _generators[gen] = RngEngine(src); | ||||||
|  |   }     | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | class GridSerialRNG : public GridRNGbase { | ||||||
|  | public: | ||||||
|  |  | ||||||
|  |   GridSerialRNG() : GridRNGbase() { | ||||||
|  |     _generators.resize(1); | ||||||
|  |     _uniform.resize(1,std::uniform_real_distribution<RealD>{0,1}); | ||||||
|  |     _gaussian.resize(1,std::normal_distribution<RealD>(0.0,1.0) ); | ||||||
|  |     _bernoulli.resize(1,std::discrete_distribution<int32_t>{1,1}); | ||||||
|  |     _uid.resize(1,std::uniform_int_distribution<uint32_t>() ); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   template <class sobj,class distribution> inline void fill(sobj &l,std::vector<distribution> &dist){ | ||||||
|  |  | ||||||
|  |     typedef typename sobj::scalar_type scalar_type; | ||||||
|  |   | ||||||
|  |     int words = sizeof(sobj)/sizeof(scalar_type); | ||||||
|  |  | ||||||
|  |     scalar_type *buf = (scalar_type *) & l; | ||||||
|  |  | ||||||
|  |     dist[0].reset(); | ||||||
|  |     for(int idx=0;idx<words;idx++){ | ||||||
|  |       fillScalar(buf[idx],dist[0],_generators[0]); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     CartesianCommunicator::BroadcastWorld(0,(void *)&l,sizeof(l)); | ||||||
|  |  | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   template <class distribution>  inline void fill(ComplexF &l,std::vector<distribution> &dist){ | ||||||
|  |     dist[0].reset(); | ||||||
|  |     fillScalar(l,dist[0],_generators[0]); | ||||||
|  |     CartesianCommunicator::BroadcastWorld(0,(void *)&l,sizeof(l)); | ||||||
|  |   } | ||||||
|  |   template <class distribution>  inline void fill(ComplexD &l,std::vector<distribution> &dist){ | ||||||
|  |     dist[0].reset(); | ||||||
|  |     fillScalar(l,dist[0],_generators[0]); | ||||||
|  |     CartesianCommunicator::BroadcastWorld(0,(void *)&l,sizeof(l)); | ||||||
|  |   } | ||||||
|  |   template <class distribution>  inline void fill(RealF &l,std::vector<distribution> &dist){ | ||||||
|  |     dist[0].reset(); | ||||||
|  |     fillScalar(l,dist[0],_generators[0]); | ||||||
|  |     CartesianCommunicator::BroadcastWorld(0,(void *)&l,sizeof(l)); | ||||||
|  |   } | ||||||
|  |   template <class distribution>  inline void fill(RealD &l,std::vector<distribution> &dist){ | ||||||
|  |     dist[0].reset(); | ||||||
|  |     fillScalar(l,dist[0],_generators[0]); | ||||||
|  |     CartesianCommunicator::BroadcastWorld(0,(void *)&l,sizeof(l)); | ||||||
|  |   } | ||||||
|  |   // vector fill | ||||||
|  |   template <class distribution>  inline void fill(vComplexF &l,std::vector<distribution> &dist){ | ||||||
|  |     RealF *pointer=(RealF *)&l; | ||||||
|  |     dist[0].reset(); | ||||||
|  |     for(int i=0;i<2*vComplexF::Nsimd();i++){ | ||||||
|  |       fillScalar(pointer[i],dist[0],_generators[0]); | ||||||
|  |     } | ||||||
|  |     CartesianCommunicator::BroadcastWorld(0,(void *)&l,sizeof(l)); | ||||||
|  |   } | ||||||
|  |   template <class distribution>  inline void fill(vComplexD &l,std::vector<distribution> &dist){ | ||||||
|  |     RealD *pointer=(RealD *)&l; | ||||||
|  |     dist[0].reset(); | ||||||
|  |     for(int i=0;i<2*vComplexD::Nsimd();i++){ | ||||||
|  |       fillScalar(pointer[i],dist[0],_generators[0]); | ||||||
|  |     } | ||||||
|  |     CartesianCommunicator::BroadcastWorld(0,(void *)&l,sizeof(l)); | ||||||
|  |   } | ||||||
|  |   template <class distribution>  inline void fill(vRealF &l,std::vector<distribution> &dist){ | ||||||
|  |     RealF *pointer=(RealF *)&l; | ||||||
|  |     dist[0].reset(); | ||||||
|  |     for(int i=0;i<vRealF::Nsimd();i++){ | ||||||
|  |       fillScalar(pointer[i],dist[0],_generators[0]); | ||||||
|  |     } | ||||||
|  |     CartesianCommunicator::BroadcastWorld(0,(void *)&l,sizeof(l)); | ||||||
|  |   } | ||||||
|  |   template <class distribution>  inline void fill(vRealD &l,std::vector<distribution> &dist){ | ||||||
|  |     RealD *pointer=(RealD *)&l; | ||||||
|  |     dist[0].reset(); | ||||||
|  |     for(int i=0;i<vRealD::Nsimd();i++){ | ||||||
|  |       fillScalar(pointer[i],dist[0],_generators[0]); | ||||||
|  |     } | ||||||
|  |     CartesianCommunicator::BroadcastWorld(0,(void *)&l,sizeof(l)); | ||||||
|  |   } | ||||||
|  |      | ||||||
|  |   void SeedFixedIntegers(const std::vector<int> &seeds){ | ||||||
|  |     CartesianCommunicator::BroadcastWorld(0,(void *)&seeds[0],sizeof(int)*seeds.size()); | ||||||
|  |     std::seed_seq src(seeds.begin(),seeds.end()); | ||||||
|  |     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 { | ||||||
|  | private: | ||||||
|  |   double _time_counter; | ||||||
|  |   GridBase *_grid; | ||||||
|  |   unsigned int _vol; | ||||||
|  |  | ||||||
|  | public: | ||||||
|  |   GridBase *Grid(void) const { return _grid; } | ||||||
|  |   int generator_idx(int os,int is) { | ||||||
|  |     return is*_grid->oSites()+os; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   GridParallelRNG(GridBase *grid) : GridRNGbase() { | ||||||
|  |     _grid = grid; | ||||||
|  |     _vol  =_grid->iSites()*_grid->oSites(); | ||||||
|  |  | ||||||
|  |     _generators.resize(_vol); | ||||||
|  |     _uniform.resize(_vol,std::uniform_real_distribution<RealD>{0,1}); | ||||||
|  |     _gaussian.resize(_vol,std::normal_distribution<RealD>(0.0,1.0) ); | ||||||
|  |     _bernoulli.resize(_vol,std::discrete_distribution<int32_t>{1,1}); | ||||||
|  |     _uid.resize(_vol,std::uniform_int_distribution<uint32_t>() ); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   template <class vobj,class distribution> inline void fill(Lattice<vobj> &l,std::vector<distribution> &dist){ | ||||||
|  |  | ||||||
|  |     typedef typename vobj::scalar_object scalar_object; | ||||||
|  |     typedef typename vobj::scalar_type scalar_type; | ||||||
|  |     typedef typename vobj::vector_type vector_type; | ||||||
|  |  | ||||||
|  |     double inner_time_counter = usecond(); | ||||||
|  |  | ||||||
|  |     int multiplicity = RNGfillable_general(_grid, l.Grid()); // l has finer or same grid | ||||||
|  |     int Nsimd  = _grid->Nsimd();  // guaranteed to be the same for l.Grid() too | ||||||
|  |     int osites = _grid->oSites();  // guaranteed to be <= l.Grid()->oSites() by a factor multiplicity | ||||||
|  |     int words  = sizeof(scalar_object) / sizeof(scalar_type); | ||||||
|  |  | ||||||
|  |     auto l_v = l.View(); | ||||||
|  |     thread_for( ss, osites, { | ||||||
|  |       ExtractBuffer<scalar_object> buf(Nsimd); | ||||||
|  |       for (int m = 0; m < multiplicity; m++) {  // Draw from same generator multiplicity times | ||||||
|  |  | ||||||
|  | 	int sm = multiplicity * ss + m;  // Maps the generator site to the fine site | ||||||
|  |  | ||||||
|  | 	for (int si = 0; si < Nsimd; si++) { | ||||||
|  |              | ||||||
|  | 	  int gdx = generator_idx(ss, si);  // index of generator state | ||||||
|  | 	  scalar_type *pointer = (scalar_type *)&buf[si]; | ||||||
|  | 	  dist[gdx].reset(); | ||||||
|  | 	  for (int idx = 0; idx < words; idx++)  | ||||||
|  | 	    fillScalar(pointer[idx], dist[gdx], _generators[gdx]); | ||||||
|  | 	} | ||||||
|  | 	// merge into SIMD lanes, FIXME suboptimal implementation | ||||||
|  | 	merge(l_v[sm], buf); | ||||||
|  |       } | ||||||
|  |       }); | ||||||
|  |     //    }); | ||||||
|  |  | ||||||
|  |     _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){ | ||||||
|  |  | ||||||
|  |     // Everyone generates the same seed_seq based on input seeds | ||||||
|  |     CartesianCommunicator::BroadcastWorld(0,(void *)&seeds[0],sizeof(int)*seeds.size()); | ||||||
|  |  | ||||||
|  |     std::seed_seq source(seeds.begin(),seeds.end()); | ||||||
|  |  | ||||||
|  |     RngEngine master_engine(source); | ||||||
|  |  | ||||||
|  | #ifdef RNG_FAST_DISCARD | ||||||
|  |     //////////////////////////////////////////////// | ||||||
|  |     // Skip ahead through a single stream. | ||||||
|  |     // Applicable to SITMO and other has based/crypto RNGs | ||||||
|  |     // Should be applicable to Mersenne Twister, but the C++11 | ||||||
|  |     // MT implementation does not implement fast discard even though | ||||||
|  |     // in principle this is possible | ||||||
|  |     //////////////////////////////////////////////// | ||||||
|  |  | ||||||
|  |     // Everybody loops over global volume. | ||||||
|  |     thread_for( gidx, _grid->_gsites, { | ||||||
|  | 	// Where is it? | ||||||
|  | 	int rank; | ||||||
|  | 	int o_idx; | ||||||
|  | 	int i_idx; | ||||||
|  |  | ||||||
|  | 	Coordinate gcoor; | ||||||
|  | 	_grid->GlobalIndexToGlobalCoor(gidx,gcoor); | ||||||
|  | 	_grid->GlobalCoorToRankIndex(rank,o_idx,i_idx,gcoor); | ||||||
|  | 	 | ||||||
|  | 	// If this is one of mine we take it | ||||||
|  | 	if( rank == _grid->ThisRank() ){ | ||||||
|  | 	  int l_idx=generator_idx(o_idx,i_idx); | ||||||
|  | 	  _generators[l_idx] = master_engine; | ||||||
|  | 	  Skip(_generators[l_idx],gidx); // Skip to next RNG sequence | ||||||
|  | 	} | ||||||
|  |     }); | ||||||
|  | #else  | ||||||
|  |     //////////////////////////////////////////////////////////////// | ||||||
|  |     // Machine and thread decomposition dependent seeding is efficient | ||||||
|  |     // and maximally parallel; but NOT reproducible from machine to machine.  | ||||||
|  |     // Not ideal, but fastest way to reseed all nodes. | ||||||
|  |     //////////////////////////////////////////////////////////////// | ||||||
|  |     { | ||||||
|  |       // Obtain one Reseed per processor | ||||||
|  |       int Nproc = _grid->ProcessorCount(); | ||||||
|  |       std::vector<RngEngine> seeders(Nproc); | ||||||
|  |       int me= _grid->ThisRank(); | ||||||
|  |       for(int p=0;p<Nproc;p++){ | ||||||
|  | 	seeders[p] = Reseed(master_engine); | ||||||
|  |       } | ||||||
|  |       master_engine = seeders[me]; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     { | ||||||
|  |       // Obtain one reseeded generator per thread | ||||||
|  |       int Nthread = GridThread::GetThreads(); | ||||||
|  |       std::vector<RngEngine> seeders(Nthread); | ||||||
|  |       for(int t=0;t<Nthread;t++){ | ||||||
|  | 	seeders[t] = Reseed(master_engine); | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       thread_for( t, Nthread, { | ||||||
|  | 	// set up one per local site in threaded fashion | ||||||
|  | 	std::vector<uint32_t> newseeds; | ||||||
|  | 	std::uniform_int_distribution<uint32_t> uid;	 | ||||||
|  | 	for(int l=0;l<_grid->lSites();l++) { | ||||||
|  | 	  if ( (l%Nthread)==t ) { | ||||||
|  | 	    _generators[l] = Reseed(seeders[t],newseeds,uid); | ||||||
|  | 	  } | ||||||
|  | 	} | ||||||
|  |       }); | ||||||
|  |     } | ||||||
|  | #endif | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   void Report(){ | ||||||
|  |     std::cout << GridLogMessage << "Time spent in the fill() routine by GridParallelRNG: "<< _time_counter/1e3 << " ms" << std::endl; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |   //////////////////////////////////////////////////////////////////////// | ||||||
|  |   // Support for rigorous test of RNG's | ||||||
|  |   // Return uniform random uint32_t from requested site generator | ||||||
|  |   //////////////////////////////////////////////////////////////////////// | ||||||
|  |   uint32_t GlobalU01(int gsite){ | ||||||
|  |  | ||||||
|  |     uint32_t the_number; | ||||||
|  |     // who | ||||||
|  |     int rank,o_idx,i_idx; | ||||||
|  |     Coordinate gcoor; | ||||||
|  |     _grid->GlobalIndexToGlobalCoor(gsite,gcoor); | ||||||
|  |     _grid->GlobalCoorToRankIndex(rank,o_idx,i_idx,gcoor); | ||||||
|  |  | ||||||
|  |     // draw | ||||||
|  |     int l_idx=generator_idx(o_idx,i_idx); | ||||||
|  |     if( rank == _grid->ThisRank() ){ | ||||||
|  |       the_number = _uid[l_idx](_generators[l_idx]); | ||||||
|  |     } | ||||||
|  |        | ||||||
|  |     // share & return | ||||||
|  |     _grid->Broadcast(rank,(void *)&the_number,sizeof(the_number)); | ||||||
|  |     return the_number; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | template <class vobj> inline void random(GridParallelRNG &rng,Lattice<vobj> &l)   { rng.fill(l,rng._uniform);  } | ||||||
|  | template <class vobj> inline void gaussian(GridParallelRNG &rng,Lattice<vobj> &l) { rng.fill(l,rng._gaussian); } | ||||||
|  | template <class vobj> inline void bernoulli(GridParallelRNG &rng,Lattice<vobj> &l){ rng.fill(l,rng._bernoulli);} | ||||||
|  |  | ||||||
|  | template <class sobj> inline void random(GridSerialRNG &rng,sobj &l)   { rng.fill(l,rng._uniform  ); } | ||||||
|  | template <class sobj> inline void gaussian(GridSerialRNG &rng,sobj &l) { rng.fill(l,rng._gaussian ); } | ||||||
|  | template <class sobj> inline void bernoulli(GridSerialRNG &rng,sobj &l){ rng.fill(l,rng._bernoulli); } | ||||||
|  |  | ||||||
|  | NAMESPACE_END(Grid); | ||||||
|  | #endif | ||||||
							
								
								
									
										69
									
								
								Grid/lattice/Lattice_trace.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								Grid/lattice/Lattice_trace.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,69 @@ | |||||||
|  | /************************************************************************************* | ||||||
|  |  | ||||||
|  |     Grid physics library, www.github.com/paboyle/Grid  | ||||||
|  |  | ||||||
|  |     Source file: ./lib/lattice/Lattice_trace.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_LATTICE_TRACE_H | ||||||
|  | #define GRID_LATTICE_TRACE_H | ||||||
|  |  | ||||||
|  | /////////////////////////////////////////////// | ||||||
|  | // Tracing, transposing, peeking, poking | ||||||
|  | /////////////////////////////////////////////// | ||||||
|  |  | ||||||
|  | NAMESPACE_BEGIN(Grid); | ||||||
|  |  | ||||||
|  | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  | // Trace | ||||||
|  | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  | template<class vobj> | ||||||
|  | inline auto trace(const Lattice<vobj> &lhs)  -> Lattice<decltype(trace(vobj()))> | ||||||
|  | { | ||||||
|  |   Lattice<decltype(trace(vobj()))> ret(lhs.Grid()); | ||||||
|  |   auto ret_v = ret.View(); | ||||||
|  |   auto lhs_v = lhs.View(); | ||||||
|  |   accelerator_for( ss, lhs_v.size(), vobj::Nsimd(), { | ||||||
|  |     coalescedWrite(ret_v[ss], trace(lhs_v(ss))); | ||||||
|  |   }); | ||||||
|  |   return ret; | ||||||
|  | }; | ||||||
|  |      | ||||||
|  | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  | // Trace Index level dependent operation | ||||||
|  | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  | template<int Index,class vobj> | ||||||
|  | inline auto TraceIndex(const Lattice<vobj> &lhs) -> Lattice<decltype(traceIndex<Index>(vobj()))> | ||||||
|  | { | ||||||
|  |   Lattice<decltype(traceIndex<Index>(vobj()))> ret(lhs.Grid()); | ||||||
|  |   auto ret_v = ret.View(); | ||||||
|  |   auto lhs_v = lhs.View(); | ||||||
|  |   accelerator_for( ss, lhs_v.size(), vobj::Nsimd(), { | ||||||
|  |     coalescedWrite(ret_v[ss], traceIndex<Index>(lhs_v(ss))); | ||||||
|  |   }); | ||||||
|  |   return ret; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | NAMESPACE_END(Grid); | ||||||
|  | #endif | ||||||
|  |  | ||||||
							
								
								
									
										1106
									
								
								Grid/lattice/Lattice_transfer.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1106
									
								
								Grid/lattice/Lattice_transfer.h
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										68
									
								
								Grid/lattice/Lattice_transpose.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								Grid/lattice/Lattice_transpose.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,68 @@ | |||||||
|  | /************************************************************************************* | ||||||
|  |  | ||||||
|  |     Grid physics library, www.github.com/paboyle/Grid  | ||||||
|  |  | ||||||
|  |     Source file: ./lib/lattice/Lattice_transpose.h | ||||||
|  |  | ||||||
|  |     Copyright (C) 2015 | ||||||
|  |  | ||||||
|  | Author: Azusa Yamaguchi <ayamaguc@staffmail.ed.ac.uk> | ||||||
|  | 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_LATTICE_TRANSPOSE_H | ||||||
|  | #define GRID_LATTICE_TRANSPOSE_H | ||||||
|  |  | ||||||
|  | /////////////////////////////////////////////// | ||||||
|  | // Transpose | ||||||
|  | /////////////////////////////////////////////// | ||||||
|  |  | ||||||
|  | NAMESPACE_BEGIN(Grid); | ||||||
|  |  | ||||||
|  | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  | // Transpose | ||||||
|  | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  | template<class vobj> | ||||||
|  | inline Lattice<vobj> transpose(const Lattice<vobj> &lhs){ | ||||||
|  |   Lattice<vobj> ret(lhs.Grid()); | ||||||
|  |   auto ret_v = ret.View(); | ||||||
|  |   auto lhs_v = lhs.View(); | ||||||
|  |   accelerator_for(ss,lhs_v.size(),vobj::Nsimd(),{ | ||||||
|  |     coalescedWrite(ret_v[ss], transpose(lhs_v(ss))); | ||||||
|  |   }); | ||||||
|  |   return ret; | ||||||
|  | }; | ||||||
|  |      | ||||||
|  | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  | // Index level dependent transpose | ||||||
|  | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  | template<int Index,class vobj> | ||||||
|  | inline auto TransposeIndex(const Lattice<vobj> &lhs) -> Lattice<decltype(transposeIndex<Index>(vobj()))> | ||||||
|  | { | ||||||
|  |   Lattice<decltype(transposeIndex<Index>(vobj()))> ret(lhs.Grid()); | ||||||
|  |   auto ret_v = ret.View(); | ||||||
|  |   auto lhs_v = lhs.View(); | ||||||
|  |   accelerator_for(ss,lhs_v.size(),vobj::Nsimd(),{ | ||||||
|  |     coalescedWrite(ret_v[ss] , transposeIndex<Index>(lhs_v(ss))); | ||||||
|  |   }); | ||||||
|  |   return ret; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | NAMESPACE_END(Grid); | ||||||
|  | #endif | ||||||
							
								
								
									
										80
									
								
								Grid/lattice/Lattice_unary.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										80
									
								
								Grid/lattice/Lattice_unary.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,80 @@ | |||||||
|  | /************************************************************************************* | ||||||
|  |  | ||||||
|  |     Grid physics library, www.github.com/paboyle/Grid  | ||||||
|  |  | ||||||
|  |     Source file: ./lib/lattice/Lattice_unary.h | ||||||
|  |  | ||||||
|  |     Copyright (C) 2015 | ||||||
|  |  | ||||||
|  | Author: Azusa Yamaguchi <ayamaguc@staffmail.ed.ac.uk> | ||||||
|  | Author: Peter Boyle <paboyle@ph.ed.ac.uk> | ||||||
|  | Author: neo <cossu@post.kek.jp> | ||||||
|  | Author: paboyle <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_LATTICE_UNARY_H | ||||||
|  | #define GRID_LATTICE_UNARY_H | ||||||
|  |  | ||||||
|  | NAMESPACE_BEGIN(Grid); | ||||||
|  |  | ||||||
|  | template<class obj> Lattice<obj> pow(const Lattice<obj> &rhs_i,RealD y){ | ||||||
|  |   Lattice<obj> ret_i(rhs_i.Grid()); | ||||||
|  |   auto rhs = rhs_i.View(); | ||||||
|  |   auto ret = ret_i.View(); | ||||||
|  |   ret.Checkerboard() = rhs.Checkerboard(); | ||||||
|  |   accelerator_for(ss,rhs.size(),1,{ | ||||||
|  |       ret[ss]=pow(rhs[ss],y); | ||||||
|  |   }); | ||||||
|  |   return ret_i; | ||||||
|  | } | ||||||
|  | template<class obj> Lattice<obj> mod(const Lattice<obj> &rhs_i,Integer y){ | ||||||
|  |   Lattice<obj> ret_i(rhs_i.Grid()); | ||||||
|  |   auto rhs = rhs_i.View(); | ||||||
|  |   auto ret = ret_i.View(); | ||||||
|  |   ret.Checkerboard() = rhs.Checkerboard(); | ||||||
|  |   accelerator_for(ss,rhs.size(),obj::Nsimd(),{ | ||||||
|  |     coalescedWrite(ret[ss],mod(rhs(ss),y)); | ||||||
|  |   }); | ||||||
|  |   return ret_i; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | template<class obj> Lattice<obj> div(const Lattice<obj> &rhs_i,Integer y){ | ||||||
|  |   Lattice<obj> ret_i(rhs_i.Grid()); | ||||||
|  |   auto ret = ret_i.View(); | ||||||
|  |   auto rhs = rhs_i.View(); | ||||||
|  |   ret.Checkerboard() = rhs_i.Checkerboard(); | ||||||
|  |   accelerator_for(ss,rhs.size(),obj::Nsimd(),{ | ||||||
|  |     coalescedWrite(ret[ss],div(rhs(ss),y)); | ||||||
|  |   }); | ||||||
|  |   return ret_i; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | template<class obj> Lattice<obj> expMat(const Lattice<obj> &rhs_i, RealD alpha, Integer Nexp = DEFAULT_MAT_EXP){ | ||||||
|  |   Lattice<obj> ret_i(rhs_i.Grid()); | ||||||
|  |   auto rhs = rhs_i.View(); | ||||||
|  |   auto ret = ret_i.View(); | ||||||
|  |   ret.Checkerboard() = rhs.Checkerboard(); | ||||||
|  |   accelerator_for(ss,rhs.size(),obj::Nsimd(),{ | ||||||
|  |     coalescedWrite(ret[ss],Exponentiate(rhs(ss),alpha, Nexp)); | ||||||
|  |   }); | ||||||
|  |   return ret_i; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | NAMESPACE_END(Grid); | ||||||
|  | #endif | ||||||
| @@ -28,28 +28,29 @@ with this program; if not, write to the Free Software Foundation, Inc., | |||||||
| See the full license in the file "LICENSE" in the top level distribution | See the full license in the file "LICENSE" in the top level distribution | ||||||
| directory | directory | ||||||
| *************************************************************************************/ | *************************************************************************************/ | ||||||
| /*  END LEGAL */ | 			   /*  END LEGAL */ | ||||||
| #include <Grid/GridCore.h> | #include <Grid/GridCore.h> | ||||||
|  | #include <Grid/util/CompilerCompatible.h> | ||||||
| 
 | 
 | ||||||
| #include <cxxabi.h> | #include <cxxabi.h> | ||||||
| #include <memory> | #include <memory> | ||||||
| 
 | 
 | ||||||
| namespace Grid { | NAMESPACE_BEGIN(Grid); | ||||||
| 
 | 
 | ||||||
|   std::string demangle(const char* name) { | std::string demangle(const char* name) { | ||||||
|      |      | ||||||
|     int status = -4; // some arbitrary value to eliminate the compiler warning
 |   int status = -4; // some arbitrary value to eliminate the compiler warning
 | ||||||
|      |      | ||||||
|     // enable c++11 by passing the flag -std=c++11 to g++
 |   // enable c++11 by passing the flag -std=c++11 to g++
 | ||||||
|     std::unique_ptr<char, void(*)(void*)> res { |   std::unique_ptr<char, void(*)(void*)> res { | ||||||
|       abi::__cxa_demangle(name, NULL, NULL, &status), |     abi::__cxa_demangle(name, NULL, NULL, &status), | ||||||
| 	std::free |       std::free | ||||||
| 	}; |       }; | ||||||
|      |      | ||||||
|     return (status==0) ? res.get() : name ; |   return (status==0) ? res.get() : name ; | ||||||
|   } | } | ||||||
|    |    | ||||||
| GridStopWatch Logger::StopWatch; | GridStopWatch Logger::GlobalStopWatch; | ||||||
| int Logger::timestamp; | int Logger::timestamp; | ||||||
| std::ostream Logger::devnull(0); | std::ostream Logger::devnull(0); | ||||||
| 
 | 
 | ||||||
| @@ -58,13 +59,16 @@ void GridLogTimestamp(int on){ | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| Colours GridLogColours(0); | Colours GridLogColours(0); | ||||||
| GridLogger GridLogError(1, "Error", GridLogColours, "RED"); | GridLogger GridLogMG     (1, "MG"    , GridLogColours, "NORMAL"); | ||||||
|  | GridLogger GridLogIRL    (1, "IRL"   , GridLogColours, "NORMAL"); | ||||||
|  | GridLogger GridLogSolver (1, "Solver", GridLogColours, "NORMAL"); | ||||||
|  | GridLogger GridLogError  (1, "Error" , GridLogColours, "RED"); | ||||||
| GridLogger GridLogWarning(1, "Warning", GridLogColours, "YELLOW"); | GridLogger GridLogWarning(1, "Warning", GridLogColours, "YELLOW"); | ||||||
| GridLogger GridLogMessage(1, "Message", GridLogColours, "NORMAL"); | GridLogger GridLogMessage(1, "Message", GridLogColours, "NORMAL"); | ||||||
| GridLogger GridLogDebug(1, "Debug", GridLogColours, "PURPLE"); | GridLogger GridLogDebug  (1, "Debug", GridLogColours, "PURPLE"); | ||||||
| GridLogger GridLogPerformance(1, "Performance", GridLogColours, "GREEN"); | GridLogger GridLogPerformance(1, "Performance", GridLogColours, "GREEN"); | ||||||
| GridLogger GridLogIterative(1, "Iterative", GridLogColours, "BLUE"); | GridLogger GridLogIterative  (1, "Iterative", GridLogColours, "BLUE"); | ||||||
| GridLogger GridLogIntegrator(1, "Integrator", GridLogColours, "BLUE"); | GridLogger GridLogIntegrator (1, "Integrator", GridLogColours, "BLUE"); | ||||||
| 
 | 
 | ||||||
| void GridLogConfigure(std::vector<std::string> &logstreams) { | void GridLogConfigure(std::vector<std::string> &logstreams) { | ||||||
|   GridLogError.Active(0); |   GridLogError.Active(0); | ||||||
| @@ -73,19 +77,18 @@ void GridLogConfigure(std::vector<std::string> &logstreams) { | |||||||
|   GridLogIterative.Active(0); |   GridLogIterative.Active(0); | ||||||
|   GridLogDebug.Active(0); |   GridLogDebug.Active(0); | ||||||
|   GridLogPerformance.Active(0); |   GridLogPerformance.Active(0); | ||||||
|   GridLogIntegrator.Active(0); |   GridLogIntegrator.Active(1); | ||||||
|   GridLogColours.Active(0); |   GridLogColours.Active(0); | ||||||
| 
 | 
 | ||||||
|   for (int i = 0; i < logstreams.size(); i++) { |   for (int i = 0; i < logstreams.size(); i++) { | ||||||
|     if (logstreams[i] == std::string("Error")) GridLogError.Active(1); |     if (logstreams[i] == std::string("Error"))       GridLogError.Active(1); | ||||||
|     if (logstreams[i] == std::string("Warning")) GridLogWarning.Active(1); |     if (logstreams[i] == std::string("Warning"))     GridLogWarning.Active(1); | ||||||
|     if (logstreams[i] == std::string("NoMessage")) GridLogMessage.Active(0); |     if (logstreams[i] == std::string("NoMessage"))   GridLogMessage.Active(0); | ||||||
|     if (logstreams[i] == std::string("Iterative")) GridLogIterative.Active(1); |     if (logstreams[i] == std::string("Iterative"))   GridLogIterative.Active(1); | ||||||
|     if (logstreams[i] == std::string("Debug")) GridLogDebug.Active(1); |     if (logstreams[i] == std::string("Debug"))       GridLogDebug.Active(1); | ||||||
|     if (logstreams[i] == std::string("Performance")) |     if (logstreams[i] == std::string("Performance")) GridLogPerformance.Active(1); | ||||||
|       GridLogPerformance.Active(1); |     if (logstreams[i] == std::string("Integrator"))  GridLogIntegrator.Active(1); | ||||||
|     if (logstreams[i] == std::string("Integrator")) GridLogIntegrator.Active(1); |     if (logstreams[i] == std::string("Colours"))     GridLogColours.Active(1); | ||||||
|     if (logstreams[i] == std::string("Colours")) GridLogColours.Active(1); |  | ||||||
|   } |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @@ -94,7 +97,7 @@ void GridLogConfigure(std::vector<std::string> &logstreams) { | |||||||
| ////////////////////////////////////////////////////////////
 | ////////////////////////////////////////////////////////////
 | ||||||
| void Grid_quiesce_nodes(void) { | void Grid_quiesce_nodes(void) { | ||||||
|   int me = 0; |   int me = 0; | ||||||
| #if defined(GRID_COMMS_MPI) || defined(GRID_COMMS_MPI3) || defined(GRID_COMMS_MPI3L) | #if defined(GRID_COMMS_MPI) || defined(GRID_COMMS_MPI3) || defined(GRID_COMMS_MPIT) | ||||||
|   MPI_Comm_rank(MPI_COMM_WORLD, &me); |   MPI_Comm_rank(MPI_COMM_WORLD, &me); | ||||||
| #endif | #endif | ||||||
| #ifdef GRID_COMMS_SHMEM | #ifdef GRID_COMMS_SHMEM | ||||||
| @@ -106,8 +109,9 @@ void Grid_quiesce_nodes(void) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void Grid_unquiesce_nodes(void) { | void Grid_unquiesce_nodes(void) { | ||||||
| #ifdef GRID_COMMS_MPI | #if defined(GRID_COMMS_MPI) || defined(GRID_COMMS_MPI3) || defined(GRID_COMMS_MPIT) | ||||||
|   std::cout.clear(); |   std::cout.clear(); | ||||||
| #endif | #endif | ||||||
| } | } | ||||||
| } | NAMESPACE_END(Grid); | ||||||
|  | 
 | ||||||
| @@ -1,4 +1,4 @@ | |||||||
|     /*************************************************************************************
 | /*************************************************************************************
 | ||||||
| 
 | 
 | ||||||
|     Grid physics library, www.github.com/paboyle/Grid  |     Grid physics library, www.github.com/paboyle/Grid  | ||||||
| 
 | 
 | ||||||
| @@ -25,8 +25,8 @@ | |||||||
|     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||||||
| 
 | 
 | ||||||
|     See the full license in the file "LICENSE" in the top level distribution directory |     See the full license in the file "LICENSE" in the top level distribution directory | ||||||
|     *************************************************************************************/ | *************************************************************************************/ | ||||||
|     /*  END LEGAL */ | /*  END LEGAL */ | ||||||
| 
 | 
 | ||||||
| #include <map> | #include <map> | ||||||
| 
 | 
 | ||||||
| @@ -37,13 +37,12 @@ | |||||||
| #include <execinfo.h> | #include <execinfo.h> | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| namespace Grid { | NAMESPACE_BEGIN(Grid); | ||||||
| 
 | 
 | ||||||
| //////////////////////////////////////////////////////////////////////////////////////////////////
 | //////////////////////////////////////////////////////////////////////////////////////////////////
 | ||||||
| // Dress the output; use std::chrono for time stamping via the StopWatch class
 | // Dress the output; use std::chrono for time stamping via the StopWatch class
 | ||||||
| //////////////////////////////////////////////////////////////////////////////////////////////////
 | //////////////////////////////////////////////////////////////////////////////////////////////////
 | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| class Colours{ | class Colours{ | ||||||
| protected: | protected: | ||||||
|   bool is_active; |   bool is_active; | ||||||
| @@ -57,15 +56,15 @@ public: | |||||||
|   void Active(bool activate){ |   void Active(bool activate){ | ||||||
|     is_active=activate; |     is_active=activate; | ||||||
|     if (is_active){ |     if (is_active){ | ||||||
|      colour["BLACK"]  ="\033[30m"; |       colour["BLACK"]  ="\033[30m"; | ||||||
|      colour["RED"]    ="\033[31m"; |       colour["RED"]    ="\033[31m"; | ||||||
|      colour["GREEN"]  ="\033[32m"; |       colour["GREEN"]  ="\033[32m"; | ||||||
|      colour["YELLOW"] ="\033[33m"; |       colour["YELLOW"] ="\033[33m"; | ||||||
|      colour["BLUE"]   ="\033[34m"; |       colour["BLUE"]   ="\033[34m"; | ||||||
|      colour["PURPLE"] ="\033[35m"; |       colour["PURPLE"] ="\033[35m"; | ||||||
|      colour["CYAN"]   ="\033[36m"; |       colour["CYAN"]   ="\033[36m"; | ||||||
|      colour["WHITE"]  ="\033[37m"; |       colour["WHITE"]  ="\033[37m"; | ||||||
|      colour["NORMAL"] ="\033[0;39m"; |       colour["NORMAL"] ="\033[0;39m"; | ||||||
|     } else { |     } else { | ||||||
|       colour["BLACK"] =""; |       colour["BLACK"] =""; | ||||||
|       colour["RED"]   =""; |       colour["RED"]   =""; | ||||||
| @@ -85,12 +84,16 @@ class Logger { | |||||||
| protected: | protected: | ||||||
|   Colours &Painter; |   Colours &Painter; | ||||||
|   int active; |   int active; | ||||||
|  |   int timing_mode; | ||||||
|  |   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; | ||||||
| 
 | 
 | ||||||
| public: | public: | ||||||
|   static GridStopWatch StopWatch; |   static GridStopWatch GlobalStopWatch; | ||||||
|  |   GridStopWatch         LocalStopWatch; | ||||||
|  |   GridStopWatch *StopWatch; | ||||||
|   static std::ostream devnull; |   static std::ostream devnull; | ||||||
| 
 | 
 | ||||||
|   std::string background() {return Painter.colour["NORMAL"];} |   std::string background() {return Painter.colour["NORMAL"];} | ||||||
| @@ -98,25 +101,55 @@ public: | |||||||
|   std::string colour() {return Painter.colour[COLOUR];} |   std::string colour() {return Painter.colour[COLOUR];} | ||||||
| 
 | 
 | ||||||
|   Logger(std::string topNm, int on, std::string nm, Colours& col_class, std::string col)  : active(on), |   Logger(std::string topNm, int on, std::string nm, Colours& col_class, std::string col)  : active(on), | ||||||
|     name(nm), | 											    name(nm), | ||||||
|     topName(topNm), | 											    topName(topNm), | ||||||
|     Painter(col_class), | 											    Painter(col_class), | ||||||
|     COLOUR(col) {} ; | 											    timing_mode(0), | ||||||
|  | 											    COLOUR(col)  | ||||||
|  |   { | ||||||
|  |     StopWatch = & GlobalStopWatch; | ||||||
|  |   }; | ||||||
|    |    | ||||||
|   void Active(int on) {active = on;}; |   void Active(int on) {active = on;}; | ||||||
|   int  isActive(void) {return active;}; |   int  isActive(void) {return active;}; | ||||||
|   static void Timestamp(int on) {timestamp = on;}; |   static void Timestamp(int on) {timestamp = on;}; | ||||||
|  |   void Reset(void) {  | ||||||
|  |     StopWatch->Reset();  | ||||||
|  |     StopWatch->Start();  | ||||||
|  |   } | ||||||
|  |   void TimingMode(int on) {  | ||||||
|  |     timing_mode = on;  | ||||||
|  |     if(on) {  | ||||||
|  |       StopWatch = &LocalStopWatch; | ||||||
|  |       Reset();  | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   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){ | ||||||
| 
 | 
 | ||||||
|     if ( log.active ) { |     if ( log.active ) { | ||||||
|       stream << log.background()<< std::setw(10) << std::left << log.topName << log.background()<< " : "; |       stream << log.background()<<  std::left; | ||||||
|       stream << log.colour() << std::setw(14) << std::left << log.name << log.background() << " : "; |       if (log.topWidth > 0) | ||||||
|  |       { | ||||||
|  |         stream << std::setw(log.topWidth); | ||||||
|  |       } | ||||||
|  |       stream << log.topName << 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 ) { | ||||||
| 	StopWatch.Stop(); | 	log.StopWatch->Stop(); | ||||||
| 	GridTime now = StopWatch.Elapsed(); | 	GridTime now = log.StopWatch->Elapsed(); | ||||||
| 	StopWatch.Start(); | 	 | ||||||
| 	stream << log.evidence()<< now << log.background() << " : " ; | 	if ( log.timing_mode==1 ) log.StopWatch->Reset(); | ||||||
|  | 	log.StopWatch->Start(); | ||||||
|  | 	stream << log.evidence() | ||||||
|  | 	       << now	       << log.background() << " : " ; | ||||||
|       } |       } | ||||||
|       stream << log.colour(); |       stream << log.colour(); | ||||||
|       return stream; |       return stream; | ||||||
| @@ -130,11 +163,14 @@ public: | |||||||
| class GridLogger: public Logger { | class GridLogger: public Logger { | ||||||
| public: | public: | ||||||
|   GridLogger(int on, std::string nm, Colours&col_class, std::string col_key = "NORMAL"): |   GridLogger(int on, std::string nm, Colours&col_class, std::string col_key = "NORMAL"): | ||||||
|   Logger("Grid", on, nm, col_class, col_key){}; |     Logger("Grid", on, nm, col_class, col_key){}; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| void GridLogConfigure(std::vector<std::string> &logstreams); | void GridLogConfigure(std::vector<std::string> &logstreams); | ||||||
| 
 | 
 | ||||||
|  | extern GridLogger GridLogMG; | ||||||
|  | extern GridLogger GridLogIRL; | ||||||
|  | extern GridLogger GridLogSolver; | ||||||
| extern GridLogger GridLogError; | extern GridLogger GridLogError; | ||||||
| extern GridLogger GridLogWarning; | extern GridLogger GridLogWarning; | ||||||
| extern GridLogger GridLogMessage; | extern GridLogger GridLogMessage; | ||||||
| @@ -144,39 +180,39 @@ extern GridLogger GridLogIterative  ; | |||||||
| extern GridLogger GridLogIntegrator  ; | extern GridLogger GridLogIntegrator  ; | ||||||
| extern Colours    GridLogColours; | extern Colours    GridLogColours; | ||||||
| 
 | 
 | ||||||
|  std::string demangle(const char* name) ; | std::string demangle(const char* name) ; | ||||||
| 
 | 
 | ||||||
| #define _NBACKTRACE (256) | #define _NBACKTRACE (256) | ||||||
| extern void * Grid_backtrace_buffer[_NBACKTRACE]; | extern void * Grid_backtrace_buffer[_NBACKTRACE]; | ||||||
| 
 | 
 | ||||||
| #define BACKTRACEFILE() {\ | #define BACKTRACEFILE() {						\ | ||||||
| char string[20];					\ |     char string[20];							\ | ||||||
| std::sprintf(string,"backtrace.%d",CartesianCommunicator::RankWorld()); \ |     std::sprintf(string,"backtrace.%d",CartesianCommunicator::RankWorld()); \ | ||||||
| std::FILE * fp = std::fopen(string,"w");				\ |     std::FILE * fp = std::fopen(string,"w");				\ | ||||||
| BACKTRACEFP(fp)\ |     BACKTRACEFP(fp)							\ | ||||||
| std::fclose(fp);	    \ |       std::fclose(fp);							\ | ||||||
| } |   } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| #ifdef HAVE_EXECINFO_H | #ifdef HAVE_EXECINFO_H | ||||||
| #define BACKTRACEFP(fp) { \ | #define BACKTRACEFP(fp) {						\ | ||||||
| int symbols    = backtrace        (Grid_backtrace_buffer,_NBACKTRACE);\ |     int symbols    = backtrace        (Grid_backtrace_buffer,_NBACKTRACE); \ | ||||||
| char **strings = backtrace_symbols(Grid_backtrace_buffer,symbols);\ |     char **strings = backtrace_symbols(Grid_backtrace_buffer,symbols);	\ | ||||||
| for (int i = 0; i < symbols; i++){\ |     for (int i = 0; i < symbols; i++){					\ | ||||||
|   std::fprintf (fp,"BackTrace Strings: %d %s\n",i, demangle(strings[i]).c_str()); std::fflush(fp); \ |       std::fprintf (fp,"BackTrace Strings: %d %s\n",i, demangle(strings[i]).c_str()); std::fflush(fp); \ | ||||||
| }\ |     }									\ | ||||||
| } |   } | ||||||
| #else  | #else  | ||||||
| #define BACKTRACEFP(fp) { \ | #define BACKTRACEFP(fp) {						\ | ||||||
| std::fprintf (fp,"BT %d %lx\n",0, __builtin_return_address(0)); std::fflush(fp); \ |     std::fprintf (fp,"BT %d %lx\n",0, __builtin_return_address(0)); std::fflush(fp); \ | ||||||
| std::fprintf (fp,"BT %d %lx\n",1, __builtin_return_address(1)); std::fflush(fp); \ |     std::fprintf (fp,"BT %d %lx\n",1, __builtin_return_address(1)); std::fflush(fp); \ | ||||||
| std::fprintf (fp,"BT %d %lx\n",2, __builtin_return_address(2)); std::fflush(fp); \ |     std::fprintf (fp,"BT %d %lx\n",2, __builtin_return_address(2)); std::fflush(fp); \ | ||||||
| std::fprintf (fp,"BT %d %lx\n",3, __builtin_return_address(3)); std::fflush(fp); \ |     std::fprintf (fp,"BT %d %lx\n",3, __builtin_return_address(3)); std::fflush(fp); \ | ||||||
| } |   } | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| #define BACKTRACE() BACKTRACEFP(stdout)  | #define BACKTRACE() BACKTRACEFP(stdout)  | ||||||
| 
 | 
 | ||||||
|  | NAMESPACE_END(Grid); | ||||||
| 
 | 
 | ||||||
| } |  | ||||||
| #endif | #endif | ||||||
							
								
								
									
										3
									
								
								Grid/parallelIO/BinaryIO.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								Grid/parallelIO/BinaryIO.cc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,3 @@ | |||||||
|  | #include <Grid/GridCore.h> | ||||||
|  |  | ||||||
|  | int Grid::BinaryIO::latticeWriteMaxRetry = -1; | ||||||
							
								
								
									
										753
									
								
								Grid/parallelIO/BinaryIO.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										753
									
								
								Grid/parallelIO/BinaryIO.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,753 @@ | |||||||
|  |     /************************************************************************************* | ||||||
|  |  | ||||||
|  |     Grid physics library, www.github.com/paboyle/Grid  | ||||||
|  |  | ||||||
|  |     Source file: ./lib/parallelIO/BinaryIO.h | ||||||
|  |  | ||||||
|  |     Copyright (C) 2015 | ||||||
|  |  | ||||||
|  |     Author: Peter Boyle <paboyle@ph.ed.ac.uk> | ||||||
|  |     Author: Guido Cossu<guido.cossu@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 */ | ||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #if defined(GRID_COMMS_MPI) || defined(GRID_COMMS_MPI3) || defined(GRID_COMMS_MPIT)  | ||||||
|  | #define USE_MPI_IO | ||||||
|  | #else | ||||||
|  | #undef  USE_MPI_IO | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #ifdef HAVE_ENDIAN_H | ||||||
|  | #include <endian.h> | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #include <arpa/inet.h> | ||||||
|  | #include <algorithm> | ||||||
|  |  | ||||||
|  | NAMESPACE_BEGIN(Grid); | ||||||
|  |  | ||||||
|  | ///////////////////////////////////////////////////////////////////////////////// | ||||||
|  | // Byte reversal garbage | ||||||
|  | ///////////////////////////////////////////////////////////////////////////////// | ||||||
|  | inline uint32_t byte_reverse32(uint32_t f) {  | ||||||
|  |       f = ((f&0xFF)<<24) | ((f&0xFF00)<<8) | ((f&0xFF0000)>>8) | ((f&0xFF000000UL)>>24) ;  | ||||||
|  |       return f; | ||||||
|  | } | ||||||
|  | inline uint64_t byte_reverse64(uint64_t f) {  | ||||||
|  |   uint64_t g; | ||||||
|  |   g = ((f&0xFF)<<24) | ((f&0xFF00)<<8) | ((f&0xFF0000)>>8) | ((f&0xFF000000UL)>>24) ;  | ||||||
|  |   g = g << 32; | ||||||
|  |   f = f >> 32; | ||||||
|  |   g|= ((f&0xFF)<<24) | ((f&0xFF00)<<8) | ((f&0xFF0000)>>8) | ((f&0xFF000000UL)>>24) ;  | ||||||
|  |   return g; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #if BYTE_ORDER == BIG_ENDIAN  | ||||||
|  | inline uint64_t Grid_ntohll(uint64_t A) { return A; } | ||||||
|  | #else | ||||||
|  | inline uint64_t Grid_ntohll(uint64_t A) {  | ||||||
|  |   return byte_reverse64(A); | ||||||
|  | } | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | // A little helper | ||||||
|  | inline void removeWhitespace(std::string &key) | ||||||
|  | { | ||||||
|  |   key.erase(std::remove_if(key.begin(), key.end(), ::isspace),key.end()); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /////////////////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  | // Static class holding the parallel IO code | ||||||
|  | // Could just use a namespace | ||||||
|  | /////////////////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  | class BinaryIO { | ||||||
|  |  public: | ||||||
|  |   static int latticeWriteMaxRetry; | ||||||
|  |  | ||||||
|  |   ///////////////////////////////////////////////////////////////////////////// | ||||||
|  |   // more byte manipulation helpers | ||||||
|  |   ///////////////////////////////////////////////////////////////////////////// | ||||||
|  |  | ||||||
|  |   template<class vobj> static inline void Uint32Checksum(Lattice<vobj> &lat,uint32_t &nersc_csum) | ||||||
|  |   { | ||||||
|  |     typedef typename vobj::scalar_object sobj; | ||||||
|  |  | ||||||
|  |     GridBase *grid = lat.Grid(); | ||||||
|  |     uint64_t lsites = grid->lSites(); | ||||||
|  |  | ||||||
|  |     std::vector<sobj> scalardata(lsites);  | ||||||
|  |     unvectorizeToLexOrdArray(scalardata,lat);     | ||||||
|  |  | ||||||
|  |     NerscChecksum(grid,scalardata,nersc_csum); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   template <class fobj> | ||||||
|  |   static inline void NerscChecksum(GridBase *grid, std::vector<fobj> &fbuf, uint32_t &nersc_csum) | ||||||
|  |   { | ||||||
|  |     const uint64_t size32 = sizeof(fobj) / sizeof(uint32_t); | ||||||
|  |  | ||||||
|  |     uint64_t lsites = grid->lSites(); | ||||||
|  |     if (fbuf.size() == 1) | ||||||
|  |     { | ||||||
|  |       lsites = 1; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     thread_region | ||||||
|  |     { | ||||||
|  |       uint32_t nersc_csum_thr = 0; | ||||||
|  |  | ||||||
|  |       thread_for_in_region( local_site, lsites,  | ||||||
|  |       { | ||||||
|  |         uint32_t *site_buf = (uint32_t *)&fbuf[local_site]; | ||||||
|  |         for (uint64_t j = 0; j < size32; j++) | ||||||
|  |         { | ||||||
|  |           nersc_csum_thr = nersc_csum_thr + site_buf[j]; | ||||||
|  |         } | ||||||
|  |       }); | ||||||
|  |  | ||||||
|  |       thread_critical | ||||||
|  |       { | ||||||
|  |         nersc_csum += nersc_csum_thr; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   template<class fobj> static inline void ScidacChecksum(GridBase *grid,std::vector<fobj> &fbuf,uint32_t &scidac_csuma,uint32_t &scidac_csumb) | ||||||
|  |   { | ||||||
|  |     int nd = grid->_ndimension; | ||||||
|  |  | ||||||
|  |     uint64_t lsites              =grid->lSites(); | ||||||
|  |     if (fbuf.size()==1) { | ||||||
|  |       lsites=1; | ||||||
|  |     } | ||||||
|  |     Coordinate local_vol   =grid->LocalDimensions(); | ||||||
|  |     Coordinate local_start =grid->LocalStarts(); | ||||||
|  |     Coordinate global_vol  =grid->FullDimensions(); | ||||||
|  |  | ||||||
|  |     thread_region | ||||||
|  |     {  | ||||||
|  |       Coordinate coor(nd); | ||||||
|  |       uint32_t scidac_csuma_thr=0; | ||||||
|  |       uint32_t scidac_csumb_thr=0; | ||||||
|  |       uint32_t site_crc=0; | ||||||
|  |  | ||||||
|  |       thread_for_in_region( local_site, lsites,  | ||||||
|  |       { | ||||||
|  |  | ||||||
|  | 	uint32_t * site_buf = (uint32_t *)&fbuf[local_site]; | ||||||
|  |  | ||||||
|  | 	/*  | ||||||
|  | 	 * Scidac csum  is rather more heavyweight | ||||||
|  | 	 * FIXME -- 128^3 x 256 x 16 will overflow. | ||||||
|  | 	 */ | ||||||
|  | 	 | ||||||
|  | 	int global_site; | ||||||
|  |  | ||||||
|  | 	Lexicographic::CoorFromIndex(coor,local_site,local_vol); | ||||||
|  |  | ||||||
|  | 	for(int d=0;d<nd;d++) { | ||||||
|  | 	  coor[d] = coor[d]+local_start[d]; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	Lexicographic::IndexFromCoor(coor,global_site,global_vol); | ||||||
|  |  | ||||||
|  | 	uint32_t gsite29   = global_site%29; | ||||||
|  | 	uint32_t gsite31   = global_site%31; | ||||||
|  | 	 | ||||||
|  | 	site_crc = crc32(0,(unsigned char *)site_buf,sizeof(fobj)); | ||||||
|  | 	//	std::cout << "Site "<<local_site << " crc "<<std::hex<<site_crc<<std::dec<<std::endl; | ||||||
|  | 	//	std::cout << "Site "<<local_site << std::hex<<site_buf[0] <<site_buf[1]<<std::dec <<std::endl; | ||||||
|  | 	scidac_csuma_thr ^= site_crc<<gsite29 | site_crc>>(32-gsite29); | ||||||
|  | 	scidac_csumb_thr ^= site_crc<<gsite31 | site_crc>>(32-gsite31); | ||||||
|  |       }); | ||||||
|  |  | ||||||
|  |       thread_critical | ||||||
|  |       { | ||||||
|  | 	scidac_csuma^= scidac_csuma_thr; | ||||||
|  | 	scidac_csumb^= scidac_csumb_thr; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   // Network is big endian | ||||||
|  |   static inline void htobe32_v(void *file_object,uint32_t bytes){ be32toh_v(file_object,bytes);}  | ||||||
|  |   static inline void htobe64_v(void *file_object,uint32_t bytes){ be64toh_v(file_object,bytes);}  | ||||||
|  |   static inline void htole32_v(void *file_object,uint32_t bytes){ le32toh_v(file_object,bytes);}  | ||||||
|  |   static inline void htole64_v(void *file_object,uint32_t bytes){ le64toh_v(file_object,bytes);}  | ||||||
|  |  | ||||||
|  |   static inline void be32toh_v(void *file_object,uint64_t bytes) | ||||||
|  |   { | ||||||
|  |     uint32_t * f = (uint32_t *)file_object; | ||||||
|  |     uint64_t count = bytes/sizeof(uint32_t); | ||||||
|  |     thread_for( i, count, {   | ||||||
|  |       f[i] = ntohl(f[i]); | ||||||
|  |     }); | ||||||
|  |   } | ||||||
|  |   // LE must Swap and switch to host | ||||||
|  |   static inline void le32toh_v(void *file_object,uint64_t bytes) | ||||||
|  |   { | ||||||
|  |     uint32_t *fp = (uint32_t *)file_object; | ||||||
|  |  | ||||||
|  |     uint64_t count = bytes/sizeof(uint32_t); | ||||||
|  |     thread_for(i,count,{ | ||||||
|  |       uint32_t f; | ||||||
|  |       f = fp[i]; | ||||||
|  |       // got network order and the network to host | ||||||
|  |       f = ((f&0xFF)<<24) | ((f&0xFF00)<<8) | ((f&0xFF0000)>>8) | ((f&0xFF000000UL)>>24) ;  | ||||||
|  |       fp[i] = ntohl(f); | ||||||
|  |     }); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   // BE is same as network | ||||||
|  |   static inline void be64toh_v(void *file_object,uint64_t bytes) | ||||||
|  |   { | ||||||
|  |     uint64_t * f = (uint64_t *)file_object; | ||||||
|  |     uint64_t count = bytes/sizeof(uint64_t); | ||||||
|  |     thread_for( i, count, { | ||||||
|  |       f[i] = Grid_ntohll(f[i]); | ||||||
|  |     }); | ||||||
|  |   } | ||||||
|  |    | ||||||
|  |   // LE must swap and switch; | ||||||
|  |   static inline void le64toh_v(void *file_object,uint64_t bytes) | ||||||
|  |   { | ||||||
|  |     uint64_t *fp = (uint64_t *)file_object; | ||||||
|  |     uint64_t count = bytes/sizeof(uint64_t); | ||||||
|  |     thread_for( i, count, { | ||||||
|  |       uint64_t f,g; | ||||||
|  |       f = fp[i]; | ||||||
|  |       // got network order and the network to host | ||||||
|  |       g = ((f&0xFF)<<24) | ((f&0xFF00)<<8) | ((f&0xFF0000)>>8) | ((f&0xFF000000UL)>>24) ;  | ||||||
|  |       g = g << 32; | ||||||
|  |       f = f >> 32; | ||||||
|  |       g|= ((f&0xFF)<<24) | ((f&0xFF00)<<8) | ((f&0xFF0000)>>8) | ((f&0xFF000000UL)>>24) ;  | ||||||
|  |       fp[i] = Grid_ntohll(g); | ||||||
|  |     }); | ||||||
|  |   } | ||||||
|  |   ///////////////////////////////////////////////////////////////////////////// | ||||||
|  |   // Real action: | ||||||
|  |   // Read or Write distributed lexico array of ANY object to a specific location in file  | ||||||
|  |   ////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  |  | ||||||
|  |   static const int BINARYIO_MASTER_APPEND = 0x10; | ||||||
|  |   static const int BINARYIO_UNORDERED     = 0x08; | ||||||
|  |   static const int BINARYIO_LEXICOGRAPHIC = 0x04; | ||||||
|  |   static const int BINARYIO_READ          = 0x02; | ||||||
|  |   static const int BINARYIO_WRITE         = 0x01; | ||||||
|  |  | ||||||
|  |   template<class word,class fobj> | ||||||
|  |   static inline void IOobject(word w, | ||||||
|  | 			      GridBase *grid, | ||||||
|  | 			      std::vector<fobj> &iodata, | ||||||
|  | 			      std::string file, | ||||||
|  | 			      uint64_t& offset, | ||||||
|  | 			      const std::string &format, int control, | ||||||
|  | 			      uint32_t &nersc_csum, | ||||||
|  | 			      uint32_t &scidac_csuma, | ||||||
|  | 			      uint32_t &scidac_csumb) | ||||||
|  |   { | ||||||
|  |     grid->Barrier(); | ||||||
|  |     GridStopWatch timer;  | ||||||
|  |     GridStopWatch bstimer; | ||||||
|  |      | ||||||
|  |     nersc_csum=0; | ||||||
|  |     scidac_csuma=0; | ||||||
|  |     scidac_csumb=0; | ||||||
|  |  | ||||||
|  |     int ndim                 = grid->Dimensions(); | ||||||
|  |     int nrank                = grid->ProcessorCount(); | ||||||
|  |     int myrank               = grid->ThisRank(); | ||||||
|  |  | ||||||
|  |     Coordinate  psizes = grid->ProcessorGrid();  | ||||||
|  |     Coordinate  pcoor  = grid->ThisProcessorCoor(); | ||||||
|  |     Coordinate gLattice= grid->GlobalDimensions(); | ||||||
|  |     Coordinate lLattice= grid->LocalDimensions(); | ||||||
|  |  | ||||||
|  |     Coordinate lStart(ndim); | ||||||
|  |     Coordinate gStart(ndim); | ||||||
|  |  | ||||||
|  |     // Flatten the file | ||||||
|  |     uint64_t lsites = grid->lSites(); | ||||||
|  |     if ( control & BINARYIO_MASTER_APPEND )  { | ||||||
|  |       assert(iodata.size()==1); | ||||||
|  |     } else { | ||||||
|  |       assert(lsites==iodata.size()); | ||||||
|  |     } | ||||||
|  |     for(int d=0;d<ndim;d++){ | ||||||
|  |       gStart[d] = lLattice[d]*pcoor[d]; | ||||||
|  |       lStart[d] = 0; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | #ifdef USE_MPI_IO | ||||||
|  |     std::vector<int> distribs(ndim,MPI_DISTRIBUTE_BLOCK); | ||||||
|  |     std::vector<int> dargs   (ndim,MPI_DISTRIBUTE_DFLT_DARG); | ||||||
|  |     MPI_Datatype mpiObject; | ||||||
|  |     MPI_Datatype fileArray; | ||||||
|  |     MPI_Datatype localArray; | ||||||
|  |     MPI_Datatype mpiword; | ||||||
|  |     MPI_Offset disp = offset; | ||||||
|  |     MPI_File fh ; | ||||||
|  |     MPI_Status status; | ||||||
|  |     int numword; | ||||||
|  |  | ||||||
|  |     if ( sizeof( word ) == sizeof(float ) ) { | ||||||
|  |       numword = sizeof(fobj)/sizeof(float); | ||||||
|  |       mpiword = MPI_FLOAT; | ||||||
|  |     } else { | ||||||
|  |       numword = sizeof(fobj)/sizeof(double); | ||||||
|  |       mpiword = MPI_DOUBLE; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     ////////////////////////////////////////////////////////////////////////////// | ||||||
|  |     // Sobj in MPI phrasing | ||||||
|  |     ////////////////////////////////////////////////////////////////////////////// | ||||||
|  |     int ierr; | ||||||
|  |     ierr = MPI_Type_contiguous(numword,mpiword,&mpiObject);    assert(ierr==0); | ||||||
|  |     ierr = MPI_Type_commit(&mpiObject); | ||||||
|  |  | ||||||
|  |     ////////////////////////////////////////////////////////////////////////////// | ||||||
|  |     // File global array data type | ||||||
|  |     ////////////////////////////////////////////////////////////////////////////// | ||||||
|  |     ierr=MPI_Type_create_subarray(ndim,&gLattice[0],&lLattice[0],&gStart[0],MPI_ORDER_FORTRAN, mpiObject,&fileArray);    assert(ierr==0); | ||||||
|  |     ierr=MPI_Type_commit(&fileArray);    assert(ierr==0); | ||||||
|  |  | ||||||
|  |     ////////////////////////////////////////////////////////////////////////////// | ||||||
|  |     // local lattice array | ||||||
|  |     ////////////////////////////////////////////////////////////////////////////// | ||||||
|  |     ierr=MPI_Type_create_subarray(ndim,&lLattice[0],&lLattice[0],&lStart[0],MPI_ORDER_FORTRAN, mpiObject,&localArray);    assert(ierr==0); | ||||||
|  |     ierr=MPI_Type_commit(&localArray);    assert(ierr==0); | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  |     ////////////////////////////////////////////////////////////////////////////// | ||||||
|  |     // Byte order | ||||||
|  |     ////////////////////////////////////////////////////////////////////////////// | ||||||
|  |     int ieee32big = (format == std::string("IEEE32BIG")); | ||||||
|  |     int ieee32    = (format == std::string("IEEE32")); | ||||||
|  |     int ieee64big = (format == std::string("IEEE64BIG")); | ||||||
|  |     int ieee64    = (format == std::string("IEEE64")); | ||||||
|  |     assert(ieee64||ieee32|ieee64big||ieee32big); | ||||||
|  |     assert((ieee64+ieee32+ieee64big+ieee32big)==1); | ||||||
|  |     ////////////////////////////////////////////////////////////////////////////// | ||||||
|  |     // Do the I/O | ||||||
|  |     ////////////////////////////////////////////////////////////////////////////// | ||||||
|  |     if ( control & BINARYIO_READ ) {  | ||||||
|  |  | ||||||
|  |       timer.Start(); | ||||||
|  |  | ||||||
|  |       if ( (control & BINARYIO_LEXICOGRAPHIC) && (nrank > 1) ) { | ||||||
|  | #ifdef USE_MPI_IO | ||||||
|  | 	std::cout<< GridLogMessage<<"IOobject: MPI read I/O "<< file<< std::endl; | ||||||
|  | 	ierr=MPI_File_open(grid->communicator,(char *) file.c_str(), MPI_MODE_RDONLY, MPI_INFO_NULL, &fh);    assert(ierr==0); | ||||||
|  | 	ierr=MPI_File_set_view(fh, disp, mpiObject, fileArray, "native", MPI_INFO_NULL);    assert(ierr==0); | ||||||
|  | 	ierr=MPI_File_read_all(fh, &iodata[0], 1, localArray, &status);    assert(ierr==0); | ||||||
|  | 	MPI_File_close(&fh); | ||||||
|  | 	MPI_Type_free(&fileArray); | ||||||
|  | 	MPI_Type_free(&localArray); | ||||||
|  | #else  | ||||||
|  | 	assert(0); | ||||||
|  | #endif | ||||||
|  |       } else { | ||||||
|  | 	std::cout << GridLogMessage <<"IOobject: C++ read I/O " << file << " : " | ||||||
|  |                   << iodata.size() * sizeof(fobj) << " bytes and offset " << offset << std::endl; | ||||||
|  |         std::ifstream fin; | ||||||
|  | 	fin.open(file, std::ios::binary | std::ios::in); | ||||||
|  |         if (control & BINARYIO_MASTER_APPEND) | ||||||
|  |         { | ||||||
|  |           fin.seekg(-sizeof(fobj), fin.end); | ||||||
|  |         } | ||||||
|  |         else | ||||||
|  |         { | ||||||
|  |           fin.seekg(offset + myrank * lsites * sizeof(fobj)); | ||||||
|  |         } | ||||||
|  |         fin.read((char *)&iodata[0], iodata.size() * sizeof(fobj)); | ||||||
|  |         assert(fin.fail() == 0); | ||||||
|  |         fin.close(); | ||||||
|  |       } | ||||||
|  |       timer.Stop(); | ||||||
|  |  | ||||||
|  |       grid->Barrier(); | ||||||
|  |  | ||||||
|  |       bstimer.Start(); | ||||||
|  |       ScidacChecksum(grid,iodata,scidac_csuma,scidac_csumb); | ||||||
|  |       if (ieee32big) be32toh_v((void *)&iodata[0], sizeof(fobj)*iodata.size()); | ||||||
|  |       if (ieee32)    le32toh_v((void *)&iodata[0], sizeof(fobj)*iodata.size()); | ||||||
|  |       if (ieee64big) be64toh_v((void *)&iodata[0], sizeof(fobj)*iodata.size()); | ||||||
|  |       if (ieee64)    le64toh_v((void *)&iodata[0], sizeof(fobj)*iodata.size()); | ||||||
|  |       NerscChecksum(grid,iodata,nersc_csum); | ||||||
|  |       bstimer.Stop(); | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     if ( control & BINARYIO_WRITE ) {  | ||||||
|  |  | ||||||
|  |       bstimer.Start(); | ||||||
|  |       NerscChecksum(grid,iodata,nersc_csum); | ||||||
|  |       if (ieee32big) htobe32_v((void *)&iodata[0], sizeof(fobj)*iodata.size()); | ||||||
|  |       if (ieee32)    htole32_v((void *)&iodata[0], sizeof(fobj)*iodata.size()); | ||||||
|  |       if (ieee64big) htobe64_v((void *)&iodata[0], sizeof(fobj)*iodata.size()); | ||||||
|  |       if (ieee64)    htole64_v((void *)&iodata[0], sizeof(fobj)*iodata.size()); | ||||||
|  |       ScidacChecksum(grid,iodata,scidac_csuma,scidac_csumb); | ||||||
|  |       bstimer.Stop(); | ||||||
|  |  | ||||||
|  |       grid->Barrier(); | ||||||
|  |  | ||||||
|  |       timer.Start(); | ||||||
|  |       if ( (control & BINARYIO_LEXICOGRAPHIC) && (nrank > 1) ) { | ||||||
|  | #ifdef USE_MPI_IO | ||||||
|  |         std::cout << GridLogMessage <<"IOobject: MPI write I/O " << file << std::endl; | ||||||
|  |         ierr = MPI_File_open(grid->communicator, (char *)file.c_str(), MPI_MODE_RDWR | MPI_MODE_CREATE, MPI_INFO_NULL, &fh); | ||||||
|  | 	//        std::cout << GridLogMessage << "Checking for errors" << std::endl; | ||||||
|  |         if (ierr != MPI_SUCCESS) | ||||||
|  |         { | ||||||
|  |           char error_string[BUFSIZ]; | ||||||
|  |           int length_of_error_string, error_class; | ||||||
|  |  | ||||||
|  |           MPI_Error_class(ierr, &error_class); | ||||||
|  |           MPI_Error_string(error_class, error_string, &length_of_error_string); | ||||||
|  |           fprintf(stderr, "%3d: %s\n", myrank, error_string); | ||||||
|  |           MPI_Error_string(ierr, error_string, &length_of_error_string); | ||||||
|  |           fprintf(stderr, "%3d: %s\n", myrank, error_string); | ||||||
|  |           MPI_Abort(MPI_COMM_WORLD, 1); //assert(ierr == 0); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         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); | ||||||
|  |         assert(ierr == 0); | ||||||
|  |  | ||||||
|  |         std::cout << GridLogDebug << "MPI write I/O write all " << file << std::endl; | ||||||
|  |         ierr = MPI_File_write_all(fh, &iodata[0], 1, localArray, &status); | ||||||
|  |         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_Type_free(&fileArray); | ||||||
|  |         MPI_Type_free(&localArray); | ||||||
|  | #else  | ||||||
|  | 	assert(0); | ||||||
|  | #endif | ||||||
|  |       } else {  | ||||||
|  |  | ||||||
|  |         std::cout << GridLogMessage << "IOobject: C++ write I/O " << file << " : " | ||||||
|  |                   << iodata.size() * sizeof(fobj) << " bytes and offset " << offset << std::endl; | ||||||
|  |          | ||||||
|  | 	std::ofstream fout;  | ||||||
|  | 	fout.exceptions ( std::fstream::failbit | std::fstream::badbit ); | ||||||
|  | 	try { | ||||||
|  | 	  if (offset) { // Must already exist and contain data | ||||||
|  | 	    fout.open(file,std::ios::binary|std::ios::out|std::ios::in); | ||||||
|  | 	  } else {     // Allow create | ||||||
|  | 	    fout.open(file,std::ios::binary|std::ios::out); | ||||||
|  | 	  } | ||||||
|  | 	} catch (const std::fstream::failure& exc) { | ||||||
|  | 	  std::cout << GridLogError << "Error in opening the file " << file << " for output" <<std::endl; | ||||||
|  | 	  std::cout << GridLogError << "Exception description: " << exc.what() << std::endl; | ||||||
|  | 	  //	  std::cout << GridLogError << "Probable cause: wrong path, inaccessible location "<< std::endl; | ||||||
|  | #ifdef USE_MPI_IO | ||||||
|  | 	  MPI_Abort(MPI_COMM_WORLD,1); | ||||||
|  | #else | ||||||
|  | 	  exit(1); | ||||||
|  | #endif | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | 	if ( control & BINARYIO_MASTER_APPEND )  { | ||||||
|  | 	  try { | ||||||
|  | 	    fout.seekp(0,fout.end); | ||||||
|  | 	  } catch (const std::fstream::failure& exc) { | ||||||
|  | 	    std::cout << "Exception in seeking file end " << file << std::endl; | ||||||
|  | 	  } | ||||||
|  | 	} else { | ||||||
|  | 	  try {  | ||||||
|  | 	    fout.seekp(offset+myrank*lsites*sizeof(fobj)); | ||||||
|  | 	  } catch (const std::fstream::failure& exc) { | ||||||
|  | 	    std::cout << "Exception in seeking file " << file <<" offset "<< offset << std::endl; | ||||||
|  | 	  } | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	try { | ||||||
|  | 	  fout.write((char *)&iodata[0],iodata.size()*sizeof(fobj));//assert( fout.fail()==0); | ||||||
|  | 	} | ||||||
|  | 	catch (const std::fstream::failure& exc) { | ||||||
|  | 	  std::cout << "Exception in writing file " << file << std::endl; | ||||||
|  | 	  std::cout << GridLogError << "Exception description: "<< exc.what() << std::endl; | ||||||
|  | #ifdef USE_MPI_IO | ||||||
|  | 	  MPI_Abort(MPI_COMM_WORLD,1); | ||||||
|  | #else | ||||||
|  | 	  exit(1); | ||||||
|  | #endif | ||||||
|  | 	} | ||||||
|  |   offset  = fout.tellp(); | ||||||
|  | 	fout.close(); | ||||||
|  |       } | ||||||
|  |       timer.Stop(); | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     std::cout<<GridLogMessage<<"IOobject: "; | ||||||
|  |     if ( control & BINARYIO_READ) std::cout << " read  "; | ||||||
|  |     else                          std::cout << " write "; | ||||||
|  |     uint64_t bytes = sizeof(fobj)*iodata.size()*nrank; | ||||||
|  |     std::cout<< bytes <<" bytes in "<<timer.Elapsed() <<" " | ||||||
|  | 	     << (double)bytes/ (double)timer.useconds() <<" MB/s "<<std::endl; | ||||||
|  |  | ||||||
|  |     std::cout<<GridLogMessage<<"IOobject: endian and checksum overhead "<<bstimer.Elapsed()  <<std::endl; | ||||||
|  |  | ||||||
|  |     ////////////////////////////////////////////////////////////////////////////// | ||||||
|  |     // Safety check | ||||||
|  |     ////////////////////////////////////////////////////////////////////////////// | ||||||
|  |     // if the data size is 1 we do not want to sum over the MPI ranks | ||||||
|  |     if (iodata.size() != 1){ | ||||||
|  |       grid->Barrier(); | ||||||
|  |       grid->GlobalSum(nersc_csum); | ||||||
|  |       grid->GlobalXOR(scidac_csuma); | ||||||
|  |       grid->GlobalXOR(scidac_csumb); | ||||||
|  |       grid->Barrier(); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   ///////////////////////////////////////////////////////////////////////////// | ||||||
|  |   // Read a Lattice of object | ||||||
|  |   ////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  |   template<class vobj,class fobj,class munger> | ||||||
|  |   static inline void readLatticeObject(Lattice<vobj> &Umu, | ||||||
|  | 				       std::string file, | ||||||
|  | 				       munger munge, | ||||||
|  | 				       uint64_t offset, | ||||||
|  | 				       const std::string &format, | ||||||
|  | 				       uint32_t &nersc_csum, | ||||||
|  | 				       uint32_t &scidac_csuma, | ||||||
|  | 				       uint32_t &scidac_csumb) | ||||||
|  |   { | ||||||
|  |     typedef typename vobj::scalar_object sobj; | ||||||
|  |     typedef typename vobj::Realified::scalar_type word;    word w=0; | ||||||
|  |  | ||||||
|  |     GridBase *grid = Umu.Grid(); | ||||||
|  |     uint64_t lsites = grid->lSites(); | ||||||
|  |  | ||||||
|  |     std::vector<sobj> scalardata(lsites);  | ||||||
|  |     std::vector<fobj>     iodata(lsites); // Munge, checksum, byte order in here | ||||||
|  |      | ||||||
|  |     IOobject(w,grid,iodata,file,offset,format,BINARYIO_READ|BINARYIO_LEXICOGRAPHIC, | ||||||
|  | 	     nersc_csum,scidac_csuma,scidac_csumb); | ||||||
|  |  | ||||||
|  |     GridStopWatch timer;  | ||||||
|  |     timer.Start(); | ||||||
|  |  | ||||||
|  |     thread_for(x,lsites, { munge(iodata[x], scalardata[x]); }); | ||||||
|  |  | ||||||
|  |     vectorizeFromLexOrdArray(scalardata,Umu);     | ||||||
|  |     grid->Barrier(); | ||||||
|  |  | ||||||
|  |     timer.Stop(); | ||||||
|  |     std::cout<<GridLogMessage<<"readLatticeObject: vectorize overhead "<<timer.Elapsed()  <<std::endl; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   ///////////////////////////////////////////////////////////////////////////// | ||||||
|  |   // Write a Lattice of object | ||||||
|  |   ////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  |   template<class vobj,class fobj,class munger> | ||||||
|  |     static inline void writeLatticeObject(Lattice<vobj> &Umu, | ||||||
|  | 					  std::string file, | ||||||
|  | 					  munger munge, | ||||||
|  | 					  uint64_t offset, | ||||||
|  | 					  const std::string &format, | ||||||
|  | 					  uint32_t &nersc_csum, | ||||||
|  | 					  uint32_t &scidac_csuma, | ||||||
|  | 					  uint32_t &scidac_csumb) | ||||||
|  |   { | ||||||
|  |     typedef typename vobj::scalar_object sobj; | ||||||
|  |     typedef typename vobj::Realified::scalar_type word;    word w=0; | ||||||
|  |     GridBase *grid = Umu.Grid(); | ||||||
|  |     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<fobj>     iodata(lsites); // Munge, checksum, byte order in here | ||||||
|  |  | ||||||
|  |     ////////////////////////////////////////////////////////////////////////////// | ||||||
|  |     // Munge [ .e.g 3rd row recon ] | ||||||
|  |     ////////////////////////////////////////////////////////////////////////////// | ||||||
|  |     GridStopWatch timer; timer.Start(); | ||||||
|  |     unvectorizeToLexOrdArray(scalardata,Umu);     | ||||||
|  |  | ||||||
|  |     thread_for(x, lsites, { munge(scalardata[x],iodata[x]); }); | ||||||
|  |  | ||||||
|  |     grid->Barrier(); | ||||||
|  |     timer.Stop(); | ||||||
|  |     while (attemptsLeft >= 0) | ||||||
|  |     { | ||||||
|  |       grid->Barrier(); | ||||||
|  |       IOobject(w,grid,iodata,file,offset,format,BINARYIO_WRITE|BINARYIO_LEXICOGRAPHIC, | ||||||
|  | 	             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; | ||||||
|  |           thread_for(x,lsites, { munge(scalardata[x],iodata[x]); }); | ||||||
|  |         } | ||||||
|  |         else | ||||||
|  |         { | ||||||
|  |           std::cout << GridLogMessage << "writeLatticeObject: read test checksum correct" << std::endl; | ||||||
|  |           break; | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |       attemptsLeft--; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |  | ||||||
|  |     std::cout<<GridLogMessage<<"writeLatticeObject: unvectorize overhead "<<timer.Elapsed()  <<std::endl; | ||||||
|  |   } | ||||||
|  |    | ||||||
|  |   ///////////////////////////////////////////////////////////////////////////// | ||||||
|  |   // Read a RNG;  use IOobject and lexico map to an array of state  | ||||||
|  |   ////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  |   static inline void readRNG(GridSerialRNG &serial_rng, | ||||||
|  | 			     GridParallelRNG ¶llel_rng, | ||||||
|  | 			     std::string file, | ||||||
|  | 			     uint64_t offset, | ||||||
|  | 			     uint32_t &nersc_csum, | ||||||
|  | 			     uint32_t &scidac_csuma, | ||||||
|  | 			     uint32_t &scidac_csumb) | ||||||
|  |   { | ||||||
|  |     typedef typename GridSerialRNG::RngStateType RngStateType; | ||||||
|  |     const int RngStateCount = GridSerialRNG::RngStateCount; | ||||||
|  |     typedef std::array<RngStateType,RngStateCount> RNGstate; | ||||||
|  |     typedef RngStateType word;    word w=0; | ||||||
|  |  | ||||||
|  |     std::string format = "IEEE32BIG"; | ||||||
|  |  | ||||||
|  |     GridBase *grid = parallel_rng.Grid(); | ||||||
|  |     uint64_t gsites = grid->gSites(); | ||||||
|  |     uint64_t lsites = grid->lSites(); | ||||||
|  |  | ||||||
|  |     uint32_t nersc_csum_tmp   = 0; | ||||||
|  |     uint32_t scidac_csuma_tmp = 0; | ||||||
|  |     uint32_t scidac_csumb_tmp = 0; | ||||||
|  |  | ||||||
|  |     GridStopWatch timer; | ||||||
|  |  | ||||||
|  |     std::cout << GridLogMessage << "RNG read I/O on file " << file << std::endl; | ||||||
|  |  | ||||||
|  |     std::vector<RNGstate> iodata(lsites); | ||||||
|  |     IOobject(w,grid,iodata,file,offset,format,BINARYIO_READ|BINARYIO_LEXICOGRAPHIC, | ||||||
|  | 	     nersc_csum,scidac_csuma,scidac_csumb); | ||||||
|  |  | ||||||
|  |     timer.Start(); | ||||||
|  |     thread_for(lidx,lsites,{ | ||||||
|  |       std::vector<RngStateType> tmp(RngStateCount); | ||||||
|  |       std::copy(iodata[lidx].begin(),iodata[lidx].end(),tmp.begin()); | ||||||
|  |       parallel_rng.SetState(tmp,lidx); | ||||||
|  |       }); | ||||||
|  |     timer.Stop(); | ||||||
|  |  | ||||||
|  |     iodata.resize(1); | ||||||
|  |     IOobject(w,grid,iodata,file,offset,format,BINARYIO_READ|BINARYIO_MASTER_APPEND, | ||||||
|  | 	     nersc_csum_tmp,scidac_csuma_tmp,scidac_csumb_tmp); | ||||||
|  |  | ||||||
|  |     { | ||||||
|  |       std::vector<RngStateType> tmp(RngStateCount); | ||||||
|  |       std::copy(iodata[0].begin(),iodata[0].end(),tmp.begin()); | ||||||
|  |       serial_rng.SetState(tmp,0); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     nersc_csum   = nersc_csum   + nersc_csum_tmp; | ||||||
|  |     scidac_csuma = scidac_csuma ^ scidac_csuma_tmp; | ||||||
|  |     scidac_csumb = scidac_csumb ^ scidac_csumb_tmp; | ||||||
|  |  | ||||||
|  |     std::cout << GridLogMessage << "RNG file nersc_checksum   " << std::hex << nersc_csum << std::dec << std::endl; | ||||||
|  |     std::cout << GridLogMessage << "RNG file scidac_checksuma " << std::hex << scidac_csuma << std::dec << std::endl; | ||||||
|  |     std::cout << GridLogMessage << "RNG file scidac_checksumb " << std::hex << scidac_csumb << std::dec << std::endl; | ||||||
|  |  | ||||||
|  |     std::cout << GridLogMessage << "RNG state overhead " << timer.Elapsed() << std::endl; | ||||||
|  |   } | ||||||
|  |   ///////////////////////////////////////////////////////////////////////////// | ||||||
|  |   // Write a RNG; lexico map to an array of state and use IOobject | ||||||
|  |   ////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  |   static inline void writeRNG(GridSerialRNG &serial_rng, | ||||||
|  | 			      GridParallelRNG ¶llel_rng, | ||||||
|  | 			      std::string file, | ||||||
|  | 			      uint64_t offset, | ||||||
|  | 			      uint32_t &nersc_csum, | ||||||
|  | 			      uint32_t &scidac_csuma, | ||||||
|  | 			      uint32_t &scidac_csumb) | ||||||
|  |   { | ||||||
|  |     typedef typename GridSerialRNG::RngStateType RngStateType; | ||||||
|  |     typedef RngStateType word; word w=0; | ||||||
|  |     const int RngStateCount = GridSerialRNG::RngStateCount; | ||||||
|  |     typedef std::array<RngStateType,RngStateCount> RNGstate; | ||||||
|  |  | ||||||
|  |     GridBase *grid = parallel_rng.Grid(); | ||||||
|  |     uint64_t gsites = grid->gSites(); | ||||||
|  |     uint64_t lsites = grid->lSites(); | ||||||
|  |  | ||||||
|  |     uint32_t nersc_csum_tmp; | ||||||
|  |     uint32_t scidac_csuma_tmp; | ||||||
|  |     uint32_t scidac_csumb_tmp; | ||||||
|  |  | ||||||
|  |     GridStopWatch timer; | ||||||
|  |     std::string format = "IEEE32BIG"; | ||||||
|  |  | ||||||
|  |     std::cout << GridLogMessage << "RNG write I/O on file " << file << std::endl; | ||||||
|  |  | ||||||
|  |     timer.Start(); | ||||||
|  |     std::vector<RNGstate> iodata(lsites); | ||||||
|  |     thread_for(lidx,lsites,{ | ||||||
|  |       std::vector<RngStateType> tmp(RngStateCount); | ||||||
|  |       parallel_rng.GetState(tmp,lidx); | ||||||
|  |       std::copy(tmp.begin(),tmp.end(),iodata[lidx].begin()); | ||||||
|  |     }); | ||||||
|  |     timer.Stop(); | ||||||
|  |  | ||||||
|  |     IOobject(w,grid,iodata,file,offset,format,BINARYIO_WRITE|BINARYIO_LEXICOGRAPHIC, | ||||||
|  | 	     nersc_csum,scidac_csuma,scidac_csumb); | ||||||
|  |     iodata.resize(1); | ||||||
|  |     { | ||||||
|  |       std::vector<RngStateType> tmp(RngStateCount); | ||||||
|  |       serial_rng.GetState(tmp,0); | ||||||
|  |       std::copy(tmp.begin(),tmp.end(),iodata[0].begin()); | ||||||
|  |     } | ||||||
|  |     IOobject(w,grid,iodata,file,offset,format,BINARYIO_WRITE|BINARYIO_MASTER_APPEND, | ||||||
|  | 	     nersc_csum_tmp,scidac_csuma_tmp,scidac_csumb_tmp); | ||||||
|  |  | ||||||
|  |     nersc_csum   = nersc_csum   + nersc_csum_tmp; | ||||||
|  |     scidac_csuma = scidac_csuma ^ scidac_csuma_tmp; | ||||||
|  |     scidac_csumb = scidac_csumb ^ scidac_csumb_tmp; | ||||||
|  |      | ||||||
|  |     std::cout << GridLogMessage << "RNG file checksum " << std::hex << nersc_csum    << std::dec << std::endl; | ||||||
|  |     std::cout << GridLogMessage << "RNG file checksuma " << std::hex << scidac_csuma << std::dec << std::endl; | ||||||
|  |     std::cout << GridLogMessage << "RNG file checksumb " << std::hex << scidac_csumb << std::dec << std::endl; | ||||||
|  |     std::cout << GridLogMessage << "RNG state overhead " << timer.Elapsed() << std::endl; | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | NAMESPACE_END(Grid); | ||||||
							
								
								
									
										937
									
								
								Grid/parallelIO/IldgIO.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										937
									
								
								Grid/parallelIO/IldgIO.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,937 @@ | |||||||
|  | /************************************************************************************* | ||||||
|  |  | ||||||
|  | Grid physics library, www.github.com/paboyle/Grid | ||||||
|  |  | ||||||
|  | Source file: ./lib/parallelIO/IldgIO.h | ||||||
|  |  | ||||||
|  | Copyright (C) 2015 | ||||||
|  |  | ||||||
|  | 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 */ | ||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #ifdef HAVE_LIME | ||||||
|  | #include <algorithm> | ||||||
|  | #include <fstream> | ||||||
|  | #include <iomanip> | ||||||
|  | #include <iostream> | ||||||
|  | #include <map> | ||||||
|  |  | ||||||
|  | #include <pwd.h> | ||||||
|  | #include <sys/utsname.h> | ||||||
|  | #include <unistd.h> | ||||||
|  |  | ||||||
|  | //C-Lime is a must have for this functionality | ||||||
|  | extern "C" {   | ||||||
|  | #include "lime.h" | ||||||
|  | } | ||||||
|  |  | ||||||
|  | NAMESPACE_BEGIN(Grid); | ||||||
|  |  | ||||||
|  | #define GRID_FIELD_NORM "FieldNormMetaData" | ||||||
|  | #define GRID_FIELD_NORM_CALC(FieldNormMetaData_, n2ck) \ | ||||||
|  | 0.5*fabs(FieldNormMetaData_.norm2 - n2ck)/(FieldNormMetaData_.norm2 + n2ck) | ||||||
|  | #define GRID_FIELD_NORM_CHECK(FieldNormMetaData_, n2ck) \ | ||||||
|  | assert(GRID_FIELD_NORM_CALC(FieldNormMetaData_, n2ck) < 1.0e-5); | ||||||
|  |  | ||||||
|  |   ///////////////////////////////// | ||||||
|  |   // Encode word types as strings | ||||||
|  |   ///////////////////////////////// | ||||||
|  |  template<class word> inline std::string ScidacWordMnemonic(void){ return std::string("unknown"); } | ||||||
|  |  template<> inline std::string ScidacWordMnemonic<double>  (void){ return std::string("D"); } | ||||||
|  |  template<> inline std::string ScidacWordMnemonic<float>   (void){ return std::string("F"); } | ||||||
|  |  template<> inline std::string ScidacWordMnemonic< int32_t>(void){ return std::string("I32_t"); } | ||||||
|  |  template<> inline std::string ScidacWordMnemonic<uint32_t>(void){ return std::string("U32_t"); } | ||||||
|  |  template<> inline std::string ScidacWordMnemonic< int64_t>(void){ return std::string("I64_t"); } | ||||||
|  |  template<> inline std::string ScidacWordMnemonic<uint64_t>(void){ return std::string("U64_t"); } | ||||||
|  |  | ||||||
|  |   ///////////////////////////////////////// | ||||||
|  |   // Encode a generic tensor as a string | ||||||
|  |   ///////////////////////////////////////// | ||||||
|  |  template<class vobj> std::string ScidacRecordTypeString(int &colors, int &spins, int & typesize,int &datacount) {  | ||||||
|  |  | ||||||
|  |    typedef typename getPrecision<vobj>::real_scalar_type stype; | ||||||
|  |  | ||||||
|  |    int _ColourN       = indexRank<ColourIndex,vobj>(); | ||||||
|  |    int _ColourScalar  =  isScalar<ColourIndex,vobj>(); | ||||||
|  |    int _ColourVector  =  isVector<ColourIndex,vobj>(); | ||||||
|  |    int _ColourMatrix  =  isMatrix<ColourIndex,vobj>(); | ||||||
|  |  | ||||||
|  |    int _SpinN       = indexRank<SpinIndex,vobj>(); | ||||||
|  |    int _SpinScalar  =  isScalar<SpinIndex,vobj>(); | ||||||
|  |    int _SpinVector  =  isVector<SpinIndex,vobj>(); | ||||||
|  |    int _SpinMatrix  =  isMatrix<SpinIndex,vobj>(); | ||||||
|  |  | ||||||
|  |    int _LorentzN       = indexRank<LorentzIndex,vobj>(); | ||||||
|  |    int _LorentzScalar  =  isScalar<LorentzIndex,vobj>(); | ||||||
|  |    int _LorentzVector  =  isVector<LorentzIndex,vobj>(); | ||||||
|  |    int _LorentzMatrix  =  isMatrix<LorentzIndex,vobj>(); | ||||||
|  |  | ||||||
|  |    std::stringstream stream; | ||||||
|  |  | ||||||
|  |    stream << "GRID_"; | ||||||
|  |    stream << ScidacWordMnemonic<stype>(); | ||||||
|  |  | ||||||
|  |    if ( _LorentzVector )   stream << "_LorentzVector"<<_LorentzN; | ||||||
|  |    if ( _LorentzMatrix )   stream << "_LorentzMatrix"<<_LorentzN; | ||||||
|  |  | ||||||
|  |    if ( _SpinVector )   stream << "_SpinVector"<<_SpinN; | ||||||
|  |    if ( _SpinMatrix )   stream << "_SpinMatrix"<<_SpinN; | ||||||
|  |  | ||||||
|  |    if ( _ColourVector )   stream << "_ColourVector"<<_ColourN; | ||||||
|  |    if ( _ColourMatrix )   stream << "_ColourMatrix"<<_ColourN; | ||||||
|  |  | ||||||
|  |    if ( _ColourScalar && _LorentzScalar && _SpinScalar )   stream << "_Complex"; | ||||||
|  |  | ||||||
|  |  | ||||||
|  |    typesize = sizeof(typename vobj::scalar_type); | ||||||
|  |  | ||||||
|  |    if ( _ColourMatrix ) typesize*= _ColourN*_ColourN; | ||||||
|  |    else                 typesize*= _ColourN; | ||||||
|  |  | ||||||
|  |    if ( _SpinMatrix )   typesize*= _SpinN*_SpinN; | ||||||
|  |    else                 typesize*= _SpinN; | ||||||
|  |  | ||||||
|  |    colors    = _ColourN; | ||||||
|  |    spins     = _SpinN; | ||||||
|  |    datacount = _LorentzN; | ||||||
|  |  | ||||||
|  |    return stream.str(); | ||||||
|  |  } | ||||||
|  |   | ||||||
|  |  template<class vobj> std::string ScidacRecordTypeString(Lattice<vobj> & lat,int &colors, int &spins, int & typesize,int &datacount) {  | ||||||
|  |    return ScidacRecordTypeString<vobj>(colors,spins,typesize,datacount); | ||||||
|  |  }; | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  //////////////////////////////////////////////////////////// | ||||||
|  |  // Helper to fill out metadata | ||||||
|  |  //////////////////////////////////////////////////////////// | ||||||
|  |  template<class vobj> void ScidacMetaData(Lattice<vobj> & field, | ||||||
|  | 					  FieldMetaData &header, | ||||||
|  | 					  scidacRecord & _scidacRecord, | ||||||
|  | 					  scidacFile   & _scidacFile)  | ||||||
|  |  { | ||||||
|  |    typedef typename getPrecision<vobj>::real_scalar_type stype; | ||||||
|  |  | ||||||
|  |    ///////////////////////////////////// | ||||||
|  |    // Pull Grid's metadata | ||||||
|  |    ///////////////////////////////////// | ||||||
|  |    PrepareMetaData(field,header); | ||||||
|  |  | ||||||
|  |    ///////////////////////////////////// | ||||||
|  |    // Scidac Private File structure | ||||||
|  |    ///////////////////////////////////// | ||||||
|  |    _scidacFile              = scidacFile(field.Grid()); | ||||||
|  |  | ||||||
|  |    ///////////////////////////////////// | ||||||
|  |    // Scidac Private Record structure | ||||||
|  |    ///////////////////////////////////// | ||||||
|  |    scidacRecord sr; | ||||||
|  |    sr.datatype   = ScidacRecordTypeString(field,sr.colors,sr.spins,sr.typesize,sr.datacount); | ||||||
|  |    sr.date       = header.creation_date; | ||||||
|  |    sr.precision  = ScidacWordMnemonic<stype>(); | ||||||
|  |    sr.recordtype = GRID_IO_FIELD; | ||||||
|  |  | ||||||
|  |    _scidacRecord = sr; | ||||||
|  |  | ||||||
|  |    //   std::cout << GridLogMessage << "Build SciDAC datatype " <<sr.datatype<<std::endl; | ||||||
|  |  } | ||||||
|  |   | ||||||
|  |  /////////////////////////////////////////////////////// | ||||||
|  |  // Scidac checksum | ||||||
|  |  /////////////////////////////////////////////////////// | ||||||
|  |  static int scidacChecksumVerify(scidacChecksum &scidacChecksum_,uint32_t scidac_csuma,uint32_t scidac_csumb) | ||||||
|  |  { | ||||||
|  |    uint32_t scidac_checksuma = stoull(scidacChecksum_.suma,0,16); | ||||||
|  |    uint32_t scidac_checksumb = stoull(scidacChecksum_.sumb,0,16); | ||||||
|  |    if ( scidac_csuma !=scidac_checksuma) return 0; | ||||||
|  |    if ( scidac_csumb !=scidac_checksumb) return 0; | ||||||
|  |    return 1; | ||||||
|  |  } | ||||||
|  |  | ||||||
|  | //////////////////////////////////////////////////////////////////////////////////// | ||||||
|  | // Lime, ILDG and Scidac I/O classes | ||||||
|  | //////////////////////////////////////////////////////////////////////////////////// | ||||||
|  | class GridLimeReader : public BinaryIO { | ||||||
|  |  public: | ||||||
|  |    /////////////////////////////////////////////////// | ||||||
|  |    // FIXME: format for RNG? Now just binary out instead | ||||||
|  |    /////////////////////////////////////////////////// | ||||||
|  |  | ||||||
|  |    FILE       *File; | ||||||
|  |    LimeReader *LimeR; | ||||||
|  |    std::string filename; | ||||||
|  |  | ||||||
|  |    ///////////////////////////////////////////// | ||||||
|  |    // Open the file | ||||||
|  |    ///////////////////////////////////////////// | ||||||
|  |    void open(const std::string &_filename)  | ||||||
|  |    { | ||||||
|  |      filename= _filename; | ||||||
|  |      File = fopen(filename.c_str(), "r"); | ||||||
|  |      if (File == nullptr) | ||||||
|  |      { | ||||||
|  |        std::cerr << "cannot open file '" << filename << "'" << std::endl; | ||||||
|  |        abort(); | ||||||
|  |      } | ||||||
|  |      LimeR = limeCreateReader(File); | ||||||
|  |    } | ||||||
|  |    ///////////////////////////////////////////// | ||||||
|  |    // Close the file | ||||||
|  |    ///////////////////////////////////////////// | ||||||
|  |    void close(void){ | ||||||
|  |      fclose(File); | ||||||
|  |      //     limeDestroyReader(LimeR); | ||||||
|  |    } | ||||||
|  |  | ||||||
|  |   //////////////////////////////////////////// | ||||||
|  |   // Read a generic lattice field and verify checksum | ||||||
|  |   //////////////////////////////////////////// | ||||||
|  |   template<class vobj> | ||||||
|  |   void readLimeLatticeBinaryObject(Lattice<vobj> &field,std::string record_name) | ||||||
|  |   { | ||||||
|  |     typedef typename vobj::scalar_object sobj; | ||||||
|  |     scidacChecksum scidacChecksum_; | ||||||
|  |     FieldNormMetaData  FieldNormMetaData_; | ||||||
|  |     uint32_t nersc_csum,scidac_csuma,scidac_csumb; | ||||||
|  |  | ||||||
|  |     std::string format = getFormatString<vobj>(); | ||||||
|  |  | ||||||
|  |     while ( limeReaderNextRecord(LimeR) == LIME_SUCCESS ) {  | ||||||
|  |  | ||||||
|  |       uint64_t file_bytes =limeReaderBytes(LimeR); | ||||||
|  |  | ||||||
|  |       //      std::cout << GridLogMessage << limeReaderType(LimeR) << " "<< file_bytes <<" bytes "<<std::endl; | ||||||
|  |       //      std::cout << GridLogMessage<< " readLimeObject seeking "<<  record_name <<" found record :" <<limeReaderType(LimeR) <<std::endl; | ||||||
|  |  | ||||||
|  |       if ( !strncmp(limeReaderType(LimeR), record_name.c_str(),strlen(record_name.c_str()) )  ) { | ||||||
|  |  | ||||||
|  | 	//	std::cout << GridLogMessage<< " readLimeLatticeBinaryObject matches ! " <<std::endl; | ||||||
|  |  | ||||||
|  | 	uint64_t PayloadSize = sizeof(sobj) * field.Grid()->_gsites; | ||||||
|  |  | ||||||
|  | 	//	std::cout << "R sizeof(sobj)= " <<sizeof(sobj)<<std::endl; | ||||||
|  | 	//	std::cout << "R Gsites " <<field.Grid()->_gsites<<std::endl; | ||||||
|  | 	//	std::cout << "R Payload expected " <<PayloadSize<<std::endl; | ||||||
|  | 	//	std::cout << "R file size " <<file_bytes <<std::endl; | ||||||
|  |  | ||||||
|  | 	assert(PayloadSize == file_bytes);// Must match or user error | ||||||
|  |  | ||||||
|  | 	uint64_t offset= ftello(File); | ||||||
|  | 	//	std::cout << " ReadLatticeObject from offset "<<offset << std::endl; | ||||||
|  | 	BinarySimpleMunger<sobj,sobj> munge; | ||||||
|  | 	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 | ||||||
|  | 	///////////////////////////////////////////// | ||||||
|  | 	readScidacChecksum(scidacChecksum_,FieldNormMetaData_); | ||||||
|  | 	///////////////////////////////////////////// | ||||||
|  | 	// Verify checksums | ||||||
|  | 	///////////////////////////////////////////// | ||||||
|  | 	if(FieldNormMetaData_.norm2 != 0.0){  | ||||||
|  | 	  RealD n2ck = norm2(field); | ||||||
|  | 	  std::cout << GridLogMessage << "Field norm: metadata= " << FieldNormMetaData_.norm2  | ||||||
|  |               << " / field= " << n2ck << " / rdiff= " << GRID_FIELD_NORM_CALC(FieldNormMetaData_,n2ck) << std::endl; | ||||||
|  | 	  GRID_FIELD_NORM_CHECK(FieldNormMetaData_,n2ck); | ||||||
|  | 	} | ||||||
|  | 	assert(scidacChecksumVerify(scidacChecksum_,scidac_csuma,scidac_csumb)==1); | ||||||
|  |  | ||||||
|  | 	// find out if next field is a GridFieldNorm | ||||||
|  | 	return; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   void readScidacChecksum(scidacChecksum     &scidacChecksum_, | ||||||
|  | 			  FieldNormMetaData  &FieldNormMetaData_) | ||||||
|  |   { | ||||||
|  |     FieldNormMetaData_.norm2 =0.0; | ||||||
|  |     std::string scidac_str(SCIDAC_CHECKSUM); | ||||||
|  |     std::string field_norm_str(GRID_FIELD_NORM); | ||||||
|  |     while ( limeReaderNextRecord(LimeR) == LIME_SUCCESS ) {  | ||||||
|  |       uint64_t nbytes = limeReaderBytes(LimeR);//size of this record (configuration) | ||||||
|  |       std::vector<char> xmlc(nbytes+1,'\0'); | ||||||
|  |       limeReaderReadData((void *)&xmlc[0], &nbytes, LimeR);     | ||||||
|  |       std::string xmlstring = std::string(&xmlc[0]); | ||||||
|  |       XmlReader RD(xmlstring, true, ""); | ||||||
|  |       if ( !strncmp(limeReaderType(LimeR), field_norm_str.c_str(),strlen(field_norm_str.c_str()) )  ) { | ||||||
|  | 	//	std::cout << "FieldNormMetaData "<<xmlstring<<std::endl; | ||||||
|  | 	read(RD,field_norm_str,FieldNormMetaData_); | ||||||
|  |       } | ||||||
|  |       if ( !strncmp(limeReaderType(LimeR), scidac_str.c_str(),strlen(scidac_str.c_str()) )  ) { | ||||||
|  | 	//	std::cout << SCIDAC_CHECKSUM << " " <<xmlstring<<std::endl; | ||||||
|  | 	read(RD,std::string("scidacChecksum"),scidacChecksum_); | ||||||
|  | 	return; | ||||||
|  |       }       | ||||||
|  |     } | ||||||
|  |     assert(0); | ||||||
|  |   } | ||||||
|  |   //////////////////////////////////////////// | ||||||
|  |   // Read a generic serialisable object | ||||||
|  |   //////////////////////////////////////////// | ||||||
|  |   void readLimeObject(std::string &xmlstring,std::string record_name) | ||||||
|  |   { | ||||||
|  |     // should this be a do while; can we miss a first record?? | ||||||
|  |     while ( limeReaderNextRecord(LimeR) == LIME_SUCCESS ) {  | ||||||
|  |  | ||||||
|  |       //      std::cout << GridLogMessage<< " readLimeObject seeking "<< record_name <<" found record :" <<limeReaderType(LimeR) <<std::endl; | ||||||
|  |       uint64_t nbytes = limeReaderBytes(LimeR);//size of this record (configuration) | ||||||
|  |  | ||||||
|  |       if ( !strncmp(limeReaderType(LimeR), record_name.c_str(),strlen(record_name.c_str()) )  ) { | ||||||
|  |  | ||||||
|  | 	//	std::cout << GridLogMessage<< " readLimeObject matches ! " << record_name <<std::endl; | ||||||
|  | 	std::vector<char> xmlc(nbytes+1,'\0'); | ||||||
|  | 	limeReaderReadData((void *)&xmlc[0], &nbytes, LimeR);     | ||||||
|  | 	//	std::cout << GridLogMessage<< " readLimeObject matches XML " << &xmlc[0] <<std::endl; | ||||||
|  |  | ||||||
|  | 	xmlstring = std::string(&xmlc[0]); | ||||||
|  | 	return; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |     }   | ||||||
|  |     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  | ||||||
|  | { | ||||||
|  |  public: | ||||||
|  |  | ||||||
|  |    /////////////////////////////////////////////////// | ||||||
|  |    // FIXME: format for RNG? Now just binary out instead | ||||||
|  |    // FIXME: collective calls or not ? | ||||||
|  |    //      : must know if I am the I/O boss | ||||||
|  |    /////////////////////////////////////////////////// | ||||||
|  |    FILE       *File; | ||||||
|  |    LimeWriter *LimeW; | ||||||
|  |    std::string filename; | ||||||
|  |    bool        boss_node; | ||||||
|  |    GridLimeWriter( bool isboss = true) { | ||||||
|  |      boss_node = isboss; | ||||||
|  |    } | ||||||
|  |    void open(const std::string &_filename) {  | ||||||
|  |      filename= _filename; | ||||||
|  |      if ( boss_node ) { | ||||||
|  |        File = fopen(filename.c_str(), "w"); | ||||||
|  |        LimeW = limeCreateWriter(File); assert(LimeW != NULL ); | ||||||
|  |      } | ||||||
|  |    } | ||||||
|  |    ///////////////////////////////////////////// | ||||||
|  |    // Close the file | ||||||
|  |    ///////////////////////////////////////////// | ||||||
|  |    void close(void) { | ||||||
|  |      if ( boss_node ) { | ||||||
|  |        fclose(File); | ||||||
|  |      } | ||||||
|  |      //  limeDestroyWriter(LimeW); | ||||||
|  |    } | ||||||
|  |   /////////////////////////////////////////////////////// | ||||||
|  |   // Lime utility functions | ||||||
|  |   /////////////////////////////////////////////////////// | ||||||
|  |   int createLimeRecordHeader(std::string message, int MB, int ME, size_t PayloadSize) | ||||||
|  |   { | ||||||
|  |     if ( boss_node ) { | ||||||
|  |       LimeRecordHeader *h; | ||||||
|  |       h = limeCreateHeader(MB, ME, const_cast<char *>(message.c_str()), PayloadSize); | ||||||
|  |       assert(limeWriteRecordHeader(h, LimeW) >= 0); | ||||||
|  |       limeDestroyHeader(h); | ||||||
|  |     } | ||||||
|  |     return LIME_SUCCESS; | ||||||
|  |   } | ||||||
|  |   //////////////////////////////////////////// | ||||||
|  |   // Write a generic serialisable object | ||||||
|  |   //////////////////////////////////////////// | ||||||
|  |   void writeLimeObject(int MB,int ME,XmlWriter &writer,std::string object_name,std::string record_name) | ||||||
|  |   { | ||||||
|  |     if ( boss_node ) { | ||||||
|  |       std::string xmlstring = writer.docString(); | ||||||
|  |  | ||||||
|  |       //    std::cout << "WriteLimeObject" << record_name <<std::endl; | ||||||
|  |       uint64_t nbytes = xmlstring.size(); | ||||||
|  |       //    std::cout << " xmlstring "<< nbytes<< " " << xmlstring <<std::endl; | ||||||
|  |       int err; | ||||||
|  |       LimeRecordHeader *h = limeCreateHeader(MB, ME,const_cast<char *>(record_name.c_str()), nbytes);  | ||||||
|  |       assert(h!= NULL); | ||||||
|  |        | ||||||
|  |       err=limeWriteRecordHeader(h, LimeW);                    assert(err>=0); | ||||||
|  |       err=limeWriteRecordData(&xmlstring[0], &nbytes, LimeW); assert(err>=0); | ||||||
|  |       err=limeWriterCloseRecord(LimeW);                       assert(err>=0); | ||||||
|  |       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 | ||||||
|  |   // This routine is Collectively called by all nodes | ||||||
|  |   // in communicator used by the field.Grid() | ||||||
|  |   //////////////////////////////////////////////////// | ||||||
|  |   template<class vobj> | ||||||
|  |   void writeLimeLatticeBinaryObject(Lattice<vobj> &field,std::string record_name) | ||||||
|  |   { | ||||||
|  |     //////////////////////////////////////////////////////////////////// | ||||||
|  |     // NB: FILE and iostream are jointly writing disjoint sequences in the | ||||||
|  |     // the same file through different file handles (integer units). | ||||||
|  |     //  | ||||||
|  |     // These are both buffered, so why I think this code is right is as follows. | ||||||
|  |     // | ||||||
|  |     // i)  write record header to FILE *File, telegraphing the size; flush | ||||||
|  |     // ii) ftello reads the offset from FILE *File .  | ||||||
|  |     // iii) iostream / MPI Open independently seek this offset. Write sequence direct to disk. | ||||||
|  |     //      Closes iostream and flushes. | ||||||
|  |     // iv) fseek on FILE * to end of this disjoint section. | ||||||
|  |     //  v) Continue writing scidac record. | ||||||
|  |     //////////////////////////////////////////////////////////////////// | ||||||
|  |      | ||||||
|  |     GridBase *grid = field.Grid(); | ||||||
|  |     assert(boss_node == field.Grid()->IsBoss() ); | ||||||
|  |  | ||||||
|  |     FieldNormMetaData FNMD; FNMD.norm2 = norm2(field); | ||||||
|  |  | ||||||
|  |     //////////////////////////////////////////// | ||||||
|  |     // Create record header | ||||||
|  |     //////////////////////////////////////////// | ||||||
|  |     typedef typename vobj::scalar_object sobj; | ||||||
|  |     int err; | ||||||
|  |     uint32_t nersc_csum,scidac_csuma,scidac_csumb; | ||||||
|  |     uint64_t PayloadSize = sizeof(sobj) * grid->_gsites; | ||||||
|  |     if ( boss_node ) { | ||||||
|  |       createLimeRecordHeader(record_name, 0, 0, PayloadSize); | ||||||
|  |       fflush(File); | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     //    std::cout << "W sizeof(sobj)"      <<sizeof(sobj)<<std::endl; | ||||||
|  |     //    std::cout << "W Gsites "           <<field.Grid()->_gsites<<std::endl; | ||||||
|  |     //    std::cout << "W Payload expected " <<PayloadSize<<std::endl; | ||||||
|  |  | ||||||
|  |     //////////////////////////////////////////////// | ||||||
|  |     // Check all nodes agree on file position | ||||||
|  |     //////////////////////////////////////////////// | ||||||
|  |     uint64_t offset1; | ||||||
|  |     if ( boss_node ) { | ||||||
|  |       offset1 = ftello(File);     | ||||||
|  |     } | ||||||
|  |     grid->Broadcast(0,(void *)&offset1,sizeof(offset1)); | ||||||
|  |  | ||||||
|  |     /////////////////////////////////////////// | ||||||
|  |     // The above is collective. Write by other means into the binary record | ||||||
|  |     /////////////////////////////////////////// | ||||||
|  |     std::string format = getFormatString<vobj>(); | ||||||
|  |     BinarySimpleMunger<sobj,sobj> munge; | ||||||
|  |     BinaryIO::writeLatticeObject<vobj,sobj>(field, filename, munge, offset1, format,nersc_csum,scidac_csuma,scidac_csumb); | ||||||
|  |  | ||||||
|  |     /////////////////////////////////////////// | ||||||
|  |     // Wind forward and close the record | ||||||
|  |     /////////////////////////////////////////// | ||||||
|  |     if ( boss_node ) { | ||||||
|  |       fseek(File,0,SEEK_END);              | ||||||
|  |       uint64_t offset2 = ftello(File);     //    std::cout << " now at offset "<<offset2 << std::endl; | ||||||
|  |       assert( (offset2-offset1) == PayloadSize); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     ///////////////////////////////////////////////////////////// | ||||||
|  |     // Check MPI-2 I/O did what we expect to file | ||||||
|  |     ///////////////////////////////////////////////////////////// | ||||||
|  |  | ||||||
|  |     if ( boss_node ) {  | ||||||
|  |       err=limeWriterCloseRecord(LimeW);  assert(err>=0); | ||||||
|  |     } | ||||||
|  |     //////////////////////////////////////// | ||||||
|  |     // Write checksum element, propagaing forward from the BinaryIO | ||||||
|  |     // Always pair a checksum with a binary object, and close message | ||||||
|  |     //////////////////////////////////////// | ||||||
|  |     scidacChecksum checksum; | ||||||
|  |     std::stringstream streama; streama << std::hex << scidac_csuma; | ||||||
|  |     std::stringstream streamb; streamb << std::hex << scidac_csumb; | ||||||
|  |     checksum.suma= streama.str(); | ||||||
|  |     checksum.sumb= streamb.str(); | ||||||
|  |     if ( boss_node ) {  | ||||||
|  |       writeLimeObject(0,0,FNMD,std::string(GRID_FIELD_NORM),std::string(GRID_FIELD_NORM)); | ||||||
|  |       writeLimeObject(0,1,checksum,std::string("scidacChecksum"),std::string(SCIDAC_CHECKSUM)); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | class ScidacWriter : public GridLimeWriter { | ||||||
|  |  public: | ||||||
|  |  | ||||||
|  |   ScidacWriter(bool isboss =true ) : GridLimeWriter(isboss)  { }; | ||||||
|  |  | ||||||
|  |   template<class SerialisableUserFile> | ||||||
|  |   void writeScidacFileRecord(GridBase *grid,SerialisableUserFile &_userFile) | ||||||
|  |   { | ||||||
|  |     scidacFile    _scidacFile(grid); | ||||||
|  |     if ( this->boss_node ) { | ||||||
|  |       writeLimeObject(1,0,_scidacFile,_scidacFile.SerialisableClassName(),std::string(SCIDAC_PRIVATE_FILE_XML)); | ||||||
|  |       writeLimeObject(0,1,_userFile,_userFile.SerialisableClassName(),std::string(SCIDAC_FILE_XML)); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   //////////////////////////////////////////////// | ||||||
|  |   // Write generic lattice field in scidac format | ||||||
|  |   //////////////////////////////////////////////// | ||||||
|  |   template <class vobj, class userRecord> | ||||||
|  |   void writeScidacFieldRecord(Lattice<vobj> &field,userRecord _userRecord, | ||||||
|  |                               const unsigned int recordScientificPrec = 0)  | ||||||
|  |   { | ||||||
|  |     GridBase * grid = field.Grid(); | ||||||
|  |  | ||||||
|  |     //////////////////////////////////////// | ||||||
|  |     // fill the Grid header | ||||||
|  |     //////////////////////////////////////// | ||||||
|  |     FieldMetaData header; | ||||||
|  |     scidacRecord  _scidacRecord; | ||||||
|  |     scidacFile    _scidacFile; | ||||||
|  |  | ||||||
|  |     ScidacMetaData(field,header,_scidacRecord,_scidacFile); | ||||||
|  |  | ||||||
|  |     ////////////////////////////////////////////// | ||||||
|  |     // Fill the Lime file record by record | ||||||
|  |     ////////////////////////////////////////////// | ||||||
|  |     if ( this->boss_node ) { | ||||||
|  |       writeLimeObject(1,0,header ,std::string("FieldMetaData"),std::string(GRID_FORMAT)); // Open message  | ||||||
|  |       writeLimeObject(0,0,_userRecord,_userRecord.SerialisableClassName(),std::string(SCIDAC_RECORD_XML), recordScientificPrec); | ||||||
|  |       writeLimeObject(0,0,_scidacRecord,_scidacRecord.SerialisableClassName(),std::string(SCIDAC_PRIVATE_RECORD_XML)); | ||||||
|  |     } | ||||||
|  |     // Collective call | ||||||
|  |     writeLimeLatticeBinaryObject(field,std::string(ILDG_BINARY_DATA));      // Closes message with checksum | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class ScidacReader : public GridLimeReader { | ||||||
|  |  public: | ||||||
|  |  | ||||||
|  |    template<class SerialisableUserFile> | ||||||
|  |    void readScidacFileRecord(GridBase *grid,SerialisableUserFile &_userFile) | ||||||
|  |    { | ||||||
|  |      scidacFile    _scidacFile(grid); | ||||||
|  |      readLimeObject(_scidacFile,_scidacFile.SerialisableClassName(),std::string(SCIDAC_PRIVATE_FILE_XML)); | ||||||
|  |      readLimeObject(_userFile,_userFile.SerialisableClassName(),std::string(SCIDAC_FILE_XML)); | ||||||
|  |    } | ||||||
|  |   //////////////////////////////////////////////// | ||||||
|  |   // Write generic lattice field in scidac format | ||||||
|  |   //////////////////////////////////////////////// | ||||||
|  |   template <class vobj, class userRecord> | ||||||
|  |   void readScidacFieldRecord(Lattice<vobj> &field,userRecord &_userRecord)  | ||||||
|  |   { | ||||||
|  |     typedef typename vobj::scalar_object sobj; | ||||||
|  |     GridBase * grid = field.Grid(); | ||||||
|  |  | ||||||
|  |     //////////////////////////////////////// | ||||||
|  |     // fill the Grid header | ||||||
|  |     //////////////////////////////////////// | ||||||
|  |     FieldMetaData header; | ||||||
|  |     scidacRecord  _scidacRecord; | ||||||
|  |     scidacFile    _scidacFile; | ||||||
|  |  | ||||||
|  |     ////////////////////////////////////////////// | ||||||
|  |     // Fill the Lime file record by record | ||||||
|  |     ////////////////////////////////////////////// | ||||||
|  |     readLimeObject(header ,std::string("FieldMetaData"),std::string(GRID_FORMAT)); // Open message  | ||||||
|  |     readLimeObject(_userRecord,_userRecord.SerialisableClassName(),std::string(SCIDAC_RECORD_XML)); | ||||||
|  |     readLimeObject(_scidacRecord,_scidacRecord.SerialisableClassName(),std::string(SCIDAC_PRIVATE_RECORD_XML)); | ||||||
|  |     readLimeLatticeBinaryObject(field,std::string(ILDG_BINARY_DATA)); | ||||||
|  |   } | ||||||
|  |   void skipPastBinaryRecord(void) { | ||||||
|  |     std::string rec_name(ILDG_BINARY_DATA); | ||||||
|  |     while ( limeReaderNextRecord(LimeR) == LIME_SUCCESS ) {  | ||||||
|  |       if ( !strncmp(limeReaderType(LimeR), rec_name.c_str(),strlen(rec_name.c_str()) )  ) { | ||||||
|  | 	skipPastObjectRecord(std::string(SCIDAC_CHECKSUM)); | ||||||
|  | 	return; | ||||||
|  |       } | ||||||
|  |     }     | ||||||
|  |   } | ||||||
|  |   void skipPastObjectRecord(std::string rec_name) { | ||||||
|  |     while ( limeReaderNextRecord(LimeR) == LIME_SUCCESS ) {  | ||||||
|  |       if ( !strncmp(limeReaderType(LimeR), rec_name.c_str(),strlen(rec_name.c_str()) )  ) { | ||||||
|  | 	return; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   void skipScidacFieldRecord() { | ||||||
|  |     skipPastObjectRecord(std::string(GRID_FORMAT)); | ||||||
|  |     skipPastObjectRecord(std::string(SCIDAC_RECORD_XML)); | ||||||
|  |     skipPastObjectRecord(std::string(SCIDAC_PRIVATE_RECORD_XML)); | ||||||
|  |     skipPastBinaryRecord(); | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class IldgWriter : public ScidacWriter { | ||||||
|  |  public: | ||||||
|  |    | ||||||
|  |   IldgWriter(bool isboss) : ScidacWriter(isboss) {}; | ||||||
|  |  | ||||||
|  |   /////////////////////////////////// | ||||||
|  |   // A little helper | ||||||
|  |   /////////////////////////////////// | ||||||
|  |   void writeLimeIldgLFN(std::string &LFN) | ||||||
|  |   { | ||||||
|  |     uint64_t PayloadSize = LFN.size(); | ||||||
|  |     int err; | ||||||
|  |     createLimeRecordHeader(ILDG_DATA_LFN, 0 , 0, PayloadSize); | ||||||
|  |     err=limeWriteRecordData(const_cast<char*>(LFN.c_str()), &PayloadSize,LimeW); assert(err>=0); | ||||||
|  |     err=limeWriterCloseRecord(LimeW); assert(err>=0); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   //////////////////////////////////////////////////////////////// | ||||||
|  |   // Special ILDG operations ; gauge configs only. | ||||||
|  |   // Don't require scidac records EXCEPT checksum | ||||||
|  |   // Use Grid MetaData object if present. | ||||||
|  |   //////////////////////////////////////////////////////////////// | ||||||
|  |   template <class vsimd> | ||||||
|  |   void writeConfiguration(Lattice<iLorentzColourMatrix<vsimd> > &Umu,int sequence,std::string LFN,std::string description)  | ||||||
|  |   { | ||||||
|  |     GridBase * grid = Umu.Grid(); | ||||||
|  |     typedef Lattice<iLorentzColourMatrix<vsimd> > GaugeField; | ||||||
|  |     typedef iLorentzColourMatrix<vsimd> vobj; | ||||||
|  |     typedef typename vobj::scalar_object sobj; | ||||||
|  |  | ||||||
|  |     //////////////////////////////////////// | ||||||
|  |     // fill the Grid header | ||||||
|  |     //////////////////////////////////////// | ||||||
|  |     FieldMetaData header; | ||||||
|  |     scidacRecord  _scidacRecord; | ||||||
|  |     scidacFile    _scidacFile; | ||||||
|  |  | ||||||
|  |     ScidacMetaData(Umu,header,_scidacRecord,_scidacFile); | ||||||
|  |  | ||||||
|  |     std::string format = header.floating_point; | ||||||
|  |     header.ensemble_id    = description; | ||||||
|  |     header.ensemble_label = description; | ||||||
|  |     header.sequence_number = sequence; | ||||||
|  |     header.ildg_lfn = LFN; | ||||||
|  |  | ||||||
|  |     assert ( (format == std::string("IEEE32BIG"))   | ||||||
|  |            ||(format == std::string("IEEE64BIG")) ); | ||||||
|  |  | ||||||
|  |     ////////////////////////////////////////////////////// | ||||||
|  |     // Fill ILDG header data struct | ||||||
|  |     ////////////////////////////////////////////////////// | ||||||
|  |     ildgFormat ildgfmt ; | ||||||
|  |     ildgfmt.field     = std::string("su3gauge"); | ||||||
|  |  | ||||||
|  |     if ( format == std::string("IEEE32BIG") ) {  | ||||||
|  |       ildgfmt.precision = 32; | ||||||
|  |     } else {  | ||||||
|  |       ildgfmt.precision = 64; | ||||||
|  |     } | ||||||
|  |     ildgfmt.version = 1.0; | ||||||
|  |     ildgfmt.lx = header.dimension[0]; | ||||||
|  |     ildgfmt.ly = header.dimension[1]; | ||||||
|  |     ildgfmt.lz = header.dimension[2]; | ||||||
|  |     ildgfmt.lt = header.dimension[3]; | ||||||
|  |     assert(header.nd==4); | ||||||
|  |     assert(header.nd==header.dimension.size()); | ||||||
|  |  | ||||||
|  |     ////////////////////////////////////////////////////////////////////////////// | ||||||
|  |     // Field norm tests | ||||||
|  |     ////////////////////////////////////////////////////////////////////////////// | ||||||
|  |     FieldNormMetaData FieldNormMetaData_; | ||||||
|  |     FieldNormMetaData_.norm2 = norm2(Umu); | ||||||
|  |  | ||||||
|  |     ////////////////////////////////////////////////////////////////////////////// | ||||||
|  |     // Fill the USQCD info field | ||||||
|  |     ////////////////////////////////////////////////////////////////////////////// | ||||||
|  |     usqcdInfo info; | ||||||
|  |     info.version=1.0; | ||||||
|  |     info.plaq   = header.plaquette; | ||||||
|  |     info.linktr = header.link_trace; | ||||||
|  |  | ||||||
|  |     //    std::cout << GridLogMessage << " Writing config; IldgIO n2 "<< FieldNormMetaData_.norm2<<std::endl; | ||||||
|  |     ////////////////////////////////////////////// | ||||||
|  |     // Fill the Lime file record by record | ||||||
|  |     ////////////////////////////////////////////// | ||||||
|  |     writeLimeObject(1,0,header ,std::string("FieldMetaData"),std::string(GRID_FORMAT)); // Open message  | ||||||
|  |     writeLimeObject(0,0,FieldNormMetaData_,FieldNormMetaData_.SerialisableClassName(),std::string(GRID_FIELD_NORM)); | ||||||
|  |     writeLimeObject(0,0,_scidacFile,_scidacFile.SerialisableClassName(),std::string(SCIDAC_PRIVATE_FILE_XML)); | ||||||
|  |     writeLimeObject(0,1,info,info.SerialisableClassName(),std::string(SCIDAC_FILE_XML)); | ||||||
|  |     writeLimeObject(1,0,_scidacRecord,_scidacRecord.SerialisableClassName(),std::string(SCIDAC_PRIVATE_RECORD_XML)); | ||||||
|  |     writeLimeObject(0,0,info,info.SerialisableClassName(),std::string(SCIDAC_RECORD_XML)); | ||||||
|  |     writeLimeObject(0,0,ildgfmt,std::string("ildgFormat")   ,std::string(ILDG_FORMAT)); // rec | ||||||
|  |     writeLimeIldgLFN(header.ildg_lfn);                                                 // rec | ||||||
|  |     writeLimeLatticeBinaryObject(Umu,std::string(ILDG_BINARY_DATA));      // Closes message with checksum | ||||||
|  |     //    limeDestroyWriter(LimeW); | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | class IldgReader : public GridLimeReader { | ||||||
|  |  public: | ||||||
|  |  | ||||||
|  |   //////////////////////////////////////////////////////////////// | ||||||
|  |   // Read either Grid/SciDAC/ILDG configuration | ||||||
|  |   // Don't require scidac records EXCEPT checksum | ||||||
|  |   // Use Grid MetaData object if present. | ||||||
|  |   // Else use ILDG MetaData object if present. | ||||||
|  |   // Else use SciDAC MetaData object if present. | ||||||
|  |   //////////////////////////////////////////////////////////////// | ||||||
|  |   template <class vsimd> | ||||||
|  |   void readConfiguration(Lattice<iLorentzColourMatrix<vsimd> > &Umu, FieldMetaData &FieldMetaData_) { | ||||||
|  |  | ||||||
|  |     typedef Lattice<iLorentzColourMatrix<vsimd> > GaugeField; | ||||||
|  |     typedef typename GaugeField::vector_object  vobj; | ||||||
|  |     typedef typename vobj::scalar_object sobj; | ||||||
|  |  | ||||||
|  |     typedef LorentzColourMatrixF fobj; | ||||||
|  |     typedef LorentzColourMatrixD dobj; | ||||||
|  |  | ||||||
|  |     GridBase *grid = Umu.Grid(); | ||||||
|  |  | ||||||
|  |     Coordinate dims = Umu.Grid()->FullDimensions(); | ||||||
|  |  | ||||||
|  |     assert(dims.size()==4); | ||||||
|  |  | ||||||
|  |     // Metadata holders | ||||||
|  |     ildgFormat     ildgFormat_    ; | ||||||
|  |     std::string    ildgLFN_       ; | ||||||
|  |     scidacChecksum scidacChecksum_;  | ||||||
|  |     usqcdInfo      usqcdInfo_     ; | ||||||
|  |     FieldNormMetaData FieldNormMetaData_; | ||||||
|  |  | ||||||
|  |     // track what we read from file | ||||||
|  |     int found_ildgFormat    =0; | ||||||
|  |     int found_ildgLFN       =0; | ||||||
|  |     int found_scidacChecksum=0; | ||||||
|  |     int found_usqcdInfo     =0; | ||||||
|  |     int found_ildgBinary =0; | ||||||
|  |     int found_FieldMetaData =0; | ||||||
|  |     int found_FieldNormMetaData =0; | ||||||
|  |     uint32_t nersc_csum; | ||||||
|  |     uint32_t scidac_csuma; | ||||||
|  |     uint32_t scidac_csumb; | ||||||
|  |  | ||||||
|  |     // Binary format | ||||||
|  |     std::string format; | ||||||
|  |  | ||||||
|  |     ////////////////////////////////////////////////////////////////////////// | ||||||
|  |     // Loop over all records | ||||||
|  |     // -- Order is poorly guaranteed except ILDG header preceeds binary section. | ||||||
|  |     // -- Run like an event loop. | ||||||
|  |     // -- Impose trust hierarchy. Grid takes precedence & look for ILDG, and failing | ||||||
|  |     //    that Scidac.  | ||||||
|  |     // -- Insist on Scidac checksum record. | ||||||
|  |     ////////////////////////////////////////////////////////////////////////// | ||||||
|  |  | ||||||
|  |     while ( limeReaderNextRecord(LimeR) == LIME_SUCCESS ) {  | ||||||
|  |  | ||||||
|  |       uint64_t nbytes = limeReaderBytes(LimeR);//size of this record (configuration) | ||||||
|  |        | ||||||
|  |       ////////////////////////////////////////////////////////////////// | ||||||
|  |       // If not BINARY_DATA read a string and parse | ||||||
|  |       ////////////////////////////////////////////////////////////////// | ||||||
|  |       if ( strncmp(limeReaderType(LimeR), ILDG_BINARY_DATA,strlen(ILDG_BINARY_DATA) )  ) { | ||||||
|  | 	 | ||||||
|  | 	// Copy out the string | ||||||
|  | 	std::vector<char> xmlc(nbytes+1,'\0'); | ||||||
|  | 	limeReaderReadData((void *)&xmlc[0], &nbytes, LimeR);     | ||||||
|  | 	//	std::cout << GridLogMessage<< "Non binary record :" <<limeReaderType(LimeR) <<std::endl; //<<"\n"<<(&xmlc[0])<<std::endl; | ||||||
|  |  | ||||||
|  | 	////////////////////////////////// | ||||||
|  | 	// ILDG format record | ||||||
|  |  | ||||||
|  | 	std::string xmlstring(&xmlc[0]); | ||||||
|  | 	if ( !strncmp(limeReaderType(LimeR), ILDG_FORMAT,strlen(ILDG_FORMAT)) ) {  | ||||||
|  |  | ||||||
|  | 	  XmlReader RD(xmlstring, true, ""); | ||||||
|  | 	  read(RD,"ildgFormat",ildgFormat_); | ||||||
|  |  | ||||||
|  | 	  if ( ildgFormat_.precision == 64 ) format = std::string("IEEE64BIG"); | ||||||
|  | 	  if ( ildgFormat_.precision == 32 ) format = std::string("IEEE32BIG"); | ||||||
|  |  | ||||||
|  | 	  assert( ildgFormat_.lx == dims[0]); | ||||||
|  | 	  assert( ildgFormat_.ly == dims[1]); | ||||||
|  | 	  assert( ildgFormat_.lz == dims[2]); | ||||||
|  | 	  assert( ildgFormat_.lt == dims[3]); | ||||||
|  |  | ||||||
|  | 	  found_ildgFormat = 1; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if ( !strncmp(limeReaderType(LimeR), ILDG_DATA_LFN,strlen(ILDG_DATA_LFN)) ) { | ||||||
|  | 	  FieldMetaData_.ildg_lfn = xmlstring; | ||||||
|  | 	  found_ildgLFN = 1; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if ( !strncmp(limeReaderType(LimeR), GRID_FORMAT,strlen(ILDG_FORMAT)) ) {  | ||||||
|  |  | ||||||
|  | 	  XmlReader RD(xmlstring, true, ""); | ||||||
|  | 	  read(RD,"FieldMetaData",FieldMetaData_); | ||||||
|  |  | ||||||
|  | 	  format = FieldMetaData_.floating_point; | ||||||
|  |  | ||||||
|  | 	  assert(FieldMetaData_.dimension[0] == dims[0]); | ||||||
|  | 	  assert(FieldMetaData_.dimension[1] == dims[1]); | ||||||
|  | 	  assert(FieldMetaData_.dimension[2] == dims[2]); | ||||||
|  | 	  assert(FieldMetaData_.dimension[3] == dims[3]); | ||||||
|  |  | ||||||
|  | 	  found_FieldMetaData = 1; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if ( !strncmp(limeReaderType(LimeR), SCIDAC_RECORD_XML,strlen(SCIDAC_RECORD_XML)) ) {  | ||||||
|  | 	  // is it a USQCD info field | ||||||
|  | 	  if ( xmlstring.find(std::string("usqcdInfo")) != std::string::npos ) {  | ||||||
|  | 	    //	    std::cout << GridLogMessage<<"...found a usqcdInfo field"<<std::endl; | ||||||
|  | 	    XmlReader RD(xmlstring, true, ""); | ||||||
|  | 	    read(RD,"usqcdInfo",usqcdInfo_); | ||||||
|  | 	    found_usqcdInfo = 1; | ||||||
|  | 	  } | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if ( !strncmp(limeReaderType(LimeR), SCIDAC_CHECKSUM,strlen(SCIDAC_CHECKSUM)) ) {  | ||||||
|  | 	  XmlReader RD(xmlstring, true, ""); | ||||||
|  | 	  read(RD,"scidacChecksum",scidacChecksum_); | ||||||
|  | 	  found_scidacChecksum = 1; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if ( !strncmp(limeReaderType(LimeR), GRID_FIELD_NORM,strlen(GRID_FIELD_NORM)) ) {  | ||||||
|  | 	  XmlReader RD(xmlstring, true, ""); | ||||||
|  | 	  read(RD,GRID_FIELD_NORM,FieldNormMetaData_); | ||||||
|  | 	  found_FieldNormMetaData = 1; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  |       } else {   | ||||||
|  | 	///////////////////////////////// | ||||||
|  | 	// Binary data | ||||||
|  | 	///////////////////////////////// | ||||||
|  | 	//	std::cout << GridLogMessage << "ILDG Binary record found : "  ILDG_BINARY_DATA << std::endl; | ||||||
|  | 	uint64_t offset= ftello(File); | ||||||
|  | 	if ( format == std::string("IEEE64BIG") ) { | ||||||
|  | 	  GaugeSimpleMunger<dobj, sobj> munge; | ||||||
|  | 	  BinaryIO::readLatticeObject< vobj, dobj >(Umu, filename, munge, offset, format,nersc_csum,scidac_csuma,scidac_csumb); | ||||||
|  | 	} else {  | ||||||
|  | 	  GaugeSimpleMunger<fobj, sobj> munge; | ||||||
|  | 	  BinaryIO::readLatticeObject< vobj, fobj >(Umu, filename, munge, offset, format,nersc_csum,scidac_csuma,scidac_csumb); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	found_ildgBinary = 1; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     ////////////////////////////////////////////////////// | ||||||
|  |     // Minimally must find binary segment and checksum | ||||||
|  |     // Since this is an ILDG reader require ILDG format | ||||||
|  |     ////////////////////////////////////////////////////// | ||||||
|  |     assert(found_ildgLFN); | ||||||
|  |     assert(found_ildgBinary); | ||||||
|  |     assert(found_ildgFormat); | ||||||
|  |     assert(found_scidacChecksum); | ||||||
|  |  | ||||||
|  |     // Must find something with the lattice dimensions | ||||||
|  |     assert(found_FieldMetaData||found_ildgFormat); | ||||||
|  |  | ||||||
|  |     if ( found_FieldMetaData ) { | ||||||
|  |  | ||||||
|  |       std::cout << GridLogMessage<<"Grid MetaData was record found: configuration was probably written by Grid ! Yay ! "<<std::endl; | ||||||
|  |  | ||||||
|  |     } else {  | ||||||
|  |  | ||||||
|  |       assert(found_ildgFormat); | ||||||
|  |       assert ( ildgFormat_.field == std::string("su3gauge") ); | ||||||
|  |  | ||||||
|  |       /////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  |       // Populate our Grid metadata as best we can | ||||||
|  |       /////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  |  | ||||||
|  |       std::ostringstream vers; vers << ildgFormat_.version; | ||||||
|  |       FieldMetaData_.hdr_version = vers.str(); | ||||||
|  |       FieldMetaData_.data_type = std::string("4D_SU3_GAUGE_3X3"); | ||||||
|  |  | ||||||
|  |       FieldMetaData_.nd=4; | ||||||
|  |       FieldMetaData_.dimension.resize(4); | ||||||
|  |  | ||||||
|  |       FieldMetaData_.dimension[0] = ildgFormat_.lx ; | ||||||
|  |       FieldMetaData_.dimension[1] = ildgFormat_.ly ; | ||||||
|  |       FieldMetaData_.dimension[2] = ildgFormat_.lz ; | ||||||
|  |       FieldMetaData_.dimension[3] = ildgFormat_.lt ; | ||||||
|  |  | ||||||
|  |       if ( found_usqcdInfo ) {  | ||||||
|  | 	FieldMetaData_.plaquette = usqcdInfo_.plaq; | ||||||
|  | 	FieldMetaData_.link_trace= usqcdInfo_.linktr; | ||||||
|  | 	std::cout << GridLogMessage <<"This configuration was probably written by USQCD "<<std::endl; | ||||||
|  | 	std::cout << GridLogMessage <<"USQCD xml record Plaquette : "<<FieldMetaData_.plaquette<<std::endl; | ||||||
|  | 	std::cout << GridLogMessage <<"USQCD xml record LinkTrace : "<<FieldMetaData_.link_trace<<std::endl; | ||||||
|  |       } else {  | ||||||
|  | 	FieldMetaData_.plaquette = 0.0; | ||||||
|  | 	FieldMetaData_.link_trace= 0.0; | ||||||
|  | 	std::cout << GridLogWarning << "This configuration is unsafe with no plaquette records that can verify it !!! "<<std::endl; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     //////////////////////////////////////////////////////////// | ||||||
|  |     // Really really want to mandate a scidac checksum | ||||||
|  |     //////////////////////////////////////////////////////////// | ||||||
|  |     if ( found_FieldNormMetaData ) {  | ||||||
|  |       RealD nn = norm2(Umu); | ||||||
|  |       GRID_FIELD_NORM_CHECK(FieldNormMetaData_,nn); | ||||||
|  |       std::cout << GridLogMessage<<"FieldNormMetaData matches " << std::endl; | ||||||
|  |     }  else {  | ||||||
|  |       std::cout << GridLogWarning<<"FieldNormMetaData not found. " << std::endl; | ||||||
|  |     } | ||||||
|  |     if ( found_scidacChecksum ) { | ||||||
|  |       FieldMetaData_.scidac_checksuma = stoull(scidacChecksum_.suma,0,16); | ||||||
|  |       FieldMetaData_.scidac_checksumb = stoull(scidacChecksum_.sumb,0,16); | ||||||
|  |       scidacChecksumVerify(scidacChecksum_,scidac_csuma,scidac_csumb); | ||||||
|  |       assert( scidac_csuma ==FieldMetaData_.scidac_checksuma); | ||||||
|  |       assert( scidac_csumb ==FieldMetaData_.scidac_checksumb); | ||||||
|  |       std::cout << GridLogMessage<<"SciDAC checksums match " << std::endl; | ||||||
|  |     } else {  | ||||||
|  |       std::cout << GridLogWarning<<"SciDAC checksums not found. This is unsafe. " << std::endl; | ||||||
|  |       assert(0); // Can I insist always checksum ? | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if ( found_FieldMetaData || found_usqcdInfo ) { | ||||||
|  |       FieldMetaData checker; | ||||||
|  |       GaugeStatistics(Umu,checker); | ||||||
|  |       assert(fabs(checker.plaquette  - FieldMetaData_.plaquette )<1.0e-5); | ||||||
|  |       assert(fabs(checker.link_trace - FieldMetaData_.link_trace)<1.0e-5); | ||||||
|  |       std::cout << GridLogMessage<<"Plaquette and link trace match " << std::endl; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  }; | ||||||
|  |  | ||||||
|  | NAMESPACE_END(Grid); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | //HAVE_LIME | ||||||
|  | #endif | ||||||
|  |  | ||||||
							
								
								
									
										237
									
								
								Grid/parallelIO/IldgIOtypes.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										237
									
								
								Grid/parallelIO/IldgIOtypes.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,237 @@ | |||||||
|  | /************************************************************************************* | ||||||
|  |  | ||||||
|  | Grid physics library, www.github.com/paboyle/Grid | ||||||
|  |  | ||||||
|  | Source file: ./lib/parallelIO/IldgIO.h | ||||||
|  |  | ||||||
|  | Copyright (C) 2015 | ||||||
|  |  | ||||||
|  | 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_ILDGTYPES_IO_H | ||||||
|  | #define GRID_ILDGTYPES_IO_H | ||||||
|  |  | ||||||
|  | #ifdef HAVE_LIME | ||||||
|  | extern "C" { // for linkage | ||||||
|  | #include "lime.h" | ||||||
|  | } | ||||||
|  |  | ||||||
|  | NAMESPACE_BEGIN(Grid); | ||||||
|  |  | ||||||
|  | ///////////////////////////////////////////////////////////////////////////////// | ||||||
|  | // Data representation of records that enter ILDG and SciDac formats | ||||||
|  | ///////////////////////////////////////////////////////////////////////////////// | ||||||
|  |  | ||||||
|  | #define GRID_FORMAT      "grid-format" | ||||||
|  | #define ILDG_FORMAT      "ildg-format" | ||||||
|  | #define ILDG_BINARY_DATA "ildg-binary-data" | ||||||
|  | #define ILDG_DATA_LFN    "ildg-data-lfn" | ||||||
|  | #define SCIDAC_CHECKSUM           "scidac-checksum" | ||||||
|  | #define SCIDAC_PRIVATE_FILE_XML   "scidac-private-file-xml" | ||||||
|  | #define SCIDAC_FILE_XML           "scidac-file-xml" | ||||||
|  | #define SCIDAC_PRIVATE_RECORD_XML "scidac-private-record-xml" | ||||||
|  | #define SCIDAC_RECORD_XML         "scidac-record-xml" | ||||||
|  | #define SCIDAC_BINARY_DATA        "scidac-binary-data" | ||||||
|  | // Unused SCIDAC records names; could move to support this functionality | ||||||
|  | #define SCIDAC_SITELIST           "scidac-sitelist" | ||||||
|  |  | ||||||
|  | //////////////////////////////////////////////////////////// | ||||||
|  | const int GRID_IO_SINGLEFILE = 0; // hardcode lift from QIO compat | ||||||
|  | const int GRID_IO_MULTIFILE  = 1; // hardcode lift from QIO compat | ||||||
|  | const int GRID_IO_FIELD      = 0; // hardcode lift from QIO compat | ||||||
|  | const int GRID_IO_GLOBAL     = 1; // hardcode lift from QIO compat | ||||||
|  | //////////////////////////////////////////////////////////// | ||||||
|  |  | ||||||
|  | ///////////////////////////////////////////////////////////////////////////////// | ||||||
|  | // QIO uses mandatory "private" records fixed format | ||||||
|  | // Private is in principle "opaque" however it can't be changed now because that would break existing  | ||||||
|  | // file compatability, so should be correct to assume the undocumented but defacto file structure. | ||||||
|  | ///////////////////////////////////////////////////////////////////////////////// | ||||||
|  |  | ||||||
|  | struct emptyUserRecord : Serializable {  | ||||||
|  |   GRID_SERIALIZABLE_CLASS_MEMBERS(emptyUserRecord,int,dummy); | ||||||
|  |   emptyUserRecord() { dummy=0; }; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | //////////////////////// | ||||||
|  | // Scidac private file xml | ||||||
|  | // <?xml version="1.0" encoding="UTF-8"?><scidacFile><version>1.1</version><spacetime>4</spacetime><dims>16 16 16 32 </dims><volfmt>0</volfmt></scidacFile> | ||||||
|  | //////////////////////// | ||||||
|  | struct scidacFile : Serializable { | ||||||
|  | public: | ||||||
|  |   GRID_SERIALIZABLE_CLASS_MEMBERS(scidacFile, | ||||||
|  |                                   double, version, | ||||||
|  |                                   int, spacetime, | ||||||
|  | 				  std::string, dims, // must convert to int | ||||||
|  |                                   int, volfmt); | ||||||
|  |  | ||||||
|  |   std::vector<int> getDimensions(void) {  | ||||||
|  |     std::stringstream stream(dims); | ||||||
|  |     std::vector<int> dimensions; | ||||||
|  |     int n; | ||||||
|  |     while(stream >> n){ | ||||||
|  |       dimensions.push_back(n); | ||||||
|  |     } | ||||||
|  |     return dimensions; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   void setDimensions(Coordinate dimensions) {  | ||||||
|  |     char delimiter = ' '; | ||||||
|  |     std::stringstream stream; | ||||||
|  |     for(int i=0;i<dimensions.size();i++){  | ||||||
|  |       stream << dimensions[i]; | ||||||
|  |       if ( i != dimensions.size()-1) {  | ||||||
|  | 	stream << delimiter <<std::endl; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |     dims = stream.str(); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   // Constructor provides Grid | ||||||
|  |   scidacFile() =default; // default constructor | ||||||
|  |   scidacFile(GridBase * grid){ | ||||||
|  |     version      = 1.0; | ||||||
|  |     spacetime    = grid->_ndimension; | ||||||
|  |     setDimensions(grid->FullDimensions());  | ||||||
|  |     volfmt       = GRID_IO_SINGLEFILE; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | /////////////////////////////////////////////////////////////////////// | ||||||
|  | // scidac-private-record-xml : example | ||||||
|  | // <scidacRecord> | ||||||
|  | // <version>1.1</version><date>Tue Jul 26 21:14:44 2011 UTC</date><recordtype>0</recordtype> | ||||||
|  | // <datatype>QDP_D3_ColorMatrix</datatype><precision>D</precision><colors>3</colors><spins>4</spins> | ||||||
|  | // <typesize>144</typesize><datacount>4</datacount> | ||||||
|  | // </scidacRecord> | ||||||
|  | /////////////////////////////////////////////////////////////////////// | ||||||
|  |  | ||||||
|  | struct scidacRecord : Serializable { | ||||||
|  | public: | ||||||
|  |   GRID_SERIALIZABLE_CLASS_MEMBERS(scidacRecord, | ||||||
|  |                                   double, version, | ||||||
|  |                                   std::string, date, | ||||||
|  | 				  int, recordtype, | ||||||
|  | 				  std::string, datatype, | ||||||
|  | 				  std::string, precision, | ||||||
|  | 				  int, colors, | ||||||
|  | 				  int, spins, | ||||||
|  | 				  int, typesize, | ||||||
|  | 				  int, datacount); | ||||||
|  |  | ||||||
|  |   scidacRecord() | ||||||
|  |   : version(1.0), recordtype(0), colors(0), spins(0), typesize(0), datacount(0) | ||||||
|  |   {} | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | //////////////////////// | ||||||
|  | // ILDG format | ||||||
|  | //////////////////////// | ||||||
|  | struct ildgFormat : Serializable { | ||||||
|  | public: | ||||||
|  |   GRID_SERIALIZABLE_CLASS_MEMBERS(ildgFormat, | ||||||
|  | 				  double, version, | ||||||
|  | 				  std::string, field, | ||||||
|  | 				  int, precision, | ||||||
|  | 				  int, lx, | ||||||
|  | 				  int, ly, | ||||||
|  | 				  int, lz, | ||||||
|  | 				  int, lt); | ||||||
|  |   ildgFormat() { version=1.0; }; | ||||||
|  | }; | ||||||
|  | //////////////////////// | ||||||
|  | // USQCD info | ||||||
|  | //////////////////////// | ||||||
|  | struct usqcdInfo : Serializable {  | ||||||
|  | public: | ||||||
|  |   GRID_SERIALIZABLE_CLASS_MEMBERS(usqcdInfo, | ||||||
|  | 				  double, version, | ||||||
|  | 				  double, plaq, | ||||||
|  | 				  double, linktr, | ||||||
|  | 				  std::string, info); | ||||||
|  |   usqcdInfo() {  | ||||||
|  |     version=1.0;  | ||||||
|  |   }; | ||||||
|  | }; | ||||||
|  | //////////////////////// | ||||||
|  | // Scidac Checksum | ||||||
|  | //////////////////////// | ||||||
|  | struct scidacChecksum : Serializable {  | ||||||
|  | public: | ||||||
|  |   GRID_SERIALIZABLE_CLASS_MEMBERS(scidacChecksum, | ||||||
|  | 				  double, version, | ||||||
|  | 				  std::string, suma, | ||||||
|  | 				  std::string, sumb); | ||||||
|  |   scidacChecksum() {  | ||||||
|  |     version=1.0;  | ||||||
|  |   }; | ||||||
|  | }; | ||||||
|  | //////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  | // Type:           scidac-file-xml         <title>MILC ILDG archival gauge configuration</title> | ||||||
|  | //////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  |  | ||||||
|  | //////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  | // Type:            | ||||||
|  | //////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  |  | ||||||
|  | //////////////////////// | ||||||
|  | // Scidac private file xml  | ||||||
|  | // <?xml version="1.0" encoding="UTF-8"?><scidacFile><version>1.1</version><spacetime>4</spacetime><dims>16 16 16 32 </dims><volfmt>0</volfmt></scidacFile>  | ||||||
|  | ////////////////////////                                                                                                                                                                               | ||||||
|  |  | ||||||
|  | #if 0 | ||||||
|  | //////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  | // From http://www.physics.utah.edu/~detar/scidac/qio_2p3.pdf | ||||||
|  | //////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  | struct usqcdPropFile : Serializable {  | ||||||
|  | public: | ||||||
|  |   GRID_SERIALIZABLE_CLASS_MEMBERS(usqcdPropFile, | ||||||
|  | 				  double, version, | ||||||
|  | 				  std::string, type, | ||||||
|  | 				  std::string, info); | ||||||
|  |   usqcdPropFile() {  | ||||||
|  |     version=1.0;  | ||||||
|  |   }; | ||||||
|  | }; | ||||||
|  | struct usqcdSourceInfo : Serializable {  | ||||||
|  | public: | ||||||
|  |   GRID_SERIALIZABLE_CLASS_MEMBERS(usqcdSourceInfo, | ||||||
|  | 				  double, version, | ||||||
|  | 				  std::string, info); | ||||||
|  |   usqcdSourceInfo() {  | ||||||
|  |     version=1.0;  | ||||||
|  |   }; | ||||||
|  | }; | ||||||
|  | struct usqcdPropInfo : Serializable {  | ||||||
|  | public: | ||||||
|  |   GRID_SERIALIZABLE_CLASS_MEMBERS(usqcdPropInfo, | ||||||
|  | 				  double, version, | ||||||
|  | 				  int, spin, | ||||||
|  | 				  int, color, | ||||||
|  | 				  std::string, info); | ||||||
|  |   usqcdPropInfo() {  | ||||||
|  |     version=1.0;  | ||||||
|  |   }; | ||||||
|  | }; | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | NAMESPACE_END(Grid); | ||||||
|  | #endif | ||||||
|  | #endif | ||||||
							
								
								
									
										330
									
								
								Grid/parallelIO/MetaData.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										330
									
								
								Grid/parallelIO/MetaData.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,330 @@ | |||||||
|  | /************************************************************************************* | ||||||
|  |  | ||||||
|  |     Grid physics library, www.github.com/paboyle/Grid  | ||||||
|  |  | ||||||
|  |     Source file: ./lib/parallelIO/NerscIO.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 */ | ||||||
|  |  | ||||||
|  | #include <algorithm> | ||||||
|  | #include <iostream> | ||||||
|  | #include <iomanip> | ||||||
|  | #include <fstream> | ||||||
|  | #include <map> | ||||||
|  | #include <unistd.h> | ||||||
|  | #include <sys/utsname.h> | ||||||
|  | #include <pwd.h> | ||||||
|  |  | ||||||
|  | NAMESPACE_BEGIN(Grid); | ||||||
|  |  | ||||||
|  | /////////////////////////////////////////////////////// | ||||||
|  | // Precision mapping | ||||||
|  | /////////////////////////////////////////////////////// | ||||||
|  | template<class vobj> static std::string getFormatString (void) | ||||||
|  | { | ||||||
|  |   std::string format; | ||||||
|  |   typedef typename getPrecision<vobj>::real_scalar_type stype; | ||||||
|  |   if ( sizeof(stype) == sizeof(float) ) { | ||||||
|  |     format = std::string("IEEE32BIG"); | ||||||
|  |   } | ||||||
|  |   if ( sizeof(stype) == sizeof(double) ) { | ||||||
|  |     format = std::string("IEEE64BIG"); | ||||||
|  |   } | ||||||
|  |   return format; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  |   //////////////////////////////////////////////////////////////////////////////// | ||||||
|  |   // header specification/interpretation | ||||||
|  |   //////////////////////////////////////////////////////////////////////////////// | ||||||
|  |     class FieldNormMetaData : Serializable { | ||||||
|  |     public: | ||||||
|  |       GRID_SERIALIZABLE_CLASS_MEMBERS(FieldNormMetaData, double, norm2); | ||||||
|  |     }; | ||||||
|  |     class FieldMetaData : Serializable { | ||||||
|  |     public: | ||||||
|  |  | ||||||
|  |       GRID_SERIALIZABLE_CLASS_MEMBERS(FieldMetaData, | ||||||
|  | 				      int, nd, | ||||||
|  | 				      std::vector<int>, dimension, | ||||||
|  | 				      std::vector<std::string>, boundary, | ||||||
|  | 				      int, data_start, | ||||||
|  | 				      std::string, hdr_version, | ||||||
|  | 				      std::string, storage_format, | ||||||
|  | 				      double, link_trace, | ||||||
|  | 				      double, plaquette, | ||||||
|  | 				      uint32_t, checksum, | ||||||
|  | 				      uint32_t, scidac_checksuma, | ||||||
|  | 				      uint32_t, scidac_checksumb, | ||||||
|  | 				      unsigned int, sequence_number, | ||||||
|  | 				      std::string, data_type, | ||||||
|  | 				      std::string, ensemble_id, | ||||||
|  | 				      std::string, ensemble_label, | ||||||
|  | 				      std::string, ildg_lfn, | ||||||
|  | 				      std::string, creator, | ||||||
|  | 				      std::string, creator_hardware, | ||||||
|  | 				      std::string, creation_date, | ||||||
|  | 				      std::string, archive_date, | ||||||
|  | 				      std::string, floating_point); | ||||||
|  |       // WARNING: non-initialised values might lead to twisted parallel IO | ||||||
|  |       // issues, std::string are fine because they initliase to size 0 | ||||||
|  |       // as per C++ standard. | ||||||
|  |       FieldMetaData(void)  | ||||||
|  |       : nd(4), dimension(4,0), boundary(4, ""), data_start(0), | ||||||
|  |       link_trace(0.), plaquette(0.), checksum(0), | ||||||
|  |       scidac_checksuma(0), scidac_checksumb(0), sequence_number(0) | ||||||
|  |       {} | ||||||
|  |   }; | ||||||
|  |  | ||||||
|  | // PB disable using namespace - this is a header and forces namesapce visibility for all  | ||||||
|  | // including files | ||||||
|  | //using namespace Grid; | ||||||
|  |  | ||||||
|  | ////////////////////////////////////////////////////////////////////// | ||||||
|  | // Bit and Physical Checksumming and QA of data | ||||||
|  | ////////////////////////////////////////////////////////////////////// | ||||||
|  | inline void GridMetaData(GridBase *grid,FieldMetaData &header) | ||||||
|  | { | ||||||
|  |   int nd = grid->_ndimension; | ||||||
|  |   header.nd = nd; | ||||||
|  |   header.dimension.resize(nd); | ||||||
|  |   header.boundary.resize(nd); | ||||||
|  |   header.data_start = 0; | ||||||
|  |   for(int d=0;d<nd;d++) { | ||||||
|  |     header.dimension[d] = grid->_fdimensions[d]; | ||||||
|  |   } | ||||||
|  |   for(int d=0;d<nd;d++) { | ||||||
|  |     header.boundary[d] = std::string("PERIODIC"); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | inline void MachineCharacteristics(FieldMetaData &header) | ||||||
|  | { | ||||||
|  |   // Who | ||||||
|  |   struct passwd *pw = getpwuid (getuid()); | ||||||
|  |   if (pw) header.creator = std::string(pw->pw_name);  | ||||||
|  |  | ||||||
|  |   // When | ||||||
|  |   std::time_t t = std::time(nullptr); | ||||||
|  |   std::tm tm_ = *std::localtime(&t); | ||||||
|  |   std::ostringstream oss;  | ||||||
|  |   //      oss << std::put_time(&tm_, "%c %Z"); | ||||||
|  |   header.creation_date = oss.str(); | ||||||
|  |   header.archive_date  = header.creation_date; | ||||||
|  |  | ||||||
|  |   // What | ||||||
|  |   struct utsname name;  uname(&name); | ||||||
|  |   header.creator_hardware = std::string(name.nodename)+"-"; | ||||||
|  |   header.creator_hardware+= std::string(name.machine)+"-"; | ||||||
|  |   header.creator_hardware+= std::string(name.sysname)+"-"; | ||||||
|  |   header.creator_hardware+= std::string(name.release); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #define dump_meta_data(field, s)					\ | ||||||
|  |   s << "BEGIN_HEADER"      << std::endl;				\ | ||||||
|  |   s << "HDR_VERSION = "    << field.hdr_version    << std::endl;	\ | ||||||
|  |   s << "DATATYPE = "       << field.data_type      << std::endl;	\ | ||||||
|  |   s << "STORAGE_FORMAT = " << field.storage_format << std::endl;	\ | ||||||
|  |   for(int i=0;i<4;i++){							\ | ||||||
|  |     s << "DIMENSION_" << i+1 << " = " << field.dimension[i] << std::endl ; \ | ||||||
|  |   }									\ | ||||||
|  |   s << "LINK_TRACE = " << std::setprecision(10) << field.link_trace << std::endl; \ | ||||||
|  |   s << "PLAQUETTE  = " << std::setprecision(10) << field.plaquette  << std::endl; \ | ||||||
|  |   for(int i=0;i<4;i++){							\ | ||||||
|  |     s << "BOUNDARY_"<<i+1<<" = " << field.boundary[i] << std::endl;	\ | ||||||
|  |   }									\ | ||||||
|  | 									\ | ||||||
|  |   s << "CHECKSUM = "<< std::hex << std::setw(10) << field.checksum << std::dec<<std::endl; \ | ||||||
|  |   s << "SCIDAC_CHECKSUMA = "<< std::hex << std::setw(10) << field.scidac_checksuma << std::dec<<std::endl; \ | ||||||
|  |   s << "SCIDAC_CHECKSUMB = "<< std::hex << std::setw(10) << field.scidac_checksumb << std::dec<<std::endl; \ | ||||||
|  |   s << "ENSEMBLE_ID = "     << field.ensemble_id      << std::endl;	\ | ||||||
|  |   s << "ENSEMBLE_LABEL = "  << field.ensemble_label   << std::endl;	\ | ||||||
|  |   s << "SEQUENCE_NUMBER = " << field.sequence_number  << std::endl;	\ | ||||||
|  |   s << "CREATOR = "         << field.creator          << std::endl;	\ | ||||||
|  |   s << "CREATOR_HARDWARE = "<< field.creator_hardware << std::endl;	\ | ||||||
|  |   s << "CREATION_DATE = "   << field.creation_date    << std::endl;	\ | ||||||
|  |   s << "ARCHIVE_DATE = "    << field.archive_date     << std::endl;	\ | ||||||
|  |   s << "FLOATING_POINT = "  << field.floating_point   << std::endl;	\ | ||||||
|  |   s << "END_HEADER"         << std::endl; | ||||||
|  |  | ||||||
|  | template<class vobj> inline void PrepareMetaData(Lattice<vobj> & field, FieldMetaData &header) | ||||||
|  | { | ||||||
|  |   GridBase *grid = field.Grid(); | ||||||
|  |   std::string format = getFormatString<vobj>(); | ||||||
|  |   header.floating_point = format; | ||||||
|  |   header.checksum = 0x0; // Nersc checksum unused in ILDG, Scidac | ||||||
|  |   GridMetaData(grid,header);  | ||||||
|  |   MachineCharacteristics(header); | ||||||
|  | } | ||||||
|  | inline void GaugeStatistics(Lattice<vLorentzColourMatrixF> & data,FieldMetaData &header) | ||||||
|  | { | ||||||
|  |   // How to convert data precision etc... | ||||||
|  |   header.link_trace=WilsonLoops<PeriodicGimplF>::linkTrace(data); | ||||||
|  |   header.plaquette =WilsonLoops<PeriodicGimplF>::avgPlaquette(data); | ||||||
|  | } | ||||||
|  | inline void GaugeStatistics(Lattice<vLorentzColourMatrixD> & data,FieldMetaData &header) | ||||||
|  | { | ||||||
|  |   // How to convert data precision etc... | ||||||
|  |   header.link_trace=WilsonLoops<PeriodicGimplD>::linkTrace(data); | ||||||
|  |   header.plaquette =WilsonLoops<PeriodicGimplD>::avgPlaquette(data); | ||||||
|  | } | ||||||
|  | template<> inline void PrepareMetaData<vLorentzColourMatrixF>(Lattice<vLorentzColourMatrixF> & field, FieldMetaData &header) | ||||||
|  | { | ||||||
|  |     | ||||||
|  |   GridBase *grid = field.Grid(); | ||||||
|  |   std::string format = getFormatString<vLorentzColourMatrixF>(); | ||||||
|  |   header.floating_point = format; | ||||||
|  |   header.checksum = 0x0; // Nersc checksum unused in ILDG, Scidac | ||||||
|  |   GridMetaData(grid,header);  | ||||||
|  |   GaugeStatistics(field,header); | ||||||
|  |   MachineCharacteristics(header); | ||||||
|  | } | ||||||
|  | template<> inline void PrepareMetaData<vLorentzColourMatrixD>(Lattice<vLorentzColourMatrixD> & field, FieldMetaData &header) | ||||||
|  | { | ||||||
|  |   GridBase *grid = field.Grid(); | ||||||
|  |   std::string format = getFormatString<vLorentzColourMatrixD>(); | ||||||
|  |   header.floating_point = format; | ||||||
|  |   header.checksum = 0x0; // Nersc checksum unused in ILDG, Scidac | ||||||
|  |   GridMetaData(grid,header);  | ||||||
|  |   GaugeStatistics(field,header); | ||||||
|  |   MachineCharacteristics(header); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | ////////////////////////////////////////////////////////////////////// | ||||||
|  | // Utilities ; these are QCD aware | ||||||
|  | ////////////////////////////////////////////////////////////////////// | ||||||
|  | inline void reconstruct3(LorentzColourMatrix & cm) | ||||||
|  | { | ||||||
|  |   const int x=0; | ||||||
|  |   const int y=1; | ||||||
|  |   const int z=2; | ||||||
|  |   for(int mu=0;mu<Nd;mu++){ | ||||||
|  |     cm(mu)()(2,x) = adj(cm(mu)()(0,y)*cm(mu)()(1,z)-cm(mu)()(0,z)*cm(mu)()(1,y)); //x= yz-zy | ||||||
|  |     cm(mu)()(2,y) = adj(cm(mu)()(0,z)*cm(mu)()(1,x)-cm(mu)()(0,x)*cm(mu)()(1,z)); //y= zx-xz | ||||||
|  |     cm(mu)()(2,z) = adj(cm(mu)()(0,x)*cm(mu)()(1,y)-cm(mu)()(0,y)*cm(mu)()(1,x)); //z= xy-yx | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | //////////////////////////////////////////////////////////////////////////////// | ||||||
|  | // Some data types for intermediate storage | ||||||
|  | //////////////////////////////////////////////////////////////////////////////// | ||||||
|  | template<typename vtype> using iLorentzColour2x3 = iVector<iVector<iVector<vtype, Nc>, 2>, Nd >; | ||||||
|  |  | ||||||
|  | typedef iLorentzColour2x3<Complex>  LorentzColour2x3; | ||||||
|  | typedef iLorentzColour2x3<ComplexF> LorentzColour2x3F; | ||||||
|  | typedef iLorentzColour2x3<ComplexD> LorentzColour2x3D; | ||||||
|  |  | ||||||
|  | ///////////////////////////////////////////////////////////////////////////////// | ||||||
|  | // Simple classes for precision conversion | ||||||
|  | ///////////////////////////////////////////////////////////////////////////////// | ||||||
|  | template <class fobj, class sobj> | ||||||
|  | struct BinarySimpleUnmunger { | ||||||
|  |   typedef typename getPrecision<fobj>::real_scalar_type fobj_stype; | ||||||
|  |   typedef typename getPrecision<sobj>::real_scalar_type sobj_stype; | ||||||
|  |    | ||||||
|  |   void operator()(sobj &in, fobj &out) { | ||||||
|  |     // take word by word and transform accoding to the status | ||||||
|  |     fobj_stype *out_buffer = (fobj_stype *)&out; | ||||||
|  |     sobj_stype *in_buffer = (sobj_stype *)∈ | ||||||
|  |     size_t fobj_words = sizeof(out) / sizeof(fobj_stype); | ||||||
|  |     size_t sobj_words = sizeof(in) / sizeof(sobj_stype); | ||||||
|  |     assert(fobj_words == sobj_words); | ||||||
|  |      | ||||||
|  |     for (unsigned int word = 0; word < sobj_words; word++) | ||||||
|  |       out_buffer[word] = in_buffer[word];  // type conversion on the fly | ||||||
|  |      | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | template <class fobj, class sobj> | ||||||
|  | struct BinarySimpleMunger { | ||||||
|  |   typedef typename getPrecision<fobj>::real_scalar_type fobj_stype; | ||||||
|  |   typedef typename getPrecision<sobj>::real_scalar_type sobj_stype; | ||||||
|  |  | ||||||
|  |   void operator()(fobj &in, sobj &out) { | ||||||
|  |     // take word by word and transform accoding to the status | ||||||
|  |     fobj_stype *in_buffer = (fobj_stype *)∈ | ||||||
|  |     sobj_stype *out_buffer = (sobj_stype *)&out; | ||||||
|  |     size_t fobj_words = sizeof(in) / sizeof(fobj_stype); | ||||||
|  |     size_t sobj_words = sizeof(out) / sizeof(sobj_stype); | ||||||
|  |     assert(fobj_words == sobj_words); | ||||||
|  |      | ||||||
|  |     for (unsigned int word = 0; word < sobj_words; word++) | ||||||
|  |       out_buffer[word] = in_buffer[word];  // type conversion on the fly | ||||||
|  |      | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | template<class fobj,class sobj> | ||||||
|  | struct GaugeSimpleMunger{ | ||||||
|  |   void operator()(fobj &in, sobj &out) { | ||||||
|  |     for (int mu = 0; mu < Nd; mu++) { | ||||||
|  |       for (int i = 0; i < Nc; i++) { | ||||||
|  | 	for (int j = 0; j < Nc; j++) { | ||||||
|  | 	  out(mu)()(i, j) = in(mu)()(i, j); | ||||||
|  | 	}} | ||||||
|  |     } | ||||||
|  |   }; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | template <class fobj, class sobj> | ||||||
|  | struct GaugeSimpleUnmunger { | ||||||
|  |  | ||||||
|  |   void operator()(sobj &in, fobj &out) { | ||||||
|  |     for (int mu = 0; mu < Nd; mu++) { | ||||||
|  |       for (int i = 0; i < Nc; i++) { | ||||||
|  | 	for (int j = 0; j < Nc; j++) { | ||||||
|  | 	  out(mu)()(i, j) = in(mu)()(i, j); | ||||||
|  | 	}} | ||||||
|  |     } | ||||||
|  |   }; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | template<class fobj,class sobj> | ||||||
|  | struct Gauge3x2munger{ | ||||||
|  |   void operator() (fobj &in,sobj &out){ | ||||||
|  |     for(int mu=0;mu<Nd;mu++){ | ||||||
|  |       for(int i=0;i<2;i++){ | ||||||
|  | 	for(int j=0;j<3;j++){ | ||||||
|  | 	  out(mu)()(i,j) = in(mu)(i)(j); | ||||||
|  | 	}} | ||||||
|  |     } | ||||||
|  |     reconstruct3(out); | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | template<class fobj,class sobj> | ||||||
|  | struct Gauge3x2unmunger{ | ||||||
|  |   void operator() (sobj &in,fobj &out){ | ||||||
|  |     for(int mu=0;mu<Nd;mu++){ | ||||||
|  |       for(int i=0;i<2;i++){ | ||||||
|  | 	for(int j=0;j<3;j++){ | ||||||
|  | 	  out(mu)(i)(j) = in(mu)()(i,j); | ||||||
|  | 	}} | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | NAMESPACE_END(Grid); | ||||||
|  |  | ||||||
							
								
								
									
										359
									
								
								Grid/parallelIO/NerscIO.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										359
									
								
								Grid/parallelIO/NerscIO.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,359 @@ | |||||||
|  | /************************************************************************************* | ||||||
|  |  | ||||||
|  |     Grid physics library, www.github.com/paboyle/Grid  | ||||||
|  |  | ||||||
|  |     Source file: ./lib/parallelIO/NerscIO.h | ||||||
|  |  | ||||||
|  |     Copyright (C) 2015 | ||||||
|  |  | ||||||
|  |     Author: Matt Spraggs <matthew.spraggs@gmail.com> | ||||||
|  |     Author: Peter Boyle <paboyle@ph.ed.ac.uk> | ||||||
|  |     Author: paboyle <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_NERSC_IO_H | ||||||
|  | #define GRID_NERSC_IO_H | ||||||
|  |  | ||||||
|  | NAMESPACE_BEGIN(Grid); | ||||||
|  |  | ||||||
|  | using namespace Grid; | ||||||
|  |  | ||||||
|  | //////////////////////////////////////////////////////////////////////////////// | ||||||
|  | // Write and read from fstream; comput header offset for payload | ||||||
|  | //////////////////////////////////////////////////////////////////////////////// | ||||||
|  | class NerscIO : public BinaryIO {  | ||||||
|  | public: | ||||||
|  |  | ||||||
|  |   static inline void truncate(std::string file){ | ||||||
|  |     std::ofstream fout(file,std::ios::out); | ||||||
|  |   } | ||||||
|  |    | ||||||
|  |   static inline unsigned int writeHeader(FieldMetaData &field,std::string file) | ||||||
|  |   { | ||||||
|  |     std::ofstream fout(file,std::ios::out|std::ios::in); | ||||||
|  |     fout.seekp(0,std::ios::beg); | ||||||
|  |     dump_meta_data(field, fout); | ||||||
|  |     field.data_start = fout.tellp(); | ||||||
|  |     return field.data_start; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   // for the header-reader | ||||||
|  |   static inline int readHeader(std::string file,GridBase *grid,  FieldMetaData &field) | ||||||
|  |   { | ||||||
|  |     std::map<std::string,std::string> header; | ||||||
|  |     std::string line; | ||||||
|  |  | ||||||
|  |     ////////////////////////////////////////////////// | ||||||
|  |     // read the header | ||||||
|  |     ////////////////////////////////////////////////// | ||||||
|  |     std::ifstream fin(file); | ||||||
|  |  | ||||||
|  |     getline(fin,line); // read one line and insist is  | ||||||
|  |  | ||||||
|  |     removeWhitespace(line); | ||||||
|  |     std::cout << GridLogMessage << "* " << line << std::endl; | ||||||
|  |  | ||||||
|  |     assert(line==std::string("BEGIN_HEADER")); | ||||||
|  |  | ||||||
|  |     do { | ||||||
|  |       getline(fin,line); // read one line | ||||||
|  |       std::cout << GridLogMessage << "* "<<line<< std::endl; | ||||||
|  |       int eq = line.find("="); | ||||||
|  |       if(eq >0) { | ||||||
|  | 	std::string key=line.substr(0,eq); | ||||||
|  | 	std::string val=line.substr(eq+1); | ||||||
|  | 	removeWhitespace(key); | ||||||
|  | 	removeWhitespace(val); | ||||||
|  |        | ||||||
|  | 	header[key] = val; | ||||||
|  |       } | ||||||
|  |     } while( line.find("END_HEADER") == std::string::npos ); | ||||||
|  |  | ||||||
|  |     field.data_start = fin.tellg(); | ||||||
|  |  | ||||||
|  |     ////////////////////////////////////////////////// | ||||||
|  |     // chomp the values | ||||||
|  |     ////////////////////////////////////////////////// | ||||||
|  |     field.hdr_version    = header["HDR_VERSION"]; | ||||||
|  |     field.data_type      = header["DATATYPE"]; | ||||||
|  |     field.storage_format = header["STORAGE_FORMAT"]; | ||||||
|  |    | ||||||
|  |     field.dimension[0] = std::stol(header["DIMENSION_1"]); | ||||||
|  |     field.dimension[1] = std::stol(header["DIMENSION_2"]); | ||||||
|  |     field.dimension[2] = std::stol(header["DIMENSION_3"]); | ||||||
|  |     field.dimension[3] = std::stol(header["DIMENSION_4"]); | ||||||
|  |  | ||||||
|  |     assert(grid->_ndimension == 4); | ||||||
|  |     for(int d=0;d<4;d++){ | ||||||
|  |       assert(grid->_fdimensions[d]==field.dimension[d]); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     field.link_trace = std::stod(header["LINK_TRACE"]); | ||||||
|  |     field.plaquette  = std::stod(header["PLAQUETTE"]); | ||||||
|  |  | ||||||
|  |     field.boundary[0] = header["BOUNDARY_1"]; | ||||||
|  |     field.boundary[1] = header["BOUNDARY_2"]; | ||||||
|  |     field.boundary[2] = header["BOUNDARY_3"]; | ||||||
|  |     field.boundary[3] = header["BOUNDARY_4"]; | ||||||
|  |  | ||||||
|  |     field.checksum = std::stoul(header["CHECKSUM"],0,16); | ||||||
|  |     field.ensemble_id      = header["ENSEMBLE_ID"]; | ||||||
|  |     field.ensemble_label   = header["ENSEMBLE_LABEL"]; | ||||||
|  |     field.sequence_number  = std::stol(header["SEQUENCE_NUMBER"]); | ||||||
|  |     field.creator          = header["CREATOR"]; | ||||||
|  |     field.creator_hardware = header["CREATOR_HARDWARE"]; | ||||||
|  |     field.creation_date    = header["CREATION_DATE"]; | ||||||
|  |     field.archive_date     = header["ARCHIVE_DATE"]; | ||||||
|  |     field.floating_point   = header["FLOATING_POINT"]; | ||||||
|  |  | ||||||
|  |     return field.data_start; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  |   // Now the meat: the object readers | ||||||
|  |   ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  |  | ||||||
|  |   template<class vsimd> | ||||||
|  |   static inline void readConfiguration(Lattice<iLorentzColourMatrix<vsimd> > &Umu, | ||||||
|  | 				       FieldMetaData& header, | ||||||
|  | 				       std::string file) | ||||||
|  |   { | ||||||
|  |     typedef Lattice<iLorentzColourMatrix<vsimd> > GaugeField; | ||||||
|  |  | ||||||
|  |     GridBase *grid = Umu.Grid(); | ||||||
|  |     uint64_t offset = readHeader(file,Umu.Grid(),header); | ||||||
|  |  | ||||||
|  |     FieldMetaData clone(header); | ||||||
|  |  | ||||||
|  |     std::string format(header.floating_point); | ||||||
|  |  | ||||||
|  |     int ieee32big = (format == std::string("IEEE32BIG")); | ||||||
|  |     int ieee32    = (format == std::string("IEEE32")); | ||||||
|  |     int ieee64big = (format == std::string("IEEE64BIG")); | ||||||
|  |     int ieee64    = (format == std::string("IEEE64")); | ||||||
|  |  | ||||||
|  |     uint32_t nersc_csum,scidac_csuma,scidac_csumb; | ||||||
|  |     // depending on datatype, set up munger; | ||||||
|  |     // munger is a function of <floating point, Real, data_type> | ||||||
|  |     if ( header.data_type == std::string("4D_SU3_GAUGE") ) { | ||||||
|  |       if ( ieee32 || ieee32big ) { | ||||||
|  | 	BinaryIO::readLatticeObject<iLorentzColourMatrix<vsimd>, LorentzColour2x3F>  | ||||||
|  | 	  (Umu,file,Gauge3x2munger<LorentzColour2x3F,LorentzColourMatrix>(), offset,format, | ||||||
|  | 	   nersc_csum,scidac_csuma,scidac_csumb); | ||||||
|  |       } | ||||||
|  |       if ( ieee64 || ieee64big ) { | ||||||
|  | 	BinaryIO::readLatticeObject<iLorentzColourMatrix<vsimd>, LorentzColour2x3D>  | ||||||
|  | 	  (Umu,file,Gauge3x2munger<LorentzColour2x3D,LorentzColourMatrix>(),offset,format, | ||||||
|  | 	   nersc_csum,scidac_csuma,scidac_csumb); | ||||||
|  |       } | ||||||
|  |     } else if ( header.data_type == std::string("4D_SU3_GAUGE_3x3") ) { | ||||||
|  |       if ( ieee32 || ieee32big ) { | ||||||
|  | 	BinaryIO::readLatticeObject<iLorentzColourMatrix<vsimd>,LorentzColourMatrixF> | ||||||
|  | 	  (Umu,file,GaugeSimpleMunger<LorentzColourMatrixF,LorentzColourMatrix>(),offset,format, | ||||||
|  | 	   nersc_csum,scidac_csuma,scidac_csumb); | ||||||
|  |       } | ||||||
|  |       if ( ieee64 || ieee64big ) { | ||||||
|  | 	BinaryIO::readLatticeObject<iLorentzColourMatrix<vsimd>,LorentzColourMatrixD> | ||||||
|  | 	  (Umu,file,GaugeSimpleMunger<LorentzColourMatrixD,LorentzColourMatrix>(),offset,format, | ||||||
|  | 	   nersc_csum,scidac_csuma,scidac_csumb); | ||||||
|  |       } | ||||||
|  |     } else { | ||||||
|  |       assert(0); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     GaugeStatistics(Umu,clone); | ||||||
|  |  | ||||||
|  |     std::cout<<GridLogMessage <<"NERSC Configuration "<<file<<" checksum "<<std::hex<<nersc_csum<< std::dec | ||||||
|  | 	     <<" header   "<<std::hex<<header.checksum<<std::dec <<std::endl; | ||||||
|  |     std::cout<<GridLogMessage <<"NERSC Configuration "<<file<<" plaquette "<<clone.plaquette | ||||||
|  | 	     <<" header    "<<header.plaquette<<std::endl; | ||||||
|  |     std::cout<<GridLogMessage <<"NERSC Configuration "<<file<<" link_trace "<<clone.link_trace | ||||||
|  | 	     <<" header    "<<header.link_trace<<std::endl; | ||||||
|  |  | ||||||
|  |     if ( fabs(clone.plaquette -header.plaquette ) >=  1.0e-5 ) {  | ||||||
|  |       std::cout << " Plaquette mismatch "<<std::endl; | ||||||
|  |     } | ||||||
|  |     if ( nersc_csum != header.checksum ) {  | ||||||
|  |       std::cerr << " checksum mismatch " << std::endl; | ||||||
|  |       std::cerr << " plaqs " << clone.plaquette << " " << header.plaquette << std::endl; | ||||||
|  |       std::cerr << " trace " << clone.link_trace<< " " << header.link_trace<< std::endl; | ||||||
|  |       std::cerr << " nersc_csum  " <<std::hex<< nersc_csum << " " << header.checksum<< std::dec<< std::endl; | ||||||
|  |       exit(0); | ||||||
|  |     } | ||||||
|  |     assert(fabs(clone.plaquette -header.plaquette ) < 1.0e-5 ); | ||||||
|  |     assert(fabs(clone.link_trace-header.link_trace) < 1.0e-6 ); | ||||||
|  |     assert(nersc_csum == header.checksum ); | ||||||
|  |        | ||||||
|  |     std::cout<<GridLogMessage <<"NERSC Configuration "<<file<< " and plaquette, link trace, and checksum agree"<<std::endl; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   template<class vsimd> | ||||||
|  |   static inline void writeConfiguration(Lattice<iLorentzColourMatrix<vsimd> > &Umu, | ||||||
|  | 					std::string file,  | ||||||
|  | 					int two_row, | ||||||
|  | 					int bits32) | ||||||
|  |   { | ||||||
|  |     typedef Lattice<iLorentzColourMatrix<vsimd> > GaugeField; | ||||||
|  |  | ||||||
|  |     typedef iLorentzColourMatrix<vsimd> vobj; | ||||||
|  |     typedef typename vobj::scalar_object sobj; | ||||||
|  |  | ||||||
|  |     FieldMetaData header; | ||||||
|  |     /////////////////////////////////////////// | ||||||
|  |     // Following should become arguments | ||||||
|  |     /////////////////////////////////////////// | ||||||
|  |     header.sequence_number = 1; | ||||||
|  |     header.ensemble_id     = "UKQCD"; | ||||||
|  |     header.ensemble_label  = "DWF"; | ||||||
|  |  | ||||||
|  |     typedef LorentzColourMatrixD fobj3D; | ||||||
|  |     typedef LorentzColour2x3D    fobj2D; | ||||||
|  |    | ||||||
|  |     GridBase *grid = Umu.Grid(); | ||||||
|  |  | ||||||
|  |     GridMetaData(grid,header); | ||||||
|  |     assert(header.nd==4); | ||||||
|  |     GaugeStatistics(Umu,header); | ||||||
|  |     MachineCharacteristics(header); | ||||||
|  |  | ||||||
|  | 	uint64_t offset; | ||||||
|  |  | ||||||
|  |     // Sod it -- always write 3x3 double | ||||||
|  |     header.floating_point = std::string("IEEE64BIG"); | ||||||
|  |     header.data_type      = std::string("4D_SU3_GAUGE_3x3"); | ||||||
|  |     GaugeSimpleUnmunger<fobj3D,sobj> munge; | ||||||
|  | 	if ( grid->IsBoss() ) {  | ||||||
|  | 	  truncate(file); | ||||||
|  |     offset = writeHeader(header,file); | ||||||
|  | 	} | ||||||
|  | 	grid->Broadcast(0,(void *)&offset,sizeof(offset)); | ||||||
|  |  | ||||||
|  |     uint32_t nersc_csum,scidac_csuma,scidac_csumb; | ||||||
|  |     BinaryIO::writeLatticeObject<vobj,fobj3D>(Umu,file,munge,offset,header.floating_point, | ||||||
|  | 					      nersc_csum,scidac_csuma,scidac_csumb); | ||||||
|  |     header.checksum = nersc_csum; | ||||||
|  | 	if ( grid->IsBoss() ) {  | ||||||
|  |     writeHeader(header,file); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  |     std::cout<<GridLogMessage <<"Written NERSC Configuration on "<< file << " checksum " | ||||||
|  | 	     <<std::hex<<header.checksum | ||||||
|  | 	     <<std::dec<<" plaq "<< header.plaquette <<std::endl; | ||||||
|  |  | ||||||
|  |   } | ||||||
|  |   /////////////////////////////// | ||||||
|  |   // RNG state | ||||||
|  |   /////////////////////////////// | ||||||
|  |   static inline void writeRNGState(GridSerialRNG &serial,GridParallelRNG ¶llel,std::string file) | ||||||
|  |   { | ||||||
|  |     typedef typename GridParallelRNG::RngStateType RngStateType; | ||||||
|  |  | ||||||
|  |     // Following should become arguments | ||||||
|  |     FieldMetaData header; | ||||||
|  |     header.sequence_number = 1; | ||||||
|  |     header.ensemble_id     = "UKQCD"; | ||||||
|  |     header.ensemble_label  = "DWF"; | ||||||
|  |  | ||||||
|  |     GridBase *grid = parallel.Grid(); | ||||||
|  |  | ||||||
|  |     GridMetaData(grid,header); | ||||||
|  |     assert(header.nd==4); | ||||||
|  |     header.link_trace=0.0; | ||||||
|  |     header.plaquette=0.0; | ||||||
|  |     MachineCharacteristics(header); | ||||||
|  |  | ||||||
|  | 	uint64_t offset; | ||||||
|  |    | ||||||
|  | #ifdef RNG_RANLUX | ||||||
|  |     header.floating_point = std::string("UINT64"); | ||||||
|  |     header.data_type      = std::string("RANLUX48"); | ||||||
|  | #endif | ||||||
|  | #ifdef RNG_MT19937 | ||||||
|  |     header.floating_point = std::string("UINT32"); | ||||||
|  |     header.data_type      = std::string("MT19937"); | ||||||
|  | #endif | ||||||
|  | #ifdef RNG_SITMO | ||||||
|  |     header.floating_point = std::string("UINT64"); | ||||||
|  |     header.data_type      = std::string("SITMO"); | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | 	if ( grid->IsBoss() ) {  | ||||||
|  |     truncate(file); | ||||||
|  |     offset = writeHeader(header,file); | ||||||
|  | 	} | ||||||
|  | 	grid->Broadcast(0,(void *)&offset,sizeof(offset)); | ||||||
|  | 	 | ||||||
|  |     uint32_t nersc_csum,scidac_csuma,scidac_csumb; | ||||||
|  |     BinaryIO::writeRNG(serial,parallel,file,offset,nersc_csum,scidac_csuma,scidac_csumb); | ||||||
|  |     header.checksum = nersc_csum; | ||||||
|  | 	if ( grid->IsBoss() ) {  | ||||||
|  |     offset = writeHeader(header,file); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  |     std::cout<<GridLogMessage  | ||||||
|  | 	     <<"Written NERSC RNG STATE "<<file<< " checksum " | ||||||
|  | 	     <<std::hex<<header.checksum | ||||||
|  | 	     <<std::dec<<std::endl; | ||||||
|  |  | ||||||
|  |   } | ||||||
|  |      | ||||||
|  |   static inline void readRNGState(GridSerialRNG &serial,GridParallelRNG & parallel,FieldMetaData& header,std::string file) | ||||||
|  |   { | ||||||
|  |     typedef typename GridParallelRNG::RngStateType RngStateType; | ||||||
|  |  | ||||||
|  |     GridBase *grid = parallel.Grid(); | ||||||
|  |  | ||||||
|  | 	uint64_t offset = readHeader(file,grid,header); | ||||||
|  |  | ||||||
|  |     FieldMetaData clone(header); | ||||||
|  |  | ||||||
|  |     std::string format(header.floating_point); | ||||||
|  |     std::string data_type(header.data_type); | ||||||
|  |  | ||||||
|  | #ifdef RNG_RANLUX | ||||||
|  |     assert(format == std::string("UINT64")); | ||||||
|  |     assert(data_type == std::string("RANLUX48")); | ||||||
|  | #endif | ||||||
|  | #ifdef RNG_MT19937 | ||||||
|  |     assert(format == std::string("UINT32")); | ||||||
|  |     assert(data_type == std::string("MT19937")); | ||||||
|  | #endif | ||||||
|  | #ifdef RNG_SITMO | ||||||
|  |     assert(format == std::string("UINT64")); | ||||||
|  |     assert(data_type == std::string("SITMO")); | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  |     // depending on datatype, set up munger; | ||||||
|  |     // munger is a function of <floating point, Real, data_type> | ||||||
|  |     uint32_t nersc_csum,scidac_csuma,scidac_csumb; | ||||||
|  |     BinaryIO::readRNG(serial,parallel,file,offset,nersc_csum,scidac_csuma,scidac_csumb); | ||||||
|  |  | ||||||
|  |     if ( nersc_csum != header.checksum ) {  | ||||||
|  |       std::cerr << "checksum mismatch "<<std::hex<< nersc_csum <<" "<<header.checksum<<std::dec<<std::endl; | ||||||
|  |       exit(0); | ||||||
|  |     } | ||||||
|  |     assert(nersc_csum == header.checksum ); | ||||||
|  |  | ||||||
|  |     std::cout<<GridLogMessage <<"Read NERSC RNG file "<<file<< " format "<< data_type <<std::endl; | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | NAMESPACE_END(QCD); | ||||||
|  |  | ||||||
|  | #endif | ||||||
| @@ -1,4 +1,4 @@ | |||||||
|     /*************************************************************************************
 | /*************************************************************************************
 | ||||||
| 
 | 
 | ||||||
|     Grid physics library, www.github.com/paboyle/Grid  |     Grid physics library, www.github.com/paboyle/Grid  | ||||||
| 
 | 
 | ||||||
| @@ -23,13 +23,13 @@ Author: paboyle <paboyle@ph.ed.ac.uk> | |||||||
|     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||||||
| 
 | 
 | ||||||
|     See the full license in the file "LICENSE" in the top level distribution directory |     See the full license in the file "LICENSE" in the top level distribution directory | ||||||
|     *************************************************************************************/ | *************************************************************************************/ | ||||||
|     /*  END LEGAL */ | /*  END LEGAL */ | ||||||
| 
 | 
 | ||||||
| #include <Grid/GridCore.h> | #include <Grid/GridCore.h> | ||||||
| #include <Grid/perfmon/PerfCount.h> | #include <Grid/perfmon/PerfCount.h> | ||||||
| 
 | 
 | ||||||
| namespace Grid { | NAMESPACE_BEGIN(Grid); | ||||||
| 
 | 
 | ||||||
| #define CacheControl(L,O,R) ((PERF_COUNT_HW_CACHE_##L)|(PERF_COUNT_HW_CACHE_OP_##O<<8)| (PERF_COUNT_HW_CACHE_RESULT_##R<<16)) | #define CacheControl(L,O,R) ((PERF_COUNT_HW_CACHE_##L)|(PERF_COUNT_HW_CACHE_OP_##O<<8)| (PERF_COUNT_HW_CACHE_RESULT_##R<<16)) | ||||||
| #define RawConfig(A,B) (A<<8|B) | #define RawConfig(A,B) (A<<8|B) | ||||||
| @@ -39,16 +39,16 @@ const PerformanceCounter::PerformanceCounterConfig PerformanceCounter::Performan | |||||||
|   { PERF_TYPE_HARDWARE, PERF_COUNT_HW_CACHE_MISSES        ,  "CACHE_MISSES......." , CACHE_REFERENCES}, |   { PERF_TYPE_HARDWARE, PERF_COUNT_HW_CACHE_MISSES        ,  "CACHE_MISSES......." , CACHE_REFERENCES}, | ||||||
|   { PERF_TYPE_HARDWARE, PERF_COUNT_HW_CPU_CYCLES          ,  "CPUCYCLES.........." , INSTRUCTIONS}, |   { PERF_TYPE_HARDWARE, PERF_COUNT_HW_CPU_CYCLES          ,  "CPUCYCLES.........." , INSTRUCTIONS}, | ||||||
|   { PERF_TYPE_HARDWARE, PERF_COUNT_HW_INSTRUCTIONS        ,  "INSTRUCTIONS......." , CPUCYCLES   }, |   { PERF_TYPE_HARDWARE, PERF_COUNT_HW_INSTRUCTIONS        ,  "INSTRUCTIONS......." , CPUCYCLES   }, | ||||||
|     // 4
 |   // 4
 | ||||||
| #ifdef AVX512 | #ifdef KNL | ||||||
|     { PERF_TYPE_RAW, RawConfig(0x40,0x04), "ALL_LOADS..........", CPUCYCLES    }, |   { PERF_TYPE_RAW, RawConfig(0x40,0x04), "ALL_LOADS..........", CPUCYCLES    }, | ||||||
|     { PERF_TYPE_RAW, RawConfig(0x01,0x04), "L1_MISS_LOADS......", L1D_READ_ACCESS  }, |   { PERF_TYPE_RAW, RawConfig(0x01,0x04), "L1_MISS_LOADS......", L1D_READ_ACCESS }, | ||||||
|     { PERF_TYPE_RAW, RawConfig(0x40,0x04), "ALL_LOADS..........", L1D_READ_ACCESS    }, |   { PERF_TYPE_RAW, RawConfig(0x40,0x04), "ALL_LOADS..........", L1D_READ_ACCESS }, | ||||||
|     { PERF_TYPE_RAW, RawConfig(0x02,0x04), "L2_HIT_LOADS.......", L1D_READ_ACCESS  }, |   { PERF_TYPE_RAW, RawConfig(0x02,0x04), "L2_HIT_LOADS.......", L1D_READ_ACCESS }, | ||||||
|     { PERF_TYPE_RAW, RawConfig(0x04,0x04), "L2_MISS_LOADS......", L1D_READ_ACCESS  }, |   { PERF_TYPE_RAW, RawConfig(0x04,0x04), "L2_MISS_LOADS......", L1D_READ_ACCESS }, | ||||||
|     { PERF_TYPE_RAW, RawConfig(0x10,0x04), "UTLB_MISS_LOADS....", L1D_READ_ACCESS }, |   { PERF_TYPE_RAW, RawConfig(0x10,0x04), "UTLB_MISS_LOADS....", L1D_READ_ACCESS }, | ||||||
|     { PERF_TYPE_RAW, RawConfig(0x08,0x04), "DTLB_MISS_LOADS....", L1D_READ_ACCESS }, |   { PERF_TYPE_RAW, RawConfig(0x08,0x04), "DTLB_MISS_LOADS....", L1D_READ_ACCESS }, | ||||||
|     // 11
 |   // 11
 | ||||||
| #else | #else | ||||||
|   { PERF_TYPE_HW_CACHE, CacheControl(L1D,READ,ACCESS)     ,  "L1D_READ_ACCESS....",INSTRUCTIONS}, |   { PERF_TYPE_HW_CACHE, CacheControl(L1D,READ,ACCESS)     ,  "L1D_READ_ACCESS....",INSTRUCTIONS}, | ||||||
|   { PERF_TYPE_HW_CACHE, CacheControl(L1D,READ,MISS)       ,  "L1D_READ_MISS......",L1D_READ_ACCESS}, |   { PERF_TYPE_HW_CACHE, CacheControl(L1D,READ,MISS)       ,  "L1D_READ_MISS......",L1D_READ_ACCESS}, | ||||||
| @@ -57,19 +57,20 @@ const PerformanceCounter::PerformanceCounterConfig PerformanceCounter::Performan | |||||||
|   { PERF_TYPE_HW_CACHE, CacheControl(L1D,PREFETCH,MISS)   ,  "L1D_PREFETCH_MISS..",L1D_READ_ACCESS}, |   { PERF_TYPE_HW_CACHE, CacheControl(L1D,PREFETCH,MISS)   ,  "L1D_PREFETCH_MISS..",L1D_READ_ACCESS}, | ||||||
|   { PERF_TYPE_HW_CACHE, CacheControl(L1D,PREFETCH,ACCESS) ,  "L1D_PREFETCH_ACCESS",L1D_READ_ACCESS}, |   { PERF_TYPE_HW_CACHE, CacheControl(L1D,PREFETCH,ACCESS) ,  "L1D_PREFETCH_ACCESS",L1D_READ_ACCESS}, | ||||||
|   { PERF_TYPE_HW_CACHE, CacheControl(L1D,PREFETCH,ACCESS) ,  "L1D_PREFETCH_ACCESS",L1D_READ_ACCESS}, |   { PERF_TYPE_HW_CACHE, CacheControl(L1D,PREFETCH,ACCESS) ,  "L1D_PREFETCH_ACCESS",L1D_READ_ACCESS}, | ||||||
|     // 11
 |    // 11
 | ||||||
| #endif | #endif | ||||||
|   { PERF_TYPE_HW_CACHE, CacheControl(LL,READ,MISS)        ,  "LL_READ_MISS.......",L1D_READ_ACCESS}, |   { PERF_TYPE_HW_CACHE, CacheControl(LL,READ,MISS)        ,  "LL_READ_MISS.......",L1D_READ_ACCESS}, | ||||||
|   { PERF_TYPE_HW_CACHE, CacheControl(LL,READ,ACCESS)      ,  "LL_READ_ACCESS.....",L1D_READ_ACCESS}, |   { PERF_TYPE_HW_CACHE, CacheControl(LL,READ,ACCESS)      ,  "LL_READ_ACCESS.....",L1D_READ_ACCESS}, | ||||||
|   { PERF_TYPE_HW_CACHE, CacheControl(LL,WRITE,MISS)       ,  "LL_WRITE_MISS......",L1D_READ_ACCESS}, |   { PERF_TYPE_HW_CACHE, CacheControl(LL,WRITE,MISS)       ,  "LL_WRITE_MISS......",L1D_READ_ACCESS}, | ||||||
|   { PERF_TYPE_HW_CACHE, CacheControl(LL,WRITE,ACCESS)     ,  "LL_WRITE_ACCESS....",L1D_READ_ACCESS}, |   { PERF_TYPE_HW_CACHE, CacheControl(LL,WRITE,ACCESS)     ,  "LL_WRITE_ACCESS....",L1D_READ_ACCESS}, | ||||||
|     //15
 |   //15
 | ||||||
|   { PERF_TYPE_HW_CACHE, CacheControl(LL,PREFETCH,MISS)    ,  "LL_PREFETCH_MISS...",L1D_READ_ACCESS}, |   { PERF_TYPE_HW_CACHE, CacheControl(LL,PREFETCH,MISS)    ,  "LL_PREFETCH_MISS...",L1D_READ_ACCESS}, | ||||||
|   { PERF_TYPE_HW_CACHE, CacheControl(LL,PREFETCH,ACCESS)  ,  "LL_PREFETCH_ACCESS.",L1D_READ_ACCESS}, |   { PERF_TYPE_HW_CACHE, CacheControl(LL,PREFETCH,ACCESS)  ,  "LL_PREFETCH_ACCESS.",L1D_READ_ACCESS}, | ||||||
|   { PERF_TYPE_HW_CACHE, CacheControl(L1I,READ,MISS)       ,  "L1I_READ_MISS......",INSTRUCTIONS}, |   { PERF_TYPE_HW_CACHE, CacheControl(L1I,READ,MISS)       ,  "L1I_READ_MISS......",INSTRUCTIONS}, | ||||||
|   { PERF_TYPE_HW_CACHE, CacheControl(L1I,READ,ACCESS)     ,  "L1I_READ_ACCESS....",INSTRUCTIONS} |   { PERF_TYPE_HW_CACHE, CacheControl(L1I,READ,ACCESS)     ,  "L1I_READ_ACCESS....",INSTRUCTIONS} | ||||||
|     //19
 |   //19
 | ||||||
|   //  { PERF_TYPE_HARDWARE, PERF_COUNT_HW_STALLED_CYCLES_FRONTEND, "STALL_CYCLES" },
 |   //  { PERF_TYPE_HARDWARE, PERF_COUNT_HW_STALLED_CYCLES_FRONTEND, "STALL_CYCLES" },
 | ||||||
| #endif | #endif | ||||||
| }; | }; | ||||||
| } | NAMESPACE_END(Grid); | ||||||
|  | 
 | ||||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user