mirror of
				https://github.com/paboyle/Grid.git
				synced 2025-10-26 01:29:34 +00:00 
			
		
		
		
	Compare commits
	
		
			2334 Commits
		
	
	
		
			chulwoo-de
			...
			feature/a2
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | 9bfd641b22 | ||
|  | be40aaf751 | ||
|  | e069fd5ed8 | ||
|  | b46d31d4b6 | ||
|  | 7c57cac670 | ||
| 888ebc3cf9 | |||
| 6c031a1b81 | |||
| 02aa4bd762 | |||
| 9aafa8ee60 | |||
| 430b98b354 | |||
| 84189867ef | |||
| 4ab8cfbe2a | |||
| aadd9f4468 | |||
| 8fbb27ce13 | |||
| 21bba95909 | |||
| 6448fe7121 | |||
| 2458a11d1d | |||
| d0ca7c3fe6 | |||
| 57f899d79c | |||
| e881a0c157 | |||
| f411657118 | |||
|  | 7458c6174b | ||
|  | 21b269d0f9 | ||
|  | 083af92ac2 | ||
|  | 2c162577b5 | ||
|  | b1c4e96382 | ||
|  | a55c6f34f3 | ||
|  | beed527ea3 | ||
| eaa633cf69 | |||
| c632455129 | |||
| c012899ed5 | |||
|  | 8bab544c2f | ||
|  | 76fc06a5dc | ||
| 4af6c7e7aa | |||
| f60fbcfc4d | |||
| 464c81706e | |||
| 408130b808 | |||
| 375edd1370 | |||
| 6d912f6c67 | |||
| 6d1d28955e | |||
| 920b471761 | |||
| 63c21767ba | |||
| 7b6b712565 | |||
| 35abd05ee9 | |||
| dd36e60f6a | |||
| cb6c548e21 | |||
| 02c4ccf621 | |||
| fd24588212 | |||
| b800bb3ecb | |||
| f8abd0978b | |||
| 12c7c493bf | |||
|  | c7c9072313 | ||
| 2bf3be5fae | |||
| 3a40e4fc69 | |||
| 2e69e03f6f | |||
| a09f9bb528 | |||
| f0e341d726 | |||
| 6f09df0daf | |||
| 26cee605b8 | |||
| b3fa18c229 | |||
| 2940c9bcfd | |||
| 0bb532f72b | |||
| fada2aa0f7 | |||
| c193e4e675 | |||
| 3ee682f676 | |||
| d85ec3bac2 | |||
| b52d8eb1e3 | |||
| ee630d2e8b | |||
| 2f0af79869 | |||
| 1b7fb79ec0 | |||
| 2db1a4628c | |||
| 6aa047d842 | |||
| 8779c32ae1 | |||
| c527dc3358 | |||
| 6b42577b6b | |||
| fb3596f968 | |||
| f3a0158213 | |||
| 0250aa9347 | |||
| 3df6743396 | |||
| fb7d021b9d | |||
| 5f206df775 | |||
| 7727e81113 | |||
| c4115544a5 | |||
| 08c47328ba | |||
| 09001aedca | |||
| 2c67304716 | |||
| dc6d8686de | |||
| cc2780bea3 | |||
| 6e5a2b7922 | |||
| f4878d3a13 | |||
| 89d2fac92e | |||
| f2d3e41cf2 | |||
| 3c27bb36d4 | |||
| 603d59f389 | |||
| 07a0ef3f95 | |||
| 503259f9c9 | |||
| 5be6a51044 | |||
| ac69f042b1 | |||
| 133d5c2e34 | |||
| 2a94244890 | |||
| a15a2dfd29 | |||
| 093bb02633 | |||
| 99a85116f8 | |||
|  | 27cdb79063 | ||
| f4cbfd63ff | |||
| 2b794b6aa7 | |||
| d0244a059f | |||
| dcdd891d7d | |||
| 6d2df9de79 | |||
| 41d4e37bae | |||
| ee5c0cc9b6 | |||
| 0a4020eb4d | |||
| b2de26589b | |||
| 0677adb4dd | |||
| 231cc95be6 | |||
| 639f9cab82 | |||
| 4eac4e575e | |||
| 3f0f92cda6 | |||
| d2650e89bd | |||
| 2962123cba | |||
| 830168ec37 | |||
| 584c921ca0 | |||
| 81347b4d16 | |||
| 2cfa0b0e6b | |||
|  | fa5dee76b1 | ||
|  | 8d1679c6b8 | ||
|  | 3791a38f7c | ||
|  | 142f7b0c86 | ||
|  | 891ad66eab | ||
|  | 60c43151c5 | ||
|  | e036800261 | ||
|  | 62900def36 | ||
|  | e3a309a73f | ||
|  | ad6c1c0c4e | ||
|  | 00b92a91b5 | ||
|  | 65533741f7 | ||
|  | dc0259fbda | ||
|  | 131a6785d4 | ||
|  | 44f4f5c8e2 | ||
|  | 2679df034f | ||
| bf71162b97 | |||
| 299e828d83 | |||
| ef5452cddf | |||
| 80de748737 | |||
|  | 71e1006ba8 | ||
| 00f31ae83f | |||
| cce339deaf | |||
|  | 24128ff109 | ||
|  | 34e9d3f0ca | ||
|  | c995788259 | ||
|  | 94c7198001 | ||
|  | 04d86fe9f3 | ||
|  | b78074b6a0 | ||
|  | 7dfd3cdae8 | ||
|  | cecee1ef2c | ||
|  | 355d4b58be | ||
|  | 2c54a536f3 | ||
|  | d868a45120 | ||
|  | 9deae8c962 | ||
|  | db86cdd7bd | ||
|  | ec9939c1ba | ||
|  | f74617c124 | ||
|  | 8c6a3921ed | ||
| a8a15dd9d0 | |||
| 3ce68a751a | |||
|  | daa0977d01 | ||
|  | a2929f4384 | ||
|  | 7fe3974c0a | ||
|  | f7e86f81a0 | ||
|  | fecec803d9 | ||
|  | 8fe9a13cdd | ||
| d2c42e6f42 | |||
| 049cc518f4 | |||
| 2e1c66897f | |||
| adcef36189 | |||
|  | 2f121c41c9 | ||
| e0ed7e300f | |||
| 485207901b | |||
| c760f0a4c3 | |||
| c84eeedec3 | |||
|  | 1ac3526f33 | ||
|  | 0de090ee74 | ||
| 91405de3f7 | |||
|  | 8fccda301a | ||
|  | 7a0abfac89 | ||
|  | ae37fda699 | ||
|  | b5fc5e2030 | ||
| 8db0ef9736 | |||
|  | 95d4b46446 | ||
|  | 5dfd216a34 | ||
|  | c2e8d0aa88 | ||
|  | 0fe5aeffbb | ||
|  | 7fbc469046 | ||
|  | bf96a4bdbf | ||
|  | 84685c9bc3 | ||
|  | a8d4156997 | ||
|  | c18074869b | ||
|  | f4c6d39238 | ||
| 200d35b38a | |||
| eb52e84d09 | |||
| 72abc34764 | |||
| e3164d4c7b | |||
|  | f5db386c55 | ||
|  | 294ee70a7a | ||
|  | 013ea4e8d1 | ||
|  | 7fbbb31a50 | ||
|  | 0e127b1fc7 | ||
|  | 68c028b0a6 | ||
| 255d4992e1 | |||
| a0d399e5ce | |||
| fd3b2e945a | |||
| b999984501 | |||
|  | 7836cc2d74 | ||
| a61e0df54b | |||
| 9d835afa35 | |||
| 5e3be47117 | |||
| 48de706dd5 | |||
| f871fb0c6d | |||
| 93771f3099 | |||
| 8cb205725b | |||
| 9ad580d82f | |||
| 899f961d0d | |||
| 54d789204f | |||
| 25828746f3 | |||
| f362c00739 | |||
|  | 25d1cadd3b | ||
|  | c24d53bbd1 | ||
| 2017e4e3b4 | |||
| 27a4d4c951 | |||
| 2f92721249 | |||
| 3c7a4106ed | |||
| 3252059daf | |||
|  | 6eed167f0c | ||
|  | 4ad0df6fde | ||
| 661381e881 | |||
|  | 68a5079f33 | ||
|  | 8634e19f1b | ||
|  | 9ada378e38 | ||
|  | 9d9692d439 | ||
| 0659ae4014 | |||
| bfbf2f1fa0 | |||
| dd6b796a01 | |||
|  | 52a856b4a8 | ||
|  | 04190ee7f3 | ||
|  | 587bfcc0f4 | ||
|  | 2700992ef5 | ||
|  | 8c658de179 | ||
|  | ba37d51ee9 | ||
|  | 4f4181c54a | ||
|  | 4d4ac2517b | ||
|  | e568c24d1d | ||
|  | b458326744 | ||
|  | 6e7d5e2243 | ||
|  | b35169f1dd | ||
|  | 441ad7498d | ||
|  | 6f6c5c549a | ||
|  | 1584e17b54 | ||
|  | 12982a4455 | ||
|  | 172f412102 | ||
|  | a64497265d | ||
| ca639c195f | |||
| edc28dcfbf | |||
|  | c45f24a1b5 | ||
|  | aaf37ee4d7 | ||
|  | 1dddd17e3c | ||
|  | 661f1d3e8e | ||
|  | edcf9b9293 | ||
|  | 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 | ||
| 334da7f452 | |||
| 4669ecd4ba | |||
| 4573b34cac | |||
| 17f57e85d1 | |||
| c8d4d184ee | |||
| 17f27b1ebd | |||
| a16bbecb8a | |||
| 7c9b0dd842 | |||
| 6b7228b3e6 | |||
| f117552334 | |||
| a21a160029 | |||
| 1569a374a9 | |||
| eddf023b8a | |||
| 6b8ffbe735 | |||
| 81050535a5 | |||
| 7dcf5c90e3 | |||
| 9ce00f26f9 | |||
| 85c253ed4a | |||
| ccfc0a5a89 | |||
| d3f857b1c9 | |||
| fb62035aa0 | |||
| 0260bc7705 | |||
| 68e6a58f12 | |||
| 640515e3d8 | |||
|  | f089bf5629 | ||
|  | 276f113f28 | ||
| 97c579f637 | |||
| a13c109111 | |||
|  | ab6afd18ac | ||
|  | 5bde64d48b | ||
|  | 2f5add4d5f | ||
| c5a885dcd6 | |||
| a4d8512fb8 | |||
| 5ec903044d | |||
| 8a0cf0194f | |||
| 1c680d4b7a | |||
|  | c9c073eee4 | ||
|  | f290b2e908 | ||
|  | 5f8225461b | ||
| e9323460c7 | |||
| 20e186a1e0 | |||
|  | 6ef4af989b | ||
|  | ccde8b817f | ||
|  | 68168bf72d | ||
|  | e93d0feaa7 | ||
|  | 8f601d9b39 | ||
|  | 5436308e4a | ||
|  | 07fe7d0cbe | ||
|  | 60b57706c4 | ||
|  | 58c2f60b69 | ||
|  | bfa3a7b3b0 | ||
|  | 954e38bebe | ||
|  | b1a38bde7a | ||
|  | 2581875edc | ||
|  | f212b0a963 | ||
|  | 62702dbcb8 | ||
| 41d6cab033 | |||
| 5a31e747c9 | |||
| cbc73a3fd1 | |||
|  | 6c6d43eb4e | ||
|  | e1dcfd3553 | ||
|  | 888838473a | ||
|  | 01568b0e62 | ||
|  | d5ce66f6ab | ||
|  | d86936a3de | ||
| d516938707 | |||
| 72344d1418 | |||
| 7ecf6ab38b | |||
| 2d4d70d3ec | |||
| 78f8d47528 | |||
| b85f987b0b | |||
| f57afe2079 | |||
|  | 0fb84fa34b | ||
|  | 8462bbfe63 | ||
| 229977c955 | |||
| e485a07133 | |||
|  | 0880747edb | ||
|  | b801e1fcd6 | ||
| 70ec2faa98 | |||
| 2f849ee252 | |||
| bb6ed44339 | |||
| 360cface33 | |||
|  | 80302e95a8 | ||
| caf2f6b274 | |||
| c49be8988b | |||
| 971c2379bd | |||
|  | 94b0d66e4c | ||
|  | 5e8af396fd | ||
| 9942723189 | |||
| a7d19dbb64 | |||
| 90dbe03e17 | |||
| 8b14096990 | |||
|  | b938202081 | ||
| e79ef469ac | |||
| 485c5db0fe | |||
|  | c793947209 | ||
| 3e9ee053a1 | |||
| dda6c69d5b | |||
| cd51b9af99 | |||
|  | c399c2b44d | ||
|  | af7de7a294 | ||
|  | 1dc86efd26 | ||
| 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 | |||
|  | ec3954ff5f | ||
|  | 0f468e2179 | ||
|  | 8e61286741 | ||
|  | 4790e99817 | ||
|  | 2dd63aa7a4 | ||
|  | 559a501140 | ||
|  | 945684c470 | ||
|  | e30a80a234 | ||
|  | 69e4ecc1d2 | ||
|  | 5f483df16b | ||
|  | 4680a977c3 | ||
|  | de42456171 | ||
|  | d55212c998 | ||
|  | c96483e3bd | ||
|  | c6e1f64573 | ||
|  | ae31a6a760 | ||
|  | dd8f2a64fe | ||
|  | 724cf02d4a | ||
|  | 7b8b2731e7 | ||
|  | 237a8ec918 | ||
|  | 49a0ae73eb | ||
|  | 315f1146cd | ||
|  | 9f202782c5 | ||
|  | 594a262dcc | ||
|  | 7f8ca54285 | ||
|  | c5b23c367e | ||
|  | b6fe03eb26 | ||
|  | f37ed4958b | ||
|  | 896f3a8002 | ||
|  | 5f85473d6b | ||
|  | ac3b0ebc58 | ||
|  | f0fcdf75b5 | ||
|  | 53bffb83d4 | ||
|  | cd44e851f1 | ||
|  | fb24e3a7d2 | ||
|  | 655a69259a | ||
|  | 4e0cf0cc28 | ||
|  | 507c4e9efc | ||
|  | cdf550845f | ||
|  | 3db7a5387b | ||
|  | f8a5194c70 | ||
|  | cff3bae155 | ||
|  | 90dffc73c8 | ||
| a1151fc734 | |||
|  | ab3baeb38f | ||
|  | 389731d373 | ||
| 6e3ce7423e | |||
| 15f15a7cfd | |||
| 0e5f626226 | |||
|  | 97b9c6f03d | ||
|  | 63982819c6 | ||
|  | 6fec507bef | ||
|  | 219b3bd34f | ||
|  | b00d2d2c39 | ||
|  | f1b3e21830 | ||
|  | b7f8c5b823 | ||
|  | 3923683e9b | ||
|  | e199fda9dc | ||
| 7bb405e790 | |||
| ec16eacc6a | |||
|  | cf858deb16 | ||
|  | a3affac963 | ||
| d9d1f43ba2 | |||
| b7cd721308 | |||
| 29f026c375 | |||
| 58c7a13d54 | |||
|  | 24162c9ead | ||
|  | e564d11687 | ||
|  | 0b2162f375 | ||
|  | 5610570182 | ||
|  | 44f65526e0 | ||
|  | 43e48542ab | ||
|  | 0b85f1bfc8 | ||
|  | 9947cfbf14 | ||
|  | 357badce5e | ||
|  | 0091eec23a | ||
|  | 9e9c2962df | ||
|  | bda97212a9 | ||
|  | b91282ad46 | ||
|  | 0a68470f9a | ||
|  | 6ecf280723 | ||
|  | 7eeab7f995 | ||
|  | 9b32d51cd1 | ||
|  | 7b3ed160aa | ||
|  | 1a0163f45c | ||
|  | 9028e278e4 | ||
| dd62f2f371 | |||
| 0d612039ed | |||
| e8ac75055c | |||
| 8b30c5956c | |||
| 185da83454 | |||
| 6718fa8c4f | |||
|  | 4ce63af7d5 | ||
|  | 935cd1e173 | ||
|  | 55e39df30f | ||
| 67c3fa0f5f | |||
| 65d4f17976 | |||
| e2fe97277b | |||
|  | 84f9c37ed4 | ||
| bcf6f3890c | |||
| 591a38c487 | |||
|  | 581be32ed2 | ||
| 842754bea9 | |||
|  | 6bc136b1d0 | ||
| 0887566134 | |||
| 61fc50d616 | |||
| a9c8d7dad0 | |||
| 259d504ef0 | |||
| f3a77f4b7f | |||
| 26d7b829a0 | |||
| 64161a8743 | |||
| 2401360784 | |||
|  | 2cfb50cbe5 | ||
| f9aa39e1c4 | |||
| 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 | |||
|  | 28ceacec45 | ||
|  | e6a3e375cf | ||
|  | 4987edbd44 | ||
|  | ad140bb6e7 | ||
|  | 1f04e56038 | ||
|  | 4bfc8c85c3 | ||
|  | e55397bc13 | ||
| a3fe874a5b | |||
| f403ab0133 | |||
|  | 94b8fb5686 | ||
|  | 1f1d77b01a | ||
|  | 6a15e2e8ef | ||
| 074d17429f | |||
|  | 25f73018f4 | ||
|  | 1d7ccc6b2c | ||
|  | 59d9ccf70c | ||
|  | 1860b1698c | ||
|  | 9b8d1cc3da | ||
|  | 0c668bf46a | ||
|  | 149c3f9e9c | ||
|  | c519aab19d | ||
|  | 69929f20bb | ||
|  | 840814c776 | ||
|  | a493429218 | ||
|  | 915f610da0 | ||
|  | c79606a5dc | ||
|  | 95af55128e | ||
|  | 9f2a57e334 | ||
|  | c645d33db5 | ||
|  | e0f1349524 | ||
|  | 360efd0088 | ||
|  | 7b42ac9982 | ||
|  | c5c647e35e | ||
| a4e5fd1000 | |||
| 682e7d7839 | |||
|  | 8e057721a9 | ||
|  | fa5e4add47 | ||
|  | 79b761f923 | ||
|  | 0d4e31ca58 | ||
|  | b07a354a33 | ||
|  | 27ea2afe86 | ||
|  | 78e8704eac | ||
|  | 67131d82f2 | ||
|  | 615a9448b9 | ||
|  | 00164f5ce5 | ||
|  | a7f72eb994 | ||
|  | 501fa1614a | ||
|  | 5bf42e1e15 | ||
|  | fe4d9b003c | ||
|  | 4a699b4da3 | ||
|  | 689323f4ee | ||
|  | 749189fd72 | ||
|  | f941c4ee18 | ||
|  | 84b441800f | ||
|  | 1ef424b139 | ||
|  | 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 | ||
|  | cac1750078 | ||
|  | e17cd35151 | ||
|  | ccdec7a7ab | ||
|  | 93642d813d | ||
|  | 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 | ||
|  | 5592f7b8c1 | ||
|  | 35da4ece0b | ||
|  | 061b15b9e9 | ||
|  | ca6efc685e | ||
| 1e496fee74 | |||
| ff4e54ef80 | |||
|  | 561426f6eb | ||
|  | 83f6fab8fa | ||
|  | 0fade84ab2 | ||
|  | 9dc7ca4c3b | ||
|  | 935d82f5b1 | ||
|  | 9cbcdd65d7 | ||
|  | f18f5ed926 | ||
|  | d1d63a4f2d | ||
|  | 7e5faa0f34 | ||
|  | 6af459cae4 | ||
|  | 1c4bc7ed38 | ||
|  | cd1bd921bd | ||
|  | b8ae787b5e | ||
|  | fbe2c3b5f9 | ||
|  | 1ed69816b9 | ||
|  | fff5751b1a | ||
|  | 2c81696fdd | ||
|  | c9dc22efa1 | ||
|  | 0ab04a000f | ||
|  | 93ea5d9468 | ||
|  | 1ec5d32369 | ||
|  | 9fd23faadf | ||
|  | 10e4fa0dc8 | ||
|  | c4aca1dde4 | ||
|  | b9e8ea3aaa | ||
|  | 077aa728b9 | ||
|  | a8d83d886e | ||
|  | 7fd46eeec4 | ||
|  | e0c4eeb3ec | ||
|  | cb9a297a0a | ||
|  | 2b115929dc | ||
|  | 5c6571dab1 | ||
|  | 417ec56cca | ||
|  | 756bc25008 | ||
|  | 35695ba57a | ||
|  | 81ead48850 | ||
|  | d805867e02 | ||
|  | e55a751e23 | ||
|  | 358eb75995 | ||
|  | 98f9318279 | ||
|  | 4b17e8eba8 | ||
|  | 75112a632a | ||
|  | 18bde08d1b | ||
|  | 9f755e0379 | ||
|  | 4512dbdf58 | ||
|  | 483fd3cfa1 | ||
|  | 3750b9ffee | ||
|  | 5e549ebd8b | ||
|  | fff484eca5 | ||
|  | 5fdc05782b | ||
|  | d45cd7e677 | ||
|  | 4e96679797 | ||
|  | 85516e9c7c | ||
|  | 0c006fbfaa | ||
|  | 54c10a42cc | ||
|  | a04eb7df5d | ||
|  | 4c1ea8677e | ||
|  | fc93f0b2ec | ||
|  | 8c8473998d | ||
|  | ef0fe2bcc1 | ||
|  | 120fb59978 | ||
|  | fd56b3ff38 | ||
|  | 0ec6829edc | ||
|  | 18b7845b7b | ||
|  | 3d0fe15374 | ||
|  | 91886068fe | ||
|  | 6d1e9e5f92 | ||
|  | b640230b1e | ||
|  | e7c36771ed | ||
|  | 038b6ee9cd | ||
|  | 38806343a8 | ||
|  | 831ca4e3bf | ||
|  | 8dc57a1e25 | ||
|  | f57bd770b0 | ||
|  | 4ed10a3d06 | ||
|  | dfefc70b57 | ||
|  | 0b61f75c9e | ||
|  | 33edde245d | ||
|  | b64e004555 | ||
|  | 447c5e6cd7 | ||
|  | 8b99d80d8c | ||
|  | b3dede4dd3 | ||
|  | 4e34132f4d | ||
|  | c07cb10247 | ||
|  | d7767a2a62 | ||
|  | ec035983fd | ||
|  | 3901b17ade | ||
|  | af230a1fb8 | ||
|  | 06a132e3f9 | ||
|  | 596dcd85b2 | ||
|  | 96d44d5c55 | ||
|  | 7270c6a150 | ||
|  | 7fe797daf8 | ||
|  | 486a01294a | ||
|  | 586a7c90b7 | ||
|  | e099dcdae7 | ||
|  | 4e7ab3166f | ||
|  | aac80cbb44 | ||
|  | c80948411b | ||
|  | 95625a7bd1 | ||
|  | 0796696733 | ||
|  | f8b9ad7d50 | ||
|  | 04a1959895 | ||
|  | cc773ae70c | ||
|  | d21c51b9be | ||
|  | 597a7b4b3a | ||
|  | 1c30e9a961 | ||
|  | 93cc270016 | ||
|  | 29b60f7e1a | ||
|  | 041884acf0 | ||
|  | 15e668eef1 | ||
|  | bf7e3f20d4 | ||
|  | 902afcfbaf | ||
|  | 3ae92fa2e6 | ||
|  | 3906cd2149 | ||
|  | 5a1fb29db7 | ||
|  | 661fc4d3d1 | ||
|  | 41009cc142 | ||
|  | 37720c4db7 | ||
|  | 1a30455a10 | ||
|  | 97a6b61551 | ||
|  | cd0da81196 | ||
|  | f246fe3304 | ||
|  | 8a29c16bde | ||
|  | d68907fc3e | ||
|  | 5c0adf7bf2 | ||
|  | be3a8249c6 | ||
|  | bd600702cf | ||
|  | f011bdb869 | ||
|  | bafb101e4f | ||
|  | 08fdf05528 | ||
|  | aca7a3ef0a | ||
|  | 9e72a6b22e | ||
|  | 1c12c5612c | ||
|  | a8193c4bcb | ||
|  | c3d7ec65fa | ||
|  | 8b6a6c8236 | ||
|  | e0571c872b | ||
|  | c67f41887b | ||
|  | 84687ccf1f | ||
|  | 3274561cf8 | ||
| e08fbb3771 | |||
|  | d7464aa0fe | ||
|  | 00d29153f0 | ||
| 2ce989f220 | |||
|  | d7a1dc85be | ||
|  | fc19503673 | ||
|  | beba824136 | ||
|  | 6ebf8b12b6 | ||
|  | e5a7ed4362 | ||
|  | b9f7ea47c3 | ||
|  | 06f7ee202e | ||
|  | 2b2fc6453f | ||
|  | bdd2765461 | ||
|  | 2c246551d0 | ||
|  | 71ac2e7940 | ||
|  | 2bf4688e83 | ||
|  | a48ee6f0f2 | ||
|  | 73547cca66 | ||
|  | 123c673db7 | ||
|  | 61f82216e2 | ||
|  | 8e7ca92278 | ||
|  | 485ad6fde0 | ||
|  | 6ea2184e18 | ||
|  | fdc170b8a3 | ||
|  | 060da786e9 | ||
|  | 85c7bc4321 | ||
|  | 0883d6a7ce | ||
|  | 9ff97b4711 | ||
|  | b5e9c900a4 | ||
|  | 4bbdfb434c | ||
|  | 4a45c06dd7 | ||
|  | d6a7d7d1e0 | ||
|  | 1a122a0dd8 | ||
|  | 20e20733e8 | ||
|  | b7cd1a19e3 | ||
|  | f510002a62 | ||
|  | c94133af49 | ||
| eedcaf6470 | |||
| e7d8030a64 | |||
| d775fbb2f9 | |||
| 863855f46f | |||
| 419af7610d | |||
|  | 1e257a1251 | ||
|  | 522f6bf91a | ||
|  | d35d87d2c2 | ||
|  | 74a5cda84b | ||
|  | 5be05d85b8 | ||
|  | 35ac85aea8 | ||
|  | fa237401ff | ||
|  | 97053adcb5 | ||
|  | f8fbe4d7a3 | ||
|  | ef31c012bf | ||
| 7da7d263c4 | |||
| 1140573027 | |||
|  | 9e9f621d5d | ||
|  | 651e1a7cbc | ||
| a0cfbb6e88 | |||
|  | c4d3672720 | ||
| 515a26b3c6 | |||
|  | 16be6d378c | ||
|  | f05d0565aa | ||
| b39f0d1fb6 | |||
| 9f1267dfe6 | |||
| 2e90285232 | |||
| e254de982e | |||
| 28d99b5297 | |||
| c946d3bf3f | |||
| 1c68098780 | |||
|  | 9bf4108d1f | ||
|  | 899e685627 | ||
|  | ee93f0218b | ||
|  | 6929a84c70 | ||
|  | 5c779a789b | ||
| 161ed102a5 | |||
| 3bf993d81a | |||
| fad743fbb1 | |||
|  | e863a948e3 | ||
|  | f65a585236 | ||
|  | 977f34dca6 | ||
|  | 90ad956340 | ||
|  | 7996f06335 | ||
|  | ef8d3831eb | ||
|  | 70ed9fc40c | ||
|  | 7b40a3e3e5 | ||
| 4d3787db65 | |||
|  | 677757cfeb | ||
|  | f7fbbaaca3 | ||
|  | 17629b8d9e | ||
|  | 0baa20d292 | ||
|  | 4571c918a4 | ||
|  | 5251ea4d30 | ||
| 05cb6d318a | |||
| 0432e30256 | |||
| 2c3ebc1e07 | |||
| 068b28af2d | |||
| f7db342f49 | |||
| d65e81518f | |||
|  | 7f456b4173 | ||
| a37e71f362 | |||
|  | ae99e99da2 | ||
|  | c291ef77b5 | ||
|  | 7dd2764bb2 | ||
|  | 244f8fb6dc | ||
|  | 05c1924819 | ||
| f3ca29af6c | |||
| b7da264b0a | |||
| 37988221a8 | |||
| 74ac2aa676 | |||
| 4c75095c61 | |||
| afa095d33d | |||
| 6b5259cc10 | |||
|  | 27dfe816fa | ||
|  | af29be2c90 | ||
|  | f96fac0aee | ||
| 7423a352c5 | |||
| 81e66d6631 | |||
| ade1058e5f | |||
| 6eea9e4da7 | |||
| 2c673666da | |||
| 7a327a3f28 | |||
|  | 07f2ebea1b | ||
| d6401e6d2c | |||
| 24d3d31b01 | |||
|  | 851f2ad8ef | ||
| 5405526424 | |||
| f3f0b6fef9 | |||
| 654e0b0fd0 | |||
| 4be08ebccc | |||
| f599cb5b17 | |||
|  | 23e0561dd6 | ||
| a4a509497a | |||
| 5803933aea | |||
|  | 8ae1a95ec6 | ||
|  | 82b7d4eaf0 | ||
|  | 78774fbdc0 | ||
|  | 924130833e | ||
|  | 7cf833dfe9 | ||
|  | 0157274762 | ||
|  | 87e8aad5a0 | ||
|  | c6f59c2933 | ||
| 91a3534054 | |||
| 16a8e3d0d4 | |||
|  | b7f90aa011 | ||
| 92f8950a56 | |||
| 65987a8a58 | |||
| 889d828bc2 | |||
|  | f22b79da8f | ||
|  | 3855673ebf | ||
|  | 4db82da0db | ||
|  | 0cdc3d2fa5 | ||
| ad98b6193d | |||
| fc760016b3 | |||
| 2da86f7dae | |||
| 41df1db811 | |||
|  | 0dfda4bb90 | ||
|  | 1189ebc8b5 | ||
| 97843e2b58 | |||
| 82b3f54697 | |||
|  | 1bb8578173 | ||
|  | c3b6d573b9 | ||
| 673994b281 | |||
| bbc0eff078 | |||
| 4c60e31070 | |||
| afbf7d4c37 | |||
| 8c3cc32364 | |||
|  | 1e179c903d | ||
|  | 669cfca9b7 | ||
|  | ff2f559a57 | ||
|  | 03c81bd902 | ||
|  | a869addef1 | ||
|  | 1caa3fbc2d | ||
|  | 3d21297bbb | ||
|  | 25efefc5b4 | ||
|  | eabf316ed9 | ||
|  | 04ae7929a3 | ||
|  | caba0d42a5 | ||
|  | 9ae81c06d2 | ||
|  | 0903c48caa | ||
|  | 7dc36628a1 | ||
|  | b8cdb3e90a | ||
|  | 5241245534 | ||
|  | 960316e207 | ||
|  | 5214846341 | ||
| 4c3fd9fa3f | |||
| 17b3a10d46 | |||
| 149a46b92c | |||
| 3215ae6b7e | |||
| 7a85fddc7e | |||
|  | ce1a115e0b | ||
| db9c28a773 | |||
| 9ac3ac41df | |||
| 2af9ab9034 | |||
| 6f1ea96293 | |||
| f8d11ff673 | |||
|  | 3f2d53a994 | ||
|  | 8a337f3070 | ||
|  | a59f5374d7 | ||
|  | 4b220972ac | ||
|  | 629f43e36c | ||
|  | a3172b3455 | ||
|  | 3e6945cd65 | ||
|  | 87be03006a | ||
|  | f17436fec2 | ||
|  | 4d8b01b7ed | ||
|  | fa6acccf55 | ||
|  | 55cb22ad67 | ||
|  | df9108154d | ||
|  | b3e7f600da | ||
|  | d4071daf2a | ||
|  | a2a6329094 | ||
|  | eabc577940 | ||
| 2e3c5890b6 | |||
| bc6678732f | |||
| b10ae00c8a | |||
| 67d72000e7 | |||
| 80cef1c78f | |||
| 91e98b1dd5 | |||
| b791c274b0 | |||
| 596dd570c7 | |||
| cad158e42f | |||
| f63fac0c69 | |||
| ab92de89ab | |||
| 846272b037 | |||
| f3e49e4b73 | |||
| decbb61ec1 | |||
| 7e2482aad1 | |||
| e1653a9f94 | |||
| ea40854e0b | |||
| 34df71e755 | |||
| 3af663e17b | |||
|  | 0cd6b1858c | ||
|  | 0bd296dda4 | ||
|  | af0ccdd8e9 | ||
| c22c3db9ad | |||
| 013e710c7d | |||
| 16693bd69d | |||
| de8f80cf94 | |||
|  | 2fb92dbc6e | ||
|  | 5c74b6028b | ||
|  | e0be2b6e6c | ||
|  | ef72f322d2 | ||
|  | 426197e446 | ||
|  | 99e2c1e666 | ||
|  | 1440565a10 | ||
|  | e9f0c0ea39 | ||
|  | 7bc2065113 | ||
| 4a87486365 | |||
|  | fe187e9ed3 | ||
|  | 0091b50f49 | ||
|  | fb8d4b2357 | ||
|  | ff71a8e847 | ||
|  | 83fa038bdf | ||
|  | 7a61feb6d3 | ||
|  | 69ae817d1c | ||
|  | 2bd4233919 | ||
|  | 143c70e29f | ||
| 51322da6f8 | |||
| 49c3eeb378 | |||
| c56707e003 | |||
|  | b812d5e39c | ||
| 5b3edf08a4 | |||
| bd1d1cca34 | |||
| 646b11f5c2 | |||
| a683a0f55a | |||
| e6effcfd95 | |||
| aa016f61b9 | |||
| d42a1b73c4 | |||
| d292657ef7 | |||
| d1f7c6b94e | |||
| 7ae734103e | |||
|  | 01480da0a8 | ||
| 7a1ac45679 | |||
| 320268fe93 | |||
| dd6fb140c5 | |||
| 0b4f680d28 | |||
| a69086ba1f | |||
| 7433eed274 | |||
| ee5b1fe043 | |||
| 1540616b22 | |||
| 8190523e4c | |||
| b5555d85a7 | |||
|  | e27c6b217c | ||
| 9ad3d3453e | |||
|  | f7a6b8e5ed | ||
|  | 6adf35da54 | ||
| d8b716d2cd | |||
|  | cd01c1dbe9 | ||
|  | 6ad73145bc | ||
|  | bd0430b34f | ||
|  | c097fd041a | ||
|  | 77fb25fb29 | ||
|  | 389e0a77bd | ||
|  | 2f92b4860b | ||
|  | 4704f2d009 | ||
|  | ae9688e343 | ||
| 43928846f2 | |||
| fabcd4179d | |||
| a8843c9af6 | |||
| 7a1a7a685e | |||
|  | 1e44fd3094 | ||
|  | d8258f0758 | ||
|  | 6c0cc5676b | ||
| f7293f2ddb | |||
| 11dc0b398b | |||
|  | b18950f776 | ||
|  | 0acbf77bc6 | ||
| 3cdf945d84 | |||
| 5833f247fa | |||
|  | 95f43d27ae | ||
|  | 668ca57702 | ||
| a2cffb0304 | |||
| bafbac6ac4 | |||
| 595f1ce371 | |||
| 6d7cde4eb4 | |||
| 97cddda49e | |||
| 433afd36f5 | |||
| b873504b90 | |||
|  | 62749d05a6 | ||
|  | 3834feb4b7 | ||
|  | 6b8ee7bae0 | ||
|  | 739c2308b5 | ||
|  | 454302414d | ||
| 042ae5b87c | |||
|  | a71b69389b | ||
|  | d49e502f53 | ||
|  | 92ec3404f8 | ||
|  | f4ebea3381 | ||
|  | cf167d0cd1 | ||
|  | 6f8b771a37 | ||
|  | 4e1ffdd17c | ||
| 1aa695cd78 | |||
|  | a783282b8b | ||
|  | 19b85d8486 | ||
|  | 58f4950652 | ||
|  | c363bdd784 | ||
|  | 604f0ea2f6 | ||
|  | 42c912f608 | ||
|  | 33dc1f51b5 | ||
|  | c30d96ea50 | ||
| 13a8997789 | |||
| 9576f0903d | |||
| 34cf702b24 | |||
| 8a5e3a917c | |||
| 65bcf281d0 | |||
| cd0be8cb24 | |||
| 3d2a22a14d | |||
|  | 7ffe17ada1 | ||
| a26adfb090 | |||
| f6e1a5b348 | |||
| c5a025d421 | |||
|  | 50d277d8d9 | ||
|  | 343f3e829f | ||
|  | f85b35314d | ||
|  | 3dc2e05d6e | ||
|  | 0cff8754d1 | ||
|  | afc8d3e524 | ||
|  | 692b44dac1 | ||
|  | 96ba42a297 | ||
| 7df940dc3e | |||
|  | f7b60004f3 | ||
| 8af8b047fd | |||
| 6592078fef | |||
| ad971ca07b | |||
| f2f16eb972 | |||
|  | b7d55f7dfb | ||
|  | 6e548a8ad5 | ||
|  | ee686a7d85 | ||
|  | 1c5b7a6be5 | ||
| a5dd4a9bab | |||
| ec232af851 | |||
| 17e30281e9 | |||
| 2854e601e6 | |||
| aee44dc694 | |||
| 75bbf6a0af | |||
| c65d23935a | |||
| 92cd797636 | |||
|  | 111bfbc6bc | ||
|  | f41a230b32 | ||
|  | c067051d5f | ||
|  | afdeb2b13c | ||
|  | 9e2ec2719b | ||
|  | 757a928f9a | ||
|  | bc248b6948 | ||
|  | ae8561892e | ||
|  | 32375aca65 | ||
|  | bb94ddd0eb | ||
| 330a9b3f4c | |||
| c2d78493c8 | |||
|  | 28ff66a381 | ||
|  | 78c7bcee36 | ||
|  | 7f0fc0eff5 | ||
|  | 164d3691db | ||
|  | 791cb050c8 | ||
| 00a7b95631 | |||
| 94d8321d01 | |||
| d5e95bc350 | |||
| 6efac3a252 | |||
| 7a84906b5f | |||
| 07416e4567 | |||
| 66d832c733 | |||
| e74417ca12 | |||
| 7bd0084b5d | |||
|  | e8c3174ae2 | ||
|  | 9b066e94d0 | ||
|  | ac24cc9f99 | ||
|  | 618abdf302 | ||
|  | e1042aef77 | ||
|  | aa6a839c60 | ||
| ac99a56237 | |||
| b4d2af8c89 | |||
| 434af6aeaa | |||
| e90f8ac841 | |||
| a1705a8d53 | |||
| ca21003f01 | |||
| 14ddf2c234 | |||
|  | 1d666771f9 | ||
|  | d50055cd96 | ||
|  | bca861e112 | ||
|  | 3ab4c8c0bb | ||
| 33d199a0ad | |||
|  | 93896ce59e | ||
|  | b1508e4124 | ||
|  | b820076b91 | ||
|  | 09f66100d3 | ||
|  | d7d92af09d | ||
|  | 460d0753a1 | ||
|  | 8f8058f8a5 | ||
|  | d97a27f483 | ||
|  | 7c3363b91e | ||
|  | b94478fa51 | ||
|  | 47c7159177 | ||
| 13bf0482e3 | |||
| a795b5705e | |||
| 392e064513 | |||
|  | b6a65059a2 | ||
|  | f415db583a | ||
|  | f55c16f984 | ||
|  | ea25a4d9ac | ||
|  | c190221fd3 | ||
|  | df67e013ca | ||
|  | 3e990c9d0a | ||
|  | 4b740fc8fd | ||
|  | 0fcd2e7188 | ||
|  | 910b8dd6a1 | ||
|  | 75ebd3a0d1 | ||
|  | cccd14b09e | ||
|  | e6acffdfc2 | ||
| 26d124283e | |||
| 0d889b7041 | |||
| 7c8f79b147 | |||
|  | 09fd5c43a7 | ||
| ab31ad006a | |||
| 462921e549 | |||
|  | 392130a537 | ||
|  | f22317748f | ||
|  | 6a9eae6b6b | ||
|  | fad96cf250 | ||
|  | f331809c27 | ||
| bd6a228af6 | |||
| 63d219498b | |||
|  | 2c54a53d0a | ||
|  | 306160ad9a | ||
|  | 20a091c3ed | ||
|  | 202078eb1b | ||
|  | a762b1fb71 | ||
|  | deef2673b2 | ||
|  | 5b5925b8e5 | ||
|  | 977b0a6dd9 | ||
|  | 977d844394 | ||
|  | b58adc6a4b | ||
|  | f9d5e95d72 | ||
|  | 4f8e636a43 | ||
|  | 9b39f35ae6 | ||
|  | 5fe2b85cbd | ||
|  | c7cccaaa69 | ||
|  | cbcfea466f | ||
|  | 4955672fc3 | ||
|  | 39f1c880b8 | ||
|  | 8c043da5b7 | ||
|  | 3cbe974eb4 | ||
| 6e4a06e180 | |||
| 997fd882ff | |||
|  | 590675e2ca | ||
|  | 8c65bdf6d3 | ||
|  | 74f1ed3bc5 | ||
|  | 7af9b87318 | ||
|  | 811ca45473 | ||
|  | bc1a4d40ba | ||
|  | 79270ef510 | ||
|  | e250e6b7bb | ||
|  | c8079e6621 | ||
|  | 261342c15f | ||
|  | 8b0d171c9a | ||
|  | 1f293b76b4 | ||
|  | 8bbd9ebc27 | ||
|  | 6472b431f0 | ||
|  | bd205a3293 | ||
|  | 496beffa88 | ||
|  | 9b63e97108 | ||
|  | 81f2aeaece | ||
|  | 2d4a45c758 | ||
|  | a123dcd7e9 | ||
|  | 6b27c42dfe | ||
|  | f7c2aa3ba5 | ||
|  | 0f182f033b | ||
|  | 7240d73184 | ||
|  | 42cd148f5e | ||
|  | eda4dd622e | ||
|  | 6e01264bb7 | ||
|  | 6f408256bc | ||
|  | 8d11681aac | ||
|  | 3d5c9a1ee9 | ||
|  | db749f103f | ||
|  | dc389e467c | ||
|  | 3619167d62 | ||
|  | 96f1d1b828 | ||
|  | 657e0a8f4d | ||
|  | 616e7cd83e | ||
|  | 6f26d2e8d4 | ||
|  | c014574504 | ||
|  | d7ce164e6e | ||
|  | c0d5b99016 | ||
|  | 09ca32d678 | ||
|  | 082ae350c6 | ||
|  | 611b5d74ba | ||
|  | b56c9ffa52 | ||
|  | c68a2b9637 | ||
|  | 293df6cd20 | ||
|  | 65f61bb3bf | ||
|  | 26b9740d53 | ||
| cb02b7088f | |||
| 70c32fa49b | |||
| 77c8a94dae | |||
|  | 6eb873dd96 | ||
|  | 11b4c80b27 | ||
|  | 2e453dfbf5 | ||
|  | c065e454c3 | ||
|  | 4089984431 | ||
| 98439847cf | |||
|  | c78bbd0f8c | ||
|  | d9b5fbd374 | ||
|  | cfbc1a26b8 | ||
|  | 257f69f931 | ||
|  | e415260961 | ||
| 7ea4b959a4 | |||
| 536e2ff073 | |||
| 798ff34d7e | |||
|  | 87acd06990 | ||
|  | 9353b6edfe | ||
|  | 167cc2650e | ||
|  | 34f887ca1c | ||
|  | 7089b6d5a5 | ||
|  | 2ba7d43ddd | ||
|  | 836e929565 | ||
|  | b6713ecb60 | ||
|  | 52a39f0fcd | ||
|  | 81a7a03076 | ||
|  | 16b37b956c | ||
|  | 567b6cf23f | ||
|  | 296396646d | ||
|  | 04a437c92c | ||
|  | 5c190a1b8c | ||
|  | 15d8f5c88c | ||
|  | c4ac6e7e8f | ||
|  | 510e340e16 | ||
|  | 6ffadca153 | ||
|  | b6597b74e7 | ||
| a034e9901b | |||
| d2573189d8 | |||
| 65ca174dbb | |||
|  | 0724f7af75 | ||
| 2e74520821 | |||
|  | 6dd75ad9e5 | ||
|  | fda408ee6f | ||
|  | b9c80318a2 | ||
|  | 5df5d52d41 | ||
|  | f76f281e58 | ||
|  | aa20cc8b52 | ||
|  | 0fd179fb33 | ||
|  | f45ef8d114 | ||
|  | 7422953e36 | ||
|  | 8535d433a7 | ||
|  | b573d1f35a | ||
|  | 0c1d7e4daf | ||
|  | 02e983a0cd | ||
|  | d15ab66aae | ||
|  | 9005b82c6d | ||
|  | 3475f45ce7 | ||
|  | 0744f38866 | ||
|  | 62febd2823 | ||
|  | fd5614738d | ||
|  | 005dcc51aa | ||
|  | 655c893f86 | ||
|  | 843f5783b4 | ||
|  | 8986c9fedd | ||
|  | c80a1d427c | ||
|  | ae57032500 | ||
|  | f75468728f | ||
|  | 5acd856663 | ||
|  | b0d3e4bb2c | ||
|  | b512ccbee6 | ||
|  | 8c89391c02 | ||
|  | bfac5195b8 | ||
|  | a782ca3238 | ||
|  | 744691097f | ||
|  | ff6da364e8 | ||
| 4d11a6f5f2 | |||
|  | 88be3b39bb | ||
|  | 8a02824e08 | ||
|  | 356e7940fd | ||
|  | 73ce476890 | ||
|  | 29c4ef41de | ||
|  | e423a09974 | ||
|  | 17097a93ec | ||
|  | 94a6373a7f | ||
|  | 4ab7dbfd57 | ||
|  | 90e70790f3 | ||
|  | 9c2e8d5e28 | ||
|  | 147e2025b9 | ||
| 573b8c6020 | |||
| 15218ec57f | |||
| ec68e08dd2 | |||
|  | fc25d2295c | ||
|  | 8dc2cfcedb | ||
| 17c843700e | |||
| 7b56f63a5c | |||
| b1cfb4d661 | |||
| 836f93780c | |||
|  | 5a68715be3 | ||
|  | 32bc7a6ab8 | ||
| b65e72e521 | |||
| d1aaff65e8 | |||
| 7ff7c7d90d | |||
| 93d29bb699 | |||
| a2e9430abe | |||
| 2485ef9c9c | |||
| 3b376ed54e | |||
| d5c1f614ba | |||
| 2edc24225d | |||
| 629283726b | |||
| 6adb66dd08 | |||
| 5be92bb708 | |||
| f4c049ea6d | |||
| bc092ad30f | |||
| dad642ed1b | |||
| 63ae39abc7 | |||
| 9e5b934d21 | |||
| a7b483d67a | |||
| bb99ce0680 | |||
| 83307df1af | |||
|  | 49b5c49851 | ||
| e9f30cab2c | |||
|  | 089f0ab582 | ||
|  | df6c9f55d1 | ||
|  | b93e18ed50 | ||
|  | 9c77bb69a5 | ||
|  | 27f3ecc833 | ||
|  | f9e90eeb1f | ||
|  | fad5c675eb | ||
|  | 4908b77d46 | ||
|  | f4dd5062d7 | ||
|  | da34d75841 | ||
|  | 980ff18956 | ||
|  | 7edf4c6c04 | ||
|  | 1a6c7204ac | ||
|  | 49310fbab3 | ||
|  | 6049d5ac47 | ||
|  | 35d0d35238 | ||
|  | c0e878705e | ||
|  | 5c0c8efb9e | ||
|  | dfd714e1ef | ||
|  | 79a8ca1a62 | ||
|  | fb45eb2eb2 | ||
|  | a307274c96 | ||
|  | 3f2c44a5fe | ||
|  | 48fb1cdc11 | ||
|  | 8a79e93cc2 | ||
|  | 3493b51879 | ||
|  | de3e79d300 | ||
|  | dd62a61c5c | ||
|  | 8f47d0b5ab | ||
|  | 42af132dab | ||
|  | 9db2c6525d | ||
|  | adbc7c1188 | ||
|  | 9dc345e8e8 | ||
|  | 8b9301a74c | ||
|  | 6f47fbb1e2 | ||
|  | a9ae30f868 | ||
|  | a3c0fb79b6 | ||
|  | 62601bb649 | ||
|  | ef97e32152 | ||
|  | daea5297ee | ||
|  | 5028969d4b | ||
|  | c667d9fdcc | ||
|  | 7dbb94bab2 | ||
|  | 236dcc820b | ||
|  | a42a441a6a | ||
|  | a0676beeb1 | ||
|  | c5106d0c03 | ||
|  | fbf96b1bbb | ||
|  | 3c49ddfaa4 | ||
|  | ffb8b3116c | ||
|  | 290493e162 | ||
|  | dd8cfff111 | ||
|  | 184642adb0 | ||
|  | 4774a3bcd2 | ||
|  | 25fafa9a89 | ||
|  | 713520d3d2 | ||
|  | 85ed8175cb | ||
|  | df5c788ef2 | ||
|  | 15f22425c8 | ||
|  | e87182cf98 | ||
|  | e3d5319470 | ||
|  | ffedeb1c58 | ||
|  | 3e3b367aa9 | ||
|  | 3e80947c2b | ||
|  | fdfbf11c6d | ||
|  | 9cb90f714e | ||
|  | 6ce174cd60 | ||
|  | 17ca5240f7 | ||
|  | 2daffdf95d | ||
|  | 149f826601 | ||
|  | cd8ee27080 | ||
|  | 0fa66e8f3c | ||
|  | 8dd099267d | ||
|  | 1a6d65c6a4 | ||
|  | fc4a043663 | ||
|  | 61ba50665e | ||
|  | 446c768cd3 | ||
|  | bfe14000a9 | ||
|  | 092fa0d8da | ||
| e0b7004f96 | |||
|  | 1ceff48133 | ||
|  | 680645f849 | ||
|  | 3fc6e03ad1 | ||
|  | 2d6614f3a1 | ||
|  | 4e041b5103 | ||
|  | 712b9a3489 | ||
|  | bdaa5b1767 | ||
|  | 8fcefc021a | ||
|  | 1445189361 | ||
|  | 05c884a62a | ||
|  | a25bec87d9 | ||
|  | 2d8bb4c594 | ||
|  | 51cb2d4328 | ||
|  | 6d58cb2a68 | ||
|  | c8b35d960c | ||
|  | 532f41dd61 | ||
|  | 661b0ab45d | ||
|  | 565e9329ba | ||
|  | 4bc08ed995 | ||
|  | b2933a0557 | ||
|  | db057cc276 | ||
|  | 22e88eaf54 | ||
|  | 09fe3caebd | ||
|  | 5e02392f9c | ||
|  | 17a8f51a9b | ||
|  | 1b7f88dd00 | ||
| d6737e4bd8 | |||
| 75fc295f6e | |||
| d539888e57 | |||
|  | 86187d7cca | ||
|  | 87418e7df1 | ||
|  | 55f65b81b5 | ||
|  | d9408893b3 | ||
|  | 05acc22920 | ||
|  | 8ac021de73 | ||
|  | e503ef5590 | ||
|  | a7682b0060 | ||
| 0b731b5d80 | |||
| 8e2078be71 | |||
|  | d4c9d71fc8 | ||
|  | 786ca52c43 | ||
|  | 048ac04abc | ||
|  | f78d89bcbe | ||
|  | 53d06046b0 | ||
|  | 5d3a1a025d | ||
|  | 139cc5f1ae | ||
| 1826ed06a3 | |||
| 1c0e922585 | |||
| 9d5f693cbe | |||
| 3ff96c502b | |||
| 15a0908bfc | |||
| bb2125962b | |||
| 232fda5fe1 | |||
| 2b31bf61ff | |||
| afe5a94745 | |||
| 7ae667c767 | |||
| 07f0b69784 | |||
| 5c06e89d69 | |||
| 3d75e0f0d1 | |||
| 362f255100 | |||
| 3d78ed03ef | |||
| 835003b3c5 | |||
| 328d213c9e | |||
| 56a8d7a5bc | |||
| 78198d1b04 | |||
| 84fa2bdce6 | |||
| 29dfe99e7c | |||
| d604580e5a | |||
| 7dfdc9baa0 | |||
| 9e986654e6 | |||
| df3fbc477e | |||
| bb580ae077 | |||
| 2c226753ab | |||
| ea0cea668e | |||
| 75cd72a421 | |||
| cbe52b0659 | |||
| 3aa6463ede | |||
| 312637e5fb | |||
| 798d8f7340 | |||
| ba878724ce | |||
| b865dd9da8 | |||
| 8b313a35ac | |||
| 02ec23cdad | |||
| 6e83b6a203 | |||
| 48fcc34d72 | |||
| d08d93c44c | |||
| 0ab10cdedb | |||
| 22653edf12 | |||
| 12d2a95846 | |||
| 978cf52f6b | |||
| 63b730de80 | |||
| 7905c5b8e5 | |||
| 5e4b58ac40 | |||
| 468d8dc682 | |||
| beb11fd4ef | |||
| d7662b5175 | |||
| dc5f32e5f0 | |||
| 1869d28429 | |||
| 405b175665 | |||
| e33b0f6ff7 | |||
| 9ee54e0db7 | |||
| feae35d92c | |||
| 3834d81181 | |||
|  | 339be37dba | ||
|  | a87b744621 | ||
| 97d0d56bcb | |||
| 7c7ea35ffb | |||
| 4b1cf580e0 | |||
| 179e82b5ca | |||
| f2c59c8730 | |||
| fdd0848593 | |||
| 92f666905f | |||
| 5980fa8640 | |||
| 2d8bb356e3 | |||
| a7251f28c7 | |||
| a0d8eb2c24 | |||
| 1e10b4571d | |||
| 02f8b84ac9 | |||
| cfd368596d | |||
|  | c1b1b89d17 | ||
|  | 771235017d | ||
| ae682674e0 | |||
| 17c43f49ac | |||
| 30146e977c | |||
| 54eacec261 | |||
| 76c78f04e2 | |||
| 379580cd89 | |||
| 14a80733f9 | |||
| d4db009a58 | |||
| 20ce7e0270 | |||
| bb195607ab | |||
| 6f090e22c0 | |||
| 339e983172 | |||
| 4a7f3d1b7b | |||
| c4e2202550 | |||
| 538b16610b | 
							
								
								
									
										42
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										42
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -5,11 +5,11 @@ | ||||
| *.o | ||||
| *.obj | ||||
|  | ||||
|  | ||||
| # Editor files # | ||||
| ################ | ||||
| *~ | ||||
| *# | ||||
| *.sublime-* | ||||
|  | ||||
| # Precompiled Headers # | ||||
| ####################### | ||||
| @@ -48,6 +48,9 @@ Config.h.in | ||||
| config.log | ||||
| config.status | ||||
| .deps | ||||
| Make.inc | ||||
| eigen.inc | ||||
| Eigen.inc | ||||
|  | ||||
| # http://www.gnu.org/software/autoconf # | ||||
| ######################################## | ||||
| @@ -62,19 +65,8 @@ stamp-h1 | ||||
| config.sub | ||||
| config.guess | ||||
| INSTALL | ||||
|  | ||||
| # Packages # | ||||
| ############ | ||||
| # it's better to unpack these files and commit the raw source | ||||
| # git has its own built in compression methods | ||||
| *.7z | ||||
| *.dmg | ||||
| *.gz | ||||
| *.iso | ||||
| *.jar | ||||
| *.rar | ||||
| *.tar | ||||
| *.zip | ||||
| .dirstamp | ||||
| ltmain.sh | ||||
|   | ||||
| # Logs and databases # | ||||
| ###################### | ||||
| @@ -91,6 +83,7 @@ INSTALL | ||||
| .Trashes | ||||
| ehthumbs.db | ||||
| Thumbs.db | ||||
| .dirstamp | ||||
|  | ||||
| # build directory # | ||||
| ################### | ||||
| @@ -100,3 +93,24 @@ build*/* | ||||
| ##################### | ||||
| *.xcodeproj/* | ||||
| build.sh | ||||
| .vscode | ||||
| *.code-workspace | ||||
|  | ||||
| # Eigen source # | ||||
| ################ | ||||
| Grid/Eigen | ||||
| Eigen/* | ||||
|  | ||||
| # libtool macros # | ||||
| ################## | ||||
| m4/lt* | ||||
| m4/libtool.m4 | ||||
|  | ||||
| # github pages # | ||||
| ################ | ||||
| gh-pages/ | ||||
|  | ||||
| # generated sources # | ||||
| ##################### | ||||
| Grid/qcd/spin/gamma-gen/*.h | ||||
| Grid/qcd/spin/gamma-gen/*.cc | ||||
|   | ||||
							
								
								
									
										100
									
								
								.travis.yml
									
									
									
									
									
								
							
							
						
						
									
										100
									
								
								.travis.yml
									
									
									
									
									
								
							| @@ -1,79 +1,61 @@ | ||||
| language: cpp | ||||
|  | ||||
| cache: | ||||
|   directories: | ||||
|     - clang | ||||
|  | ||||
| matrix: | ||||
|   include: | ||||
|     - os:        osx | ||||
|       osx_image: xcode7.2 | ||||
|       osx_image: xcode8.3 | ||||
|       compiler: clang | ||||
|       env: PREC=single | ||||
|     - os:        osx | ||||
|       osx_image: xcode7.2 | ||||
|       compiler: gcc | ||||
|       env: VERSION=-5 | ||||
|     - compiler: gcc | ||||
|       addons: | ||||
|         apt: | ||||
|           sources: | ||||
|             - ubuntu-toolchain-r-test | ||||
|           packages: | ||||
|             - g++-4.9 | ||||
|             - libmpfr-dev | ||||
|             - libgmp-dev | ||||
|             - libmpc-dev | ||||
|             - binutils-dev | ||||
|       env: VERSION=-4.9 | ||||
|     - compiler: gcc | ||||
|       addons: | ||||
|         apt: | ||||
|           sources: | ||||
|             - ubuntu-toolchain-r-test | ||||
|           packages: | ||||
|             - g++-5 | ||||
|             - libmpfr-dev | ||||
|             - libgmp-dev | ||||
|             - libmpc-dev | ||||
|             - binutils-dev | ||||
|       env: VERSION=-5 | ||||
|     - compiler: clang | ||||
|       addons: | ||||
|         apt: | ||||
|           sources: | ||||
|             - ubuntu-toolchain-r-test | ||||
|             - llvm-toolchain-precise-3.7 | ||||
|           packages: | ||||
|             - clang-3.7 | ||||
|             - libmpfr-dev | ||||
|             - libgmp-dev | ||||
|             - libmpc-dev | ||||
|             - binutils-dev | ||||
|       env: VERSION=-3.7 | ||||
|     - compiler: clang | ||||
|       addons: | ||||
|         apt: | ||||
|           sources: | ||||
|             - ubuntu-toolchain-r-test | ||||
|             - llvm-toolchain-precise-3.8 | ||||
|           packages: | ||||
|             - clang-3.8 | ||||
|             - libmpfr-dev | ||||
|             - libgmp-dev | ||||
|             - libmpc-dev | ||||
|             - binutils-dev | ||||
|       env: VERSION=-3.8 | ||||
|       osx_image: xcode8.3 | ||||
|       compiler: clang | ||||
|       env: PREC=double | ||||
|        | ||||
| before_install: | ||||
|     - export GRIDDIR=`pwd` | ||||
|     - if [[ "$TRAVIS_OS_NAME" == "linux" ]] && [[ "$CC" == "clang" ]] && [ ! -e clang/bin ]; then wget $CLANG_LINK; tar -xf `basename $CLANG_LINK`; mkdir clang; mv clang+*/* clang/; 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" == "osx" ]]; then brew update; fi | ||||
|     - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install libmpc; fi | ||||
|     - if [[ "$TRAVIS_OS_NAME" == "osx" ]] && [[ "$CC" == "gcc" ]]; then brew install gcc5; fi | ||||
|     - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install libmpc openssl; fi | ||||
|      | ||||
| install: | ||||
|     - export CWD=`pwd` | ||||
|     - echo $CWD | ||||
|     - export CC=$CC$VERSION | ||||
|     - export CXX=$CXX$VERSION | ||||
|     - echo $PATH | ||||
|     - which autoconf | ||||
|     - autoconf  --version | ||||
|     - which automake | ||||
|     - automake  --version | ||||
|     - which $CC | ||||
|     - $CC  --version | ||||
|     - which $CXX | ||||
|     - $CXX --version | ||||
|     - 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: | ||||
|     - ./scripts/reconfigure_script | ||||
|     - ./bootstrap.sh | ||||
|     - mkdir build | ||||
|     - cd build | ||||
|     - ../configure CXXFLAGS="-msse4.2 -O3 -std=c++11" LIBS="-lmpfr -lgmp" --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 | ||||
|     - ./benchmarks/Benchmark_dwf --threads 1 | ||||
|     - make install | ||||
|     - cd $CWD/build | ||||
|     - ../configure --enable-precision=$PREC --enable-simd=SSE4 --enable-comms=none --with-lime=$CWD/build/lime/install ${EXTRACONF} | ||||
|     - make -j4  | ||||
|     - ./benchmarks/Benchmark_dwf --threads 1 --debug-signals | ||||
|     - make check | ||||
|   | ||||
							
								
								
									
										37
									
								
								Grid/DisableWarnings.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								Grid/DisableWarnings.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,37 @@ | ||||
| /************************************************************************************* | ||||
|  | ||||
| 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 | ||||
|  | ||||
|  //disables and intel compiler specific warning (in json.hpp) | ||||
| #pragma warning disable 488   | ||||
|  | ||||
|  | ||||
| #endif | ||||
| @@ -2,12 +2,13 @@ | ||||
| 
 | ||||
|     Grid physics library, www.github.com/paboyle/Grid  | ||||
| 
 | ||||
|     Source file: ./lib/stencil/Stencil_common.cc | ||||
|     Source file: ./lib/Grid.h | ||||
| 
 | ||||
|     Copyright (C) 2015 | ||||
| 
 | ||||
| Author: Peter Boyle <paboyle@ph.ed.ac.uk> | ||||
| Author: Peter Boyle <peterboyle@Peters-MacBook-Pro-2.local> | ||||
| Author: azusayamaguchi <ayamaguc@YAMAKAZE.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 | ||||
| @@ -26,9 +27,23 @@ Author: Peter Boyle <peterboyle@Peters-MacBook-Pro-2.local> | ||||
|     See the full license in the file "LICENSE" in the top level distribution directory | ||||
|     *************************************************************************************/ | ||||
|     /*  END LEGAL */ | ||||
| #include "Grid.h" | ||||
| //
 | ||||
| //  Grid.h
 | ||||
| //  simd
 | ||||
| //
 | ||||
| //  Created by Peter Boyle on 09/05/2014.
 | ||||
| //  Copyright (c) 2014 University of Edinburgh. All rights reserved.
 | ||||
| //
 | ||||
| 
 | ||||
| namespace Grid { | ||||
| } | ||||
| #ifndef GRID_H | ||||
| #define GRID_H | ||||
| 
 | ||||
| #include <Grid/GridCore.h> | ||||
| #include <Grid/GridQCDcore.h> | ||||
| #include <Grid/qcd/action/Action.h> | ||||
| #include <Grid/qcd/utils/GaugeFix.h> | ||||
| #include <Grid/qcd/smearing/Smearing.h> | ||||
| #include <Grid/parallelIO/MetaData.h> | ||||
| #include <Grid/qcd/hmc/HMC_aggregate.h> | ||||
| 
 | ||||
| #endif | ||||
| @@ -35,54 +35,27 @@ Author: paboyle <paboyle@ph.ed.ac.uk> | ||||
| //  Copyright (c) 2014 University of Edinburgh. All rights reserved.
 | ||||
| //
 | ||||
| 
 | ||||
| #ifndef GRID_H | ||||
| #define GRID_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 <serialisation/Serialisation.h> | ||||
| #include <Config.h> | ||||
| #include <Timer.h> | ||||
| #include <PerfCount.h> | ||||
| #include <Log.h> | ||||
| #include <AlignedAllocator.h> | ||||
| #include <Simd.h> | ||||
| #include <Threads.h> | ||||
| #include <Lexicographic.h> | ||||
| #include <Communicator.h>  | ||||
| #include <Cartesian.h>     | ||||
| #include <Tensors.h>       | ||||
| #include <Lattice.h>       | ||||
| #include <Cshift.h>        | ||||
| #include <Stencil.h>       | ||||
| #include <Algorithms.h>    | ||||
| #include <parallelIO/BinaryIO.h> | ||||
| #include <qcd/QCD.h> | ||||
| #include <parallelIO/NerscIO.h> | ||||
| #include <Init.h> | ||||
| 
 | ||||
| #include <qcd/hmc/NerscCheckpointer.h> | ||||
| #include <qcd/hmc/HmcRunner.h> | ||||
| #ifndef GRID_BASE_H | ||||
| #define GRID_BASE_H | ||||
| 
 | ||||
| #include <Grid/GridStd.h> | ||||
| 
 | ||||
| #include <Grid/perfmon/Timer.h> | ||||
| #include <Grid/perfmon/PerfCount.h> | ||||
| #include <Grid/log/Log.h> | ||||
| #include <Grid/allocator/AlignedAllocator.h> | ||||
| #include <Grid/simd/Simd.h> | ||||
| #include <Grid/serialisation/Serialisation.h> | ||||
| #include <Grid/threads/Threads.h> | ||||
| #include <Grid/util/Util.h> | ||||
| #include <Grid/util/Sha.h> | ||||
| #include <Grid/communicator/Communicator.h>  | ||||
| #include <Grid/cartesian/Cartesian.h>     | ||||
| #include <Grid/tensors/Tensors.h>       | ||||
| #include <Grid/lattice/Lattice.h>       | ||||
| #include <Grid/cshift/Cshift.h>        | ||||
| #include <Grid/stencil/Stencil.h>       | ||||
| #include <Grid/parallelIO/BinaryIO.h> | ||||
| #include <Grid/algorithms/Algorithms.h>    | ||||
| 
 | ||||
| #endif | ||||
| @@ -2,12 +2,12 @@ | ||||
| 
 | ||||
|     Grid physics library, www.github.com/paboyle/Grid  | ||||
| 
 | ||||
|     Source file: ./lib/qcd/hmc/HMC.cc | ||||
|     Source file: ./lib/Grid.h | ||||
| 
 | ||||
|     Copyright (C) 2015 | ||||
| 
 | ||||
| Author: Peter Boyle <paboyle@ph.ed.ac.uk> | ||||
| Author: neo <cossu@post.kek.jp> | ||||
| Author: azusayamaguchi <ayamaguc@YAMAKAZE.local> | ||||
| Author: paboyle <paboyle@ph.ed.ac.uk> | ||||
| 
 | ||||
|     This program is free software; you can redistribute it and/or modify | ||||
| @@ -27,10 +27,16 @@ Author: paboyle <paboyle@ph.ed.ac.uk> | ||||
|     See the full license in the file "LICENSE" in the top level distribution directory | ||||
|     *************************************************************************************/ | ||||
|     /*  END LEGAL */ | ||||
| #include <Grid.h> | ||||
| #ifndef GRID_QCD_CORE_H | ||||
| #define GRID_QCD_CORE_H | ||||
| 
 | ||||
| namespace Grid{ | ||||
|   namespace QCD{ | ||||
| /////////////////////////
 | ||||
| // Core Grid QCD headers
 | ||||
| /////////////////////////
 | ||||
| #include <Grid/GridCore.h> | ||||
| #include <Grid/qcd/QCD.h> | ||||
| #include <Grid/qcd/spin/Spin.h> | ||||
| #include <Grid/qcd/utils/Utils.h> | ||||
| #include <Grid/qcd/representations/Representations.h> | ||||
| 
 | ||||
|   } | ||||
| } | ||||
| #endif | ||||
							
								
								
									
										29
									
								
								Grid/GridStd.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								Grid/GridStd.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,29 @@ | ||||
| #ifndef GRID_STD_H | ||||
| #define GRID_STD_H | ||||
|  | ||||
| /////////////////// | ||||
| // Std C++ dependencies | ||||
| /////////////////// | ||||
| #include <cassert> | ||||
| #include <complex> | ||||
| #include <vector> | ||||
| #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 */ | ||||
							
								
								
									
										14
									
								
								Grid/Grid_Eigen_Dense.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								Grid/Grid_Eigen_Dense.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,14 @@ | ||||
| #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 | ||||
| #include <Grid/Eigen/Dense> | ||||
| #if defined __GNUC__ | ||||
| #pragma GCC diagnostic pop | ||||
| #endif | ||||
							
								
								
									
										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) | ||||
| @@ -29,45 +29,34 @@ Author: Peter Boyle <paboyle@ph.ed.ac.uk> | ||||
| #ifndef GRID_ALGORITHMS_H | ||||
| #define GRID_ALGORITHMS_H | ||||
| 
 | ||||
| #include <algorithms/SparseMatrix.h> | ||||
| #include <algorithms/LinearOperator.h> | ||||
| #include <algorithms/Preconditioner.h> | ||||
| #include <Grid/algorithms/SparseMatrix.h> | ||||
| #include <Grid/algorithms/LinearOperator.h> | ||||
| #include <Grid/algorithms/Preconditioner.h> | ||||
| 
 | ||||
| #include <algorithms/approx/Zolotarev.h> | ||||
| #include <algorithms/approx/Chebyshev.h> | ||||
| #include <algorithms/approx/Remez.h> | ||||
| #include <algorithms/approx/MultiShiftFunction.h> | ||||
| #include <Grid/algorithms/approx/Zolotarev.h> | ||||
| #include <Grid/algorithms/approx/Chebyshev.h> | ||||
| #include <Grid/algorithms/approx/Remez.h> | ||||
| #include <Grid/algorithms/approx/MultiShiftFunction.h> | ||||
| #include <Grid/algorithms/approx/Forecast.h> | ||||
| 
 | ||||
| #include <algorithms/iterative/ConjugateGradient.h> | ||||
| #include <algorithms/iterative/ConjugateResidual.h> | ||||
| #include <algorithms/iterative/NormalEquations.h> | ||||
| #include <algorithms/iterative/SchurRedBlack.h> | ||||
| #include <Grid/algorithms/iterative/Deflation.h> | ||||
| #include <Grid/algorithms/iterative/ConjugateGradient.h> | ||||
| #include <Grid/algorithms/iterative/ConjugateResidual.h> | ||||
| #include <Grid/algorithms/iterative/NormalEquations.h> | ||||
| #include <Grid/algorithms/iterative/SchurRedBlack.h> | ||||
| #include <Grid/algorithms/iterative/ConjugateGradientMultiShift.h> | ||||
| #include <Grid/algorithms/iterative/ConjugateGradientMixedPrec.h> | ||||
| #include <Grid/algorithms/iterative/BlockConjugateGradient.h> | ||||
| #include <Grid/algorithms/iterative/ConjugateGradientReliableUpdate.h> | ||||
| #include <Grid/algorithms/iterative/ImplicitlyRestartedLanczos.h> | ||||
| #include <Grid/algorithms/CoarsenedMatrix.h> | ||||
| #include <Grid/algorithms/FFT.h> | ||||
| 
 | ||||
| #include <algorithms/iterative/ConjugateGradientMultiShift.h> | ||||
| 
 | ||||
| // Lanczos support
 | ||||
| #include <algorithms/iterative/MatrixUtils.h> | ||||
| #include <algorithms/iterative/ImplicitlyRestartedLanczos.h> | ||||
| 
 | ||||
| #include <algorithms/CoarsenedMatrix.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 | ||||
| @@ -31,7 +31,6 @@ Author: paboyle <paboyle@ph.ed.ac.uk> | ||||
| #ifndef  GRID_ALGORITHM_COARSENED_MATRIX_H | ||||
| #define  GRID_ALGORITHM_COARSENED_MATRIX_H | ||||
| 
 | ||||
| #include <Grid.h> | ||||
| 
 | ||||
| namespace Grid { | ||||
| 
 | ||||
| @@ -104,29 +103,32 @@ namespace Grid { | ||||
|     GridBase *CoarseGrid; | ||||
|     GridBase *FineGrid; | ||||
|     std::vector<Lattice<Fobj> > subspace; | ||||
|     int checkerboard; | ||||
| 
 | ||||
|     Aggregation(GridBase *_CoarseGrid,GridBase *_FineGrid) :  | ||||
|   Aggregation(GridBase *_CoarseGrid,GridBase *_FineGrid,int _checkerboard) :  | ||||
|     CoarseGrid(_CoarseGrid), | ||||
|       FineGrid(_FineGrid), | ||||
|       subspace(nbasis,_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);  | ||||
|       Lattice<CComplex> pokey(CoarseGrid); | ||||
| 
 | ||||
|        | ||||
|       for(int i=0;i<nbasis;i++){ | ||||
| 	blockProject(iProj,subspace[i],subspace); | ||||
| 
 | ||||
| 	eProj=zero;  | ||||
| 	for(int ss=0;ss<CoarseGrid->oSites();ss++){ | ||||
| 	parallel_for(int ss=0;ss<CoarseGrid->oSites();ss++){ | ||||
| 	  eProj._odata[ss](i)=CComplex(1.0); | ||||
| 	} | ||||
| 	eProj=eProj - iProj; | ||||
| @@ -138,6 +140,7 @@ namespace Grid { | ||||
|       blockProject(CoarseVec,FineVec,subspace); | ||||
|     } | ||||
|     void PromoteFromSubspace(const CoarseVector &CoarseVec,FineField &FineVec){ | ||||
|       FineVec.checkerboard = subspace[0].checkerboard; | ||||
|       blockPromote(CoarseVec,FineVec,subspace); | ||||
|     } | ||||
|     void CreateSubspaceRandom(GridParallelRNG &RNG){ | ||||
| @@ -148,6 +151,7 @@ namespace Grid { | ||||
|       Orthogonalise(); | ||||
|     } | ||||
| 
 | ||||
|     /*
 | ||||
|     virtual void CreateSubspaceLanczos(GridParallelRNG  &RNG,LinearOperatorBase<FineField> &hermop,int nn=nbasis)  | ||||
|     { | ||||
|       // Run a Lanczos with sloppy convergence
 | ||||
| @@ -196,7 +200,7 @@ namespace Grid { | ||||
| 	  std::cout << GridLogMessage <<"subspace["<<b<<"] = "<<norm2(subspace[b])<<std::endl; | ||||
| 	} | ||||
|     } | ||||
| 
 | ||||
|     */ | ||||
|     virtual void CreateSubspace(GridParallelRNG  &RNG,LinearOperatorBase<FineField> &hermop,int nn=nbasis) { | ||||
| 
 | ||||
|       RealD scale; | ||||
| @@ -268,8 +272,7 @@ namespace Grid { | ||||
|       SimpleCompressor<siteVector> compressor; | ||||
|       Stencil.HaloExchange(in,compressor); | ||||
| 
 | ||||
| PARALLEL_FOR_LOOP | ||||
|       for(int ss=0;ss<Grid()->oSites();ss++){ | ||||
|       parallel_for(int ss=0;ss<Grid()->oSites();ss++){ | ||||
|         siteVector res = zero; | ||||
| 	siteVector nbr; | ||||
| 	int ptype; | ||||
| @@ -283,7 +286,7 @@ PARALLEL_FOR_LOOP | ||||
| 	  } else if(SE->_is_local) {  | ||||
| 	    nbr = in._odata[SE->_offset]; | ||||
| 	  } else { | ||||
| 	    nbr = Stencil.comm_buf[SE->_offset]; | ||||
| 	    nbr = Stencil.CommBuf()[SE->_offset]; | ||||
| 	  } | ||||
| 	  res = res + A[point]._odata[ss]*nbr; | ||||
| 	} | ||||
| @@ -381,8 +384,7 @@ PARALLEL_FOR_LOOP | ||||
| 	  Subspace.ProjectToSubspace(oProj,oblock); | ||||
| 	  //	  blockProject(iProj,iblock,Subspace.subspace);
 | ||||
| 	  //	  blockProject(oProj,oblock,Subspace.subspace);
 | ||||
| PARALLEL_FOR_LOOP | ||||
| 	  for(int ss=0;ss<Grid()->oSites();ss++){ | ||||
| 	  parallel_for(int ss=0;ss<Grid()->oSites();ss++){ | ||||
| 	    for(int j=0;j<nbasis;j++){ | ||||
| 	      if( disp!= 0 ) { | ||||
| 		A[p]._odata[ss](j,i) = oProj._odata[ss](j); | ||||
| @@ -428,7 +430,7 @@ PARALLEL_FOR_LOOP | ||||
| 	A[p]=zero; | ||||
|       } | ||||
| 
 | ||||
|       GridParallelRNG  RNG(Grid()); RNG.SeedRandomDevice(); | ||||
|       GridParallelRNG  RNG(Grid()); RNG.SeedFixedIntegers(std::vector<int>({55,72,19,17,34})); | ||||
|       Lattice<iScalar<CComplex> > val(Grid()); random(RNG,val); | ||||
| 
 | ||||
|       Complex one(1.0); | ||||
							
								
								
									
										306
									
								
								Grid/algorithms/FFT.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										306
									
								
								Grid/algorithms/FFT.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,306 @@ | ||||
|  | ||||
|     /************************************************************************************* | ||||
|  | ||||
|     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 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; | ||||
|      | ||||
|     std::vector<int> dimensions; | ||||
|     std::vector<int> processors; | ||||
|     std::vector<int> 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; | ||||
|       std::vector<int> 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,std::vector<int> 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){ | ||||
|       std::vector<int> 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]; | ||||
|        | ||||
|       std::vector<int> layout(Nd,1); | ||||
|       std::vector<int> 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); | ||||
|        | ||||
|  | ||||
|       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._odata[0]; | ||||
|         FFTW_scalar *out= (FFTW_scalar *)&pgbuf._odata[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 | ||||
|       std::vector<int> lcoor(Nd), gcoor(Nd); | ||||
|       result = source; | ||||
|       int pc = processor_coor[dim]; | ||||
|       for(int p=0;p<processors[dim];p++) { | ||||
|         PARALLEL_REGION | ||||
|         { | ||||
|           std::vector<int> cbuf(Nd); | ||||
|           sobj s; | ||||
|            | ||||
|           PARALLEL_FOR_LOOP_INTERN | ||||
|           for(int idx=0;idx<sgrid->lSites();idx++) { | ||||
|             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(); | ||||
|       PARALLEL_REGION | ||||
|       { | ||||
|         std::vector<int> cbuf(Nd); | ||||
|          | ||||
|         PARALLEL_FOR_LOOP_INTERN | ||||
|         for(int idx=0;idx<NN;idx++) { | ||||
|           pencil_g.LocalIndexToLocalCoor(idx, cbuf); | ||||
|           if ( cbuf[dim] == 0 ) {  // restricts loop to plane at lcoor[dim]==0 | ||||
|             FFTW_scalar *in = (FFTW_scalar *)&pgbuf._odata[idx]; | ||||
|             FFTW_scalar *out= (FFTW_scalar *)&pgbuf._odata[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 | ||||
|       PARALLEL_REGION | ||||
|       { | ||||
|         std::vector<int> clbuf(Nd), cgbuf(Nd); | ||||
|         sobj s; | ||||
|          | ||||
|         PARALLEL_FOR_LOOP_INTERN | ||||
|         for(int idx=0;idx<sgrid->lSites();idx++) { | ||||
|           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 | ||||
|     } | ||||
|   }; | ||||
| } | ||||
|  | ||||
| #endif | ||||
| @@ -51,7 +51,7 @@ namespace Grid { | ||||
| 
 | ||||
|       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 HermOpAndNorm(const Field &in, Field &out,RealD &n1,RealD &n2) = 0; | ||||
|       virtual void HermOp(const Field &in, Field &out)=0; | ||||
|     }; | ||||
| 
 | ||||
| @@ -162,15 +162,10 @@ namespace Grid { | ||||
| 	_Mat.M(in,out); | ||||
|       } | ||||
|       void HermOpAndNorm(const Field &in, Field &out,RealD &n1,RealD &n2){ | ||||
| 	ComplexD dot; | ||||
| 
 | ||||
| 	_Mat.M(in,out); | ||||
| 	 | ||||
| 	dot= innerProduct(in,out); | ||||
| 	n1=real(dot); | ||||
| 
 | ||||
| 	dot = innerProduct(out,out); | ||||
| 	n2=real(dot); | ||||
| 	ComplexD dot= innerProduct(in,out); n1=real(dot); | ||||
| 	n2=norm2(out); | ||||
|       } | ||||
|       void HermOp(const Field &in, Field &out){ | ||||
| 	_Mat.M(in,out); | ||||
| @@ -189,13 +184,15 @@ namespace Grid { | ||||
|       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); | ||||
|       } | ||||
|       void HermOpAndNorm(const Field &in, Field &out,RealD &n1,RealD &n2){ | ||||
|       virtual void HermOpAndNorm(const Field &in, Field &out,RealD &n1,RealD &n2){ | ||||
|       out.checkerboard = in.checkerboard; | ||||
| 	MpcDagMpc(in,out,n1,n2); | ||||
|       } | ||||
|       void HermOp(const Field &in, Field &out){ | ||||
|       virtual void HermOp(const Field &in, Field &out){ | ||||
| 	RealD n1,n2; | ||||
| 	HermOpAndNorm(in,out,n1,n2); | ||||
|       } | ||||
| @@ -212,7 +209,6 @@ namespace Grid { | ||||
|       void OpDir  (const Field &in, Field &out,int dir,int disp) { | ||||
| 	assert(0); | ||||
|       } | ||||
| 
 | ||||
|     }; | ||||
|     template<class Matrix,class Field> | ||||
|       class SchurDiagMooeeOperator :  public SchurOperatorBase<Field> { | ||||
| @@ -222,12 +218,14 @@ namespace Grid { | ||||
|       SchurDiagMooeeOperator (Matrix &Mat): _Mat(Mat){}; | ||||
|       virtual  RealD Mpc      (const Field &in, Field &out) { | ||||
|       Field tmp(in._grid); | ||||
| //	std::cout <<"grid pointers: in._grid="<< in._grid << " out._grid=" << out._grid << "  _Mat.Grid=" << _Mat.Grid() << " _Mat.RedBlackGrid=" << _Mat.RedBlackGrid() << std::endl;
 | ||||
|       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); | ||||
|       } | ||||
| @@ -270,7 +268,6 @@ namespace Grid { | ||||
| 	return axpy_norm(out,-1.0,tmp,in); | ||||
|       } | ||||
|     }; | ||||
| 
 | ||||
|     template<class Matrix,class Field> | ||||
|       class SchurDiagTwoOperator :  public SchurOperatorBase<Field> { | ||||
|     protected: | ||||
| @@ -299,6 +296,82 @@ namespace Grid { | ||||
| 	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) { | ||||
| 	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>; | ||||
| 
 | ||||
| 
 | ||||
|     /////////////////////////////////////////////////////////////
 | ||||
| @@ -314,6 +387,14 @@ namespace Grid { | ||||
|       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
 | ||||
|     /////////////////////////////////////////////////////////////
 | ||||
| @@ -336,6 +417,64 @@ namespace Grid { | ||||
|      }; | ||||
|     */ | ||||
| 
 | ||||
|   ////////////////////////////////////////////////////////////////////////////////////////////
 | ||||
|   // 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: | ||||
|     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]; | ||||
|       } | ||||
|     }; | ||||
|   }; | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| @@ -28,7 +28,6 @@ Author: Peter Boyle <paboyle@ph.ed.ac.uk> | ||||
| #ifndef  GRID_ALGORITHM_SPARSE_MATRIX_H | ||||
| #define  GRID_ALGORITHM_SPARSE_MATRIX_H | ||||
| 
 | ||||
| #include <Grid.h> | ||||
| 
 | ||||
| namespace Grid { | ||||
| 
 | ||||
| @@ -8,6 +8,7 @@ | ||||
| 
 | ||||
| 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 | ||||
| @@ -29,46 +30,16 @@ Author: paboyle <paboyle@ph.ed.ac.uk> | ||||
| #ifndef GRID_CHEBYSHEV_H | ||||
| #define GRID_CHEBYSHEV_H | ||||
| 
 | ||||
| #include<Grid.h> | ||||
| #include<algorithms/LinearOperator.h> | ||||
| #include <Grid/algorithms/LinearOperator.h> | ||||
| 
 | ||||
| namespace Grid { | ||||
| 
 | ||||
|   ////////////////////////////////////////////////////////////////////////////////////////////
 | ||||
|   // Simple general polynomial with user supplied coefficients
 | ||||
|   ////////////////////////////////////////////////////////////////////////////////////////////
 | ||||
|   template<class Field> | ||||
|   class HermOpOperatorFunction : public OperatorFunction<Field> { | ||||
|     void operator() (LinearOperatorBase<Field> &Linop, const Field &in, Field &out) { | ||||
|       Linop.HermOp(in,out); | ||||
|     }; | ||||
|   }; | ||||
| 
 | ||||
|   template<class Field> | ||||
|   class Polynomial : public OperatorFunction<Field> { | ||||
|   private: | ||||
|     std::vector<RealD> Coeffs; | ||||
|   public: | ||||
|     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]; | ||||
| //            std::cout <<"Poly in " <<norm2(in)<<" size "<< Coeffs.size()<<std::endl;
 | ||||
| //            std::cout <<"Coeffs[0]= "<<Coeffs[0]<< " 0 " <<norm2(out)<<std::endl;
 | ||||
|       for(int n=1;n<Coeffs.size();n++){ | ||||
| 	Mtmp = AtoN; | ||||
| 	Linop.HermOp(Mtmp,AtoN); | ||||
| 	out=out+AtoN*Coeffs[n]; | ||||
| //            std::cout <<"Coeffs "<<n<<"= "<< Coeffs[n]<< " 0 " <<std::endl;
 | ||||
| //		std::cout << n<<" " <<norm2(out)<<std::endl;
 | ||||
|       } | ||||
|     }; | ||||
|   }; | ||||
| struct ChebyParams : Serializable { | ||||
|   GRID_SERIALIZABLE_CLASS_MEMBERS(ChebyParams, | ||||
| 				  RealD, alpha,   | ||||
| 				  RealD, beta,    | ||||
| 				  int, Npoly); | ||||
| }; | ||||
| 
 | ||||
|   ////////////////////////////////////////////////////////////////////////////////////////////
 | ||||
|   // Generic Chebyshev approximations
 | ||||
| @@ -84,7 +55,9 @@ namespace Grid { | ||||
|   public: | ||||
|     void csv(std::ostream &out){ | ||||
|       RealD diff = hi-lo; | ||||
|       for (RealD x=lo-0.2*diff; x<hi+0.2*diff; x+=(hi-lo)/1000) { | ||||
|       RealD delta = (hi-lo)*1.0e-9; | ||||
|       for (RealD x=lo; x<hi; x+=delta) { | ||||
| 	delta*=1.1; | ||||
| 	RealD f = approx(x); | ||||
| 	out<< x<<" "<<f<<std::endl; | ||||
|       } | ||||
| @@ -100,6 +73,7 @@ namespace Grid { | ||||
|     }; | ||||
| 
 | ||||
|     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);}; | ||||
| 
 | ||||
| @@ -194,12 +168,54 @@ namespace Grid { | ||||
|       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;
 | ||||
| //<<" Linop.Grid()="<<Linop.Grid()<<"Linop.RedBlackGrid()="<<Linop.RedBlackGrid()<<std::endl;
 | ||||
| 
 | ||||
|       // 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(); | ||||
| 
 | ||||
							
								
								
									
										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 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] = std::conj(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(std::abs(G[j][j]) > std::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 = std::conj(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; | ||||
|       }; | ||||
|   }; | ||||
|  | ||||
| } | ||||
|  | ||||
| #endif | ||||
| @@ -25,7 +25,7 @@ Author: Azusa Yamaguchi <ayamaguc@staffmail.ed.ac.uk> | ||||
|     See the full license in the file "LICENSE" in the top level distribution directory | ||||
|     *************************************************************************************/ | ||||
|     /*  END LEGAL */ | ||||
| #include <Grid.h> | ||||
| #include <Grid/GridCore.h> | ||||
| 
 | ||||
| namespace Grid { | ||||
| double MultiShiftFunction::approx(double x) | ||||
| @@ -20,7 +20,7 @@ | ||||
| #include<iomanip> | ||||
| #include<cassert> | ||||
| 
 | ||||
| #include<algorithms/approx/Remez.h> | ||||
| #include<Grid/algorithms/approx/Remez.h> | ||||
| 
 | ||||
| // Constructor
 | ||||
| AlgRemez::AlgRemez(double lower, double upper, long precision)  | ||||
| @@ -16,12 +16,12 @@ | ||||
| #define INCLUDED_ALG_REMEZ_H | ||||
| 
 | ||||
| #include <stddef.h> | ||||
| #include <Config.h> | ||||
| #include <Grid/GridStd.h> | ||||
| 
 | ||||
| #ifdef HAVE_GMP_H | ||||
| #include <algorithms/approx/bigfloat.h> | ||||
| #ifdef HAVE_LIBGMP | ||||
| #include "bigfloat.h" | ||||
| #else | ||||
| #include <algorithms/approx/bigfloat_double.h> | ||||
| #include "bigfloat_double.h" | ||||
| #endif | ||||
| 
 | ||||
| #define JMAX 10000 //Maximum number of iterations of Newton's approximation
 | ||||
							
								
								
									
										606
									
								
								Grid/algorithms/iterative/BlockConjugateGradient.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										606
									
								
								Grid/algorithms/iterative/BlockConjugateGradient.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,606 @@ | ||||
| /************************************************************************************* | ||||
|  | ||||
| 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 */ | ||||
| #ifndef GRID_BLOCK_CONJUGATE_GRADIENT_H | ||||
| #define GRID_BLOCK_CONJUGATE_GRADIENT_H | ||||
|  | ||||
|  | ||||
| namespace Grid { | ||||
|  | ||||
| enum BlockCGtype { BlockCG, BlockCGrQ, CGmultiRHS }; | ||||
|  | ||||
| ////////////////////////////////////////////////////////////////////////// | ||||
| // 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 | ||||
|    | ||||
|   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) | ||||
|   {}; | ||||
|  | ||||
| //////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
| // Thin QR factorisation (google it) | ||||
| //////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
| void ThinQRfact (Eigen::MatrixXcd &m_rr, | ||||
| 		 Eigen::MatrixXcd &C, | ||||
| 		 Eigen::MatrixXcd &Cinv, | ||||
| 		 Field & Q, | ||||
| 		 const Field & R) | ||||
| { | ||||
|   int Orthog = blockDim; // First dimension is block dim; this is an assumption | ||||
|   //////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
|   //Dimensions | ||||
|   // 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 | ||||
|   //////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
|   sliceInnerProductMatrix(m_rr,R,R,Orthog); | ||||
|  | ||||
|   // Force manifest hermitian to avoid rounding related | ||||
|   m_rr = 0.5*(m_rr+m_rr.adjoint()); | ||||
|  | ||||
| #if 0 | ||||
|   std::cout << " Calling Cholesky  ldlt on m_rr "  << m_rr <<std::endl; | ||||
|   Eigen::MatrixXcd L_ldlt = m_rr.ldlt().matrixL();  | ||||
|   std::cout << " Called Cholesky  ldlt on m_rr "  << L_ldlt <<std::endl; | ||||
|   auto  D_ldlt = m_rr.ldlt().vectorD();  | ||||
|   std::cout << " Called Cholesky  ldlt on m_rr "  << D_ldlt <<std::endl; | ||||
| #endif | ||||
|  | ||||
|   //  std::cout << " Calling Cholesky  llt on m_rr "  <<std::endl; | ||||
|   Eigen::MatrixXcd L    = m_rr.llt().matrixL();  | ||||
|   //  std::cout << " Called Cholesky  llt on m_rr "  << L <<std::endl; | ||||
|   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); | ||||
| } | ||||
| //////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
| // 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 == BlockCG ) { | ||||
|     BlockCGsolve(Linop,Src,Psi); | ||||
|   } else if (CGtype == CGmultiRHS ) { | ||||
|     CGmultiRHSsolve(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]; | ||||
|  | ||||
|   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;   | ||||
|   //std::cout << GridLogMessage << " initial tmp " << norm2(tmp)<< std::endl; | ||||
|   ThinQRfact (m_rr, m_C, m_Cinv, Q, tmp); | ||||
|   //std::cout << GridLogMessage << " initial Q " << norm2(Q)<< std::endl; | ||||
|   //std::cout << GridLogMessage << " m_rr " << m_rr<<std::endl; | ||||
|   //std::cout << GridLogMessage << " m_C " << m_C<<std::endl; | ||||
|   //std::cout << GridLogMessage << " m_Cinv " << m_Cinv<<std::endl; | ||||
|   D=Q; | ||||
|  | ||||
|   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(); | ||||
|     //std::cout << GridLogMessage << " norm2 Z " <<norm2(Z)<<std::endl; | ||||
|  | ||||
|     //4. M  = [D^dag Z]^{-1} | ||||
|     sliceInnerTimer.Start(); | ||||
|     sliceInnerProductMatrix(m_DZ,D,Z,Orthog); | ||||
|     sliceInnerTimer.Stop(); | ||||
|     m_M       = m_DZ.inverse(); | ||||
|     //std::cout << GridLogMessage << " m_DZ " <<m_DZ<<std::endl; | ||||
|      | ||||
|     //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; | ||||
| } | ||||
| ////////////////////////////////////////////////////////////////////////// | ||||
| // Block conjugate gradient; Original O'Leary Dimension zero should be the block direction | ||||
| ////////////////////////////////////////////////////////////////////////// | ||||
| void BlockCGsolve(LinearOperatorBase<Field> &Linop, const Field &Src, Field &Psi)  | ||||
| { | ||||
|   int Orthog = blockDim; // First dimension is block dim; this is an assumption | ||||
|   Nblock = Src._grid->_fdimensions[Orthog]; | ||||
|  | ||||
|   std::cout<<GridLogMessage<<" Block Conjugate Gradient : Orthog "<<Orthog<<" Nblock "<<Nblock<<std::endl; | ||||
|  | ||||
|   Psi.checkerboard = Src.checkerboard; | ||||
|   conformable(Psi, Src); | ||||
|  | ||||
|   Field P(Src); | ||||
|   Field AP(Src); | ||||
|   Field R(Src); | ||||
|    | ||||
|   Eigen::MatrixXcd m_pAp    = Eigen::MatrixXcd::Identity(Nblock,Nblock); | ||||
|   Eigen::MatrixXcd m_pAp_inv= Eigen::MatrixXcd::Identity(Nblock,Nblock); | ||||
|   Eigen::MatrixXcd m_rr     = Eigen::MatrixXcd::Zero(Nblock,Nblock); | ||||
|   Eigen::MatrixXcd m_rr_inv = Eigen::MatrixXcd::Zero(Nblock,Nblock); | ||||
|  | ||||
|   Eigen::MatrixXcd m_alpha      = Eigen::MatrixXcd::Zero(Nblock,Nblock); | ||||
|   Eigen::MatrixXcd m_beta   = Eigen::MatrixXcd::Zero(Nblock,Nblock); | ||||
|  | ||||
|   // Initial residual computation & set up | ||||
|   std::vector<RealD> residuals(Nblock); | ||||
|   std::vector<RealD> ssq(Nblock); | ||||
|  | ||||
|   sliceNorm(ssq,Src,Orthog); | ||||
|   RealD sssum=0; | ||||
|   for(int b=0;b<Nblock;b++) sssum+=ssq[b]; | ||||
|  | ||||
|   sliceNorm(residuals,Src,Orthog); | ||||
|   for(int b=0;b<Nblock;b++){ assert(std::isnan(residuals[b])==0); } | ||||
|  | ||||
|   sliceNorm(residuals,Psi,Orthog); | ||||
|   for(int b=0;b<Nblock;b++){ assert(std::isnan(residuals[b])==0); } | ||||
|  | ||||
|   // Initial search dir is guess | ||||
|   Linop.HermOp(Psi, AP); | ||||
|    | ||||
|  | ||||
|   /************************************************************************ | ||||
|    * Block conjugate gradient (Stephen Pickles, thesis 1995, pp 71, O Leary 1980) | ||||
|    ************************************************************************ | ||||
|    * O'Leary : R = B - A X | ||||
|    * O'Leary : P = M R ; preconditioner M = 1 | ||||
|    * O'Leary : alpha = PAP^{-1} RMR | ||||
|    * O'Leary : beta  = RMR^{-1}_old RMR_new | ||||
|    * O'Leary : X=X+Palpha | ||||
|    * O'Leary : R_new=R_old-AP alpha | ||||
|    * O'Leary : P=MR_new+P beta | ||||
|    */ | ||||
|  | ||||
|   R = Src - AP;   | ||||
|   P = R; | ||||
|   sliceInnerProductMatrix(m_rr,R,R,Orthog); | ||||
|  | ||||
|   GridStopWatch sliceInnerTimer; | ||||
|   GridStopWatch sliceMaddTimer; | ||||
|   GridStopWatch MatrixTimer; | ||||
|   GridStopWatch SolverTimer; | ||||
|   SolverTimer.Start(); | ||||
|  | ||||
|   int k; | ||||
|   for (k = 1; k <= MaxIterations; k++) { | ||||
|  | ||||
|     RealD rrsum=0; | ||||
|     for(int b=0;b<Nblock;b++) rrsum+=real(m_rr(b,b)); | ||||
|  | ||||
|     std::cout << GridLogIterative << "\titeration "<<k<<" rr_sum "<<rrsum<<" ssq_sum "<< sssum | ||||
| 	      <<" / "<<std::sqrt(rrsum/sssum) <<std::endl; | ||||
|  | ||||
|     MatrixTimer.Start(); | ||||
|     Linop.HermOp(P, AP); | ||||
|     MatrixTimer.Stop(); | ||||
|  | ||||
|     // Alpha | ||||
|     sliceInnerTimer.Start(); | ||||
|     sliceInnerProductMatrix(m_pAp,P,AP,Orthog); | ||||
|     sliceInnerTimer.Stop(); | ||||
|     m_pAp_inv = m_pAp.inverse(); | ||||
|     m_alpha   = m_pAp_inv * m_rr ; | ||||
|  | ||||
|     // Psi, R update | ||||
|     sliceMaddTimer.Start(); | ||||
|     sliceMaddMatrix(Psi,m_alpha, P,Psi,Orthog);     // add alpha *  P to psi | ||||
|     sliceMaddMatrix(R  ,m_alpha,AP,  R,Orthog,-1.0);// sub alpha * AP to resid | ||||
|     sliceMaddTimer.Stop(); | ||||
|  | ||||
|     // Beta | ||||
|     m_rr_inv = m_rr.inverse(); | ||||
|     sliceInnerTimer.Start(); | ||||
|     sliceInnerProductMatrix(m_rr,R,R,Orthog); | ||||
|     sliceInnerTimer.Stop(); | ||||
|     m_beta = m_rr_inv *m_rr; | ||||
|  | ||||
|     // Search update | ||||
|     sliceMaddTimer.Start(); | ||||
|     sliceMaddMatrix(AP,m_beta,P,R,Orthog); | ||||
|     sliceMaddTimer.Stop(); | ||||
|     P= AP; | ||||
|  | ||||
|     /********************* | ||||
|      * convergence monitor | ||||
|      ********************* | ||||
|      */ | ||||
|     RealD max_resid=0; | ||||
|     RealD rr; | ||||
|     for(int b=0;b<Nblock;b++){ | ||||
|       rr = real(m_rr(b,b))/ssq[b]; | ||||
|       if ( rr > max_resid ) max_resid = rr; | ||||
|     } | ||||
|      | ||||
|     if ( max_resid < Tolerance*Tolerance ) {  | ||||
|  | ||||
|       SolverTimer.Stop(); | ||||
|  | ||||
|       std::cout << GridLogMessage<<"BlockCG converged in "<<k<<" iterations"<<std::endl; | ||||
|       for(int b=0;b<Nblock;b++){ | ||||
| 	std::cout << GridLogMessage<< "\t\tblock "<<b<<" computed resid " | ||||
| 		  << std::sqrt(real(m_rr(b,b))/ssq[b])<<std::endl; | ||||
|       } | ||||
|       std::cout << GridLogMessage<<"\tMax residual is "<<std::sqrt(max_resid)<<std::endl; | ||||
|  | ||||
|       Linop.HermOp(Psi, AP); | ||||
|       AP = AP-Src; | ||||
|       std::cout << GridLogMessage <<"\t True residual is " << std::sqrt(norm2(AP)/norm2(Src)) <<std::endl; | ||||
|  | ||||
|       std::cout << GridLogMessage << "Time Breakdown "<<std::endl; | ||||
|       std::cout << GridLogMessage << "\tElapsed    " << SolverTimer.Elapsed()     <<std::endl; | ||||
|       std::cout << GridLogMessage << "\tMatrix     " << MatrixTimer.Elapsed()     <<std::endl; | ||||
|       std::cout << GridLogMessage << "\tInnerProd  " << sliceInnerTimer.Elapsed() <<std::endl; | ||||
|       std::cout << GridLogMessage << "\tMaddMatrix " << sliceMaddTimer.Elapsed()  <<std::endl; | ||||
| 	     | ||||
|       IterationsToComplete = k; | ||||
|       return; | ||||
|     } | ||||
|  | ||||
|   } | ||||
|   std::cout << GridLogMessage << "BlockConjugateGradient did NOT converge" << std::endl; | ||||
|  | ||||
|   if (ErrorOnNoConverge) assert(0); | ||||
|   IterationsToComplete = k; | ||||
| } | ||||
| ////////////////////////////////////////////////////////////////////////// | ||||
| // multiRHS conjugate gradient. Dimension zero should be the block direction | ||||
| // 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; | ||||
| } | ||||
|  | ||||
| }; | ||||
|  | ||||
| } | ||||
| #endif | ||||
							
								
								
									
										177
									
								
								Grid/algorithms/iterative/ConjugateGradient.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										177
									
								
								Grid/algorithms/iterative/ConjugateGradient.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,177 @@ | ||||
| /************************************************************************************* | ||||
|  | ||||
| Grid physics library, www.github.com/paboyle/Grid | ||||
|  | ||||
| Source file: ./lib/algorithms/iterative/ConjugateGradient.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 */ | ||||
| #ifndef GRID_CONJUGATE_GRADIENT_H | ||||
| #define GRID_CONJUGATE_GRADIENT_H | ||||
|  | ||||
| namespace Grid { | ||||
|  | ||||
| ///////////////////////////////////////////////////////////// | ||||
| // Base classes for iterative processes based on operators | ||||
| // single input vec, single output vec. | ||||
| ///////////////////////////////////////////////////////////// | ||||
|  | ||||
| template <class Field> | ||||
| class ConjugateGradient : public OperatorFunction<Field> { | ||||
|  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 | ||||
|    | ||||
|   ConjugateGradient(RealD tol, Integer maxit, bool err_on_no_conv = true) | ||||
|       : Tolerance(tol), | ||||
|         MaxIterations(maxit), | ||||
|         ErrorOnNoConverge(err_on_no_conv){}; | ||||
|  | ||||
|   void operator()(LinearOperatorBase<Field> &Linop, const Field &src, Field &psi) { | ||||
|  | ||||
|  | ||||
|     psi.checkerboard = src.checkerboard; | ||||
|     conformable(psi, src); | ||||
|  | ||||
|     RealD cp, c, a, d, b, ssq, qq, b_pred; | ||||
|  | ||||
|     Field p(src); | ||||
|     Field mmp(src); | ||||
|     Field r(src); | ||||
|  | ||||
|     // Initial residual computation & set up | ||||
|     RealD guess = norm2(psi); | ||||
|     assert(std::isnan(guess) == 0); | ||||
|  | ||||
|      | ||||
|     Linop.HermOpAndNorm(psi, mmp, d, b); | ||||
|  | ||||
|     r = src - mmp; | ||||
|     p = r; | ||||
|  | ||||
|     a = norm2(p); | ||||
|     cp = a; | ||||
|     ssq = norm2(src); | ||||
|  | ||||
|     std::cout << GridLogIterative << std::setprecision(8) << "ConjugateGradient: guess " << guess << std::endl; | ||||
|     std::cout << GridLogIterative << std::setprecision(8) << "ConjugateGradient:   src " << ssq << std::endl; | ||||
|     std::cout << GridLogIterative << std::setprecision(8) << "ConjugateGradient:    mp " << d << std::endl; | ||||
|     std::cout << GridLogIterative << std::setprecision(8) << "ConjugateGradient:   mmp " << b << std::endl; | ||||
|     std::cout << GridLogIterative << std::setprecision(8) << "ConjugateGradient:  cp,r " << cp << std::endl; | ||||
|     std::cout << GridLogIterative << std::setprecision(8) << "ConjugateGradient:     p " << a << std::endl; | ||||
|  | ||||
|     RealD rsq = Tolerance * Tolerance * ssq; | ||||
|  | ||||
|     // Check if guess is really REALLY good :) | ||||
|     if (cp <= rsq) { | ||||
|       return; | ||||
|     } | ||||
|  | ||||
|     std::cout << GridLogIterative << std::setprecision(8) | ||||
|               << "ConjugateGradient: k=0 residual " << cp << " target " << rsq << std::endl; | ||||
|  | ||||
|     GridStopWatch LinalgTimer; | ||||
|     GridStopWatch InnerTimer; | ||||
|     GridStopWatch AxpyNormTimer; | ||||
|     GridStopWatch LinearCombTimer; | ||||
|     GridStopWatch MatrixTimer; | ||||
|     GridStopWatch SolverTimer; | ||||
|  | ||||
|     SolverTimer.Start(); | ||||
|     int k; | ||||
|     for (k = 1; k <= MaxIterations*1000; k++) { | ||||
|       c = cp; | ||||
|  | ||||
|       MatrixTimer.Start(); | ||||
|       Linop.HermOp(p, mmp); | ||||
|       MatrixTimer.Stop(); | ||||
|  | ||||
|       LinalgTimer.Start(); | ||||
|  | ||||
|       InnerTimer.Start(); | ||||
|       ComplexD dc  = innerProduct(p,mmp); | ||||
|       InnerTimer.Stop(); | ||||
|       d = dc.real(); | ||||
|       a = c / d; | ||||
|  | ||||
|       AxpyNormTimer.Start(); | ||||
|       cp = axpy_norm(r, -a, mmp, r); | ||||
|       AxpyNormTimer.Stop(); | ||||
|       b = cp / c; | ||||
|  | ||||
|       LinearCombTimer.Start(); | ||||
|       parallel_for(int ss=0;ss<src._grid->oSites();ss++){ | ||||
| 	vstream(psi[ss], a      *  p[ss] + psi[ss]); | ||||
| 	vstream(p  [ss], b      *  p[ss] + r[ss]); | ||||
|       } | ||||
|       LinearCombTimer.Stop(); | ||||
|       LinalgTimer.Stop(); | ||||
|  | ||||
|       std::cout << GridLogIterative << "ConjugateGradient: Iteration " << k | ||||
|                 << " residual " << cp << " target " << rsq << std::endl; | ||||
|  | ||||
|       // Stopping condition | ||||
|       if (cp <= rsq) { | ||||
|         SolverTimer.Stop(); | ||||
|         Linop.HermOpAndNorm(psi, mmp, d, qq); | ||||
|         p = mmp - src; | ||||
|  | ||||
|         RealD srcnorm = sqrt(norm2(src)); | ||||
|         RealD resnorm = sqrt(norm2(p)); | ||||
|         RealD true_residual = resnorm / srcnorm; | ||||
|  | ||||
|         std::cout << GridLogMessage << "ConjugateGradient Converged on iteration " << k << std::endl; | ||||
|         std::cout << GridLogMessage << "\tComputed residual " << 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; | ||||
| 	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); | ||||
|  | ||||
| 	IterationsToComplete = k;	 | ||||
|  | ||||
|         return; | ||||
|       } | ||||
|     } | ||||
|     std::cout << GridLogMessage << "ConjugateGradient did NOT converge" | ||||
|               << std::endl; | ||||
|  | ||||
|     if (ErrorOnNoConverge) assert(0); | ||||
|     IterationsToComplete = k; | ||||
|  | ||||
|   } | ||||
| }; | ||||
| } | ||||
| #endif | ||||
							
								
								
									
										154
									
								
								Grid/algorithms/iterative/ConjugateGradientMixedPrec.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										154
									
								
								Grid/algorithms/iterative/ConjugateGradientMixedPrec.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,154 @@ | ||||
|     /************************************************************************************* | ||||
|  | ||||
|     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 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(); | ||||
|        | ||||
| 	zeroit(sol_f); | ||||
|  | ||||
| 	//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; | ||||
|     } | ||||
|   }; | ||||
|  | ||||
| } | ||||
|  | ||||
| #endif | ||||
| @@ -43,6 +43,7 @@ namespace Grid { | ||||
| public:                                                 | ||||
|     RealD   Tolerance; | ||||
|     Integer MaxIterations; | ||||
|     Integer IterationsToComplete; //Number of iterations the CG took to finish. Filled in upon completion
 | ||||
|     int verbose; | ||||
|     MultiShiftFunction shifts; | ||||
| 
 | ||||
| @@ -164,6 +165,15 @@ void operator() (LinearOperatorBase<Field> &Linop, const Field &src, std::vector | ||||
|     axpby(psi[s],0.,-bs[s]*alpha[s],src,src); | ||||
|   } | ||||
|   | ||||
|   ///////////////////////////////////////
 | ||||
|   // Timers
 | ||||
|   ///////////////////////////////////////
 | ||||
|   GridStopWatch AXPYTimer; | ||||
|   GridStopWatch ShiftTimer; | ||||
|   GridStopWatch QRTimer; | ||||
|   GridStopWatch MatrixTimer; | ||||
|   GridStopWatch SolverTimer; | ||||
|   SolverTimer.Start(); | ||||
|    | ||||
|   // Iteration loop
 | ||||
|   int k; | ||||
| @@ -171,7 +181,9 @@ void operator() (LinearOperatorBase<Field> &Linop, const Field &src, std::vector | ||||
|   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
 | ||||
| @@ -180,6 +192,7 @@ void operator() (LinearOperatorBase<Field> &Linop, const Field &src, std::vector | ||||
|     // 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){ | ||||
| @@ -190,22 +203,34 @@ void operator() (LinearOperatorBase<Field> &Linop, const Field &src, std::vector | ||||
| 	} | ||||
|       } | ||||
|     } | ||||
|     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)); | ||||
|      | ||||
|     Linop.HermOpAndNorm(p,mmp,d,qq); | ||||
|     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]; | ||||
| @@ -215,6 +240,7 @@ void operator() (LinearOperatorBase<Field> &Linop, const Field &src, std::vector | ||||
| 	bs[s] = b*z[s][iz]/z0; // NB sign  rel to Mike
 | ||||
|       } | ||||
|     } | ||||
|     ShiftTimer.Stop(); | ||||
|      | ||||
|     for(int s=0;s<nshift;s++){ | ||||
|       int ss = s; | ||||
| @@ -243,8 +269,6 @@ void operator() (LinearOperatorBase<Field> &Linop, const Field &src, std::vector | ||||
|       if ( (!converged[s]) ){ | ||||
| 	 | ||||
| 	RealD css  = c * z[s][iz]* z[s][iz]; | ||||
|     if((k%100)==0 && (s==0) ) | ||||
| 	    std::cout<<GridLogMessage<<"ConjugateGradientMultiShift k="<<k<<" css " <<css <<std::endl; | ||||
| 	 | ||||
| 	if(css<rsq[s]){ | ||||
| 	  if ( ! converged[s] ) | ||||
| @@ -259,6 +283,9 @@ void operator() (LinearOperatorBase<Field> &Linop, const Field &src, std::vector | ||||
|      | ||||
|     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; | ||||
|        | ||||
| @@ -271,8 +298,19 @@ void operator() (LinearOperatorBase<Field> &Linop, const Field &src, std::vector | ||||
| 	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; | ||||
							
								
								
									
										256
									
								
								Grid/algorithms/iterative/ConjugateGradientReliableUpdate.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										256
									
								
								Grid/algorithms/iterative/ConjugateGradientReliableUpdate.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,256 @@ | ||||
|     /************************************************************************************* | ||||
|  | ||||
|     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 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 " << 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 = sqrt(norm2(src)); | ||||
| 	  RealD resnorm = 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 " << 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;       | ||||
|     }     | ||||
|   }; | ||||
|  | ||||
|  | ||||
| }; | ||||
|  | ||||
|  | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										104
									
								
								Grid/algorithms/iterative/Deflation.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										104
									
								
								Grid/algorithms/iterative/Deflation.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,104 @@ | ||||
|     /************************************************************************************* | ||||
|  | ||||
|     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 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 | ||||
							
								
								
									
										842
									
								
								Grid/algorithms/iterative/ImplicitlyRestartedLanczos.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										842
									
								
								Grid/algorithms/iterative/ImplicitlyRestartedLanczos.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,842 @@ | ||||
|     /************************************************************************************* | ||||
|  | ||||
|     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 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 typename Field::vector_object vobj; | ||||
|   GridBase* grid = basis[0]._grid; | ||||
|        | ||||
|   parallel_region | ||||
|   { | ||||
|  | ||||
|     std::vector < vobj , commAllocator<vobj> > B(Nm); // Thread private | ||||
|         | ||||
|     parallel_for_internal(int ss=0;ss < grid->oSites();ss++){ | ||||
|       for(int j=j0; j<j1; ++j) B[j]=0.; | ||||
|        | ||||
|       for(int j=j0; j<j1; ++j){ | ||||
| 	for(int k=k0; k<k1; ++k){ | ||||
| 	  B[j] +=Qt(j,k) * basis[k]._odata[ss]; | ||||
| 	} | ||||
|       } | ||||
|       for(int j=j0; j<j1; ++j){ | ||||
| 	  basis[j]._odata[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; | ||||
|   parallel_for(int ss=0;ss < grid->oSites();ss++){ | ||||
|     vobj B = zero; | ||||
|     for(int k=k0; k<k1; ++k){ | ||||
|       B +=Qt(j,k) * basis[k]._odata[ss]; | ||||
|     } | ||||
|     result._odata[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); | ||||
|  | ||||
|       std::swap(_v[i]._odata,_v[idx[i]]._odata); // 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); | ||||
| } | ||||
|  | ||||
| ///////////////////////////////////////////////////////////// | ||||
| // 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 = 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"<<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 = 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 = 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(); | ||||
| } | ||||
| }; | ||||
| } | ||||
| #endif | ||||
							
								
								
									
										406
									
								
								Grid/algorithms/iterative/LocalCoherenceLanczos.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										406
									
								
								Grid/algorithms/iterative/LocalCoherenceLanczos.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,406 @@ | ||||
|     /************************************************************************************* | ||||
|  | ||||
|     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 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 < std::complex<double>  >, 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); src=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; | ||||
|     } | ||||
|   } | ||||
| }; | ||||
|  | ||||
| } | ||||
| #endif | ||||
							
								
								
									
										186
									
								
								Grid/algorithms/iterative/Reconstruct5Dprop.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										186
									
								
								Grid/algorithms/iterative/Reconstruct5Dprop.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,186 @@ | ||||
|     /************************************************************************************* | ||||
|  | ||||
|     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 */ | ||||
| #pragma once | ||||
|  | ||||
| namespace Grid { | ||||
| namespace QCD { | ||||
|  | ||||
|  | ||||
| template<class Field> | ||||
| class PauliVillarsSolverUnprec | ||||
| { | ||||
|  public: | ||||
|   ConjugateGradient<Field> & CG; | ||||
|   PauliVillarsSolverUnprec(  ConjugateGradient<Field> &_CG) : CG(_CG){}; | ||||
|  | ||||
|   template<class Matrix> | ||||
|   void operator() (Matrix &_Matrix,const Field &src,Field &sol) | ||||
|   { | ||||
|     RealD m = _Matrix.Mass(); | ||||
|     Field A  (_Matrix.FermionGrid()); | ||||
|  | ||||
|     MdagMLinearOperator<Matrix,Field> HermOp(_Matrix); | ||||
|  | ||||
|     _Matrix.SetMass(1.0); | ||||
|     _Matrix.Mdag(src,A); | ||||
|     CG(HermOp,A,sol); | ||||
|     _Matrix.SetMass(m); | ||||
|   }; | ||||
| }; | ||||
|  | ||||
| template<class Field> | ||||
| class PauliVillarsSolverRBprec | ||||
| { | ||||
|  public: | ||||
|   ConjugateGradient<Field> & CG; | ||||
|   PauliVillarsSolverRBprec(  ConjugateGradient<Field> &_CG) : CG(_CG){}; | ||||
|  | ||||
|   template<class Matrix> | ||||
|   void operator() (Matrix &_Matrix,const Field &src,Field &sol) | ||||
|   { | ||||
|     RealD m = _Matrix.Mass(); | ||||
|     Field A  (_Matrix.FermionGrid()); | ||||
|  | ||||
|     _Matrix.SetMass(1.0); | ||||
|     SchurRedBlackDiagMooeeSolve<Field> SchurSolver(CG); | ||||
|     SchurSolver(_Matrix,src,sol); | ||||
|     _Matrix.SetMass(m); | ||||
|   }; | ||||
| }; | ||||
|  | ||||
| template<class Field,class PVinverter> class Reconstruct5DfromPhysical { | ||||
|  private: | ||||
|   PVinverter & PauliVillarsSolver; | ||||
|  public: | ||||
|  | ||||
|  ///////////////////////////////////////////////////// | ||||
|  // First cut works, 10 Oct 2018. | ||||
|  // | ||||
|  // Must form a plan to get this into production for Zmobius acceleration | ||||
|  // of the Mobius exact AMA corrections. | ||||
|  // | ||||
|  // TODO : understand absence of contact term in eqns in Hantao's thesis | ||||
|  //        sol4 is contact term subtracted. | ||||
|  // | ||||
|  // Options | ||||
|  // a) Defect correction approach: | ||||
|  //    1) Compute defect from current soln (initially guess). | ||||
|  //       This is ...... outerToInner check !!!! | ||||
|  //    2) Deflated Zmobius solve to get 4d soln | ||||
|  //       Ensure deflation is working | ||||
|  //    3) Refine 5d Outer using the inner 4d delta soln | ||||
|  //  | ||||
|  // Step 1: localise PV inverse in a routine. [DONE] | ||||
|  // Step 2: Schur based PV inverse            [DONE] | ||||
|  // Step 3: Fourier accelerated PV inverse | ||||
|  // Step 4:  | ||||
|  ///////////////////////////////////////////////////// | ||||
|   | ||||
|   Reconstruct5DfromPhysical(PVinverter &_PauliVillarsSolver)  | ||||
|     : PauliVillarsSolver(_PauliVillarsSolver)  | ||||
|   {  | ||||
|   }; | ||||
|  | ||||
|  | ||||
|    template<class Matrix> | ||||
|    void PV(Matrix &_Matrix,const Field &src,Field &sol) | ||||
|    { | ||||
|      RealD m = _Matrix.Mass(); | ||||
|      _Matrix.SetMass(1.0); | ||||
|      _Matrix.M(src,sol); | ||||
|      _Matrix.SetMass(m); | ||||
|    } | ||||
|    template<class Matrix> | ||||
|    void PVdag(Matrix &_Matrix,const Field &src,Field &sol) | ||||
|    { | ||||
|      RealD m = _Matrix.Mass(); | ||||
|      _Matrix.SetMass(1.0); | ||||
|      _Matrix.Mdag(src,sol); | ||||
|      _Matrix.SetMass(m); | ||||
|    } | ||||
|   template<class Matrix> | ||||
|   void operator() (Matrix & _Matrix,const Field &sol4,const Field &src4, Field &sol5){ | ||||
|  | ||||
|     int Ls =  _Matrix.Ls; | ||||
|  | ||||
|     Field psi4(_Matrix.GaugeGrid()); | ||||
|     Field psi(_Matrix.FermionGrid()); | ||||
|     Field A  (_Matrix.FermionGrid()); | ||||
|     Field B  (_Matrix.FermionGrid()); | ||||
|     Field c  (_Matrix.FermionGrid()); | ||||
|  | ||||
|     typedef typename Matrix::Coeff_t Coeff_t; | ||||
|  | ||||
|     std::cout << GridLogMessage<< " ************************************************" << std::endl; | ||||
|     std::cout << GridLogMessage<< " Reconstruct5Dprop: c.f. MADWF algorithm         " << std::endl; | ||||
|     std::cout << GridLogMessage<< " ************************************************" << std::endl; | ||||
|  | ||||
|     /////////////////////////////////////// | ||||
|     //Import source, include Dminus factors | ||||
|     /////////////////////////////////////// | ||||
|     _Matrix.ImportPhysicalFermionSource(src4,B);  | ||||
|  | ||||
|     /////////////////////////////////////// | ||||
|     // Set up c from src4 | ||||
|     /////////////////////////////////////// | ||||
|     PauliVillarsSolver(_Matrix,B,A); | ||||
|     _Matrix.Pdag(A,c); | ||||
|  | ||||
|     ////////////////////////////////////// | ||||
|     // Build Pdag PV^-1 Dm P [-sol4,c2,c3... cL] | ||||
|     ////////////////////////////////////// | ||||
|     psi4 = - sol4; | ||||
|     InsertSlice(psi4, psi, 0   , 0); | ||||
|     for (int s=1;s<Ls;s++) { | ||||
|       ExtractSlice(psi4,c,s,0); | ||||
|        InsertSlice(psi4,psi,s,0); | ||||
|     } | ||||
|  | ||||
|     ///////////////////////////// | ||||
|     // Pdag PV^-1 Dm P  | ||||
|     ///////////////////////////// | ||||
|     _Matrix.P(psi,B); | ||||
|     _Matrix.M(B,A); | ||||
|     PauliVillarsSolver(_Matrix,A,B); | ||||
|     _Matrix.Pdag(B,A); | ||||
|  | ||||
|     ////////////////////////////// | ||||
|     // Reinsert surface prop | ||||
|     ////////////////////////////// | ||||
|     InsertSlice(sol4,A,0,0); | ||||
|  | ||||
|     ////////////////////////////// | ||||
|     // Convert from y back to x  | ||||
|     ////////////////////////////// | ||||
|     _Matrix.P(A,sol5); | ||||
|      | ||||
|   } | ||||
| }; | ||||
|  | ||||
| } | ||||
| } | ||||
							
								
								
									
										503
									
								
								Grid/algorithms/iterative/SchurRedBlack.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										503
									
								
								Grid/algorithms/iterative/SchurRedBlack.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,503 @@ | ||||
|     /************************************************************************************* | ||||
|  | ||||
|     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 { | ||||
|  | ||||
|   /////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
|   // Take a matrix and form a Red Black solver calling a Herm solver | ||||
|   // Use of RB info prevents making SchurRedBlackSolve conform to standard interface | ||||
|   /////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
|   // Now make the norm reflect extra factor of Mee | ||||
|   template<class Field> class SchurRedBlackStaggeredSolve { | ||||
|   private: | ||||
|     OperatorFunction<Field> & _HermitianRBSolver; | ||||
|     int CBfactorise; | ||||
|     bool subGuess; | ||||
|   public: | ||||
|  | ||||
|     ///////////////////////////////////////////////////// | ||||
|     // Wrap the usual normal equations Schur trick | ||||
|     ///////////////////////////////////////////////////// | ||||
|   SchurRedBlackStaggeredSolve(OperatorFunction<Field> &HermitianRBSolver, const bool initSubGuess = false)  : | ||||
|      _HermitianRBSolver(HermitianRBSolver)  | ||||
|     {  | ||||
|       CBfactorise=0; | ||||
|       subtractGuess(initSubGuess); | ||||
|     }; | ||||
|     void subtractGuess(const bool initSubGuess) | ||||
|     { | ||||
|       subGuess = initSubGuess; | ||||
|     } | ||||
|     bool isSubtractGuess(void) | ||||
|     { | ||||
|       return subGuess; | ||||
|     } | ||||
|  | ||||
|     template<class Matrix> | ||||
|     void operator() (Matrix & _Matrix,const Field &in, Field &out){ | ||||
|       ZeroGuesser<Field> guess; | ||||
|       (*this)(_Matrix,in,out,guess); | ||||
|     } | ||||
|     template<class Matrix, 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(); | ||||
|  | ||||
|       SchurStaggeredOperator<Matrix,Field> _HermOpEO(_Matrix); | ||||
|   | ||||
|       Field src_e(grid); | ||||
|       Field src_o(grid); | ||||
|       Field sol_e(grid); | ||||
|       Field sol_o(grid); | ||||
|       Field   tmp(grid); | ||||
|       Field  Mtmp(grid); | ||||
|       Field resid(fgrid); | ||||
|        | ||||
|       std::cout << GridLogMessage << " SchurRedBlackStaggeredSolve " <<std::endl; | ||||
|       pickCheckerboard(Even,src_e,in); | ||||
|       pickCheckerboard(Odd ,src_o,in); | ||||
|       pickCheckerboard(Even,sol_e,out); | ||||
|       pickCheckerboard(Odd ,sol_o,out); | ||||
|       std::cout << GridLogMessage << " SchurRedBlackStaggeredSolve checkerboards picked" <<std::endl; | ||||
|      | ||||
|       ///////////////////////////////////////////////////// | ||||
|       // 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);      | ||||
|  | ||||
|       //src_o = tmp;     assert(src_o.checkerboard ==Odd); | ||||
|       _Matrix.Mooee(tmp,src_o); // Extra factor of "m" in source from dumb choice of matrix norm. | ||||
|  | ||||
|       ////////////////////////////////////////////////////////////// | ||||
|       // Call the red-black solver | ||||
|       ////////////////////////////////////////////////////////////// | ||||
|       std::cout<<GridLogMessage << "SchurRedBlackStaggeredSolver calling the Mpc solver" <<std::endl; | ||||
|       guess(src_o, sol_o); | ||||
|       Mtmp = sol_o; | ||||
|       _HermitianRBSolver(_HermOpEO,src_o,sol_o);  assert(sol_o.checkerboard==Odd); | ||||
|       std::cout<<GridLogMessage << "SchurRedBlackStaggeredSolver called  the Mpc solver" <<std::endl; | ||||
|       // Fionn A2A boolean behavioural control | ||||
|       if (subGuess)        sol_o = sol_o-Mtmp; | ||||
|  | ||||
|       /////////////////////////////////////////////////// | ||||
|       // 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); | ||||
|       | ||||
|       std::cout<<GridLogMessage << "SchurRedBlackStaggeredSolver reconstructed other CB" <<std::endl; | ||||
|       setCheckerboard(out,sol_e); assert(  sol_e.checkerboard ==Even); | ||||
|       setCheckerboard(out,sol_o); assert(  sol_o.checkerboard ==Odd ); | ||||
|       std::cout<<GridLogMessage << "SchurRedBlackStaggeredSolver inserted solution" <<std::endl; | ||||
|  | ||||
|       // Verify the unprec residual | ||||
|       if ( ! subGuess ) { | ||||
|         _Matrix.M(out,resid);  | ||||
|         resid = resid-in; | ||||
|         RealD ns = norm2(in); | ||||
|         RealD nr = norm2(resid); | ||||
|         std::cout<<GridLogMessage << "SchurRedBlackStaggered solver true unprec resid "<< std::sqrt(nr/ns) <<" nr "<< nr <<" ns "<<ns << std::endl; | ||||
|       } else { | ||||
|         std::cout << GridLogMessage << "Guess subtracted after solve." << std::endl; | ||||
|       } | ||||
|     }      | ||||
|   }; | ||||
|   template<class Field> using SchurRedBlackStagSolve = SchurRedBlackStaggeredSolve<Field>; | ||||
|  | ||||
|   /////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
|   // 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 SchurRedBlackDiagMooeeSolve { | ||||
|   private: | ||||
|     OperatorFunction<Field> & _HermitianRBSolver; | ||||
|     int CBfactorise; | ||||
|     bool subGuess; | ||||
|   public: | ||||
|  | ||||
|     ///////////////////////////////////////////////////// | ||||
|     // Wrap the usual normal equations Schur trick | ||||
|     ///////////////////////////////////////////////////// | ||||
|   SchurRedBlackDiagMooeeSolve(OperatorFunction<Field> &HermitianRBSolver,int cb=0, const bool initSubGuess = false)  :  _HermitianRBSolver(HermitianRBSolver)  | ||||
|   {  | ||||
|     CBfactorise=cb; | ||||
|     subtractGuess(initSubGuess); | ||||
|   }; | ||||
|     void subtractGuess(const bool initSubGuess) | ||||
|     { | ||||
|       subGuess = initSubGuess; | ||||
|     } | ||||
|     bool isSubtractGuess(void) | ||||
|     { | ||||
|       return subGuess; | ||||
|     } | ||||
|     template<class Matrix> | ||||
|     void operator() (Matrix & _Matrix,const Field &in, Field &out){ | ||||
|       ZeroGuesser<Field> guess; | ||||
|       (*this)(_Matrix,in,out,guess); | ||||
|     } | ||||
|     template<class Matrix, 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(); | ||||
|  | ||||
|       SchurDiagMooeeOperator<Matrix,Field> _HermOpEO(_Matrix); | ||||
|   | ||||
|       Field src_e(grid); | ||||
|       Field src_o(grid); | ||||
|       Field sol_e(grid); | ||||
|       Field sol_o(grid); | ||||
|       Field   tmp(grid); | ||||
|       Field  Mtmp(grid); | ||||
|       Field resid(fgrid); | ||||
|  | ||||
|       pickCheckerboard(Even,src_e,in); | ||||
|       pickCheckerboard(Odd ,src_o,in); | ||||
|       pickCheckerboard(Even,sol_e,out); | ||||
|       pickCheckerboard(Odd ,sol_o,out); | ||||
|      | ||||
|       ///////////////////////////////////////////////////// | ||||
|       // 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);        | ||||
|  | ||||
|       ////////////////////////////////////////////////////////////// | ||||
|       // Call the red-black solver | ||||
|       ////////////////////////////////////////////////////////////// | ||||
|       std::cout<<GridLogMessage << "SchurRedBlack solver calling the MpcDagMp solver" <<std::endl; | ||||
|       guess(src_o,sol_o); | ||||
|       Mtmp = sol_o; | ||||
|       _HermitianRBSolver(_HermOpEO,src_o,sol_o);  assert(sol_o.checkerboard==Odd); | ||||
|       // Fionn A2A boolean behavioural control | ||||
|       if (subGuess)        sol_o = sol_o-Mtmp; | ||||
|  | ||||
|       /////////////////////////////////////////////////// | ||||
|       // 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(out,sol_e); assert(  sol_e.checkerboard ==Even); | ||||
|       setCheckerboard(out,sol_o); assert(  sol_o.checkerboard ==Odd ); | ||||
|  | ||||
|       // Verify the unprec residual | ||||
|       if ( ! subGuess ) { | ||||
|         _Matrix.M(out,resid);  | ||||
|         resid = resid-in; | ||||
|         RealD ns = norm2(in); | ||||
|         RealD nr = norm2(resid); | ||||
|  | ||||
|         std::cout<<GridLogMessage << "SchurRedBlackDiagMooee solver true unprec resid "<< std::sqrt(nr/ns) <<" nr "<< nr <<" ns "<<ns << std::endl; | ||||
|       } else { | ||||
|         std::cout << GridLogMessage << "Guess subtracted after solve." << std::endl; | ||||
|       } | ||||
|     }      | ||||
|   }; | ||||
|  | ||||
|  | ||||
|   /////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
|   // 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 SchurRedBlackDiagTwoSolve { | ||||
|   private: | ||||
|     OperatorFunction<Field> & _HermitianRBSolver; | ||||
|     int CBfactorise; | ||||
|     bool subGuess; | ||||
|   public: | ||||
|  | ||||
|     ///////////////////////////////////////////////////// | ||||
|     // Wrap the usual normal equations Schur trick | ||||
|     ///////////////////////////////////////////////////// | ||||
|   SchurRedBlackDiagTwoSolve(OperatorFunction<Field> &HermitianRBSolver, const bool initSubGuess = false)  : | ||||
|      _HermitianRBSolver(HermitianRBSolver)  | ||||
|     {  | ||||
|       CBfactorise = 0; | ||||
|       subtractGuess(initSubGuess); | ||||
|     }; | ||||
|     void subtractGuess(const bool initSubGuess) | ||||
|     { | ||||
|       subGuess = initSubGuess; | ||||
|     } | ||||
|     bool isSubtractGuess(void) | ||||
|     { | ||||
|       return subGuess; | ||||
|     } | ||||
|  | ||||
|     template<class Matrix> | ||||
|     void operator() (Matrix & _Matrix,const Field &in, Field &out){ | ||||
|       ZeroGuesser<Field> guess; | ||||
|       (*this)(_Matrix,in,out,guess); | ||||
|     } | ||||
|     template<class Matrix,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(); | ||||
|  | ||||
|       SchurDiagTwoOperator<Matrix,Field> _HermOpEO(_Matrix); | ||||
|   | ||||
|       Field src_e(grid); | ||||
|       Field src_o(grid); | ||||
|       Field sol_e(grid); | ||||
|       Field sol_o(grid); | ||||
|       Field   tmp(grid); | ||||
|       Field  Mtmp(grid); | ||||
|       Field resid(fgrid); | ||||
|  | ||||
|       pickCheckerboard(Even,src_e,in); | ||||
|       pickCheckerboard(Odd ,src_o,in); | ||||
|       pickCheckerboard(Even,sol_e,out); | ||||
|       pickCheckerboard(Odd ,sol_o,out); | ||||
|      | ||||
|       ///////////////////////////////////////////////////// | ||||
|       // 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);        | ||||
|  | ||||
|       ////////////////////////////////////////////////////////////// | ||||
|       // Call the red-black solver | ||||
|       ////////////////////////////////////////////////////////////// | ||||
|       std::cout<<GridLogMessage << "SchurRedBlack solver calling the MpcDagMp solver" <<std::endl; | ||||
| //      _HermitianRBSolver(_HermOpEO,src_o,sol_o);  assert(sol_o.checkerboard==Odd); | ||||
|       guess(src_o,tmp); | ||||
|       Mtmp = tmp; | ||||
|       _HermitianRBSolver(_HermOpEO,src_o,tmp);  assert(tmp.checkerboard==Odd); | ||||
|       // Fionn A2A boolean behavioural control | ||||
|       if (subGuess)      tmp = tmp-Mtmp; | ||||
|       _Matrix.MooeeInv(tmp,sol_o);       assert(  sol_o.checkerboard   ==Odd); | ||||
|  | ||||
|       /////////////////////////////////////////////////// | ||||
|       // 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(out,sol_e); assert(  sol_e.checkerboard ==Even); | ||||
|       setCheckerboard(out,sol_o); assert(  sol_o.checkerboard ==Odd ); | ||||
|  | ||||
|       // Verify the unprec residual | ||||
|       if ( ! subGuess ) { | ||||
|         _Matrix.M(out,resid);  | ||||
|         resid = resid-in; | ||||
|         RealD ns = norm2(in); | ||||
|         RealD nr = norm2(resid); | ||||
|  | ||||
|         std::cout<<GridLogMessage << "SchurRedBlackDiagTwo solver true unprec resid "<< std::sqrt(nr/ns) <<" nr "<< nr <<" ns "<<ns << std::endl; | ||||
|       } else { | ||||
|         std::cout << GridLogMessage << "Guess subtracted after solve." << std::endl; | ||||
|       } | ||||
|     }      | ||||
|   }; | ||||
|   /////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
|   // 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 SchurRedBlackDiagTwoMixed { | ||||
|   private: | ||||
|     LinearFunction<Field> & _HermitianRBSolver; | ||||
|     int CBfactorise; | ||||
|     bool subGuess; | ||||
|   public: | ||||
|  | ||||
|     ///////////////////////////////////////////////////// | ||||
|     // Wrap the usual normal equations Schur trick | ||||
|     ///////////////////////////////////////////////////// | ||||
|   SchurRedBlackDiagTwoMixed(LinearFunction<Field> &HermitianRBSolver, const bool initSubGuess = false)  : | ||||
|      _HermitianRBSolver(HermitianRBSolver)  | ||||
|     {  | ||||
|       CBfactorise=0; | ||||
|       subtractGuess(initSubGuess); | ||||
|     }; | ||||
|     void subtractGuess(const bool initSubGuess) | ||||
|     { | ||||
|       subGuess = initSubGuess; | ||||
|     } | ||||
|     bool isSubtractGuess(void) | ||||
|     { | ||||
|       return subGuess; | ||||
|     } | ||||
|  | ||||
|     template<class Matrix> | ||||
|     void operator() (Matrix & _Matrix,const Field &in, Field &out){ | ||||
|       ZeroGuesser<Field> guess; | ||||
|       (*this)(_Matrix,in,out,guess); | ||||
|     } | ||||
|     template<class Matrix, 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(); | ||||
|  | ||||
|       SchurDiagTwoOperator<Matrix,Field> _HermOpEO(_Matrix); | ||||
|   | ||||
|       Field src_e(grid); | ||||
|       Field src_o(grid); | ||||
|       Field sol_e(grid); | ||||
|       Field sol_o(grid); | ||||
|       Field   tmp(grid); | ||||
|       Field  Mtmp(grid); | ||||
|       Field resid(fgrid); | ||||
|  | ||||
|       pickCheckerboard(Even,src_e,in); | ||||
|       pickCheckerboard(Odd ,src_o,in); | ||||
|       pickCheckerboard(Even,sol_e,out); | ||||
|       pickCheckerboard(Odd ,sol_o,out); | ||||
|      | ||||
|       ///////////////////////////////////////////////////// | ||||
|       // 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);        | ||||
|  | ||||
|       ////////////////////////////////////////////////////////////// | ||||
|       // Call the red-black solver | ||||
|       ////////////////////////////////////////////////////////////// | ||||
|       std::cout<<GridLogMessage << "SchurRedBlack solver calling the MpcDagMp solver" <<std::endl; | ||||
| //      _HermitianRBSolver(_HermOpEO,src_o,sol_o);  assert(sol_o.checkerboard==Odd); | ||||
| //      _HermitianRBSolver(_HermOpEO,src_o,tmp);  assert(tmp.checkerboard==Odd); | ||||
|       guess(src_o,tmp); | ||||
|       Mtmp = tmp; | ||||
|       _HermitianRBSolver(_HermOpEO,src_o,tmp);  assert(tmp.checkerboard==Odd); | ||||
|       // Fionn A2A boolean behavioural control | ||||
|       if (subGuess)      tmp = tmp-Mtmp; | ||||
|       _Matrix.MooeeInv(tmp,sol_o);        assert(  sol_o.checkerboard   ==Odd); | ||||
|  | ||||
|       /////////////////////////////////////////////////// | ||||
|       // 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(out,sol_e); assert(  sol_e.checkerboard ==Even); | ||||
|       setCheckerboard(out,sol_o); assert(  sol_o.checkerboard ==Odd ); | ||||
|  | ||||
|       // Verify the unprec residual | ||||
|       if ( ! subGuess ) { | ||||
|         _Matrix.M(out,resid);  | ||||
|         resid = resid-in; | ||||
|         RealD ns = norm2(in); | ||||
|         RealD nr = norm2(resid); | ||||
|  | ||||
|         std::cout << GridLogMessage << "SchurRedBlackDiagTwo solver true unprec resid " << std::sqrt(nr / ns) << " nr " << nr << " ns " << ns << std::endl; | ||||
|       } else { | ||||
|         std::cout << GridLogMessage << "Guess subtracted after solve." << std::endl; | ||||
|       } | ||||
|     }      | ||||
|   }; | ||||
|  | ||||
| } | ||||
| #endif | ||||
							
								
								
									
										125
									
								
								Grid/allocator/AlignedAllocator.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										125
									
								
								Grid/allocator/AlignedAllocator.cc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,125 @@ | ||||
| #include <Grid/GridCore.h> | ||||
| #include <fcntl.h> | ||||
|  | ||||
| namespace Grid { | ||||
|  | ||||
| MemoryStats *MemoryProfiler::stats = nullptr; | ||||
| bool         MemoryProfiler::debug = false; | ||||
|  | ||||
| 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 _OPENMP | ||||
|   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; | ||||
| } | ||||
|  | ||||
|  | ||||
| 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); | ||||
| } | ||||
|  | ||||
| } | ||||
							
								
								
									
										315
									
								
								Grid/allocator/AlignedAllocator.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										315
									
								
								Grid/allocator/AlignedAllocator.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,315 @@ | ||||
| /************************************************************************************* | ||||
|  | ||||
|     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 | ||||
|  | ||||
| namespace Grid { | ||||
|  | ||||
|   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) ; | ||||
|  | ||||
|   }; | ||||
|    | ||||
|   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); | ||||
|  | ||||
|     _Tp *ptr = (_Tp *) PointerCache::Lookup(bytes); | ||||
|     //    if ( ptr != NULL )  | ||||
|     //      std::cout << "alignedAllocator "<<__n << " cache hit "<< std::hex << ptr <<std::dec <<std::endl; | ||||
|  | ||||
|     ////////////////// | ||||
|     // Hack 2MB align; could make option probably doesn't need configurability | ||||
|     ////////////////// | ||||
| //define GRID_ALLOC_ALIGN (128) | ||||
| #define GRID_ALLOC_ALIGN (2*1024*1024) | ||||
| #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 | ||||
|     //    std::cout << "alignedAllocator " << std::hex << ptr <<std::dec <<std::endl; | ||||
|     // First touch optimise in threaded loop | ||||
|     uint8_t *cp = (uint8_t *)ptr; | ||||
| #ifdef GRID_OMP | ||||
| #pragma omp parallel for | ||||
| #endif | ||||
|     for(size_type n=0;n<bytes;n+=4096){ | ||||
|       cp[n]=0; | ||||
|     } | ||||
|     return ptr; | ||||
|   } | ||||
|  | ||||
|   void deallocate(pointer __p, size_type __n) {  | ||||
|     size_type bytes = __n * sizeof(_Tp); | ||||
|  | ||||
|     profilerFree(bytes); | ||||
|  | ||||
|     pointer __freeme = (pointer)PointerCache::Insert((void *)__p,bytes); | ||||
|  | ||||
| #ifdef HAVE_MM_MALLOC_H | ||||
|     if ( __freeme ) _mm_free((void *)__freeme);  | ||||
| #else | ||||
|     if ( __freeme ) free((void *)__freeme); | ||||
| #endif | ||||
|   } | ||||
|   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; } | ||||
|  | ||||
| ////////////////////////////////////////////////////////////////////////////////////////// | ||||
| // MPI3 : comms must use shm region | ||||
| // SHMEM: comms must use symmetric heap | ||||
| ////////////////////////////////////////////////////////////////////////////////////////// | ||||
| #ifdef GRID_COMMS_SHMEM | ||||
| extern "C" {  | ||||
| #include <mpp/shmem.h> | ||||
| extern void * shmem_align(size_t, size_t); | ||||
| extern void  shmem_free(void *); | ||||
| } | ||||
| #define PARANOID_SYMMETRIC_HEAP | ||||
| #endif | ||||
|  | ||||
| template<typename _Tp> | ||||
| class commAllocator { | ||||
| 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 commAllocator<_Tp1> other; }; | ||||
|   commAllocator() throw() { } | ||||
|   commAllocator(const commAllocator&) throw() { } | ||||
|   template<typename _Tp1> commAllocator(const commAllocator<_Tp1>&) throw() { } | ||||
|   ~commAllocator() throw() { } | ||||
|   pointer       address(reference __x)       const { return &__x; } | ||||
|   size_type  max_size() const throw() { return size_t(-1) / sizeof(_Tp); } | ||||
|  | ||||
| #ifdef GRID_COMMS_SHMEM | ||||
|   pointer allocate(size_type __n, const void* _p= 0) | ||||
|   { | ||||
|     size_type bytes = __n*sizeof(_Tp); | ||||
|  | ||||
|     profilerAllocate(bytes); | ||||
| #ifdef CRAY | ||||
|     _Tp *ptr = (_Tp *) shmem_align(bytes,64); | ||||
| #else | ||||
|     _Tp *ptr = (_Tp *) shmem_align(64,bytes); | ||||
| #endif | ||||
| #ifdef PARANOID_SYMMETRIC_HEAP | ||||
|     static void * bcast; | ||||
|     static long  psync[_SHMEM_REDUCE_SYNC_SIZE]; | ||||
|  | ||||
|     bcast = (void *) ptr; | ||||
|     shmem_broadcast32((void *)&bcast,(void *)&bcast,sizeof(void *)/4,0,0,0,shmem_n_pes(),psync); | ||||
|  | ||||
|     if ( bcast != ptr ) { | ||||
|       std::printf("inconsistent alloc pe %d %lx %lx \n",shmem_my_pe(),bcast,ptr);std::fflush(stdout); | ||||
|       //      BACKTRACEFILE(); | ||||
|       exit(0); | ||||
|     } | ||||
|     assert( bcast == (void *) ptr); | ||||
| #endif  | ||||
|     return ptr; | ||||
|   } | ||||
|   void deallocate(pointer __p, size_type __n) {  | ||||
|     size_type bytes = __n*sizeof(_Tp); | ||||
|  | ||||
|     profilerFree(bytes); | ||||
|     shmem_free((void *)__p); | ||||
|   } | ||||
| #else | ||||
|   pointer allocate(size_type __n, const void* _p= 0)  | ||||
|   { | ||||
|     size_type bytes = __n*sizeof(_Tp); | ||||
|      | ||||
|     profilerAllocate(bytes); | ||||
| #ifdef HAVE_MM_MALLOC_H | ||||
|     _Tp * ptr = (_Tp *) _mm_malloc(bytes, GRID_ALLOC_ALIGN); | ||||
| #else | ||||
|     _Tp * ptr = (_Tp *) memalign(GRID_ALLOC_ALIGN, bytes); | ||||
| #endif | ||||
|     uint8_t *cp = (uint8_t *)ptr; | ||||
|     if ( ptr ) {  | ||||
|     // One touch per 4k page, static OMP loop to catch same loop order | ||||
| #ifdef GRID_OMP | ||||
| #pragma omp parallel for schedule(static) | ||||
| #endif | ||||
|       for(size_type n=0;n<bytes;n+=4096){ | ||||
| 	cp[n]=0; | ||||
|       } | ||||
|     } | ||||
|     return ptr; | ||||
|   } | ||||
|   void deallocate(pointer __p, size_type __n) { | ||||
|     size_type bytes = __n*sizeof(_Tp); | ||||
|  | ||||
|     profilerFree(bytes); | ||||
| #ifdef HAVE_MM_MALLOC_H | ||||
|     _mm_free((void *)__p);  | ||||
| #else | ||||
|     free((void *)__p); | ||||
| #endif | ||||
|   } | ||||
| #endif | ||||
|   void construct(pointer __p, const _Tp& __val) { }; | ||||
|   void construct(pointer __p) { }; | ||||
|   void destroy(pointer __p) { }; | ||||
| }; | ||||
| template<typename _Tp>  inline bool operator==(const commAllocator<_Tp>&, const commAllocator<_Tp>&){ return true; } | ||||
| template<typename _Tp>  inline bool operator!=(const commAllocator<_Tp>&, const commAllocator<_Tp>&){ return false; } | ||||
|  | ||||
| //////////////////////////////////////////////////////////////////////////////// | ||||
| // Template typedefs | ||||
| //////////////////////////////////////////////////////////////////////////////// | ||||
| template<class T> using Vector     = std::vector<T,alignedAllocator<T> >;            | ||||
| template<class T> using commVector = std::vector<T,commAllocator<T> >;               | ||||
| template<class T> using Matrix     = std::vector<std::vector<T,alignedAllocator<T> > >; | ||||
|      | ||||
| }; // namespace Grid | ||||
| #endif | ||||
| @@ -28,8 +28,8 @@ Author: Peter Boyle <paboyle@ph.ed.ac.uk> | ||||
| #ifndef GRID_CARTESIAN_H | ||||
| #define GRID_CARTESIAN_H | ||||
| 
 | ||||
| #include <cartesian/Cartesian_base.h> | ||||
| #include <cartesian/Cartesian_full.h> | ||||
| #include <cartesian/Cartesian_red_black.h>  | ||||
| #include <Grid/cartesian/Cartesian_base.h> | ||||
| #include <Grid/cartesian/Cartesian_full.h> | ||||
| #include <Grid/cartesian/Cartesian_red_black.h>  | ||||
| 
 | ||||
| #endif | ||||
| @@ -6,8 +6,9 @@ | ||||
| 
 | ||||
|     Copyright (C) 2015 | ||||
| 
 | ||||
| Author: Peter Boyle <paboyle@ph.ed.ac.uk> | ||||
| Author: paboyle <paboyle@ph.ed.ac.uk> | ||||
|     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 | ||||
| @@ -29,7 +30,6 @@ Author: paboyle <paboyle@ph.ed.ac.uk> | ||||
| #ifndef GRID_CARTESIAN_BASE_H | ||||
| #define GRID_CARTESIAN_BASE_H | ||||
| 
 | ||||
| #include <Grid.h> | ||||
| 
 | ||||
| namespace Grid{ | ||||
| 
 | ||||
| @@ -44,16 +44,25 @@ namespace Grid{ | ||||
|   class GridBase : public CartesianCommunicator , public GridThread { | ||||
| 
 | ||||
| public: | ||||
| 
 | ||||
|     int dummy; | ||||
|     // Give Lattice access
 | ||||
|     template<class object> friend class Lattice; | ||||
| 
 | ||||
|     GridBase(const std::vector<int> & processor_grid) : CartesianCommunicator(processor_grid) {}; | ||||
|     GridBase(const std::vector<int> & processor_grid, | ||||
| 	     const CartesianCommunicator &parent, | ||||
| 	     int &split_rank)  | ||||
|       : CartesianCommunicator(processor_grid,parent,split_rank) {}; | ||||
|     GridBase(const std::vector<int> & processor_grid, | ||||
| 	     const CartesianCommunicator &parent)  | ||||
|       : CartesianCommunicator(processor_grid,parent,dummy) {}; | ||||
| 
 | ||||
|     virtual ~GridBase() = default; | ||||
| 
 | ||||
| 
 | ||||
|     // Physics Grid information.
 | ||||
|     std::vector<int> _simd_layout;// Which dimensions get relayed out over simd lanes.
 | ||||
|     std::vector<int> _fdimensions;// Global dimensions of array prior to cb removal
 | ||||
|     std::vector<int> _fdimensions;// (full) Global dimensions of array prior to cb removal
 | ||||
|     std::vector<int> _gdimensions;// Global dimensions of array after cb removal
 | ||||
|     std::vector<int> _ldimensions;// local dimensions of array with processor images removed
 | ||||
|     std::vector<int> _rdimensions;// Reduced local dimensions with simd lane images and processor images removed 
 | ||||
| @@ -63,13 +72,14 @@ public: | ||||
|     int _isites; | ||||
|     int _fsites;                  // _isites*_osites = product(dimensions).
 | ||||
|     int _gsites; | ||||
|     std::vector<int> _slice_block;   // subslice information
 | ||||
|     std::vector<int> _slice_block;// subslice information
 | ||||
|     std::vector<int> _slice_stride; | ||||
|     std::vector<int> _slice_nblock; | ||||
| 
 | ||||
|     // Might need these at some point
 | ||||
|     //    std::vector<int> _lstart;     // local start of array in gcoors. _processor_coor[d]*_ldimensions[d]
 | ||||
|     //    std::vector<int> _lend;       // local end of array in gcoors    _processor_coor[d]*_ldimensions[d]+_ldimensions_[d]-1
 | ||||
|     std::vector<int> _lstart;     // local start of array in gcoors _processor_coor[d]*_ldimensions[d]
 | ||||
|     std::vector<int> _lend  ;     // local end of array in gcoors   _processor_coor[d]*_ldimensions[d]+_ldimensions_[d]-1
 | ||||
| 
 | ||||
|     bool _isCheckerBoarded;  | ||||
| 
 | ||||
| public: | ||||
| 
 | ||||
| @@ -78,15 +88,12 @@ public: | ||||
|     // GridCartesian / GridRedBlackCartesian
 | ||||
|     ////////////////////////////////////////////////////////////////
 | ||||
|     virtual int CheckerBoarded(int dim)=0; | ||||
|     virtual int CheckerBoard(std::vector<int> site)=0; | ||||
|     virtual int CheckerBoard(const std::vector<int> &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; | ||||
|     int  CheckerBoardFromOindex (int Oindex){ | ||||
|       std::vector<int> ocoor; | ||||
|       oCoorFromOindex(ocoor,Oindex);  | ||||
|       return CheckerBoard(ocoor); | ||||
|     } | ||||
|     virtual int CheckerBoardFromOindex (int Oindex)=0; | ||||
|     virtual int CheckerBoardFromOindexTable (int Oindex)=0; | ||||
| 
 | ||||
|     //////////////////////////////////////////////////////////////////////////////////////////////
 | ||||
|     // Local layout calculations
 | ||||
| @@ -107,6 +114,12 @@ public: | ||||
|         for(int d=0;d<_ndimension;d++) idx+=_ostride[d]*(coor[d]%_rdimensions[d]); | ||||
|         return idx; | ||||
|     } | ||||
|     virtual int iIndex(std::vector<int> &lcoor) | ||||
|     { | ||||
|         int idx=0; | ||||
|         for(int d=0;d<_ndimension;d++) idx+=_istride[d]*(lcoor[d]/_rdimensions[d]); | ||||
|         return idx; | ||||
|     } | ||||
|     inline int oIndexReduced(std::vector<int> &ocoor) | ||||
|     { | ||||
|       int idx=0;  | ||||
| @@ -119,20 +132,20 @@ public: | ||||
|       Lexicographic::CoorFromIndex(coor,Oindex,_rdimensions); | ||||
|     } | ||||
| 
 | ||||
|     inline void InOutCoorToLocalCoor (std::vector<int> &ocoor, std::vector<int> &icoor, std::vector<int> &lcoor) { | ||||
|       lcoor.resize(_ndimension); | ||||
|       for (int d = 0; d < _ndimension; d++) | ||||
|         lcoor[d] = ocoor[d] + _rdimensions[d] * icoor[d]; | ||||
|     } | ||||
| 
 | ||||
|     //////////////////////////////////////////////////////////
 | ||||
|     // SIMD lane addressing
 | ||||
|     //////////////////////////////////////////////////////////
 | ||||
|     inline int iIndex(std::vector<int> &lcoor) | ||||
|     { | ||||
|         int idx=0; | ||||
|         for(int d=0;d<_ndimension;d++) idx+=_istride[d]*(lcoor[d]/_rdimensions[d]); | ||||
|         return idx; | ||||
|     } | ||||
|     inline void iCoorFromIindex(std::vector<int> &coor,int lane) | ||||
|     { | ||||
|       Lexicographic::CoorFromIndex(coor,lane,_simd_layout); | ||||
|     } | ||||
| 
 | ||||
|     inline int PermuteDim(int dimension){ | ||||
|       return _simd_layout[dimension]>1; | ||||
|     } | ||||
| @@ -173,18 +186,40 @@ public: | ||||
|     inline int gSites(void) const { return _isites*_osites*_Nprocessors; };  | ||||
|     inline int Nd    (void) const { return _ndimension;}; | ||||
| 
 | ||||
|     inline const std::vector<int> LocalStarts(void)             { return _lstart;    }; | ||||
|     inline const std::vector<int> &FullDimensions(void)         { return _fdimensions;}; | ||||
|     inline const std::vector<int> &GlobalDimensions(void)       { return _gdimensions;}; | ||||
|     inline const std::vector<int> &LocalDimensions(void)        { return _ldimensions;}; | ||||
|     inline const std::vector<int> &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,std::vector<int> &gcoor){ | ||||
|       assert(gidx< gSites()); | ||||
|       Lexicographic::CoorFromIndex(gcoor,gidx,_gdimensions); | ||||
|     } | ||||
|     void LocalIndexToLocalCoor(int lidx,std::vector<int> &lcoor){ | ||||
|       assert(lidx<lSites()); | ||||
|       Lexicographic::CoorFromIndex(lcoor,lidx,_ldimensions); | ||||
|     } | ||||
|     void GlobalCoorToGlobalIndex(const std::vector<int> & gcoor,int & gidx){ | ||||
| @@ -211,16 +246,16 @@ public: | ||||
|       std::vector<int> lcoor; | ||||
|       GlobalCoorToProcessorCoorLocalCoor(pcoor,lcoor,gcoor); | ||||
|       rank = RankFromProcessorCoor(pcoor); | ||||
| 
 | ||||
|       /*
 | ||||
|       std::vector<int> cblcoor(lcoor); | ||||
|       for(int d=0;d<cblcoor.size();d++){ | ||||
|         if( this->CheckerBoarded(d) ) { | ||||
|           cblcoor[d] = lcoor[d]/2; | ||||
|         } | ||||
|       } | ||||
| 
 | ||||
|       i_idx= iIndex(cblcoor);// this does not imply divide by 2 on checker dim
 | ||||
|       o_idx= oIndex(lcoor);// this implies divide by 2 on checkerdim
 | ||||
|       */ | ||||
|       i_idx= iIndex(lcoor); | ||||
|       o_idx= oIndex(lcoor); | ||||
|     } | ||||
| 
 | ||||
|     void RankIndexToGlobalCoor(int rank, int o_idx, int i_idx , std::vector<int> &gcoor) | ||||
							
								
								
									
										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 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 std::vector<int> &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 std::vector<int> &dimensions, | ||||
| 		  const std::vector<int> &simd_layout, | ||||
| 		  const std::vector<int> &processor_grid, | ||||
| 		  const GridCartesian &parent) : GridBase(processor_grid,parent,dummy) | ||||
|     { | ||||
|       Init(dimensions,simd_layout,processor_grid); | ||||
|     } | ||||
|     GridCartesian(const std::vector<int> &dimensions, | ||||
| 		  const std::vector<int> &simd_layout, | ||||
| 		  const std::vector<int> &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 std::vector<int> &dimensions, | ||||
| 		  const std::vector<int> &simd_layout, | ||||
| 		  const std::vector<int> &processor_grid) : GridBase(processor_grid) | ||||
|     { | ||||
|       Init(dimensions,simd_layout,processor_grid); | ||||
|     } | ||||
|  | ||||
|     virtual ~GridCartesian() = default; | ||||
|  | ||||
|     void Init(const std::vector<int> &dimensions, | ||||
| 	      const std::vector<int> &simd_layout, | ||||
| 	      const std::vector<int> &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]; | ||||
|       } | ||||
|     }; | ||||
|  | ||||
| }; | ||||
| } | ||||
| #endif | ||||
							
								
								
									
										320
									
								
								Grid/cartesian/Cartesian_red_black.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										320
									
								
								Grid/cartesian/Cartesian_red_black.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,320 @@ | ||||
|     /************************************************************************************* | ||||
|  | ||||
|     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 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: | ||||
|     std::vector<int> _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 std::vector<int> &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) | ||||
|     { | ||||
|       std::vector<int> 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; | ||||
|       std::vector<int> 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 std::vector<int> &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; | ||||
| #if 0 | ||||
|     //////////////////////////////////////////////////////////// | ||||
|     // Create redblack grid ;; deprecate these. Should not | ||||
|     // need direct creation of redblack without a full grid to base on | ||||
|     //////////////////////////////////////////////////////////// | ||||
|     GridRedBlackCartesian(const GridBase *base, | ||||
| 			  const std::vector<int> &dimensions, | ||||
| 			  const std::vector<int> &simd_layout, | ||||
| 			  const std::vector<int> &processor_grid, | ||||
| 			  const std::vector<int> &checker_dim_mask, | ||||
| 			  int checker_dim | ||||
| 			  ) :  GridBase(processor_grid,*base)  | ||||
|     { | ||||
|       Init(dimensions,simd_layout,processor_grid,checker_dim_mask,checker_dim); | ||||
|     } | ||||
|  | ||||
|     //////////////////////////////////////////////////////////// | ||||
|     // Create redblack grid | ||||
|     //////////////////////////////////////////////////////////// | ||||
|     GridRedBlackCartesian(const GridBase *base, | ||||
| 			  const std::vector<int> &dimensions, | ||||
| 			  const std::vector<int> &simd_layout, | ||||
| 			  const std::vector<int> &processor_grid) : GridBase(processor_grid,*base)  | ||||
|     { | ||||
|       std::vector<int> checker_dim_mask(dimensions.size(),1); | ||||
|       int checker_dim = 0; | ||||
|       Init(dimensions,simd_layout,processor_grid,checker_dim_mask,checker_dim); | ||||
|     } | ||||
| #endif | ||||
|  | ||||
|     void Init(const std::vector<int> &dimensions, | ||||
|               const std::vector<int> &simd_layout, | ||||
|               const std::vector<int> &processor_grid, | ||||
|               const std::vector<int> &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(std::vector<int> &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(std::vector<int> &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; | ||||
|     } | ||||
| }; | ||||
| } | ||||
| #endif | ||||
| @@ -28,6 +28,7 @@ Author: Peter Boyle <paboyle@ph.ed.ac.uk> | ||||
| #ifndef GRID_COMMUNICATOR_H | ||||
| #define GRID_COMMUNICATOR_H | ||||
| 
 | ||||
| #include <communicator/Communicator_base.h> | ||||
| #include <Grid/communicator/SharedMemory.h> | ||||
| #include <Grid/communicator/Communicator_base.h> | ||||
| 
 | ||||
| #endif | ||||
							
								
								
									
										76
									
								
								Grid/communicator/Communicator_base.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										76
									
								
								Grid/communicator/Communicator_base.cc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,76 @@ | ||||
|     /************************************************************************************* | ||||
|  | ||||
|     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 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 std::vector<int> & CartesianCommunicator::ThisProcessorCoor(void) { return _processor_coor; }; | ||||
| const std::vector<int> & 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); | ||||
| } | ||||
|    | ||||
| } | ||||
|  | ||||
							
								
								
									
										207
									
								
								Grid/communicator/Communicator_base.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										207
									
								
								Grid/communicator/Communicator_base.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,207 @@ | ||||
|  | ||||
|     /************************************************************************************* | ||||
|  | ||||
|     Grid physics library, www.github.com/paboyle/Grid  | ||||
|  | ||||
|     Source file: ./lib/communicator/Communicator_base.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_COMMUNICATOR_BASE_H | ||||
| #define GRID_COMMUNICATOR_BASE_H | ||||
|  | ||||
| /////////////////////////////////// | ||||
| // Processor layout information | ||||
| /////////////////////////////////// | ||||
| #include <Grid/communicator/SharedMemory.h> | ||||
|  | ||||
| namespace Grid { | ||||
|  | ||||
| class CartesianCommunicator : public SharedMemory { | ||||
|  | ||||
| public:     | ||||
|  | ||||
|   //////////////////////////////////////////// | ||||
|   // Policies | ||||
|   //////////////////////////////////////////// | ||||
|   enum CommunicatorPolicy_t { CommunicatorPolicyConcurrent, CommunicatorPolicySequential }; | ||||
|   static CommunicatorPolicy_t CommunicatorPolicy; | ||||
|   static void SetCommunicatorPolicy(CommunicatorPolicy_t policy ) { CommunicatorPolicy = policy; } | ||||
|   static int       nCommThreads; | ||||
|  | ||||
|   //////////////////////////////////////////// | ||||
|   // 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; | ||||
|   static Grid_MPI_Comm      communicator_world; | ||||
|   Grid_MPI_Comm             communicator; | ||||
|   std::vector<Grid_MPI_Comm> communicator_halo; | ||||
|    | ||||
|   //////////////////////////////////////////////// | ||||
|   // Must call in Grid startup | ||||
|   //////////////////////////////////////////////// | ||||
|   static void Init(int *argc, char ***argv); | ||||
|  | ||||
|   //////////////////////////////////////////////// | ||||
|   // Constructors to sub-divide a parent communicator | ||||
|   // and default to comm world | ||||
|   //////////////////////////////////////////////// | ||||
|   CartesianCommunicator(const std::vector<int> &processors,const CartesianCommunicator &parent,int &srank); | ||||
|   CartesianCommunicator(const std::vector<int> &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 std::vector<int> &processors, Grid_MPI_Comm communicator_base); | ||||
|  | ||||
|  public: | ||||
|  | ||||
|    | ||||
|   //////////////////////////////////////////////////////////////////////////////////////// | ||||
|   // Wraps MPI_Cart routines, or implements equivalent on other impls | ||||
|   //////////////////////////////////////////////////////////////////////////////////////// | ||||
|   void ShiftedRanks(int dim,int shift,int & source, int & dest); | ||||
|   int  RankFromProcessorCoor(std::vector<int> &coor); | ||||
|   void ProcessorCoorFromRank(int rank,std::vector<int> &coor); | ||||
|    | ||||
|   int                      Dimensions(void)        ; | ||||
|   int                      IsBoss(void)            ; | ||||
|   int                      BossRank(void)          ; | ||||
|   int                      ThisRank(void)          ; | ||||
|   const std::vector<int> & ThisProcessorCoor(void) ; | ||||
|   const std::vector<int> & ProcessorGrid(void)     ; | ||||
|   int                      ProcessorCount(void)    ; | ||||
|  | ||||
|   //////////////////////////////////////////////////////////////////////////////// | ||||
|   // very VERY rarely (Log, serial RNG) we need world without a grid | ||||
|   //////////////////////////////////////////////////////////////////////////////// | ||||
|   static int  RankWorld(void) ; | ||||
|   static void BroadcastWorld(int root,void* data, int bytes); | ||||
|    | ||||
|   //////////////////////////////////////////////////////////// | ||||
|   // Reduction | ||||
|   //////////////////////////////////////////////////////////// | ||||
|   void GlobalSum(RealF &); | ||||
|   void GlobalSumVector(RealF *,int N); | ||||
|   void GlobalSum(RealD &); | ||||
|   void GlobalSumVector(RealD *,int N); | ||||
|   void GlobalSum(uint32_t &); | ||||
|   void GlobalSum(uint64_t &); | ||||
|   void GlobalSum(ComplexF &c); | ||||
|   void GlobalSumVector(ComplexF *c,int N); | ||||
|   void GlobalSum(ComplexD &c); | ||||
|   void GlobalSumVector(ComplexD *c,int N); | ||||
|   void GlobalXOR(uint32_t &); | ||||
|   void GlobalXOR(uint64_t &); | ||||
|    | ||||
|   template<class obj> void GlobalSum(obj &o){ | ||||
|     typedef typename obj::scalar_type scalar_type; | ||||
|     int words = sizeof(obj)/sizeof(scalar_type); | ||||
|     scalar_type * ptr = (scalar_type *)& o; | ||||
|     GlobalSumVector(ptr,words); | ||||
|   } | ||||
|    | ||||
|   //////////////////////////////////////////////////////////// | ||||
|   // Face exchange, buffer swap in translational invariant way | ||||
|   //////////////////////////////////////////////////////////// | ||||
|   void SendToRecvFrom(void *xmit, | ||||
| 		      int xmit_to_rank, | ||||
| 		      void *recv, | ||||
| 		      int recv_from_rank, | ||||
| 		      int bytes); | ||||
|    | ||||
|   void SendRecvPacket(void *xmit, | ||||
| 		      void *recv, | ||||
| 		      int xmit_to_rank, | ||||
| 		      int recv_from_rank, | ||||
| 		      int bytes); | ||||
|    | ||||
|   void SendToRecvFromBegin(std::vector<CommsRequest_t> &list, | ||||
| 			   void *xmit, | ||||
| 			   int xmit_to_rank, | ||||
| 			   void *recv, | ||||
| 			   int recv_from_rank, | ||||
| 			   int bytes); | ||||
|    | ||||
|   void SendToRecvFromComplete(std::vector<CommsRequest_t> &waitall); | ||||
|  | ||||
|   double StencilSendToRecvFrom(void *xmit, | ||||
| 			       int xmit_to_rank, | ||||
| 			       void *recv, | ||||
| 			       int recv_from_rank, | ||||
| 			       int bytes,int dir); | ||||
|  | ||||
|   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); | ||||
|  | ||||
|   //////////////////////////////////////////////////////////// | ||||
|   // Barrier | ||||
|   //////////////////////////////////////////////////////////// | ||||
|   void Barrier(void); | ||||
|    | ||||
|   //////////////////////////////////////////////////////////// | ||||
|   // Broadcast a buffer and composite larger | ||||
|   //////////////////////////////////////////////////////////// | ||||
|   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) | ||||
|     { | ||||
|       Broadcast(root,(void *)&data,sizeof(data)); | ||||
|     }; | ||||
|  | ||||
| };  | ||||
| } | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										514
									
								
								Grid/communicator/Communicator_mpi3.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										514
									
								
								Grid/communicator/Communicator_mpi3.cc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,514 @@ | ||||
| /************************************************************************************* | ||||
|  | ||||
|     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 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) || | ||||
|         (nCommThreads > 1 && provided != MPI_THREAD_MULTIPLE) ) | ||||
|       assert(0); | ||||
|   } | ||||
|  | ||||
|   Grid_quiesce_nodes(); | ||||
|  | ||||
|   // Never clean up as done once. | ||||
|   MPI_Comm_dup (MPI_COMM_WORLD,&communicator_world); | ||||
|  | ||||
|   GlobalSharedMemory::Init(communicator_world); | ||||
|   GlobalSharedMemory::SharedMemoryAllocate( | ||||
| 		   GlobalSharedMemory::MAX_MPI_SHM_BYTES, | ||||
| 		   GlobalSharedMemory::Hugepages); | ||||
| } | ||||
|  | ||||
| /////////////////////////////////////////////////////////////////////////// | ||||
| // 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(std::vector<int> &coor) | ||||
| { | ||||
|   int rank; | ||||
|   int ierr=MPI_Cart_rank  (communicator, &coor[0], &rank); | ||||
|   assert(ierr==0); | ||||
|   return rank; | ||||
| } | ||||
| void  CartesianCommunicator::ProcessorCoorFromRank(int rank, std::vector<int> &coor) | ||||
| { | ||||
|   coor.resize(_ndimension); | ||||
|   int ierr=MPI_Cart_coords  (communicator, rank, _ndimension,&coor[0]); | ||||
|   assert(ierr==0); | ||||
| } | ||||
|  | ||||
| //////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
| // Initialises from communicator_world | ||||
| //////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
| CartesianCommunicator::CartesianCommunicator(const std::vector<int> &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 std::vector<int> &processors,const CartesianCommunicator &parent,int &srank)     | ||||
| { | ||||
|   _ndimension = processors.size(); | ||||
|  | ||||
|   int parent_ndimension = parent._ndimension; assert(_ndimension >= parent._ndimension); | ||||
|   std::vector<int> parent_processor_coor(_ndimension,0); | ||||
|   std::vector<int> 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 ;  | ||||
|   //  std::cout << " splitting from communicator "<<parent.communicator <<std::endl; | ||||
|   int Nparent; | ||||
|   MPI_Comm_size(parent.communicator,&Nparent); | ||||
|   //  std::cout << " Parent size  "<<Nparent <<std::endl; | ||||
|  | ||||
|   int childsize=1; | ||||
|   for(int d=0;d<processors.size();d++) { | ||||
|     childsize *= processors[d]; | ||||
|   } | ||||
|   int Nchild = Nparent/childsize; | ||||
|   assert (childsize * Nchild == Nparent); | ||||
|  | ||||
|   //  std::cout << " child size  "<<childsize <<std::endl; | ||||
|  | ||||
|   std::vector<int> ccoor(_ndimension); // coor within subcommunicator | ||||
|   std::vector<int> scoor(_ndimension); // coor of split within parent | ||||
|   std::vector<int> 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 ) {  | ||||
|  | ||||
|     if(0){ | ||||
|       std::cout << GridLogMessage<<"Child communicator of "<< std::hex << parent.communicator << std::dec<<std::endl; | ||||
|       std::cout << GridLogMessage<<" parent grid["<< parent._ndimension<<"]    "; | ||||
|       for(int d=0;d<parent._ndimension;d++)  std::cout << parent._processors[d] << " "; | ||||
|       std::cout<<std::endl; | ||||
|        | ||||
|       std::cout << GridLogMessage<<" child grid["<< _ndimension <<"]    "; | ||||
|       for(int d=0;d<processors.size();d++)  std::cout << processors[d] << " "; | ||||
|       std::cout<<std::endl; | ||||
|        | ||||
|       std::cout << GridLogMessage<<" old rank "<< parent._processor<<" coor ["<< parent._ndimension <<"]    "; | ||||
|       for(int d=0;d<parent._ndimension;d++)  std::cout << parent._processor_coor[d] << " "; | ||||
|       std::cout<<std::endl; | ||||
|        | ||||
|       std::cout << GridLogMessage<<" new split "<< srank<<" scoor ["<< _ndimension <<"]    "; | ||||
|       for(int d=0;d<processors.size();d++)  std::cout << scoor[d] << " "; | ||||
|       std::cout<<std::endl; | ||||
|        | ||||
|       std::cout << GridLogMessage<<" new rank "<< crank<<" coor ["<< _ndimension <<"]    "; | ||||
|       for(int d=0;d<processors.size();d++)  std::cout << ccoor[d] << " "; | ||||
|       std::cout<<std::endl; | ||||
|  | ||||
|       ////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
|       // Declare victory | ||||
|       ////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
|       std::cout << GridLogMessage<<"Divided communicator "<< parent._Nprocessors<<" into " | ||||
| 		<< Nchild <<" communicators with " << childsize << " ranks"<<std::endl; | ||||
|       std::cout << " Split communicator " <<comm_split <<std::endl; | ||||
|     } | ||||
|  | ||||
|     //////////////////////////////////////////////////////////////// | ||||
|     // 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 std::vector<int> &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]; | ||||
|   } | ||||
|  | ||||
|   std::vector<int> 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) | ||||
| { | ||||
|   std::vector<int> 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); | ||||
| } | ||||
|  | ||||
|  | ||||
|  | ||||
| } | ||||
|  | ||||
| @@ -25,14 +25,29 @@ Author: Peter Boyle <paboyle@ph.ed.ac.uk> | ||||
|     See the full license in the file "LICENSE" in the top level distribution directory | ||||
|     *************************************************************************************/ | ||||
|     /*  END LEGAL */ | ||||
| #include "Grid.h" | ||||
| #include <Grid/GridCore.h> | ||||
| 
 | ||||
| namespace Grid { | ||||
| 
 | ||||
| ///////////////////////////////////////////////////////////////////////////////////////////////////
 | ||||
| // Info that is setup once and indept of cartesian layout
 | ||||
| ///////////////////////////////////////////////////////////////////////////////////////////////////
 | ||||
| Grid_MPI_Comm       CartesianCommunicator::communicator_world; | ||||
| 
 | ||||
| void CartesianCommunicator::Init(int *argc, char *** arv) | ||||
| { | ||||
|   GlobalSharedMemory::Init(communicator_world); | ||||
|   GlobalSharedMemory::SharedMemoryAllocate( | ||||
| 		   GlobalSharedMemory::MAX_MPI_SHM_BYTES, | ||||
| 		   GlobalSharedMemory::Hugepages); | ||||
| } | ||||
| 
 | ||||
| int Rank(void ){ return 0; }; | ||||
| CartesianCommunicator::CartesianCommunicator(const std::vector<int> &processors,const CartesianCommunicator &parent,int &srank)  | ||||
|   : CartesianCommunicator(processors)  | ||||
| { | ||||
|   srank=0; | ||||
|   SetCommunicator(communicator_world); | ||||
| } | ||||
| 
 | ||||
| CartesianCommunicator::CartesianCommunicator(const std::vector<int> &processors) | ||||
| { | ||||
| @@ -47,14 +62,19 @@ CartesianCommunicator::CartesianCommunicator(const std::vector<int> &processors) | ||||
|     assert(_processors[d]==1); | ||||
|     _processor_coor[d] = 0; | ||||
|   } | ||||
|   SetCommunicator(communicator_world); | ||||
| } | ||||
| 
 | ||||
| CartesianCommunicator::~CartesianCommunicator(){} | ||||
| 
 | ||||
| void CartesianCommunicator::GlobalSum(float &){} | ||||
| void CartesianCommunicator::GlobalSumVector(float *,int N){} | ||||
| void CartesianCommunicator::GlobalSum(double &){} | ||||
| void CartesianCommunicator::GlobalSum(uint32_t &){} | ||||
| void CartesianCommunicator::GlobalSum(uint64_t &){} | ||||
| void CartesianCommunicator::GlobalSumVector(double *,int N){} | ||||
| void CartesianCommunicator::GlobalXOR(uint32_t &){} | ||||
| void CartesianCommunicator::GlobalXOR(uint64_t &){} | ||||
| 
 | ||||
| void CartesianCommunicator::SendRecvPacket(void *xmit, | ||||
| 					   void *recv, | ||||
| @@ -84,35 +104,61 @@ void CartesianCommunicator::SendToRecvFromBegin(std::vector<CommsRequest_t> &lis | ||||
| { | ||||
|   assert(0); | ||||
| } | ||||
| 
 | ||||
| void CartesianCommunicator::SendToRecvFromComplete(std::vector<CommsRequest_t> &list) | ||||
| { | ||||
|   assert(0); | ||||
| } | ||||
| 
 | ||||
| void CartesianCommunicator::Barrier(void) | ||||
| 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); | ||||
| } | ||||
| 
 | ||||
| void CartesianCommunicator::Broadcast(int root,void* data, int bytes) | ||||
| { | ||||
| } | ||||
| void CartesianCommunicator::BroadcastWorld(int root,void* data, int bytes) | ||||
| { | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| int  CartesianCommunicator::RankWorld(void){return 0;} | ||||
| void CartesianCommunicator::Barrier(void){} | ||||
| void CartesianCommunicator::Broadcast(int root,void* data, int bytes) {} | ||||
| void CartesianCommunicator::BroadcastWorld(int root,void* data, int bytes) { } | ||||
| int  CartesianCommunicator::RankFromProcessorCoor(std::vector<int> &coor) {  return 0;} | ||||
| void CartesianCommunicator::ProcessorCoorFromRank(int rank, std::vector<int> &coor){  coor = _processor_coor; } | ||||
| void CartesianCommunicator::ShiftedRanks(int dim,int shift,int &source,int &dest) | ||||
| { | ||||
|   source =0; | ||||
|   dest=0; | ||||
| } | ||||
| int CartesianCommunicator::RankFromProcessorCoor(std::vector<int> &coor) | ||||
| 
 | ||||
| double CartesianCommunicator::StencilSendToRecvFrom( void *xmit, | ||||
| 						     int xmit_to_rank, | ||||
| 						     void *recv, | ||||
| 						     int recv_from_rank, | ||||
| 						     int bytes, int dir) | ||||
| { | ||||
|   return 0; | ||||
|   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; | ||||
| } | ||||
| void  CartesianCommunicator::ProcessorCoorFromRank(int rank, std::vector<int> &coor) | ||||
| 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){}; | ||||
| 
 | ||||
| 
 | ||||
| } | ||||
							
								
								
									
										92
									
								
								Grid/communicator/SharedMemory.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										92
									
								
								Grid/communicator/SharedMemory.cc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,92 @@ | ||||
| /************************************************************************************* | ||||
|  | ||||
|     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 Grid {  | ||||
|  | ||||
| // static data | ||||
|  | ||||
| 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); | ||||
|   } | ||||
|   return ptr; | ||||
| } | ||||
| void SharedMemory::ShmBufferFreeAll(void) {  | ||||
|   heap_top  =(size_t)ShmBufferSelf(); | ||||
|   heap_bytes=0; | ||||
| } | ||||
| void *SharedMemory::ShmBufferSelf(void) | ||||
| { | ||||
|   return ShmCommBufs[ShmRank]; | ||||
| } | ||||
|  | ||||
|  | ||||
|  | ||||
| } | ||||
							
								
								
									
										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 */ | ||||
|  | ||||
|  | ||||
| // TODO | ||||
| // 1) move includes into SharedMemory.cc | ||||
| // | ||||
| // 2) split shared memory into a) optimal communicator creation from comm world | ||||
| //  | ||||
| //                             b) shared memory buffers container | ||||
| //                                -- static globally shared; init once | ||||
| //                                -- per instance set of buffers. | ||||
| //                                    | ||||
|  | ||||
| #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 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: | ||||
|   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 std::vector<int> &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); | ||||
|  | ||||
| }; | ||||
|  | ||||
| ////////////////////////////// | ||||
| // 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;}; | ||||
|  | ||||
| }; | ||||
|  | ||||
| } | ||||
							
								
								
									
										651
									
								
								Grid/communicator/SharedMemoryMPI.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										651
									
								
								Grid/communicator/SharedMemoryMPI.cc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,651 @@ | ||||
| /************************************************************************************* | ||||
|  | ||||
|     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> | ||||
|  | ||||
| namespace Grid {  | ||||
|  | ||||
| /*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); | ||||
|   // 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 std::vector<int> &processors,Grid_MPI_Comm & optimal_comm) | ||||
| { | ||||
| #ifdef HYPERCUBE | ||||
|   //////////////////////////////////////////////////////////////// | ||||
|   // Assert power of two shm_size. | ||||
|   //////////////////////////////////////////////////////////////// | ||||
|   int log2size = Log2Size(WorldShmSize,MAXLOG2RANKSPERNODE); | ||||
|   assert(log2size != -1); | ||||
|  | ||||
|   //////////////////////////////////////////////////////////////// | ||||
|   // Identify the hypercube coordinate of this node using hostname | ||||
|   //////////////////////////////////////////////////////////////// | ||||
|   // n runs 0...7 9...16 18...25 27...34     (8*4)  5 bits | ||||
|   // i runs 0..7                                    3 bits | ||||
|   // r runs 0..3                                    2 bits | ||||
|   // 2^10 = 1024 nodes | ||||
|   const int maxhdim = 10;  | ||||
|   std::vector<int> HyperCubeCoords(maxhdim,0); | ||||
|   std::vector<int> RootHyperCubeCoords(maxhdim,0); | ||||
|   int R; | ||||
|   int I; | ||||
|   int N; | ||||
|   const int namelen = _POSIX_HOST_NAME_MAX; | ||||
|   char name[namelen]; | ||||
|  | ||||
|   // Parse ICE-XA hostname to get hypercube location | ||||
|   gethostname(name,namelen); | ||||
|   int nscan = sscanf(name,"r%di%dn%d",&R,&I,&N) ; | ||||
|   assert(nscan==3); | ||||
|  | ||||
|   int nlo = N%9; | ||||
|   int nhi = N/9; | ||||
|   uint32_t hypercoor = (R<<8)|(I<<5)|(nhi<<3)|nlo ; | ||||
|   uint32_t rootcoor  = hypercoor; | ||||
|  | ||||
|   ////////////////////////////////////////////////////////////////// | ||||
|   // Print debug info | ||||
|   ////////////////////////////////////////////////////////////////// | ||||
|   for(int d=0;d<maxhdim;d++){ | ||||
|     HyperCubeCoords[d] = (hypercoor>>d)&0x1; | ||||
|   } | ||||
|  | ||||
|   std::string hname(name); | ||||
|   std::cout << "hostname "<<hname<<std::endl; | ||||
|   std::cout << "R " << R << " I " << I << " N "<< N | ||||
|             << " hypercoor 0x"<<std::hex<<hypercoor<<std::dec<<std::endl; | ||||
|  | ||||
|   ////////////////////////////////////////////////////////////////// | ||||
|   // broadcast node 0's base coordinate for this partition. | ||||
|   ////////////////////////////////////////////////////////////////// | ||||
|   MPI_Bcast(&rootcoor, sizeof(rootcoor), MPI_BYTE, 0, WorldComm);  | ||||
|   hypercoor=hypercoor-rootcoor; | ||||
|   assert(hypercoor<WorldSize); | ||||
|   assert(hypercoor>=0); | ||||
|  | ||||
|   ////////////////////////////////////// | ||||
|   // Printing | ||||
|   ////////////////////////////////////// | ||||
|   for(int d=0;d<maxhdim;d++){ | ||||
|     HyperCubeCoords[d] = (hypercoor>>d)&0x1; | ||||
|   } | ||||
|  | ||||
|   //////////////////////////////////////////////////////////////// | ||||
|   // Identify subblock of ranks on node spreading across dims | ||||
|   // in a maximally symmetrical way | ||||
|   //////////////////////////////////////////////////////////////// | ||||
|   int ndimension              = processors.size(); | ||||
|   std::vector<int> processor_coor(ndimension); | ||||
|   std::vector<int> WorldDims = processors;   std::vector<int> ShmDims  (ndimension,1);  std::vector<int> NodeDims (ndimension); | ||||
|   std::vector<int> ShmCoor  (ndimension);    std::vector<int> NodeCoor (ndimension);    std::vector<int> WorldCoor(ndimension); | ||||
|   std::vector<int> HyperCoor(ndimension); | ||||
|   int dim = 0; | ||||
|   for(int l2=0;l2<log2size;l2++){ | ||||
|     while ( (WorldDims[dim] / ShmDims[dim]) <= 1 ) dim=(dim+1)%ndimension; | ||||
|     ShmDims[dim]*=2; | ||||
|     dim=(dim+1)%ndimension; | ||||
|   } | ||||
|  | ||||
|   //////////////////////////////////////////////////////////////// | ||||
|   // Establish torus of processes and nodes with sub-blockings | ||||
|   //////////////////////////////////////////////////////////////// | ||||
|   for(int d=0;d<ndimension;d++){ | ||||
|     NodeDims[d] = WorldDims[d]/ShmDims[d]; | ||||
|   } | ||||
|   //////////////////////////////////////////////////////////////// | ||||
|   // Map Hcube according to physical lattice  | ||||
|   // must partition. Loop over dims and find out who would join. | ||||
|   //////////////////////////////////////////////////////////////// | ||||
|   int hcoor = hypercoor; | ||||
|   for(int d=0;d<ndimension;d++){ | ||||
|      int bits = Log2Size(NodeDims[d],MAXLOG2RANKSPERNODE); | ||||
|      int msk  = (0x1<<bits)-1; | ||||
|      HyperCoor[d]=hcoor & msk;   | ||||
|      HyperCoor[d]=BinaryToGray(HyperCoor[d]); // Space filling curve magic | ||||
|      hcoor = hcoor >> bits; | ||||
|   }  | ||||
|   //////////////////////////////////////////////////////////////// | ||||
|   // Check processor counts match | ||||
|   //////////////////////////////////////////////////////////////// | ||||
|   int Nprocessors=1; | ||||
|   for(int i=0;i<ndimension;i++){ | ||||
|     Nprocessors*=processors[i]; | ||||
|   } | ||||
|   assert(WorldSize==Nprocessors); | ||||
|  | ||||
|   //////////////////////////////////////////////////////////////// | ||||
|   // Establish mapping between lexico physics coord and WorldRank | ||||
|   //////////////////////////////////////////////////////////////// | ||||
|   int rank; | ||||
|  | ||||
|   Lexicographic::CoorFromIndexReversed(NodeCoor,WorldNode   ,NodeDims); | ||||
|  | ||||
|   for(int d=0;d<ndimension;d++) NodeCoor[d]=HyperCoor[d]; | ||||
|  | ||||
|   Lexicographic::CoorFromIndexReversed(ShmCoor ,WorldShmRank,ShmDims); | ||||
|   for(int d=0;d<ndimension;d++) WorldCoor[d] = NodeCoor[d]*ShmDims[d]+ShmCoor[d]; | ||||
|   Lexicographic::IndexFromCoorReversed(WorldCoor,rank,WorldDims); | ||||
|  | ||||
|   ///////////////////////////////////////////////////////////////// | ||||
|   // Build the new communicator | ||||
|   ///////////////////////////////////////////////////////////////// | ||||
|   int ierr= MPI_Comm_split(WorldComm,0,rank,&optimal_comm); | ||||
|   assert(ierr==0); | ||||
| #else  | ||||
|   //////////////////////////////////////////////////////////////// | ||||
|   // Assert power of two shm_size. | ||||
|   //////////////////////////////////////////////////////////////// | ||||
|   int log2size = Log2Size(WorldShmSize,MAXLOG2RANKSPERNODE); | ||||
|   assert(log2size != -1); | ||||
|  | ||||
|   //////////////////////////////////////////////////////////////// | ||||
|   // Identify subblock of ranks on node spreading across dims | ||||
|   // in a maximally symmetrical way | ||||
|   //////////////////////////////////////////////////////////////// | ||||
|   int ndimension              = processors.size(); | ||||
|   std::vector<int> processor_coor(ndimension); | ||||
|   std::vector<int> WorldDims = processors;   std::vector<int> ShmDims  (ndimension,1);  std::vector<int> NodeDims (ndimension); | ||||
|   std::vector<int> ShmCoor  (ndimension);    std::vector<int> NodeCoor (ndimension);    std::vector<int> WorldCoor(ndimension); | ||||
|   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); | ||||
| #endif | ||||
| } | ||||
| //////////////////////////////////////////////////////////////////////////////////////////// | ||||
| // SHMGET | ||||
| //////////////////////////////////////////////////////////////////////////////////////////// | ||||
| #ifdef GRID_MPI3_SHMGET | ||||
| void GlobalSharedMemory::SharedMemoryAllocate(uint64_t bytes, int flags) | ||||
| { | ||||
|   std::cout << "SharedMemoryAllocate "<< bytes<< " shmget implementation "<<std::endl; | ||||
|   assert(_ShmSetup==1); | ||||
|   assert(_ShmAlloc==0); | ||||
|  | ||||
|   ////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
|   // allocate the shared windows for our group | ||||
|   ////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
|   MPI_Barrier(WorldShmComm); | ||||
|   WorldShmCommBufs.resize(WorldShmSize); | ||||
|   std::vector<int> shmids(WorldShmSize); | ||||
|  | ||||
|   if ( WorldShmRank == 0 ) { | ||||
|     for(int r=0;r<WorldShmSize;r++){ | ||||
|       size_t size = bytes; | ||||
|       key_t key   = IPC_PRIVATE; | ||||
|       int flags = IPC_CREAT | SHM_R | SHM_W; | ||||
| #ifdef SHM_HUGETLB | ||||
|       if (Hugepages) flags|=SHM_HUGETLB; | ||||
| #endif | ||||
|       if ((shmids[r]= shmget(key,size, flags)) ==-1) { | ||||
|         int errsv = errno; | ||||
|         printf("Errno %d\n",errsv); | ||||
|         printf("key   %d\n",key); | ||||
|         printf("size  %lld\n",size); | ||||
|         printf("flags %d\n",flags); | ||||
|         perror("shmget"); | ||||
|         exit(1); | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|   MPI_Barrier(WorldShmComm); | ||||
|   MPI_Bcast(&shmids[0],WorldShmSize*sizeof(int),MPI_BYTE,0,WorldShmComm); | ||||
|   MPI_Barrier(WorldShmComm); | ||||
|  | ||||
|   for(int r=0;r<WorldShmSize;r++){ | ||||
|     WorldShmCommBufs[r] = (uint64_t *)shmat(shmids[r], NULL,0); | ||||
|     if (WorldShmCommBufs[r] == (uint64_t *)-1) { | ||||
|       perror("Shared memory attach failure"); | ||||
|       shmctl(shmids[r], IPC_RMID, NULL); | ||||
|       exit(2); | ||||
|     } | ||||
|   } | ||||
|   MPI_Barrier(WorldShmComm); | ||||
|   /////////////////////////////////// | ||||
|   // Mark for clean up | ||||
|   /////////////////////////////////// | ||||
|   for(int r=0;r<WorldShmSize;r++){ | ||||
|     shmctl(shmids[r], IPC_RMID,(struct shmid_ds *)NULL); | ||||
|   } | ||||
|   MPI_Barrier(WorldShmComm); | ||||
|  | ||||
|   _ShmAlloc=1; | ||||
|   _ShmAllocBytes  = bytes; | ||||
| } | ||||
| #endif | ||||
|   | ||||
| //////////////////////////////////////////////////////////////////////////////////////////// | ||||
| // Hugetlbfs mapping intended | ||||
| //////////////////////////////////////////////////////////////////////////////////////////// | ||||
| #ifdef GRID_MPI3_SHMMMAP | ||||
| void GlobalSharedMemory::SharedMemoryAllocate(uint64_t bytes, int flags) | ||||
| { | ||||
|   std::cout << "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 << "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 << "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 << "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 | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|   //////////////////////////////////////////////////////// | ||||
|   // 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]; | ||||
|     //    std::cout << "SetCommunicator ShmCommBufs ["<< r<< "] = "<< ShmCommBufs[r]<< "  wsr = "<<wsr<<std::endl; | ||||
|   } | ||||
|   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]);  | ||||
| } | ||||
| ////////////////////////////////////////////////////////////////// | ||||
| // On node barrier | ||||
| ////////////////////////////////////////////////////////////////// | ||||
| void SharedMemory::ShmBarrier(void) | ||||
| { | ||||
|   MPI_Barrier  (ShmComm); | ||||
| } | ||||
| ////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
| // Test the shared memory is working | ||||
| ////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
| void SharedMemory::SharedMemoryTest(void) | ||||
| { | ||||
|   ShmBarrier(); | ||||
|   if ( ShmRank == 0 ) { | ||||
|     for(int r=0;r<ShmSize;r++){ | ||||
|       uint64_t * check = (uint64_t *) ShmCommBufs[r]; | ||||
|       check[0] = GlobalSharedMemory::WorldNode; | ||||
|       check[1] = r; | ||||
|       check[2] = 0x5A5A5A; | ||||
|     } | ||||
|   } | ||||
|   ShmBarrier(); | ||||
|   for(int r=0;r<ShmSize;r++){ | ||||
|     uint64_t * check = (uint64_t *) ShmCommBufs[r]; | ||||
|      | ||||
|     assert(check[0]==GlobalSharedMemory::WorldNode); | ||||
|     assert(check[1]==r); | ||||
|     assert(check[2]==0x5A5A5A); | ||||
|      | ||||
|   } | ||||
|   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) | ||||
| { | ||||
|   static int count =0; | ||||
|   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); | ||||
|   } | ||||
| }; | ||||
|  | ||||
| } | ||||
							
								
								
									
										128
									
								
								Grid/communicator/SharedMemoryNone.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										128
									
								
								Grid/communicator/SharedMemoryNone.cc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,128 @@ | ||||
| /************************************************************************************* | ||||
|  | ||||
|     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 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 std::vector<int> &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() | ||||
| {}; | ||||
|  | ||||
| } | ||||
| @@ -28,17 +28,25 @@ Author: Peter Boyle <paboyle@ph.ed.ac.uk> | ||||
| #ifndef _GRID_CSHIFT_H_ | ||||
| #define _GRID_CSHIFT_H_ | ||||
| 
 | ||||
| #include <cshift/Cshift_common.h> | ||||
| #include <Grid/cshift/Cshift_common.h> | ||||
| 
 | ||||
| #ifdef GRID_COMMS_NONE | ||||
| #include <cshift/Cshift_none.h> | ||||
| #include <Grid/cshift/Cshift_none.h> | ||||
| #endif | ||||
| 
 | ||||
| #ifdef GRID_COMMS_MPI | ||||
| #include <cshift/Cshift_mpi.h> | ||||
| #include <Grid/cshift/Cshift_mpi.h> | ||||
| #endif  | ||||
| 
 | ||||
| #ifdef GRID_COMMS_MPI3 | ||||
| #include <Grid/cshift/Cshift_mpi.h> | ||||
| #endif  | ||||
| 
 | ||||
| #ifdef GRID_COMMS_MPIT | ||||
| #include <Grid/cshift/Cshift_mpi.h> | ||||
| #endif  | ||||
| 
 | ||||
| #ifdef GRID_COMMS_SHMEM | ||||
| #include <cshift/Cshift_mpi.h> // uses same implementation of communicator | ||||
| #include <Grid/cshift/Cshift_mpi.h> // uses same implementation of communicator | ||||
| #endif  | ||||
| #endif | ||||
| @@ -1,4 +1,4 @@ | ||||
|     /*************************************************************************************
 | ||||
| /*************************************************************************************
 | ||||
| 
 | ||||
|     Grid physics library, www.github.com/paboyle/Grid  | ||||
| 
 | ||||
| @@ -30,21 +30,11 @@ Author: Peter Boyle <paboyle@ph.ed.ac.uk> | ||||
| 
 | ||||
| namespace Grid { | ||||
| 
 | ||||
| template<class vobj> | ||||
| class SimpleCompressor { | ||||
| public: | ||||
|   void Point(int) {}; | ||||
| 
 | ||||
|   vobj operator() (const vobj &arg) { | ||||
|     return arg; | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| ///////////////////////////////////////////////////////////////////
 | ||||
| // Gather for when there is no need to SIMD split with compression
 | ||||
| // Gather for when there is no need to SIMD split 
 | ||||
| ///////////////////////////////////////////////////////////////////
 | ||||
| template<class vobj,class cobj,class compressor> void  | ||||
| Gather_plane_simple (const Lattice<vobj> &rhs,std::vector<cobj,alignedAllocator<cobj> > &buffer,int dimension,int plane,int cbmask,compressor &compress, int off=0) | ||||
| 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]; | ||||
| 
 | ||||
| @@ -52,18 +42,20 @@ Gather_plane_simple (const Lattice<vobj> &rhs,std::vector<cobj,alignedAllocator< | ||||
|     cbmask = 0x3; | ||||
|   } | ||||
|    | ||||
|   int so  = plane*rhs._grid->_ostride[dimension]; // base offset for start of plane 
 | ||||
|    | ||||
|   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 std::vector<std::pair<int,int> > table; table.resize(e1*e2); | ||||
| 
 | ||||
|   int stride=rhs._grid->_slice_stride[dimension]; | ||||
|   if ( cbmask == 0x3 ) {  | ||||
| PARALLEL_NESTED_LOOP2 | ||||
|     for(int n=0;n<e1;n++){ | ||||
|       for(int b=0;b<e2;b++){ | ||||
| 	int o  = n*stride; | ||||
| 	int bo = n*e2; | ||||
| 	buffer[off+bo+b]=compress(rhs._odata[so+o+b]); | ||||
| 	table[ent++] = std::pair<int,int>(off+bo+b,so+o+b); | ||||
|       } | ||||
|     } | ||||
|   } else {  | ||||
| @@ -71,21 +63,23 @@ PARALLEL_NESTED_LOOP2 | ||||
|      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);// Could easily be a table lookup
 | ||||
| 	 int ocb=1<<rhs._grid->CheckerBoardFromOindex(o+b); | ||||
| 	 if ( ocb &cbmask ) { | ||||
| 	   buffer[off+bo++]=compress(rhs._odata[so+o+b]); | ||||
| 	   table[ent++]=std::pair<int,int> (off+bo++,so+o+b); | ||||
| 	 } | ||||
|        } | ||||
|      } | ||||
|   } | ||||
|   parallel_for(int i=0;i<ent;i++){ | ||||
|     buffer[table[i].first]=rhs._odata[table[i].second]; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| ///////////////////////////////////////////////////////////////////
 | ||||
| // Gather for when there *is* need to SIMD split with compression
 | ||||
| // Gather for when there *is* need to SIMD split 
 | ||||
| ///////////////////////////////////////////////////////////////////
 | ||||
| template<class cobj,class vobj,class compressor> void  | ||||
| Gather_plane_extract(const Lattice<vobj> &rhs,std::vector<typename cobj::scalar_object *> pointers,int dimension,int plane,int cbmask,compressor &compress) | ||||
| template<class vobj> void  | ||||
| Gather_plane_extract(const Lattice<vobj> &rhs,std::vector<typename vobj::scalar_object *> pointers,int dimension,int plane,int cbmask) | ||||
| { | ||||
|   int rd = rhs._grid->_rdimensions[dimension]; | ||||
| 
 | ||||
| @@ -98,59 +92,44 @@ Gather_plane_extract(const Lattice<vobj> &rhs,std::vector<typename cobj::scalar_ | ||||
|   int e1=rhs._grid->_slice_nblock[dimension]; | ||||
|   int e2=rhs._grid->_slice_block[dimension]; | ||||
|   int n1=rhs._grid->_slice_stride[dimension]; | ||||
|   int n2=rhs._grid->_slice_block[dimension]; | ||||
| 
 | ||||
|   if ( cbmask ==0x3){ | ||||
| PARALLEL_NESTED_LOOP2 | ||||
|     for(int n=0;n<e1;n++){ | ||||
|     parallel_for_nest2(int n=0;n<e1;n++){ | ||||
|       for(int b=0;b<e2;b++){ | ||||
| 
 | ||||
| 	int o      =   n*n1; | ||||
| 	int offset = b+n*n2; | ||||
| 	cobj temp =compress(rhs._odata[so+o+b]); | ||||
| 	extract<cobj>(temp,pointers,offset); | ||||
| 	int offset = b+n*e2; | ||||
| 	 | ||||
| 	vobj temp =rhs._odata[so+o+b]; | ||||
| 	extract<vobj>(temp,pointers,offset); | ||||
| 
 | ||||
|       } | ||||
|     } | ||||
|   } else {  | ||||
| 
 | ||||
|     assert(0); //Fixme think this is buggy
 | ||||
|     for(int n=0;n<e1;n++){ | ||||
|     // 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; | ||||
|     parallel_for_nest2(int n=0;n<e1;n++){ | ||||
|       for(int b=0;b<e2;b++){ | ||||
| 	int o=n*rhs._grid->_slice_stride[dimension]; | ||||
| 
 | ||||
| 	int o=n*n1; | ||||
| 	int ocb=1<<rhs._grid->CheckerBoardFromOindex(o+b); | ||||
| 	int offset = b+n*rhs._grid->_slice_block[dimension]; | ||||
| 	int offset = b+n*e2; | ||||
| 
 | ||||
| 	if ( ocb & cbmask ) { | ||||
| 	  cobj temp =compress(rhs._odata[so+o+b]); | ||||
| 	  extract<cobj>(temp,pointers,offset); | ||||
| 	  vobj temp =rhs._odata[so+o+b]; | ||||
| 	  extract<vobj>(temp,pointers,offset); | ||||
| 	} | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| //////////////////////////////////////////////////////
 | ||||
| // Gather for when there is no need to SIMD split
 | ||||
| //////////////////////////////////////////////////////
 | ||||
| template<class vobj> void Gather_plane_simple (const Lattice<vobj> &rhs,std::vector<vobj,alignedAllocator<vobj> > &buffer,             int dimension,int plane,int cbmask) | ||||
| { | ||||
|   SimpleCompressor<vobj> dontcompress; | ||||
|   Gather_plane_simple (rhs,buffer,dimension,plane,cbmask,dontcompress); | ||||
| } | ||||
| 
 | ||||
| //////////////////////////////////////////////////////
 | ||||
| // Gather for when there *is* need to SIMD split
 | ||||
| //////////////////////////////////////////////////////
 | ||||
| template<class vobj> void Gather_plane_extract(const Lattice<vobj> &rhs,std::vector<typename vobj::scalar_object *> pointers,int dimension,int plane,int cbmask) | ||||
| { | ||||
|   SimpleCompressor<vobj> dontcompress; | ||||
|   Gather_plane_extract<vobj,vobj,decltype(dontcompress)>(rhs,pointers,dimension,plane,cbmask,dontcompress); | ||||
| } | ||||
| 
 | ||||
| //////////////////////////////////////////////////////
 | ||||
| // Scatter for when there is no need to SIMD split
 | ||||
| //////////////////////////////////////////////////////
 | ||||
| template<class vobj> void Scatter_plane_simple (Lattice<vobj> &rhs,std::vector<vobj,alignedAllocator<vobj> > &buffer, int dimension,int plane,int cbmask) | ||||
| 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]; | ||||
| 
 | ||||
| @@ -162,35 +141,43 @@ template<class vobj> void Scatter_plane_simple (Lattice<vobj> &rhs,std::vector<v | ||||
|      | ||||
|   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 ) { | ||||
| PARALLEL_NESTED_LOOP2 | ||||
| 
 | ||||
|     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]; | ||||
| 	rhs._odata[so+o+b]=buffer[bo+b]; | ||||
| 	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 bo  =n*rhs._grid->_slice_block[dimension]; | ||||
| 	int ocb=1<<rhs._grid->CheckerBoardFromOindex(o+b);// Could easily be a table lookup
 | ||||
| 	if ( ocb & cbmask ) { | ||||
| 	  rhs._odata[so+o+b]=buffer[bo++]; | ||||
| 	  table[ent++]=std::pair<int,int> (so+o+b,bo++); | ||||
| 	} | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   parallel_for(int i=0;i<ent;i++){ | ||||
|     rhs._odata[table[i].first]=buffer[table[i].second]; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| //////////////////////////////////////////////////////
 | ||||
| // Scatter for when there *is* need to SIMD split
 | ||||
| //////////////////////////////////////////////////////
 | ||||
|  template<class vobj,class cobj> void Scatter_plane_merge(Lattice<vobj> &rhs,std::vector<cobj *> pointers,int dimension,int plane,int cbmask) | ||||
| template<class vobj> void Scatter_plane_merge(Lattice<vobj> &rhs,std::vector<typename vobj::scalar_object *> pointers,int dimension,int plane,int cbmask) | ||||
| { | ||||
|   int rd = rhs._grid->_rdimensions[dimension]; | ||||
| 
 | ||||
| @@ -204,8 +191,7 @@ PARALLEL_NESTED_LOOP2 | ||||
|   int e2=rhs._grid->_slice_block[dimension]; | ||||
| 
 | ||||
|   if(cbmask ==0x3 ) { | ||||
| PARALLEL_NESTED_LOOP2 | ||||
|     for(int n=0;n<e1;n++){ | ||||
|     parallel_for_nest2(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]; | ||||
| @@ -213,7 +199,11 @@ PARALLEL_NESTED_LOOP2 | ||||
|       } | ||||
|     } | ||||
|   } else {  | ||||
|     assert(0); // think this is buggy FIXME
 | ||||
| 
 | ||||
|     // 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; | ||||
|     for(int n=0;n<e1;n++){ | ||||
|       for(int b=0;b<e2;b++){ | ||||
| 	int o      = n*rhs._grid->_slice_stride[dimension]; | ||||
| @@ -244,31 +234,32 @@ template<class vobj> void Copy_plane(Lattice<vobj>& lhs,const Lattice<vobj> &rhs | ||||
|   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 ){ | ||||
| PARALLEL_NESTED_LOOP2 | ||||
|     for(int n=0;n<e1;n++){ | ||||
|       for(int b=0;b<e2;b++){ | ||||
|   | ||||
|         int o =n*stride+b; | ||||
|   	//lhs._odata[lo+o]=rhs._odata[ro+o];
 | ||||
| 	vstream(lhs._odata[lo+o],rhs._odata[ro+o]); | ||||
| 	table[ent++] = std::pair<int,int>(lo+o,ro+o); | ||||
|       } | ||||
|     } | ||||
|   } else {  | ||||
| PARALLEL_NESTED_LOOP2 | ||||
|     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 ) { | ||||
|   	//lhs._odata[lo+o]=rhs._odata[ro+o];
 | ||||
| 	  vstream(lhs._odata[lo+o],rhs._odata[ro+o]); | ||||
| 	  table[ent++] = std::pair<int,int>(lo+o,ro+o); | ||||
| 	} | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   parallel_for(int i=0;i<ent;i++){ | ||||
|     lhs._odata[table[i].first]=rhs._odata[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) | ||||
| @@ -286,17 +277,29 @@ template<class vobj> void Copy_plane_permute(Lattice<vobj>& lhs,const Lattice<vo | ||||
|   int e1=rhs._grid->_slice_nblock[dimension]; | ||||
|   int e2=rhs._grid->_slice_block [dimension]; | ||||
|   int stride = rhs._grid->_slice_stride[dimension]; | ||||
| PARALLEL_NESTED_LOOP2 | ||||
| 
 | ||||
|   static std::vector<std::pair<int,int> > table;  table.resize(e1*e2); | ||||
|   int ent=0; | ||||
| 
 | ||||
|   double t_tab,t_perm; | ||||
|   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 ) { | ||||
| 	permute(lhs._odata[lo+o+b],rhs._odata[ro+o+b],permute_type); | ||||
|       if ( ocb&cbmask ) table[ent++] = std::pair<int,int>(lo+o+b,ro+o+b); | ||||
|     }} | ||||
|   } | ||||
| 
 | ||||
|   }} | ||||
|   parallel_for(int i=0;i<ent;i++){ | ||||
|     permute(lhs._odata[table[i].first],rhs._odata[table[i].second],permute_type); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| //////////////////////////////////////////////////////
 | ||||
| @@ -309,6 +312,8 @@ template<class vobj> void Cshift_local(Lattice<vobj>& ret,const Lattice<vobj> &r | ||||
|   sshift[0] = rhs._grid->CheckerBoardShiftForCB(rhs.checkerboard,dimension,shift,Even); | ||||
|   sshift[1] = rhs._grid->CheckerBoardShiftForCB(rhs.checkerboard,dimension,shift,Odd); | ||||
| 
 | ||||
|   double t_local; | ||||
|    | ||||
|   if ( sshift[0] == sshift[1] ) { | ||||
|     Cshift_local(ret,rhs,dimension,shift,0x3); | ||||
|   } else { | ||||
| @@ -317,7 +322,7 @@ template<class vobj> void Cshift_local(Lattice<vobj>& ret,const Lattice<vobj> &r | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| template<class vobj> Lattice<vobj> Cshift_local(Lattice<vobj> &ret,const Lattice<vobj> &rhs,int dimension,int shift,int cbmask) | ||||
| 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]; | ||||
| @@ -329,8 +334,8 @@ template<class vobj> Lattice<vobj> Cshift_local(Lattice<vobj> &ret,const Lattice | ||||
|   // Map to always positive shift modulo global full dimension.
 | ||||
|   shift = (shift+fd)%fd; | ||||
| 
 | ||||
|   ret.checkerboard = grid->CheckerBoardDestination(rhs.checkerboard,shift,dimension); | ||||
|   // 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; | ||||
| @@ -339,22 +344,31 @@ template<class vobj> Lattice<vobj> Cshift_local(Lattice<vobj> &ret,const Lattice | ||||
| 
 | ||||
|     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; | ||||
|      | ||||
|     // FIXME : This must change where we have a 
 | ||||
|     // Rotate slice.
 | ||||
|      | ||||
|     // Document how this works ; why didn't I do this when I first wrote it...
 | ||||
|     // 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; | ||||
|       int wrap = sshift/rd; wrap=wrap % ly; | ||||
|       int  num = sshift%rd; | ||||
| 
 | ||||
|       if ( x< rd-num ) permute_slice=wrap; | ||||
| @@ -366,15 +380,12 @@ template<class vobj> Lattice<vobj> Cshift_local(Lattice<vobj> &ret,const Lattice | ||||
|       } 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);  | ||||
|    | ||||
|    | ||||
|   } | ||||
|   return ret; | ||||
| } | ||||
| } | ||||
| #endif | ||||
| @@ -54,13 +54,13 @@ template<class vobj> Lattice<vobj> Cshift(const Lattice<vobj> &rhs,int dimension | ||||
| 
 | ||||
| 
 | ||||
|   if ( !comm_dim ) { | ||||
|     //    std::cout << "Cshift_local" <<std::endl;
 | ||||
|     //std::cout << "CSHIFT: Cshift_local" <<std::endl;
 | ||||
|     Cshift_local(ret,rhs,dimension,shift); // Handles checkerboarding
 | ||||
|   } 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); | ||||
|   } else { | ||||
|     //    std::cout << "Cshift_comms" <<std::endl;
 | ||||
|     //std::cout << "CSHIFT: Cshift_comms" <<std::endl;
 | ||||
|     Cshift_comms(ret,rhs,dimension,shift); | ||||
|   } | ||||
|   return ret; | ||||
| @@ -74,7 +74,6 @@ template<class vobj> void Cshift_comms(Lattice<vobj>& ret,const Lattice<vobj> &r | ||||
|   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;
 | ||||
| 
 | ||||
|   if ( sshift[0] == sshift[1] ) { | ||||
|     //    std::cout << "Single pass Cshift_comms" <<std::endl;
 | ||||
|     Cshift_comms(ret,rhs,dimension,shift,0x3); | ||||
| @@ -92,9 +91,12 @@ template<class vobj> void Cshift_comms_simd(Lattice<vobj>& ret,const Lattice<vob | ||||
|   sshift[0] = rhs._grid->CheckerBoardShiftForCB(rhs.checkerboard,dimension,shift,Even); | ||||
|   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] ) { | ||||
|     //std::cout << "Single pass Cshift_comms" <<std::endl;
 | ||||
|     Cshift_comms_simd(ret,rhs,dimension,shift,0x3); | ||||
|   } 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,0x2);// both with block stride loop iteration
 | ||||
|   } | ||||
| @@ -119,8 +121,8 @@ template<class vobj> void Cshift_comms(Lattice<vobj> &ret,const Lattice<vobj> &r | ||||
|   assert(shift<fd); | ||||
|    | ||||
|   int buffer_size = rhs._grid->_slice_nblock[dimension]*rhs._grid->_slice_block[dimension]; | ||||
|   std::vector<vobj,alignedAllocator<vobj> > send_buf(buffer_size); | ||||
|   std::vector<vobj,alignedAllocator<vobj> > recv_buf(buffer_size); | ||||
|   commVector<vobj> send_buf(buffer_size); | ||||
|   commVector<vobj> recv_buf(buffer_size); | ||||
| 
 | ||||
|   int cb= (cbmask==0x2)? Odd : Even; | ||||
|   int sshift= rhs._grid->CheckerBoardShiftForCB(rhs.checkerboard,dimension,shift,cb); | ||||
| @@ -154,10 +156,8 @@ template<class vobj> void Cshift_comms(Lattice<vobj> &ret,const Lattice<vobj> &r | ||||
| 			   (void *)&recv_buf[0], | ||||
| 			   recv_from_rank, | ||||
| 			   bytes); | ||||
|       grid->Barrier(); | ||||
| 
 | ||||
|       //      for(int i=0;i<words;i++){
 | ||||
|       //	std::cout << "SendRecv ["<<i<<"] snd "<<send_buf[i]<<" rcv " << recv_buf[i] << "  0x" << cbmask<<std::endl;
 | ||||
|       //      }
 | ||||
|       Scatter_plane_simple (ret,recv_buf,dimension,x,cbmask); | ||||
|     } | ||||
|   } | ||||
| @@ -178,6 +178,10 @@ template<class vobj> void  Cshift_comms_simd(Lattice<vobj> &ret,const Lattice<vo | ||||
|   int simd_layout     = grid->_simd_layout[dimension]; | ||||
|   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(simd_layout==2); | ||||
|   assert(shift>=0); | ||||
| @@ -191,8 +195,8 @@ template<class vobj> void  Cshift_comms_simd(Lattice<vobj> &ret,const Lattice<vo | ||||
|   int buffer_size = grid->_slice_nblock[dimension]*grid->_slice_block[dimension]; | ||||
|   int words = sizeof(vobj)/sizeof(vector_type); | ||||
| 
 | ||||
|   std::vector<Vector<scalar_object> >   send_buf_extract(Nsimd,Vector<scalar_object>(buffer_size) ); | ||||
|   std::vector<Vector<scalar_object> >   recv_buf_extract(Nsimd,Vector<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) ); | ||||
| 
 | ||||
|   int bytes = buffer_size*sizeof(scalar_object); | ||||
| 
 | ||||
| @@ -243,7 +247,7 @@ template<class vobj> void  Cshift_comms_simd(Lattice<vobj> &ret,const Lattice<vo | ||||
| 			     (void *)&recv_buf_extract[i][0], | ||||
| 			     recv_from_rank, | ||||
| 			     bytes); | ||||
| 
 | ||||
| 	grid->Barrier(); | ||||
| 	rpointers[i] = &recv_buf_extract[i][0]; | ||||
|       } else {  | ||||
| 	rpointers[i] = &send_buf_extract[nbr_lane][0]; | ||||
							
								
								
									
										18920
									
								
								Grid/json/json.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18920
									
								
								Grid/json/json.hpp
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -28,6 +28,6 @@ Author: Peter Boyle <paboyle@ph.ed.ac.uk> | ||||
| #ifndef GRID_LATTICE_H | ||||
| #define GRID_LATTICE_H | ||||
| 
 | ||||
| #include <lattice/Lattice_base.h> | ||||
| #include <Grid/lattice/Lattice_base.h> | ||||
| 
 | ||||
| #endif | ||||
							
								
								
									
										466
									
								
								Grid/lattice/Lattice_ET.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										466
									
								
								Grid/lattice/Lattice_ET.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,466 @@ | ||||
| /************************************************************************************* | ||||
|  | ||||
| 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 Grid { | ||||
|  | ||||
| //////////////////////////////////////////////////// | ||||
| // Predicated where support | ||||
| //////////////////////////////////////////////////// | ||||
| template <class iobj, class vobj, class robj> | ||||
| 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(); | ||||
|   const int words = sizeof(vobj) / sizeof(vector_type); | ||||
|  | ||||
|   std::vector<Integer> mask(Nsimd); | ||||
|   std::vector<scalar_object> truevals(Nsimd); | ||||
|   std::vector<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; | ||||
| } | ||||
|  | ||||
| //////////////////////////////////////////// | ||||
| // recursive evaluation of expressions; Could | ||||
| // switch to generic approach with variadics, a la | ||||
| // Antonin's Lat Sim but the repack to variadic with popped | ||||
| // from tuple is hideous; C++14 introduces std::make_index_sequence for this | ||||
| //////////////////////////////////////////// | ||||
|  | ||||
| // leaf eval of lattice ; should enable if protect using traits | ||||
|  | ||||
| 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 <typename T> using is_lattice_expr = std::is_base_of<LatticeExpressionBase,T >; | ||||
|  | ||||
| //Specialization of getVectorType for lattices | ||||
| template<typename T> | ||||
| struct getVectorType<Lattice<T> >{ | ||||
|   typedef typename Lattice<T>::vector_object type; | ||||
| }; | ||||
|   | ||||
| template<class sobj> | ||||
| inline sobj eval(const unsigned int ss, const sobj &arg) | ||||
| { | ||||
|   return arg; | ||||
| } | ||||
| template <class lobj> | ||||
| inline const lobj &eval(const unsigned int ss, const Lattice<lobj> &arg) { | ||||
|   return arg._odata[ss]; | ||||
| } | ||||
|  | ||||
| // handle nodes in syntax tree | ||||
| template <typename Op, typename T1> | ||||
| auto inline eval( | ||||
|     const unsigned int ss, | ||||
|     const LatticeUnaryExpression<Op, T1> &expr)  // eval one operand | ||||
|     -> decltype(expr.first.func(eval(ss, std::get<0>(expr.second)))) { | ||||
|   return expr.first.func(eval(ss, std::get<0>(expr.second))); | ||||
| } | ||||
|  | ||||
| template <typename Op, typename T1, typename T2> | ||||
| auto inline eval( | ||||
|     const unsigned int ss, | ||||
|     const LatticeBinaryExpression<Op, T1, T2> &expr)  // eval two operands | ||||
|     -> decltype(expr.first.func(eval(ss, std::get<0>(expr.second)), | ||||
|                                 eval(ss, std::get<1>(expr.second)))) { | ||||
|   return expr.first.func(eval(ss, std::get<0>(expr.second)), | ||||
|                          eval(ss, std::get<1>(expr.second))); | ||||
| } | ||||
|  | ||||
| template <typename Op, typename T1, typename T2, typename T3> | ||||
| auto inline eval(const unsigned int ss, | ||||
|                  const LatticeTrinaryExpression<Op, T1, T2, T3> | ||||
|                      &expr)  // eval three operands | ||||
|     -> decltype(expr.first.func(eval(ss, std::get<0>(expr.second)), | ||||
|                                 eval(ss, std::get<1>(expr.second)), | ||||
|                                 eval(ss, std::get<2>(expr.second)))) { | ||||
|   return expr.first.func(eval(ss, std::get<0>(expr.second)), | ||||
|                          eval(ss, std::get<1>(expr.second)), | ||||
|                          eval(ss, std::get<2>(expr.second))); | ||||
| } | ||||
|  | ||||
| ////////////////////////////////////////////////////////////////////////// | ||||
| // Obtain the grid 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 GridFromExpression(GridBase *&grid, const T1 &lat)  // Lattice leaf | ||||
| { | ||||
|   if (grid) { | ||||
|     conformable(grid, lat._grid); | ||||
|   } | ||||
|   grid = lat._grid; | ||||
| } | ||||
| template <class T1, | ||||
|           typename std::enable_if<!is_lattice<T1>::value, T1>::type * = nullptr> | ||||
| inline void GridFromExpression(GridBase *&grid, | ||||
|                                const T1 ¬lat)  // non-lattice leaf | ||||
| {} | ||||
| template <typename Op, typename T1> | ||||
| inline void GridFromExpression(GridBase *&grid, | ||||
|                                const LatticeUnaryExpression<Op, T1> &expr) { | ||||
|   GridFromExpression(grid, std::get<0>(expr.second));  // recurse | ||||
| } | ||||
|  | ||||
| template <typename Op, typename T1, typename T2> | ||||
| inline void GridFromExpression( | ||||
|     GridBase *&grid, const LatticeBinaryExpression<Op, T1, T2> &expr) { | ||||
|   GridFromExpression(grid, std::get<0>(expr.second));  // recurse | ||||
|   GridFromExpression(grid, std::get<1>(expr.second)); | ||||
| } | ||||
| template <typename Op, typename T1, typename T2, typename T3> | ||||
| inline void GridFromExpression( | ||||
|     GridBase *&grid, const LatticeTrinaryExpression<Op, T1, T2, T3> &expr) { | ||||
|   GridFromExpression(grid, std::get<0>(expr.second));  // recurse | ||||
|   GridFromExpression(grid, std::get<1>(expr.second)); | ||||
|   GridFromExpression(grid, std::get<2>(expr.second)); | ||||
| } | ||||
|  | ||||
| ////////////////////////////////////////////////////////////////////////// | ||||
| // 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; | ||||
|   //  std::cout<<GridLogMessage<<"Lattice leaf cb "<<cb<<std::endl; | ||||
| } | ||||
| 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 | ||||
| { | ||||
|   //  std::cout<<GridLogMessage<<"Non lattice leaf cb"<<cb<<std::endl; | ||||
| } | ||||
| template <typename Op, typename T1> | ||||
| inline void CBFromExpression(int &cb, | ||||
|                              const LatticeUnaryExpression<Op, T1> &expr) { | ||||
|   CBFromExpression(cb, std::get<0>(expr.second));  // recurse | ||||
|   //  std::cout<<GridLogMessage<<"Unary node cb "<<cb<<std::endl; | ||||
| } | ||||
|  | ||||
| template <typename Op, typename T1, typename T2> | ||||
| inline void CBFromExpression(int &cb, | ||||
|                              const LatticeBinaryExpression<Op, T1, T2> &expr) { | ||||
|   CBFromExpression(cb, std::get<0>(expr.second));  // recurse | ||||
|   CBFromExpression(cb, std::get<1>(expr.second)); | ||||
|   //  std::cout<<GridLogMessage<<"Binary node cb "<<cb<<std::endl; | ||||
| } | ||||
| template <typename Op, typename T1, typename T2, typename T3> | ||||
| inline void CBFromExpression( | ||||
|     int &cb, const LatticeTrinaryExpression<Op, T1, T2, T3> &expr) { | ||||
|   CBFromExpression(cb, std::get<0>(expr.second));  // recurse | ||||
|   CBFromExpression(cb, std::get<1>(expr.second)); | ||||
|   CBFromExpression(cb, std::get<2>(expr.second)); | ||||
|   //  std::cout<<GridLogMessage<<"Trinary node cb "<<cb<<std::endl; | ||||
| } | ||||
|  | ||||
| //////////////////////////////////////////// | ||||
| // Unary operators and funcs | ||||
| //////////////////////////////////////////// | ||||
| #define GridUnopClass(name, ret)                                          \ | ||||
|   template <class arg>                                                    \ | ||||
|   struct name {                                                           \ | ||||
|     static auto 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 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 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), const T1 &>(       \ | ||||
|           std::make_pair(GRID_UNOP(name)(), std::forward_as_tuple(arg)))) { \ | ||||
|     return LatticeUnaryExpression<GRID_UNOP(name), const T1 &>(             \ | ||||
|         std::make_pair(GRID_UNOP(name)(), std::forward_as_tuple(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), const T1 &, const T2 &>(  \ | ||||
|               std::make_pair(GRID_BINOP(name)(),                              \ | ||||
|                              std::forward_as_tuple(lhs, rhs)))) {             \ | ||||
|     return LatticeBinaryExpression<GRID_BINOP(name), const T1 &, const T2 &>( \ | ||||
|         std::make_pair(GRID_BINOP(name)(), std::forward_as_tuple(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), const T1 &, const T2 &>(  \ | ||||
|               std::make_pair(GRID_BINOP(name)(),                              \ | ||||
|                              std::forward_as_tuple(lhs, rhs)))) {             \ | ||||
|     return LatticeBinaryExpression<GRID_BINOP(name), const T1 &, const T2 &>( \ | ||||
|         std::make_pair(GRID_BINOP(name)(), std::forward_as_tuple(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), const T1 &, const T2 &,  \ | ||||
|                                    const T3 &>(std::make_pair(                 \ | ||||
|               GRID_TRINOP(name)(), std::forward_as_tuple(pred, lhs, rhs)))) {  \ | ||||
|     return LatticeTrinaryExpression<GRID_TRINOP(name), const T1 &, const T2 &, \ | ||||
|                                     const T3 &>(std::make_pair(                \ | ||||
|         GRID_TRINOP(name)(), std::forward_as_tuple(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.first.func(eval(0, std::get<0>(expr.second))))> { | ||||
|   Lattice<decltype(expr.first.func(eval(0, std::get<0>(expr.second))))> ret( | ||||
|       expr); | ||||
|   return ret; | ||||
| } | ||||
| template <class Op, class T1, class T2> | ||||
| auto closure(const LatticeBinaryExpression<Op, T1, T2> &expr) | ||||
|     -> Lattice<decltype(expr.first.func(eval(0, std::get<0>(expr.second)), | ||||
|                                         eval(0, std::get<1>(expr.second))))> { | ||||
|   Lattice<decltype(expr.first.func(eval(0, std::get<0>(expr.second)), | ||||
|                                    eval(0, std::get<1>(expr.second))))> | ||||
|       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.first.func(eval(0, std::get<0>(expr.second)), | ||||
|                                         eval(0, std::get<1>(expr.second)), | ||||
|                                         eval(0, std::get<2>(expr.second))))> { | ||||
|   Lattice<decltype(expr.first.func(eval(0, std::get<0>(expr.second)), | ||||
|                                    eval(0, std::get<1>(expr.second)), | ||||
|                                    eval(0, std::get<2>(expr.second))))> | ||||
|       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 | ||||
| } | ||||
|  | ||||
| #if 0 | ||||
| using namespace Grid; | ||||
|          | ||||
|  int main(int argc,char **argv){ | ||||
|     | ||||
|    Lattice<double> v1(16); | ||||
|    Lattice<double> v2(16); | ||||
|    Lattice<double> v3(16); | ||||
|  | ||||
|    BinaryAdd<double,double> tmp; | ||||
|    LatticeBinaryExpression<BinaryAdd<double,double>,Lattice<double> &,Lattice<double> &>  | ||||
|      expr(std::make_pair(tmp, | ||||
|     std::forward_as_tuple(v1,v2))); | ||||
|    tmp.func(eval(0,v1),eval(0,v2)); | ||||
|  | ||||
|    auto var = v1+v2; | ||||
|    std::cout<<GridLogMessage<<typeid(var).name()<<std::endl; | ||||
|  | ||||
|    v3=v1+v2; | ||||
|    v3=v1+v2+v1*v2; | ||||
|  }; | ||||
|  | ||||
| void testit(Lattice<double> &v1,Lattice<double> &v2,Lattice<double> &v3) | ||||
| { | ||||
|    v3=v1+v2+v1*v2; | ||||
| } | ||||
| #endif | ||||
|  | ||||
| #endif | ||||
| @@ -39,8 +39,7 @@ namespace Grid { | ||||
|     ret.checkerboard = lhs.checkerboard; | ||||
|     conformable(ret,rhs); | ||||
|     conformable(lhs,rhs); | ||||
| PARALLEL_FOR_LOOP | ||||
|     for(int ss=0;ss<lhs._grid->oSites();ss++){ | ||||
|     parallel_for(int ss=0;ss<lhs._grid->oSites();ss++){ | ||||
| #ifdef STREAMING_STORES | ||||
|       obj1 tmp; | ||||
|       mult(&tmp,&lhs._odata[ss],&rhs._odata[ss]); | ||||
| @@ -56,8 +55,7 @@ PARALLEL_FOR_LOOP | ||||
|     ret.checkerboard = lhs.checkerboard; | ||||
|     conformable(ret,rhs); | ||||
|     conformable(lhs,rhs); | ||||
| PARALLEL_FOR_LOOP | ||||
|     for(int ss=0;ss<lhs._grid->oSites();ss++){ | ||||
|     parallel_for(int ss=0;ss<lhs._grid->oSites();ss++){ | ||||
| #ifdef STREAMING_STORES | ||||
|       obj1 tmp; | ||||
|       mac(&tmp,&lhs._odata[ss],&rhs._odata[ss]); | ||||
| @@ -73,8 +71,7 @@ PARALLEL_FOR_LOOP | ||||
|     ret.checkerboard = lhs.checkerboard; | ||||
|     conformable(ret,rhs); | ||||
|     conformable(lhs,rhs); | ||||
| PARALLEL_FOR_LOOP | ||||
|     for(int ss=0;ss<lhs._grid->oSites();ss++){ | ||||
|     parallel_for(int ss=0;ss<lhs._grid->oSites();ss++){ | ||||
| #ifdef STREAMING_STORES | ||||
|       obj1 tmp; | ||||
|       sub(&tmp,&lhs._odata[ss],&rhs._odata[ss]); | ||||
| @@ -89,8 +86,7 @@ PARALLEL_FOR_LOOP | ||||
|     ret.checkerboard = lhs.checkerboard; | ||||
|     conformable(ret,rhs); | ||||
|     conformable(lhs,rhs); | ||||
| PARALLEL_FOR_LOOP | ||||
|     for(int ss=0;ss<lhs._grid->oSites();ss++){ | ||||
|     parallel_for(int ss=0;ss<lhs._grid->oSites();ss++){ | ||||
| #ifdef STREAMING_STORES | ||||
|       obj1 tmp; | ||||
|       add(&tmp,&lhs._odata[ss],&rhs._odata[ss]); | ||||
| @@ -108,8 +104,7 @@ PARALLEL_FOR_LOOP | ||||
|     void mult(Lattice<obj1> &ret,const Lattice<obj2> &lhs,const obj3 &rhs){ | ||||
|     ret.checkerboard = lhs.checkerboard; | ||||
|     conformable(lhs,ret); | ||||
| PARALLEL_FOR_LOOP | ||||
|     for(int ss=0;ss<lhs._grid->oSites();ss++){ | ||||
|     parallel_for(int ss=0;ss<lhs._grid->oSites();ss++){ | ||||
|       obj1 tmp; | ||||
|       mult(&tmp,&lhs._odata[ss],&rhs); | ||||
|       vstream(ret._odata[ss],tmp); | ||||
| @@ -120,8 +115,7 @@ PARALLEL_FOR_LOOP | ||||
|     void mac(Lattice<obj1> &ret,const Lattice<obj2> &lhs,const obj3 &rhs){ | ||||
|     ret.checkerboard = lhs.checkerboard; | ||||
|     conformable(ret,lhs); | ||||
| PARALLEL_FOR_LOOP | ||||
|     for(int ss=0;ss<lhs._grid->oSites();ss++){ | ||||
|     parallel_for(int ss=0;ss<lhs._grid->oSites();ss++){ | ||||
|       obj1 tmp; | ||||
|       mac(&tmp,&lhs._odata[ss],&rhs); | ||||
|       vstream(ret._odata[ss],tmp); | ||||
| @@ -132,8 +126,7 @@ PARALLEL_FOR_LOOP | ||||
|     void sub(Lattice<obj1> &ret,const Lattice<obj2> &lhs,const obj3 &rhs){ | ||||
|     ret.checkerboard = lhs.checkerboard; | ||||
|     conformable(ret,lhs); | ||||
| PARALLEL_FOR_LOOP | ||||
|     for(int ss=0;ss<lhs._grid->oSites();ss++){ | ||||
|     parallel_for(int ss=0;ss<lhs._grid->oSites();ss++){ | ||||
| #ifdef STREAMING_STORES | ||||
|       obj1 tmp; | ||||
|       sub(&tmp,&lhs._odata[ss],&rhs); | ||||
| @@ -147,8 +140,7 @@ PARALLEL_FOR_LOOP | ||||
|     void add(Lattice<obj1> &ret,const Lattice<obj2> &lhs,const obj3 &rhs){ | ||||
|     ret.checkerboard = lhs.checkerboard; | ||||
|     conformable(lhs,ret); | ||||
| PARALLEL_FOR_LOOP | ||||
|     for(int ss=0;ss<lhs._grid->oSites();ss++){ | ||||
|     parallel_for(int ss=0;ss<lhs._grid->oSites();ss++){ | ||||
| #ifdef STREAMING_STORES | ||||
|       obj1 tmp; | ||||
|       add(&tmp,&lhs._odata[ss],&rhs); | ||||
| @@ -166,8 +158,7 @@ PARALLEL_FOR_LOOP | ||||
|     void mult(Lattice<obj1> &ret,const obj2 &lhs,const Lattice<obj3> &rhs){ | ||||
|     ret.checkerboard = rhs.checkerboard; | ||||
|     conformable(ret,rhs); | ||||
| PARALLEL_FOR_LOOP | ||||
|     for(int ss=0;ss<rhs._grid->oSites();ss++){ | ||||
|     parallel_for(int ss=0;ss<rhs._grid->oSites();ss++){ | ||||
| #ifdef STREAMING_STORES | ||||
|       obj1 tmp; | ||||
|       mult(&tmp,&lhs,&rhs._odata[ss]); | ||||
| @@ -182,8 +173,7 @@ PARALLEL_FOR_LOOP | ||||
|     void mac(Lattice<obj1> &ret,const obj2 &lhs,const Lattice<obj3> &rhs){ | ||||
|     ret.checkerboard = rhs.checkerboard; | ||||
|     conformable(ret,rhs); | ||||
| PARALLEL_FOR_LOOP | ||||
|     for(int ss=0;ss<rhs._grid->oSites();ss++){ | ||||
|     parallel_for(int ss=0;ss<rhs._grid->oSites();ss++){ | ||||
| #ifdef STREAMING_STORES | ||||
|       obj1 tmp; | ||||
|       mac(&tmp,&lhs,&rhs._odata[ss]); | ||||
| @@ -198,8 +188,7 @@ PARALLEL_FOR_LOOP | ||||
|     void sub(Lattice<obj1> &ret,const obj2 &lhs,const Lattice<obj3> &rhs){ | ||||
|     ret.checkerboard = rhs.checkerboard; | ||||
|     conformable(ret,rhs); | ||||
| PARALLEL_FOR_LOOP | ||||
|     for(int ss=0;ss<rhs._grid->oSites();ss++){ | ||||
|     parallel_for(int ss=0;ss<rhs._grid->oSites();ss++){ | ||||
| #ifdef STREAMING_STORES | ||||
|       obj1 tmp; | ||||
|       sub(&tmp,&lhs,&rhs._odata[ss]); | ||||
| @@ -213,8 +202,7 @@ PARALLEL_FOR_LOOP | ||||
|     void add(Lattice<obj1> &ret,const obj2 &lhs,const Lattice<obj3> &rhs){ | ||||
|     ret.checkerboard = rhs.checkerboard; | ||||
|     conformable(ret,rhs); | ||||
| PARALLEL_FOR_LOOP | ||||
|     for(int ss=0;ss<rhs._grid->oSites();ss++){ | ||||
|     parallel_for(int ss=0;ss<rhs._grid->oSites();ss++){ | ||||
| #ifdef STREAMING_STORES | ||||
|       obj1 tmp; | ||||
|       add(&tmp,&lhs,&rhs._odata[ss]); | ||||
| @@ -230,8 +218,7 @@ PARALLEL_FOR_LOOP | ||||
|     ret.checkerboard = x.checkerboard; | ||||
|     conformable(ret,x); | ||||
|     conformable(x,y); | ||||
| PARALLEL_FOR_LOOP | ||||
|     for(int ss=0;ss<x._grid->oSites();ss++){ | ||||
|     parallel_for(int ss=0;ss<x._grid->oSites();ss++){ | ||||
| #ifdef STREAMING_STORES | ||||
|       vobj tmp = a*x._odata[ss]+y._odata[ss]; | ||||
|       vstream(ret._odata[ss],tmp); | ||||
| @@ -245,8 +232,7 @@ PARALLEL_FOR_LOOP | ||||
|     ret.checkerboard = x.checkerboard; | ||||
|     conformable(ret,x); | ||||
|     conformable(x,y); | ||||
| PARALLEL_FOR_LOOP | ||||
|     for(int ss=0;ss<x._grid->oSites();ss++){ | ||||
|     parallel_for(int ss=0;ss<x._grid->oSites();ss++){ | ||||
| #ifdef STREAMING_STORES | ||||
|       vobj tmp = a*x._odata[ss]+b*y._odata[ss]; | ||||
|       vstream(ret._odata[ss],tmp); | ||||
| @@ -258,19 +244,11 @@ PARALLEL_FOR_LOOP | ||||
| 
 | ||||
|   template<class sobj,class vobj> strong_inline | ||||
|   RealD axpy_norm(Lattice<vobj> &ret,sobj a,const Lattice<vobj> &x,const Lattice<vobj> &y){ | ||||
|     ret.checkerboard = x.checkerboard; | ||||
|     conformable(ret,x); | ||||
|     conformable(x,y); | ||||
|     axpy(ret,a,x,y); | ||||
|     return norm2(ret); | ||||
|     return axpy_norm_fast(ret,a,x,y); | ||||
|   } | ||||
|   template<class sobj,class vobj> strong_inline | ||||
|   RealD axpby_norm(Lattice<vobj> &ret,sobj a,sobj b,const Lattice<vobj> &x,const Lattice<vobj> &y){ | ||||
|     ret.checkerboard = x.checkerboard; | ||||
|     conformable(ret,x); | ||||
|     conformable(x,y); | ||||
|     axpby(ret,a,b,x,y); | ||||
|     return norm2(ret); // FIXME implement parallel norm in ss loop
 | ||||
|     return axpby_norm_fast(ret,a,b,x,y); | ||||
|   } | ||||
| 
 | ||||
| } | ||||
| @@ -1,32 +1,33 @@ | ||||
|     /*************************************************************************************
 | ||||
| /*************************************************************************************
 | ||||
| 
 | ||||
|     Grid physics library, www.github.com/paboyle/Grid  | ||||
| Grid physics library, www.github.com/paboyle/Grid | ||||
| 
 | ||||
|     Source file: ./lib/lattice/Lattice_base.h | ||||
| Source file: ./lib/lattice/Lattice_base.h | ||||
| 
 | ||||
|     Copyright (C) 2015 | ||||
| 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 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. | ||||
| 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. | ||||
| 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 */ | ||||
| See the full license in the file "LICENSE" in the top level distribution | ||||
| directory | ||||
| *************************************************************************************/ | ||||
| /*  END LEGAL */ | ||||
| #ifndef GRID_LATTICE_BASE_H | ||||
| #define GRID_LATTICE_BASE_H | ||||
| 
 | ||||
| @@ -64,9 +65,6 @@ public: | ||||
|      | ||||
| class LatticeExpressionBase {}; | ||||
| 
 | ||||
| template<class T> using Vector = std::vector<T,alignedAllocator<T> >;               // Aligned allocator??
 | ||||
| template<class T> using Matrix = std::vector<std::vector<T,alignedAllocator<T> > >; // Aligned allocator??
 | ||||
| 
 | ||||
| template <typename Op, typename T1>                            | ||||
| class LatticeUnaryExpression  : public std::pair<Op,std::tuple<T1> > , public LatticeExpressionBase { | ||||
|  public: | ||||
| @@ -101,6 +99,7 @@ public: | ||||
|     int begin(void) { return 0;}; | ||||
|     int end(void)   { return _odata.size(); } | ||||
|     vobj & operator[](int i) { return _odata[i]; }; | ||||
|     const vobj & operator[](int i) const { return _odata[i]; }; | ||||
| 
 | ||||
| public: | ||||
|     typedef typename vobj::scalar_type scalar_type; | ||||
| @@ -122,8 +121,7 @@ public: | ||||
|     assert( (cb==Odd) || (cb==Even)); | ||||
|     checkerboard=cb; | ||||
| 
 | ||||
| PARALLEL_FOR_LOOP | ||||
|     for(int ss=0;ss<_grid->oSites();ss++){ | ||||
|     parallel_for(int ss=0;ss<_grid->oSites();ss++){ | ||||
| #ifdef STREAMING_STORES | ||||
|       vobj tmp = eval(ss,expr); | ||||
|       vstream(_odata[ss] ,tmp); | ||||
| @@ -145,8 +143,7 @@ PARALLEL_FOR_LOOP | ||||
|     assert( (cb==Odd) || (cb==Even)); | ||||
|     checkerboard=cb; | ||||
| 
 | ||||
| PARALLEL_FOR_LOOP | ||||
|     for(int ss=0;ss<_grid->oSites();ss++){ | ||||
|     parallel_for(int ss=0;ss<_grid->oSites();ss++){ | ||||
| #ifdef STREAMING_STORES | ||||
|       vobj tmp = eval(ss,expr); | ||||
|       vstream(_odata[ss] ,tmp); | ||||
| @@ -168,8 +165,7 @@ PARALLEL_FOR_LOOP | ||||
|     assert( (cb==Odd) || (cb==Even)); | ||||
|     checkerboard=cb; | ||||
| 
 | ||||
| PARALLEL_FOR_LOOP | ||||
|     for(int ss=0;ss<_grid->oSites();ss++){ | ||||
|     parallel_for(int ss=0;ss<_grid->oSites();ss++){ | ||||
| #ifdef STREAMING_STORES | ||||
|       //vobj tmp = eval(ss,expr);
 | ||||
|       vstream(_odata[ss] ,eval(ss,expr)); | ||||
| @@ -192,8 +188,7 @@ PARALLEL_FOR_LOOP | ||||
|     checkerboard=cb; | ||||
| 
 | ||||
|     _odata.resize(_grid->oSites()); | ||||
| PARALLEL_FOR_LOOP | ||||
|     for(int ss=0;ss<_grid->oSites();ss++){ | ||||
|     parallel_for(int ss=0;ss<_grid->oSites();ss++){ | ||||
| #ifdef STREAMING_STORES | ||||
|       vobj tmp = eval(ss,expr); | ||||
|       vstream(_odata[ss] ,tmp); | ||||
| @@ -214,8 +209,7 @@ PARALLEL_FOR_LOOP | ||||
|     checkerboard=cb; | ||||
| 
 | ||||
|     _odata.resize(_grid->oSites()); | ||||
| PARALLEL_FOR_LOOP | ||||
|     for(int ss=0;ss<_grid->oSites();ss++){ | ||||
|     parallel_for(int ss=0;ss<_grid->oSites();ss++){ | ||||
| #ifdef STREAMING_STORES | ||||
|       vobj tmp = eval(ss,expr); | ||||
|       vstream(_odata[ss] ,tmp); | ||||
| @@ -236,8 +230,7 @@ PARALLEL_FOR_LOOP | ||||
|     checkerboard=cb; | ||||
| 
 | ||||
|     _odata.resize(_grid->oSites()); | ||||
| PARALLEL_FOR_LOOP | ||||
|     for(int ss=0;ss<_grid->oSites();ss++){ | ||||
|     parallel_for(int ss=0;ss<_grid->oSites();ss++){ | ||||
|       vstream(_odata[ss] ,eval(ss,expr)); | ||||
|     } | ||||
|   }; | ||||
| @@ -255,26 +248,69 @@ PARALLEL_FOR_LOOP | ||||
|     checkerboard=0; | ||||
|   } | ||||
|    | ||||
|     virtual ~Lattice(void) = default; | ||||
|   Lattice(const Lattice& r){ // copy constructor
 | ||||
|     _grid = r._grid; | ||||
|     checkerboard = r.checkerboard; | ||||
|     _odata.resize(_grid->oSites());// essential
 | ||||
|     parallel_for(int ss=0;ss<_grid->oSites();ss++){ | ||||
|       _odata[ss]=r._odata[ss]; | ||||
|     }  	 | ||||
|   } | ||||
| 
 | ||||
|     template<class sobj> strong_inline Lattice<vobj> & operator = (const sobj & r){ | ||||
| PARALLEL_FOR_LOOP | ||||
|         for(int ss=0;ss<_grid->oSites();ss++){ | ||||
|             this->_odata[ss]=r; | ||||
|   Lattice(Lattice&& r){ // move constructor
 | ||||
|     _grid = r._grid; | ||||
|     checkerboard = r.checkerboard; | ||||
|     _odata=std::move(r._odata); | ||||
|   } | ||||
|    | ||||
|   inline Lattice<vobj> & operator = (Lattice<vobj> && r) | ||||
|   { | ||||
|     _grid        = r._grid; | ||||
|     checkerboard = r.checkerboard; | ||||
|     _odata       =std::move(r._odata); | ||||
|     return *this; | ||||
|   } | ||||
| 
 | ||||
|   inline Lattice<vobj> & operator = (const Lattice<vobj> & r){ | ||||
|     _grid        = r._grid; | ||||
|     checkerboard = r.checkerboard; | ||||
|     _odata.resize(_grid->oSites());// essential
 | ||||
|      | ||||
|     parallel_for(int ss=0;ss<_grid->oSites();ss++){ | ||||
|       _odata[ss]=r._odata[ss]; | ||||
|     }  	 | ||||
|     return *this; | ||||
|   } | ||||
| 
 | ||||
|   template<class robj> strong_inline Lattice<vobj> & operator = (const Lattice<robj> & r){ | ||||
|     this->checkerboard = r.checkerboard; | ||||
|     conformable(*this,r); | ||||
|       std::cout<<GridLogMessage<<"Lattice operator ="<<std::endl; | ||||
| PARALLEL_FOR_LOOP | ||||
|         for(int ss=0;ss<_grid->oSites();ss++){ | ||||
|      | ||||
|     parallel_for(int ss=0;ss<_grid->oSites();ss++){ | ||||
|       this->_odata[ss]=r._odata[ss]; | ||||
|     } | ||||
|     return *this; | ||||
|   } | ||||
| 
 | ||||
|   virtual ~Lattice(void) = default; | ||||
|      | ||||
|   void reset(GridBase* grid) { | ||||
|     if (_grid != grid) { | ||||
|       _grid = grid; | ||||
|       _odata.resize(grid->oSites()); | ||||
|       checkerboard = 0; | ||||
|     } | ||||
|   } | ||||
|    | ||||
| 
 | ||||
|   template<class sobj> strong_inline Lattice<vobj> & operator = (const sobj & r){ | ||||
|     parallel_for(int ss=0;ss<_grid->oSites();ss++){ | ||||
|       this->_odata[ss]=r; | ||||
|     } | ||||
|     return *this; | ||||
|   } | ||||
|    | ||||
|    | ||||
|   // *=,+=,-= operators inherit behvour from correspond */+/- operation
 | ||||
|   template<class T> strong_inline Lattice<vobj> &operator *=(const T &r) { | ||||
|     *this = (*this)*r; | ||||
| @@ -289,18 +325,7 @@ PARALLEL_FOR_LOOP | ||||
|     *this = (*this)+r; | ||||
|     return *this; | ||||
|   } | ||||
|      | ||||
|     strong_inline friend Lattice<vobj> operator / (const Lattice<vobj> &lhs,const Lattice<vobj> &rhs){ | ||||
|         conformable(lhs,rhs); | ||||
|         Lattice<vobj> ret(lhs._grid); | ||||
| PARALLEL_FOR_LOOP | ||||
|         for(int ss=0;ss<lhs._grid->oSites();ss++){ | ||||
| 	  ret._odata[ss] = lhs._odata[ss]*pow(rhs._odata[ss],-1.0); | ||||
|         } | ||||
|         return ret; | ||||
|     }; | ||||
| 
 | ||||
|  }; // class Lattice
 | ||||
| }; // class Lattice
 | ||||
|    | ||||
|   template<class vobj> std::ostream& operator<< (std::ostream& stream, const Lattice<vobj> &o){ | ||||
|     std::vector<int> gcoor; | ||||
| @@ -324,27 +349,27 @@ PARALLEL_FOR_LOOP | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| #include <lattice/Lattice_conformable.h> | ||||
| #include "Lattice_conformable.h" | ||||
| #define GRID_LATTICE_EXPRESSION_TEMPLATES | ||||
| #ifdef  GRID_LATTICE_EXPRESSION_TEMPLATES | ||||
| #include <lattice/Lattice_ET.h> | ||||
| #include "Lattice_ET.h" | ||||
| #else  | ||||
| #include <lattice/Lattice_overload.h> | ||||
| #include "Lattice_overload.h" | ||||
| #endif | ||||
| #include <lattice/Lattice_arith.h> | ||||
| #include <lattice/Lattice_trace.h> | ||||
| #include <lattice/Lattice_transpose.h> | ||||
| #include <lattice/Lattice_local.h> | ||||
| #include <lattice/Lattice_reduction.h> | ||||
| #include <lattice/Lattice_peekpoke.h> | ||||
| #include <lattice/Lattice_reality.h> | ||||
| #include <lattice/Lattice_comparison_utils.h> | ||||
| #include <lattice/Lattice_comparison.h> | ||||
| #include <lattice/Lattice_coordinate.h> | ||||
| #include <lattice/Lattice_where.h> | ||||
| #include <lattice/Lattice_rng.h> | ||||
| #include <lattice/Lattice_unary.h> | ||||
| #include <lattice/Lattice_transfer.h> | ||||
| #include "Lattice_arith.h" | ||||
| #include "Lattice_trace.h" | ||||
| #include "Lattice_transpose.h" | ||||
| #include "Lattice_local.h" | ||||
| #include "Lattice_reduction.h" | ||||
| #include "Lattice_peekpoke.h" | ||||
| #include "Lattice_reality.h" | ||||
| #include "Lattice_comparison_utils.h" | ||||
| #include "Lattice_comparison.h" | ||||
| #include "Lattice_coordinate.h" | ||||
| #include "Lattice_where.h" | ||||
| #include "Lattice_rng.h" | ||||
| #include "Lattice_unary.h" | ||||
| #include "Lattice_transfer.h" | ||||
| 
 | ||||
| 
 | ||||
| #endif | ||||
| @@ -47,8 +47,7 @@ namespace Grid { | ||||
|     inline Lattice<vInteger> LLComparison(vfunctor op,const Lattice<lobj> &lhs,const Lattice<robj> &rhs) | ||||
|   { | ||||
|     Lattice<vInteger> ret(rhs._grid); | ||||
| PARALLEL_FOR_LOOP | ||||
|         for(int ss=0;ss<rhs._grid->oSites(); ss++){ | ||||
|     parallel_for(int ss=0;ss<rhs._grid->oSites(); ss++){ | ||||
|       ret._odata[ss]=op(lhs._odata[ss],rhs._odata[ss]); | ||||
|     } | ||||
|     return ret; | ||||
| @@ -60,8 +59,7 @@ PARALLEL_FOR_LOOP | ||||
|     inline Lattice<vInteger> LSComparison(vfunctor op,const Lattice<lobj> &lhs,const robj &rhs) | ||||
|   { | ||||
|     Lattice<vInteger> ret(lhs._grid); | ||||
| PARALLEL_FOR_LOOP | ||||
|         for(int ss=0;ss<lhs._grid->oSites(); ss++){ | ||||
|     parallel_for(int ss=0;ss<lhs._grid->oSites(); ss++){ | ||||
|       ret._odata[ss]=op(lhs._odata[ss],rhs); | ||||
|     } | ||||
|     return ret; | ||||
| @@ -73,8 +71,7 @@ PARALLEL_FOR_LOOP | ||||
|     inline Lattice<vInteger> SLComparison(vfunctor op,const lobj &lhs,const Lattice<robj> &rhs) | ||||
|   { | ||||
|     Lattice<vInteger> ret(rhs._grid); | ||||
| PARALLEL_FOR_LOOP | ||||
|         for(int ss=0;ss<rhs._grid->oSites(); ss++){ | ||||
|     parallel_for(int ss=0;ss<rhs._grid->oSites(); ss++){ | ||||
|       ret._odata[ss]=op(lhs._odata[ss],rhs); | ||||
|     } | ||||
|     return ret; | ||||
| @@ -168,6 +165,5 @@ PARALLEL_FOR_LOOP | ||||
|      inline Lattice<vInteger> operator != (const lobj & lhs, const Lattice<robj> & rhs) { | ||||
|      return SLComparison(vne<lobj,robj>(),lhs,rhs); | ||||
|    } | ||||
| 
 | ||||
| } | ||||
| #endif | ||||
| @@ -179,7 +179,7 @@ namespace Grid { | ||||
|       return ret; | ||||
|     } | ||||
| 
 | ||||
| #define DECLARE_RELATIONAL(op,functor) \ | ||||
| #define DECLARE_RELATIONAL_EQ(op,functor) \ | ||||
|   template<class vsimd,IfSimd<vsimd> = 0>\ | ||||
|     inline vInteger operator op (const vsimd & lhs, const vsimd & rhs)\ | ||||
|     {\ | ||||
| @@ -198,11 +198,6 @@ namespace Grid { | ||||
|       typedef typename vsimd::scalar_type scalar;\ | ||||
|       return Comparison(functor<scalar,scalar>(),lhs,rhs);\ | ||||
|     }\ | ||||
|   template<class vsimd>\ | ||||
|     inline vInteger operator op(const iScalar<vsimd> &lhs,const iScalar<vsimd> &rhs)\ | ||||
|     {									\ | ||||
|       return lhs._internal op rhs._internal;				\ | ||||
|     }									\ | ||||
|   template<class vsimd>\ | ||||
|     inline vInteger operator op(const iScalar<vsimd> &lhs,const typename vsimd::scalar_type &rhs) \ | ||||
|     {									\ | ||||
| @@ -212,14 +207,21 @@ namespace Grid { | ||||
|     inline vInteger operator op(const typename vsimd::scalar_type &lhs,const iScalar<vsimd> &rhs) \ | ||||
|     {									\ | ||||
|       return lhs op rhs._internal;					\ | ||||
|     }									 | ||||
|     }									\ | ||||
| 
 | ||||
| #define DECLARE_RELATIONAL(op,functor) \ | ||||
|   DECLARE_RELATIONAL_EQ(op,functor)    \ | ||||
|   template<class vsimd>\ | ||||
|     inline vInteger operator op(const iScalar<vsimd> &lhs,const iScalar<vsimd> &rhs)\ | ||||
|     {									\ | ||||
|       return lhs._internal op rhs._internal;				\ | ||||
|     }									 | ||||
| 
 | ||||
| DECLARE_RELATIONAL(<,slt); | ||||
| DECLARE_RELATIONAL(<=,sle); | ||||
| DECLARE_RELATIONAL(>,sgt); | ||||
| DECLARE_RELATIONAL(>=,sge); | ||||
| DECLARE_RELATIONAL(==,seq); | ||||
| DECLARE_RELATIONAL_EQ(==,seq); | ||||
| DECLARE_RELATIONAL(!=,sne); | ||||
| 
 | ||||
| #undef DECLARE_RELATIONAL | ||||
| @@ -52,23 +52,5 @@ namespace Grid { | ||||
|       } | ||||
|     }; | ||||
| 
 | ||||
|     // LatticeCoordinate();
 | ||||
|     // FIXME for debug; deprecate this; made obscelete by 
 | ||||
|     template<class vobj> void lex_sites(Lattice<vobj> &l){ | ||||
|       Real *v_ptr = (Real *)&l._odata[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; | ||||
| 	  } | ||||
| 	}} | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
| } | ||||
| #endif | ||||
| @@ -43,8 +43,7 @@ namespace Grid { | ||||
|     inline auto localNorm2 (const Lattice<vobj> &rhs)-> Lattice<typename vobj::tensor_reduced> | ||||
|     { | ||||
|       Lattice<typename vobj::tensor_reduced> ret(rhs._grid); | ||||
| PARALLEL_FOR_LOOP | ||||
|         for(int ss=0;ss<rhs._grid->oSites(); ss++){ | ||||
|       parallel_for(int ss=0;ss<rhs._grid->oSites(); ss++){ | ||||
| 	ret._odata[ss]=innerProduct(rhs._odata[ss],rhs._odata[ss]); | ||||
|       } | ||||
|       return ret; | ||||
| @@ -55,8 +54,7 @@ PARALLEL_FOR_LOOP | ||||
|     inline auto localInnerProduct (const Lattice<vobj> &lhs,const Lattice<vobj> &rhs) -> Lattice<typename vobj::tensor_reduced> | ||||
|     { | ||||
|       Lattice<typename vobj::tensor_reduced> ret(rhs._grid); | ||||
| PARALLEL_FOR_LOOP | ||||
|       for(int ss=0;ss<rhs._grid->oSites(); ss++){ | ||||
|       parallel_for(int ss=0;ss<rhs._grid->oSites(); ss++){ | ||||
| 	ret._odata[ss]=innerProduct(lhs._odata[ss],rhs._odata[ss]); | ||||
|       } | ||||
|       return ret; | ||||
| @@ -68,13 +66,10 @@ PARALLEL_FOR_LOOP | ||||
|     inline auto outerProduct (const Lattice<ll> &lhs,const Lattice<rr> &rhs) -> Lattice<decltype(outerProduct(lhs._odata[0],rhs._odata[0]))> | ||||
|   { | ||||
|     Lattice<decltype(outerProduct(lhs._odata[0],rhs._odata[0]))> ret(rhs._grid); | ||||
| PARALLEL_FOR_LOOP | ||||
|         for(int ss=0;ss<rhs._grid->oSites(); ss++){ | ||||
|     parallel_for(int ss=0;ss<rhs._grid->oSites(); ss++){ | ||||
|       ret._odata[ss]=outerProduct(lhs._odata[ss],rhs._odata[ss]); | ||||
|     } | ||||
|     return ret; | ||||
|   } | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| #endif | ||||
| @@ -37,8 +37,7 @@ namespace Grid { | ||||
|   inline Lattice<vobj> operator -(const Lattice<vobj> &r) | ||||
|   { | ||||
|     Lattice<vobj> ret(r._grid); | ||||
| PARALLEL_FOR_LOOP | ||||
|     for(int ss=0;ss<r._grid->oSites();ss++){ | ||||
|     parallel_for(int ss=0;ss<r._grid->oSites();ss++){ | ||||
|       vstream(ret._odata[ss], -r._odata[ss]); | ||||
|     } | ||||
|     return ret; | ||||
| @@ -74,8 +73,7 @@ PARALLEL_FOR_LOOP | ||||
|   inline auto operator * (const left &lhs,const Lattice<right> &rhs) -> Lattice<decltype(lhs*rhs._odata[0])> | ||||
|   { | ||||
|     Lattice<decltype(lhs*rhs._odata[0])> ret(rhs._grid); | ||||
| PARALLEL_FOR_LOOP | ||||
|     for(int ss=0;ss<rhs._grid->oSites(); ss++){ | ||||
|     parallel_for(int ss=0;ss<rhs._grid->oSites(); ss++){ | ||||
|       decltype(lhs*rhs._odata[0]) tmp=lhs*rhs._odata[ss];  | ||||
|       vstream(ret._odata[ss],tmp); | ||||
| 	   //      ret._odata[ss]=lhs*rhs._odata[ss];
 | ||||
| @@ -86,8 +84,7 @@ PARALLEL_FOR_LOOP | ||||
|     inline auto operator + (const left &lhs,const Lattice<right> &rhs) -> Lattice<decltype(lhs+rhs._odata[0])> | ||||
|     { | ||||
|       Lattice<decltype(lhs+rhs._odata[0])> ret(rhs._grid); | ||||
| PARALLEL_FOR_LOOP | ||||
|       for(int ss=0;ss<rhs._grid->oSites(); ss++){ | ||||
|       parallel_for(int ss=0;ss<rhs._grid->oSites(); ss++){ | ||||
| 	decltype(lhs+rhs._odata[0]) tmp =lhs-rhs._odata[ss];   | ||||
| 	vstream(ret._odata[ss],tmp); | ||||
| 	//	ret._odata[ss]=lhs+rhs._odata[ss];
 | ||||
| @@ -98,11 +95,9 @@ PARALLEL_FOR_LOOP | ||||
|     inline auto operator - (const left &lhs,const Lattice<right> &rhs) -> Lattice<decltype(lhs-rhs._odata[0])> | ||||
|   { | ||||
|     Lattice<decltype(lhs-rhs._odata[0])> ret(rhs._grid); | ||||
| PARALLEL_FOR_LOOP | ||||
|     for(int ss=0;ss<rhs._grid->oSites(); ss++){ | ||||
|     parallel_for(int ss=0;ss<rhs._grid->oSites(); ss++){ | ||||
|       decltype(lhs-rhs._odata[0]) tmp=lhs-rhs._odata[ss];   | ||||
|       vstream(ret._odata[ss],tmp); | ||||
|       //      ret._odata[ss]=lhs-rhs._odata[ss];
 | ||||
|     } | ||||
|     return ret; | ||||
|   } | ||||
| @@ -110,8 +105,7 @@ PARALLEL_FOR_LOOP | ||||
|       inline auto operator * (const Lattice<left> &lhs,const right &rhs) -> Lattice<decltype(lhs._odata[0]*rhs)> | ||||
|     { | ||||
|       Lattice<decltype(lhs._odata[0]*rhs)> ret(lhs._grid); | ||||
| PARALLEL_FOR_LOOP | ||||
|       for(int ss=0;ss<lhs._grid->oSites(); ss++){ | ||||
|       parallel_for(int ss=0;ss<lhs._grid->oSites(); ss++){ | ||||
| 	decltype(lhs._odata[0]*rhs) tmp =lhs._odata[ss]*rhs; | ||||
| 	vstream(ret._odata[ss],tmp); | ||||
| 	//            ret._odata[ss]=lhs._odata[ss]*rhs;
 | ||||
| @@ -122,8 +116,7 @@ PARALLEL_FOR_LOOP | ||||
|       inline auto operator + (const Lattice<left> &lhs,const right &rhs) -> Lattice<decltype(lhs._odata[0]+rhs)> | ||||
|     { | ||||
|         Lattice<decltype(lhs._odata[0]+rhs)> ret(lhs._grid); | ||||
| PARALLEL_FOR_LOOP | ||||
|         for(int ss=0;ss<rhs._grid->oSites(); ss++){ | ||||
| 	parallel_for(int ss=0;ss<rhs._grid->oSites(); ss++){ | ||||
| 	  decltype(lhs._odata[0]+rhs) tmp=lhs._odata[ss]+rhs;  | ||||
| 	  vstream(ret._odata[ss],tmp); | ||||
| 	  //	  ret._odata[ss]=lhs._odata[ss]+rhs;
 | ||||
| @@ -134,15 +127,12 @@ PARALLEL_FOR_LOOP | ||||
|       inline auto operator - (const Lattice<left> &lhs,const right &rhs) -> Lattice<decltype(lhs._odata[0]-rhs)> | ||||
|     { | ||||
|       Lattice<decltype(lhs._odata[0]-rhs)> ret(lhs._grid); | ||||
| PARALLEL_FOR_LOOP | ||||
|       for(int ss=0;ss<rhs._grid->oSites(); ss++){ | ||||
|       parallel_for(int ss=0;ss<rhs._grid->oSites(); ss++){ | ||||
| 	  decltype(lhs._odata[0]-rhs) tmp=lhs._odata[ss]-rhs; | ||||
| 	  vstream(ret._odata[ss],tmp); | ||||
| 	  //	ret._odata[ss]=lhs._odata[ss]-rhs;
 | ||||
|       } | ||||
|       return ret; | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
| } | ||||
| #endif | ||||
| @@ -44,8 +44,7 @@ namespace Grid { | ||||
|     { | ||||
|       Lattice<decltype(peekIndex<Index>(lhs._odata[0],i))> ret(lhs._grid); | ||||
|       ret.checkerboard=lhs.checkerboard; | ||||
| PARALLEL_FOR_LOOP | ||||
|         for(int ss=0;ss<lhs._grid->oSites();ss++){ | ||||
|       parallel_for(int ss=0;ss<lhs._grid->oSites();ss++){ | ||||
| 	ret._odata[ss] = peekIndex<Index>(lhs._odata[ss],i); | ||||
|       } | ||||
|       return ret; | ||||
| @@ -55,8 +54,7 @@ PARALLEL_FOR_LOOP | ||||
|     { | ||||
|       Lattice<decltype(peekIndex<Index>(lhs._odata[0],i,j))> ret(lhs._grid); | ||||
|       ret.checkerboard=lhs.checkerboard; | ||||
| PARALLEL_FOR_LOOP | ||||
|         for(int ss=0;ss<lhs._grid->oSites();ss++){ | ||||
|       parallel_for(int ss=0;ss<lhs._grid->oSites();ss++){ | ||||
| 	ret._odata[ss] = peekIndex<Index>(lhs._odata[ss],i,j); | ||||
|       } | ||||
|       return ret; | ||||
| @@ -68,16 +66,14 @@ PARALLEL_FOR_LOOP | ||||
|     template<int Index,class vobj>  | ||||
|     void PokeIndex(Lattice<vobj> &lhs,const Lattice<decltype(peekIndex<Index>(lhs._odata[0],0))> & rhs,int i) | ||||
|     { | ||||
| PARALLEL_FOR_LOOP | ||||
|         for(int ss=0;ss<lhs._grid->oSites();ss++){ | ||||
|       parallel_for(int ss=0;ss<lhs._grid->oSites();ss++){ | ||||
| 	pokeIndex<Index>(lhs._odata[ss],rhs._odata[ss],i); | ||||
|       }       | ||||
|     } | ||||
|     template<int Index,class vobj> | ||||
|       void PokeIndex(Lattice<vobj> &lhs,const Lattice<decltype(peekIndex<Index>(lhs._odata[0],0,0))> & rhs,int i,int j) | ||||
|     { | ||||
| PARALLEL_FOR_LOOP | ||||
|         for(int ss=0;ss<lhs._grid->oSites();ss++){ | ||||
|       parallel_for(int ss=0;ss<lhs._grid->oSites();ss++){ | ||||
| 	pokeIndex<Index>(lhs._odata[ss],rhs._odata[ss],i,j); | ||||
|       }       | ||||
|     } | ||||
| @@ -86,7 +82,7 @@ PARALLEL_FOR_LOOP | ||||
|     // Poke a scalar object into the SIMD array
 | ||||
|     //////////////////////////////////////////////////////
 | ||||
|     template<class vobj,class sobj> | ||||
|     void pokeSite(const sobj &s,Lattice<vobj> &l,std::vector<int> &site){ | ||||
|     void pokeSite(const sobj &s,Lattice<vobj> &l,const std::vector<int> &site){ | ||||
| 
 | ||||
|       GridBase *grid=l._grid; | ||||
| 
 | ||||
| @@ -120,7 +116,7 @@ PARALLEL_FOR_LOOP | ||||
|     // Peek a scalar object from the SIMD array
 | ||||
|     //////////////////////////////////////////////////////////
 | ||||
|     template<class vobj,class sobj> | ||||
|       void peekSite(sobj &s,const Lattice<vobj> &l,std::vector<int> &site){ | ||||
|       void peekSite(sobj &s,const Lattice<vobj> &l,const std::vector<int> &site){ | ||||
|          | ||||
|       GridBase *grid=l._grid; | ||||
| 
 | ||||
| @@ -131,9 +127,6 @@ PARALLEL_FOR_LOOP | ||||
| 
 | ||||
|       assert( l.checkerboard == l._grid->CheckerBoard(site)); | ||||
| 
 | ||||
|       // FIXME
 | ||||
|       //      assert( sizeof(sobj)*Nsimd == sizeof(vobj));
 | ||||
| 
 | ||||
|       int rank,odx,idx; | ||||
|       grid->GlobalCoorToRankIndex(rank,odx,idx,site); | ||||
| 
 | ||||
| @@ -154,7 +147,7 @@ PARALLEL_FOR_LOOP | ||||
|     template<class vobj,class sobj> | ||||
|     void peekLocalSite(sobj &s,const Lattice<vobj> &l,std::vector<int> &site){ | ||||
|          | ||||
|       GridBase *grid=l._grid; | ||||
|       GridBase *grid = l._grid; | ||||
| 
 | ||||
|       typedef typename vobj::scalar_type scalar_type; | ||||
|       typedef typename vobj::vector_type vector_type; | ||||
| @@ -164,15 +157,17 @@ PARALLEL_FOR_LOOP | ||||
|       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); | ||||
| 
 | ||||
|       std::vector<sobj> buf(Nsimd); | ||||
|       scalar_type * vp = (scalar_type *)&l._odata[odx]; | ||||
|       scalar_type * pt = (scalar_type *)&s; | ||||
|        | ||||
|       extract(l._odata[odx],buf); | ||||
|        | ||||
|       s = buf[idx]; | ||||
|       for(int w=0;w<words;w++){ | ||||
|         pt[w] = vp[idx+w*Nsimd]; | ||||
|       } | ||||
|        | ||||
|       return; | ||||
|     }; | ||||
| @@ -190,18 +185,17 @@ PARALLEL_FOR_LOOP | ||||
|       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); | ||||
| 
 | ||||
|       std::vector<sobj> buf(Nsimd); | ||||
|       scalar_type * vp = (scalar_type *)&l._odata[odx]; | ||||
|       scalar_type * pt = (scalar_type *)&s; | ||||
|        | ||||
|       // extract-modify-merge cycle is easiest way and this is not perf critical
 | ||||
|       extract(l._odata[odx],buf); | ||||
|        | ||||
|       buf[idx] = s; | ||||
| 
 | ||||
|       merge(l._odata[odx],buf); | ||||
|       for(int w=0;w<words;w++){ | ||||
|         vp[idx+w*Nsimd] = pt[w]; | ||||
|       } | ||||
| 
 | ||||
|       return; | ||||
|     }; | ||||
| @@ -40,8 +40,7 @@ namespace Grid { | ||||
| 
 | ||||
|     template<class vobj> inline Lattice<vobj> adj(const Lattice<vobj> &lhs){ | ||||
|         Lattice<vobj> ret(lhs._grid); | ||||
| PARALLEL_FOR_LOOP | ||||
|         for(int ss=0;ss<lhs._grid->oSites();ss++){ | ||||
| 	parallel_for(int ss=0;ss<lhs._grid->oSites();ss++){ | ||||
|             ret._odata[ss] = adj(lhs._odata[ss]); | ||||
|         } | ||||
|         return ret; | ||||
| @@ -49,13 +48,10 @@ PARALLEL_FOR_LOOP | ||||
| 
 | ||||
|     template<class vobj> inline Lattice<vobj> conjugate(const Lattice<vobj> &lhs){ | ||||
|         Lattice<vobj> ret(lhs._grid); | ||||
| PARALLEL_FOR_LOOP | ||||
|         for(int ss=0;ss<lhs._grid->oSites();ss++){ | ||||
| 	parallel_for(int ss=0;ss<lhs._grid->oSites();ss++){ | ||||
| 	  ret._odata[ss] = conjugate(lhs._odata[ss]); | ||||
|         } | ||||
|         return ret; | ||||
|     }; | ||||
| 
 | ||||
| 
 | ||||
| } | ||||
| #endif | ||||
							
								
								
									
										733
									
								
								Grid/lattice/Lattice_reduction.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										733
									
								
								Grid/lattice/Lattice_reduction.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,733 @@ | ||||
| /************************************************************************************* | ||||
|     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 */ | ||||
| #ifndef GRID_LATTICE_REDUCTION_H | ||||
| #define GRID_LATTICE_REDUCTION_H | ||||
|  | ||||
| #include <Grid/Grid_Eigen_Dense.h> | ||||
|  | ||||
| namespace Grid { | ||||
| #ifdef GRID_WARN_SUBOPTIMAL | ||||
| #warning "Optimisation alert all these reduction loops are NOT threaded " | ||||
| #endif      | ||||
|  | ||||
|   //////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
|   // Deterministic Reduction operations | ||||
|   //////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
| template<class vobj> inline RealD norm2(const Lattice<vobj> &arg){ | ||||
|   auto nrm = innerProduct(arg,arg); | ||||
|   return std::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; | ||||
|   GridBase *grid = left._grid; | ||||
|   const int pad = 8; | ||||
|  | ||||
|   ComplexD  inner; | ||||
|   Vector<ComplexD> sumarray(grid->SumArraySize()*pad); | ||||
|  | ||||
|   parallel_for(int thr=0;thr<grid->SumArraySize();thr++){ | ||||
|     int nwork, mywork, myoff; | ||||
|     GridThread::GetWork(left._grid->oSites(),thr,mywork,myoff); | ||||
|      | ||||
|     decltype(innerProductD(left._odata[0],right._odata[0])) vinner=zero; // private to thread; sub summation | ||||
|     for(int ss=myoff;ss<mywork+myoff; ss++){ | ||||
|       vinner = vinner + innerProductD(left._odata[ss],right._odata[ss]); | ||||
|     } | ||||
|     // All threads sum across SIMD; reduce serial work at end | ||||
|     // one write per cacheline with streaming store | ||||
|     ComplexD tmp = Reduce(TensorRemove(vinner)) ; | ||||
|     vstream(sumarray[thr*pad],tmp); | ||||
|   } | ||||
|    | ||||
|   inner=0.0; | ||||
|   for(int i=0;i<grid->SumArraySize();i++){ | ||||
|     inner = inner+sumarray[i*pad]; | ||||
|   }  | ||||
|   right._grid->GlobalSum(inner); | ||||
|   return inner; | ||||
| } | ||||
|  | ||||
| ///////////////////////// | ||||
| // Fast axpby_norm | ||||
| // z = a x + b y | ||||
| // return norm z | ||||
| ///////////////////////// | ||||
| template<class sobj,class vobj> strong_inline RealD  | ||||
| axpy_norm_fast(Lattice<vobj> &z,sobj a,const Lattice<vobj> &x,const Lattice<vobj> &y)  | ||||
| { | ||||
|   sobj one(1.0); | ||||
|   return axpby_norm_fast(z,a,one,x,y); | ||||
| } | ||||
|  | ||||
| template<class sobj,class vobj> strong_inline RealD  | ||||
| axpby_norm_fast(Lattice<vobj> &z,sobj a,sobj b,const Lattice<vobj> &x,const Lattice<vobj> &y)  | ||||
| { | ||||
|   const int pad = 8; | ||||
|   z.checkerboard = x.checkerboard; | ||||
|   conformable(z,x); | ||||
|   conformable(x,y); | ||||
|  | ||||
|   typedef typename vobj::scalar_type scalar_type; | ||||
|   typedef typename vobj::vector_typeD vector_type; | ||||
|   RealD  nrm; | ||||
|    | ||||
|   GridBase *grid = x._grid; | ||||
|    | ||||
|   Vector<RealD> sumarray(grid->SumArraySize()*pad); | ||||
|    | ||||
|   parallel_for(int thr=0;thr<grid->SumArraySize();thr++){ | ||||
|     int nwork, mywork, myoff; | ||||
|     GridThread::GetWork(x._grid->oSites(),thr,mywork,myoff); | ||||
|      | ||||
|     // private to thread; sub summation | ||||
|     decltype(innerProductD(z._odata[0],z._odata[0])) vnrm=zero;  | ||||
|     for(int ss=myoff;ss<mywork+myoff; ss++){ | ||||
|       vobj tmp = a*x._odata[ss]+b*y._odata[ss]; | ||||
|       vnrm = vnrm + innerProductD(tmp,tmp); | ||||
|       vstream(z._odata[ss],tmp); | ||||
|     } | ||||
|     vstream(sumarray[thr*pad],real(Reduce(TensorRemove(vnrm)))) ; | ||||
|   } | ||||
|    | ||||
|   nrm = 0.0; // sum across threads; linear in thread count but fast | ||||
|   for(int i=0;i<grid->SumArraySize();i++){ | ||||
|     nrm = nrm+sumarray[i*pad]; | ||||
|   }  | ||||
|   z._grid->GlobalSum(nrm); | ||||
|   return nrm;  | ||||
| } | ||||
|  | ||||
|   | ||||
| template<class Op,class T1> | ||||
| inline auto sum(const LatticeUnaryExpression<Op,T1> & expr) | ||||
|   ->typename decltype(expr.first.func(eval(0,std::get<0>(expr.second))))::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.first.func(eval(0,std::get<0>(expr.second)),eval(0,std::get<1>(expr.second))))::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.first.func(eval(0,std::get<0>(expr.second)), | ||||
| 				      eval(0,std::get<1>(expr.second)), | ||||
| 				      eval(0,std::get<2>(expr.second)) | ||||
| 				      ))::scalar_object | ||||
| { | ||||
|   return sum(closure(expr)); | ||||
| } | ||||
|  | ||||
| template<class vobj> | ||||
| inline typename vobj::scalar_object sum(const Lattice<vobj> &arg) | ||||
| { | ||||
|   GridBase *grid=arg._grid; | ||||
|   int Nsimd = grid->Nsimd(); | ||||
|    | ||||
|   std::vector<vobj,alignedAllocator<vobj> > sumarray(grid->SumArraySize()); | ||||
|   for(int i=0;i<grid->SumArraySize();i++){ | ||||
|     sumarray[i]=zero; | ||||
|   } | ||||
|    | ||||
|   parallel_for(int thr=0;thr<grid->SumArraySize();thr++){ | ||||
|     int nwork, mywork, myoff; | ||||
|     GridThread::GetWork(grid->oSites(),thr,mywork,myoff); | ||||
|      | ||||
|     vobj vvsum=zero; | ||||
|     for(int ss=myoff;ss<mywork+myoff; ss++){ | ||||
|       vvsum = vvsum + arg._odata[ss]; | ||||
|     } | ||||
|     sumarray[thr]=vvsum; | ||||
|   } | ||||
|    | ||||
|   vobj vsum=zero;  // sum across threads | ||||
|   for(int i=0;i<grid->SumArraySize();i++){ | ||||
|     vsum = vsum+sumarray[i]; | ||||
|   }  | ||||
|    | ||||
|   typedef typename vobj::scalar_object sobj; | ||||
|   sobj ssum=zero; | ||||
|    | ||||
|   std::vector<sobj>               buf(Nsimd); | ||||
|   extract(vsum,buf); | ||||
|    | ||||
|   for(int i=0;i<Nsimd;i++) ssum = ssum + buf[i]; | ||||
|   arg._grid->GlobalSum(ssum); | ||||
|    | ||||
|   return ssum; | ||||
| } | ||||
|  | ||||
|  | ||||
| ////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
| // 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]; | ||||
|  | ||||
|   std::vector<vobj,alignedAllocator<vobj> > lvSum(rd); // will locally sum vectors first | ||||
|   std::vector<sobj> lsSum(ld,zero);                    // sum across these down to scalars | ||||
|   std::vector<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 | ||||
|   parallel_for(int r=0;r<rd;r++){ | ||||
|  | ||||
|     int so=r*grid->_ostride[orthogdim]; // base offset for start of plane  | ||||
|  | ||||
|     for(int n=0;n<e1;n++){ | ||||
|       for(int b=0;b<e2;b++){ | ||||
| 	int ss= so+n*stride+b; | ||||
| 	lvSum[r]=lvSum[r]+Data._odata[ss]; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   // Sum across simd lanes in the plane, breaking out orthog dir. | ||||
|   std::vector<int> 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; | ||||
|  | ||||
|   std::vector<vector_type,alignedAllocator<vector_type> > lvSum(rd); // will locally sum vectors first | ||||
|   lsSum.resize(ld,scalar_type(0.0));                    // sum across these down to scalars | ||||
|   std::vector<iScalar<scalar_type>> extracted(Nsimd);   // splitting the SIMD   | ||||
|   // std::cout << GridLogMessage << "End alloc" << std::endl; | ||||
|  | ||||
|   result.resize(fd); // And then global sum to return the same vector to every node for IO to file | ||||
|   for(int r=0;r<rd;r++){ | ||||
|     lvSum[r]=zero; | ||||
|   } | ||||
|  | ||||
|   int e1=    grid->_slice_nblock[orthogdim]; | ||||
|   int e2=    grid->_slice_block [orthogdim]; | ||||
|   int stride=grid->_slice_stride[orthogdim]; | ||||
|   // std::cout << GridLogMessage << "End prep" << std::endl; | ||||
|   // std::cout << GridLogMessage << "Start parallel inner product, _rd = " << rd << std::endl; | ||||
|   vector_type vv; | ||||
|   parallel_for(int r=0;r<rd;r++) | ||||
|   { | ||||
|  | ||||
|     int so=r*grid->_ostride[orthogdim]; // base offset for start of plane  | ||||
|  | ||||
|     for(int n=0;n<e1;n++){ | ||||
|       for(int b=0;b<e2;b++){ | ||||
|         int ss = so + n * stride + b; | ||||
|         vv = TensorRemove(innerProduct(lhs._odata[ss], rhs._odata[ss])); | ||||
|         lvSum[r] = lvSum[r] + vv; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|   // std::cout << GridLogMessage << "End parallel inner product" << std::endl; | ||||
|  | ||||
|   // Sum across simd lanes in the plane, breaking out orthog dir. | ||||
|   std::vector<int> icoor(Nd); | ||||
|   for(int rt=0;rt<rd;rt++){ | ||||
|  | ||||
|     iScalar<vector_type> temp;  | ||||
|     temp._internal = lvSum[rt]; | ||||
|     extract(temp,extracted); | ||||
|  | ||||
|     for(int idx=0;idx<Nsimd;idx++){ | ||||
|  | ||||
|       grid->iCoorFromIindex(icoor,idx); | ||||
|  | ||||
|       int ldx =rt+icoor[orthogdim]*rd; | ||||
|  | ||||
|       lsSum[ldx]=lsSum[ldx]+extracted[idx]._internal; | ||||
|  | ||||
|     } | ||||
|   } | ||||
|   // std::cout << GridLogMessage << "End sum over simd lanes" << std::endl; | ||||
| } | ||||
| template <class vobj> | ||||
| static void globalSliceInnerProductVector(std::vector<ComplexD> &result, const Lattice<vobj> &lhs, std::vector<typename vobj::scalar_type> &lsSum, int orthogdim) | ||||
| { | ||||
|   typedef typename vobj::scalar_type scalar_type; | ||||
|   GridBase *grid = lhs._grid; | ||||
|   int fd = result.size(); | ||||
|   int ld = lsSum.size(); | ||||
|   // sum over nodes. | ||||
|   std::vector<scalar_type> gsum; | ||||
|   gsum.resize(fd, scalar_type(0.0)); | ||||
|   // std::cout << GridLogMessage << "Start of gsum[t] creation:" << std::endl; | ||||
|   for(int t=0;t<fd;t++){ | ||||
|     int pt = t/ld; // processor plane | ||||
|     int lt = t%ld; | ||||
|     if ( pt == grid->_processor_coor[orthogdim] ) { | ||||
|       gsum[t]=lsSum[lt]; | ||||
|     } | ||||
|   } | ||||
|   // std::cout << GridLogMessage << "End of gsum[t] creation:" << std::endl; | ||||
|   // std::cout << GridLogMessage << "Start of GlobalSumVector:" << std::endl; | ||||
|   grid->GlobalSumVector(&gsum[0], fd); | ||||
|   // std::cout << GridLogMessage << "End of GlobalSumVector:" << std::endl; | ||||
|  | ||||
|   result = gsum; | ||||
| } | ||||
| template<class vobj> | ||||
| 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]; | ||||
|  | ||||
|   std::vector<vector_type,alignedAllocator<vector_type> > lvSum(rd); // will locally sum vectors first | ||||
|   std::vector<scalar_type > lsSum(ld,scalar_type(0.0));                    // sum across these down to scalars | ||||
|   std::vector<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]; | ||||
|  | ||||
|   parallel_for(int r=0;r<rd;r++){ | ||||
|  | ||||
|     int so=r*grid->_ostride[orthogdim]; // base offset for start of plane  | ||||
|  | ||||
|     for(int n=0;n<e1;n++){ | ||||
|       for(int b=0;b<e2;b++){ | ||||
| 	int ss= so+n*stride+b; | ||||
| 	vector_type vv = TensorRemove(innerProduct(lhs._odata[ss],rhs._odata[ss])); | ||||
| 	lvSum[r]=lvSum[r]+vv; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   // Sum across simd lanes in the plane, breaking out orthog dir. | ||||
|   std::vector<int> icoor(Nd); | ||||
|   for(int rt=0;rt<rd;rt++){ | ||||
|  | ||||
|     iScalar<vector_type> temp;  | ||||
|     temp._internal = lvSum[rt]; | ||||
|     extract(temp,extracted); | ||||
|  | ||||
|     for(int idx=0;idx<Nsimd;idx++){ | ||||
|  | ||||
|       grid->iCoorFromIindex(icoor,idx); | ||||
|  | ||||
|       int ldx =rt+icoor[orthogdim]*rd; | ||||
|  | ||||
|       lsSum[ldx]=lsSum[ldx]+extracted[idx]._internal; | ||||
|  | ||||
|     } | ||||
|   } | ||||
|    | ||||
|   // 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]; | ||||
|  | ||||
|   std::vector<int> 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; | ||||
|  | ||||
|     parallel_for_nest2(int n=0;n<e1;n++){ | ||||
|       for(int b=0;b<e2;b++){ | ||||
| 	int ss= so+n*stride+b; | ||||
| 	R._odata[ss] = at*X._odata[ss]+Y._odata[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]; | ||||
| #pragma omp parallel  | ||||
|   { | ||||
|     std::vector<vobj> s_x(Nblock); | ||||
|  | ||||
| #pragma omp for collapse(2) | ||||
|     for(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[o+i*ostride]; | ||||
|       } | ||||
|  | ||||
|       vobj dot; | ||||
|       for(int i=0;i<Nblock;i++){ | ||||
| 	dot = Y[o+i*ostride]; | ||||
| 	for(int j=0;j<Nblock;j++){ | ||||
| 	  dot = dot + s_x[j]*(scale*aa(j,i)); | ||||
| 	} | ||||
| 	R[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]; | ||||
| #pragma omp parallel  | ||||
|   { | ||||
|     std::vector<vobj> s_x(Nblock); | ||||
|  | ||||
| #pragma omp for collapse(2) | ||||
|     for(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[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[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; | ||||
|  | ||||
| #pragma omp parallel  | ||||
|   { | ||||
|     std::vector<vobj> Left(Nblock); | ||||
|     std::vector<vobj> Right(Nblock); | ||||
|     Eigen::MatrixXcd  mat_thread = Eigen::MatrixXcd::Zero(Nblock,Nblock); | ||||
|  | ||||
| #pragma omp for collapse(2) | ||||
|     for(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[o+i*ostride]; | ||||
| 	Right[i] = rhs[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); | ||||
| 	mat_thread(i,j) += Reduce(rtmp); | ||||
|       }} | ||||
|     }} | ||||
| #pragma omp 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; | ||||
| } | ||||
|  | ||||
| } /*END NAMESPACE GRID*/ | ||||
| #endif | ||||
|  | ||||
|  | ||||
|  | ||||
							
								
								
									
										520
									
								
								Grid/lattice/Lattice_rng.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										520
									
								
								Grid/lattice/Lattice_rng.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,520 @@ | ||||
|     /************************************************************************************* | ||||
|  | ||||
|     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 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)); | ||||
|   } | ||||
|   template<class distribution,class generator>  | ||||
|   void fillScalar(ComplexD &s,distribution &dist,generator &gen) | ||||
|   { | ||||
|     s=ComplexD(dist(gen),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; | ||||
|  | ||||
|       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 { | ||||
|  | ||||
|     double _time_counter; | ||||
|  | ||||
|   public: | ||||
|     GridBase *_grid; | ||||
|     unsigned int _vol; | ||||
|  | ||||
|     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); | ||||
|  | ||||
|       parallel_for(int ss=0;ss<osites;ss++){ | ||||
|         std::vector<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._odata[sm], buf); | ||||
|         } | ||||
|       } | ||||
|  | ||||
|       _time_counter += usecond()- inner_time_counter; | ||||
|     }; | ||||
|  | ||||
|     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 parallel RNG with unique string '"  | ||||
|                 << s << "'" << std::endl; | ||||
|       std::cout << GridLogMessage << "Seed SHA256: " << sha.str() << 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. | ||||
|       parallel_for(int gidx=0;gidx<_grid->_gsites;gidx++){ | ||||
|  | ||||
| 	// Where is it? | ||||
| 	int rank,o_idx,i_idx; | ||||
| 	std::vector<int> 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); | ||||
| 	} | ||||
|  | ||||
| 	parallel_for(int t=0;t<Nthread;t++) { | ||||
| 	  // 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 | ||||
|       std::vector<int> gcoor; | ||||
|       int rank,o_idx,i_idx; | ||||
|       _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); } | ||||
|  | ||||
| } | ||||
| #endif | ||||
| @@ -42,8 +42,7 @@ namespace Grid { | ||||
|       -> Lattice<decltype(trace(lhs._odata[0]))> | ||||
|     { | ||||
|       Lattice<decltype(trace(lhs._odata[0]))> ret(lhs._grid); | ||||
| PARALLEL_FOR_LOOP | ||||
|         for(int ss=0;ss<lhs._grid->oSites();ss++){ | ||||
|       parallel_for(int ss=0;ss<lhs._grid->oSites();ss++){ | ||||
|             ret._odata[ss] = trace(lhs._odata[ss]); | ||||
|         } | ||||
|         return ret; | ||||
| @@ -56,8 +55,7 @@ PARALLEL_FOR_LOOP | ||||
|     inline auto TraceIndex(const Lattice<vobj> &lhs) -> Lattice<decltype(traceIndex<Index>(lhs._odata[0]))> | ||||
|     { | ||||
|       Lattice<decltype(traceIndex<Index>(lhs._odata[0]))> ret(lhs._grid); | ||||
| PARALLEL_FOR_LOOP | ||||
|       for(int ss=0;ss<lhs._grid->oSites();ss++){ | ||||
|       parallel_for(int ss=0;ss<lhs._grid->oSites();ss++){ | ||||
| 	ret._odata[ss] = traceIndex<Index>(lhs._odata[ss]); | ||||
|       } | ||||
|       return ret; | ||||
							
								
								
									
										1085
									
								
								Grid/lattice/Lattice_transfer.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1085
									
								
								Grid/lattice/Lattice_transfer.h
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -41,8 +41,7 @@ namespace Grid { | ||||
|   template<class vobj> | ||||
|     inline Lattice<vobj> transpose(const Lattice<vobj> &lhs){ | ||||
|     Lattice<vobj> ret(lhs._grid); | ||||
| PARALLEL_FOR_LOOP | ||||
|         for(int ss=0;ss<lhs._grid->oSites();ss++){ | ||||
|     parallel_for(int ss=0;ss<lhs._grid->oSites();ss++){ | ||||
|       ret._odata[ss] = transpose(lhs._odata[ss]); | ||||
|     } | ||||
|     return ret; | ||||
| @@ -55,12 +54,10 @@ PARALLEL_FOR_LOOP | ||||
|     inline auto TransposeIndex(const Lattice<vobj> &lhs) -> Lattice<decltype(transposeIndex<Index>(lhs._odata[0]))> | ||||
|   { | ||||
|     Lattice<decltype(transposeIndex<Index>(lhs._odata[0]))> ret(lhs._grid); | ||||
| PARALLEL_FOR_LOOP | ||||
|         for(int ss=0;ss<lhs._grid->oSites();ss++){ | ||||
|     parallel_for(int ss=0;ss<lhs._grid->oSites();ss++){ | ||||
|       ret._odata[ss] = transposeIndex<Index>(lhs._odata[ss]); | ||||
|     } | ||||
|     return ret; | ||||
|   }; | ||||
| 
 | ||||
| } | ||||
| #endif | ||||
| @@ -37,8 +37,7 @@ namespace Grid { | ||||
|     Lattice<obj> ret(rhs._grid); | ||||
|     ret.checkerboard = rhs.checkerboard; | ||||
|     conformable(ret,rhs); | ||||
| PARALLEL_FOR_LOOP | ||||
|     for(int ss=0;ss<rhs._grid->oSites();ss++){ | ||||
|     parallel_for(int ss=0;ss<rhs._grid->oSites();ss++){ | ||||
|       ret._odata[ss]=pow(rhs._odata[ss],y); | ||||
|     } | ||||
|     return ret; | ||||
| @@ -47,8 +46,7 @@ PARALLEL_FOR_LOOP | ||||
|     Lattice<obj> ret(rhs._grid); | ||||
|     ret.checkerboard = rhs.checkerboard; | ||||
|     conformable(ret,rhs); | ||||
| PARALLEL_FOR_LOOP | ||||
|     for(int ss=0;ss<rhs._grid->oSites();ss++){ | ||||
|     parallel_for(int ss=0;ss<rhs._grid->oSites();ss++){ | ||||
|       ret._odata[ss]=mod(rhs._odata[ss],y); | ||||
|     } | ||||
|     return ret; | ||||
| @@ -58,22 +56,26 @@ PARALLEL_FOR_LOOP | ||||
|     Lattice<obj> ret(rhs._grid); | ||||
|     ret.checkerboard = rhs.checkerboard; | ||||
|     conformable(ret,rhs); | ||||
| PARALLEL_FOR_LOOP | ||||
|     for(int ss=0;ss<rhs._grid->oSites();ss++){ | ||||
|     parallel_for(int ss=0;ss<rhs._grid->oSites();ss++){ | ||||
|       ret._odata[ss]=div(rhs._odata[ss],y); | ||||
|     } | ||||
|     return ret; | ||||
|   } | ||||
| 
 | ||||
|   template<class obj> Lattice<obj> expMat(const Lattice<obj> &rhs, ComplexD alpha, Integer Nexp = DEFAULT_MAT_EXP){ | ||||
|   template<class obj> Lattice<obj> expMat(const Lattice<obj> &rhs, RealD alpha, Integer Nexp = DEFAULT_MAT_EXP){ | ||||
|     Lattice<obj> ret(rhs._grid); | ||||
|     ret.checkerboard = rhs.checkerboard; | ||||
|     conformable(ret,rhs); | ||||
| PARALLEL_FOR_LOOP | ||||
|     for(int ss=0;ss<rhs._grid->oSites();ss++){ | ||||
|     parallel_for(int ss=0;ss<rhs._grid->oSites();ss++){ | ||||
|       ret._odata[ss]=Exponentiate(rhs._odata[ss],alpha, Nexp); | ||||
|     } | ||||
| 
 | ||||
|     return ret; | ||||
| 
 | ||||
|      | ||||
|      | ||||
| 
 | ||||
|      | ||||
|   } | ||||
| 
 | ||||
| 
 | ||||
| @@ -56,8 +56,7 @@ inline void whereWolf(Lattice<vobj> &ret,const Lattice<iobj> &predicate,Lattice< | ||||
|   std::vector<scalar_object> truevals (Nsimd); | ||||
|   std::vector<scalar_object> falsevals(Nsimd); | ||||
| 
 | ||||
| PARALLEL_FOR_LOOP | ||||
|   for(int ss=0;ss<iftrue._grid->oSites(); ss++){ | ||||
|   parallel_for(int ss=0;ss<iftrue._grid->oSites(); ss++){ | ||||
| 
 | ||||
|     extract(iftrue._odata[ss]   ,truevals); | ||||
|     extract(iffalse._odata[ss]  ,falsevals); | ||||
							
								
								
									
										116
									
								
								Grid/log/Log.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										116
									
								
								Grid/log/Log.cc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,116 @@ | ||||
| /************************************************************************************* | ||||
|  | ||||
| Grid physics library, www.github.com/paboyle/Grid | ||||
|  | ||||
| Source file: ./lib/Log.cc | ||||
|  | ||||
| Copyright (C) 2015 | ||||
|  | ||||
| Author: Antonin Portelli <antonin.portelli@me.com> | ||||
| 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 */ | ||||
| #include <Grid/GridCore.h> | ||||
| #include <Grid/util/CompilerCompatible.h> | ||||
|  | ||||
| #include <cxxabi.h> | ||||
| #include <memory> | ||||
|  | ||||
| namespace Grid { | ||||
|  | ||||
|   std::string demangle(const char* name) { | ||||
|      | ||||
|     int status = -4; // some arbitrary value to eliminate the compiler warning | ||||
|      | ||||
|     // enable c++11 by passing the flag -std=c++11 to g++ | ||||
|     std::unique_ptr<char, void(*)(void*)> res { | ||||
|       abi::__cxa_demangle(name, NULL, NULL, &status), | ||||
| 	std::free | ||||
| 	}; | ||||
|      | ||||
|     return (status==0) ? res.get() : name ; | ||||
|   } | ||||
|    | ||||
| GridStopWatch Logger::GlobalStopWatch; | ||||
| int Logger::timestamp; | ||||
| std::ostream Logger::devnull(0); | ||||
|  | ||||
| void GridLogTimestamp(int on){ | ||||
|   Logger::Timestamp(on); | ||||
| } | ||||
|  | ||||
| Colours GridLogColours(0); | ||||
| 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 GridLogMessage(1, "Message", GridLogColours, "NORMAL"); | ||||
| GridLogger GridLogDebug  (1, "Debug", GridLogColours, "PURPLE"); | ||||
| GridLogger GridLogPerformance(1, "Performance", GridLogColours, "GREEN"); | ||||
| GridLogger GridLogIterative  (1, "Iterative", GridLogColours, "BLUE"); | ||||
| GridLogger GridLogIntegrator (1, "Integrator", GridLogColours, "BLUE"); | ||||
|  | ||||
| void GridLogConfigure(std::vector<std::string> &logstreams) { | ||||
|   GridLogError.Active(0); | ||||
|   GridLogWarning.Active(0); | ||||
|   GridLogMessage.Active(1); // at least the messages should be always on | ||||
|   GridLogIterative.Active(0); | ||||
|   GridLogDebug.Active(0); | ||||
|   GridLogPerformance.Active(0); | ||||
|   GridLogIntegrator.Active(0); | ||||
|   GridLogColours.Active(0); | ||||
|  | ||||
|   for (int i = 0; i < logstreams.size(); i++) { | ||||
|     if (logstreams[i] == std::string("Error")) GridLogError.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("Iterative")) GridLogIterative.Active(1); | ||||
|     if (logstreams[i] == std::string("Debug")) GridLogDebug.Active(1); | ||||
|     if (logstreams[i] == std::string("Performance")) | ||||
|       GridLogPerformance.Active(1); | ||||
|     if (logstreams[i] == std::string("Integrator")) GridLogIntegrator.Active(1); | ||||
|     if (logstreams[i] == std::string("Colours")) GridLogColours.Active(1); | ||||
|   } | ||||
| } | ||||
|  | ||||
| //////////////////////////////////////////////////////////// | ||||
| // Verbose limiter on MPI tasks | ||||
| //////////////////////////////////////////////////////////// | ||||
| void Grid_quiesce_nodes(void) { | ||||
|   int me = 0; | ||||
| #if defined(GRID_COMMS_MPI) || defined(GRID_COMMS_MPI3) || defined(GRID_COMMS_MPIT) | ||||
|   MPI_Comm_rank(MPI_COMM_WORLD, &me); | ||||
| #endif | ||||
| #ifdef GRID_COMMS_SHMEM | ||||
|   me = shmem_my_pe(); | ||||
| #endif | ||||
|   if (me) { | ||||
|     std::cout.setstate(std::ios::badbit); | ||||
|   } | ||||
| } | ||||
|  | ||||
| void Grid_unquiesce_nodes(void) { | ||||
| #ifdef GRID_COMMS_MPI | ||||
|   std::cout.clear(); | ||||
| #endif | ||||
| } | ||||
| } | ||||
							
								
								
									
										216
									
								
								Grid/log/Log.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										216
									
								
								Grid/log/Log.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,216 @@ | ||||
|     /************************************************************************************* | ||||
|  | ||||
|     Grid physics library, www.github.com/paboyle/Grid  | ||||
|  | ||||
|     Source file: ./lib/Log.h | ||||
|  | ||||
|     Copyright (C) 2015 | ||||
|  | ||||
|     Author: Antonin Portelli <antonin.portelli@me.com> | ||||
|     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 */ | ||||
|  | ||||
| #include <map> | ||||
|  | ||||
| #ifndef GRID_LOG_H | ||||
| #define GRID_LOG_H | ||||
|  | ||||
| #ifdef HAVE_EXECINFO_H | ||||
| #include <execinfo.h> | ||||
| #endif | ||||
|  | ||||
| namespace Grid { | ||||
|  | ||||
| ////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
| // Dress the output; use std::chrono for time stamping via the StopWatch class | ||||
| ////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
|  | ||||
|  | ||||
| class Colours{ | ||||
| protected: | ||||
|   bool is_active; | ||||
| public: | ||||
|   std::map<std::string, std::string> colour; | ||||
|  | ||||
|   Colours(bool activate=false){ | ||||
|     Active(activate); | ||||
|   }; | ||||
|  | ||||
|   void Active(bool activate){ | ||||
|     is_active=activate; | ||||
|     if (is_active){ | ||||
|      colour["BLACK"]  ="\033[30m"; | ||||
|      colour["RED"]    ="\033[31m"; | ||||
|      colour["GREEN"]  ="\033[32m"; | ||||
|      colour["YELLOW"] ="\033[33m"; | ||||
|      colour["BLUE"]   ="\033[34m"; | ||||
|      colour["PURPLE"] ="\033[35m"; | ||||
|      colour["CYAN"]   ="\033[36m"; | ||||
|      colour["WHITE"]  ="\033[37m"; | ||||
|      colour["NORMAL"] ="\033[0;39m"; | ||||
|     } else { | ||||
|       colour["BLACK"] =""; | ||||
|       colour["RED"]   =""; | ||||
|       colour["GREEN"] =""; | ||||
|       colour["YELLOW"]=""; | ||||
|       colour["BLUE"]  =""; | ||||
|       colour["PURPLE"]=""; | ||||
|       colour["CYAN"]  =""; | ||||
|       colour["WHITE"] =""; | ||||
|       colour["NORMAL"]=""; | ||||
|     } | ||||
|   }; | ||||
| }; | ||||
|  | ||||
|  | ||||
| class Logger { | ||||
| protected: | ||||
|   Colours &Painter; | ||||
|   int active; | ||||
|   int timing_mode; | ||||
|   int topWidth{-1}, chanWidth{-1}; | ||||
|   static int timestamp; | ||||
|   std::string name, topName; | ||||
|   std::string COLOUR; | ||||
|  | ||||
| public: | ||||
|   static GridStopWatch GlobalStopWatch; | ||||
|   GridStopWatch         LocalStopWatch; | ||||
|   GridStopWatch *StopWatch; | ||||
|   static std::ostream devnull; | ||||
|  | ||||
|   std::string background() {return Painter.colour["NORMAL"];} | ||||
|   std::string evidence() {return Painter.colour["YELLOW"];} | ||||
|   std::string colour() {return Painter.colour[COLOUR];} | ||||
|  | ||||
|   Logger(std::string topNm, int on, std::string nm, Colours& col_class, std::string col)  : active(on), | ||||
|     name(nm), | ||||
|     topName(topNm), | ||||
|     Painter(col_class), | ||||
|     timing_mode(0), | ||||
|     COLOUR(col)  | ||||
|     { | ||||
|       StopWatch = & GlobalStopWatch; | ||||
|     }; | ||||
|    | ||||
|   void Active(int on) {active = on;}; | ||||
|   int  isActive(void) {return active;}; | ||||
|   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){ | ||||
|  | ||||
|     if ( log.active ) { | ||||
|       stream << log.background()<<  std::left; | ||||
|       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 ) { | ||||
| 	log.StopWatch->Stop(); | ||||
| 	GridTime now = log.StopWatch->Elapsed(); | ||||
| 	if ( log.timing_mode==1 ) log.StopWatch->Reset(); | ||||
| 	log.StopWatch->Start(); | ||||
| 	stream << log.evidence()<< std::setw(6)<<now << log.background() << " : " ; | ||||
|       } | ||||
|       stream << log.colour(); | ||||
|       return stream; | ||||
|     } else {  | ||||
|       return devnull; | ||||
|     } | ||||
|   } | ||||
|  | ||||
| }; | ||||
|  | ||||
| class GridLogger: public Logger { | ||||
| public: | ||||
|   GridLogger(int on, std::string nm, Colours&col_class, std::string col_key = "NORMAL"): | ||||
|   Logger("Grid", on, nm, col_class, col_key){}; | ||||
| }; | ||||
|  | ||||
| void GridLogConfigure(std::vector<std::string> &logstreams); | ||||
|  | ||||
| extern GridLogger GridLogIRL; | ||||
| extern GridLogger GridLogSolver; | ||||
| extern GridLogger GridLogError; | ||||
| extern GridLogger GridLogWarning; | ||||
| extern GridLogger GridLogMessage; | ||||
| extern GridLogger GridLogDebug  ; | ||||
| extern GridLogger GridLogPerformance; | ||||
| extern GridLogger GridLogIterative  ; | ||||
| extern GridLogger GridLogIntegrator  ; | ||||
| extern Colours    GridLogColours; | ||||
|  | ||||
|  std::string demangle(const char* name) ; | ||||
|  | ||||
| #define _NBACKTRACE (256) | ||||
| extern void * Grid_backtrace_buffer[_NBACKTRACE]; | ||||
|  | ||||
| #define BACKTRACEFILE() {\ | ||||
| char string[20];					\ | ||||
| std::sprintf(string,"backtrace.%d",CartesianCommunicator::RankWorld()); \ | ||||
| std::FILE * fp = std::fopen(string,"w");				\ | ||||
| BACKTRACEFP(fp)\ | ||||
| std::fclose(fp);	    \ | ||||
| } | ||||
|  | ||||
|  | ||||
| #ifdef HAVE_EXECINFO_H | ||||
| #define BACKTRACEFP(fp) { \ | ||||
| int symbols    = backtrace        (Grid_backtrace_buffer,_NBACKTRACE);\ | ||||
| char **strings = backtrace_symbols(Grid_backtrace_buffer,symbols);\ | ||||
| for (int i = 0; i < symbols; i++){\ | ||||
|   std::fprintf (fp,"BackTrace Strings: %d %s\n",i, demangle(strings[i]).c_str()); std::fflush(fp); \ | ||||
| }\ | ||||
| } | ||||
| #else  | ||||
| #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",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",3, __builtin_return_address(3)); std::fflush(fp); \ | ||||
| } | ||||
| #endif | ||||
|  | ||||
| #define BACKTRACE() BACKTRACEFP(stdout)  | ||||
|  | ||||
|  | ||||
| } | ||||
| #endif | ||||
							
								
								
									
										729
									
								
								Grid/parallelIO/BinaryIO.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										729
									
								
								Grid/parallelIO/BinaryIO.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,729 @@ | ||||
|     /************************************************************************************* | ||||
|  | ||||
|     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 */ | ||||
| #ifndef GRID_BINARY_IO_H | ||||
| #define GRID_BINARY_IO_H | ||||
|  | ||||
| #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 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: | ||||
|  | ||||
|   ///////////////////////////////////////////////////////////////////////////// | ||||
|   // 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; | ||||
|     } | ||||
|  | ||||
| PARALLEL_REGION | ||||
|     { | ||||
|       uint32_t nersc_csum_thr = 0; | ||||
|  | ||||
| PARALLEL_FOR_LOOP_INTERN | ||||
|       for (uint64_t local_site = 0; local_site < lsites; local_site++) | ||||
|       { | ||||
|         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]; | ||||
|         } | ||||
|       } | ||||
|  | ||||
| PARALLEL_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) | ||||
|   { | ||||
|     const uint64_t size32 = sizeof(fobj)/sizeof(uint32_t); | ||||
|  | ||||
|  | ||||
|     int nd = grid->_ndimension; | ||||
|  | ||||
|     uint64_t lsites              =grid->lSites(); | ||||
|     if (fbuf.size()==1) { | ||||
|       lsites=1; | ||||
|     } | ||||
|     std::vector<int> local_vol   =grid->LocalDimensions(); | ||||
|     std::vector<int> local_start =grid->LocalStarts(); | ||||
|     std::vector<int> global_vol  =grid->FullDimensions(); | ||||
|  | ||||
| PARALLEL_REGION | ||||
|     {  | ||||
|       std::vector<int> coor(nd); | ||||
|       uint32_t scidac_csuma_thr=0; | ||||
|       uint32_t scidac_csumb_thr=0; | ||||
|       uint32_t site_crc=0; | ||||
|  | ||||
| PARALLEL_FOR_LOOP_INTERN | ||||
|       for(uint64_t local_site=0;local_site<lsites;local_site++){ | ||||
|  | ||||
| 	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); | ||||
|       } | ||||
|  | ||||
| PARALLEL_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); | ||||
|     parallel_for(uint64_t i=0;i<count;i++){   | ||||
|       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; | ||||
|     uint32_t f; | ||||
|  | ||||
|     uint64_t count = bytes/sizeof(uint32_t); | ||||
|     parallel_for(uint64_t i=0;i<count;i++){   | ||||
|       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); | ||||
|     parallel_for(uint64_t i=0;i<count;i++){   | ||||
|       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 f,g; | ||||
|      | ||||
|     uint64_t count = bytes/sizeof(uint64_t); | ||||
|     parallel_for(uint64_t i=0;i<count;i++){   | ||||
|       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(); | ||||
|  | ||||
|     std::vector<int>  psizes = grid->ProcessorGrid();  | ||||
|     std::vector<int>  pcoor  = grid->ThisProcessorCoor(); | ||||
|     std::vector<int> gLattice= grid->GlobalDimensions(); | ||||
|     std::vector<int> lLattice= grid->LocalDimensions(); | ||||
|  | ||||
|     std::vector<int> lStart(ndim); | ||||
|     std::vector<int> 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")); | ||||
|  | ||||
|     ////////////////////////////////////////////////////////////////////////////// | ||||
|     // 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" << 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(); | ||||
|  | ||||
|     parallel_for(uint64_t x=0;x<lsites;x++) 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(); | ||||
|  | ||||
|     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);     | ||||
|  | ||||
|     parallel_for(uint64_t x=0;x<lsites;x++) munge(scalardata[x],iodata[x]); | ||||
|  | ||||
|     grid->Barrier(); | ||||
|     timer.Stop(); | ||||
|  | ||||
|     IOobject(w,grid,iodata,file,offset,format,BINARYIO_WRITE|BINARYIO_LEXICOGRAPHIC, | ||||
| 	     nersc_csum,scidac_csuma,scidac_csumb); | ||||
|  | ||||
|     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, | ||||
| 			     GridParallelRNG ¶llel, | ||||
| 			     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._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(); | ||||
|     parallel_for(uint64_t lidx=0;lidx<lsites;lidx++){ | ||||
|       std::vector<RngStateType> tmp(RngStateCount); | ||||
|       std::copy(iodata[lidx].begin(),iodata[lidx].end(),tmp.begin()); | ||||
|       parallel.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.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, | ||||
| 			      GridParallelRNG ¶llel, | ||||
| 			      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._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); | ||||
|     parallel_for(uint64_t lidx=0;lidx<lsites;lidx++){ | ||||
|       std::vector<RngStateType> tmp(RngStateCount); | ||||
|       parallel.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.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; | ||||
|   } | ||||
| }; | ||||
| } | ||||
| #endif | ||||
							
								
								
									
										875
									
								
								Grid/parallelIO/IldgIO.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										875
									
								
								Grid/parallelIO/IldgIO.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,875 @@ | ||||
| /************************************************************************************* | ||||
|  | ||||
| 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_ILDG_IO_H | ||||
| #define GRID_ILDG_IO_H | ||||
|  | ||||
| #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 Grid { | ||||
| namespace QCD { | ||||
|  | ||||
|   ///////////////////////////////// | ||||
|   // 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_; | ||||
|     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); | ||||
|  | ||||
| 	///////////////////////////////////////////// | ||||
| 	// Insist checksum is next record | ||||
| 	///////////////////////////////////////////// | ||||
| 	readLimeObject(scidacChecksum_,std::string("scidacChecksum"),std::string(SCIDAC_CHECKSUM)); | ||||
|  | ||||
| 	///////////////////////////////////////////// | ||||
| 	// Verify checksums | ||||
| 	///////////////////////////////////////////// | ||||
| 	assert(scidacChecksumVerify(scidacChecksum_,scidac_csuma,scidac_csumb)==1); | ||||
| 	return; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|   //////////////////////////////////////////// | ||||
|   // 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() ); | ||||
|  | ||||
|     //////////////////////////////////////////// | ||||
|     // 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,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()); | ||||
|  | ||||
|     ////////////////////////////////////////////////////////////////////////////// | ||||
|     // 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 "<<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,_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; | ||||
|  | ||||
|     std::vector<int> dims = Umu._grid->FullDimensions(); | ||||
|  | ||||
|     assert(dims.size()==4); | ||||
|  | ||||
|     // Metadata holders | ||||
|     ildgFormat     ildgFormat_    ; | ||||
|     std::string    ildgLFN_       ; | ||||
|     scidacChecksum scidacChecksum_;  | ||||
|     usqcdInfo      usqcdInfo_     ; | ||||
|  | ||||
|     // 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; | ||||
|  | ||||
|     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; | ||||
| 	} | ||||
|  | ||||
|       } 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_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_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; | ||||
|     } | ||||
|   } | ||||
|  }; | ||||
|  | ||||
| }} | ||||
|  | ||||
| //HAVE_LIME | ||||
| #endif | ||||
|  | ||||
| #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 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(std::vector<int> 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 | ||||
|  | ||||
| } | ||||
| #endif | ||||
| #endif | ||||
							
								
								
									
										327
									
								
								Grid/parallelIO/MetaData.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										327
									
								
								Grid/parallelIO/MetaData.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,327 @@ | ||||
| /************************************************************************************* | ||||
|  | ||||
|     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 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 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) | ||||
|       {} | ||||
|     }; | ||||
|  | ||||
|   namespace QCD { | ||||
|  | ||||
|     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=Grid::QCD::WilsonLoops<PeriodicGimplF>::linkTrace(data); | ||||
|    header.plaquette =Grid::QCD::WilsonLoops<PeriodicGimplF>::avgPlaquette(data); | ||||
|  } | ||||
|  inline void GaugeStatistics(Lattice<vLorentzColourMatrixD> & data,FieldMetaData &header) | ||||
|  { | ||||
|    // How to convert data precision etc... | ||||
|    header.link_trace=Grid::QCD::WilsonLoops<PeriodicGimplD>::linkTrace(data); | ||||
|    header.plaquette =Grid::QCD::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); | ||||
| 	  }} | ||||
| 	} | ||||
|       } | ||||
|     }; | ||||
|   } | ||||
|  | ||||
|  | ||||
| } | ||||
							
								
								
									
										363
									
								
								Grid/parallelIO/NerscIO.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										363
									
								
								Grid/parallelIO/NerscIO.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,363 @@ | ||||
| /************************************************************************************* | ||||
|  | ||||
|     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 Grid { | ||||
|   namespace QCD { | ||||
|  | ||||
|     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) | ||||
|       { | ||||
|       uint64_t offset=0; | ||||
|       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; | ||||
| 	std::cout << Umu[0]<<std::endl; | ||||
| 	std::cout << Umu[1]<<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; | ||||
|       } | ||||
|  | ||||
|     }; | ||||
|  | ||||
|   }} | ||||
| #endif | ||||
| @@ -26,34 +26,50 @@ Author: paboyle <paboyle@ph.ed.ac.uk> | ||||
|     *************************************************************************************/ | ||||
|     /*  END LEGAL */ | ||||
| 
 | ||||
| #include <Grid.h> | ||||
| #include <PerfCount.h> | ||||
| #include <Grid/GridCore.h> | ||||
| #include <Grid/perfmon/PerfCount.h> | ||||
| 
 | ||||
| namespace 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 RawConfig(A,B) (A<<8|B) | ||||
| const PerformanceCounter::PerformanceCounterConfig PerformanceCounter::PerformanceCounterConfigs [] = { | ||||
| #ifdef __linux__ | ||||
|   { PERF_TYPE_HARDWARE, PERF_COUNT_HW_CPU_CYCLES          ,  "CPUCYCLES.........." }, | ||||
|   { PERF_TYPE_HARDWARE, PERF_COUNT_HW_INSTRUCTIONS        ,  "INSTRUCTIONS......." }, | ||||
|   { PERF_TYPE_HARDWARE, PERF_COUNT_HW_CACHE_REFERENCES    ,  "CACHE_REFERENCES..." }, | ||||
|   { PERF_TYPE_HARDWARE, PERF_COUNT_HW_CACHE_MISSES        ,  "CACHE_MISSES......." }, | ||||
|   { PERF_TYPE_HW_CACHE, CacheControl(L1D,READ,MISS)       ,  "L1D_READ_MISS......"}, | ||||
|   { PERF_TYPE_HW_CACHE, CacheControl(L1D,READ,ACCESS)     ,  "L1D_READ_ACCESS...."}, | ||||
|   { PERF_TYPE_HW_CACHE, CacheControl(L1D,WRITE,MISS)      ,  "L1D_WRITE_MISS....."}, | ||||
|   { PERF_TYPE_HW_CACHE, CacheControl(L1D,WRITE,ACCESS)    ,  "L1D_WRITE_ACCESS..."}, | ||||
|   { PERF_TYPE_HW_CACHE, CacheControl(L1D,PREFETCH,MISS)   ,  "L1D_PREFETCH_MISS.."}, | ||||
|   { PERF_TYPE_HW_CACHE, CacheControl(L1D,PREFETCH,ACCESS) ,  "L1D_PREFETCH_ACCESS"}, | ||||
|   { PERF_TYPE_HW_CACHE, CacheControl(LL,READ,MISS)        ,  "LL_READ_MISS......."}, | ||||
|   //  { PERF_TYPE_HW_CACHE, CacheControl(LL,READ,ACCESS)      ,  "LL_READ_ACCESS....."},
 | ||||
|   { PERF_TYPE_HW_CACHE, CacheControl(LL,WRITE,MISS)       ,  "LL_WRITE_MISS......"}, | ||||
|   { PERF_TYPE_HW_CACHE, CacheControl(LL,WRITE,ACCESS)     ,  "LL_WRITE_ACCESS...."}, | ||||
|   { PERF_TYPE_HW_CACHE, CacheControl(LL,PREFETCH,MISS)    ,  "LL_PREFETCH_MISS..."}, | ||||
|   { PERF_TYPE_HW_CACHE, CacheControl(LL,PREFETCH,ACCESS)  ,  "LL_PREFETCH_ACCESS."}, | ||||
|   { PERF_TYPE_HW_CACHE, CacheControl(L1I,READ,MISS)       ,  "L1I_READ_MISS......"}, | ||||
|   { PERF_TYPE_HW_CACHE, CacheControl(L1I,READ,ACCESS)     ,  "L1I_READ_ACCESS...."} | ||||
|   { PERF_TYPE_HARDWARE, PERF_COUNT_HW_CACHE_REFERENCES    ,  "CACHE_REFERENCES..." , INSTRUCTIONS}, | ||||
|   { 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_INSTRUCTIONS        ,  "INSTRUCTIONS......." , CPUCYCLES   }, | ||||
|     // 4
 | ||||
| #ifdef KNL | ||||
|     { 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(0x40,0x04), "ALL_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(0x10,0x04), "UTLB_MISS_LOADS....", L1D_READ_ACCESS }, | ||||
|     { PERF_TYPE_RAW, RawConfig(0x08,0x04), "DTLB_MISS_LOADS....", L1D_READ_ACCESS }, | ||||
|     // 11
 | ||||
| #else | ||||
|   { 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,WRITE,MISS)      ,  "L1D_WRITE_MISS.....",L1D_READ_ACCESS}, | ||||
|   { PERF_TYPE_HW_CACHE, CacheControl(L1D,WRITE,ACCESS)    ,  "L1D_WRITE_ACCESS...",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}, | ||||
|     // 11
 | ||||
| #endif | ||||
|   { 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,WRITE,MISS)       ,  "LL_WRITE_MISS......",L1D_READ_ACCESS}, | ||||
|   { PERF_TYPE_HW_CACHE, CacheControl(LL,WRITE,ACCESS)     ,  "LL_WRITE_ACCESS....",L1D_READ_ACCESS}, | ||||
|     //15
 | ||||
|   { 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(L1I,READ,MISS)       ,  "L1I_READ_MISS......",INSTRUCTIONS}, | ||||
|   { PERF_TYPE_HW_CACHE, CacheControl(L1I,READ,ACCESS)     ,  "L1I_READ_ACCESS....",INSTRUCTIONS} | ||||
|     //19
 | ||||
|   //  { PERF_TYPE_HARDWARE, PERF_COUNT_HW_STALLED_CYCLES_FRONTEND, "STALL_CYCLES" },
 | ||||
| #endif | ||||
| }; | ||||
| } | ||||
| @@ -43,6 +43,9 @@ Author: paboyle <paboyle@ph.ed.ac.uk> | ||||
| #else | ||||
| #include <sys/syscall.h> | ||||
| #endif | ||||
| #ifdef __x86_64__ | ||||
| #include <x86intrin.h> | ||||
| #endif | ||||
| 
 | ||||
| namespace Grid { | ||||
| 
 | ||||
| @@ -58,6 +61,27 @@ static long perf_event_open(struct perf_event_attr *hw_event, pid_t pid, | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| #ifdef TIMERS_OFF | ||||
| 
 | ||||
| 
 | ||||
| inline uint64_t cyclecount(void){  | ||||
|   return 0; | ||||
| } | ||||
| #define __SSC_MARK(mark) __asm__ __volatile__ ("movl %0, %%ebx; .byte 0x64, 0x67, 0x90 " ::"i"(mark):"%ebx") | ||||
| #define __SSC_STOP  __SSC_MARK(0x110) | ||||
| #define __SSC_START __SSC_MARK(0x111) | ||||
| 
 | ||||
| 
 | ||||
| #else | ||||
| 
 | ||||
| #define __SSC_MARK(mark)  | ||||
| #define __SSC_STOP   | ||||
| #define __SSC_START  | ||||
| 
 | ||||
| /*
 | ||||
|  * cycle counters arch dependent | ||||
|  */ | ||||
| 
 | ||||
| #ifdef __bgq__ | ||||
| inline uint64_t cyclecount(void){  | ||||
|    uint64_t tmp; | ||||
| @@ -65,18 +89,19 @@ inline uint64_t cyclecount(void){ | ||||
|    return tmp; | ||||
| } | ||||
| #elif defined __x86_64__ | ||||
| #include <immintrin.h> | ||||
| #ifndef __INTEL_COMPILER | ||||
| #include <x86intrin.h> | ||||
| #endif | ||||
| inline uint64_t cyclecount(void){  | ||||
|   return __rdtsc(); | ||||
|   //  unsigned int dummy;
 | ||||
|   // return __rdtscp(&dummy);
 | ||||
| } | ||||
| #else | ||||
| #warning No cycle counter implemented for this architecture | ||||
| 
 | ||||
| inline uint64_t cyclecount(void){  | ||||
|    return 0; | ||||
| } | ||||
| 
 | ||||
| #endif | ||||
| 
 | ||||
| #endif | ||||
| 
 | ||||
| class PerformanceCounter { | ||||
| @@ -87,6 +112,7 @@ private: | ||||
|     uint32_t type; | ||||
|     uint64_t config; | ||||
|     const char *name; | ||||
|     int normalisation; | ||||
|   } PerformanceCounterConfig;  | ||||
|    | ||||
|   static const PerformanceCounterConfig PerformanceCounterConfigs []; | ||||
| @@ -94,26 +120,12 @@ private: | ||||
| public: | ||||
| 
 | ||||
|   enum PerformanceCounterType { | ||||
|     CPUCYCLES=0, | ||||
|     INSTRUCTIONS, | ||||
|     //    STALL_CYCLES,
 | ||||
|     CACHE_REFERENCES, | ||||
|     CACHE_MISSES, | ||||
|     L1D_READ_MISS, | ||||
|     L1D_READ_ACCESS, | ||||
|     L1D_WRITE_MISS, | ||||
|     L1D_WRITE_ACCESS, | ||||
|     L1D_PREFETCH_MISS, | ||||
|     L1D_PREFETCH_ACCESS, | ||||
|     LL_READ_MISS, | ||||
|     //    LL_READ_ACCESS,
 | ||||
|     LL_WRITE_MISS, | ||||
|     LL_WRITE_ACCESS, | ||||
|     LL_PREFETCH_MISS, | ||||
|     LL_PREFETCH_ACCESS, | ||||
|     L1I_READ_MISS, | ||||
|     L1I_READ_ACCESS, | ||||
|     PERFORMANCE_COUNTER_NUM_TYPES | ||||
|     CACHE_REFERENCES=0, | ||||
|     CACHE_MISSES=1, | ||||
|     CPUCYCLES=2, | ||||
|     INSTRUCTIONS=3, | ||||
|     L1D_READ_ACCESS=4, | ||||
|     PERFORMANCE_COUNTER_NUM_TYPES=19 | ||||
|   }; | ||||
| 
 | ||||
| public: | ||||
| @@ -121,7 +133,9 @@ public: | ||||
|   int PCT; | ||||
| 
 | ||||
|   long long count; | ||||
|   long long cycles; | ||||
|   int fd; | ||||
|   int cyclefd; | ||||
|   unsigned long long elapsed; | ||||
|   uint64_t begin; | ||||
| 
 | ||||
| @@ -134,7 +148,9 @@ public: | ||||
|     assert(_pct>=0); | ||||
|     assert(_pct<PERFORMANCE_COUNTER_NUM_TYPES); | ||||
|     fd=-1; | ||||
|     cyclefd=-1; | ||||
|     count=0; | ||||
|     cycles=0; | ||||
|     PCT =_pct; | ||||
|     Open(); | ||||
| #endif | ||||
| @@ -156,7 +172,16 @@ public: | ||||
|     const char * name = PerformanceCounterConfigs[PCT].name; | ||||
|     fd = perf_event_open(&pe, 0, -1, -1, 0); // pid 0, cpu -1 current process any cpu. group -1
 | ||||
|     if (fd == -1) { | ||||
|       fprintf(stderr, "Error opening leader %llx for event %s\n", pe.config,name); | ||||
|       fprintf(stderr, "Error opening leader %llx for event %s\n",(long long) pe.config,name); | ||||
|       perror("Error is"); | ||||
|     } | ||||
|     int norm = PerformanceCounterConfigs[PCT].normalisation; | ||||
|     pe.type  = PerformanceCounterConfigs[norm].type; | ||||
|     pe.config= PerformanceCounterConfigs[norm].config; | ||||
|     name = PerformanceCounterConfigs[norm].name; | ||||
|     cyclefd = perf_event_open(&pe, 0, -1, -1, 0); // pid 0, cpu -1 current process any cpu. group -1
 | ||||
|     if (cyclefd == -1) { | ||||
|       fprintf(stderr, "Error opening leader %llx for event %s\n",(long long) pe.config,name); | ||||
|       perror("Error is"); | ||||
|     } | ||||
| #endif | ||||
| @@ -168,6 +193,8 @@ public: | ||||
|     if ( fd!= -1) { | ||||
|       ::ioctl(fd, PERF_EVENT_IOC_RESET, 0); | ||||
|       ::ioctl(fd, PERF_EVENT_IOC_ENABLE, 0); | ||||
|       ::ioctl(cyclefd, PERF_EVENT_IOC_RESET, 0); | ||||
|       ::ioctl(cyclefd, PERF_EVENT_IOC_ENABLE, 0); | ||||
|     } | ||||
|     begin  =cyclecount(); | ||||
| #else | ||||
| @@ -177,10 +204,15 @@ public: | ||||
| 
 | ||||
|   void Stop(void) { | ||||
|     count=0; | ||||
|     cycles=0; | ||||
| #ifdef __linux__ | ||||
|     ssize_t ign; | ||||
|     if ( fd!= -1) { | ||||
|       ::ioctl(fd, PERF_EVENT_IOC_DISABLE, 0); | ||||
|       ::read(fd, &count, sizeof(long long)); | ||||
|       ::ioctl(cyclefd, PERF_EVENT_IOC_DISABLE, 0); | ||||
|       ign=::read(fd, &count, sizeof(long long)); | ||||
|       ign+=::read(cyclefd, &cycles, sizeof(long long)); | ||||
|       assert(ign=2*sizeof(long long)); | ||||
|     } | ||||
|     elapsed = cyclecount() - begin; | ||||
| #else | ||||
| @@ -190,7 +222,11 @@ public: | ||||
|   } | ||||
|   void Report(void) { | ||||
| #ifdef __linux__ | ||||
|     std::printf("%llu cycles %s = %20llu\n", elapsed , PerformanceCounterConfigs[PCT].name, count); | ||||
|     int N = PerformanceCounterConfigs[PCT].normalisation; | ||||
|     const char * sn = PerformanceCounterConfigs[N].name ; | ||||
|     const char * sc = PerformanceCounterConfigs[PCT].name; | ||||
|       std::printf("tsc = %llu %s = %llu  %s = %20llu\n (%s/%s) rate = %lf\n", elapsed,sn ,cycles,  | ||||
| 		  sc, count, sc,sn, (double)count/(double)cycles); | ||||
| #else | ||||
|     std::printf("%llu cycles \n", elapsed ); | ||||
| #endif | ||||
| @@ -199,7 +235,7 @@ public: | ||||
|   ~PerformanceCounter() | ||||
|   { | ||||
| #ifdef __linux__ | ||||
|     ::close(fd); | ||||
|     ::close(fd);    ::close(cyclefd); | ||||
| #endif | ||||
|   } | ||||
| 
 | ||||
							
								
								
									
										245
									
								
								Grid/perfmon/Stat.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										245
									
								
								Grid/perfmon/Stat.cc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,245 @@ | ||||
| #include <Grid/GridCore.h> | ||||
| #include <Grid/perfmon/PerfCount.h> | ||||
| #include <Grid/perfmon/Stat.h> | ||||
|  | ||||
| namespace Grid {  | ||||
|  | ||||
| bool PmuStat::pmu_initialized=false; | ||||
|  | ||||
|  | ||||
| void PmuStat::init(const char *regname) | ||||
| { | ||||
| #ifdef __x86_64__ | ||||
|   name = regname; | ||||
|   if (!pmu_initialized) | ||||
|     { | ||||
|       std::cout<<"initialising pmu"<<std::endl; | ||||
|       pmu_initialized = true; | ||||
|       pmu_init(); | ||||
|     } | ||||
|   clear(); | ||||
| #endif | ||||
| } | ||||
| void PmuStat::clear(void) | ||||
| { | ||||
| #ifdef __x86_64__ | ||||
|   count = 0; | ||||
|   tregion = 0; | ||||
|   pmc0 = 0; | ||||
|   pmc1 = 0; | ||||
|   inst = 0; | ||||
|   cyc = 0; | ||||
|   ref = 0; | ||||
|   tcycles = 0; | ||||
|   reads = 0; | ||||
|   writes = 0; | ||||
| #endif | ||||
| } | ||||
| void PmuStat::print(void) | ||||
| { | ||||
| #ifdef __x86_64__ | ||||
|   std::cout <<"Reg "<<std::string(name)<<":\n"; | ||||
|   std::cout <<"  region "<<tregion<<std::endl; | ||||
|   std::cout <<"  cycles "<<tcycles<<std::endl; | ||||
|   std::cout <<"  inst   "<<inst   <<std::endl; | ||||
|   std::cout <<"  cyc    "<<cyc    <<std::endl; | ||||
|   std::cout <<"  ref    "<<ref    <<std::endl; | ||||
|   std::cout <<"  pmc0   "<<pmc0   <<std::endl; | ||||
|   std::cout <<"  pmc1   "<<pmc1   <<std::endl; | ||||
|   std::cout <<"  count  "<<count  <<std::endl; | ||||
|   std::cout <<"  reads  "<<reads  <<std::endl; | ||||
|   std::cout <<"  writes "<<writes <<std::endl; | ||||
| #endif | ||||
| } | ||||
| void PmuStat::start(void) | ||||
| { | ||||
| #ifdef __x86_64__ | ||||
|   pmu_start(); | ||||
|   ++count; | ||||
|   xmemctrs(&mrstart, &mwstart); | ||||
|   tstart = __rdtsc(); | ||||
| #endif | ||||
| } | ||||
| void PmuStat::enter(int t) | ||||
| { | ||||
| #ifdef __x86_64__ | ||||
|   counters[0][t] = __rdpmc(0); | ||||
|   counters[1][t] = __rdpmc(1); | ||||
|   counters[2][t] = __rdpmc((1<<30)|0); | ||||
|   counters[3][t] = __rdpmc((1<<30)|1); | ||||
|   counters[4][t] = __rdpmc((1<<30)|2); | ||||
|   counters[5][t] = __rdtsc(); | ||||
| #endif | ||||
| } | ||||
| void PmuStat::exit(int t) | ||||
| { | ||||
| #ifdef __x86_64__ | ||||
|   counters[0][t] = __rdpmc(0) - counters[0][t]; | ||||
|   counters[1][t] = __rdpmc(1) - counters[1][t]; | ||||
|   counters[2][t] = __rdpmc((1<<30)|0) - counters[2][t]; | ||||
|   counters[3][t] = __rdpmc((1<<30)|1) - counters[3][t]; | ||||
|   counters[4][t] = __rdpmc((1<<30)|2) - counters[4][t]; | ||||
|   counters[5][t] = __rdtsc() - counters[5][t]; | ||||
| #endif | ||||
| } | ||||
| void PmuStat::accum(int nthreads) | ||||
| { | ||||
| #ifdef __x86_64__ | ||||
|   tend = __rdtsc(); | ||||
|   xmemctrs(&mrend, &mwend); | ||||
|   pmu_stop(); | ||||
|   for (int t = 0; t < nthreads; ++t) { | ||||
|     pmc0 += counters[0][t]; | ||||
|     pmc1 += counters[1][t]; | ||||
|     inst += counters[2][t]; | ||||
|     cyc += counters[3][t]; | ||||
|     ref += counters[4][t]; | ||||
|     tcycles += counters[5][t]; | ||||
|   } | ||||
|   uint64_t region = tend - tstart; | ||||
|   tregion += region; | ||||
|   uint64_t mreads = mrend - mrstart; | ||||
|   reads += mreads; | ||||
|   uint64_t mwrites = mwend - mwstart; | ||||
|   writes += mwrites; | ||||
| #endif | ||||
| } | ||||
|  | ||||
|  | ||||
| void PmuStat::pmu_fini(void) {} | ||||
| void PmuStat::pmu_start(void) {}; | ||||
| void PmuStat::pmu_stop(void) {}; | ||||
| void PmuStat::pmu_init(void) | ||||
| { | ||||
| #ifdef _KNIGHTS_LANDING_ | ||||
|   KNLsetup(); | ||||
| #endif | ||||
| } | ||||
| void PmuStat::xmemctrs(uint64_t *mr, uint64_t *mw) | ||||
| { | ||||
| #ifdef _KNIGHTS_LANDING_ | ||||
|   ctrs c; | ||||
|   KNLreadctrs(c); | ||||
|   uint64_t emr = 0, emw = 0; | ||||
|   for (int i = 0; i < NEDC; ++i) | ||||
|     { | ||||
|       emr += c.edcrd[i]; | ||||
|       emw += c.edcwr[i]; | ||||
|     } | ||||
|   *mr = emr; | ||||
|   *mw = emw; | ||||
| #else | ||||
|   *mr = *mw = 0; | ||||
| #endif | ||||
| } | ||||
|  | ||||
| #ifdef _KNIGHTS_LANDING_ | ||||
|  | ||||
| struct knl_gbl_ PmuStat::gbl; | ||||
|  | ||||
| #define PMU_MEM | ||||
|  | ||||
| void PmuStat::KNLevsetup(const char *ename, int &fd, int event, int umask) | ||||
| { | ||||
|   char fname[1024]; | ||||
|   snprintf(fname, sizeof(fname), "%s/type", ename); | ||||
|   FILE *fp = fopen(fname, "r"); | ||||
|   if (fp == 0) { | ||||
|     ::printf("open %s", fname); | ||||
|     ::exit(0); | ||||
|   } | ||||
|   int type; | ||||
|   int ret = fscanf(fp, "%d", &type); | ||||
|   assert(ret == 1); | ||||
|   fclose(fp); | ||||
|   //  std::cout << "Using PMU type "<<type<<" from " << std::string(ename) <<std::endl; | ||||
|  | ||||
|   struct perf_event_attr hw = {}; | ||||
|   hw.size = sizeof(hw); | ||||
|   hw.type = type; | ||||
|   // see /sys/devices/uncore_*/format/* | ||||
|   // All of the events we are interested in are configured the same way, but | ||||
|   // that isn't always true. Proper code would parse the format files | ||||
|   hw.config = event | (umask << 8); | ||||
|   //hw.read_format = PERF_FORMAT_GROUP; | ||||
|   // unfortunately the above only works within a single PMU; might | ||||
|   // as well just read them one at a time | ||||
|   int cpu = 0; | ||||
|   fd = perf_event_open(&hw, -1, cpu, -1, 0); | ||||
|   if (fd == -1) { | ||||
|     ::printf("CPU %d, box %s, event 0x%lx", cpu, ename, hw.config); | ||||
|     ::exit(0); | ||||
|   } else {  | ||||
|     //    std::cout << "event "<<std::string(ename)<<" set up for fd "<<fd<<" hw.config "<<hw.config <<std::endl; | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
|  void PmuStat::KNLsetup(void){ | ||||
|  | ||||
|    int ret; | ||||
|    char fname[1024]; | ||||
|  | ||||
|    // MC RPQ inserts and WPQ inserts (reads & writes) | ||||
|    for (int mc = 0; mc < NMC; ++mc) | ||||
|      { | ||||
|        ::snprintf(fname, sizeof(fname), "/sys/devices/uncore_imc_%d",mc); | ||||
|        // RPQ Inserts | ||||
|        KNLevsetup(fname, gbl.mc_rd[mc], 0x1, 0x1); | ||||
|        // WPQ Inserts | ||||
|        KNLevsetup(fname, gbl.mc_wr[mc], 0x2, 0x1); | ||||
|      } | ||||
|    // EDC RPQ inserts and WPQ inserts | ||||
|    for (int edc=0; edc < NEDC; ++edc) | ||||
|      { | ||||
|        ::snprintf(fname, sizeof(fname), "/sys/devices/uncore_edc_eclk_%d",edc); | ||||
|        // RPQ inserts | ||||
|        KNLevsetup(fname, gbl.edc_rd[edc], 0x1, 0x1); | ||||
|        // WPQ inserts | ||||
|        KNLevsetup(fname, gbl.edc_wr[edc], 0x2, 0x1); | ||||
|      } | ||||
|    // EDC HitE, HitM, MissE, MissM | ||||
|    for (int edc=0; edc < NEDC; ++edc) | ||||
|      { | ||||
|        ::snprintf(fname, sizeof(fname), "/sys/devices/uncore_edc_uclk_%d", edc); | ||||
|        KNLevsetup(fname, gbl.edc_hite[edc], 0x2, 0x1); | ||||
|        KNLevsetup(fname, gbl.edc_hitm[edc], 0x2, 0x2); | ||||
|        KNLevsetup(fname, gbl.edc_misse[edc], 0x2, 0x4); | ||||
|        KNLevsetup(fname, gbl.edc_missm[edc], 0x2, 0x8); | ||||
|      } | ||||
|  } | ||||
|  | ||||
| uint64_t PmuStat::KNLreadctr(int fd) | ||||
| { | ||||
|   uint64_t data; | ||||
|   size_t s = ::read(fd, &data, sizeof(data)); | ||||
|   if (s != sizeof(uint64_t)){ | ||||
|     ::printf("read counter %lu", s); | ||||
|     ::exit(0); | ||||
|   } | ||||
|   return data; | ||||
| } | ||||
|  | ||||
| void PmuStat::KNLreadctrs(ctrs &c) | ||||
| { | ||||
|   for (int i = 0; i < NMC; ++i) | ||||
|     { | ||||
|       c.mcrd[i] = KNLreadctr(gbl.mc_rd[i]); | ||||
|       c.mcwr[i] = KNLreadctr(gbl.mc_wr[i]); | ||||
|     } | ||||
|   for (int i = 0; i < NEDC; ++i) | ||||
|     { | ||||
|       c.edcrd[i] = KNLreadctr(gbl.edc_rd[i]); | ||||
|       c.edcwr[i] = KNLreadctr(gbl.edc_wr[i]); | ||||
|     } | ||||
|   for (int i = 0; i < NEDC; ++i) | ||||
|     { | ||||
|       c.edchite[i] = KNLreadctr(gbl.edc_hite[i]); | ||||
|       c.edchitm[i] = KNLreadctr(gbl.edc_hitm[i]); | ||||
|       c.edcmisse[i] = KNLreadctr(gbl.edc_misse[i]); | ||||
|       c.edcmissm[i] = KNLreadctr(gbl.edc_missm[i]); | ||||
|     } | ||||
| } | ||||
|  | ||||
| #endif | ||||
| } | ||||
							
								
								
									
										104
									
								
								Grid/perfmon/Stat.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										104
									
								
								Grid/perfmon/Stat.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,104 @@ | ||||
| #ifndef _GRID_STAT_H | ||||
| #define _GRID_STAT_H | ||||
|  | ||||
| #ifdef AVX512 | ||||
| #define _KNIGHTS_LANDING_ROOTONLY | ||||
| #endif | ||||
|  | ||||
| namespace Grid {  | ||||
|  | ||||
| /////////////////////////////////////////////////////////////////////////////// | ||||
| // Extra KNL counters from MCDRAM | ||||
| /////////////////////////////////////////////////////////////////////////////// | ||||
| #ifdef _KNIGHTS_LANDING_ | ||||
| #define NMC 6 | ||||
| #define NEDC 8 | ||||
| struct ctrs | ||||
| { | ||||
|     uint64_t mcrd[NMC]; | ||||
|     uint64_t mcwr[NMC]; | ||||
|     uint64_t edcrd[NEDC];  | ||||
|     uint64_t edcwr[NEDC]; | ||||
|     uint64_t edchite[NEDC]; | ||||
|     uint64_t edchitm[NEDC]; | ||||
|     uint64_t edcmisse[NEDC]; | ||||
|     uint64_t edcmissm[NEDC]; | ||||
| }; | ||||
| // Peter/Azusa: | ||||
| // Our modification of a code provided by Larry Meadows from Intel | ||||
| // Verified by email exchange non-NDA, ok for github. Should be as uses /sys/devices/ FS | ||||
| // so is already public and in the linux kernel for KNL. | ||||
| struct knl_gbl_ | ||||
| { | ||||
|   int mc_rd[NMC]; | ||||
|   int mc_wr[NMC]; | ||||
|   int edc_rd[NEDC]; | ||||
|   int edc_wr[NEDC]; | ||||
|   int edc_hite[NEDC]; | ||||
|   int edc_hitm[NEDC]; | ||||
|   int edc_misse[NEDC]; | ||||
|   int edc_missm[NEDC]; | ||||
| }; | ||||
| #endif | ||||
| /////////////////////////////////////////////////////////////////////////////// | ||||
|  | ||||
| class PmuStat | ||||
| { | ||||
|     uint64_t counters[8][256]; | ||||
| #ifdef _KNIGHTS_LANDING_ | ||||
|     static struct knl_gbl_ gbl; | ||||
| #endif | ||||
|     const char *name; | ||||
|  | ||||
|     uint64_t reads;     // memory reads | ||||
|     uint64_t writes;    // memory writes | ||||
|     uint64_t mrstart;   // memory read counter at start of parallel region | ||||
|     uint64_t mrend;     // memory read counter at end of parallel region | ||||
|     uint64_t mwstart;   // memory write counter at start of parallel region | ||||
|     uint64_t mwend;     // memory write counter at end of parallel region | ||||
|  | ||||
|     // cumulative counters | ||||
|     uint64_t count;     // number of invocations | ||||
|     uint64_t tregion;   // total time in parallel region (from thread 0) | ||||
|     uint64_t tcycles;   // total cycles inside parallel region | ||||
|     uint64_t inst, ref, cyc;   // fixed counters | ||||
|     uint64_t pmc0, pmc1;// pmu | ||||
|     // add memory counters here | ||||
|     // temp variables | ||||
|     uint64_t tstart;    // tsc at start of parallel region | ||||
|     uint64_t tend;      // tsc at end of parallel region | ||||
|     // map for ctrs values | ||||
|     // 0 pmc0 start | ||||
|     // 1 pmc0 end | ||||
|     // 2 pmc1 start | ||||
|     // 3 pmc1 end | ||||
|     // 4 tsc start | ||||
|     // 5 tsc end | ||||
|     static bool pmu_initialized; | ||||
| public: | ||||
|     static bool is_init(void){ return pmu_initialized;} | ||||
|     static void pmu_init(void); | ||||
|     static void pmu_fini(void); | ||||
|     static void pmu_start(void); | ||||
|     static void pmu_stop(void); | ||||
|     void accum(int nthreads); | ||||
|     static void xmemctrs(uint64_t *mr, uint64_t *mw); | ||||
|     void start(void); | ||||
|     void enter(int t); | ||||
|     void exit(int t); | ||||
|     void print(void); | ||||
|     void init(const char *regname); | ||||
|     void clear(void); | ||||
| #ifdef _KNIGHTS_LANDING_ | ||||
|     static void     KNLsetup(void); | ||||
|     static uint64_t KNLreadctr(int fd); | ||||
|     static void     KNLreadctrs(ctrs &c); | ||||
|     static void     KNLevsetup(const char *ename, int &fd, int event, int umask); | ||||
| #endif | ||||
|      | ||||
|   }; | ||||
|  | ||||
| } | ||||
| #endif | ||||
|  | ||||
|  | ||||
| @@ -39,11 +39,18 @@ namespace Grid { | ||||
|   // Dress the output; use std::chrono
 | ||||
| 
 | ||||
| // C++11 time facilities better?
 | ||||
| double usecond(void); | ||||
| inline double usecond(void) { | ||||
|   struct timeval tv; | ||||
| #ifdef TIMERS_ON | ||||
|   gettimeofday(&tv,NULL); | ||||
| #endif | ||||
|   return 1.0*tv.tv_usec + 1.0e6*tv.tv_sec; | ||||
| } | ||||
| 
 | ||||
| typedef  std::chrono::system_clock          GridClock; | ||||
| typedef  std::chrono::time_point<GridClock> GridTimePoint; | ||||
| typedef  std::chrono::milliseconds          GridTime; | ||||
| typedef  std::chrono::milliseconds          GridMillisecs; | ||||
| typedef  std::chrono::microseconds          GridTime; | ||||
| typedef  std::chrono::microseconds          GridUsecs; | ||||
| 
 | ||||
| inline std::ostream& operator<< (std::ostream & stream, const std::chrono::milliseconds & time) | ||||
| @@ -51,6 +58,11 @@ inline std::ostream& operator<< (std::ostream & stream, const std::chrono::milli | ||||
|   stream << time.count()<<" ms"; | ||||
|   return stream; | ||||
| } | ||||
| inline std::ostream& operator<< (std::ostream & stream, const std::chrono::microseconds & time) | ||||
| { | ||||
|   stream << time.count()<<" usec"; | ||||
|   return stream; | ||||
| } | ||||
|   | ||||
| class GridStopWatch { | ||||
| private: | ||||
| @@ -63,17 +75,23 @@ public: | ||||
|   } | ||||
|   void     Start(void) {  | ||||
|     assert(running == false); | ||||
| #ifdef TIMERS_ON | ||||
|     start = GridClock::now();  | ||||
| #endif | ||||
|     running = true; | ||||
|   } | ||||
|   void     Stop(void)  {  | ||||
|     assert(running == true); | ||||
| #ifdef TIMERS_ON | ||||
|     accumulator+= std::chrono::duration_cast<GridUsecs>(GridClock::now()-start);  | ||||
| #endif | ||||
|     running = false;  | ||||
|   }; | ||||
|   void     Reset(void){ | ||||
|     running = false; | ||||
| #ifdef TIMERS_ON | ||||
|     start = GridClock::now(); | ||||
| #endif | ||||
|     accumulator = std::chrono::duration_cast<GridUsecs>(start-start);  | ||||
|   } | ||||
|   GridTime Elapsed(void) { | ||||
| @@ -84,6 +102,9 @@ public: | ||||
|     assert(running == false); | ||||
|     return (uint64_t) accumulator.count(); | ||||
|   } | ||||
|   bool isRunning(void){ | ||||
|     return running; | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| } | ||||
| @@ -1,7 +1,7 @@ | ||||
| /**
 | ||||
|  * pugixml parser - version 1.6 | ||||
|  * pugixml parser - version 1.9 | ||||
|  * -------------------------------------------------------- | ||||
|  * Copyright (C) 2006-2015, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com) | ||||
|  * Copyright (C) 2006-2018, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com) | ||||
|  * Report bugs and download new versions at http://pugixml.org/
 | ||||
|  * | ||||
|  * This library is distributed under the MIT License. See notice at the end | ||||
| @@ -17,6 +17,9 @@ | ||||
| // Uncomment this to enable wchar_t mode
 | ||||
| // #define PUGIXML_WCHAR_MODE
 | ||||
| 
 | ||||
| // Uncomment this to enable compact mode
 | ||||
| // #define PUGIXML_COMPACT
 | ||||
| 
 | ||||
| // Uncomment this to disable XPath
 | ||||
| // #define PUGIXML_NO_XPATH
 | ||||
| 
 | ||||
| @@ -46,7 +49,7 @@ | ||||
| #endif | ||||
| 
 | ||||
| /**
 | ||||
|  * Copyright (c) 2006-2015 Arseny Kapoulkine | ||||
|  * Copyright (c) 2006-2018 Arseny Kapoulkine | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person | ||||
|  * obtaining a copy of this software and associated documentation | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -1,7 +1,7 @@ | ||||
| /**
 | ||||
|  * pugixml parser - version 1.6 | ||||
|  * pugixml parser - version 1.9 | ||||
|  * -------------------------------------------------------- | ||||
|  * Copyright (C) 2006-2015, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com) | ||||
|  * Copyright (C) 2006-2018, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com) | ||||
|  * Report bugs and download new versions at http://pugixml.org/
 | ||||
|  * | ||||
|  * This library is distributed under the MIT License. See notice at the end | ||||
| @@ -13,11 +13,11 @@ | ||||
| 
 | ||||
| #ifndef PUGIXML_VERSION | ||||
| // Define version macro; evaluates to major * 100 + minor so that it's safe to use in less-than comparisons
 | ||||
| #	define PUGIXML_VERSION 160 | ||||
| #	define PUGIXML_VERSION 190 | ||||
| #endif | ||||
| 
 | ||||
| // Include user configuration file (this can define various configuration macros)
 | ||||
| #include <pugixml/pugiconfig.hpp> | ||||
| #include "pugiconfig.hpp" | ||||
| 
 | ||||
| #ifndef HEADER_PUGIXML_HPP | ||||
| #define HEADER_PUGIXML_HPP | ||||
| @@ -72,6 +72,44 @@ | ||||
| #	endif | ||||
| #endif | ||||
| 
 | ||||
| // If the platform is known to have move semantics support, compile move ctor/operator implementation
 | ||||
| #ifndef PUGIXML_HAS_MOVE | ||||
| #	if __cplusplus >= 201103 | ||||
| #		define PUGIXML_HAS_MOVE | ||||
| #	elif defined(_MSC_VER) && _MSC_VER >= 1600 | ||||
| #		define PUGIXML_HAS_MOVE | ||||
| #	endif | ||||
| #endif | ||||
| 
 | ||||
| // If C++ is 2011 or higher, add 'noexcept' specifiers
 | ||||
| #ifndef PUGIXML_NOEXCEPT | ||||
| #	if __cplusplus >= 201103 | ||||
| #		define PUGIXML_NOEXCEPT noexcept | ||||
| #	elif defined(_MSC_VER) && _MSC_VER >= 1900 | ||||
| #		define PUGIXML_NOEXCEPT noexcept | ||||
| #	else | ||||
| #		define PUGIXML_NOEXCEPT | ||||
| #	endif | ||||
| #endif | ||||
| 
 | ||||
| // Some functions can not be noexcept in compact mode
 | ||||
| #ifdef PUGIXML_COMPACT | ||||
| #	define PUGIXML_NOEXCEPT_IF_NOT_COMPACT | ||||
| #else | ||||
| #	define PUGIXML_NOEXCEPT_IF_NOT_COMPACT PUGIXML_NOEXCEPT | ||||
| #endif | ||||
| 
 | ||||
| // If C++ is 2011 or higher, add 'override' qualifiers
 | ||||
| #ifndef PUGIXML_OVERRIDE | ||||
| #	if __cplusplus >= 201103 | ||||
| #		define PUGIXML_OVERRIDE override | ||||
| #	elif defined(_MSC_VER) && _MSC_VER >= 1700 | ||||
| #		define PUGIXML_OVERRIDE override | ||||
| #	else | ||||
| #		define PUGIXML_OVERRIDE | ||||
| #	endif | ||||
| #endif | ||||
| 
 | ||||
| // Character interface macros
 | ||||
| #ifdef PUGIXML_WCHAR_MODE | ||||
| #	define PUGIXML_TEXT(t) L ## t | ||||
| @@ -158,6 +196,11 @@ namespace pugi | ||||
| 	// is a valid document. This flag is off by default.
 | ||||
| 	const unsigned int parse_fragment = 0x1000; | ||||
| 
 | ||||
| 	// This flag determines if plain character data is be stored in the parent element's value. This significantly changes the structure of
 | ||||
| 	// the document; this flag is only recommended for parsing documents with many PCDATA nodes in memory-constrained environments.
 | ||||
| 	// This flag is off by default.
 | ||||
| 	const unsigned int parse_embed_pcdata = 0x2000; | ||||
| 
 | ||||
| 	// The default parsing mode.
 | ||||
| 	// Elements, PCDATA and CDATA sections are added to the DOM tree, character/reference entities are expanded,
 | ||||
| 	// End-of-Line characters are normalized, attribute values are normalized using CDATA normalization rules.
 | ||||
| @@ -206,6 +249,9 @@ namespace pugi | ||||
| 	// Write every attribute on a new line with appropriate indentation. This flag is off by default.
 | ||||
| 	const unsigned int format_indent_attributes = 0x40; | ||||
| 
 | ||||
| 	// Don't output empty element tags, instead writing an explicit start and end tag even if there are no children. This flag is off by default.
 | ||||
| 	const unsigned int format_no_empty_element_tags = 0x80; | ||||
| 
 | ||||
| 	// The default set of formatting flags.
 | ||||
| 	// Nodes are indented depending on their depth in DOM tree, a default declaration is output if document has none.
 | ||||
| 	const unsigned int format_default = format_indent; | ||||
| @@ -268,7 +314,7 @@ namespace pugi | ||||
| 		// Construct writer from a FILE* object; void* is used to avoid header dependencies on stdio
 | ||||
| 		xml_writer_file(void* file); | ||||
| 
 | ||||
| 		virtual void write(const void* data, size_t size); | ||||
| 		virtual void write(const void* data, size_t size) PUGIXML_OVERRIDE; | ||||
| 
 | ||||
| 	private: | ||||
| 		void* file; | ||||
| @@ -283,7 +329,7 @@ namespace pugi | ||||
| 		xml_writer_stream(std::basic_ostream<char, std::char_traits<char> >& stream); | ||||
| 		xml_writer_stream(std::basic_ostream<wchar_t, std::char_traits<wchar_t> >& stream); | ||||
| 
 | ||||
| 		virtual void write(const void* data, size_t size); | ||||
| 		virtual void write(const void* data, size_t size) PUGIXML_OVERRIDE; | ||||
| 
 | ||||
| 	private: | ||||
| 		std::basic_ostream<char, std::char_traits<char> >* narrow_stream; | ||||
| @@ -354,6 +400,8 @@ namespace pugi | ||||
| 		// Set attribute value with type conversion (numbers are converted to strings, boolean is converted to "true"/"false")
 | ||||
| 		bool set_value(int rhs); | ||||
| 		bool set_value(unsigned int rhs); | ||||
| 		bool set_value(long rhs); | ||||
| 		bool set_value(unsigned long rhs); | ||||
| 		bool set_value(double rhs); | ||||
| 		bool set_value(float rhs); | ||||
| 		bool set_value(bool rhs); | ||||
| @@ -367,6 +415,8 @@ namespace pugi | ||||
| 		xml_attribute& operator=(const char_t* rhs); | ||||
| 		xml_attribute& operator=(int rhs); | ||||
| 		xml_attribute& operator=(unsigned int rhs); | ||||
| 		xml_attribute& operator=(long rhs); | ||||
| 		xml_attribute& operator=(unsigned long rhs); | ||||
| 		xml_attribute& operator=(double rhs); | ||||
| 		xml_attribute& operator=(float rhs); | ||||
| 		xml_attribute& operator=(bool rhs); | ||||
| @@ -601,8 +651,8 @@ namespace pugi | ||||
| 		xpath_node_set select_nodes(const xpath_query& query) const; | ||||
| 
 | ||||
| 		// (deprecated: use select_node instead) Select single node by evaluating XPath query.
 | ||||
| 		xpath_node select_single_node(const char_t* query, xpath_variable_set* variables = 0) const; | ||||
| 		xpath_node select_single_node(const xpath_query& query) const; | ||||
| 		PUGIXML_DEPRECATED xpath_node select_single_node(const char_t* query, xpath_variable_set* variables = 0) const; | ||||
| 		PUGIXML_DEPRECATED xpath_node select_single_node(const xpath_query& query) const; | ||||
| 
 | ||||
| 	#endif | ||||
| 
 | ||||
| @@ -701,6 +751,8 @@ namespace pugi | ||||
| 		// Set text with type conversion (numbers are converted to strings, boolean is converted to "true"/"false")
 | ||||
| 		bool set(int rhs); | ||||
| 		bool set(unsigned int rhs); | ||||
| 		bool set(long rhs); | ||||
| 		bool set(unsigned long rhs); | ||||
| 		bool set(double rhs); | ||||
| 		bool set(float rhs); | ||||
| 		bool set(bool rhs); | ||||
| @@ -714,6 +766,8 @@ namespace pugi | ||||
| 		xml_text& operator=(const char_t* rhs); | ||||
| 		xml_text& operator=(int rhs); | ||||
| 		xml_text& operator=(unsigned int rhs); | ||||
| 		xml_text& operator=(long rhs); | ||||
| 		xml_text& operator=(unsigned long rhs); | ||||
| 		xml_text& operator=(double rhs); | ||||
| 		xml_text& operator=(float rhs); | ||||
| 		xml_text& operator=(bool rhs); | ||||
| @@ -945,10 +999,11 @@ namespace pugi | ||||
| 
 | ||||
| 		// Non-copyable semantics
 | ||||
| 		xml_document(const xml_document&); | ||||
| 		const xml_document& operator=(const xml_document&); | ||||
| 		xml_document& operator=(const xml_document&); | ||||
| 
 | ||||
| 		void create(); | ||||
| 		void destroy(); | ||||
| 		void _create(); | ||||
| 		void _destroy(); | ||||
| 		void _move(xml_document& rhs) PUGIXML_NOEXCEPT_IF_NOT_COMPACT; | ||||
| 
 | ||||
| 	public: | ||||
| 		// Default constructor, makes empty document
 | ||||
| @@ -957,6 +1012,12 @@ namespace pugi | ||||
| 		// Destructor, invalidates all node/attribute handles to this document
 | ||||
| 		~xml_document(); | ||||
| 
 | ||||
| 	#ifdef PUGIXML_HAS_MOVE | ||||
| 		// Move semantics support
 | ||||
| 		xml_document(xml_document&& rhs) PUGIXML_NOEXCEPT_IF_NOT_COMPACT; | ||||
| 		xml_document& operator=(xml_document&& rhs) PUGIXML_NOEXCEPT_IF_NOT_COMPACT; | ||||
| 	#endif | ||||
| 
 | ||||
| 		// Removes all nodes, leaving the empty document
 | ||||
| 		void reset(); | ||||
| 
 | ||||
| @@ -970,7 +1031,7 @@ namespace pugi | ||||
| 	#endif | ||||
| 
 | ||||
| 		// (deprecated: use load_string instead) Load document from zero-terminated string. No encoding conversions are applied.
 | ||||
| 		xml_parse_result load(const char_t* contents, unsigned int options = parse_default); | ||||
| 		PUGIXML_DEPRECATED xml_parse_result load(const char_t* contents, unsigned int options = parse_default); | ||||
| 
 | ||||
| 		// Load document from zero-terminated string. No encoding conversions are applied.
 | ||||
| 		xml_parse_result load_string(const char_t* contents, unsigned int options = parse_default); | ||||
| @@ -1095,10 +1156,10 @@ namespace pugi | ||||
| 		xpath_variable_set(const xpath_variable_set& rhs); | ||||
| 		xpath_variable_set& operator=(const xpath_variable_set& rhs); | ||||
| 
 | ||||
| 	#if __cplusplus >= 201103 | ||||
| 	#ifdef PUGIXML_HAS_MOVE | ||||
| 		// Move semantics support
 | ||||
| 		xpath_variable_set(xpath_variable_set&& rhs); | ||||
| 		xpath_variable_set& operator=(xpath_variable_set&& rhs); | ||||
| 		xpath_variable_set(xpath_variable_set&& rhs) PUGIXML_NOEXCEPT; | ||||
| 		xpath_variable_set& operator=(xpath_variable_set&& rhs) PUGIXML_NOEXCEPT; | ||||
| 	#endif | ||||
| 
 | ||||
| 		// Add a new variable or get the existing one, if the types match
 | ||||
| @@ -1139,10 +1200,10 @@ namespace pugi | ||||
| 		// Destructor
 | ||||
| 		~xpath_query(); | ||||
| 
 | ||||
| 	#if __cplusplus >= 201103 | ||||
| 	#ifdef PUGIXML_HAS_MOVE | ||||
| 		// Move semantics support
 | ||||
| 		xpath_query(xpath_query&& rhs); | ||||
| 		xpath_query& operator=(xpath_query&& rhs); | ||||
| 		xpath_query(xpath_query&& rhs) PUGIXML_NOEXCEPT; | ||||
| 		xpath_query& operator=(xpath_query&& rhs) PUGIXML_NOEXCEPT; | ||||
| 	#endif | ||||
| 
 | ||||
| 		// Get query expression return type
 | ||||
| @@ -1201,7 +1262,7 @@ namespace pugi | ||||
| 		explicit xpath_exception(const xpath_parse_result& result); | ||||
| 
 | ||||
| 		// Get error message
 | ||||
| 		virtual const char* what() const throw(); | ||||
| 		virtual const char* what() const throw() PUGIXML_OVERRIDE; | ||||
| 
 | ||||
| 		// Get parse result
 | ||||
| 		const xpath_parse_result& result() const; | ||||
| @@ -1280,10 +1341,10 @@ namespace pugi | ||||
| 		xpath_node_set(const xpath_node_set& ns); | ||||
| 		xpath_node_set& operator=(const xpath_node_set& ns); | ||||
| 
 | ||||
| 	#if __cplusplus >= 201103 | ||||
| 	#ifdef PUGIXML_HAS_MOVE | ||||
| 		// Move semantics support
 | ||||
| 		xpath_node_set(xpath_node_set&& rhs); | ||||
| 		xpath_node_set& operator=(xpath_node_set&& rhs); | ||||
| 		xpath_node_set(xpath_node_set&& rhs) PUGIXML_NOEXCEPT; | ||||
| 		xpath_node_set& operator=(xpath_node_set&& rhs) PUGIXML_NOEXCEPT; | ||||
| 	#endif | ||||
| 
 | ||||
| 		// Get collection type
 | ||||
| @@ -1317,7 +1378,7 @@ namespace pugi | ||||
| 		xpath_node* _end; | ||||
| 
 | ||||
| 		void _assign(const_iterator begin, const_iterator end, type_t type); | ||||
| 		void _move(xpath_node_set& rhs); | ||||
| 		void _move(xpath_node_set& rhs) PUGIXML_NOEXCEPT; | ||||
| 	}; | ||||
| #endif | ||||
| 
 | ||||
| @@ -1375,7 +1436,7 @@ namespace std | ||||
| #endif | ||||
| 
 | ||||
| /**
 | ||||
|  * Copyright (c) 2006-2015 Arseny Kapoulkine | ||||
|  * Copyright (c) 2006-2018 Arseny Kapoulkine | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person | ||||
|  * obtaining a copy of this software and associated documentation | ||||
| @@ -1,6 +1,6 @@ | ||||
| pugixml 1.6 - an XML processing library | ||||
| pugixml 1.9 - an XML processing library | ||||
| 
 | ||||
| Copyright (C) 2006-2015, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com) | ||||
| Copyright (C) 2006-2018, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com) | ||||
| Report bugs and download new versions at http://pugixml.org/ | ||||
| 
 | ||||
| This is the distribution of pugixml, which is a C++ XML processing library, | ||||
| @@ -28,7 +28,7 @@ The distribution contains the following folders: | ||||
| 
 | ||||
| This library is distributed under the MIT License: | ||||
| 
 | ||||
| Copyright (c) 2006-2015 Arseny Kapoulkine | ||||
| Copyright (c) 2006-2018 Arseny Kapoulkine | ||||
| 
 | ||||
| Permission is hereby granted, free of charge, to any person | ||||
| obtaining a copy of this software and associated documentation | ||||
							
								
								
									
										124
									
								
								Grid/qcd/LatticeTheories.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										124
									
								
								Grid/qcd/LatticeTheories.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,124 @@ | ||||
| /************************************************************************************* | ||||
|  | ||||
| Grid physics library, www.github.com/paboyle/Grid | ||||
|  | ||||
| Source file: ./lib/qcd/QCD.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: 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_LT_H | ||||
| #define GRID_LT_H | ||||
| namespace Grid{ | ||||
|  | ||||
| // First steps in the complete generalization of the Physics part | ||||
| // Design not final | ||||
| namespace LatticeTheories { | ||||
|  | ||||
| template <int Dimensions> | ||||
| struct LatticeTheory { | ||||
|   static const int Nd = Dimensions; | ||||
|   static const int Nds = Dimensions * 2;  // double stored field | ||||
|   template <typename vtype> | ||||
|   using iSinglet = iScalar<iScalar<iScalar<vtype> > >; | ||||
| }; | ||||
|  | ||||
| template <int Dimensions, int Colours> | ||||
| struct LatticeGaugeTheory : public LatticeTheory<Dimensions> { | ||||
|   static const int Nds = Dimensions * 2; | ||||
|   static const int Nd = Dimensions; | ||||
|   static const int Nc = Colours; | ||||
|  | ||||
|   template <typename vtype>  | ||||
|   using iColourMatrix = iScalar<iScalar<iMatrix<vtype, Nc> > >; | ||||
|   template <typename vtype> | ||||
|   using iLorentzColourMatrix = iVector<iScalar<iMatrix<vtype, Nc> >, Nd>; | ||||
|   template <typename vtype> | ||||
|   using iDoubleStoredColourMatrix = iVector<iScalar<iMatrix<vtype, Nc> >, Nds>; | ||||
|   template <typename vtype> | ||||
|   using iColourVector = iScalar<iScalar<iVector<vtype, Nc> > >; | ||||
| }; | ||||
|  | ||||
| template <int Dimensions, int Colours, int Spin> | ||||
| struct FermionicLatticeGaugeTheory | ||||
|     : public LatticeGaugeTheory<Dimensions, Colours> { | ||||
|   static const int Nd = Dimensions; | ||||
|   static const int Nds = Dimensions * 2; | ||||
|   static const int Nc = Colours; | ||||
|   static const int Ns = Spin; | ||||
|  | ||||
|   template <typename vtype> | ||||
|   using iSpinMatrix = iScalar<iMatrix<iScalar<vtype>, Ns> >; | ||||
|   template <typename vtype> | ||||
|   using iSpinColourMatrix = iScalar<iMatrix<iMatrix<vtype, Nc>, Ns> >; | ||||
|   template <typename vtype> | ||||
|   using iSpinVector = iScalar<iVector<iScalar<vtype>, Ns> >; | ||||
|   template <typename vtype> | ||||
|   using iSpinColourVector = iScalar<iVector<iVector<vtype, Nc>, Ns> >; | ||||
|   // These 2 only if Spin is a multiple of 2 | ||||
|   static const int Nhs = Spin / 2; | ||||
|   template <typename vtype> | ||||
|   using iHalfSpinVector = iScalar<iVector<iScalar<vtype>, Nhs> >; | ||||
|   template <typename vtype> | ||||
|   using iHalfSpinColourVector = iScalar<iVector<iVector<vtype, Nc>, Nhs> >; | ||||
|  | ||||
|   //tests | ||||
|   typedef iColourMatrix<Complex> ColourMatrix; | ||||
|   typedef iColourMatrix<ComplexF> ColourMatrixF; | ||||
|   typedef iColourMatrix<ComplexD> ColourMatrixD; | ||||
|  | ||||
|  | ||||
| }; | ||||
|  | ||||
| // Examples, not complete now. | ||||
| struct QCD : public FermionicLatticeGaugeTheory<4, 3, 4> { | ||||
|     static const int Xp = 0; | ||||
|     static const int Yp = 1; | ||||
|     static const int Zp = 2; | ||||
|     static const int Tp = 3; | ||||
|     static const int Xm = 4; | ||||
|     static const int Ym = 5; | ||||
|     static const int Zm = 6; | ||||
|     static const int Tm = 7; | ||||
|  | ||||
|     typedef FermionicLatticeGaugeTheory FLGT; | ||||
|  | ||||
|     typedef FLGT::iSpinMatrix<Complex  >          SpinMatrix; | ||||
|     typedef FLGT::iSpinMatrix<ComplexF >          SpinMatrixF; | ||||
|     typedef FLGT::iSpinMatrix<ComplexD >          SpinMatrixD; | ||||
|  | ||||
| }; | ||||
| struct QED : public FermionicLatticeGaugeTheory<4, 1, 4> {//fill | ||||
| }; | ||||
|  | ||||
| template <int Dimensions> | ||||
| struct Scalar : public LatticeTheory<Dimensions> {}; | ||||
|  | ||||
| };  // LatticeTheories | ||||
|  | ||||
| } // Grid | ||||
|  | ||||
| #endif | ||||
| @@ -29,12 +29,16 @@ Author: paboyle <paboyle@ph.ed.ac.uk> | ||||
|     See the full license in the file "LICENSE" in the top level distribution directory | ||||
|     *************************************************************************************/ | ||||
|     /*  END LEGAL */ | ||||
| #ifndef GRID_QCD_H | ||||
| #define GRID_QCD_H | ||||
| #ifndef GRID_QCD_BASE_H | ||||
| #define GRID_QCD_BASE_H | ||||
| namespace Grid{ | ||||
| 
 | ||||
| namespace QCD { | ||||
| 
 | ||||
|     static const int Xdir = 0; | ||||
|     static const int Ydir = 1; | ||||
|     static const int Zdir = 2; | ||||
|     static const int Tdir = 3; | ||||
| 
 | ||||
|    | ||||
|     static const int Xp = 0; | ||||
|     static const int Yp = 1; | ||||
| @@ -55,10 +59,18 @@ namespace QCD { | ||||
|     //////////////////////////////////////////////////////////////////////////////
 | ||||
|     // QCD iMatrix types
 | ||||
|     // Index conventions:                            Lorentz x Spin x Colour
 | ||||
|     // note: static const int or constexpr will work for type deductions
 | ||||
|     //       with the intel compiler (up to version 17)
 | ||||
|     //////////////////////////////////////////////////////////////////////////////
 | ||||
|     static const int ColourIndex = 2; | ||||
|     static const int SpinIndex   = 1; | ||||
|     static const int LorentzIndex= 0; | ||||
|     #define ColourIndex  2 | ||||
|     #define SpinIndex    1 | ||||
|     #define LorentzIndex 0 | ||||
| 
 | ||||
|     // Also should make these a named enum type
 | ||||
|     static const int DaggerNo=0; | ||||
|     static const int DaggerYes=1; | ||||
|     static const int InverseNo=0; | ||||
|     static const int InverseYes=1; | ||||
| 
 | ||||
|     // Useful traits is this a spin index
 | ||||
|     //typename std::enable_if<matchGridTensorIndex<iVector<vtype,Ns>,SpinorIndex>::value,iVector<vtype,Ns> >::type *SFINAE;
 | ||||
| @@ -409,15 +421,16 @@ namespace QCD { | ||||
|     //////////////////////////////////////////////
 | ||||
|     // Fermion <-> propagator assignements
 | ||||
|     //////////////////////////////////////////////
 | ||||
|     template <class Prop, class Ferm> | ||||
|     void FermToProp(Prop &p, const Ferm &f, const int s, const int c) | ||||
|     //template <class Prop, class Ferm>
 | ||||
|     template <class Fimpl> | ||||
|       void FermToProp(typename Fimpl::PropagatorField &p, const typename Fimpl::FermionField &f, const int s, const int c) | ||||
|     { | ||||
|       for(int j = 0; j < Ns; ++j) | ||||
|         { | ||||
|             auto pjs = peekSpin(p, j, s); | ||||
|             auto fj  = peekSpin(f, j); | ||||
|              | ||||
|             for(int i = 0; i < Nc; ++i) | ||||
|             for(int i = 0; i < Fimpl::Dimension; ++i) | ||||
|             { | ||||
|                 pokeColour(pjs, peekColour(fj, i), i, c); | ||||
|             } | ||||
| @@ -425,15 +438,16 @@ namespace QCD { | ||||
|         } | ||||
|     } | ||||
|      | ||||
|     template <class Prop, class Ferm> | ||||
|     void PropToFerm(Ferm &f, const Prop &p, const int s, const int c) | ||||
|     //template <class Prop, class Ferm>
 | ||||
|     template <class Fimpl> | ||||
|       void PropToFerm(typename Fimpl::FermionField &f, const typename Fimpl::PropagatorField &p, const int s, const int c) | ||||
|     { | ||||
|         for(int j = 0; j < Ns; ++j) | ||||
|         { | ||||
|             auto pjs = peekSpin(p, j, s); | ||||
|             auto fj  = peekSpin(f, j); | ||||
|              | ||||
|             for(int i = 0; i < Nc; ++i) | ||||
|             for(int i = 0; i < Fimpl::Dimension; ++i) | ||||
|             { | ||||
|                 pokeColour(fj, peekColour(pjs, i, c), i); | ||||
|             } | ||||
| @@ -481,19 +495,17 @@ namespace QCD { | ||||
|       return traceIndex<ColourIndex>(lhs); | ||||
|     } | ||||
| 
 | ||||
|     //////////////////////////////////////////
 | ||||
|     // Current types
 | ||||
|     //////////////////////////////////////////
 | ||||
|     GRID_SERIALIZABLE_ENUM(Current, undef, | ||||
|                            Vector,  0, | ||||
|                            Axial,   1, | ||||
|                            Tadpole, 2); | ||||
| 
 | ||||
| }   //namespace QCD
 | ||||
| } // Grid
 | ||||
| 
 | ||||
| #include <qcd/utils/SpaceTimeGrid.h> | ||||
| #include <qcd/spin/Dirac.h> | ||||
| #include <qcd/spin/TwoSpinor.h> | ||||
| #include <qcd/utils/LinalgUtils.h> | ||||
| #include <qcd/utils/CovariantCshift.h> | ||||
| #include <qcd/utils/SUn.h> | ||||
| #include <qcd/action/Actions.h> | ||||
| #include <qcd/hmc/integrators/Integrator.h> | ||||
| #include <qcd/hmc/integrators/Integrator_algorithm.h> | ||||
| #include <qcd/hmc/HMC.h> | ||||
| 
 | ||||
| 
 | ||||
| #endif | ||||
| @@ -2,11 +2,15 @@ | ||||
| 
 | ||||
|     Grid physics library, www.github.com/paboyle/Grid  | ||||
| 
 | ||||
|     Source file: ./lib/qcd/action/ActionParams.h | ||||
|     Source file: ./lib/qcd/action/Actions.h | ||||
| 
 | ||||
|     Copyright (C) 2015 | ||||
| 
 | ||||
| Author: Azusa Yamaguchi <ayamaguc@staffmail.ed.ac.uk> | ||||
| Author: Peter Boyle <pabobyle@ph.ed.ac.uk> | ||||
| Author: Peter Boyle <paboyle@ph.ed.ac.uk> | ||||
| Author: Peter Boyle <peterboyle@Peters-MacBook-Pro-2.local> | ||||
| 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 | ||||
| @@ -26,38 +30,21 @@ Author: paboyle <paboyle@ph.ed.ac.uk> | ||||
|     See the full license in the file "LICENSE" in the top level distribution directory | ||||
|     *************************************************************************************/ | ||||
|     /*  END LEGAL */ | ||||
| #ifndef GRID_QCD_ACTION_PARAMS_H | ||||
| #define GRID_QCD_ACTION_PARAMS_H | ||||
| #ifndef GRID_QCD_ACTION_H | ||||
| #define GRID_QCD_ACTION_H | ||||
| 
 | ||||
| namespace Grid { | ||||
| namespace QCD { | ||||
| 
 | ||||
|     // These can move into a params header and be given MacroMagic serialisation
 | ||||
|     struct GparityWilsonImplParams { | ||||
|       bool overlapCommsCompute; | ||||
|       std::vector<int> twists;  | ||||
|       GparityWilsonImplParams () : twists(Nd,0), overlapCommsCompute(false) {}; | ||||
| 
 | ||||
|     }; | ||||
| 
 | ||||
|     struct WilsonImplParams { | ||||
|       bool overlapCommsCompute; | ||||
|       WilsonImplParams() : overlapCommsCompute(false) {}; | ||||
|     }; | ||||
| 
 | ||||
|     struct OneFlavourRationalParams {  | ||||
|       RealD  lo; | ||||
|       RealD  hi; | ||||
|       int MaxIter;   // Vector?
 | ||||
|       RealD tolerance; // Vector? 
 | ||||
|       int    degree=10; | ||||
|       int precision=64; | ||||
| 
 | ||||
|       OneFlavourRationalParams (RealD _lo,RealD _hi,int _maxit,RealD tol=1.0e-8,int _degree = 10,int _precision=64) : | ||||
|         lo(_lo), hi(_hi), MaxIter(_maxit), tolerance(tol), degree(_degree), precision(_precision) | ||||
|       {}; | ||||
|     }; | ||||
| 
 | ||||
| }} | ||||
| ////////////////////////////////////////////
 | ||||
| // Abstract base interface
 | ||||
| ////////////////////////////////////////////
 | ||||
| #include <Grid/qcd/action/ActionCore.h> | ||||
| ////////////////////////////////////////////////////////////////////////
 | ||||
| // Fermion actions; prevent coupling fermion.cc files to other headers
 | ||||
| ////////////////////////////////////////////////////////////////////////
 | ||||
| #include <Grid/qcd/action/fermion/FermionCore.h> | ||||
| #include <Grid/qcd/action/fermion/Fermion.h> | ||||
| ////////////////////////////////////////
 | ||||
| // Pseudo fermion combinations for HMC
 | ||||
| ////////////////////////////////////////
 | ||||
| #include <Grid/qcd/action/pseudofermion/PseudoFermion.h> | ||||
| 
 | ||||
| #endif | ||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user