├── .coverage ├── .gitignore ├── .travis.yml ├── LICENSE ├── MANIFEST ├── README.rst ├── codecov.yml ├── config.ini ├── coverage.xml ├── docs ├── .nojekyll ├── Makefile ├── builddoc.sh └── source │ ├── conf.py │ ├── example.rst │ ├── execute.rst │ ├── fetch.rst │ ├── gen_str.rst │ ├── image1.jpg │ ├── image10.png │ ├── image2.png │ ├── image3.png │ ├── image4.png │ ├── image5.png │ ├── image6.png │ ├── image7.png │ ├── image8.png │ ├── image9.png │ ├── incar.rst │ ├── index.rst │ ├── installation.rst │ ├── job.rst │ ├── kill.rst │ ├── kpoints.rst │ ├── kpt_eq.png │ ├── potcar.rst │ ├── prepare.rst │ └── test_para.rst ├── examples └── common_calculations │ ├── band.sh │ ├── defect_cal.sh │ ├── dos.sh │ └── readme.md ├── pyvaspflow ├── __init__.py ├── defect_cal │ ├── __init__.py │ ├── chemical_potential.py │ ├── defect_formation_energy.py │ └── defect_maker.py ├── io │ ├── __init__.py │ ├── vasp_input.py │ └── vasp_out.py ├── pyvasp.py ├── utils.py └── vasp │ ├── __init__.py │ ├── prep_vasp.py │ ├── run_vasp.py │ ├── schedule.py │ ├── test_para.py │ └── vasp_err.py ├── setup.py ├── test ├── conf.json ├── test_prep_vasp.py └── test_vasp_input.py └── tox.ini /.coverage: -------------------------------------------------------------------------------- 1 | !coverage.py: This is a private format, don't read it directly!{"lines":{"/home/hecc/Documents/python-package/pyvaspflow/test/test_vasp_input.py":[4,5,6,7,9,18,23,29,33,34,19,20,21,24,25,26,27,10,11,12,13,14,15,16,30],"/home/hecc/Documents/python-package/pyvaspflow/pyvaspflow/__init__.py":[1,2,4,6,9,12],"/home/hecc/Documents/python-package/pyvaspflow/pyvaspflow/io/__init__.py":[1],"/home/hecc/Documents/python-package/pyvaspflow/pyvaspflow/io/vasp_input.py":[5,6,7,8,9,10,12,14,27,32,38,44,76,79,83,87,101,175,191,202,206,208,235,238,244,265,266,267,268,269,270,271,273,276,285,286,288,289,290,291,292,346,350,363,379,395,411,464,488,527,547,559,660,664,667,699,717,733,331,334,335,336,337,352,355,356,357,361,338,339,340,341,342,343,344,373,374,375,376,389,390,391,392,393,15,16,17,18,28,29,111,113,115,117,122,128,129,144,152,153,30,154,155,159,160,162,163,164,165,167,168,169,170],"/home/hecc/Documents/python-package/pyvaspflow/pyvaspflow/utils.py":[1,2,3,4,5,6,7,8,9,10,11,12,15,36,42,145,155,189,210,221,233,423,437,461,484,487,490,508,516,523],"/home/hecc/.virtualenvs/vasp/lib/python3.7/site-packages/numpy/__init__.py":[106,107,109,110,112,113,117,118,119,120,122,125,126,133,134,136,137,140,142,143,144,145,146,147,148,149,150,151,152,153,154,155,159,160,161,165,167,169,170,171,172,173,176,177,178,182,183,187,190,191,192,195,218,206,207,208,219],"/home/hecc/.virtualenvs/vasp/lib/python3.7/site-packages/numpy/_globals.py":[17,18,21,27,29,32,40,43,46,53,56,59,65,66,67,74,77,81,69,70,71,78],"/home/hecc/.virtualenvs/vasp/lib/python3.7/site-packages/numpy/__config__.py":[3,7,8,10,12,16,17,18,19,20,21,22,24,28],"/home/hecc/.virtualenvs/vasp/lib/python3.7/site-packages/numpy/version.py":[5,6,7,8,9,11],"/home/hecc/.virtualenvs/vasp/lib/python3.7/site-packages/numpy/_distributor_init.py":[10],"/home/hecc/.virtualenvs/vasp/lib/python3.7/site-packages/numpy/core/__init__.py":[1,3,4,6,11,33,34,35,36,37,39,40,73,74,75,76,77,79,83,84,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,116,117,121,123,124,125,126,128,129,130,131,132,133,134,135,136,137,143,151,157,158,159,163,165,166,167,169,170,171],"/home/hecc/.virtualenvs/vasp/lib/python3.7/site-packages/numpy/core/info.py":[83,84,86,87],"/home/hecc/.virtualenvs/vasp/lib/python3.7/site-packages/numpy/core/multiarray.py":[7,9,10,12,13,14,15,16,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,44,45,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,68,69,70,73,74,135,136,225,302,303,377,378,459,460,570,621,693,694,781,839,840,915,916,976,977,1029,1030,1064,1109,1110,1157,1158,1204,1205,1248,1249,1289,1290,1343,1345,1437,1439,1505,1506,1507],"/home/hecc/.virtualenvs/vasp/lib/python3.7/site-packages/numpy/core/overrides.py":[1,2,3,4,6,8,11,12,15,16,46,50,51,65,68,71,93,112,180,183,187,184,185,186,144,146,152,147,148,149,150,151,104,108,105,106,107],"/home/hecc/.virtualenvs/vasp/lib/python3.7/site-packages/numpy/compat/__init__.py":[10,11,13,14,15,16,18,19,20],"/home/hecc/.virtualenvs/vasp/lib/python3.7/site-packages/numpy/compat/_inspect.py":[7,8,10,12,15,28,43,65,67,98,115,127,133,142,143,144,145,146,147,171,172,173,174,175,108,26,110,41,112,76,61,79,80,81,86,87,89,90,93,94,96,113,156,157,158,159,160,137,140,161,163,162,164,166,168,91,92,95,165,167,111],"/home/hecc/.virtualenvs/vasp/lib/python3.7/site-packages/numpy/compat/py3k.py":[4,5,7,8,9,10,11,13,14,15,19,20,22,23,24,25,26,28,33,38,43,46,49,52,80,83,89,95,104,113,115,118,121,125,126,184,185,186,192,193,194,195],"/home/hecc/.virtualenvs/vasp/lib/python3.7/site-packages/numpy/core/umath.py":[7,9,10,11,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35],"/home/hecc/.virtualenvs/vasp/lib/python3.7/site-packages/numpy/core/numerictypes.py":[81,82,84,85,86,87,89,90,95,98,99,100,101,102,107,111,121,125,126,127,133,135,136,137,138,139,140,141,143,192,238,239,293,333,365,429,436,438,441,442,443,444,445,457,446,447,448,449,450,451,452,454,455,460,513,514,515,517,518,521,523,525,526,530,531,532,534,536,537,538,539,540,541,542,543,544,547,548,561,563,564,568,578,593,599,594,595,596,597,602],"/home/hecc/.virtualenvs/vasp/lib/python3.7/site-packages/numpy/core/_string_helpers.py":[5,9,10,11,12,13,16,44,72,40,41,97,98,68,69],"/home/hecc/.virtualenvs/vasp/lib/python3.7/site-packages/numpy/core/_type_aliases.py":[24,25,26,28,29,30,31,32,35,36,37,42,48,49,53,54,55,57,58,61,59,63,66,79,95,105,96,98,99,100,101,103,104,112,113,115,152,116,118,122,81,67,68,76,82,83,84,86,89,90,92,124,128,131,132,134,135,139,142,143,146,147,148,150,151,119,137,133,87,154,178,155,156,157,158,159,161,162,163,164,167,168,169,170,171,172,173,174,176,181,187,229,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,212,213,214,216,217,218,219,223,224,225,226,227,228,232,233,234,235,236,238,246,266,247,248,249,250,251,239,240,244,252,241,242,253,254,255,256,257,258,270,271,272,276,277,280,278,282],"/home/hecc/.virtualenvs/vasp/lib/python3.7/site-packages/numpy/core/_dtype.py":[5,6,8,10,14,15,16,17,18,19,20,21,22,24,25,26,27,36,46,57,64,75,80,115,172,190,201,245,268,294,311,319,37,38],"/home/hecc/.virtualenvs/vasp/lib/python3.7/site-packages/numpy/core/numeric.py":[1,3,6,9,10,11,12,13,14,16,17,18,28,31,32,33,34,37,38,39,41,42,43,45,46,47,48,49,50,53,54,60,61,64,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,92,96,97,104,105,108,112,113,175,176,228,232,233,293,294,340,344,345,402,406,407,469,470,541,542,594,595,635,636,676,677,775,838,842,884,888,929,930,931,934,940,944,945,1013,1017,1018,1117,1121,1122,1206,1210,1211,1397,1401,1402,1491,1495,1496,1557,1616,1620,1693,1697,1701,1702,1899,1902,1903,1974,2031,2035,2112,2113,2223,2224,2280,2307,2318,2319,2351,2355,2356,2427,2431,2432,2547,2551,2594,2598,2646,2647,2648,2649,2650,2651,2653,2656,2657,2758,2810,2835,2849,2942,2988,2989,2992,2995,2996,3050,3054,3058,3063,3069,3075,3070,3071,3077,3078,3079,3080,3083,3091,3092,3093,3094,3095,3096,3097,3084,3085,3086,3087,3088,3098,3099,3100,3055,3056,3059,2736,2737,2796,2797,2798,2799,2800,2801,2802,2803,2804,2805,2806,2807,2739,2741,2743,2745,2750,2751,2753,2754,2755,3060,3064,3065,2740,2742,2744,2746,223,224,225],"/home/hecc/.virtualenvs/vasp/lib/python3.7/site-packages/numpy/core/_internal.py":[6,7,9,10,12,13,14,15,16,20,21,25,56,88,140,146,150,151,155,157,204,205,207,209,211,213,216,235,239,240,243,244,248,256,257,260,272,288,289,308,320,329,338,356,368,379,389,390,391,392,395,418,436,468,501,502,503,504,505,506,507,508,509,510,511,512,513,514,515,516,517,518,519,520,521,522,523,525,528,529,530,531,532,533,534,535,536,537,538,539,540,541,542,543,544,545,546,547,548,550,553,554,555,556,559,560,564,569,575,587,591,593,596,601,746,761,783,789,795,799,800,801,803,804,805,806,821,833,840,886,899,923,924,926,217,218,220,224,225,227,228,233,234,889,892,894,848,849,854,856,857,867,874,875,878,879,880,881,882,851],"/home/hecc/.virtualenvs/vasp/lib/python3.7/site-packages/numpy/core/fromnumeric.py":[3,4,6,7,8,10,11,12,13,14,15,16,17,19,23,24,25,26,27,28,29,32,34,36,37,41,54,69,89,93,94,192,197,198,295,302,303,425,429,430,474,478,479,537,541,588,592,593,642,646,647,738,742,743,811,815,816,938,942,943,1037,1041,1042,1106,1110,1111,1175,1179,1180,1249,1253,1327,1331,1332,1391,1395,1396,1511,1515,1516,1579,1583,1584,1690,1694,1781,1785,1831,1835,1836,1899,1903,1904,1962,1966,1967,2079,2083,2084,2167,2171,2172,2248,2252,2253,2320,2324,2325,2393,2397,2398,2508,2512,2513,2621,2625,2660,2664,2665,2775,2779,2780,2843,2847,2885,2889,2890,2936,2940,2941,3010,3014,3015,3122,3126,3127,3246,3250,3251,3373,3374,3385,3397,3409,3423,3435],"/home/hecc/.virtualenvs/vasp/lib/python3.7/site-packages/numpy/core/_methods.py":[5,6,8,10,11,12,13,14,17,18,19,20,21,22,26,27,30,31,34,35,38,39,42,45,48,58,91,138,151],"/home/hecc/.virtualenvs/vasp/lib/python3.7/site-packages/numpy/core/arrayprint.py":[5,6,8,9,10,11,27,28,29,30,31,32,41,42,43,44,45,48,49,50,52,53,54,57,58,59,60,61,62,63,64,65,66,67,71,98,101,260,290,291,324,344,352,355,358,411,450,480,460,476,481,461,463,474,513,518,519,520,521,522,693,707,825,832,833,834,861,945,975,976,982,983,989,991,1058,1061,1135,1136,1144,1148,1149,1154,1158,1159,1161,1176,1187,1188,1194,1195,1202,1203,1217,1221,1228,1230,1248,1253,1260,1261,1265,1266,1269,1275,1282,1283,1286,1300,1312,1313,1321,1330,1331,1333,1337,1373,1398,1399,1445,1449,1450,1496,1500,1501,1520,1524,1525,1564,1565,1566,1567,1568,1571,1630,1622,1628,1631,1503,1510,1514,465,466,468,469,470,472],"/home/hecc/.virtualenvs/vasp/lib/python3.7/site-packages/numpy/core/defchararray.py":[17,18,20,21,22,23,24,25,26,27,28,29,32,33,34,35,36,37,38,39,40,44,45,46,47,51,53,54,57,71,78,94,105,109,135,161,188,214,240,266,270,291,319,323,353,357,385,424,428,429,465,469,470,516,520,521,567,568,603,607,608,652,656,657,692,693,728,729,757,783,809,835,862,889,915,942,946,973,977,978,1013,1050,1054,1055,1112,1116,1152,1156,1157,1189,1190,1222,1223,1252,1253,1288,1324,1328,1329,1366,1370,1371,1415,1416,1450,1454,1455,1484,1488,1489,1520,1521,1569,1607,1647,1651,1652,1688,1725,1729,1760,1792,1824,1825,1966,1968,2002,2007,2024,2034,2044,2054,2064,2074,2084,2095,2106,2117,2128,2140,2143,2162,2164,2176,2187,2199,2210,2221,2233,2245,2257,2268,2281,2294,2306,2319,2332,2344,2357,2369,2381,2393,2405,2415,2427,2440,2452,2464,2474,2486,2498,2510,2522,2534,2546,2558,2571,2585,2597,2609,2621,2634,2786],"/home/hecc/.virtualenvs/vasp/lib/python3.7/site-packages/numpy/core/records.py":[36,37,39,40,41,43,44,45,46,47,50,53,55,56,57,58,59,60,61,62,63,64,65,66,67,68,75,77,87,88,146,148,154,173,209,220,222,226,227,229,234,239,264,278,288,305,409,413,414,418,433,439,473,505,522,556,575,640,709,728,738,814],"/home/hecc/.virtualenvs/vasp/lib/python3.7/site-packages/numpy/core/memmap.py":[1,3,4,5,8,10,12,13,14,17,18,19,20,24,25,203,205,207,208,285,297,315,330],"/home/hecc/.virtualenvs/vasp/lib/python3.7/site-packages/numpy/core/function_base.py":[1,3,4,5,7,8,10,11,13,16,17,20,33,37,39,183,187,189,284,288,289,431,452,453,454,455,456,457,461,462],"/home/hecc/.virtualenvs/vasp/lib/python3.7/site-packages/numpy/core/machar.py":[7,8,10,12,13,14,18,19,98,100,101,102,103,118,329,343],"/home/hecc/.virtualenvs/vasp/lib/python3.7/site-packages/numpy/core/getlimits.py":[3,4,6,8,10,11,12,13,14,15,16,19,27,34,35,37,62,63,64,68,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,91,92,94,96,239,282,293,294,361,363,365,398,422,436,444,445,492,494,495,497,508,520,522,534,536,547,498,499,502,503,504,505,524,525,526,527,530,531,532,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,40,41,42,43,45,47,29,30,31,32,48,49,50,51,52,53,54,55,21,22,23,24,56,57,58,59,114,93,115,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,158,159,160,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,179,180,181,182,183,186,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,206,207,214,216,217,218,219,220,221,222,223,224,225,226,227,228,229,231,232,234,235,236],"/home/hecc/.virtualenvs/vasp/lib/python3.7/site-packages/numpy/core/shape_base.py":[1,3,4,6,7,8,9,11,12,13,14,17,18,21,25,79,83,137,141,209,220,225,229,286,343,352,353,426,434,510,516,527,585,638,657,669,844,861,880],"/home/hecc/.virtualenvs/vasp/lib/python3.7/site-packages/numpy/core/einsumfunc.py":[4,5,7,9,10,11,12,14,16,17,20,58,87,147,217,275,314,415,525,693,703,993,1002],"/home/hecc/.virtualenvs/vasp/lib/python3.7/site-packages/numpy/core/_add_newdocs.py":[10,11,13,14,15,25,66,70,85,104,123,129,154,416,420,439,446,454,464,479,488,497,505,564,566,586,631,635,653,675,691,706,720,734,748,785,897,899,948,950,962,964,1015,1017,1023,1025,1073,1075,1110,1112,1144,1146,1219,1221,1262,1264,1265,1267,1268,1270,1329,1331,1336,1338,1343,1346,1352,1354,1402,1404,1462,1464,1480,1482,1514,1516,1818,1835,1954,1964,1968,1972,1976,1980,1987,2008,2082,2086,2115,2130,2146,2223,2265,2285,2301,2320,2361,2387,2449,2479,2489,2495,2501,2511,2519,2527,2548,2563,2578,2593,2608,2623,2640,2709,2749,2764,2780,2795,2810,2825,2868,2883,2898,2915,2944,2958,2972,2997,3035,3077,3135,3181,3196,3211,3226,3265,3268,3304,3307,3349,3364,3379,3394,3408,3439,3441,3481,3484,3501,3516,3538,3630,3645,3660,3711,3788,3844,3899,3914,3929,3944,3959,3974,4014,4084,4086,4087,4089,4093,4094,4095,4097,4112,4166,4181,4287,4329,4331,4393,4395,4452,4461,4469,4471,4495,4497,4540,4542,4584,4586,4615,4631,4680,4689,4708,4732,4750,4773,4799,4836,4873,4990,5069,5176,5240,5304,5387,5395,5403,5446,5449,5460,5488,5500,5513,5542,5549,5557,5566,5586,5594,5609,5617,5624,5633,5636,5650,5659,5731,5793,5795,5798,5801,5850,5852,5887,5896,5906,5910,5924,5938,5941,5944,5947,5950,5953,5956,5959,5962,5965,5968,5971,5976,5990,6004,6018,6032,6046,6060,6074,6088,6102,6116,6130,6144,6158,6172,6186,6200,6214,6228,6242,6256,6270,6284,6298,6312,6326,6359,6373,6387,6401,6415,6429,6443,6457,6471,6485,6499,6513,6527,6541,6555,6569,6583,6597,6611,6625,6639,6653,6667,6681,6695,6717,6721,6723,6727,6729,6733,6735,6739,6741,6747,6749,6753,6755,6760,6762,6768,6770,6774,6783,6796,6797,6798,6799,6800,6801,6802,6803,6804,6805,6806,6807,6808,6809,6810,6811,6812,6813,6814,6815,6784,6793,6785,6786,6787,6792,6788,6790,6819,6838,6841,6820,6822,6823,6824,6825,6826,6832,6833,6835,6843,6846,6848,6851,6853,6856,6858,6861,6863,6866,6868,6871,6873,6876,6878,6881,6883,6886,6888,6891,6893,6896,6898,6901,6903,6907,6909,6913,6915,6919,6921,6925,6927,6931,6933,6936],"/home/hecc/.virtualenvs/vasp/lib/python3.7/site-packages/numpy/core/_dtype_ctypes.py":[24,25,26,28,31,35,69,81,97,101,103,105,107,109,110,73,74,75,76,78],"/home/hecc/.virtualenvs/vasp/lib/python3.7/site-packages/numpy/_pytesttester.py":[29,30,32,33,35,39,47,71,72,76,73],"/home/hecc/.virtualenvs/vasp/lib/python3.7/site-packages/numpy/lib/__init__.py":[1,3,5,6,8,9,10,11,12,13,14,15,16,17,19,20,22,23,24,25,26,27,28,29,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,49,50,51],"/home/hecc/.virtualenvs/vasp/lib/python3.7/site-packages/numpy/lib/info.py":[156,157,159,160],"/home/hecc/.virtualenvs/vasp/lib/python3.7/site-packages/numpy/lib/type_check.py":[3,4,5,6,8,9,10,11,13,14,15,16,17,20,21,24,27,28,83,87,88,120,124,166,170,209,213,250,282,323,360,366,370,371,453,457,458,513,517,551,552,553,554,555,556,557,558,559,560,561,562,563,564,565,566,567,568,569,570,571,572,575,630,631,632,633,634,635,636,637,638,641,645],"/home/hecc/.virtualenvs/vasp/lib/python3.7/site-packages/numpy/lib/ufunclike.py":[5,6,8,10,11,12,13,16,41,58,59,62,63,22,23,38,67,68,69,114,115,116,183,184,185],"/home/hecc/.virtualenvs/vasp/lib/python3.7/site-packages/numpy/lib/index_tricks.py":[1,3,4,5,7,8,11,13,14,15,16,17,18,21,22,26,27,28,32,36,109,142,144,147,209,250,251,254,252,145,256,293,294,297,295,300,305,307,308,310,316,413,420,513,515,518,516,311,312,313,314,520,543,545,549,546,552,553,578,580,583,597,600,603,604,632,634,642,645,653,668,682,724,726,729,735,727,736,745,749,750,864,865,933,937],"/home/hecc/.virtualenvs/vasp/lib/python3.7/site-packages/numpy/matrixlib/__init__.py":[3,4,6,8,10,11,12],"/home/hecc/.virtualenvs/vasp/lib/python3.7/site-packages/numpy/matrixlib/defmatrix.py":[1,3,5,6,7,8,9,10,13,16,38,39,74,75,115,116,117,169,191,217,225,228,232,235,239,242,255,266,289,325,378,415,449,483,517,550,573,613,648,687,722,761,794,838,867,895,934,966,1000,1001,1002,1003,1004,1006,1031,1032,1109],"/home/hecc/.virtualenvs/vasp/lib/python3.7/site-packages/numpy/linalg/__init__.py":[45,46,49,51,53,54,55],"/home/hecc/.virtualenvs/vasp/lib/python3.7/site-packages/numpy/linalg/info.py":[34,35,37],"/home/hecc/.virtualenvs/vasp/lib/python3.7/site-packages/numpy/linalg/linalg.py":[10,11,14,15,16,17,19,20,21,23,31,32,33,34,35,38,39,43,44,45,46,47,49,52,53,79,82,93,83,84,86,87,88,90,94,96,99,102,105,108,111,116,121,124,125,126,127,129,130,131,132,134,137,140,144,171,173,185,197,203,209,215,220,224,229,248,252,253,323,327,408,412,413,482,486,555,559,678,765,769,770,985,1076,1080,1081,1173,1182,1324,1325,1464,1468,1469,1629,1633,1634,1751,1755,1756,1860,1864,1865,1953,2040,2100,2104,2105,2261,2289,2293,2294,2536,2540,2652,2673,2714],"/home/hecc/.virtualenvs/vasp/lib/python3.7/site-packages/numpy/lib/twodim_base.py":[3,4,6,8,13,14,15,19,20,21,24,25,28,29,30,33,44,48,99,154,155,212,216,217,288,289,348,349,398,402,403,441,442,470,475,476,567,571,573,704,705,775,776,856,860,861,889,890,972,973],"/home/hecc/.virtualenvs/vasp/lib/python3.7/site-packages/numpy/lib/function_base.py":[1,3,6,9,10,11,12,14,15,16,17,22,26,29,30,31,32,33,34,35,39,40,42,47,50,51,55,58,59,60,61,62,63,64,65,69,73,74,160,164,165,258,290,294,295,434,435,502,510,632,639,640,743,747,748,797,803,1145,1149,1150,1278,1282,1283,1415,1419,1420,1467,1471,1472,1528,1532,1569,1573,1574,1624,1628,1680,1684,1728,1771,1772,1773,1774,1775,1778,1801,1835,1864,1870,1878,1879,2029,2032,2063,2093,2154,2176,2241,2245,2247,2455,2459,2460,2543,2643,2750,2852,2954,2955,2956,2957,2958,2959,2960,2961,2962,2963,2964,2965,2966,2967,2968,2969,2970,2971,2972,2973,2974,2975,2976,2977,2978,2979,2980,2981,2982,2983,2987,2988,2989,2990,2991,2992,2993,2994,2995,2996,2997,2998,2999,3000,3001,3002,3003,3004,3005,3006,3007,3008,3009,3010,3011,3015,3027,3031,3035,3039,3107,3236,3240,3321,3325,3354,3410,3414,3415,3503,3560,3564,3566,3711,3715,3717,3822,3833,3847,3978,3982,3983,4073,4078,4216,4220,4221,4426,4430,4431,4637,4641,4642,4697,4701,4702],"/home/hecc/.virtualenvs/vasp/lib/python3.7/site-packages/numpy/lib/utils.py":[1,3,4,5,6,7,9,10,11,12,15,18,19,20,23,53,58,68,70,75,118,172,179,236,341,360,361,365,385,436,437,642,643,694,698,701,703,830,970,994,1007,1008,1013,1018,1022,1025,1028,1031,1034,1038,1041,1044,1053,1063,1067,1116,164,165,166,168,71,72,73,80,81,82,84,89,92,93,95,98,103,54,55,104,105,108,109,110,111,115,116,170,85,86,90,96],"/home/hecc/.virtualenvs/vasp/lib/python3.7/site-packages/numpy/lib/histograms.py":[3,4,6,7,8,10,11,12,14,16,17,21,24,45,68,92,114,155,190,220,264,265,266,267,268,269,270,271,274,295,325,351,445,457,461,462,662,666,668,920,924,926],"/home/hecc/.virtualenvs/vasp/lib/python3.7/site-packages/numpy/lib/stride_tricks.py":[7,8,10,11,13,16,19,21,26,39,116,139,143,144,185,204,208],"/home/hecc/.virtualenvs/vasp/lib/python3.7/site-packages/numpy/lib/mixins.py":[1,2,4,6,9,12,20,30,40,48,55,63,139,144,22,26,27,145,146,147,148,149,152,50,51,32,36,37,52,42,44,45,153,154,155,156,157,160,161,162,163,164,165,166,169,170,171,172,173,174,175,176,179,57,59,60,180,181,182],"/home/hecc/.virtualenvs/vasp/lib/python3.7/site-packages/numpy/lib/nanfunctions.py":[22,23,25,26,27,28,29,32,33,37,38,39,43,87,116,156,197,201,202,310,314,315,423,427,428,472,476,477,522,526,527,617,621,622,687,691,692,757,761,762,824,828,829,926,939,965,983,987,988,1087,1091,1092,1093,1213,1217,1218,1219,1324,1325,1343,1366,1381,1385,1386,1528,1532,1533],"/home/hecc/.virtualenvs/vasp/lib/python3.7/site-packages/numpy/lib/shape_base.py":[1,3,4,6,7,10,11,12,13,14,16,17,21,22,23,24,28,29,32,55,59,176,180,266,270,418,422,509,513,592,595,599,643,647,702,711,715,716,771,775,776,854,858,922,975,1021,1033,1046,1050,1150,1154],"/home/hecc/.virtualenvs/vasp/lib/python3.7/site-packages/numpy/lib/scimath.py":[17,18,20,21,22,23,24,28,29,33,36,99,127,154,181,185,229,277,327,331,367,415,419,464,509,555],"/home/hecc/.virtualenvs/vasp/lib/python3.7/site-packages/numpy/lib/polynomial.py":[4,5,7,8,9,11,12,13,14,16,18,19,20,21,22,23,26,27,30,31,38,39,42,46,164,168,254,258,259,353,357,358,427,431,432,660,664,735,739,801,849,907,911,977,978,1005,1006,1105,1106,1108,1113,1119,1125,1130,1137,1140,1145,1146,1147,1149,1176,1182,1187,1190,1247,1250,1253,1256,1263,1270,1274,1278,1286,1290,1294,1301,1303,1310,1312,1319,1325,1333,1344,1347,1360,1375],"/home/hecc/.virtualenvs/vasp/lib/python3.7/site-packages/numpy/lib/arraysetops.py":[27,28,30,32,33,36,37,41,42,46,50,51,138,147,151,153,300,333,337,338,433,437,438,480,484,485,597,601,602,700,704,741,745,746],"/home/hecc/.virtualenvs/vasp/lib/python3.7/site-packages/numpy/lib/npyio.py":[1,3,4,5,6,7,8,9,10,12,13,14,15,16,17,18,19,25,29,31,32,38,48,49,50,54,55,58,86,88,92,98,107,122,187,190,210,213,216,229,233,236,239,269,274,282,291,293,463,467,468,542,549,629,636,701,768,800,803,804,805,806,1189,1193,1195,1444,1445,1543,1544,1545,1546,1547,1548,1549,1550,2229,2246,2263,2295],"/home/hecc/.virtualenvs/vasp/lib/python3.7/site-packages/numpy/lib/format.py":[156,157,159,160,161,162,163,164,167,170,171,172,173,178,183,208,230,262,299,326,382,395,410,441,475,516,570,648,744,854],"/home/hecc/.virtualenvs/vasp/lib/python3.7/site-packages/numpy/lib/_datasource.py":[35,36,38,39,40,41,42,44,47,50,73,98,142,164,166,170,203,222,226,167,168,228,269,270,317,319,329,334,341,351,364,373,391,428,459,504,518,578,627,665,667,672,675,684,688,711,745,777],"/home/hecc/.virtualenvs/vasp/lib/python3.7/site-packages/numpy/lib/_iotools.py":[3,4,6,8,9,10,11,13,14,15,20,46,57,68,102,129,170,184,186,207,236,246,257,266,270,320,322,323,327,353,424,428,464,468,469,472,476,477,480,489,490,493,540,542,543,547,550,551,552,553,554,556,558,564,574,582,583,625,708,715,741,745,790,821,878],"/home/hecc/.virtualenvs/vasp/lib/python3.7/site-packages/numpy/lib/financial.py":[12,13,15,16,18,19,22,23,26,27,29,30,31,32,33,34,36,47,51,52,141,145,146,239,243,244,313,317,318,414,424,428,429,458,462,463,560,569,580,581,653,657,738,742,789,793],"/home/hecc/.virtualenvs/vasp/lib/python3.7/site-packages/numpy/lib/arrayterator.py":[9,10,12,13,15,17,20,87,89,97,100,132,141,170,181],"/home/hecc/.virtualenvs/vasp/lib/python3.7/site-packages/numpy/lib/arraypad.py":[5,6,8,9,12,19,62,78,86,91,97,102,107,136,166,193,221,271,321,367,415,461,510,556,605,651,699,770,838,889,960,964],"/home/hecc/.virtualenvs/vasp/lib/python3.7/site-packages/numpy/lib/_version.py":[7,8,10,12,15,18,54,56,79,100,115,137,140,143,146,149,152,155],"/home/hecc/.virtualenvs/vasp/lib/python3.7/site-packages/numpy/fft/__init__.py":[1,4,6,7,9,10,11],"/home/hecc/.virtualenvs/vasp/lib/python3.7/site-packages/numpy/fft/info.py":[184,185,187],"/home/hecc/.virtualenvs/vasp/lib/python3.7/site-packages/numpy/fft/fftpack.py":[32,33,35,36,38,40,42,43,44,45,47,48,51,52,55,56,104,111,115,116,212,213,307,308,397,398,488,489,571,572,633,652,662,666,667,764,765,862,863,953,954,1041,1042,1134,1135,1172,1173,1267,1268],"/home/hecc/.virtualenvs/vasp/lib/python3.7/site-packages/numpy/fft/helper.py":[4,5,7,8,9,12,13,14,18,20,23,27,28,84,85,131,132,180,181,232,252,253,259,285,313,319,254,255,256,257],"/home/hecc/.virtualenvs/vasp/lib/python3.7/site-packages/numpy/polynomial/__init__.py":[15,16,18,19,20,21,22,23,25,26,27],"/home/hecc/.virtualenvs/vasp/lib/python3.7/site-packages/numpy/polynomial/polynomial.py":[57,58,61,62,63,64,65,67,68,69,70,72,73,75,83,86,89,92,99,133,208,252,298,338,376,433,487,573,696,792,880,937,992,1051,1110,1166,1226,1293,1512,1552,1614,1635,1637,1638,1639,1640,1641,1642,1643,1644,1645,1646,1647,1648,1651,1652,1653,1654,1656],"/home/hecc/.virtualenvs/vasp/lib/python3.7/site-packages/numpy/polynomial/polyutils.py":[45,46,48,51,52,58,59,60,62,63,64,66,72,73,79,88,89,94,124,200,254,300,347],"/home/hecc/.virtualenvs/vasp/lib/python3.7/site-packages/numpy/polynomial/_polybase.py":[8,9,11,12,14,15,17,19,61,62,65,68,71,73,77,81,85,89,93,97,101,105,109,113,117,121,125,129,133,137,160,178,196,214,250,266,274,280,291,297,358,365,370,375,378,383,386,389,397,405,413,417,426,432,438,450,455,462,469,476,480,485,491,497,508,516,523,534,547,572,595,624,664,693,726,748,763,795,797,885,886,926,927,959,960,998,999],"/home/hecc/.virtualenvs/vasp/lib/python3.7/site-packages/numpy/polynomial/chebyshev.py":[89,90,92,93,94,95,97,98,101,102,103,104,105,106,107,109,116,141,166,193,260,292,330,380,447,450,453,456,459,495,561,611,664,710,759,825,880,976,1108,1195,1251,1306,1365,1424,1479,1542,1607,1803,1848,1904,1971,2016,2044,2081,2118,2139,2141,2142,2143,2144,2145,2146,2147,2148,2149,2150,2151,2152,2154,2155,2197,2198,2199,2200],"/home/hecc/.virtualenvs/vasp/lib/python3.7/site-packages/numpy/polynomial/legendre.py":[83,84,86,87,88,89,91,92,95,96,97,98,99,100,102,105,153,219,222,225,228,231,267,333,383,436,492,560,628,679,775,907,995,1051,1106,1165,1224,1279,1342,1407,1605,1649,1705,1773,1804,1825,1827,1828,1829,1830,1831,1832,1833,1834,1835,1836,1837,1838,1841,1842,1843,1844],"/home/hecc/.virtualenvs/vasp/lib/python3.7/site-packages/numpy/polynomial/hermite.py":[60,61,63,64,65,66,68,69,72,73,74,75,76,77,79,82,128,191,194,197,200,203,239,306,354,403,456,522,589,643,730,856,952,1008,1063,1122,1181,1244,1307,1372,1573,1618,1677,1720,1787,1819,1840,1842,1843,1844,1845,1846,1847,1848,1849,1850,1851,1852,1853,1856,1857,1858,1859],"/home/hecc/.virtualenvs/vasp/lib/python3.7/site-packages/numpy/polynomial/hermite_e.py":[60,61,63,64,65,66,68,69,72,73,74,75,76,77,78,80,83,129,191,194,197,200,203,240,307,355,404,453,519,584,638,725,851,946,1002,1057,1116,1175,1237,1300,1365,1566,1612,1671,1714,1781,1812,1833,1835,1836,1837,1838,1839,1840,1841,1842,1843,1844,1845,1846,1849,1850,1851,1852],"/home/hecc/.virtualenvs/vasp/lib/python3.7/site-packages/numpy/polynomial/laguerre.py":[60,61,63,64,65,66,68,69,72,73,74,75,76,77,79,82,128,188,191,194,197,200,236,303,352,401,455,521,586,640,729,857,952,1008,1063,1122,1181,1243,1306,1371,1572,1616,1675,1739,1769,1790,1792,1793,1794,1795,1796,1797,1798,1799,1800,1801,1802,1803,1806,1807,1808,1809],"/home/hecc/.virtualenvs/vasp/lib/python3.7/site-packages/numpy/random/__init__.py":[86,87,89,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,141,142,143,146,147,149,164,165,166],"/home/hecc/.virtualenvs/vasp/lib/python3.7/site-packages/numpy/ctypeslib.py":[51,52,54,55,57,58,61,63,64,68,87,88,89,90,93,159,160,162,168,169,170,179,180,200,206,207,215,230,231,349,350,359,373,363,365,366,367,368,370,376,395,401,455,464,505,526],"/home/hecc/.virtualenvs/vasp/lib/python3.7/site-packages/numpy/ma/__init__.py":[41,42,44,45,47,48,50,51,52,54,55,56],"/home/hecc/.virtualenvs/vasp/lib/python3.7/site-packages/numpy/ma/core.py":[21,23,25,26,27,28,29,30,32,33,37,38,39,40,41,42,43,46,47,48,49,50,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,89,90,92,93,95,123,146,163,167,168,171,175,176,185,186,187,188,189,190,191,192,193,197,199,200,202,203,204,205,206,207,208,211,226,236,291,306,357,408,440,484,549,562,594,640,667,719,722,781,791,792,795,802,804,811,820,826,828,832,838,842,844,847,859,863,865,869,875,879,881,885,891,892,897,901,917,919,926,975,993,995,1008,1055,1085,1110,1123,1142,1144,1155,1199,920,893,894,895,921,922,923,924,1200,1201,1202,1203,1204,1205,1206,1207,1208,1209,1210,1211,1212,1213,1214,1215,1216,1219,1220,883,1221,1222,867,1223,1224,1225,1226,1227,1228,830,1229,1230,806,808,809,1231,1232,1233,1234,1235,1236,1239,1002,1003,1004,1005,1006,1240,1241,1242,1243,1244,1245,1246,1247,1248,1249,1250,1251,1252,1253,1254,1255,1256,1257,1258,1259,1260,1261,1262,1263,1266,845,1148,1149,1150,1151,1152,1153,1267,1268,1269,1270,1271,1272,1273,1274,1282,1314,1328,1361,1422,1425,1480,1548,1558,1647,1697,1764,1821,1833,1950,1976,2002,2028,2054,2080,2110,2150,2190,2251,2331,2378,2382,2384,2392,2399,2406,2413,2420,2423,2426,2389,2390,2429,2447,2448,2454,2455,2462,2463,2467,2468,2473,2481,2495,2551,2596,2642,2644,2653,2656,2671,2676,2707,2710,2763,2765,2766,2767,2768,2772,2773,2775,2776,2777,2905,2931,3024,3080,3161,3163,3283,3349,3353,3365,3369,3377,3446,3448,3456,3458,3470,3479,3481,3496,3511,3512,3514,3532,3533,3535,3561,3562,3564,3571,3572,3574,3578,3583,3584,3586,3621,3660,3661,3663,3739,3766,3834,3865,3868,3872,3956,3970,4034,4047,4060,4069,4078,4087,4094,4100,4109,4118,4127,4134,4143,4150,4159,4166,4183,4199,4215,4233,4251,4269,4290,4303,4315,4327,4360,4362,4394,4396,4496,4542,4598,4616,4686,4712,4740,4780,4810,4911,4924,4926,4965,5018,5056,5096,5098,5129,5177,5217,5218,5279,5281,5282,5305,5330,5331,5410,5451,5489,5565,5628,5686,5749,5786,5792,5798,5825,2578,2589,2590,2591,2592,2593,5826,5827,5828,5829,5830,5831,5832,5833,5835,5886,5894,5934,5949,6001,6004,6013,6030,6038,6049,6059,6062,6064,6065,6084,6088,6090,6112,6119,6130,6132,6145,6148,6170,6199,6251,6252,6255,6257,6259,6265,6283,6297,6300,6303,6306,6310,6317,6324,6332,6333,6335,6341,6344,6347,6360,6266,6263,6269,6270,6273,6274,6279,2787,2788,2789,2791,2797,2800,2937,2910,2911,2915,2916,2917,2918,2919,2920,2921,2922,2923,2924,2925,2926,2927,2928,2929,2965,2968,2971,1419,2980,3002,3006,3008,3018,3020,3351,2802,2808,1358,1323,1324,1325,1284,1287,1298,1305,1308,1311,2810,2843,2845,2849,2850,2856,3367,2868,2869,2870,2891,2892,2894,2897,2898,2901,2902,3128,3133,3134,3135,3136,6284,6287,2981,6348,6350,3009,3010,3137,3148,3149,3152,3160,6281,6361,6364,6365,6366,6378,6381,6439,6447,6448,6453,6464,6498,6514,6524,6526,6536,6539,6548,6556,6565,6567,6572,6582,6597,6568,6569,6574,6576,151,152,155,6577,6578,6579,6580,6570,6598,6599,6600,6601,6602,6603,6604,6605,6606,6607,6449,6450,6451,6608,6609,6610,6611,6612,6613,6614,6615,6616,6617,6618,6619,6621,6622,6624,6626,6633,6684,6685,6687,6700,6702,6715,6718,6734,6794,6812,6833,6854,6873,6912,6953,6972,7036,7050,7053,7060,7063,7066,7069,7072,7080,7161,7236,7267,7272,7366,7450,7465,7466,128,130,133,138,140,141,143,7467,7470,7483,7484,7485,7488,7507,7535,7563,7621,7724,7774,7828,7837,7859,7876,7904,7924,7929,7994,8004,8005,8007,8012,8023,8038,8008,8009,8014,8015,153,154,8016,8018,8020,8021,8010,8039,8040,8041,8042,8043,8044,8019,8045,8046,8047,8048,8049,8050,8051,8052,8055],"/home/hecc/.virtualenvs/vasp/lib/python3.7/site-packages/numpy/ma/extras.py":[10,11,14,15,16,17,18,19,20,21,22,25,26,28,29,36,37,38,39,40,41,42,45,53,108,160,218,236,238,242,269,273,278,279,291,296,297,304,312,313,329,339,340,352,239,240,260,261,262,263,264,266,353,354,356,357,358,359,360,362,364,370,380,461,464,488,489,490,517,520,618,700,786,828,884,901,918,963,1013,1042,1066,1098,1125,1167,1190,1204,1237,1280,1353,1354,1443,1453,1454,1456,1465,1473,1488,1489,1492,1490,1498,1553,1604,1660,1741,1770,1809,1853,1864,1867,1901],"/home/hecc/.virtualenvs/vasp/lib/python3.7/site-packages/numpy/testing/__init__.py":[7,8,10,12,13,14,18,20,21,22],"/home/hecc/.virtualenvs/vasp/lib/python3.7/site-packages/numpy/testing/_private/__init__.py":[1],"/home/hecc/.virtualenvs/vasp/lib/python3.7/site-packages/numpy/testing/_private/utils.py":[4,5,7,8,9,10,11,12,13,14,15,16,17,18,19,21,23,25,26,31,32,33,34,35,36,37,38,39,40,41,45,46,47,50,51,53,54,57,79,99,117,136,155,171,205,207,228,229,230,267,294,425,466,591,692,830,899,1010,1090,1094,1164,1210,1250,1253,1254,1257,1259,1288,1319,1366,1414,1439,1496,1559,1604,1658,1673,1687,1688,1698,1741,1742,1752,1788,1857,1858,1859,1862,1877,1899,1940,1941,1943,1948,1956,1965,2038,2039,2049,2061,2086,2109,2139,2171,2179,2231,2244,2245,2295],"/home/hecc/.virtualenvs/vasp/lib/python3.7/site-packages/numpy/testing/_private/decorators.py":[15,16,18,21,25,27,28,31,66,99,176,230,276,292,128,173],"/home/hecc/.virtualenvs/vasp/lib/python3.7/site-packages/numpy/testing/_private/nosetester.py":[6,7,9,10,11,12,13,15,18,19,20,23,64,115,156,158,198,235,255,266,331,482,556],"/home/hecc/Documents/python-package/sagar/sagar/__init__.py":[1],"/home/hecc/Documents/python-package/sagar/sagar/toolkit/__init__.py":[1],"/home/hecc/Documents/python-package/sagar/sagar/toolkit/mathtool.py":[2,4,5,7,11,24,44,56,61],"/home/hecc/Documents/python-package/sagar/sagar/molecule/__init__.py":[1],"/home/hecc/Documents/python-package/sagar/sagar/molecule/structure.py":[7,8,10,11,12,15,25,27,54,58,62,75,81],"/home/hecc/Documents/python-package/sagar/sagar/molecule/symmetry.py":[6,7,8,11,21,58,76],"/home/hecc/Documents/python-package/sagar/sagar/element/__init__.py":[1],"/home/hecc/Documents/python-package/sagar/sagar/element/base.py":[5,6,7,8,9,10,11,12,15,29],"/home/hecc/Documents/python-package/sagar/sagar/io/__init__.py":[1],"/home/hecc/Documents/python-package/sagar/sagar/io/vasp.py":[2,3,4,5,7,8,11,26,113,135],"/home/hecc/Documents/python-package/sagar/sagar/crystal/__init__.py":[1],"/home/hecc/Documents/python-package/sagar/sagar/crystal/structure.py":[2,3,4,6,8,9,11,16,20,30,32,66,69,72,76,80,84,101,130,138,178,184,190,201,213,226,236,242,258,266,285,295,300,335,338,340,352,363,373,378,383,391,411,414,421,427],"/home/hecc/.virtualenvs/vasp/lib/python3.7/site-packages/spglib/__init__.py":[35,56],"/home/hecc/.virtualenvs/vasp/lib/python3.7/site-packages/spglib/spglib.py":[35,36,38,39,41,43,47,121,218,237,246,276,324,370,404,430,456,468,518,569,589,609,649,683,717,720,741,759,762,44,763,45],"/home/hecc/.virtualenvs/vasp/lib/python3.7/site-packages/pniggli/__init__.py":[1,2,4,7,9,11],"/home/hecc/.virtualenvs/vasp/lib/python3.7/site-packages/pniggli/reduce_3d.py":[1,2,4,7,9,11,130,135],"/home/hecc/.virtualenvs/vasp/lib/python3.7/site-packages/pniggli/utils_3d.py":[1,2,4,22,31,48],"/home/hecc/.virtualenvs/vasp/lib/python3.7/site-packages/pniggli/reduce_2d.py":[1,2,4,6,8],"/home/hecc/.virtualenvs/vasp/lib/python3.7/site-packages/pniggli/utils_2d.py":[1,2,4,21,25,37],"/home/hecc/Documents/python-package/sagar/sagar/crystal/derive.py":[2,4,5,6,8,11,39,42,44,54,94,97,99,106,145,186],"/home/hecc/Documents/python-package/sagar/sagar/crystal/utils.py":[2,3,5,6,8,9,12,27,39,50,98,105,128,147,149,155,159,163,167,170,176,181,196,205,230,236,256,262,269,276,283,291,300,307,312],"/home/hecc/Documents/python-package/sagar/sagar/toolkit/derivetool.py":[2,3,5,7,14,57,68,98,104],"/home/hecc/Documents/python-package/pyvaspflow/pyvaspflow/io/vasp_out.py":[5,6,7,8,9,12,13,18,23,29,37,43,47,54,115,126,130,142],"/home/hecc/Documents/python-package/seekpath/seekpath/__init__.py":[8,10,11,12,13,14,15,17],"/home/hecc/Documents/python-package/seekpath/seekpath/getpaths.py":[3,4,7,78,192],"/home/hecc/Documents/python-package/pyvaspflow/pyvaspflow/vasp/__init__.py":[1],"/home/hecc/Documents/python-package/pyvaspflow/pyvaspflow/vasp/prep_vasp.py":[5,6,7,8,9,12,21,37,45,84,89,106]}} 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.so 3 | *.pyc 4 | *.egg-info/ 5 | *__pycache__/ 6 | .buildinfo 7 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | python: 3 | - "3.5" 4 | - "3.6" 5 | # command to install dependencies 6 | install: 7 | - pip install . 8 | # command to run tests 9 | script: 10 | - pytest 11 | 12 | after_success: 13 | - codecov 14 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 hecc 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /MANIFEST: -------------------------------------------------------------------------------- 1 | # file GENERATED by distutils, do NOT edit 2 | setup.py 3 | pyvaspflow/__init__.py 4 | pyvaspflow/pyvasp.py 5 | pyvaspflow/utils.py 6 | pyvaspflow/defect_cal/__init__.py 7 | pyvaspflow/defect_cal/chemical_potential.py 8 | pyvaspflow/defect_cal/defect_formation_energy.py 9 | pyvaspflow/defect_cal/defect_maker.py 10 | pyvaspflow/io/__init__.py 11 | pyvaspflow/io/vasp_input.py 12 | pyvaspflow/io/vasp_out.py 13 | pyvaspflow/vasp/__init__.py 14 | pyvaspflow/vasp/prep_vasp.py 15 | pyvaspflow/vasp/run_vasp.py 16 | pyvaspflow/vasp/test_para.py 17 | test/test_prep_vasp.py 18 | test/test_vasp_input.py 19 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | Defect-Formation-Calculation 2 | 3 | 4 | .. image:: https://travis-ci.com/ChangChunHe/pyvaspflow.svg?branch=master 5 | :target: https://travis-ci.com/ChangChunHe/pyvaspflow 6 | :alt: Build Status 7 | 8 | .. image:: https://codecov.io/gh/ChangChunHe/pyvaspflow/branch/master/graph/badge.svg 9 | :target: https://codecov.io/gh/ChangChunHe/pyvaspflow 10 | :alt: codecov 11 | 12 | .. image:: https://readthedocs.org/projects/pyvaspflow/badge/?version=latest 13 | :target: https://pyvaspflow.readthedocs.io/zh_CN/latest/ 14 | :alt: Documentation Status 15 | 16 | .. image :: https://badges.frapsoft.com/os/mit/mit.svg?v=103 17 | :target: https://opensource.org/licenses/mit-license.php 18 | :alt: MIT Licence 19 | 20 | .. image :: https://badges.frapsoft.com/os/v1/open-source.svg?v=103 21 | :target: https://opensource.org/licenses/mit-license.php 22 | :alt: Open Source Love 23 | 24 | 25 | This package is a integrated Defect Formation energy package, which contains generating tetrahedral interstitial sites and octahedral interstitial sites, submitting `VASP` calculation job and extracting necessary data to calculate defect formation energy. If you have any problems when using this package, you can new an issue or email me at changchun_he@foxmail.com. You can also visit the `online version`_ 26 | 27 | .. _online version: http://sagar.compphys.cn/sagar 28 | -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | codecov: 2 | token: 79d92264-f12a-443d-b842-caa414b32f55 3 | fixes: 4 | - "pyvaspflow/test/::test/" 5 | -------------------------------------------------------------------------------- /config.ini: -------------------------------------------------------------------------------- 1 | [RUN_VASP] 2 | prepend = module load vasp/5.4.4-impi-mkl 3 | exec = mpirun -n ${SLURM_NPROCS} vasp_std 4 | append = exit 5 | 6 | [POTCAR_PATH] 7 | paw_pbe = /opt/ohpc/pub/apps/vasp/pps/paw_PBE 8 | paw_lda = /opt/ohpc/pub/apps/vasp/pps/paw_LDA 9 | paw_pw91 = /opt/ohpc/pub/apps/vasp/pps/paw_PW91 10 | uspp_lda = /opt/ohpc/pub/apps/vasp/pps/USPP_LDA 11 | uspp_pw91 = /opt/ohpc/pub/apps/vasp/pps/USPP_PW91 12 | default_type = paw_pbe 13 | 14 | [Task_Schedule] 15 | default_node_name = short_q 16 | default_cpu_num = 24 17 | default_schedule = SLURM 18 | 19 | [SLURM] 20 | submission = sbatch ./job.sh 21 | job_queue = squeue 22 | node_state = sinfo 23 | 24 | [LSF] 25 | submission = bsub < ./job.sh 26 | job_queue = bjobs 27 | node_state = bhost 28 | -------------------------------------------------------------------------------- /docs/.nojekyll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChangChunHe/pyvaspflow/5976630a3b5cd05f634c5bc0146eafaff429c4a7/docs/.nojekyll -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = -D language='zh_CN' 6 | SPHINXBUILD = sphinx-build 7 | SOURCEDIR = source 8 | BUILDDIR = build 9 | 10 | # Put it first so that "make" without argument is like "make help". 11 | help: 12 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 13 | 14 | .PHONY: help Makefile 15 | 16 | .PHONY: xelatexpdf 17 | xelatexpdf: 18 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 19 | @echo "Running LaTeX files through xelatex..." 20 | $(MAKE) PDFLATEX=xelatex -C $(BUILDDIR)/latex all-pdf 21 | @echo "xelatex finished; the PDF files are in $(BUILDDIR)/latex." 22 | # Catch-all target: route all unknown targets to Sphinx using the new 23 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 24 | %: Makefile 25 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 26 | -------------------------------------------------------------------------------- /docs/builddoc.sh: -------------------------------------------------------------------------------- 1 | sphinx-apidoc -o ./doc ../pyvaspflow 2 | make html 3 | cp -a build/html/. . 4 | rm -rf build 5 | -------------------------------------------------------------------------------- /docs/source/conf.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Configuration file for the Sphinx documentation builder. 4 | # 5 | # This file does only contain a selection of the most common options. For a 6 | # full list see the documentation: 7 | # http://www.sphinx-doc.org/en/master/config 8 | 9 | # -- Path setup -------------------------------------------------------------- 10 | 11 | # If extensions (or modules to document with autodoc) are in another directory, 12 | # add these directories to sys.path here. If the directory is relative to the 13 | # documentation root, use os.path.abspath to make it absolute, like shown here. 14 | # 15 | import os 16 | import sys 17 | sys.path.insert(0, os.path.abspath('../..')) 18 | 19 | autodoc_mock_imports = ['spglib', 'ase'] 20 | 21 | # -- Project information ----------------------------------------------------- 22 | 23 | project = 'pyvaspflowdoc' 24 | copyright = '2019, ChangChun He' 25 | author = 'ChangChun He' 26 | 27 | # The short X.Y version 28 | version = '0.0.1' 29 | # The full version, including alpha/beta/rc tags 30 | release = '0.1.0' 31 | 32 | 33 | # -- General configuration --------------------------------------------------- 34 | 35 | # If your documentation needs a minimal Sphinx version, state it here. 36 | # 37 | # needs_sphinx = '1.0' 38 | 39 | # Add any Sphinx extension module names here, as strings. They can be 40 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom 41 | # ones. 42 | extensions = [ 43 | 'sphinx.ext.autodoc', 44 | 'sphinx.ext.todo', 45 | 'sphinx.ext.mathjax', 46 | 'sphinx.ext.viewcode', 47 | 'sphinx.ext.githubpages', 48 | ] 49 | 50 | # Add any paths that contain templates here, relative to this directory. 51 | templates_path = ['_templates'] 52 | 53 | # The suffix(es) of source filenames. 54 | # You can specify multiple suffix as a list of string: 55 | # 56 | # source_suffix = ['.rst', '.md'] 57 | source_suffix = '.rst' 58 | 59 | # The master toctree document. 60 | master_doc = 'index' 61 | 62 | # The language for content autogenerated by Sphinx. Refer to documentation 63 | # for a list of supported languages. 64 | # 65 | # This is also used if you do content translation via gettext catalogs. 66 | # Usually you set "language" from the command line for these cases. 67 | language = None 68 | 69 | # List of patterns, relative to source directory, that match files and 70 | # directories to ignore when looking for source files. 71 | # This pattern also affects html_static_path and html_extra_path . 72 | exclude_patterns = [] 73 | 74 | # The name of the Pygments (syntax highlighting) style to use. 75 | pygments_style = 'sphinx' 76 | 77 | 78 | # -- Options for HTML output ------------------------------------------------- 79 | 80 | # The theme to use for HTML and HTML Help pages. See the documentation for 81 | # a list of builtin themes. 82 | # 83 | html_theme = 'bizstyle' 84 | 85 | # Theme options are theme-specific and customize the look and feel of a theme 86 | # further. For a list of options available for each theme, see the 87 | # documentation. 88 | # 89 | # html_theme_options = {} 90 | 91 | # Add any paths that contain custom static files (such as style sheets) here, 92 | # relative to this directory. They are copied after the builtin static files, 93 | # so a file named "default.css" will overwrite the builtin "default.css". 94 | html_static_path = ['_static'] 95 | 96 | # Custom sidebar templates, must be a dictionary that maps document names 97 | # to template names. 98 | # 99 | # The default sidebars (for documents that don't match any pattern) are 100 | # defined by theme itself. Builtin themes are using these templates by 101 | # default: ``['localtoc.html', 'relations.html', 'sourcelink.html', 102 | # 'searchbox.html']``. 103 | # 104 | # html_sidebars = {} 105 | 106 | 107 | # -- Options for HTMLHelp output --------------------------------------------- 108 | 109 | # Output file base name for HTML help builder. 110 | htmlhelp_basename = 'pyvaspflowdoc' 111 | 112 | 113 | # -- Options for LaTeX output ------------------------------------------------ 114 | 115 | latex_elements = { 116 | # The paper size ('letterpaper' or 'a4paper'). 117 | # 118 | # 'papersize': 'letterpaper', 119 | 120 | # The font size ('10pt', '11pt' or '12pt'). 121 | # 122 | # 'pointsize': '10pt', 123 | 124 | # Additional stuff for the LaTeX preamble. 125 | # 126 | # 'preamble': '', 127 | 128 | # Latex figure (float) alignment 129 | # 130 | # 'figure_align': 'htbp', 131 | } 132 | 133 | # Grouping the document tree into LaTeX files. List of tuples 134 | # (source start file, target name, title, 135 | # author, documentclass [howto, manual, or own class]). 136 | latex_documents = [ 137 | (master_doc, 'pyvaspflow.tex', 'pyvaspflow Documentation', 138 | 'ChangChun He', 'manual'), 139 | ] 140 | 141 | 142 | # -- Options for manual page output ------------------------------------------ 143 | 144 | # One entry per manual page. List of tuples 145 | # (source start file, name, description, authors, manual section). 146 | man_pages = [ 147 | (master_doc, 'pyvaspflow', 'pyvaspflow Documentation', 148 | [author], 1) 149 | ] 150 | 151 | 152 | # -- Options for Texinfo output ---------------------------------------------- 153 | 154 | # Grouping the document tree into Texinfo files. List of tuples 155 | # (source start file, target name, title, author, 156 | # dir menu entry, description, category) 157 | texinfo_documents = [ 158 | (master_doc, 'pyvaspflow', 'pyvaspflow Documentation', 159 | author, 'pyvaspflow', 'One line description of project.', 160 | 'Miscellaneous'), 161 | ] 162 | 163 | 164 | # -- Extension configuration ------------------------------------------------- 165 | 166 | # -- Options for todo extension ---------------------------------------------- 167 | 168 | # If true, `todo` and `todoList` produce output, else they produce nothing. 169 | todo_include_todos = True 170 | -------------------------------------------------------------------------------- /docs/source/example.rst: -------------------------------------------------------------------------------- 1 | ============ 2 | 具体的例子 3 | ============ 4 | 5 | .. attention:: 6 | 7 | | 如果你交一份比较长的代码, 可能其中会有错误, 所以强烈建议你设置执行shell文件,遇到错误即推出 8 | | 你可以在shell文件中加入 `set -e` , 或者 ``bash -e shell.sh`` 来运行脚本 9 | | 以免脚本错误以后还继续运行造成不必要的麻烦. 10 | 11 | 12 | 13 | 计算能带, 态密度 14 | =============== 15 | 下面是计算能带的例子, 相信如果你读完前面的文档应该是可以看得懂的:: 16 | 17 | #!/bin/bash 18 | # make sure you have install pyvasp in your current environment 19 | # make sure current directory has POSCAR 20 | 21 | pyvasp prep_single_vasp POSCAR -a ISIF=3,job_name=stru_relax 22 | pyvasp run_single_vasp stru_relax 23 | pyvasp prep_single_vasp stru_relax/CONTCAR -a job_name=scf,NSW=0,LCHARG=True 24 | pyvasp run_single_vasp scf 25 | pyvasp prep_single_vasp scf/CONTCAR -a style=band,NSW=0,job_name=band,ICHARG=11 26 | cp scf/CHG* band/ 27 | pyvasp run_single_vasp band 28 | 29 | 计算态密度的例子:: 30 | 31 | #!/bin/bash 32 | # make sure you have install pyvasp in your current environment 33 | # make sure current directory has POSCAR 34 | 35 | pyvasp prep_single_vasp POSCAR -a ISIF=3,job_name=stru_relax 36 | pyvasp run_single_vasp stru_relax 37 | pyvasp prep_single_vasp stru_relax/CONTCAR -a kppa=4000,job_name=scf,NSW=0,LCHARG=True 38 | pyvasp run_single_vasp scf 39 | pyvasp prep_single_vasp scf/CONTCAR -a kppa=8000,ISMEAR=-5,job_name=dos,NSW=0,LORBIT=11 40 | cp scf/CHG* dos/ 41 | pyvasp run_single_vasp dos 42 | 43 | 这两个例子可以在源文件中找到: `band`_ , `dos`_ . 44 | 45 | .. _band: https://github.com/ChangChunHe/pyvaspflow/blob/master/pyvaspflow/examples/common_calculations/band.sh 46 | .. _dos: https://github.com/ChangChunHe/pyvaspflow/blob/master/pyvaspflow/examples/common_calculations/dos.sh 47 | 48 | 49 | .. note:: 例子:: 50 | 51 | $ bash band.sh 1>std.out 2>err.out & # for Linux user 52 | $ nohup bash dos.sh 1>std.out 2>err.out& # for Windows user, 1后面重定向标准输出, 2后面重定向错误输出. 53 | 54 | 55 | 计算基态相图 56 | ============ 57 | 这一小节实际上是说例如$A_xB_{1-x}$合金, 我们可以给出指定胞的各种不重复结构, 然后计算能量, 最后可以给出一个横轴的浓度$x$的基态相图. 58 | 59 | pyvasp get_grd_state:: 60 | 61 | $ $ pyvasp get_grd_state --help 62 | $ Usage: pyvasp get_grd_state [OPTIONS] 63 | $ 64 | $ pyvasp get_grd_state task 100 # return the number of ground state 65 | 66 | 67 | 68 | 69 | 70 | 计算缺陷形成能 71 | ============== 72 | 73 | 1.1 基础知识: 74 | --------- 75 | 76 | .. image:: image1.jpg 77 | 78 | *图片引用于:Goyal A , Gorai P , Peng H , et al. A computational framework for automation of point defect calculations[J]. Computational Materials Science, 2017, 130:1-9.* 79 | 80 | 由上图可知,缺陷形成能的计算一共可以分为四个部分,即 81 | 82 | ①带缺陷、不带缺陷结构的总能的计算 (Defect and Host Supercell) 83 | 84 | ②化学势的计算 (chemical potentials from phase stability) 85 | 86 | ③电子化学势即费米能的取值 (Electro chemical potential) 87 | 88 | ④缺陷形成能的修正计算 (Finite size corrections) 89 | 90 | 1.2 公式中各个部分的简单讲解 91 | --------- 92 | 93 | 1.2.1 带缺陷、不带缺陷结构的总能的计算 (Defect and Host Supercell) 94 | >>>>>>>>> 95 | 96 | .. image:: image2.png 97 | 98 | 通过以上流程便可以将超胞能量EH和缺陷能量ED,q求出。值得注意的是在不同的带电情况下可以求出不同的缺陷形成能(比如带-1、0、+1的缺陷能量,即ED,-1 、ED,0 、ED,1) 99 | 100 | 101 | 1.2.2 化学势的计算 (chemical potentials from phase stability) 102 | >>>>>>>>> 103 | 104 | .. image:: image3.png 105 | 106 | 计算不同的环境下(如富氧,贫氧环境下)的化学势。如上图所示,A、B两点为贫氧环境下各个元素的化学势(具体数值可以由程序得出),而C、D两点则是富氧环境下各个元素的化学势。 107 | 108 | 1.2.3 电子化学势即费米能的取值 (Electro chemical potential) 109 | >>>>>>>>> 110 | 111 | 电子化学势一般选取导带、价带两点的数值,并由此确定一直线,即分别取Ef = Ecbm和Ef = Evbm两点。 112 | 113 | 1.2.4 缺陷形成能的修正计算 (Finite size corrections) 114 | >>>>>>>>> 115 | 116 | 修正项的详细内容请参考第一张图中的文章。其中,修正项主要有两项组成: 117 | ①线性修正: 118 | 119 | .. image:: image4.png 120 | 121 | ②电荷校正: 122 | 123 | .. image:: image5.png 124 | 125 | 126 | 1.3 具体操作方法(以单空位的Si为例子) 127 | --------- 128 | 129 | 1.3.1 扩包至超胞内至少100个原子 130 | >>>>>>>>> 131 | 132 | 扩胞命令:: 133 | 134 | 135 | pyvasp cell -v 5 5 5 POSCAR 136 | 137 | 1.3.2 获取多个不等价的Si缺陷结构:: 138 | >>>>>>>>> 139 | 140 | 扩胞命令:: 141 | 142 | 143 | pyvasp get_point_defect -i Vac -o Si Si-POSCAR # generate a vacancy 144 | 145 | (注:如果不是空位缺陷而是替换缺陷,则将Vacc换成替换原子,如Ga) 146 | 147 | 1.3.3 一步完成以下多种操作 148 | >>>>>>>>> 149 | 150 | ①获取能量最低的结构 151 | 152 | ②计算该结构下不同电荷的能量 153 | 154 | ③计算各种修正项 155 | 156 | I. 提交以下任务:: 157 | 158 | 159 | #/bin/bash 160 | # relax calculation and scf calculation 161 | pyvasp prep_single_vasp -a ISIF=3,node_name=long_q,job_name=supercell 162 | pyvasp run_single_vasp supercell 163 | cd supercell 164 | pyvasp prep_single_vasp -p CONTCAR -a kppa=4000,job_name=scf,node_name=long_q,NSW=0 165 | pyvasp run_single_vasp scf 166 | cd .. 167 | 168 | 169 | # get ground state of defect configurations 170 | pyvasp get_point_defect -i Vacc -o Si supercell/scf/CONTCAR 171 | 172 | cd Si-Vacc-1-defect 173 | i=0 174 | for f in `ls` 175 | do 176 | mv $f POSCAR$i 177 | let i=i+1 178 | done 179 | pyvasp prep_multi_vasp $((i-1)) -a node_name=long_q 180 | pyvasp run_multi_vasp task $((i-1)) 181 | grd_idx=`pyvasp get_grd_state task $((i-1)) ` 182 | cp task${grd_idx}/CONTCAR grd_poscar 183 | 184 | 185 | ## calculate possible charge states 186 | total_ele=`pyvasp main -a ele-free -w task0` 187 | for q in -2 -1 0 1 2 188 | do 189 | let ele=${total_ele}-$q 190 | pyvasp prep_single_vasp -p grd_poscar -a NELECT=$ele,job_name=charge_state_$q,node_name=long_q 191 | pyvasp run_single_vasp charge_state_$q 192 | cd charge_state_$q 193 | pyvasp prep_single_vasp -p CONTCAR -a NELECT=$ele,job_name=scf,node_name=long_q,NSW=0 194 | pyvasp run_single_vasp scf 195 | cd .. 196 | done 197 | 198 | cd .. 199 | 200 | ## calculate image correlation 201 | sed -n '1,5p' supercell/scf/POSCAR >poscar_img 202 | echo H >> poscar_img 203 | echo 1 >> poscar_img 204 | echo direct >>poscar_img 205 | echo "0.5 0.5 0.5 " >>poscar_img 206 | if [ ! -d image_corr ] 207 | then 208 | mkdir image_corr 209 | fi 210 | pyvasp prep_single_vasp -p poscar_img -a ISIF=2,job_name=image_corr,node_name=long_q 211 | rm poscar_img 212 | pyvasp run_single_vasp image_corr 213 | 214 | 215 | II. 计算完成后可以得到以下目录结构 (重要) 216 | 217 | .. image:: image6.png 218 | 219 | 1.3.4 计算最终的缺陷形成能 220 | >>>>>>>>> 221 | 222 | I. 计算前必须在./Si的目录文件下提供defect-incar文件 223 | 224 | 文件内容:: 225 | 226 | 227 | epsilon=13.36 #介电常数 228 | mu_Si = -5.41 #化学势 229 | 230 | II. 计算缺陷形成能:: 231 | 232 | 233 | pyvasp get_def_form_energy --help 234 | Usage: pyvasp get_def_form_energy [OPTIONS] 235 | pyvasp get_def_form_energy Si Si/Si-Vacc-defect 236 | 237 | 注:./Si 与Si/Si-Vacc-defect为目录结构,可参考上一步操作最后生成的目录结构。 238 | 239 | 如果该计算有多种缺陷,比如同时有空位和Ga替换Si,可用以下命令:: 240 | 241 | 242 | pyvasp get_def_form_energy Si Si/Si-Vacc-defect Si/Si-Ga-defect 243 | 244 | III. 查看结果 245 | 246 | 在运行完上述命令后会生成defect_formation_energy.png和defect-log.txt 247 | 248 | 249 | .. image:: image7.png 250 | 251 | 252 | .. image:: image8.png 253 | 254 | 1.3.5 化学势的计算 (chemical potentials from phase stability) 255 | >>>>>>>>> 256 | 257 | 对于三组分体系,在不同环境(如贫氧和富氧)下,defect-incar中的化学势是不一样的,因此需要对此进行分析。以ZnGa2O3为例;需要提供chemical-incar文件以生成相图; 258 | 259 | I. 提供chemical-incar 260 | 261 | 文件内容:(以下是该元素或者化合物的总能,可以通过DFT计算获得,也可以通过查询Aflow得到):: 262 | 263 | 264 | Ga=-2.916203375 265 | 266 | Ga8O12=-121.098 267 | 268 | O2=-8.9573588 269 | 270 | Zn=-2.5493 271 | 272 | #Zn8Ga16O32=-328.32564 273 | 274 | ZnO=-10.586057 275 | 276 | II. 运行以下命令:: 277 | 278 | 279 | pyvasp chem_pot -r 0 chemical-incar 280 | 281 | III. 得到目标相图chemical-potential.png以及chemical_log.txt 282 | 283 | 如下: 284 | 285 | .. image:: image9.png 286 | 287 | 以及: 288 | 289 | .. image:: image10.png 290 | -------------------------------------------------------------------------------- /docs/source/execute.rst: -------------------------------------------------------------------------------- 1 | ============ 2 | 运行任务 3 | ============ 4 | 5 | 这里我们提供了两种执行任务的命令, 分别为执行单个任务和多个任务( ``run_single_vasp`` , ``run_multi_vasp`` ). 6 | 7 | ``run_ringle_vasp`` 8 | ====================== 9 | 10 | 这是在你已经准备好了要计算的文件以后才可以运行的, 这个命令的作用在于它可以等待你的vasp计算完成 11 | 之后才会停止运行. 比如你需要在计算完成之后提取某些数据, 如果你直接 ``sbatch job.sh`` , 那么 12 | 这句命令直接就运行结束了, 但是vasp却没有计算完成, 所以你就没法提取数据了, 这个命令的好处在于他会查询你提交的任务号是否 13 | 还在队列中, 如果不在了则说明你已经计算完毕了, 才会继续进行下面的操作, 比如你要进行的提取数据的操作. 14 | 15 | 16 | 例子:: 17 | 18 | $ pyvasp run_ringle_vasp task 19 | 20 | 21 | 最后跟上你要计算的文件夹即可. 但是注意到该命令会跟着你的任务计算同时停止掉, 所以你需要把这个程 22 | 序放到后台执行. 对于Linux用户只需要加末尾加上一个&号即可, 对于 Windows用户需要使用 ``nohup`` 对程序进行后台托管. 23 | 24 | .. note:: 例子:: 25 | 26 | $ nohup pyvasp run_ringle_vasp task 1>std.out 2>err.out& # 1后面重定向标准输出, 2后面重定向错误输出. 27 | 28 | 注意你也可以不写重定向的东西, 直接以&结尾, 但是这个是不建议的. 29 | 30 | 31 | 32 | 33 | ``run_multi_vasp`` 34 | =================== 35 | 36 | 37 | 先贴一下这个命令的帮助:: 38 | 39 | $ pyvasp run_multi_vasp --help 40 | Usage: pyvasp run_multi_vasp [OPTIONS] 41 | 42 | Options: 43 | -s, --start_job_num INTEGER 44 | -p, --par_job_num INTEGER 45 | --help Show this message and exit. 46 | 47 | 48 | 49 | 第一个参数是 ``job_name``, 这个就是你之前生成的文件夹的前缀, 比如之前你生成 50 | 了 task0,task1,task2,...,task20, 那么这里的job_name就应该填入 ``task`` , 51 | 这里的 ``-s`` 是开始的任务号, 比如你可以指定从 ``task4`` 开始计算, ``-s 4`` 即可, 该参数默认为0. ``-p`` 是队列里同时有的最大任务数目. 52 | 默认是4, 具体的意思就是比如你有10个任务, 最开始一次性提交4个任务, 接着如果第一个计算完毕了, 而且二三四都没有计算完毕, 那么第五个任务就会被 53 | 提交上去, 会一直保持任务队列中有4个任务直到所有任务结束为止. 比如:: 54 | 55 | $ pyvasp run_multi_vasp -p 6 -s 5 struc_opt 20 56 | 57 | 比如这个例子就是说从struc_opt5开始计算, 到struc_opt20截止, 同时运行的任务数为6个. 与之前一样, 该程序最好也用后台进行. 58 | 59 | .. note:: 例子:: 60 | 61 | $ nohup pyvasp run_multi_vasp -p 6 -s 5 struc_opt 20 1>std.out 2>err.out& # 1后面重定向标准输出, 2后面重定向错误输出. 62 | 63 | 64 | ``run_multi_vasp_without_job`` 65 | =============================== 66 | 先贴一下这个命令的帮助:: 67 | 68 | $ pyvasp run_multi_vasp --help 69 | Usage: pyvasp run_multi_vasp_without_job [OPTIONS] 70 | 71 | Example: 72 | 73 | pyvasp run_multi_vasp_without_job task 5 --node_name test_q --cpu_num 24 74 | 75 | run multiple vasp task from task0 to task5 through test_q node whith 24 cpu 76 | 77 | pyvasp run_multi_vasp_without_job task 5 --node_name test_q,super_q --cpu_num 24,12 78 | 79 | 80 | 这个命令可以用于, 例如你期望你的任务佔用多個節點, 那麼就不能使用`run_multi_vasp`這個命令了, 81 | 因爲他是直接提交任務文件夾裏面`job.sh`, 這裏可以自行設置節點和cpu數目. 这里需要指定的是节 82 | 点名 ``node_nam`` 和 cpu数量 ``cpu_num``, 节点数不建议修改, 83 | 就按照默认的1, 这样就可以使用 ``par_job_num``这个参数同时提交多个任务了. 你也可以指定多个 84 | 节点名, 相对应的也需要指定多个 ``cpu_num`` , 就可以在这些就节点上优先提交空闲的, 写在前面的节点. 85 | 86 | 87 | 88 | ``run_multi_vasp_from_file`` 89 | ============================== 90 | 与准备文件的命令类似, 运行任务也有类似from_file的命令, 使用说明:: 91 | 92 | $ pyvasp run_multi_vasp_from_file -h 93 | $ Usage: pyvasp run_multi_vasp_from_file [OPTIONS] 94 | $ pyvasp run_multi_vasp task job_list_file -p 6 & 95 | 96 | 97 | ``run_multi_vasp_without_job_from_file`` 98 | ============================================ 99 | 类似地, 运行任务也有类似without_job 类型的命令, 使用说明:: 100 | 101 | $ pyvasp run_multi_vasp_without_job_from_file -h 102 | $ Usage: pyvasp run_multi_vasp_without_job_from_file [OPTIONS] 103 | $ pyvasp run_multi_vasp_without_job_from_file task job_list_file --node_name test_q --cpu_num 24 104 | $ pyvasp run_multi_vasp_without_job_from_file task job_list_file --node_name test_q --cpu_num 24 105 | 106 | 107 | 108 | 109 | ``run_multi_vasp_from_shell`` 110 | ============================== 111 | 因爲上面的任務都是單步的, 也就是你只能計算一次, 如果你希望計算能帶, 那麼你需要計算三次:1. 结构 112 | 优化, 2. 结构自恰, 3.计算线性K点的能带, 这样就不能使用上述 ``prep_multi_vasp`` 和 ``run_multi_vasp`` 等等来 113 | 系统计算多个任务了.你只能先计算完所有的结构优化, 然后把所有结构的 `CONTCAR` 拷贝出来再计算自恰等等. 这个是不太 114 | 恰当的, 所以就有了这个 ``run_multi_vasp_from_shell`` 的命令, 使用说明:: 115 | 116 | $ pyvasp run_multi_vasp_from_shell -h 117 | $ Usage: pyvasp run_multi_vasp_from_shell [OPTIONS] 118 | 119 | 这里需要提供一个 `shell` 文件,例如我们计算能带的时候,可以使用如下的 `band.sh` 文件:: 120 | 121 | #!/bin/bash 122 | # make sure you have install pyvasp in your current environment 123 | # make sure current directory has POSCAR 124 | 125 | module load pyvaspflow 126 | pyvasp prep_single_vasp POSCAR -a ISIF=3,job_name=stru_relax 127 | pyvasp run_single_vasp stru_relax 128 | pyvasp prep_single_vasp stru_relax/CONTCAR -a job_name=scf,NSW=0,LCHARG=True 129 | pyvasp run_single_vasp scf 130 | pyvasp prep_single_vasp scf/CONTCAR -a style=band,NSW=0,job_name=band,ICHARG=11 131 | cp scf/CHG* band/ 132 | pyvasp run_single_vasp band 133 | 134 | 假设你的文件夹下面现在有10个POSCAR, 按照流水号命名,POSCAR0-POSCAR9, 还有如上的一个 `band.sh` 文件, 那 135 | 么你就可以使用命令:: 136 | 137 | $ pyvasp run_multi_vasp_from_shell band.sh 9 -w job -p 5 138 | 139 | 这个命令会自己新建文件夹,按照job前缀的流水号命名, 然后将POSCAR$idx copy到该文件夹里面 140 | 为POSCAR, 然后运行这个 `band.sh` . 参数 ``-p`` 与上述的含义是一样的, 只是保持同时有5个 `band.sh` 文件在运行. 141 | 这里可以注意到,在 `band.sh` 里面是只能写 `run_single_vasp` 这样的命令, 那么就不能占据多个节点计算了, 所以 142 | 就有了这个 `run_single_vasp_without_job` 这个命令. 143 | 144 | 145 | 146 | ``run_single_vasp_without_job`` 147 | ================================ 148 | 类似与 ``run_multi_vasp_without_job`` 这个命令, 你可以指定用哪些节点,一旦有空闲的节点就会把任务提交上去, 举个例子:: 149 | 150 | $ pyvasp run_single_vasp_without_job stru_relax -nname short_q,long_q,test_q -cnum 24,24,24 151 | 152 | 它会先把任务交到 `short_q` 上, 然后监测到如果任务一直在挂起的状态而 `long_q` 或者 `test_q` 这两个 153 | 节点有空闲,那它会把交到 `short_q` 的任务取消掉,重新将任务提交到 `long_q` 或者 `test_q` 上, 这个命令 154 | 刚好可以跟 ``run_multi_vasp_from_shell`` 配合使用. 例如可以写一个如下的 `spin.sh` 的shell脚本:: 155 | 156 | module load pyvaspflow 157 | pyvasp prep_single_vasp POSCAR -a NSW=100,kpts=1,1,1,job_name=nospin 158 | pyvasp run_single_vasp_without_job nospin -nname inter_q,test_q,short_q,long_q,super_q -cnum 24,24,24,24,12 159 | 160 | pyvasp prep_single_vasp nospin/CONTCAR -a NSW=1,kpts=1,1,1,job_name=spin,ISPIN=2,NUPDOWN=2 161 | pyvasp run_single_vasp_without_job spin -nname inter_q,test_q,short_q,long_q,super_q -cnum 24,24,24,24,12 162 | 163 | 再配合使用命令:: 164 | 165 | $ nohup pyvasp run_multi_vasp_from_shell spin.sh 4182 job -p 5 1>std 2>err & 166 | 167 | 那么就可以同时提交5个 `spin.sh` 的任务, 而且每个任务都可以按照节点空闲情况进行分配任务. 168 | 169 | 170 | logging 171 | =============== 172 | 日志系统 173 | -------------------------------------------------------------------------------- /docs/source/fetch.rst: -------------------------------------------------------------------------------- 1 | ============ 2 | 处理输出的vasp数据 3 | ============ 4 | 5 | 6 | 1 ``pyvasp`` 7 | =============== 8 | 这个命令是的到一些基本的信息, 例如能量, 带隙, 费米能级, Ewald能, 电子数等等. 例子:: 9 | 10 | $ pyvasp gap -w . # this can read the gap and vbm, cbm 11 | $ pyvasp fermi # this can read the fermi energy 12 | $ pyvasp energy # this can read the total energy 13 | $ pyvasp electron_number # this can read the electrons in your OUTCAR 14 | $ pyvasp electron_defect_free . # this can get electrons number of the defect-free system 15 | $ pyvasp image # this can get Ewald energy of your system, 16 | $ # using `pyvasp ewald image_corr` can also get the same result. 17 | $ pyvasp cpu # get total run time 18 | 19 | ``-w`` 指定计算的文件夹, 默认是当前文件夹. 这里还有一个是的到electrostatic能的命令是:: 20 | 21 | $ pyvasp electrostatic 23 # 得到 23 号原子的静电势能 22 | 23 | 24 | 2 ``pyvasp symmetry`` 25 | ======================= 26 | 27 | 得到结构对称性的一些信息:: 28 | 29 | $ pyvasp symmetry spacegroup POSCAR # get space group 30 | $ pyvasp symmetry equivalent POSCAR # get equivalent atoms 31 | $ pyvasp symmetry primitive POSCAR 32 | 33 | 34 | 3 ``pyvasp diff_pos`` 35 | ======================= 36 | 37 | 用于比较两个POSCAR是否是一个结构, 这里需要保证两个POSCAR是同一个晶胞, 并且给出未掺杂的结构的POSCAR. 38 | 具体而言即为, 例如有一个原始的金刚石结构的Si的POSCAR, 然后将其中一个Si替换成C, 然后你有两个替换不同位置的Si的POSCAR1,POSCAR2 39 | 那么你就可以比较POSCAR1和POSCAR2是否是等价的:: 40 | 41 | $ pyvasp diff_pos --help 42 | Usage: pyvasp diff_pos [OPTIONS] 43 | 44 | $ pyvasp diff_pos POSCAR POSCAR1 POSCAR2 45 | 46 | 4 ``pyvasp get_grd_state`` 47 | =========================== 48 | 49 | 用于得到一系列结构的能量最低的结构的序号. 例如你用 ``pyvasp get_point_defect`` 生成了许 50 | 多结构, 然后计算完能量就可以使用该命令得到能量最低的结构的序号:: 51 | 52 | $ pyvasp get_grd_state -h 53 | Usage: pyvasp get_grd_state [OPTIONS] 54 | 55 | Exmaple: 56 | 57 | pyvasp get_grd_state -s 2 task 100 58 | 59 | Options: 60 | -s, --start_job_num INTEGER 61 | -h, --help Show this message and exit. 62 | -------------------------------------------------------------------------------- /docs/source/gen_str.rst: -------------------------------------------------------------------------------- 1 | ============ 2 | 生成结构 3 | ============ 4 | 5 | 6 | 沿着基矢方向扩胞 7 | ============ 8 | 9 | 将晶胞扩到指定的大小, ``-v`` 下面即为扩成2*2*2的超胞 :: 10 | 11 | $ pyvasp extend_spec_direc -v 2 2 2 POSCAR 12 | 13 | 14 | 指定体积扩胞 15 | ============ 16 | 17 | 将晶胞扩到指定的体积, ``-v`` 指定扩的体积上下限 :: 18 | 19 | $ pyvasp extend_spec_vol -v 2 4 POSCAR 20 | 21 | 注意这里提供的POSCAR必须为原胞, 如果不是原胞可以使用 ``pyvasp symmetry primitive_cell POSCAR`` 得到原胞. 22 | 如果你只想生成指定体积的胞, 只需要上下限想等即可. 23 | 24 | 25 | 生成替换原子的结构 26 | ================= 27 | 28 | 该命令即为替换原子生成结构, ``-i`` 代表进去的原子, ``-o`` 代表移除的原子. 29 | 30 | 31 | 例子:: 32 | 33 | $ pyvasp get_point_defect -i Vac -o Si Si-POSCAR # generate a vacancy 34 | $ pyvasp get_point_defect -i Ga -o In In2O3-POSCAR # genrate a Ga defect 35 | $ pyvasp get_point_defect -i Fe,Cu -o In -n 2,3 In2O3-POSCAR # genrate a 2Fe3Cu defect 36 | 37 | 38 | 39 | 40 | 生成四面体中心位置的结构 41 | ======================= 42 | 43 | 该命令会生成三种四面体中心的位置, ``-d`` 参数设置两个缺陷的最近的距离不可以小于的数值, 默认设置是1.5. 44 | 45 | 46 | 例子:: 47 | 48 | $ pyvasp get_tetrahedral -i H -d 1 YFe2-POSCAR 49 | 50 | 该命令有一个 ``-u`` (``--isunique``) 的参数, 含义是四面体中心位是否是包含等价的还是都是非等价的, 默认是包含等价的, 即为生成所有 51 | 可能的位置, `-u False`, 你可以修改成 `True` 就会生成各种不等价的结构, 每个结构只包含一个四面体中心位. 52 | -------------------------------------------------------------------------------- /docs/source/image1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChangChunHe/pyvaspflow/5976630a3b5cd05f634c5bc0146eafaff429c4a7/docs/source/image1.jpg -------------------------------------------------------------------------------- /docs/source/image10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChangChunHe/pyvaspflow/5976630a3b5cd05f634c5bc0146eafaff429c4a7/docs/source/image10.png -------------------------------------------------------------------------------- /docs/source/image2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChangChunHe/pyvaspflow/5976630a3b5cd05f634c5bc0146eafaff429c4a7/docs/source/image2.png -------------------------------------------------------------------------------- /docs/source/image3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChangChunHe/pyvaspflow/5976630a3b5cd05f634c5bc0146eafaff429c4a7/docs/source/image3.png -------------------------------------------------------------------------------- /docs/source/image4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChangChunHe/pyvaspflow/5976630a3b5cd05f634c5bc0146eafaff429c4a7/docs/source/image4.png -------------------------------------------------------------------------------- /docs/source/image5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChangChunHe/pyvaspflow/5976630a3b5cd05f634c5bc0146eafaff429c4a7/docs/source/image5.png -------------------------------------------------------------------------------- /docs/source/image6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChangChunHe/pyvaspflow/5976630a3b5cd05f634c5bc0146eafaff429c4a7/docs/source/image6.png -------------------------------------------------------------------------------- /docs/source/image7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChangChunHe/pyvaspflow/5976630a3b5cd05f634c5bc0146eafaff429c4a7/docs/source/image7.png -------------------------------------------------------------------------------- /docs/source/image8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChangChunHe/pyvaspflow/5976630a3b5cd05f634c5bc0146eafaff429c4a7/docs/source/image8.png -------------------------------------------------------------------------------- /docs/source/image9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChangChunHe/pyvaspflow/5976630a3b5cd05f634c5bc0146eafaff429c4a7/docs/source/image9.png -------------------------------------------------------------------------------- /docs/source/incar.rst: -------------------------------------------------------------------------------- 1 | ============ 2 | INCAR 文件 3 | ============ 4 | 5 | INCAR 参数的设置也是在 ``-a`` 中, 只需要指定INCAR的参数就可以自动写入到INCAR文件. 6 | 7 | 例如:: 8 | 9 | 10 | $ pyvasp prep_single_vasp POSCAR -a NSW=143.2,LCHARG=True,EDIFF=1e-4,NELECT=145 11 | 12 | 13 | 我们可以自动将输入的参数格式化到正确的格式, 例如 ``NSW=143.2`` 可以转化成 ``NSW=143`` . 14 | 15 | 16 | 我们也提供了只生成INCAR文件的命令, 使用方式都是一样的. 17 | 18 | 例如:: 19 | 20 | $ pyvasp incar -h 21 | Usage: pyvasp incar [OPTIONS] 22 | 23 | Example: 24 | 25 | pyvasp incar -f INCAR -a NSW=100,EDIFF=1e-6 26 | 27 | For more help you can refer to 28 | 29 | https://pyvaspflow.readthedocs.io/zh_CN/latest/incar.html 30 | 31 | Options: 32 | -a, --attribute TEXT 33 | -f, --incar_file TEXT 34 | -h, --help Show this message and exit. 35 | 36 | 37 | 一个例子:: 38 | 39 | # generate a new INCAR 40 | $ pyvasp incar -a NSW=143.2,LCHARG=True,EDIFF=1e-4,NELECT=145 41 | 42 | # generate a INCAR based on an old INCAR file 43 | $ pyvasp incar -f INCAR -a NSW=100,EDIFF=1e-6 44 | 45 | 下面这个例子是指可以基于已有的INCAR文件生成一个新的INCAR, ``-a`` 后面的参数会更新到INCAR文件中。 46 | -------------------------------------------------------------------------------- /docs/source/index.rst: -------------------------------------------------------------------------------- 1 | .. pyvaspflow documentation master file, created by 2 | sphinx-quickstart on Sat May 25 19:47:24 2019. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | Welcome to pyvaspflow's documentation! 7 | ======================================================== 8 | 9 | pyvaspflow source code address: https://github.com/ChangChunHe/pyvaspflow 10 | 11 | .. toctree:: 12 | :maxdepth: 2 13 | :caption: Contents: 14 | 15 | installation 16 | gen_str 17 | prepare 18 | incar 19 | kpoints 20 | potcar 21 | job 22 | execute 23 | kill 24 | test_para 25 | fetch 26 | example 27 | 28 | 29 | Indices and tables 30 | ================== 31 | 32 | * :ref:`genindex` 33 | * :ref:`modindex` 34 | * :ref:`search` 35 | -------------------------------------------------------------------------------- /docs/source/installation.rst: -------------------------------------------------------------------------------- 1 | .. _Installation: 2 | 3 | ============= 4 | 快速安装 5 | ============= 6 | 7 | 你可以通过源码进行安装, 这里我们建议安装在服务器上. 8 | 9 | .. code-block:: python 10 | 11 | pip install -e . # -e for developer 12 | 13 | 14 | 下面是配置文件, 用于指定赝势的位置和`job.sh`文件的书写. 15 | 注意这里为了配置两种不同的任务管理系统, SLURM 和 LSF, 我们设置了 ``default_schedule`` 参数来指定默认的管理系统, 注意只能是 ``LSF`` 或者 ``SLURM``. 16 | 17 | .. code-block:: json 18 | 19 | [RUN_VASP] 20 | prepend = module load vasp/5.4.4-impi-mkl 21 | exec = mpirun -n ${SLURM_NPROCS} vasp_std 22 | append = exit 23 | 24 | [POTCAR_PATH] 25 | paw_pbe = /opt/ohpc/pub/apps/vasp/pps/paw_PBE 26 | paw_lda = /opt/ohpc/pub/apps/vasp/pps/paw_LDA 27 | paw_pw91 = /opt/ohpc/pub/apps/vasp/pps/paw_PW91 28 | uspp_lda = /opt/ohpc/pub/apps/vasp/pps/USPP_LDA 29 | uspp_pw91 = /opt/ohpc/pub/apps/vasp/pps/USPP_PW91 30 | default_type = paw_pbe 31 | 32 | [Task_Schedule] 33 | default_node_name = short_q 34 | default_cpu_num = 24 35 | default_schedule = SLURM 36 | 37 | [SLURM] 38 | submission = sbatch ./job.sh 39 | job_queue = squeue 40 | node_state = sinfo 41 | 42 | [LSF] 43 | submission = bsub < ./job.sh 44 | job_queue = bjobs 45 | node_state = bhost 46 | 47 | 48 | 49 | potcar_path 50 | =============== 51 | 配置文件需要指定赝势的文件位置以及对应的泛函的位置, 注意到这里的"paw_PBE,paw_LDA"等也即为在命令行中生成赝势所需要指定的"functional". 52 | 53 | :code:`pyvasp prep_single_vasp POSCAR -a functional=paw_pbe` 54 | 55 | 这里指定的"paw_PBE"也即为说明程序会自动向“/opt/ohpc/pub/apps/vasp/pps/paw_PBE”中寻找对应的赝势文件. 56 | 57 | job 58 | =============== 59 | job所对应的部分是生成 ``job.sh`` 文件, 这里 `prepend` 所对应的是运行程序前需要 60 | 先加载的模块, `exec` 对应的是执行的代码, `append` 对应程序执行完以后需要执行的代码. 61 | 62 | 如果你需要运行gamma版本, 你可以将 ``vasp_std`` 改成 ``vasp_gam`` . 63 | 64 | 该文件请放置在$HOME/.config/pyvaspflow/conf.json, 当然你可以可以放在当前文件夹, 我们会优先读取当前文件夹是否有配置文件, 如果没有才会到$HOME/.config/pyvaspflow/conf.json下面找. 所以你可以在$HOME/.config/pyvaspflow/conf.json下面设置一个常用的配置文件, 对与特殊的需要可以拷贝一份放在当前文件夹作为特殊用处. 65 | 66 | 例如你一般会使用 ``vasp_std`` , 然后只是偶尔需要计算分子的能量, 此时需要使用gamma版本的vasp, 那么你就可以拷贝一份配置文件在当前文件夹, 并把 ``vasp_std`` 改成 ``vasp_gam`` 即可. 67 | 68 | 69 | 自动补齐命令 70 | =============== 71 | ``pyvasp`` 是支持自动补齐命令的, 例如 ``pyvasp symm`` 按下tab键是可以自动补 72 | 齐成 ``pyvasp symmetry`` 的, 接着按下两次tab键可以 73 | 给出候选项 ``equivalent_atoms primitive_cell space_group`` 这三个子命令, 74 | 你可以接着键入 ``p`` 来补齐命令 ``primitive_cell`` . 但是这个是需要配置的, 需要你在 ``bashrc`` 里面加入:: 75 | 76 | eval "$(_PYVASP_COMPLETE=source pyvasp)" 77 | 78 | 如果你使用 ``zsh`` , 那么需要在你的 ``zshrc`` 就加入:: 79 | 80 | eval "$(_PYVASP_COMPLETE=source_zsh pyvasp)" 81 | 82 | 组内的同学 83 | =============== 84 | 注意到组内的服务器上是以 ``module`` 的方式安装的, 所以如果只是在你的 ``.bashrc`` 里面 85 | 加入这句话是不行的, 因为你还没有load ``pyvaspflow`` 这个包, 所以 ``eval`` 是没有效果的, 86 | 必须得在load你的module以后执行才会有效. 所以对于组内的同学我建议你可 87 | 以在 ``.bashrc`` 里面加入:: 88 | 89 | alias mlpy='module load pyvaspflow;eval "$(_PYVASP_COMPLETE=source pyvasp)"' 90 | 91 | 然后使用命令 ``mlpy`` 即可加载模块 ``pyvaspflow`` 并且激活自动补齐命令. 92 | -------------------------------------------------------------------------------- /docs/source/job.rst: -------------------------------------------------------------------------------- 1 | ============ 2 | job 文件 3 | ============ 4 | 5 | 这里我们生成的 ``job.sh`` 文件是:: 6 | 7 | #!/bin/bash 8 | #SBATCH -J task 9 | #SBATCH -p short_q -N 1 -n 24 10 | 11 | module load vasp/5.4.4-impi-mkl 12 | 13 | mpirun -n ${SLURM_NPROCS} vasp_std 14 | 15 | 你可以通过指定 ``node_name`` , ``node_num`` , ``cpu_num`` and ``job_name`` 在你的 ``job.sh`` 文件中 16 | 这里默认是设置是: node_name=short_q,cpu_num=24,node_num=1,job_name=task 17 | 18 | 举一个例子:: 19 | 20 | $ pyvasp prep_single_vasp POSCAR -a node_name=super_q,cpu_num=12,job_name=task 21 | -------------------------------------------------------------------------------- /docs/source/kill.rst: -------------------------------------------------------------------------------- 1 | ============ 2 | 杀掉任务 3 | ============ 4 | 5 | 这里我们提供了杀掉任务的命令 ``kill`` , 用于杀掉交任务的 ``pyvasp`` , 它可以用于杀掉 ``pyvasp`` 这个进程而且取消掉由它提交 的 任务. 6 | 7 | ``kill`` 8 | ============ 9 | 10 | 首先你需要 使用 ``ps -ef|grep pyvasp`` 得到你的任务进程号. 使用该命令你可以得到类似下面的结果:: 11 | 12 | [hecc@cmp ~]$ ps -ef|grep pyvasp 13 | hecc 66237 56185 19 04:34 ? 01:03:44 /opt/ohpc/pub/apps/python-virtualenv/pyvaspflow/bin/python3.6 /opt/ohpc/pub/apps/python-virtualenv/pyvaspflow/bin/pyvasp run_multi_vasp_without_job task 125 -nname short_q,super_q -cnum 24,12 -p 8 14 | xwq 107772 95242 22 08:49 pts/12 00:16:16 /opt/ohpc/pub/apps/python-virtualenv/pyvaspflow/bin/python3.6 /opt/ohpc/pub/apps/python-virtualenv/pyvaspflow/bin/pyvasp run_multi_vasp_without_job -nnum 1 -nname short_q -cnum 24 -s 1 -p 2 dir-dir-POSCAR4-2H- 3 15 | hecc 108275 121327 0 10:02 pts/14 00:00:00 grep --color=auto pyvasp 16 | xwq 132222 95242 21 08:50 pts/12 00:15:36 /opt/ohpc/pub/apps/python-virtualenv/pyvaspflow/bin/python3.6 /opt/ohpc/pub/apps/python-virtualenv/pyvaspflow/bin/pyvasp run_multi_vasp_without_job -nnum 1 -nname short_q -cnum 24 -s 0 -p 2 dir-dir-POSCAR- 3 17 | 18 | 这里你可以查看最后一列的命令来确定你要 ``kill`` 掉哪个进程, 其进程号就是第二列的数字, 例如你要杀掉第一行的进程, 那么你使用:: 19 | 20 | $ pyvasp kill 66237 21 | 22 | 就可以了. 这里还提供了一个 ``-c`` 的参数用于选择是否取消已经在队列里面的任务, 默认是 ``True``, 你可以选择``False`` 来不选择取消队列中的任务:: 23 | 24 | $ pyvasp kill 66237 -c False 25 | -------------------------------------------------------------------------------- /docs/source/kpoints.rst: -------------------------------------------------------------------------------- 1 | ============ 2 | KPOINTS 文件 3 | ============ 4 | 5 | KPOINTS 参数的设置也是在 ``-a`` 中, 下面介绍几种KPOINTS文件的写法 6 | 7 | 你可以选择 style=auto,gamma,monkhorst,line 来生成不同样式的 KPOINTS. 8 | 9 | 10 | 11 | 1. 默认设置 12 | =============== 13 | 14 | 默认是按照你的结构生成Monkhorst-Pack的格点或者Gamma中心的网格k点, 计算的mesh方法: 15 | Uses a simple approach scaling the number of divisions along each 16 | reciprocal lattice vector proportional to its length. 17 | 18 | .. image:: kpt_eq.png 19 | :alt: alternate text 20 | :align: center 21 | 22 | 关于k点的关键字什么都不写就是用这种方式生成k点, 默认 ``kppa=3000`` :: 23 | 24 | $ pyvasp prep_single_vasp POSCAR 25 | 26 | 27 | 28 | 2. 指定gamma中心和kppa设置k点 29 | ============================== 30 | 31 | 例子:: 32 | 33 | $ pyvasp prep_single_vasp POSCAR -a style=gamma,kppa=5000 34 | 35 | 3. 指定mesh设置k点 36 | =================== 37 | 38 | 例子:: 39 | 40 | $ # gamma center, k-mesh=5*6*7, shift=0.5 0.5 0.5, default shift is 0 0 0 41 | $ pyvasp prep_single_vasp POSCAR -a style=gamma,kpts=5,6,7,shift=0.5,0.5,0.5 42 | 43 | 44 | 45 | $ pyvasp prep_single_vasp POSCAR -a style=monkhorst,kpts=5,6,7 46 | 47 | 4. 指定设置线性的k点 48 | =================== 49 | 50 | 只需要设置 ``style=band`` 或者 ``style=line`` 就可以了, 生成的高对称点是调用 `seekpath`_ 51 | 的, num_kpt是用于指定两个高对称点之间插入的k点的数目, 默认是16个. 52 | 53 | 例子:: 54 | 55 | $ pyvasp prep_single_vasp POSCAR -a style=line,num_kpts=20 56 | 57 | 58 | 59 | 60 | 最后 我们也提供了了一个单独生成 ``KPOINTS`` 的命令接口:: 61 | 62 | 63 | $ pyvasp kpoints -a style=line,num_kpts=20 64 | 65 | .. _seekpath: https://github.com/giovannipizzi/seekpath 66 | -------------------------------------------------------------------------------- /docs/source/kpt_eq.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChangChunHe/pyvaspflow/5976630a3b5cd05f634c5bc0146eafaff429c4a7/docs/source/kpt_eq.png -------------------------------------------------------------------------------- /docs/source/potcar.rst: -------------------------------------------------------------------------------- 1 | ============ 2 | POTCRA 文件 3 | ============ 4 | 5 | 生成POTCAR 参数的设置也是在 ``-a`` 中, 需要指定使用的泛函类型和使用哪一种类型的赝势. 6 | 即 ``functional`` 和 ``sym_potcar_map`` 这两个参数. 举个例子:: 7 | 8 | # this will generate Zr_sv of paw_LDA POTCAR 9 | # for those not specified in `sym_potcar_map` will using the default 10 | # the default is the element itself 11 | 12 | $ pyvasp prep_single_vasp POSCAR -a functional=paw_LDA,sym_potcar_map=Zr_sv 13 | -------------------------------------------------------------------------------- /docs/source/prepare.rst: -------------------------------------------------------------------------------- 1 | ============ 2 | 准备输入文件 3 | ============ 4 | 5 | 这里我们主要提供了两个准备输入文件的命令行接口, 分别是准备单个任务和多个任务的命令, ``prep_single_vasp, prep_multi_vasp``. 下面会主要介绍这两个命令的用法. 使用这两个命令之前都需要你先提供 ``POSCAR`` 文件. 6 | 7 | 8 | 9 | 10 | ``prep_single_vasp`` 11 | ===================== 12 | 首先你可以通过使用 ``help`` 命令来获取帮助:: 13 | 14 | $ pyvasp prep_single_vasp -h 15 | Usage: pyvasp prep_single_vasp [OPTIONS] POSCAR 16 | 17 | Example: 18 | 19 | pyvasp prep_single_vasp POSCAR -a functional=paw_LDA,sym_potcar_map=Zr_sv,NSW=100,style=band 20 | 21 | For more help you can refer to 22 | 23 | https://pyvaspflow.readthedocs.io/zh_CN/latest/prepare.html#prep-single- 24 | vasp 25 | 26 | Options: 27 | -a, --attribute TEXT 28 | -h, --help Show this message and exit. 29 | 30 | 31 | pyvasp prep_single_vasp 有可选参数 ``-a``, ``-a`` 是为了设置一些任务的参数, 例如 ``INCAR, KPOINTS, POTCAR, job.sh`` 中的 32 | 参数设置, 后面会仔细介绍 ``-a`` 这个参数的用法. 33 | 34 | 这里举一个例子:: 35 | 36 | $ pyvasp prep_single_vasp POSCAR -a NSW=100,job_name=task,style=band 37 | 38 | 这里的 ``NSW=100`` 是设置 ``INCAR`` 的参数, ``style=band`` 是设置线性的k点用于计算能带.这 39 | 里的 ``job_name`` 是指会生成一个为 ``task`` 的文件夹, 所生成的文件都在这个文件夹里面. 40 | 41 | 42 | 43 | ``prep_multi_vasp`` 44 | ===================== 45 | 运行这个命令之前你需要先准备多个 ``POSCAR`` 文件, 这里文件需要按照流水号命名, 不然程序无法识别出来. 46 | 使用说明:: 47 | 48 | $ pyvasp prep_multi_vasp --help 49 | Usage: pyvasp prep_multi_vasp [OPTIONS] 50 | 51 | 这里的参数和上面的几乎是一样的, 只是最后需要指定最后一个任务的序号.例子:: 52 | 53 | $ pyvasp prep_multi_vasp -s 2 -a node_name=super_q,cpu_num=12,job_name=struc_opt 20 54 | 55 | 这里的 ``-s`` 是指从 ``POSCAR2`` 开始生成任务文件, 最后的20是是指一直生成到 ``POSCAR20`` 为止. 56 | 对于这些生成的任务我们会生成各个独立的文件夹, 以 ``struc_opt`` 为前缀流水号命名. 57 | 58 | 59 | ``prep_multi_vasp_from_file`` 60 | ================================ 61 | 为了满足一些其它要求, 我们可以不需要 ``POSCAR`` 文件按照流水号命名, 但是需要你提供一个 ``POSCAR`` 后面的id号的文件 `job_list_file`. 62 | 63 | 使用说明:: 64 | 65 | $ pyvasp prep_multi_vasp_from_file --help 66 | 67 | Usage: pyvasp prep_multi_vasp_from_file [OPTIONS] 68 | 69 | 例如:: 70 | 71 | $ cat job_list 72 | $ 2 3 5 6 7 73 | $ pyvasp prep_multi_vasp_from_file -a node_name=super_q,cpu_num=12,job_name=struc_opt job_list 74 | 75 | 这里仅仅会生成2,3,4,6,7这几个文件的任务. 76 | -------------------------------------------------------------------------------- /docs/source/test_para.rst: -------------------------------------------------------------------------------- 1 | ============ 2 | 测试参数 3 | ============ 4 | 5 | 这里我们提供了一些测试参数的命令. 6 | 7 | 8 | 测试截断能 9 | ============ 10 | 11 | 这里是测试截断能的命令:: 12 | 13 | $ pyvasp test_encut POSCAR -s 0.8 -e 1.3 -t 30 14 | 15 | 16 | 这里 ``-s`` 是 0.8*max_encut, encut 是你的赝势中的最大的 ``ENMAX`` , 17 | 类似的 ``-e`` 是 1.3*max_encut, ``-t`` 就是间隔. 这个命令也是支持 ``-a`` 这个参数的, 你可以制定一些其他参数. 18 | 19 | 20 | 21 | 测试k点 22 | ============ 23 | 24 | 这里是测试k-mesh的命令:: 25 | 26 | $ pyvasp test_kpts POSCAR -s 1000 -e 3000 -t 200 27 | 28 | 这里与上面是类似的, ``-s`` 是起始的kppa, ``-e`` 是最终的kppa, ``-t`` 指定了间隔, 同样的也支持 ``-a`` 参数. 29 | 30 | 注意这里会出现这样的情况, ``kppa=1000`` 和 ``kppa=1200`` 生成的k-mesh 是一样的, 所以为了避免重复计算, 就把重 31 | 复的 mesh 只生成了一次, 所以可能出现生成的 test_kpts只有几个. 这里我们提供了 -r 这个参数:: 32 | 33 | $ pyvasp test_kpts POSCAR -s 1000 -e 3000 -t 200 -r False 34 | 35 | 这样只会生成文件而不会提交计算. 所以你可以先用这个命令生成文件,看是否达到了你的要求,再运行:: 36 | 37 | $ pyvasp test_kpts POSCAR -s 1000 -e 3000 -t 200 38 | 39 | 就可以测试不同的 k-mesh 了. 40 | -------------------------------------------------------------------------------- /examples/common_calculations/band.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # make sure you have install pyvasp in your current environment 3 | # make sure current directory has POSCAR 4 | 5 | module load pyvaspflow # we make a module in our server 6 | 7 | pyvasp prep_single_vasp POSCAR -a ISIF=3,job_name=stru_relax 8 | pyvasp run_single_vasp stru_relax 9 | pyvasp prep_single_vasp stru_relax/CONTCAR -a job_name=scf,NSW=0,LCHARG=True 10 | pyvasp run_single_vasp scf 11 | pyvasp prep_single_vasp scf/CONTCAR -a style=band,NSW=0,job_name=band,ICHARG=11 12 | cp scf/CHG* band/ 13 | pyvasp run_single_vasp band 14 | -------------------------------------------------------------------------------- /examples/common_calculations/defect_cal.sh: -------------------------------------------------------------------------------- 1 | #/bin/bash 2 | 3 | module load pyvaspflow # we make a module in our server 4 | 5 | 6 | # relax calculation and scf calculation 7 | pyvasp prep_single_vasp POSCAR -a ISIF=3,node_name=long_q,job_name=supercell 8 | pyvasp run_single_vasp supercell 9 | cd supercell 10 | pyvasp prep_single_vasp CONTCAR -a kppa=4000,job_name=scf,node_name=long_q,NSW=0 11 | pyvasp run_single_vasp scf 12 | cd .. 13 | 14 | 15 | # get ground state of defect configurations 16 | pyvasp get_point_defect -i Vac -o Si supercell/scf/CONTCAR 17 | 18 | cd Si-Vac-1-defect 19 | i=0 20 | for f in `ls` 21 | do 22 | mv $f POSCAR$i 23 | let i=i+1 24 | done 25 | pyvasp prep_multi_vasp $((i-1)) -a node_name=long_q 26 | pyvasp run_multi_vasp task $((i-1)) 27 | grd_idx=`pyvasp get_grd_state task $((i-1)) ` 28 | cp task${grd_idx}/CONTCAR grd_poscar 29 | 30 | 31 | ## calculate possible charge states 32 | total_ele=`pyvasp main -a ele-free -w task0` 33 | for q in -2 -1 0 1 2 34 | do 35 | let ele=${total_ele}-$q 36 | pyvasp prep_single_vasp grd_poscar -a NELECT=$ele,job_name=charge_state_$q,node_name=long_q 37 | pyvasp run_single_vasp charge_state_$q 38 | cd charge_state_$q 39 | pyvasp prep_single_vasp CONTCAR -a NELECT=$ele,job_name=scf,node_name=long_q,NSW=0 40 | pyvasp run_single_vasp scf 41 | cd .. 42 | done 43 | 44 | cd .. 45 | 46 | ## calculate image correlation 47 | sed -n '1,5p' supercell/scf/POSCAR >poscar_img 48 | echo H >> poscar_img 49 | echo 1 >> poscar_img 50 | echo direct >>poscar_img 51 | echo "0.5 0.5 0.5 " >>poscar_img 52 | if [ ! -d image_corr ] 53 | then 54 | mkdir image_corr 55 | fi 56 | pyvasp prep_single_vasp poscar_img -a ISIF=2,job_name=image_corr,node_name=long_q 57 | rm poscar_img 58 | pyvasp run_single_vasp image_corr 59 | -------------------------------------------------------------------------------- /examples/common_calculations/dos.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # make sure you have install pyvasp in your current environment 3 | # make sure current directory has POSCAR 4 | 5 | module load pyvaspflow # we make a module in our server 6 | 7 | 8 | pyvasp prep_single_vasp POSCAR -a ISIF=3,job_name=stru_relax 9 | pyvasp run_single_vasp stru_relax 10 | pyvasp prep_single_vasp stru_relax/CONTCAR -a kppa=4000,job_name=scf,NSW=0,LCHARG=True 11 | pyvasp run_single_vasp scf 12 | pyvasp prep_single_vasp scf/CONTCAR -a kppa=8000,ISMEAR=-5,job_name=dos,NSW=0,LORBIT=11 13 | cp scf/CHG* dos/ 14 | pyvasp run_single_vasp dos 15 | -------------------------------------------------------------------------------- /examples/common_calculations/readme.md: -------------------------------------------------------------------------------- 1 | # examples 2 | 3 | 4 | In fact, it is easy to construct your job through this package. 5 | 6 | Here we supply some common vasp calculation shell scripts, they are [band.sh](https://github.com/ChangChunHe/Defect-Formation-Calculation/blob/master/pyvaspflow/examples/common_calculations/band.sh), [dos.sh](https://github.com/ChangChunHe/Defect-Formation-Calculation/blob/master/pyvaspflow/examples/common_calculations/dos.sh). You should supply a `POSCAR` file in your current directory. 7 | 8 | 9 | 10 | 11 | 12 | ## defect calculation 13 | 14 | You can read my `defect_cal.sh` example to know how to calculate defect formation energy in VASP. You should supply a poscar file in your current directory. If everything goes right, you will finally get the below directory hierarchy. 15 | 16 | ``` 17 | (vasp) [hecc@cmp test_defect_cal]$ tree -d 18 | . 19 | ├── C-Si-defect 20 | │   ├── charge_state_0 21 | │   │   └── scf 22 | │   ├── charge_state_1 23 | │   │   └── scf 24 | │   ├── charge_state_-1 25 | │   │   └── scf 26 | │   ├── charge_state_2 27 | │   │   └── scf 28 | │   ├── charge_state_-2 29 | │   │   └── scf 30 | │   ├── task0 31 | │   ├── task1 32 | │   └── task2 33 | ├── image_corr 34 | └── supercell 35 | └── scf 36 | ``` 37 | 38 | This directory hierarchy will support you to use `pyvasp get_def_form_energy` command, which will generate a `defect-log.txt` and plot a `defect-formation-energy.png` figure. 39 | 40 | ```shell 41 | pyvasp get_def_form_energy . O-Vacc-defect H-Vacc-defect 42 | ``` 43 | -------------------------------------------------------------------------------- /pyvaspflow/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /pyvaspflow/defect_cal/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChangChunHe/pyvaspflow/5976630a3b5cd05f634c5bc0146eafaff429c4a7/pyvaspflow/defect_cal/__init__.py -------------------------------------------------------------------------------- /pyvaspflow/defect_cal/chemical_potential.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3.6 2 | # -*- coding: utf-8 -*- 3 | 4 | import numpy as np 5 | import matplotlib 6 | matplotlib.use('agg') 7 | import matplotlib.pyplot as plt 8 | from itertools import combinations 9 | from collections import namedtuple, defaultdict 10 | import re 11 | from sagar.element.base import periodic_table_dict as ptd 12 | 13 | 14 | all_eles = [key for key in ptd] 15 | def get_ele_num(line): 16 | _element = [] 17 | for ele in all_eles: 18 | tmp = line.find(ele) 19 | if tmp != -1: 20 | if line[tmp:tmp+2] in all_eles: 21 | _element.append(line[tmp:tmp+2]) 22 | else: 23 | _element.append(line[tmp:tmp+1]) 24 | _element = list(set(_element)) 25 | idx = np.argsort([line.index(ele) for ele in _element]) 26 | element = [_element[i] for i in idx] 27 | all_idx = [(line.index(ele), len(ele)) for ele in element] 28 | number = [] 29 | for ii in range(len(all_idx)-1): 30 | tmp = line[all_idx[ii][0]+all_idx[ii][1]:all_idx[ii+1][0]] 31 | if tmp == '':tmp = '1' 32 | number.append(int(tmp)) 33 | tmp = line[all_idx[-1][1]+all_idx[-1][0]:] 34 | if tmp == '':tmp = '1' 35 | number.append(int(tmp)) 36 | return (element,number) 37 | 38 | 39 | def get_3d_cross_pts(A,B): 40 | # A = [1,2,4,-10] 41 | # B = [1,0,1,-6] 42 | C = np.array([A,B]) 43 | res = [] 44 | for com in combinations(range(len(A)-1),len(A)-2): 45 | a,b = C[:,com],C[:,-1] 46 | x = np.linalg.solve(a, b) 47 | _res = np.zeros((len(A)-1,)) 48 | _res[list(com)] = x 49 | _res[np.setdiff1d(range(len(A)-1),com)] = 0 50 | res.append(_res.tolist()) 51 | return res 52 | 53 | 54 | class Phase: 55 | def __init__(self,name='',element='',number='',energy=''): 56 | self.name = name 57 | self.element = element 58 | self.number = number 59 | self.energy = energy 60 | def __repr__(self): 61 | print('name: ',self.name) 62 | print('element: ',self.element) 63 | print('number: ',self.number) 64 | print('energy: ',self.energy) 65 | 66 | 67 | def plot_2d_chemical_potential_phase(chem_incar, remove_ele=0): 68 | with open(chem_incar,'r') as f: 69 | lines = f.readlines() 70 | pure_phase = {} 71 | for line in lines: 72 | if not line.strip(): continue 73 | line = re.sub(r"\s+","",line,flags=re.UNICODE).split('=') 74 | (tmp_ele,tmp_num) = get_ele_num(line[0]) 75 | if len(tmp_ele) == 1: 76 | pure_phase[tmp_ele[0]] = float(line[1]) / float(tmp_num[0]) 77 | else: 78 | if '#' in line[0]: 79 | line[0] = line[0].replace('#','') 80 | element, number = get_ele_num(line[0]) 81 | energy = float(line[1]) 82 | host = Phase(name=line[0],element=element,number=number,energy=energy) 83 | for idx in range(len(host.element)): 84 | host.energy -= host.number[idx] * pure_phase[host.element[idx]] 85 | compete_phase = [] 86 | for line in lines: 87 | if not line.strip(): continue 88 | line = re.sub(r"\s+","",line,flags=re.UNICODE).split('=') 89 | element, number = get_ele_num(line[0]) 90 | ele_num = defaultdict(lambda: 0, dict(zip(element,number))) 91 | if '#' not in line[0] and len(element) > 1: 92 | element = host.element 93 | number = [ele_num[key] for key in element] 94 | energy = float(line[1]) 95 | for idy in range(len(host.element)): 96 | energy -= number[idy] * pure_phase[host.element[idy]] 97 | compete_phase.append(Phase(name=line[0],element=element,number=number,energy=energy)) 98 | atom_num = len(host.element) 99 | f = open('chemical_log.txt','w') 100 | pts = {} 101 | for phase in compete_phase: 102 | f.write('chemical potential constrain of '+phase.name+'\n') 103 | for ii in host.element: 104 | f.write(str(ii)+'\t') 105 | f.write('\n') 106 | A_ub = phase.number 107 | A_ub.append(phase.energy) 108 | A_eq = host.number.copy() 109 | A_eq.append(host.energy) 110 | pts_val1 = get_3d_cross_pts(A_eq,A_ub) 111 | pts[phase.name] = pts_val1 112 | for pt in pts_val1: 113 | f.write('\t'.join([str(np.round(i,4)) for i in pt])+'\n') 114 | f.write('\n') 115 | f.close() 116 | idx = [0,1,2] 117 | idx.remove(remove_ele) 118 | fig = plt.figure() 119 | ax=plt.axes() 120 | ax.spines['right'].set_color('none') 121 | ax.spines['top'].set_color('none') 122 | ax.xaxis.set_ticks_position('bottom') 123 | ax.spines['bottom'].set_position(('data',0)) 124 | ax.yaxis.set_ticks_position('left') 125 | ax.spines['left'].set_position(('data',0)) 126 | ax.set_xlabel(r'$\mu $'+host.element[idx[0]]+' (eV)',ha='left',va='top') 127 | ax.xaxis.set_label_coords(0, 1.01) 128 | ax.set_ylabel(r'$\mu$'+host.element[idx[1]]+' (eV)') 129 | ax.yaxis.set_label_coords(1.01, 0) 130 | for key, val in pts.items(): 131 | for two_pts in combinations(val,2): 132 | pts0,pts1 = two_pts[0],two_pts[1] 133 | x1,x2,y1,y2 = pts0[idx[0]],pts1[idx[0]],pts0[idx[1]],pts1[idx[1]] 134 | if all(np.array([x1,x2,y1,y2])<=0) and A_eq[idx[0]]*x1+A_eq[idx[1]]*y1 >=A_eq[-1] \ 135 | and A_eq[idx[0]]*x2+A_eq[idx[1]]*y2 >=A_eq[-1]: 136 | plt.plot([x1,x2],[y1,y2],linewidth=1,linestyle="-",label=key) 137 | xlim,ylim = host.energy/host.number[idx[0]],host.energy/host.number[idx[1]] 138 | plt.plot([xlim,0],[0,ylim],color="blue",linewidth=2,linestyle="-") 139 | plt.plot([xlim,0],[0,0],color="blue",linewidth=2,linestyle="-") 140 | plt.plot([0,0],[0,ylim],color="blue",linewidth=2,linestyle="-") 141 | plt.legend() 142 | plt.savefig('chemical-potential.png',dpi=450) 143 | 144 | 145 | if __name__ == '__main__': 146 | plot_2d_chemical_potential_phase('chemical-incar') 147 | -------------------------------------------------------------------------------- /pyvaspflow/defect_cal/defect_formation_energy.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3.6 2 | # -*- coding: utf-8 -*- 3 | 4 | import matplotlib 5 | matplotlib.use('agg') 6 | import matplotlib.pyplot as plt 7 | import warnings,sys,os 8 | import numpy as np 9 | from pyvaspflow.io.vasp_out import ExtractValue,get_ele_sta,read_incar 10 | from pyvaspflow.utils import get_farther_atom_num 11 | 12 | def get_defect_formation_energy(data_dir,defect_dirs): 13 | print('The main direcroty is: ', data_dir) 14 | f = open(os.path.join(data_dir,'defect-log.txt'),'w') 15 | fig, ax = plt.subplots() 16 | for defect_dir in defect_dirs: 17 | print('Reading ', defect_dir) 18 | f.write(defect_dir+'\n') 19 | SC_energy = ExtractValue(os.path.join(data_dir,'supercell/scf/')).get_energy() 20 | print('Energy of supcell is: '+str(SC_energy)+' eV') 21 | f.write('Energy of supcell is: '+str(SC_energy)+' eV\n') 22 | res = ExtractValue(os.path.join(data_dir,'supercell/scf/')).get_gap() 23 | if len(res) == 3: 24 | Evbm, Ecbm, gap = res 25 | elif len(res) == 2: 26 | Evbm, Ecbm, gap = res[0] 27 | print('Evbm, Ecbm, gap of supcell is: ', Evbm, Ecbm, gap) 28 | f.write('Evbm: '+str(Evbm)+' eV\n'+'Ecbm: '+str(Ecbm)+' eV\n'+'gap: '+str(gap)+' eV\n') 29 | chg_state = [] 30 | f.write('charge\t\tenergy\t\tE_PA\t\tE_IC\tfar_atom_def_sys\tfar_atom_def_fr_system\n') 31 | for chg_fd in os.listdir(os.path.join(defect_dir)): 32 | if 'charge_state_' in chg_fd: 33 | q = chg_fd.split('_')[-1] 34 | e = ExtractValue(os.path.join(defect_dir,chg_fd,'scf')).get_energy() 35 | no_def_poscar = os.path.join(data_dir,'supercell','scf/CONTCAR') 36 | def_poscar = os.path.join(defect_dir,chg_fd,'POSCAR') 37 | num_def, num_no_def = get_farther_atom_num(no_def_poscar, def_poscar) 38 | pa_def = get_ele_sta(os.path.join(defect_dir,chg_fd,'scf','OUTCAR'),num_def) 39 | pa_no_def = get_ele_sta(os.path.join(data_dir,'supercell','scf','OUTCAR'),num_no_def) 40 | E_imagecor = ExtractValue(os.path.join(data_dir,'image_corr')).get_image() 41 | chg_state.append([int(float(q)), e, pa_def-pa_no_def, E_imagecor, num_def, num_no_def]) 42 | ele_in_out = read_incar('element-in-out') 43 | incar_para = read_incar(os.path.join(data_dir,'defect-incar')) 44 | incar_para['mu_Vacc'] = 0 45 | if 'epsilon' in incar_para: 46 | epsilon = float(incar_para['epsilon']) 47 | else: 48 | epsilon = 1e10 49 | warnings.warn("You should specify epsilon in your defect-incar, here we just ignore this correlation") 50 | chg_state = np.asarray(chg_state) 51 | chg_state[:,2] = chg_state[:,2]*chg_state[:,0] 52 | chg_state[:,3] = -2/3*chg_state[:,0]**2*chg_state[:,3]/epsilon 53 | for c in chg_state: 54 | f.write('{:2d}\t\t{:.5f}\t{:+.5f}\t{:+.5f}\t{:d}\t\t\t{:d}\n'.format(int(c[0]),c[1],c[2],c[3],int(c[4]),int(c[5]))) 55 | mu = 0 56 | for key,val in ele_in_out.items(): 57 | if 'mu_'+key in incar_para: 58 | mu += float(incar_para['mu_'+key])*int(val) 59 | f.write('chemical potential of '+key.title()+': '+str(incar_para['mu_'+key])+' eV\n') 60 | else: 61 | raise ValueError('chemical potential mu_'+key.title()+' cannot found') 62 | os.system('rm element-in-out') 63 | for key, val in ele_in_out.items(): 64 | if int(val) == -1: 65 | f.writelines(key.title()+' has been doped\n') 66 | else: 67 | f.writelines(key.title()+' has been removed\n') 68 | f.writelines('\n') 69 | Ef = np.linspace(Evbm,Ecbm,1000) 70 | chg_state = np.asarray(chg_state) 71 | E = [] 72 | for idx in range(np.shape(chg_state)[0]): 73 | E.append(chg_state[idx,1]-SC_energy+mu+chg_state[idx,0]*Ef+chg_state[idx,2]+chg_state[idx,3]) 74 | E = np.asarray(E) 75 | ax.set_aspect('equal') 76 | ax.plot(Ef-Evbm,np.min(E,axis=0),label=defect_dir) 77 | f.close() 78 | plt.xlabel(r'$E_F$ (eV)') 79 | plt.ylabel(r'$\Delta E (eV)$') 80 | plt.legend() 81 | plt.savefig(os.path.join(data_dir,'defect_formation_energy.png'),dpi=450) 82 | -------------------------------------------------------------------------------- /pyvaspflow/defect_cal/defect_maker.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3.6 2 | # -*- coding: utf-8 -*- 3 | """ 4 | Created on Fri Mar 8 15:22:33 2019 5 | 6 | @author: hecc 7 | """ 8 | 9 | import numpy as np 10 | from sagar.crystal.derive import ConfigurationGenerator 11 | from sagar.io.vasp import read_vasp,_read_string 12 | from sagar.crystal.structure import symbol2number as s2n 13 | from sagar.element.base import get_symbol 14 | from sagar.molecule.derive import ConfigurationGenerator as mole_CG 15 | from sagar.molecule.structure import Molecule 16 | from pyvaspflow.utils import generate_all_basis, refine_points,write_poscar,get_identity_atoms 17 | from itertools import combinations,chain 18 | from sagar.crystal.structure import Cell 19 | from shutil import rmtree 20 | import os 21 | 22 | 23 | class DefectMaker: 24 | def __init__(self, no_defect='POSCAR',no_defect_string=''): 25 | # 初始化用 POSCAR路径? 26 | if no_defect_string : 27 | self.no_defect_cell = _read_string(no_defect_string) 28 | else: 29 | self.no_defect_cell = read_vasp(no_defect) 30 | self.lattice = self.no_defect_cell.lattice 31 | self.positions = self.no_defect_cell.positions 32 | self.atoms = self.no_defect_cell.atoms 33 | 34 | 35 | def extend(self, h): 36 | if isinstance(h, int): 37 | self.no_defect_cell = self.no_defect_cell.extend(np.array([[h,0,0],[0,h,0],[0,0,h]])) 38 | else: 39 | self.no_defect_cell = self.no_defect_cell.extend(np.array(h)) 40 | self.lattice = self.no_defect_cell.lattice 41 | self.positions = self.no_defect_cell.positions 42 | self.atoms = self.no_defect_cell.atoms 43 | print('Warning: this operation will change your cell, \n', 44 | 'and the lattice has been changed to be:\n', self.lattice) 45 | 46 | 47 | def get_tetrahedral_defect(self, isunique=False, doped_in='H',min_d=1.5,folder='tetrahedral-defect'): 48 | all_basis = generate_all_basis(1,1,1) 49 | direct_lattice = np.array([[1,0,0],[0,1,0],[0,0,1]]) 50 | extend_S = np.zeros((0,3)) 51 | for basis in all_basis: 52 | new_basis = np.sum([(direct_lattice[ii]*basis[ii]).tolist() for ii in range(3)],axis=0) 53 | extend_S = np.vstack((extend_S, 54 | self.positions+np.tile(new_basis,len(self.atoms)).reshape((-1,3)))) 55 | idx = np.sum((extend_S <= 1.2) &(extend_S >= -0.2),axis=1) 56 | idx = np.where(idx == 3)[0] 57 | extend_S = np.dot(extend_S[idx],self.lattice) 58 | n = extend_S.shape[0] 59 | d = np.zeros((n,n)) 60 | for ii in range(n): 61 | d[ii,ii+1:] = np.linalg.norm(extend_S[ii]-extend_S[ii+1:],axis=1) 62 | d = d + d.T 63 | first_tetra,sec_tetra,third_tetra = [],[],[] 64 | for ii in range(n): 65 | temp_d = sorted(d[ii]) 66 | idx = np.where(abs(d[ii] - temp_d[1])0]) < 0.01: 74 | if abs(tmp[0,1]-temp_d[1]) < 0.1: 75 | first_tetra.append(comb_list) 76 | else: 77 | sec_tetra.append(comb_list) 78 | else: 79 | tmp = d[comb_list][:,comb_list] 80 | tmp = np.triu(tmp) 81 | tmp = sorted(tmp[tmp>0]) 82 | if (np.std(tmp[0:4]) < 0.1 or np.std(tmp[1:5]) < 0.1 or 83 | np.std(tmp[2:]) < 0.1) and np.std(tmp) < 0.5: 84 | third_tetra.append(comb_list) 85 | all_tetra = [] 86 | if len(first_tetra) != 0: 87 | first_tetra = np.unique(np.sort(first_tetra,axis=1),axis=0) 88 | first_tetra = refine_points(first_tetra,extend_S,self.lattice,min_d=min_d) 89 | all_tetra.append(first_tetra) 90 | if len(sec_tetra) !=0: 91 | sec_tetra = np.unique(np.sort(sec_tetra,axis=1),axis=0) 92 | sec_tetra = refine_points(sec_tetra,extend_S,self.lattice,min_d=min_d) 93 | all_tetra.append(sec_tetra) 94 | if len(third_tetra) != 0: 95 | third_tetra = np.unique(np.sort(third_tetra,axis=1),axis=0) 96 | third_tetra = refine_points(third_tetra,extend_S,self.lattice,min_d=min_d) 97 | all_tetra.append(third_tetra) 98 | if isunique: 99 | if not os.path.exists(folder): 100 | os.mkdir(folder) 101 | else: 102 | rmtree(folder) 103 | os.mkdir(folder) 104 | idx = 0 105 | # deg = [] 106 | for tetra in all_tetra: 107 | if len(tetra) == 0: 108 | continue 109 | new_pos = np.vstack((self.positions,tetra)) 110 | new_atoms = np.hstack((self.atoms,s2n(doped_in)*np.ones((tetra.shape[0],)))) 111 | new_cell = Cell(self.lattice,new_pos,new_atoms) 112 | equi_atoms = new_cell.get_symmetry()['equivalent_atoms'] 113 | purity_atom_type = np.unique(equi_atoms[-tetra.shape[0]:]) 114 | for atom_type in purity_atom_type: 115 | new_uniq_pos = np.vstack((self.positions,new_pos[atom_type])) 116 | new_uniq_atoms = np.hstack((self.atoms,s2n(doped_in)*np.ones((1,)))) 117 | new_uniq_cell = Cell(self.lattice,new_uniq_pos,new_uniq_atoms) 118 | # deg.append(len(np.where(equi_atoms == atom_type)[0])) 119 | write_poscar(new_uniq_cell,folder,idx) 120 | idx += 1 121 | # np.savetxt(folder+'/deg.txt',deg,fmt='%d') 122 | else: 123 | if not os.path.exists(folder): 124 | os.mkdir(folder) 125 | else: 126 | rmtree(folder) 127 | os.mkdir(folder) 128 | idx = 0 129 | for tetra in all_tetra: 130 | if len(tetra) == 0: 131 | continue 132 | new_pos = np.vstack((self.positions,tetra)) 133 | new_atoms = np.hstack((self.atoms,s2n(doped_in)*np.ones((tetra.shape[0],)))) 134 | new_cell = Cell(self.lattice,new_pos,new_atoms) 135 | write_poscar(new_cell,folder,idx) 136 | idx += 1 137 | 138 | 139 | def get_point_defect(self,symprec=1e-3,doped_out='all',doped_in=['Vac'],num=[1]): 140 | cell = self.no_defect_cell 141 | cg = ConfigurationGenerator(cell, symprec) 142 | sites = _get_sites(list(cell.atoms), doped_out=doped_out, doped_in=doped_in) 143 | if num == None: 144 | confs = cg.cons_specific_cell(sites, e_num=None, symprec=symprec) 145 | comment = ["-".join(doped_in)+"-all_concentration"] 146 | else: 147 | purity_atom_num = sum([1 if len(site)>1 else 0 for site in sites]) 148 | confs = cg.cons_specific_cell(sites, e_num=[purity_atom_num-sum(num)]+num, symprec=symprec) 149 | comment = list(chain(*zip(doped_in, [str(i) for i in num]))) 150 | comment = '-'.join(doped_out) +'-'+'-'.join(comment) + '-defect' 151 | folder = comment 152 | if not os.path.isdir(folder): 153 | os.makedirs(folder) 154 | deg = [] 155 | idx = 0 156 | for c, _deg in confs: 157 | write_poscar(c,folder,idx) 158 | deg.append(_deg) 159 | idx += 1 160 | np.savetxt(os.path.join(folder,"deg.txt"),deg,fmt='%d') 161 | 162 | 163 | def get_mole_point_defect(self,symprec=1e-3,doped_out='all',doped_in=['Vac'],num=[1]): 164 | pos,lat,atoms = self.positions,self.lattice,self.atoms 165 | mole = Molecule(np.dot(pos,lat),atoms) 166 | cg = mole_CG(mole, symprec) 167 | sites = _get_sites(list(mole.atoms), doped_out=doped_out, doped_in=doped_in) 168 | if num == None: 169 | confs = cg.get_configurations(sites, e_num=None) 170 | comment = ["-".join(doped_in)+"-all_concentration"] 171 | else: 172 | purity_atom_num = sum([1 if len(site)>1 else 0 for site in sites]) 173 | confs = cg.get_configurations(sites, e_num=[purity_atom_num-sum(num)]+num) 174 | comment = list(chain(*zip(doped_in, [str(i) for i in num]))) 175 | folder = '-'.join(doped_out) +'-'+'-'.join(comment) + '-defect' 176 | if not os.path.exists('./'+folder): 177 | os.mkdir('./'+folder) 178 | else: 179 | rmtree('./'+folder) 180 | os.mkdir('./'+folder) 181 | deg = [] 182 | idx = 0 183 | for c, _deg in confs: 184 | c.lattice = lat 185 | c._positions = np.dot(c.positions,np.linalg.inv(lat)) 186 | write_poscar(c,folder,idx) 187 | deg.append(_deg) 188 | idx += 1 189 | np.savetxt(os.path.join(folder,"deg.txt"),deg,fmt='%d') 190 | 191 | def get_magnetic_config(self,magnetic_atom,magmon=1,magmon_identity=False,symprec=1e-3): 192 | cell = self.no_defect_cell 193 | cg = ConfigurationGenerator(cell, symprec) 194 | doped_in = get_symbol(np.setdiff1d(range(1,56),np.unique(cell.atoms))[0]) 195 | sites = _get_sites(list(cell.atoms), doped_out=magnetic_atom, doped_in=[doped_in]) 196 | n = len(cell.atoms) 197 | magmom = [] 198 | magnetic_atom_idx = np.where(cell.atoms==s2n(magnetic_atom[0]))[0].astype("int") 199 | atoms_type = get_identity_atoms(cell,symprec) 200 | unique_atoms_type = np.unique(atoms_type) 201 | for num in range(len(magnetic_atom_idx)//2+1): 202 | confs = cg.cons_specific_cell(sites, e_num=[len(magnetic_atom_idx)-num,num], symprec=symprec) 203 | for c,_def in confs: 204 | tmp_magmom = np.zeros((n,)) 205 | tmp_magmom[magnetic_atom_idx] = magmon 206 | mag_idx = [np.where(np.linalg.norm(cell.positions-c.positions[_idx],axis=1)<0.01)[0][0] \ 207 | for _idx in np.where(c.atoms==s2n(doped_in[0]))[0]] 208 | tmp_magmom[mag_idx] = -magmon 209 | if magmon_identity: 210 | flag = True 211 | for i in unique_atoms_type: 212 | if len(np.unique(tmp_magmom[np.where(atoms_type==i)[0]])) != 1: 213 | flag = False 214 | break 215 | if flag: 216 | magmom.append(tmp_magmom.tolist()) 217 | else: 218 | magmom.append(tmp_magmom.tolist()) 219 | # remove the equivalent AFM -1 1/1 -1 220 | final_magmom = set() 221 | final_magmom.add(tuple(magmom[0])) 222 | for idx in range(1,len(magmom)): 223 | mag = np.array(magmom[idx]).astype("int") 224 | if tuple(mag) in final_magmom: 225 | continue 226 | idx_up = np.where(mag==magmon)[0].astype("int") 227 | idx_down = np.where(mag==-magmon)[0].astype("int") 228 | mag[idx_up] = -magmon 229 | mag[idx_down] = magmon 230 | if tuple(mag) in final_magmom: 231 | continue 232 | final_magmom.add(tuple(mag)) 233 | final_magmom = np.array([list(i) for i in final_magmom]) 234 | np.savetxt("INCAR-magmon",final_magmom,fmt='%2d') 235 | 236 | # def _get_sites(atoms,doped_out,doped_in): 237 | # doped_in = [s2n(i) for i in doped_in] 238 | # if doped_out == 'all': 239 | # return [tuple([atom]+doped_in) for atom in atoms] 240 | # else: 241 | # doped_out = s2n(doped_out) 242 | # _ins = tuple([doped_out]+doped_in) 243 | # return [_ins if atom == doped_out else (atom,) for atom in atoms] 244 | 245 | def _get_sites(atoms,doped_out,doped_in): 246 | doped_in = [s2n(i) for i in doped_in] 247 | if doped_out == ['all']: 248 | return [tuple([atom]+doped_in) for atom in atoms] 249 | elif len(doped_out) > 1: 250 | doped_out = [s2n(i) for i in doped_out] 251 | return [tuple([atom]+doped_in) if atom in doped_out else (atom,) for atom in atoms ] 252 | else: 253 | doped_out = [s2n(i) for i in doped_out] 254 | _ins = tuple(doped_out+doped_in) 255 | return [_ins if atom == doped_out else (atom,) for atom in atoms] 256 | 257 | if __name__ == '__main__': 258 | dm = DefectMaker('/home/hecc/Downloads/POSCAR') 259 | dm.get_mole_point_defect(symprec=0.1,doped_out='C',doped_in=['Vac'],num=[2]) 260 | -------------------------------------------------------------------------------- /pyvaspflow/io/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChangChunHe/pyvaspflow/5976630a3b5cd05f634c5bc0146eafaff429c4a7/pyvaspflow/io/__init__.py -------------------------------------------------------------------------------- /pyvaspflow/io/vasp_out.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3.6 2 | # -*- coding: utf-8 -*- 3 | 4 | 5 | import linecache as lc 6 | import numpy as np 7 | import os 8 | from sagar.io.vasp import read_vasp 9 | import subprocess 10 | 11 | 12 | class ExtractValue(): 13 | def __init__(self,data_folder='./',atomic_num=3): 14 | 15 | self.data_folder = data_folder 16 | self.atomic_num = atomic_num 17 | 18 | def get_energy(self): 19 | file_osz = os.path.join(self.data_folder,'OSZICAR') 20 | return float(subprocess.run(['tail','-1',file_osz],stdout=subprocess.PIPE).stdout.decode('utf-8').split()[4]) 21 | 22 | 23 | def get_fermi(self): 24 | # read from scf calculation 25 | file_outcar = os.path.join(self.data_folder,'OUTCAR') 26 | grep_res = subprocess.Popen(['grep','E-fermi',file_outcar],stdout=subprocess.PIPE) 27 | return float(subprocess.check_output(['tail','-1'],stdin=grep_res.stdout).decode('utf-8').split()[2]) 28 | 29 | def get_Ne_defect_free(self): 30 | # you can get valance electrons in your defect-free system 31 | file_pos = os.path.join(self.data_folder, 'POSCAR') 32 | file_pot = os.path.join(self.data_folder, 'POTCAR') 33 | ele_num_atom = [float(i) for i in subprocess.run(['grep','ZVAL',file_pot],stdout=subprocess.PIPE).stdout.decode('utf-8').split()[5::9]] 34 | atom_num = [float(i) for i in lc.getlines(file_pos)[6].split()] 35 | return int(np.dot(atom_num,ele_num_atom)) 36 | 37 | def get_Ne_defect(self): 38 | #get all valance electrons number in OUTCAR 39 | file_outcar = os.path.join(self.data_folder,'OUTCAR') 40 | grep_res = subprocess.run(['grep','NELECT',file_outcar],stdout=subprocess.PIPE) 41 | return int(float(grep_res.stdout.decode('utf-8').split()[2])) 42 | 43 | def get_image(self): 44 | file_image = os.path.join(self.data_folder,'OUTCAR') 45 | return float(subprocess.run(['grep','Ewald',file_image],stdout=subprocess.PIPE).stdout.decode('utf-8').split('\n')[0].split()[-1]) 46 | 47 | def get_cpu_time(self): 48 | file_outcar = os.path.join(self.data_folder,'OUTCAR') 49 | with open(file_outcar) as f: 50 | lines = f.readlines() 51 | cpu_line = [line for line in lines if 'CPU' in line] 52 | return float(cpu_line[0].split()[-1]) 53 | 54 | def get_gap(self,vbm_occupancy=0.7,cbm_occupancy=0.3): 55 | file_eig = os.path.join(self.data_folder,'EIGENVAL') 56 | line6 = np.genfromtxt(file_eig,skip_header=5,max_rows=1) 57 | kpt_num, eig_num = int(line6[1]), int(line6[2]) 58 | if len(lc.getlines(file_eig)[8].split()) == 3: 59 | isspin = False 60 | elif len(lc.getlines(file_eig)[8].split()) == 5: 61 | isspin = True 62 | if not isspin: 63 | all_eigval = np.zeros((eig_num, kpt_num*2)) 64 | for ii in range(kpt_num): 65 | all_eigval[:,2*ii:2*ii+2] = np.genfromtxt(file_eig, 66 | skip_header=8+eig_num*int(ii)+2*ii, 67 | max_rows=eig_num,usecols=(1,2)) 68 | else: 69 | all_eigval = np.zeros((eig_num, kpt_num*4)) 70 | for ii in range(kpt_num): 71 | all_eigval[:,4*ii:4*ii+4] = np.genfromtxt(file_eig, 72 | skip_header=8+eig_num*int(ii)+2*ii, 73 | max_rows=eig_num,usecols=(1,2,3,4)) 74 | if not isspin: 75 | elec_num = np.mean(all_eigval[:,1::2],axis=1) 76 | idx1 = np.where(elec_num > vbm_occupancy) 77 | idx2 = np.where(elec_num < cbm_occupancy) 78 | if idx1[0][-1] - idx2[0][0] == -1: 79 | vbm = np.max(all_eigval[idx1[0][-1],::2]) 80 | cbm = np.min(all_eigval[idx2[0][0],::2]) 81 | gap = cbm - vbm if cbm > vbm else 0 82 | else: 83 | print('The gap of this system can not be obtained from this progrmme', 84 | 'I suggest you carefully check the EIGENVAL by yourself') 85 | return 0 86 | return (vbm, cbm, gap) 87 | else: 88 | all_eigval_up = all_eigval[:,0::2] 89 | all_eigval_down = all_eigval[:,1::2] 90 | elec_num_up = np.mean(all_eigval_up[:,1::2],axis=1) 91 | idx1 = np.where(elec_num_up > vbm_occupancy) 92 | idx2 = np.where(elec_num_up < cbm_occupancy) 93 | if idx1[0][-1] - idx2[0][0] == -1: 94 | vbm_up = np.max(all_eigval_up[idx1[0][-1],::2]) 95 | cbm_up = np.min(all_eigval_up[idx2[0][0],::2]) 96 | gap_up = cbm_up - vbm_up if cbm_up > vbm_up else 0 97 | else: 98 | print('The gap of this system can not be obtained from this progrmme', 99 | 'I suggest you carefully check the EIGENVAL by yourself') 100 | return 0 101 | elec_num_down = np.mean(all_eigval_down[:,1::2],axis=1) 102 | idx1 = np.where(elec_num_down > vbm_occupancy) 103 | idx2 = np.where(elec_num_down < cbm_occupancy) 104 | if idx1[0][-1] - idx2[0][0] == -1: 105 | vbm_down = np.max(all_eigval_down[idx1[0][-1],::2]) 106 | cbm_down = np.min(all_eigval_down[idx2[0][0],::2]) 107 | gap_down = cbm_down - vbm_down if cbm_down > vbm_down else 0 108 | else: 109 | print('The gap of this system can not be obtained from this progrmme', 110 | 'I suggest you carefully check the EIGENVAL by yourself') 111 | return 0 112 | return (vbm_up, cbm_up, gap_up), (vbm_down, cbm_down, gap_down) 113 | 114 | 115 | def get_ele_sta(no_defect_outcar,number): 116 | number = int(number) 117 | tmp_match_line = _get_line(no_defect_outcar,rematch='electrostatic') 118 | rows = number // 5 119 | col = number - rows * 5 - 1 120 | if col == -1: 121 | rows -= 1 122 | col = 4 123 | tmp_line = lc.getlines(no_defect_outcar)[tmp_match_line[0]+rows+3].split() 124 | return float(tmp_line[2*col+1]) 125 | 126 | def _get_line(file_tmp,rematch=None): 127 | grep_res = subprocess.Popen(['grep', rematch, file_tmp,'-n'],stdout=subprocess.PIPE) 128 | return [int(ii) - 1 for ii in subprocess.check_output(['cut','-d',':','-f','1'],stdin=grep_res.stdout).decode('utf-8').split()] 129 | 130 | def read_incar(incar): 131 | import re 132 | res = {} 133 | with open(incar,'r') as f: 134 | lines = f.readlines() 135 | for line in lines: 136 | if line.strip() == '': 137 | continue 138 | line = re.sub(r"\s+","",line,flags=re.UNICODE).split('=') 139 | res[line[0]] = line[1] 140 | return res 141 | 142 | def read_doscar(wd): 143 | c = read_vasp(os.path.join(wd,'POSCAR')) 144 | line6 = np.genfromtxt(os.path.join(wd,'DOSCAR'),skip_header=5,max_rows=1) 145 | n_dos = int(line6[2]) 146 | sum_dos = np.genfromtxt(os.path.join(wd,'DOSCAR'),skip_header=6,max_rows=n_dos) 147 | np.savetxt(os.path.join(wd,'sum_dos.txt'),sum_dos,fmt="%.5f") 148 | incar = read_incar(os.path.join(wd,'INCAR')) 149 | if 'LORBIT' not in incar: 150 | return 151 | if int(incar['LORBIT']) == 11: 152 | for ii in range(c.atoms.shape[0]): 153 | p_dos = np.genfromtxt(os.path.join(wd,'DOSCAR'),skip_header=6+(1+n_dos)*(ii+1),max_rows=n_dos) 154 | np.savetxt(os.path.join(wd,'p_dos'+str(ii)+'.txt'),p_dos,fmt="%.5f") 155 | -------------------------------------------------------------------------------- /pyvaspflow/pyvasp.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import numpy as np 4 | import linecache as lc 5 | import os,subprocess,click,re,psutil 6 | import pyvaspflow.utils as us 7 | from sagar.io.vasp import read_vasp, write_vasp 8 | from sagar.crystal.derive import cells_nonredundant 9 | from pyvaspflow.io.vasp_out import ExtractValue, get_ele_sta 10 | from pyvaspflow.defect_cal.defect_maker import DefectMaker 11 | from pyvaspflow.vasp.prep_vasp import prep_single_vasp as psv 12 | from pyvaspflow.vasp.run_vasp import run_single_vasp as rsv 13 | from pyvaspflow.vasp.prep_vasp import prep_multi_vasp as pmv 14 | from pyvaspflow.vasp.run_vasp import run_multi_vasp as rmv 15 | from pyvaspflow.vasp.run_vasp import run_multi_vasp_with_shell as rmvws 16 | from pyvaspflow.vasp.run_vasp import run_multi_vasp_without_job as rmvwj 17 | from pyvaspflow.vasp.run_vasp import run_single_vasp_without_job as rsvwj 18 | from pyvaspflow.vasp.prep_vasp import write_incar as wi 19 | from pyvaspflow.vasp.prep_vasp import write_kpoints as wk 20 | from pyvaspflow.defect_cal.defect_formation_energy import get_defect_formation_energy 21 | from pyvaspflow.vasp import test_para 22 | from pyvaspflow.io.vasp_out import read_doscar 23 | 24 | CONTEXT_SETTINGS = dict(help_option_names=['-h', '--help']) 25 | 26 | @click.group(context_settings=CONTEXT_SETTINGS) 27 | def cli(): 28 | ''' 29 | you can refer to 30 | 31 | https://pyvaspflow.readthedocs.io/zh_CN/latest/index.html 32 | 33 | for more help 34 | ''' 35 | pass 36 | 37 | 38 | def get_poscar_files(ctx, args, incomplete): 39 | if incomplete: 40 | return [k for k in os.listdir() if k.startswith(incomplete)] 41 | else: 42 | return [k for k in os.listdir() if (k.lower().startswith('poscar') \ 43 | or k.endswith('vasp')) and os.path.isfile(k)] 44 | 45 | def get_dir_name(ctx, args, incomplete): 46 | if incomplete: 47 | return [k for k in os.listdir() if k.startswith(incomplete)] 48 | else: 49 | return [k for k in os.listdir() if os.path.isdir(k)] 50 | 51 | 52 | @cli.command('gap',short_help="Get band gap and vbm cbm") 53 | @click.option('--wd','-w',default='.',help='your work direcroty',show_default=True, 54 | type=click.Path(exists=True,resolve_path=True),autocompletion=get_dir_name) 55 | @click.option('--vo', '-v', type=float,default=0.7,help="vbm occupancy") 56 | @click.option('--co', '-c', type=float,default=0.3,help="cbm occupancy") 57 | def gap(wd,vo,co): 58 | EV = ExtractValue(wd) 59 | get_gap(EV,float(vo),float(co)) 60 | 61 | @cli.command('fermi',short_help="Get fermi energy level") 62 | @click.option('--wd','-w',default='.',help='your work direcroty',show_default=True, 63 | type=click.Path(exists=True,resolve_path=True),autocompletion=get_dir_name) 64 | def fermi(wd): 65 | EV = ExtractValue(wd) 66 | click.echo(EV.get_fermi()) 67 | 68 | @cli.command('energy',short_help="Get total energy") 69 | @click.option('--wd','-w',default='.',help='your work direcroty',show_default=True, 70 | type=click.Path(exists=True,resolve_path=True),autocompletion=get_dir_name) 71 | def energy(wd): 72 | EV = ExtractValue(wd) 73 | click.echo(EV.get_energy()) 74 | 75 | @cli.command('electron_defect_free',short_help="Get electron number of defect free system") 76 | @click.option('--wd','-w',default='.',help='your work direcroty',show_default=True, 77 | type=click.Path(exists=True,resolve_path=True),autocompletion=get_dir_name) 78 | def electron_defect_free(wd): 79 | EV = ExtractValue(wd) 80 | click.echo(EV.get_Ne_defect_free()) 81 | 82 | @cli.command('electron_number',short_help="Get electron number of current system") 83 | @click.option('--wd','-w',default='.',help='your work direcroty',show_default=True, 84 | type=click.Path(exists=True,resolve_path=True),autocompletion=get_dir_name) 85 | def electron_number(wd): 86 | EV = ExtractValue(wd) 87 | click.echo(EV.get_Ne_defect()) 88 | 89 | @cli.command('ewald',short_help="Get ewald energy of current system") 90 | @click.option('--wd','-w',default='.',help='your work direcroty',show_default=True, 91 | type=click.Path(exists=True,resolve_path=True),autocompletion=get_dir_name) 92 | def ewald(wd): 93 | EV = ExtractValue(wd) 94 | click.echo(EV.get_image()) 95 | 96 | @cli.command('electrostatic',short_help="Get electrostatic energy of current system") 97 | @click.argument('number', type=int,nargs=1) 98 | @click.option('--wd','-w',default='.',help='your work direcroty',show_default=True, 99 | type=click.Path(exists=True,resolve_path=True),autocompletion=get_dir_name) 100 | def ewald(wd,number): 101 | outcar = os.path.join(wd,'OUTCAR') 102 | click.echo(': '.join(get_ele_sta(outcar, number))) 103 | 104 | 105 | def get_gap(EV,vo,co): 106 | gap_res = EV.get_gap(vo,co) 107 | if isinstance(gap_res,int): 108 | click.echo('gap: '+str(0)) 109 | else: 110 | if len(gap_res) == 3: 111 | click.echo('vbm: ' + str(gap_res[0])+ 112 | '\ncbm: '+str(gap_res[1])+'\ngap: '+str(gap_res[2])) 113 | elif len(gap_res) == 2: 114 | click.echo('This is a spin system') 115 | click.echo('vbm_up: ' + str(gap_res[0][0])+ 116 | '\ncbm_up: '+str(gap_res[0][1])+'\ngap_up: '+str(gap_res[0][2])) 117 | click.echo('vbm_down: ' + str(gap_res[1][0])+ 118 | '\ncbm_down: '+str(gap_res[1][1])+'\ngap_down: '+str(gap_res[1][2])) 119 | 120 | def get_ele_sta(no_defect_outcar,number): 121 | number = int(number) 122 | tmp_match_line = _get_line(no_defect_outcar,rematch='electrostatic') 123 | rows = number // 5 124 | col = number - rows * 5 - 1 125 | if col == -1: 126 | rows -= 1 127 | col = 4 128 | tmp_line = lc.getlines(no_defect_outcar)[tmp_match_line[0]+rows+3].split() 129 | return [str(i) for i in tmp_line[2*col:2*col+2]] 130 | 131 | def _get_line(file_tmp,rematch=None): 132 | grep_res = subprocess.Popen(['grep', rematch, file_tmp,'-n'],stdout=subprocess.PIPE) 133 | return [int(ii) - 1 for ii in subprocess.check_output(['cut','-d',':','-f','1'],stdin=grep_res.stdout).decode('utf-8').split()] 134 | 135 | 136 | @cli.command('extend_spec_direc', short_help="Expanding cell in specific direction") 137 | @click.argument('pcell_filename', metavar='', 138 | type=click.Path(exists=True, resolve_path=True, readable=True, file_okay=True), 139 | autocompletion=get_poscar_files) 140 | @click.option('--volume', '-v', nargs=3, type=int, metavar=' ',default=(1,1,1), 141 | help="Expand cell to supercell of dismension ") 142 | def extend_spec_direc(pcell_filename, volume): 143 | """ 144 | First parameter: filename, the path of your initial POSCAR 145 | 146 | Sencond parameter: volume, the volume you want to extend 147 | 148 | Example: 149 | 150 | pyvasp extend_spec_direc -v 2 2 2 POSCAR 151 | """ 152 | pcell = read_vasp(pcell_filename) 153 | supcell = pcell.extend(np.diag(volume)) 154 | write_vasp(supcell, 'supcell') 155 | 156 | 157 | @cli.command('extend_spec_vol', short_help="Expanding primitive cell to specific range of volumes.") 158 | @click.argument('pcell_filename', metavar='', 159 | type=click.Path(exists=True, resolve_path=True, readable=True, file_okay=True), 160 | autocompletion=get_poscar_files) 161 | @click.option('--dimension', '-d', type=int, default=3, 162 | help="Dimension of the system, 2 for slab. Defalut=3 for crystal") 163 | @click.option('--volume', '-v', nargs=2, type=int, metavar=' ', 164 | help="Expand primitive cell to supercell of volume to , set as -1 for creating only volume expanded supercells") 165 | @click.option('--symprec', '-s', type=float, default=1e-5, 166 | help="Symmetry precision to decide the symmetry of primitive cell. Default=1e-5") 167 | @click.option('--comprec', '-p', type=float, default=1e-5, 168 | help="Compare precision to judging if supercell is redundant. Defalut=1e-5") 169 | @click.option('--verbose', '-vvv', is_flag=True, metavar='', 170 | help="Will print verbose messages.") 171 | def extend_specific_volume(pcell_filename, dimension, volume, symprec, comprec, verbose): 172 | """ 173 | Primitive cell structure file, now only vasp POSCAR version5 supported. 174 | """ 175 | pcell = read_vasp(pcell_filename) 176 | comment = 'cell' 177 | (min_v, max_v) = volume 178 | if min_v == -1: 179 | click.echo("Expanding primitive to volume {:d}".format(max_v)) 180 | _export_supercell(pcell, comment, dimension, max_v, symprec, comprec, verbose) 181 | else: 182 | for v in range(min_v, max_v + 1): 183 | click.echo("Expanding primitive to volume {:d}".format(v)) 184 | _export_supercell(pcell, comment, dimension, v, symprec, comprec, verbose) 185 | 186 | 187 | def _export_supercell(pcell, comment, dimension, v, symprec, comprec, verbose): 188 | 189 | cells = cells_nonredundant( 190 | pcell, v, dimension, symprec=symprec, comprec=comprec) 191 | for idx, c in enumerate(cells): 192 | if verbose: 193 | print(" " + "No.{:d}: Processing".format(idx)) 194 | filename = '{:s}_v{:d}_id{:d}'.format(comment, v, idx) 195 | write_vasp(c, filename) 196 | 197 | 198 | @cli.command('get_point_defect',short_help="Get purity POSCAR") 199 | @click.argument('poscar', metavar='', 200 | type=click.Path(exists=True, resolve_path=True, readable=True, file_okay=True), 201 | autocompletion=get_poscar_files) 202 | @click.option('--doped_in', '-i', default='Vac', type=str, nargs=1, 203 | help='the element you want to dope into the system') 204 | @click.option('--doped_out', '-o', default='all', type=str, nargs=1, 205 | help='the element you want to remove out of the system') 206 | @click.option('--symprec', '-s', default='1e-3', type=float, 207 | help='system precision') 208 | @click.option('--num', '-n', default='1', type=str, nargs=1, 209 | help='the number of elements you want to substitute') 210 | def get_point_defect(poscar,doped_in,doped_out,num,symprec): 211 | """ 212 | argument: 213 | 214 | poscar, the path of your initial POSCAR 215 | 216 | doped_in, the element you want to put into the system 217 | 218 | doped_out, the element you want to remove out of the system 219 | 220 | Optional parameter: 221 | num: the number of element you want to put, the default is 1 222 | sympre: system precision 223 | 224 | Example: 225 | 226 | pyvasp get_point_defect -i Fe,Ti -o Si -n 2,3 POSCAR 227 | """ 228 | DM = DefectMaker(no_defect=poscar) 229 | doped_out,doped_in,num = doped_out.split(','),doped_in.split(','),num.split(',') 230 | try: 231 | num = [int(i) for i in num] 232 | except: 233 | if num[0].lower() == "all": 234 | num = None 235 | else: 236 | raise ValueError(num+" is not supported here") 237 | DM.get_point_defect(doped_in=doped_in,doped_out=doped_out,symprec=symprec,num=num) 238 | 239 | 240 | @cli.command('get_magnetic_config',short_help="Get magnetic configurations") 241 | @click.argument('poscar', metavar='', 242 | type=click.Path(exists=True, resolve_path=True, readable=True, file_okay=True), 243 | autocompletion=get_poscar_files) 244 | @click.option('--magnetic_atom', '-ma', default='all', type=str, nargs=1, 245 | help='specify a magnetic atom') 246 | @click.option('--symprec', '-s', default='1e-3', type=float,help='system precision') 247 | @click.option('--magmon', '-m', default=1, type=int,help='magmon') 248 | @click.option('--magmon_identity', '-mi', default=False, type=bool,help='equivalent atoms with equivalent spin') 249 | def get_magnetic_config(poscar,magnetic_atom,magmon,magmon_identity,symprec): 250 | """ 251 | argument: 252 | poscar, the path of your initial POSCAR 253 | Optional parameter: 254 | magnetic_atom, specify a magnetic atom 255 | magmon, magmon 256 | magmon_identity, the equivalent atoms will have equivalent spins. (True or False) 257 | sympre: system precision 258 | Example: 259 | pyvasp get_magnetic_config POSCAR -ma Fe -m 3 -mi True 260 | """ 261 | DM = DefectMaker(no_defect=poscar) 262 | DM.get_magnetic_config([magnetic_atom],magmon,magmon_identity,symprec) 263 | 264 | 265 | @cli.command('get_mole_point_defect',short_help="Get purity POSCAR of molecule") 266 | @click.argument('poscar', metavar='', 267 | type=click.Path(exists=True, resolve_path=True, readable=True, file_okay=True), 268 | autocompletion=get_poscar_files) 269 | @click.option('--doped_in', '-i', default='Vac', type=str, nargs=1, 270 | help='the element you want to dope into the system') 271 | @click.option('--doped_out', '-o', default='all', type=str, nargs=1, 272 | help='the element you want to remove out of the system') 273 | @click.option('--symprec', '-s', default='1e-3', type=float, 274 | help='system precision') 275 | @click.option('--num', '-n', default='1', type=str, nargs=1, 276 | help='the number of elements you want to substitute') 277 | def get_mole_point_defect(poscar,doped_in,doped_out,num,symprec): 278 | """ 279 | argument: 280 | 281 | poscar, the path of your initial POSCAR 282 | 283 | doped_in, the element you want to put into the system 284 | 285 | doped_out, the element you want to remove out of the system 286 | 287 | Optional parameter: 288 | num: the number of element you want to put, the default is 1 289 | sympre: system precision 290 | 291 | Example: 292 | 293 | pyvasp get_mole_point_defect -i Fe,Ti -o Si -n 2,3 POSCAR 294 | """ 295 | DM = DefectMaker(no_defect=poscar) 296 | doped_in,num = doped_in.split(','),num.split(',') 297 | DM.get_mole_point_defect(doped_in=doped_in,doped_out=doped_out,symprec=symprec,num=[int(i) for i in num]) 298 | 299 | 300 | 301 | @cli.command('get_tetrahedral',short_help="Get get tetrahedral sites of POSCAR") 302 | @click.argument('poscar', metavar='', 303 | type=click.Path(exists=True, resolve_path=True, readable=True, file_okay=True), 304 | autocompletion=get_poscar_files) 305 | @click.option('--doped_in','-i', default='H', type=str,show_default=True) 306 | @click.option('--isunique','-u', default=False, type=bool) 307 | @click.option('--min_d','-d',default=1.5,type=float,show_default=True) 308 | def get_tetrahedral_poscar(poscar,doped_in,isunique,min_d): 309 | """ 310 | argument: 311 | 312 | poscar, the path of your initial POSCAR 313 | 314 | doped_in, the element you want to put into the system 315 | 316 | Example: 317 | 318 | pyvasp get_tetrahedral_poscar -i H POSCAR 319 | """ 320 | DM = DefectMaker(no_defect=poscar) 321 | DM.get_tetrahedral_defect(isunique=isunique,doped_in=doped_in,min_d=min_d) 322 | 323 | 324 | def get_symmetry_attr(ctx, args, incomplete): 325 | return [k for k in ['space_group','equivalent_atoms','primitive_cell'] if k.startswith(incomplete)] 326 | 327 | 328 | @cli.command('symmetry',short_help="Get symmetry of POSCAR") 329 | @click.argument('attr', type=str,autocompletion=get_symmetry_attr) 330 | @click.argument('poscar', metavar='', 331 | type=click.Path(exists=True, resolve_path=True, readable=True, file_okay=True), 332 | autocompletion=get_poscar_files) 333 | @click.option('--sympre','-s', default=1e-3, type=float) 334 | def symmetry(poscar,attr,sympre): 335 | """ 336 | argument: 337 | 338 | poscar, the path of your initial POSCAR 339 | 340 | attr, the attribute you want to get 341 | 342 | Example: 343 | 344 | pyvasp symmetry space POSCAR # get space_group 345 | 346 | pyvasp symmetry equivalent POSCAR # get equivalent_atoms 347 | 348 | pyvasp symmetry primitive POSCAR # get primitive cell 349 | """ 350 | c = read_vasp(poscar) 351 | if 'space' in attr or 'group' in attr: 352 | print('Space group: ', c.get_spacegroup(sympre)) 353 | elif 'equiv' in attr: 354 | equ_atom = c.get_symmetry(sympre)['equivalent_atoms'] 355 | atom_type = np.unique(equ_atom) 356 | atom_species,k = {},1 357 | for ii in atom_type: 358 | atom_species[k] = np.where(equ_atom==ii)[0]+1 359 | k += 1 360 | for key, val in atom_species.items(): 361 | print(key,val) 362 | elif 'primi' in attr: 363 | if c.is_primitive(sympre): 364 | click.echo('This poscar is a primitive cell, or you can decrease symprec to try to get a primitive cell') 365 | return 366 | pc = c.get_primitive_cell(sympre) 367 | write_vasp(pc,'primitive_cell') 368 | 369 | 370 | @cli.command('incar',short_help="Prepare INCAR for vasp calculation") 371 | @click.option('--attribute','-a', default='', type=str) 372 | @click.option('--incar_file','-f', default=None, 373 | type=click.Path(exists=True, resolve_path=True, readable=True, file_okay=True)) 374 | def incar(attribute,incar_file): 375 | ''' 376 | Example: 377 | 378 | pyvasp incar -f INCAR -a NSW=100,EDIFF=1e-6 379 | 380 | For more help you can refer to 381 | 382 | https://pyvaspflow.readthedocs.io/zh_CN/latest/incar.html 383 | ''' 384 | wi(incar_file=incar_file,kw=us.get_kw(attribute)) 385 | 386 | 387 | @cli.command('kpoints',short_help="Prepare KPOINTS for vasp calculation") 388 | @click.argument('poscar_file', type=str,autocompletion=get_poscar_files) 389 | @click.option('--attribute','-a', default='', type=str) 390 | def kpoints(poscar_file,attribute): 391 | ''' 392 | Example: 393 | 394 | pyvasp kpoints POSCAR -a kppa=3000,style=gamma 395 | 396 | For more help you can refer to 397 | 398 | https://pyvaspflow.readthedocs.io/zh_CN/latest/kpoints.html 399 | ''' 400 | wk(poscar_file,kw=us.get_kw(attribute)) 401 | 402 | 403 | @cli.command('prep_single_vasp',short_help="Prepare necessary files for single vasp calculation") 404 | @click.argument('poscar', type=str, autocompletion=get_poscar_files) 405 | @click.option('--attribute','-a', default='', type=str) 406 | def prep_single_vasp(poscar,attribute): 407 | ''' 408 | Example: 409 | 410 | pyvasp prep_single_vasp POSCAR -a functional=paw_LDA,sym_potcar_map=Zr_sv,NSW=100,style=band 411 | 412 | For more help you can refer to 413 | 414 | https://pyvaspflow.readthedocs.io/zh_CN/latest/prepare.html#prep-single-vasp 415 | ''' 416 | psv(poscar=poscar,kw=us.get_kw(attribute)) 417 | 418 | 419 | @cli.command('run_single_vasp',short_help="run single vasp calculation") 420 | @click.argument('job_name', metavar='',nargs=1,autocompletion=get_dir_name) 421 | @click.option('--cpu_num','-n',default=24,type=int) 422 | @click.option('--cwd','-d',default="",nargs=1,type=str) 423 | @click.option('--main_pid','-m',default=None,nargs=1,type=str) 424 | def run_single_vasp(job_name,cpu_num,cwd,main_pid): 425 | ''' 426 | Example: 427 | 428 | pyvasp run_ringle_vasp task & 429 | 430 | For more help you can refer to 431 | 432 | https://pyvaspflow.readthedocs.io/zh_CN/latest/execute.html#execute-single-vasp-task 433 | ''' 434 | rsv(job_name=job_name,cpu_num=cpu_num,cwd=cwd,main_pid=main_pid) 435 | 436 | 437 | @cli.command('run_single_vasp_without_job',short_help="run single vasp calculation") 438 | @click.argument('job_name', metavar='',nargs=1,autocompletion=get_dir_name) 439 | @click.option('--node_name','-nname',default="short_q",type=str) 440 | @click.option('--cpu_num','-cnum',default='1',nargs=1,type=str) 441 | @click.option('--node_num','-nnum',default=1,nargs=1,type=int) 442 | @click.option('--cwd','-d',default="",nargs=1,type=str) 443 | @click.option('--main_pid','-m',default=None,nargs=1,type=str) 444 | def run_single_vasp_without_job(job_name,node_name,cpu_num,node_num,cwd,main_pid): 445 | ''' 446 | Example: 447 | 448 | pyvasp run_ringle_vasp task & 449 | 450 | For more help you can refer to 451 | 452 | https://pyvaspflow.readthedocs.io/zh_CN/latest/execute.html#execute-single-vasp-task 453 | ''' 454 | # import pdb;pdb.set_trace() 455 | node_name,cpu_num = node_name.split(','),cpu_num.split(',') 456 | if len(cpu_num) != len(node_name): 457 | raise ValueError("The length of node_name is not consistent with the length of cpu_num") 458 | rsvwj(job_name,node_name,cpu_num,node_num=1,cwd=cwd,main_pid=main_pid) 459 | 460 | 461 | 462 | def get_prep_end_job_num(ctx, args, incomplete): 463 | dir_names = [i for i in os.listdir() if os.path.isfile(i)] 464 | prefix = 'POSCAR' 465 | max_num = [] 466 | for dir_name in dir_names: 467 | if dir_name.startswith(prefix): 468 | res = re.search('\d+',dir_name) 469 | if res: 470 | max_num.append(int(float(res.group()))) 471 | return [str(max(max_num))] 472 | 473 | @cli.command('prep_multi_vasp',short_help="Prepare necessary files for multiple vasp calculation") 474 | @click.argument('end_job_num', metavar='',nargs=1,autocompletion=get_prep_end_job_num) 475 | @click.option('--attribute','-a', default='', type=str) 476 | @click.option('--start_job_num','-s', default=0, type=int) 477 | def prep_multi_vasp(attribute,start_job_num,end_job_num): 478 | ''' 479 | Example: 480 | 481 | pyvasp prep_multi_vasp -s 2 -a kppa=4000,node_name=super_q,cpu_num=12,job_name=struc_opt 20 482 | 483 | prepare multiple vasp task from POSCAR2 to POSCAR20 484 | 485 | For more help you can refer to 486 | 487 | https://pyvaspflow.readthedocs.io/zh_CN/latest/prepare.html#prep-multi-vasp 488 | ''' 489 | pmv(start_job_num,int(end_job_num),kw=us.get_kw(attribute)) 490 | 491 | 492 | 493 | def get_job_name(ctx, args, incomplete): 494 | dir_names = [i for i in os.listdir() if os.path.isdir(i)] 495 | prefix_list = [] 496 | num_list = [] 497 | if len(dir_names) == 0: 498 | return ["Not found any directory"] 499 | for dir_name in dir_names: 500 | res = re.match('([^\d]+?)(\d+)',dir_name) 501 | if res: 502 | prefix = res.groups()[0] 503 | num = 0 504 | for _dir_name in dir_names: 505 | if _dir_name.startswith(prefix): 506 | num += 1 507 | prefix_list.append([prefix]) 508 | num_list.append(num) 509 | return prefix_list[np.argmax(num_list)] 510 | 511 | def get_run_end_job_num(ctx, args, incomplete): 512 | dir_names = [i for i in os.listdir() if os.path.isdir(i)] 513 | prefix_list = [] 514 | num_list = [] 515 | for dir_name in dir_names: 516 | res = re.match('([^\d]+?)(\d+)',dir_name) 517 | if res: 518 | prefix = res.groups()[0] 519 | num = 0 520 | for _dir_name in dir_names: 521 | if _dir_name.startswith(prefix): 522 | num += 1 523 | prefix_list.append(prefix) 524 | num_list.append(num) 525 | prefix = prefix_list[np.argmax(num_list)] 526 | max_num = [] 527 | for dir_name in dir_names: 528 | if dir_name.startswith(prefix): 529 | res = re.match('([^\d]+?)(\d+)',dir_name) 530 | if res: 531 | max_num.append(int(float(res.groups()[1]))) 532 | return [str(max(max_num))] 533 | 534 | 535 | @cli.command('run_multi_vasp',short_help="run multiple vasp calculations") 536 | @click.argument('job_name', metavar='',nargs=1,autocompletion=get_job_name) 537 | @click.argument('end_job_num', metavar='',nargs=1,autocompletion=get_run_end_job_num) 538 | @click.option('--start_job_num','-s', default=0, type=int) 539 | @click.option('--par_job_num','-p', default=4, type=int) 540 | def run_multi_vasp(job_name,end_job_num,start_job_num,par_job_num): 541 | ''' 542 | Example: 543 | 544 | pyvasp run_multi_vasp -s 3 -p 6 task 20 & 545 | 546 | run multiple vasp task from task3 to task20 with 6 nodes in queue 547 | 548 | For more help you can refer to 549 | 550 | https://pyvaspflow.readthedocs.io/zh_CN/latest/execute.html#execute-multiple-vasp-tasks 551 | ''' 552 | rmv(job_name=job_name,end_job_num=end_job_num, 553 | start_job_num=start_job_num,par_job_num=par_job_num) 554 | pid = os.getpid() 555 | os.remove(os.path.join(os.path.expanduser("~"),'.config','pyvaspflow',str(pid))) 556 | 557 | 558 | @cli.command('run_multi_vasp_from_shell',short_help="run multiple vasp calculations from shell scripts") 559 | @click.argument('shell_file', metavar='',nargs=1) 560 | @click.argument('end_job_num', metavar='',nargs=1,autocompletion=get_run_end_job_num) 561 | @click.option('--work_name','-w', default='job', type=str) 562 | @click.option('--start_job_num','-s', default=0, type=int) 563 | @click.option('--par_job_num','-p', default=4, type=int) 564 | def run_multi_vasp_from_shell(work_name,shell_file,end_job_num,start_job_num,par_job_num): 565 | ''' 566 | Example: 567 | 568 | nohup pyvasp run_multi_vasp_from_shell band.sh 9 -w job -p 5 1>std 2>err & 569 | 570 | For more help you can refer to 571 | 572 | https://pyvaspflow.readthedocs.io/zh_CN/latest/execute.html#execute-multiple-vasp-tasks 573 | ''' 574 | rmvws(work_name,shell_file,end_job_num=end_job_num,start_job_num=start_job_num,job_list=None,par_job_num=par_job_num) 575 | pid = os.getpid() 576 | os.remove(os.path.join(os.path.expanduser("~"),'.config','pyvaspflow',str(pid))) 577 | 578 | 579 | @cli.command('run_multi_vasp_without_job',short_help="run multiple vasp calculations without job files") 580 | @click.argument('job_name', metavar='',nargs=1,autocompletion=get_job_name) 581 | @click.argument('end_job_num', metavar='',nargs=1,autocompletion=get_run_end_job_num) 582 | @click.option('--node_num','-nnum',default=1,nargs=1,type=int) 583 | @click.option('--node_name','-nname',default="short_q",type=str) 584 | @click.option('--cpu_num','-cnum',default=24,type=str) 585 | @click.option('--start_job_num','-s', default=0, type=int) 586 | @click.option('--par_job_num','-p', default=4, type=int) 587 | def run_multi_vasp_without_job(job_name,end_job_num,node_name,cpu_num,node_num,start_job_num,par_job_num): 588 | ''' 589 | Example: 590 | 591 | pyvasp run_multi_vasp_without_job task 5 --node_name test_q --cpu_num 24 592 | 593 | run multiple vasp task from task0 to task5 through test_q node whith 24 cpu 594 | 595 | For more help you can refer to 596 | 597 | https://pyvaspflow.readthedocs.io/zh_CN/latest/execute.html#run-multi-vasp-without-job 598 | ''' 599 | node_name,cpu_num = node_name.split(','),cpu_num.split(',') 600 | if len(cpu_num) != len(node_name): 601 | raise ValueError("The length of node_name is not consistent with the length of cpu_num") 602 | rmvwj(job_name=job_name,end_job_num=end_job_num,node_name=node_name,cpu_num=cpu_num, 603 | node_num=node_num,start_job_num=start_job_num,par_job_num=par_job_num) 604 | pid = os.getpid() 605 | os.remove(os.path.join(os.path.expanduser("~"),'.config','pyvaspflow',str(pid))) 606 | 607 | 608 | 609 | @cli.command('run_multi_vasp_from_file',short_help="run multiple vasp calculations from file") 610 | @click.argument('job_name', metavar='',nargs=1,autocompletion=get_job_name) 611 | @click.argument('job_list_file', metavar='',nargs=1) 612 | @click.option('--par_job_num','-p', default=4, type=int) 613 | def run_multi_vasp_from_file(job_name,job_list_file,par_job_num): 614 | ''' 615 | Example: 616 | 617 | pyvasp run_multi_vasp task job_list_file 618 | 619 | For more help you can refer to 620 | 621 | https://pyvaspflow.readthedocs.io/zh_CN/latest/execute.html#run-multi-vasp-from-file 622 | ''' 623 | job_list = np.loadtxt(job_list_file,dtype=int) 624 | rmv(job_name=job_name,job_list=job_list,par_job_num=par_job_num) 625 | pid = os.getpid() 626 | os.remove(os.path.join(os.path.expanduser("~"),'.config','pyvaspflow',str(pid))) 627 | 628 | 629 | @cli.command('run_multi_vasp_without_job_from_file',short_help="run multiple vasp calculations") 630 | @click.argument('job_name', metavar='',nargs=1,autocompletion=get_job_name) 631 | @click.argument('job_list_file', metavar='',nargs=1) 632 | @click.option('--node_num','-nnum',default=1,nargs=1,type=int) 633 | @click.option('--node_name','-nname',default="short_q",nargs=1,type=str) 634 | @click.option('--cpu_num','-cnum',default=24,nargs=1,type=str) 635 | @click.option('--start_job_num','-s', default=0, type=int) 636 | @click.option('--par_job_num','-p', default=4, type=int) 637 | def run_multi_vasp_without_job_from_file(job_name,job_list_file,node_name,cpu_num,node_num,start_job_num,par_job_num): 638 | ''' 639 | Example: 640 | 641 | pyvasp run_multi_vasp_without_job_from_file task job_list_file --node_name test_q --cpu_num 24 642 | 643 | run multiple vasp task from job_list_file through test_q node whith 24 cpu 644 | 645 | For more help you can refer to 646 | 647 | https://pyvaspflow.readthedocs.io/zh_CN/latest/execute.html#run-multi-vasp-without-job-from-file 648 | ''' 649 | job_list = np.loadtxt(job_list_file,dtype=int) 650 | node_name,cpu_num = node_name.split(','),cpu_num.split(',') 651 | if len(cpu_num) != len(node_name): 652 | raise ValueError("The length of node_name is not consistent with the length of cpu_num") 653 | rmvwj(job_name=job_name,job_list=job_list,node_name=node_name,cpu_num=cpu_num, 654 | node_num=node_num,start_job_num=start_job_num,par_job_num=par_job_num) 655 | pid = os.getpid() 656 | os.remove(os.path.join(os.path.expanduser("~"),'.config','pyvaspflow',str(pid))) 657 | 658 | @cli.command('test_encut',short_help="test encut in vasp calculation") 659 | @click.argument('poscar', type=str, autocompletion=get_poscar_files) 660 | @click.option('-start','-s', default=0.8,type=float) 661 | @click.option('--end','-e', default=1.3,type=float) 662 | @click.option('--step','-t', default=10,type=float) 663 | @click.option('--attribute','-a', default='',type=str) 664 | @click.option('--is_login_node','-i',default=False,type=bool) 665 | def test_encut(poscar,start,end,step,attribute,is_login_node): 666 | ''' 667 | Example: 668 | 669 | pyvasp test_encut POSCAR -s 0.8 -e 1.3 -t 30 670 | 671 | For more help you can refer to 672 | 673 | https://pyvaspflow.readthedocs.io/zh_CN/latest/test_para.html#id2 674 | ''' 675 | tp = test_para.TestParameter(poscar=poscar) 676 | kw = {'start':start,'end':end,'step':step,'is_login_node':is_login_node} 677 | kw.update(us.get_kw(attribute)) 678 | tp.test_encut(kw=kw) 679 | 680 | 681 | @cli.command('test_kpts',short_help="test kpoints in vasp calculation") 682 | @click.argument('poscar', type=str, autocompletion=get_poscar_files) 683 | @click.option('-start','-s', default=2000,type=int) 684 | @click.option('--end','-e', default=4000,type=int) 685 | @click.option('--step','-t', default=300,type=int) 686 | @click.option('--attribute','-a', default='',type=str) 687 | @click.option('--is_login_node','-i',default=False,type=bool) 688 | @click.option('--run','-r',default=True,type=bool) 689 | def test_kpts(poscar,start,end,step,attribute,is_login_node,run): 690 | ''' 691 | Example: 692 | 693 | pyvasp test_kpts POSCAR -s 1000 -e 3000 -t 200 694 | 695 | For more help you can refer to 696 | 697 | https://pyvaspflow.readthedocs.io/zh_CN/latest/test_para.html#k 698 | ''' 699 | tp = test_para.TestParameter(poscar=poscar) 700 | kw = {'start':start,'end':end,'step':step,'is_login_node':is_login_node} 701 | kw.update(us.get_kw(attribute)) 702 | tp.test_kpts(kw=kw,run=run) 703 | 704 | 705 | 706 | 707 | 708 | 709 | @cli.command('get_def_form_energy',short_help="get defect formation energy") 710 | @click.argument('data_dir', metavar='',nargs=1, 711 | autocompletion=get_dir_name) 712 | @click.argument('defect_dirs', metavar='', 713 | nargs=-1,autocompletion=get_dir_name) 714 | def get_def_form_energy(data_dir,defect_dirs): 715 | get_defect_formation_energy(data_dir,defect_dirs) 716 | 717 | @cli.command('save_pdos',short_help="save your DOS to txt file") 718 | @click.option('--wd','-w',default='.') 719 | def save_pdos(wd): 720 | read_doscar(wd) 721 | 722 | @cli.command('kill',short_help="kill the pyvasp and cancel jobs have been submitted") 723 | @click.argument('pid', metavar='pid_of_pyvasp',nargs=1) 724 | @click.option('--cancel_or_not','-c',default=True,type=bool) 725 | def kill(pid,cancel_or_not): 726 | parent = psutil.Process(int(pid)) 727 | for child in parent.children(recursive=True): # or parent.children() for recursive=False 728 | child.kill() 729 | parent.kill() 730 | click.echo(pid) 731 | job_id_file = os.path.join(os.path.expanduser("~"),'.config','pyvaspflow',str(pid)) 732 | with open(job_id_file,'r') as f: 733 | job_idx = f.readlines() 734 | if cancel_or_not: 735 | for idx in job_idx: 736 | os.system('scancel '+str(idx)) 737 | os.remove(job_id_file) 738 | 739 | 740 | if __name__ == "__main__": 741 | cli() 742 | -------------------------------------------------------------------------------- /pyvaspflow/utils.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from sagar.toolkit.mathtool import refine_positions 3 | from sagar.molecule.structure import Molecule 4 | from sagar.crystal.utils import non_dup_hnfs, snf 5 | from sagar.io.vasp import write_vasp, read_vasp 6 | from sagar.toolkit.derivetool import remove_redundant 7 | from sagar.crystal.structure import Cell 8 | from sagar.element.base import periodic_table_dict as ptd 9 | from sagar.toolkit.mathtool import is_int_np_array 10 | from sagar.crystal.derive import PermutationGroup as PG 11 | from pyvaspflow.io.vasp_out import ExtractValue 12 | from sagar.element.base import periodic_table_dict as ptd 13 | from itertools import combinations 14 | from os import path 15 | import configparser 16 | 17 | 18 | def refine_points(tetra,extend_S,C,min_d=1): 19 | n = np.shape(tetra)[0] 20 | tetra_cen = np.zeros((n,3)) 21 | for ii in range(n): 22 | tetra_cen[ii] = np.mean(extend_S[tetra[ii]],axis=0) 23 | tetra_cen = [cen for cen in tetra_cen if min(np.linalg.norm(cen-extend_S,axis=1))>1.5] 24 | final_res = [] 25 | for cen in tetra_cen: 26 | d = np.linalg.norm(cen-tetra_cen,axis=1) 27 | d = d[d>0] 28 | if min(d) > min_d: 29 | final_res.append(cen) 30 | if len(final_res) == 0: 31 | return np.array([]) 32 | final_res = np.dot(final_res,np.linalg.inv(C)) 33 | final_res = np.unique(np.round(final_res,decimals=3),axis=0) 34 | final_res[final_res>0.99] = 0 35 | final_res[final_res<0.01] = 0 36 | return np.unique(final_res,axis=0) 37 | 38 | 39 | def write_poscar(cell,folder='.',idx=0,comment=""): 40 | filename = '{:s}{:s}'.format('POSCAR'+comment, str(idx)) 41 | file = path.join(folder, filename) 42 | write_vasp(cell,file,suffix='') 43 | 44 | 45 | def get_delete_atom_num(no_defect_poscar,one_defect_poscar): 46 | no_defect = read_vasp(no_defect_poscar) 47 | one_defect = read_vasp(one_defect_poscar) 48 | no_def_pos = no_defect.positions 49 | one_def_pos = one_defect.positions 50 | no_def_pos[abs(no_def_pos-1) < 0.01] = 0 51 | one_def_pos[abs(one_def_pos-1) < 0.01] = 0 52 | if len(no_defect.atoms)-1 == len(one_defect.atoms): 53 | num = no_def_pos.shape[0] 54 | for ii in range(num): 55 | d = np.linalg.norm(no_def_pos[ii] - one_def_pos,axis=1) 56 | if min(d) > 0.1: 57 | break 58 | _no_def_pos = np.unique(np.delete(no_def_pos,ii,0),axis=0) 59 | _one_def_pos = np.unique(one_def_pos,axis=0) 60 | d = 0 61 | for i in _no_def_pos: 62 | d = d + min(np.linalg.norm(i - _one_def_pos,axis=1)) 63 | for key,val in ptd.items(): 64 | if val == no_defect.atoms[ii]: 65 | rm_atom = key 66 | break 67 | print('This is a vacancy defect','atom: \n', 68 | rm_atom,ii+1,'in the defect-free POSCAR has benn removed') 69 | with open('element-in-out','w') as f: 70 | f.writelines(str(rm_atom)+'='+str(1)+'\n') 71 | f.writelines('Vacc=-1 \n') 72 | return ii,d 73 | elif len(no_defect.atoms) == len(one_defect.atoms): 74 | no_def_atoms,def_atoms = np.unique(no_defect.atoms),np.unique(one_defect.atoms) 75 | purity_atom = np.setdiff1d(def_atoms,no_def_atoms) 76 | if len(purity_atom) != 0: # introduce a new atom purity 77 | idx = np.where(one_defect.atoms==purity_atom)[0] 78 | d = np.linalg.norm(one_def_pos[idx]-no_def_pos,axis=1) 79 | ii,d = np.argmin(d), np.min(d) 80 | for key,val in ptd.items(): 81 | if val == no_defect.atoms[ii]: 82 | rm_atom = key 83 | if val == purity_atom: 84 | in_atom = key 85 | print('This is a purity defect','atom: \n', 86 | rm_atom, ii+1,'in the defect-free POSCAR has benn dopped by', in_atom) 87 | with open('element-in-out','w') as f: 88 | f.writelines(str(rm_atom)+'='+str(1)+'\n') 89 | f.writelines(str(in_atom)+'='+str(-1)+'\n') 90 | return ii,d 91 | else: 92 | purity_atom = [] 93 | for _atom in no_def_atoms: 94 | idx_num_1,idx_num_2 = len(np.where(_atom==no_defect.atoms)[0]),len(np.where(_atom==one_defect.atoms)[0]) 95 | if abs(idx_num_2-idx_num_1) == 1: 96 | purity_atom.append(_atom) 97 | elif abs(idx_num_1-idx_num_2) > 1: 98 | raise ValueError("The POSCAR has two or more defect atoms") 99 | if len(purity_atom) > 2: 100 | raise ValueError("The POSCAR has two or more defect atoms") 101 | no_def_pos_0 = no_def_pos[no_defect.atoms==purity_atom[0]] 102 | no_def_pos_1 = no_def_pos[no_defect.atoms==purity_atom[1]] 103 | 104 | one_def_pos_0 = one_def_pos[one_defect.atoms==purity_atom[0]] 105 | one_def_pos_1 = one_def_pos[one_defect.atoms==purity_atom[1]] 106 | 107 | if no_def_pos_0.shape[0]- one_def_pos_0.shape[0] == 1: 108 | purity_in = purity_atom[1] 109 | purity_out = purity_atom[0] 110 | d = [min(np.linalg.norm(pos-one_def_pos_0,axis=1)) for pos in no_def_pos_0] 111 | ahead_num = np.where(no_defect.atoms==purity_out)[0][0] 112 | idx = np.argmax(d) 113 | for key,val in ptd.items(): 114 | if val == purity_out: 115 | rm_atom = key 116 | if val == purity_in: 117 | in_atom = key 118 | print('This is a purity defect','atom: \n', 119 | rm_atom, ahead_num+idx+1,'in the defect-free POSCAR has benn dopped by', in_atom) 120 | with open('element-in-out','w') as f: 121 | f.writelines(str(rm_atom)+'='+str(1)+'\n') 122 | f.writelines(str(in_atom)+'='+str(-1)+'\n') 123 | return ahead_num+idx,d[idx] 124 | else: 125 | purity_in = purity_atom[0] 126 | purity_out = purity_atom[1] 127 | d = [min(np.linalg.norm(pos-one_def_pos_1,axis=1)) for pos in no_def_pos_1] 128 | idx = np.argmax(d) 129 | ahead_num = np.where(no_defect.atoms==purity_out)[0][0] 130 | # import pdb; pdb.set_trace() 131 | for key,val in ptd.items(): 132 | if val == purity_out: 133 | rm_atom = key 134 | if val == purity_in: 135 | in_atom = key 136 | print('This is a purity defect','atom: \n', 137 | rm_atom, ahead_num+idx+1,'in the defect-free POSCAR has benn dopped by', in_atom) 138 | with open('element-in-out','w') as f: 139 | f.writelines(str(rm_atom)+'='+str(1)+'\n') 140 | f.writelines(str(in_atom)+'='+str(-1)+'\n') 141 | return ahead_num+idx,d[idx] 142 | 143 | else: 144 | print('This kind of defect is not supported here right now') 145 | 146 | 147 | 148 | def generate_all_basis(N1,N2,N3): 149 | n1,n2,n3 = 2*N1+1, 2*N2+1, 2*N3+1 150 | x = np.tile(np.arange(-N3,N3+1),n1*n2) 151 | y = np.tile(np.repeat(np.arange(-N2,N2+1),n3),n1) 152 | z = np.repeat(np.arange(-N1,N1+1),n2*n3) 153 | x,y,z = np.reshape(x,(-1,1)),np.reshape(y,(-1,1)),np.reshape(z,(-1,1)) 154 | tmp = np.hstack((z,y)) 155 | return np.hstack((tmp,x)) 156 | 157 | 158 | def get_farther_atom_num(no_defect_poscar, one_defect_poscar): 159 | ''' 160 | Return: 161 | 1: atom number of the farther atom in defect system 162 | 2: atom number of the farther atom in defect-free system 163 | ''' 164 | all_basis = generate_all_basis(1,1,1) 165 | no_defect = read_vasp(no_defect_poscar) 166 | one_defect = read_vasp(one_defect_poscar) 167 | no_def_pos = no_defect.positions 168 | one_def_pos = one_defect.positions 169 | c = no_defect.lattice 170 | no_def_pos = np.dot(no_def_pos,c) 171 | one_def_pos = np.dot(one_def_pos,c) 172 | ii,d = get_delete_atom_num(no_defect_poscar,one_defect_poscar) 173 | defect_atom = no_def_pos[ii] 174 | extend_S = [] 175 | 176 | d,idx = np.zeros((no_def_pos.shape[0],27)),0 177 | for basis in all_basis: 178 | i,j,k = basis 179 | d[:,idx] = np.linalg.norm(defect_atom-(no_def_pos+i*c[0]+j*c[1]+k*c[2]),axis=1) 180 | idx += 1 181 | max_idx_no_def = np.argmax(np.min(d,axis=1))#no-defect-farther-atom-number 182 | # import pdb;pdb.set_trace() 183 | d,idx = np.zeros((one_def_pos.shape[0],27)),0 184 | for basis in all_basis: 185 | i,j,k = basis 186 | d[:,idx] = np.linalg.norm(defect_atom-(one_def_pos+i*c[0]+j*c[1]+k*c[2]),axis=1) 187 | idx += 1 188 | max_idx_one_def = np.argmax(np.min(d,axis=1)) 189 | return max_idx_one_def+1,max_idx_no_def+1 190 | 191 | 192 | def str_delimited(results, header=None, delimiter="\t"): 193 | """ 194 | Given a tuple of tuples, generate a delimited string form. 195 | >>> results = [["a","b","c"],["d","e","f"],[1,2,3]] 196 | >>> print(str_delimited(results,delimiter=",")) 197 | a,b,c 198 | d,e,f 199 | 1,2,3 200 | Args: 201 | result: 2d sequence of arbitrary types. 202 | header: optional header 203 | Returns: 204 | Aligned string output in a table-like format. 205 | """ 206 | returnstr = "" 207 | if header is not None: 208 | returnstr += delimiter.join(header) + "\n" 209 | return returnstr + "\n".join([delimiter.join([str(m) for m in result]) 210 | for result in results]) 211 | 212 | 213 | def clean_lines(string_list, remove_empty_lines=True): 214 | for s in string_list: 215 | clean_s = s 216 | if '#' in s: 217 | ind = s.index('#') 218 | clean_s = s[:ind] 219 | clean_s = clean_s.strip() 220 | if (not remove_empty_lines) or clean_s != '': 221 | yield clean_s 222 | 223 | 224 | def zread(filename): 225 | name, ext = path.splitext(filename) 226 | ext = ext.upper() 227 | if ext in (".GZ", ".Z"): 228 | with open(filename,'rb') as f: 229 | data = f.read() 230 | return unlzw(data).decode('utf-8') 231 | else: 232 | with open(filename,'r') as f: 233 | data = f.read() 234 | return data 235 | 236 | def unlzw(data): 237 | """ 238 | This function was adapted for Python from Mark Adler's C implementation 239 | https://github.com/umeat/unlzw 240 | Decompress compressed data generated by the Unix compress utility (LZW 241 | compression, files with .Z suffix). Input can be given as any type which 242 | can be 'converted' to a bytearray (e.g. string, or bytearray). Returns 243 | decompressed data as string, or raises error. 244 | Written by Brandon Owen, May 2016, brandon.owen@hotmail.com 245 | Adapted from original work by Mark Adler - orginal copyright notice below 246 | Copyright (C) 2014, 2015 Mark Adler 247 | This software is provided 'as-is', without any express or implied 248 | warranty. In no event will the authors be held liable for any damages 249 | arising from the use of this software. 250 | Permission is granted to anyone to use this software for any purpose, 251 | including commercial applications, and to alter it and redistribute it 252 | freely, subject to the following restrictions: 253 | 1. The origin of this software must not be misrepresented; you must not 254 | claim that you wrote the original software. If you use this software 255 | in a product, an acknowledgment in the product documentation would be 256 | appreciated but is not required. 257 | 2. Altered source versions must be plainly marked as such, and must not be 258 | misrepresented as being the original software. 259 | 3. This notice may not be removed or altered from any source distribution. 260 | Mark Adler 261 | madler@alumni.caltech.edu 262 | """ 263 | 264 | # Convert input data stream to byte array, and get length of that array 265 | try: 266 | ba_in = bytearray(data) 267 | except ValueError: 268 | raise TypeError("Unable to convert inputted data to bytearray") 269 | 270 | inlen = len(ba_in) 271 | prefix = [None] * 65536 # index to LZW prefix string 272 | suffix = [None] * 65536 # one-character LZW suffix 273 | 274 | # Process header 275 | if inlen < 3: 276 | raise ValueError( 277 | "Invalid Input: Length of input too short for processing") 278 | 279 | if (ba_in[0] != 0x1f) or (ba_in[1] != 0x9d): 280 | raise ValueError( 281 | "Invalid Header Flags Byte: Incorrect magic bytes") 282 | 283 | flags = ba_in[2] 284 | 285 | if flags & 0x60: 286 | raise ValueError( 287 | "Invalid Header Flags Byte: Flag byte contains invalid data") 288 | 289 | max_ = flags & 0x1f 290 | if (max_ < 9) or (max_ > 16): 291 | raise ValueError( 292 | "Invalid Header Flags Byte: Max code size bits out of range") 293 | 294 | if (max_ == 9): 295 | max_ = 10 # 9 doesn't really mean 9 296 | 297 | flags &= 0x80 # true if block compressed 298 | 299 | # Clear table, start at nine bits per symbol 300 | bits = 9 301 | mask = 0x1ff 302 | end = 256 if flags else 255 303 | 304 | # Ensure stream is initially valid 305 | if inlen == 3: 306 | return 0 # zero-length input is permitted 307 | if inlen == 4: # a partial code is not okay 308 | raise ValueError("Invalid Data: Stream ended in the middle of a code") 309 | 310 | # Set up: get the first 9-bit code, which is the first decompressed byte, 311 | # but don't create a table entry until the next code 312 | buf = ba_in[3] 313 | buf += ba_in[4] << 8 314 | final = prev = buf & mask # code 315 | buf >>= bits 316 | left = 16 - bits 317 | if prev > 255: 318 | raise ValueError("Invalid Data: First code must be a literal") 319 | 320 | # We have output - allocate and set up an output buffer with first byte 321 | put = [final] 322 | 323 | # Decode codes 324 | mark = 3 # start of compressed data 325 | nxt = 5 # consumed five bytes so far 326 | while nxt < inlen: 327 | # If the table will be full after this, increment the code size 328 | if (end >= mask) and (bits < max_): 329 | # Flush unused input bits and bytes to next 8*bits bit boundary 330 | # (this is a vestigial aspect of the compressed data format 331 | # derived from an implementation that made use of a special VAX 332 | # machine instruction!) 333 | rem = (nxt - mark) % bits 334 | 335 | if (rem): 336 | rem = bits - rem 337 | if rem >= inlen - nxt: 338 | break 339 | nxt += rem 340 | 341 | buf = 0 342 | left = 0 343 | 344 | # mark this new location for computing the next flush 345 | mark = nxt 346 | 347 | # increment the number of bits per symbol 348 | bits += 1 349 | mask <<= 1 350 | mask += 1 351 | 352 | # Get a code of bits bits 353 | buf += ba_in[nxt] << left 354 | nxt += 1 355 | left += 8 356 | if left < bits: 357 | if nxt == inlen: 358 | raise ValueError( 359 | "Invalid Data: Stream ended in the middle of a code") 360 | buf += ba_in[nxt] << left 361 | nxt += 1 362 | left += 8 363 | code = buf & mask 364 | buf >>= bits 365 | left -= bits 366 | 367 | # process clear code (256) 368 | if (code == 256) and flags: 369 | # Flush unused input bits and bytes to next 8*bits bit boundary 370 | rem = (nxt - mark) % bits 371 | if rem: 372 | rem = bits - rem 373 | if rem > inlen - nxt: 374 | break 375 | nxt += rem 376 | buf = 0 377 | left = 0 378 | 379 | # Mark this location for computing the next flush 380 | mark = nxt 381 | 382 | # Go back to nine bits per symbol 383 | bits = 9 # initialize bits and mask 384 | mask = 0x1ff 385 | end = 255 # empty table 386 | continue # get next code 387 | 388 | # Process LZW code 389 | temp = code # save the current code 390 | stack = [] # buffer for reversed match - empty stack 391 | 392 | # Special code to reuse last match 393 | if code > end: 394 | # Be picky on the allowed code here, and make sure that the 395 | # code we drop through (prev) will be a valid index so that 396 | # random input does not cause an exception 397 | if (code != end + 1) or (prev > end): 398 | raise ValueError("Invalid Data: Invalid code detected") 399 | stack.append(final) 400 | code = prev 401 | 402 | # Walk through linked list to generate output in reverse order 403 | while code >= 256: 404 | stack.append(suffix[code]) 405 | code = prefix[code] 406 | 407 | stack.append(code) 408 | final = code 409 | 410 | # Link new table entry 411 | if end < mask: 412 | end += 1 413 | prefix[end] = prev 414 | suffix[end] = final 415 | 416 | # Set previous code for next iteration 417 | prev = temp 418 | 419 | # Write stack to output in forward order 420 | put += stack[::-1] 421 | 422 | # Return the decompressed data as string 423 | return bytes(bytearray(put)) 424 | 425 | 426 | def get_kw(attribute): 427 | kw = {} 428 | if attribute: 429 | if attribute[-1] == ",": 430 | attribute = attribute[:-1] 431 | attribute = attribute.split('=') 432 | n = len(attribute) 433 | if len(attribute[1].split(',')) == 2 : 434 | kw[attribute[0]] = attribute[1].split(',')[0] 435 | else: 436 | kw[attribute[0]] = attribute[1].split(',')[:-1] 437 | for ii in range(1,n-1): 438 | if len(attribute[ii+1].split(',')) == 2: 439 | kw[attribute[ii].split(',')[-1]] = attribute[ii+1].split(',')[0] 440 | else: 441 | kw[attribute[ii].split(',')[-1]] = attribute[ii+1].split(',')[:-1] 442 | if len(attribute[-1].split(',')) > 1: 443 | kw[attribute[-2].split(',')[-1]] = attribute[-1].split(',') 444 | else: 445 | kw[attribute[-2].split(',')[-1]] = attribute[-1] 446 | if 'kpts' in kw: 447 | kw['kpts'] = tuple(int(i) for i in kw['kpts']) 448 | if 'shift' in kw: 449 | kw['shift'] = tuple(float(i) for i in kw['shift']) 450 | return kw 451 | 452 | 453 | 454 | def get_idx_in_pri_pos(pri_pos,pos): 455 | return [np.argmin(np.linalg.norm(p-pri_pos,axis=1)) for p in pos] 456 | 457 | def _get_min_serial(perms,serial): 458 | return np.unique(np.sort(perms[:,serial],axis=1),axis=0)[0] 459 | 460 | 461 | def is_2d_structure(cell): 462 | pos = cell.positions 463 | pos_std = np.std(pos,axis=0) 464 | if min(pos_std) < 0.1*max(pos_std): 465 | idx = np.argmin(pos_std) 466 | return True,idx 467 | return False 468 | 469 | def get_grd_state(job_name,start_job_num,end_job_num): 470 | energy = [] 471 | for ii in range(start_job_num,end_job_num+1): 472 | EV = ExtractValue(data_folder=job_name+str(ii)) 473 | energy.append(EV.get_energy()) 474 | return np.argmin(energy) 475 | 476 | def get_perms(cell,str_type='crystal',symprec=1e-3): 477 | latt = cell.lattice 478 | pos = cell.positions 479 | pos = np.dot(pos,latt) 480 | if str_type == "crystal": 481 | symm = cell.get_symmetry() 482 | trans,rots = symm['translations'],symm['rotations'] 483 | perms = np.zeros((np.shape(trans)[0],len(cell.atoms))) 484 | origin_positions = refine_positions(cell.positions) 485 | for ix, rot in enumerate(rots): 486 | for iy,o_pos in enumerate(origin_positions): 487 | new_pos = np.dot(rot,o_pos.T) + trans[ix] 488 | new_pos = np.mod(new_pos,1) 489 | new_pos = refine_positions(new_pos) 490 | idx = np.argmin(np.linalg.norm(new_pos-origin_positions,axis=1)) 491 | perms[ix,iy] = idx 492 | perms_table = np.unique(perms,axis=0) 493 | else: 494 | mol = Molecule(pos,cell.atoms) 495 | perms_table = mol.get_symmetry_permutation(symprec) 496 | return perms_table 497 | 498 | def add_log_shell_file(shell_file,log_dir,main_pid): 499 | with open(shell_file,"r") as f: 500 | lines = f.readlines() 501 | new_lines = [] 502 | for line in lines: 503 | if 'pyvasp run_' in line: 504 | line = line.rstrip() 505 | line += " -d "+log_dir + " -m " + str(main_pid)+"\n" 506 | new_lines.append(line) 507 | else: 508 | new_lines.append(line) 509 | return new_lines 510 | 511 | 512 | def get_max_volume(pcell, sites, max_volume, min_volume=1, dimension=3, symprec=1e-5): 513 | for volume in range(min_volume, max_volume + 1): 514 | hnfs = non_dup_hnfs(pcell, volume, dimension, symprec) 515 | dict_trans = {} # 记录已经产生过的snf,相同snf的平移操作相同。 516 | for h in hnfs: 517 | hfpg = PG(pcell, h) 518 | perms = hfpg.get_symmetry_perms(symprec) 519 | if dimension == 2: 520 | supercell = pcell.extend(h)._get_niggli_2D() 521 | else: 522 | supercell = pcell.extend(h)._get_niggli_3D() 523 | _sites = np.repeat(sites, volume, axis=0) 524 | for mol, _ in remove_redundant(supercell.positions, _sites, perms): 525 | c = Cell(supercell.lattice, mol[0], mol[1]) 526 | if c.is_primitive(symprec): 527 | yield c 528 | 529 | def get_identity_atoms(cell,symprec,style="crystal"): 530 | atom_number = cell.atoms 531 | if style == "crystal": 532 | equ_atom = cell.get_symmetry(symprec)['equivalent_atoms'] 533 | atom_uniq_type = np.unique(equ_atom) 534 | atom_type = np.zeros(np.shape(equ_atom)) 535 | for idx,ea in enumerate(equ_atom): 536 | atom_type[idx] = np.where(atom_uniq_type==ea)[0] 537 | return atom_type 538 | 539 | 540 | def read_config(): 541 | from os import pardir,getcwd 542 | home = path.expanduser("~") 543 | wd = getcwd() 544 | if path.isfile(path.join(wd,'config.ini')): 545 | conf_file_path = path.join(wd,'config.ini') 546 | elif path.isfile(path.join(home,'.config','pyvaspflow','config.ini')): 547 | conf_file_path = path.join(home,'.config','pyvaspflow','config.ini') 548 | else: 549 | config_ini = ''' 550 | [RUN_VASP] 551 | prepend = module load vasp/5.4.4-impi-mkl 552 | exec = mpirun -n ${SLURM_NPROCS} vasp_std 553 | append = exit 554 | 555 | [POTCAR_PATH] 556 | paw_pbe = /opt/ohpc/pub/apps/vasp/pps/paw_PBE 557 | paw_lda = /opt/ohpc/pub/apps/vasp/pps/paw_LDA 558 | paw_pw91 = /opt/ohpc/pub/apps/vasp/pps/paw_PW91 559 | uspp_lda = /opt/ohpc/pub/apps/vasp/pps/USPP_LDA 560 | uspp_pw91 = /opt/ohpc/pub/apps/vasp/pps/USPP_PW91 561 | default_type = paw_pbe 562 | 563 | [Task_Schedule] 564 | default_node_name = short_q 565 | default_cpu_num = 24 566 | default_schedule = SLURM 567 | 568 | [SLURM] 569 | submission = sbatch ./job.sh 570 | job_queue = squeue 571 | node_state = sinfo 572 | 573 | [LSF] 574 | submission = bsub < ./job.lsf 575 | job_queue = bjobs 576 | node_state = bhost\n 577 | ''' 578 | home = path.expanduser("~") 579 | 580 | if not path.isdir(path.join(home,'.config')): 581 | mkdir(path.join(home,'.config')) 582 | 583 | if not path.isdir(path.join(home,'.config','pyvaspflow')): 584 | mkdir(path.join(home,'.config','pyvaspflow')) 585 | 586 | if not path.isfile(path.join(home,'.config','pyvaspflow','config.ini')): 587 | with open(path.join(home,'.config','pyvaspflow','config.ini'),'w') as outfile: 588 | outfile.write(config_ini) 589 | conf_file_path = path.join(home,'.config','pyvaspflow','config.ini') 590 | config = configparser.ConfigParser() 591 | config.read(conf_file_path) 592 | return config 593 | 594 | 595 | def clean_parse(kw,key,def_val): 596 | val = kw.get(key,def_val) 597 | kw.pop(key,None) 598 | return val,kw 599 | -------------------------------------------------------------------------------- /pyvaspflow/vasp/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChangChunHe/pyvaspflow/5976630a3b5cd05f634c5bc0146eafaff429c4a7/pyvaspflow/vasp/__init__.py -------------------------------------------------------------------------------- /pyvaspflow/vasp/prep_vasp.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3.6 2 | # -*- coding: utf-8 -*- 3 | 4 | 5 | from pyvaspflow.utils import read_config,clean_parse 6 | from os import path,makedirs,chdir,listdir 7 | from shutil import rmtree,copy2 8 | from sagar.io.vasp import read_vasp 9 | from pyvaspflow.io.vasp_input import Incar,Kpoints,Potcar 10 | import sys,progressbar 11 | from pyvaspflow.vasp.schedule import Schedule 12 | 13 | 14 | config = read_config() 15 | schedule = Schedule() 16 | 17 | 18 | 19 | def write_incar(incar_file=None,kw={}): 20 | if path.isfile('POTCAR'): 21 | with open('POTCAR') as f: 22 | data = f.readlines() 23 | enmax = 1.3*max([float(i.split()[2].replace(';','')) for i in [i for i in data if 'ENMAX' in i]]) 24 | else: 25 | enmax = None 26 | incar = Incar() 27 | if incar_file: 28 | incar.from_file(incar_file) 29 | if enmax and 'ENCUT' not in incar: 30 | incar['ENCUT'] = enmax 31 | incar.update(kw) 32 | incar.write_file('INCAR') 33 | return kw 34 | 35 | def write_potcar(poscar='POSCAR',kw={}): 36 | if not path.isfile('POTCAR'): 37 | functional,kw = clean_parse(kw,'functional','paw_PBE') 38 | sym_potcar_map,kw = clean_parse(kw,'sym_potcar_map',None) 39 | pot = Potcar(poscar=poscar,functional=functional,sym_potcar_map=sym_potcar_map) 40 | pot.write_file('POTCAR') 41 | return kw 42 | 43 | def write_kpoints(poscar='POSCAR',kw={}): 44 | if not path.isfile(poscar): 45 | raise FileNotFoundError('Not found POSCAR') 46 | stru = read_vasp(poscar) 47 | style,kw = clean_parse(kw,'style','gamma') 48 | if not path.isfile('KPOINTS'): 49 | _kpts = Kpoints() 50 | if 'auto' in style.lower(): 51 | if 'kpts' not in kw : 52 | kppa,kw = clean_parse(kw,'kppa',3000) 53 | kppa = float(kppa) 54 | _kpts.automatic_density(structure=stru,kppa=kppa) 55 | _kpts.write_file('KPOINTS') 56 | else: 57 | kpts,kw = clean_parse(kw,'kpts',(1,1,1)) 58 | shift,kw = clean_parse(kw,'shift',(0,0,0)) 59 | _kpts.gamma_automatic(kpts=kpts,shift=shift) 60 | _kpts.write_file('KPOINTS') 61 | elif 'gamma' in style.lower() and 'kpts' not in kw: 62 | kppa,kw = clean_parse(kw,'kppa',3000) 63 | kppa = float(kppa) 64 | _kpts.automatic_gamma_density(structure=stru,kppa=kppa) 65 | _kpts.write_file('KPOINTS') 66 | elif 'gamma' in style.lower() and 'kpts' in kw: 67 | kpts,kw = clean_parse(kw,'kpts',(1,1,1)) 68 | shift,kw = clean_parse(kw,'shift',(0,0,0)) 69 | _kpts.gamma_automatic(kpts=kpts,shift=shift) 70 | _kpts.write_file('KPOINTS') 71 | elif 'monk' in style.lower() and 'kpts' in kw: 72 | kpts,kw = clean_parse(kw,'kpts',(1,1,1)) 73 | shift,kw = clean_parse(kw,'shift',(0,0,0)) 74 | _kpts.monkhorst_automatic(kpts=kpts,shift=shift) 75 | _kpts.write_file('KPOINTS') 76 | elif 'band' in style.lower() or 'line' in style.lower(): 77 | num_kpts,kw = clean_parse(kw,'num_kpts',16) 78 | _kpts.automatic_linemode(structure=stru,num_kpts=int(num_kpts)) 79 | _kpts.write_file('KPOINTS') 80 | return kw 81 | 82 | 83 | 84 | def prep_single_vasp(poscar='POSCAR',kw={}): 85 | node_name,kw = clean_parse(kw,'node_name',config['Task_Schedule']['default_node_name']) 86 | cpu_num,kw = clean_parse(kw,'cpu_num',config['Task_Schedule']['default_cpu_num']) 87 | node_num,kw = clean_parse(kw,'node_num',1) 88 | job_name,kw = clean_parse(kw,'job_name','task') 89 | if path.isdir(job_name): 90 | rmtree(job_name) 91 | makedirs(job_name) 92 | chdir(job_name) 93 | copy2('../'+poscar,'./POSCAR') 94 | kw = write_potcar(kw=kw) 95 | kw = write_kpoints(kw=kw) 96 | kw = write_incar(kw=kw) 97 | chdir('..') 98 | schedule.schedule_type.write_job_file(node_name=node_name,node_num=node_num,cpu_num=cpu_num,job_name=job_name) 99 | 100 | def prep_multi_vasp(start_job_num=0,end_job_num=0,job_list=None,kw={}): 101 | node_name,kw = clean_parse(kw,'node_name',config['Task_Schedule']['default_node_name']) 102 | cpu_num,kw = clean_parse(kw,'cpu_num',config['Task_Schedule']['default_cpu_num']) 103 | node_num,kw = clean_parse(kw,'node_num',1) 104 | job_name,kw = clean_parse(kw,'job_name','task') 105 | _kw = kw.copy() 106 | if job_list is None: 107 | job_list = range(start_job_num,end_job_num+1) 108 | toolbar_width = end_job_num - start_job_num + 1 109 | with progressbar.ProgressBar(max_value=toolbar_width) as bar: 110 | for idx,ii in enumerate(job_list): 111 | if path.isdir(job_name+str(ii)): 112 | rmtree(job_name+str(ii)) 113 | makedirs(job_name+str(ii)) 114 | copy2(path.join('./POSCAR'+str(ii)),path.join(job_name+str(ii),'POSCAR')) 115 | chdir(job_name+str(ii)) 116 | kw = write_potcar(kw=kw) 117 | kw = write_kpoints(kw=kw) 118 | kw = write_incar(kw=kw) 119 | kw = _kw.copy() 120 | chdir('..') 121 | schedule.schedule_type.write_job_file(node_name=node_name,node_num=node_num,cpu_num=cpu_num,job_name=job_name+str(ii)) 122 | bar.update(idx) 123 | -------------------------------------------------------------------------------- /pyvaspflow/vasp/run_vasp.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3.6 2 | # -*- coding: utf-8 -*- 3 | 4 | 5 | from pyvaspflow.vasp import prep_vasp 6 | from pyvaspflow.utils import add_log_shell_file 7 | from time import sleep,ctime 8 | from pyvaspflow.vasp.schedule import Schedule 9 | import os,logging 10 | 11 | 12 | schedule = Schedule() 13 | 14 | def has_job_finished(folder): 15 | if (not os.path.isfile(os.path.join(folder,"EIGENVAL"))) or (not os.path.isfile(os.path.join(folder,"EIGENVAL"))): 16 | return False 17 | size = os.path.getsize(os.path.join(folder,"EIGENVAL")) + os.path.getsize(os.path.join(folder,"DOSCAR")) 18 | if size < 1000: 19 | return False 20 | return True 21 | 22 | 23 | 24 | def get_number_of_running_shell_files(shell_file,main_pid): 25 | p = subprocess.Popen(['ps', '-ef'],stdout=subprocess.PIPE) 26 | que_res = p.stdout.readlines() 27 | p.stdout.close() 28 | pid_res = [i for i in que_res if 'bash '+shell_file in i.decode("utf-8") and str(main_pid) in i.decode("utf-8") ] 29 | p.kill() 30 | return len(pid_res) 31 | 32 | 33 | def run_single_vasp(job_name,is_login_node=False,cpu_num=24,cwd="",main_pid=None): 34 | if not main_pid: 35 | main_pid = os.getpid() 36 | job_id_file = os.path.join(os.path.expanduser("~"),'.config','pyvaspflow',str(main_pid)) 37 | logging.basicConfig(level=logging.INFO, 38 | format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s', 39 | datefmt='%a, %d %b %Y %H:%M:%S', 40 | filename=os.path.join(cwd,'run-'+str(main_pid)+'.log'), 41 | filemode='a') 42 | 43 | job_id = schedule.schedule_type.submit_job(job_name) 44 | logging.info(job_name+" calculation has submitted at calculation node") 45 | # pid = os.getpid() 46 | # job_id_file = os.path.join(os.path.expanduser("~"),'.config','pyvaspflow',str(pid)) 47 | with open(job_id_file,'a') as f: 48 | f.writelines(job_id+"\n") 49 | while True: 50 | if not schedule.schedule_type.is_inqueue(job_id): 51 | logging.info(job_name+" in dir of "+os.getcwd()+" calculation finished") 52 | break 53 | sleep(5) 54 | 55 | 56 | def run_single_vasp_without_job(job_name,node_name,cpu_num,node_num=1,cwd="",main_pid=None): 57 | if not main_pid: 58 | main_pid = os.getpid() 59 | job_id_file = os.path.join(os.path.expanduser("~"),'.config','pyvaspflow',str(main_pid)) 60 | else: 61 | job_id_file = os.path.join(os.path.expanduser("~"),'.config','pyvaspflow',str(main_pid)) 62 | logging.basicConfig(level=logging.INFO, 63 | format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s', 64 | datefmt='%a, %d %b %Y %H:%M:%S', 65 | filename=os.path.join(cwd,'run-'+str(main_pid)+'.log'), 66 | filemode='a') 67 | job_id,submit_job_idx = schedule.schedule_type.submit_job_without_job(job_name,node_name,cpu_num,node_num=1) 68 | with open(job_id_file,'a') as f: 69 | f.writelines(job_id+"\n") 70 | sleep(5) 71 | while True: 72 | for idx,nname in enumerate(node_name): 73 | if schedule.schedule_type.node_is_idle(nname) and schedule.schedule_type.is_job_pd(job_id): 74 | os.system("scancel "+job_id) 75 | logging.info(job_name+" has been cancelled, the queue id is "+job_id) 76 | schedule.schedule_type.write_job_file(job_name,nname,cpu_num[idx],node_num) 77 | res = subprocess.Popen(['sbatch', './job.sh'],stdout=subprocess.PIPE,cwd=job_name) 78 | std = res.stdout.readlines() 79 | res.stdout.close() 80 | job_id = std[0].decode('utf-8').split()[-1] 81 | logging.info(job_name+" has been submitted at "+nname+" node, the queue id is "+job_id) 82 | with open(job_id_file,'a') as f: 83 | f.writelines(job_id+"\n") 84 | sleep(5) 85 | if not is_inqueue(job_id): 86 | logging.info(job_name+" in dir of "+os.getcwd()+" calculation finished") 87 | break 88 | sleep(5) 89 | 90 | 91 | def run_multi_vasp(job_name='task',end_job_num=1,start_job_num=0,job_list=None,par_job_num=4,cwd=""): 92 | pid = os.getpid() 93 | logging.basicConfig(level=logging.INFO, 94 | format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s', 95 | datefmt='%a, %d %b %Y %H:%M:%S', 96 | filename=os.path.join(cwd,'run-'+str(pid)+'.log'), 97 | filemode='a') 98 | 99 | job_id_file = os.path.join(os.path.expanduser("~"),'.config','pyvaspflow',str(pid)) 100 | start_job_num,end_job_num,par_job_num = int(start_job_num),int(end_job_num),int(par_job_num) 101 | jobid_pool = [] 102 | idx = start_job_num 103 | for ii in range(min(par_job_num,end_job_num-start_job_num)): 104 | _job_id = schedule.schedule_type.submit_job(job_name+str(ii+start_job_num)) 105 | jobid_pool.append(_job_id) 106 | with open(job_id_file,'a') as f: 107 | f.writelines(_job_id+"\n") 108 | idx += 1 109 | if idx == end_job_num+1: 110 | return 111 | while True: 112 | inqueue_num = schedule.schedule_type.num_of_job_inqueue(jobid_pool) 113 | logging.info(str(inqueue_num)+" in queue") 114 | if inqueue_num < par_job_num and idx < end_job_num+1: 115 | _job_id = schedule.schedule_type.submit_job(job_name + str(idx)) 116 | jobid_pool.append(_job_id) 117 | with open(job_id_file,'a') as f: 118 | f.writelines(_job_id+"\n") 119 | idx += 1 120 | sleep(5) 121 | if idx == end_job_num+1 and schedule.schedule_type.num_of_job_inqueue(jobid_pool) == 0: 122 | return 123 | 124 | 125 | def run_multi_vasp_without_job(job_name='task',end_job_num=1,node_name="short_q",cpu_num=24,node_num=1,start_job_num=0,par_job_num=4,cwd=""): 126 | logging.basicConfig(level=logging.INFO, 127 | format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s', 128 | datefmt='%a, %d %b %Y %H:%M:%S', 129 | filename=os.path.join(cwd,'run-'+str(os.getpid())+'.log'), 130 | filemode='a') 131 | main_pid = os.getpid() 132 | job_id_file = os.path.join(os.path.expanduser("~"),'.config','pyvaspflow',str(main_pid)) 133 | with open(job_id_file,'w') as f: 134 | pass 135 | submit_job_idx = 0 136 | start_job_num,end_job_num,par_job_num = int(start_job_num),int(end_job_num),int(par_job_num) 137 | jobid_pool = [] 138 | idx = start_job_num 139 | for ii in range(min(par_job_num,end_job_num-start_job_num)): 140 | _job_id,submit_job_idx = schedule.schedule_type.submit_job_without_job(job_name+str(ii+start_job_num),node_name,cpu_num,node_num=1,submit_job_idx=submit_job_idx) 141 | jobid_pool.append(_job_id) 142 | with open(job_id_file,'a') as f: 143 | f.writelines(_job_id+"\n") 144 | idx += 1 145 | if idx == end_job_num + 1: 146 | return 147 | while True: 148 | inqueue_num = schedule.schedule_type.num_of_job_inqueue(jobid_pool) 149 | logging.info(str(inqueue_num)+" in queue") 150 | if inqueue_num < par_job_num and idx < end_job_num+1: 151 | _job_id,submit_job_idx = schedule.schedule_type.submit_job_without_job(job_name + str(idx),node_name,cpu_num,node_num=1,submit_job_idx=submit_job_idx) 152 | if job_list is not None: 153 | start_job_num,end_job_num,par_job_num = 0,len(job_list)-1,int(par_job_num) 154 | jobid_pool = [] 155 | idx = 0 156 | for ii in range(min(par_job_num,end_job_num)): 157 | _job_id,submit_job_idx = submit_job_without_job(job_name+str(job_list[ii]),node_name,cpu_num,node_num=1,submit_job_idx=submit_job_idx) 158 | jobid_pool.append(_job_id) 159 | with open(job_id_file,'a') as f: 160 | f.writelines(_job_id+"\n") 161 | idx += 1 162 | if idx == end_job_num+1: 163 | return 164 | while True: 165 | inqueue_num = job_inqueue_num(jobid_pool) 166 | logging.info(str(inqueue_num)+" in queue") 167 | if inqueue_num < par_job_num and idx < end_job_num+1: 168 | _job_id,submit_job_idx = submit_job_without_job(job_name + str(job_list[idx]),node_name,cpu_num,node_num=1,submit_job_idx=submit_job_idx) 169 | jobid_pool.append(_job_id) 170 | with open(job_id_file,'a') as f: 171 | f.writelines(_job_id+"\n") 172 | idx += 1 173 | sleep(5) 174 | sleep(10) 175 | if idx == end_job_num+1 and job_inqueue_num(jobid_pool) == 0: 176 | break 177 | else: 178 | start_job_num,end_job_num,par_job_num = int(start_job_num),int(end_job_num),int(par_job_num) 179 | jobid_pool = [] 180 | idx = start_job_num 181 | for ii in range(min(par_job_num,end_job_num-start_job_num)): 182 | _job_id,submit_job_idx = submit_job_without_job(job_name+str(ii+start_job_num),node_name,cpu_num,node_num=1,submit_job_idx=submit_job_idx) 183 | jobid_pool.append(_job_id) 184 | with open(job_id_file,'a') as f: 185 | f.writelines(_job_id+"\n") 186 | idx += 1 187 | sleep(5) 188 | sleep(5) 189 | if idx == end_job_num+1 and schedule.schedule_type.num_of_job_inqueue(jobid_pool) == 0: 190 | return 191 | while True: 192 | inqueue_num = job_inqueue_num(jobid_pool) 193 | logging.info(str(inqueue_num)+" in queue") 194 | if inqueue_num < par_job_num and idx < end_job_num+1: 195 | _job_id,submit_job_idx = submit_job_without_job(job_name + str(idx),node_name,cpu_num,node_num=1,submit_job_idx=submit_job_idx) 196 | jobid_pool.append(_job_id) 197 | with open(job_id_file,'a') as f: 198 | f.writelines(_job_id+"\n") 199 | idx += 1 200 | sleep(5) 201 | sleep(10) 202 | if idx == end_job_num+1 and job_inqueue_num(jobid_pool) == 0: 203 | break 204 | os.remove(job_id_file) 205 | 206 | 207 | 208 | def run_multi_vasp_with_shell(work_name,shell_file,end_job_num=1,start_job_num=0,par_job_num=4): 209 | cwd = os.getcwd() 210 | logging.basicConfig(level=logging.INFO, 211 | format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s', 212 | datefmt='%a, %d %b %Y %H:%M:%S', 213 | filename=os.path.join(cwd,'run-'+str(os.getpid())+'.log'), 214 | filemode='a') 215 | main_pid = os.getpid() 216 | job_id_file = os.path.join(os.path.expanduser("~"),'.config','pyvaspflow',str(main_pid)) 217 | 218 | start_job_num,end_job_num,par_job_num = int(start_job_num),int(end_job_num),int(par_job_num) 219 | pid_pool = [] 220 | idx = start_job_num 221 | for ii in range(min(par_job_num,end_job_num-start_job_num)): 222 | if os.path.isdir(work_name+str(idx)): 223 | shutil.rmtree(work_name+str(idx)) 224 | os.makedirs(work_name+str(idx)) 225 | shutil.copyfile("POSCAR"+str(idx),work_name+str(idx)+"/POSCAR") 226 | new_lines = add_log_shell_file(shell_file,cwd,main_pid) 227 | with open(work_name+str(idx)+"/"+shell_file,"w") as f: 228 | f.writelines(new_lines) 229 | res = subprocess.Popen(['bash',shell_file],cwd=work_name+str(idx)) 230 | pid_pool.append(res.pid) 231 | idx += 1 232 | sleep(5) 233 | if idx == end_job_num+1: 234 | return 235 | while True: 236 | inqueue_num = get_number_of_running_shell_files(shell_file,main_pid) 237 | logging.info(str(inqueue_num)+" in queue") 238 | if inqueue_num < par_job_num and idx < end_job_num+1: 239 | if os.path.isdir(work_name+str(idx)): 240 | shutil.rmtree(work_name+str(idx)) 241 | os.makedirs(work_name+str(idx)) 242 | shutil.copyfile("POSCAR"+str(idx),work_name+str(idx)+"/POSCAR") 243 | new_lines = add_log_shell_file(shell_file,cwd,main_pid) 244 | with open(work_name+str(idx)+"/"+shell_file,"w") as f: 245 | f.writelines(new_lines) 246 | res = subprocess.Popen(['bash',shell_file],cwd=work_name+str(idx)) 247 | pid_pool.append(res.pid) 248 | idx += 1 249 | sleep(5) 250 | if idx == end_job_num+1 and get_number_of_running_shell_files(shell_file,main_pid) == 0: 251 | break 252 | sleep(60) 253 | -------------------------------------------------------------------------------- /pyvaspflow/vasp/schedule.py: -------------------------------------------------------------------------------- 1 | import os,subprocess,shutil,logging 2 | from time import sleep 3 | from pyvaspflow.utils import read_config 4 | 5 | 6 | config = read_config() 7 | 8 | 9 | class Schedule(): 10 | def __init__(self): 11 | 12 | if config["Task_Schedule"]["default_schedule"] == "SLURM": 13 | self.schedule_type = Slurm() 14 | 15 | elif config["Task_Schedule"]["default_schedule"] == "LSF": 16 | self.schedule_type = LSF() 17 | 18 | 19 | class Slurm(): 20 | def __init__(self): 21 | pass 22 | 23 | def is_inqueue(self,pid): 24 | p = subprocess.Popen('squeue',stdout=subprocess.PIPE) 25 | que_res = p.stdout.readlines() 26 | p.stdout.close() 27 | for ii in que_res: 28 | if str(pid) in ii.decode('utf-8'): 29 | return True 30 | return False 31 | 32 | def num_of_job_inqueue(self,pid_list): 33 | p = subprocess.Popen('squeue',stdout=subprocess.PIPE) 34 | sinf_res = p.stdout.read() 35 | sinf_res = sinf_res.decode('utf-8').split('\n') 36 | p.stdout.close() 37 | num = 0 38 | for _pid in pid_list: 39 | for line in sinf_res: 40 | if len(line.strip()) == 0: 41 | continue 42 | if _pid in line.split()[0]: 43 | num += 1 44 | return num 45 | 46 | def node_is_idle(self,node_name): 47 | p = subprocess.Popen('sinfo',stdout=subprocess.PIPE) 48 | sinf_res = p.stdout.read() 49 | sinf_res = sinf_res.decode('utf-8').split('\n') 50 | p.stdout.close() 51 | for line in sinf_res: 52 | if 'idle' in line and node_name in line: 53 | return True 54 | return False 55 | 56 | def is_job_running(self,pid): 57 | p = subprocess.Popen('squeue',stdout=subprocess.PIPE) 58 | sinf_res = p.stdout.read() 59 | sinf_res = sinf_res.decode('utf-8').split('\n') 60 | p.stdout.close() 61 | for line in sinf_res: 62 | if ' R ' in line and pid in line: 63 | return True 64 | return False 65 | 66 | def is_job_pd(self,pid): 67 | p = subprocess.Popen('squeue',stdout=subprocess.PIPE) 68 | sinf_res = p.stdout.read() 69 | sinf_res = sinf_res.decode('utf-8').split('\n') 70 | p.stdout.close() 71 | for line in sinf_res: 72 | if ' PD ' in line and pid in line: 73 | return True 74 | return False 75 | 76 | def cancel_job(self,pid): 77 | while True: 78 | p = subprocess.Popen(['scancel',pid],stdout=subprocess.PIPE) 79 | if not self.is_inqueue(pid): 80 | break 81 | 82 | def write_job_file(self,node_name,cpu_num,node_num,job_name): 83 | with open(os.path.join(os.getcwd(),job_name,'job.sh'),'w') as f: 84 | f.writelines('#!/bin/bash -l\n') 85 | f.writelines('#SBATCH -J '+job_name+'\n') 86 | f.writelines('#SBATCH -p '+node_name+' -N '+ str(int(node_num)) +' -n '+str(int(cpu_num))+'\n\n') 87 | f.writelines(config['RUN_VASP']['prepend']+'\n') 88 | f.writelines(config['RUN_VASP']['exec']+'\n') 89 | if "append" in config["RUN_VASP"]: 90 | f.writelines(config['RUN_VASP']['append']+'\n') 91 | 92 | def submit_job(self,job_name): 93 | res = subprocess.Popen(['/bin/my_sbatch', './job.sh'],stdout=subprocess.PIPE,cwd=job_name) 94 | std = res.stdout.readlines() 95 | res.stdout.close() 96 | pid = std[0].decode("utf-8").split()[-1] 97 | try: 98 | int(pid) 99 | except: 100 | raise ValueError("Too many jobs you have submitted") 101 | logging.info(job_name+" calculation has been submitted, the queue id is "+pid) 102 | logging.info("The work dir is "+os.path.join(os.getcwd(),job_name)) 103 | return pid 104 | 105 | def submit_job_without_job(self,job_name,node_name,cpu_num,node_num=1,submit_job_idx=0): 106 | has_write_job = False 107 | for idx in range(len(node_name)): 108 | if self.node_is_idle(node_name[idx]): 109 | self.write_job_file(job_name=job_name,node_name=node_name[idx],cpu_num=cpu_num[idx],node_num=node_num) 110 | has_write_job = True 111 | node_submitted = node_name[idx] 112 | break 113 | if not has_write_job: 114 | self.write_job_file(job_name=job_name,node_name=node_name[submit_job_idx],cpu_num=cpu_num[submit_job_idx],node_num=node_num) 115 | node_submitted = node_name[submit_job_idx] 116 | submit_job_idx += 1 117 | if submit_job_idx == len(node_name): 118 | submit_job_idx = 0 119 | res = subprocess.Popen(['/bin/my_sbatch', './job.sh'],stdout=subprocess.PIPE,cwd=job_name) 120 | std = res.stdout.readlines() 121 | res.stdout.close() 122 | pid = std[0].decode('utf-8').split()[-1] 123 | try: 124 | int(pid) 125 | except: 126 | raise ValueError("Too many jobs you have submitted") 127 | logging.info(job_name+" calculation has been submitted, the queue id is "+pid) 128 | logging.info("The work dir is "+os.path.join(os.getcwd(),job_name)) 129 | sleep(5) 130 | return pid,submit_job_idx 131 | 132 | 133 | 134 | class LSF(): 135 | def __init__(self): 136 | pass 137 | 138 | def is_inqueue(self,pid): 139 | p = subprocess.Popen('squeue',stdout=subprocess.PIPE) 140 | que_res = p.stdout.readlines() 141 | p.stdout.close() 142 | for ii in que_res: 143 | if str(pid) in ii.decode('utf-8'): 144 | return True 145 | return False 146 | 147 | def num_of_job_inqueue(self,pid_list): 148 | p = subprocess.Popen('squeue',stdout=subprocess.PIPE) 149 | sinf_res = p.stdout.read() 150 | sinf_res = sinf_res.decode('utf-8').split('\n') 151 | p.stdout.close() 152 | num = 0 153 | for _pid in pid_list: 154 | for line in sinf_res: 155 | if len(line.strip()) == 0: 156 | continue 157 | if _pid in line.split()[0]: 158 | num += 1 159 | return num 160 | 161 | def node_is_idle(self,node_name): 162 | p = subprocess.Popen('sinfo',stdout=subprocess.PIPE) 163 | sinf_res = p.stdout.read() 164 | sinf_res = sinf_res.decode('utf-8').split('\n') 165 | p.stdout.close() 166 | for line in sinf_res: 167 | if 'idle' in line and node_name in line: 168 | return True 169 | return False 170 | 171 | def is_job_running(self,pid): 172 | p = subprocess.Popen('squeue',stdout=subprocess.PIPE) 173 | sinf_res = p.stdout.read() 174 | sinf_res = sinf_res.decode('utf-8').split('\n') 175 | p.stdout.close() 176 | for line in sinf_res: 177 | if ' R ' in line and pid in line: 178 | return True 179 | return False 180 | 181 | def is_job_pd(self,pid): 182 | p = subprocess.Popen('squeue',stdout=subprocess.PIPE) 183 | sinf_res = p.stdout.read() 184 | sinf_res = sinf_res.decode('utf-8').split('\n') 185 | p.stdout.close() 186 | for line in sinf_res: 187 | if ' PD ' in line and pid in line: 188 | return True 189 | return False 190 | 191 | def cancel_job(self,pid): 192 | while True: 193 | p = subprocess.Popen(['scancel',pid],stdout=subprocess.PIPE) 194 | if not self.is_inqueue(pid): 195 | break 196 | 197 | def write_job_file(self,node_name,cpu_num,node_num,job_name): 198 | with open(os.path.join(os.getcwd(),job_name,'job.sh'),'w') as f: 199 | f.writelines('#!/bin/sh -l\n') 200 | f.writelines('#BSUB -q '+node_name +'\n') 201 | f.writelines('#BSUB -n '+cpu_num +'\n') 202 | f.writelines('#BSUB -e %J.err\n') 203 | f.writelines('#BSUB -o %J.out\n') 204 | f.writelines('#BSUB -R "span[ptile=24]"\n') 205 | f.writelines('hostfile=`echo $LSB_DJOB_HOSTFILE`\n') 206 | f.writelines('NP=`cat $hostfile | wc -l`\n\n') 207 | f.writelines(config['RUN_VASP']['prepend']+'\n') 208 | f.writelines(config['RUN_VASP']['exec']+'\n') 209 | if "append" in config["RUN_VASP"]: 210 | f.writelines(config['RUN_VASP']['append']+'\n') 211 | 212 | def submit_job(self,job_name): 213 | res = subprocess.Popen(['/bin/my_sbatch', './job.sh'],stdout=subprocess.PIPE,cwd=job_name) 214 | std = res.stdout.readlines() 215 | res.stdout.close() 216 | pid = std[0].decode("utf-8").split()[-1] 217 | try: 218 | int(pid) 219 | except: 220 | raise ValueError("Too many jobs you have submitted") 221 | logging.info(job_name+" calculation has been submitted, the queue id is "+pid) 222 | logging.info("The work dir is "+os.path.join(os.getcwd(),job_name)) 223 | return pid 224 | 225 | def submit_job_without_job(self,job_name,node_name,cpu_num,node_num=1,submit_job_idx=0): 226 | has_write_job = False 227 | for idx in range(len(node_name)): 228 | if self.node_is_idle(node_name[idx]): 229 | self.write_job_file(job_name=job_name,node_name=node_name[idx],cpu_num=cpu_num[idx],node_num=node_num) 230 | has_write_job = True 231 | node_submitted = node_name[idx] 232 | break 233 | if not has_write_job: 234 | self.write_job_file(job_name=job_name,node_name=node_name[submit_job_idx],cpu_num=cpu_num[submit_job_idx],node_num=node_num) 235 | node_submitted = node_name[submit_job_idx] 236 | submit_job_idx += 1 237 | if submit_job_idx == len(node_name): 238 | submit_job_idx = 0 239 | res = subprocess.Popen(['/bin/my_sbatch', './job.sh'],stdout=subprocess.PIPE,cwd=job_name) 240 | std = res.stdout.readlines() 241 | res.stdout.close() 242 | pid = std[0].decode('utf-8').split()[-1] 243 | try: 244 | int(pid) 245 | except: 246 | raise ValueError("Too many jobs you have submitted") 247 | logging.info(job_name+" calculation has been submitted, the queue id is "+pid) 248 | logging.info("The work dir is "+os.path.join(os.getcwd(),job_name)) 249 | sleep(5) 250 | return pid,submit_job_idx 251 | -------------------------------------------------------------------------------- /pyvaspflow/vasp/test_para.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3.6 2 | # -*- coding: utf-8 -*- 3 | 4 | 5 | from pyvaspflow.vasp import prep_vasp,run_vasp 6 | from pyvaspflow.io.vasp_input import Kpoints 7 | from pyvaspflow.utils import is_2d_structure 8 | from pyvaspflow.io.vasp_out import ExtractValue 9 | from sagar.io.vasp import read_vasp 10 | from os import makedirs,path,chdir,remove 11 | from shutil import rmtree,copy2 12 | import numpy as np 13 | 14 | class TestParameter(): 15 | def __init__(self,poscar='POSCAR'): 16 | self.poscar = poscar 17 | if is_2d_structure(read_vasp(self.poscar)): 18 | self.dimen = 2 19 | else: 20 | self.dimen = 3 21 | 22 | def test_encut(self,kw={}): 23 | start,end,step = kw.get('start'),kw.get('end'),kw.get('step') 24 | is_login_node,kw = run_vasp.clean_parse(kw,'is_login_node',False) 25 | kw.pop('start');kw.pop('end');kw.pop('step') 26 | _kw = kw.copy() 27 | prep_vasp.write_potcar(poscar=self.poscar,kw=_kw) 28 | with open('POTCAR') as f: 29 | lines = f.readlines() 30 | en_line = [i for i in lines if 'ENMAX' in i] 31 | enmax = max([float(i.split()[2].replace(';','')) for i in en_line]) 32 | remove('POTCAR') 33 | idx = 0 34 | for en in np.arange(start*enmax,end*enmax,step): 35 | _kw = kw.copy() 36 | _kw.update({'ENCUT':int(en),'job_name':'test_encut'+str(idx),'NSW':0}) 37 | prep_vasp.prep_single_vasp(poscar=self.poscar,kw=_kw) 38 | idx += 1 39 | for i in range(idx): 40 | run_vasp.run_single_vasp(job_name='test_encut'+str(i),is_login_node=is_login_node) 41 | encut_list = [] 42 | encut = np.arange(start*enmax,end*enmax,step) 43 | for ii in range(len(encut)): 44 | EV = ExtractValue(data_folder='test_encut'+str(ii)) 45 | encut_list.append([encut[ii],EV.get_energy(),EV.get_cpu_time()]) 46 | with open('test_encut.txt','w') as f: 47 | f.writelines('ENMAX\tEnergy\tcpu_time\n') 48 | for line in encut_list: 49 | f.writelines(str(line[0])+'\t'+str(line[1])+'\t'+str(line[2])+'\n') 50 | 51 | 52 | def test_kpts(self,kw={},run=True): 53 | start,end,step = kw.get('start'),kw.get('end'),kw.get('step') 54 | is_login_node,kw = run_vasp.clean_parse(kw,'is_login_node',False) 55 | kw.pop('start');kw.pop('end');kw.pop('step') 56 | kpts = Kpoints() 57 | kpts_list = [] 58 | kppa_list = [] 59 | for kppa in range(start,end,step): 60 | kpts.automatic_density(structure=read_vasp(self.poscar),kppa=kppa) 61 | if list(kpts.kpts[0]) not in kpts_list: 62 | kpts_list.append(kpts.kpts[0]) 63 | kppa_list.append(kppa) 64 | idx = 0 65 | for kppa in kppa_list: 66 | _kw = kw.copy() 67 | if 'style' not in _kw: 68 | _kw.update({'kppa':kppa,'style':'auto','job_name':'test_kpts'+str(idx),'NSW':0}) 69 | prep_vasp.prep_single_vasp(poscar=self.poscar,kw=_kw) 70 | idx += 1 71 | np.savetxt("kppa_list",kppa_list,fmt="%d") 72 | np.savetxt("kpts_list",kpts_list,fmt="%d") 73 | 74 | if run: 75 | for i in range(idx): 76 | run_vasp.run_single_vasp(job_name='test_kpts'+str(i),is_login_node=is_login_node) 77 | kpts_res = [] 78 | for ii in range(len(kppa_list)): 79 | EV = ExtractValue(data_folder='test_kpts'+str(ii)) 80 | kpts_res.append([kppa_list[ii],EV.get_energy(),EV.get_cpu_time()]) 81 | with open('test_kpts.txt','w') as f: 82 | f.writelines('KPTS\tEnergy\tcpu_time\n') 83 | for line in kpts_res: 84 | f.writelines(str(line[0])+'\t'+str(line[1])+'\t'+str(line[2])+'\n') 85 | 86 | 87 | if __name__ == '__main__': 88 | tp = TestParameter() 89 | tp.test_kpts(kw={'start':1000,'end':5000,'step':10}) 90 | -------------------------------------------------------------------------------- /pyvaspflow/vasp/vasp_err.py: -------------------------------------------------------------------------------- 1 | 2 | class VaspError(): 3 | def __init__(curr_dir="./"): 4 | # determine which error the current task belongs to 5 | pass 6 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | 5 | from distutils.core import setup 6 | from os import pardir,path,mkdir 7 | 8 | #This is a list of files to install, and where 9 | #(relative to the 'root' dir, where setup.py is) 10 | #You could be more specific. 11 | 12 | 13 | setup(name = "pyvaspflow", 14 | version = "0.0.3", 15 | description = "Vasp Calculation", 16 | long_description="A Python package for VASP task preparation and submission maganement.", 17 | author = "hecc", 18 | author_email = "changchun_he@foxmail.com", 19 | #Name the folder where your packages live: 20 | #(If you have other packages (dirs) or modules (py files) then 21 | #put them into the package directory - they will be found 22 | #recursively.) 23 | packages = ['pyvaspflow','pyvaspflow.io','pyvaspflow.vasp','pyvaspflow.defect_cal'], 24 | install_requires=['numpy','sagar','seekpath','psutil','click==7.1.2','progressbar2','matplotlib'], 25 | url="https://github.com/ChangChunHe/pyvaspflow", 26 | entry_points={ 27 | 'console_scripts': [ 28 | 'pyvasp = pyvaspflow.pyvasp:cli', 29 | ]} 30 | ) 31 | 32 | 33 | 34 | home = path.expanduser("~") 35 | 36 | if not path.isdir(path.join(home,'.config')): 37 | mkdir(path.join(home,'.config')) 38 | 39 | if not path.isdir(path.join(home,'.config','pyvaspflow')): 40 | mkdir(path.join(home,'.config','pyvaspflow')) 41 | 42 | if not path.isfile(path.join(home,'.config','pyvaspflow','config.ini')): 43 | with open("./config.ini","r") as f: 44 | lines = f.read() 45 | with open(path.join(home,'.config','pyvaspflow','config.ini'),'w') as outfile: 46 | outfile.write(lines) 47 | -------------------------------------------------------------------------------- /test/conf.json: -------------------------------------------------------------------------------- 1 | { 2 | "potcar_path": 3 | {"paw_PBE":"/opt/ohpc/pub/apps/vasp/pps/paw_PBE", 4 | "paw_LDA":"/opt/ohpc/pub/apps/vasp/pps/paw_LDA", 5 | "paw_PW91":"/opt/ohpc/pub/apps/vasp/pps/paw_PW91", 6 | "USPP_LDA":"/opt/ohpc/pub/apps/vasp/pps/USPP_LDA", 7 | "USPP_PW91":"/opt/ohpc/pub/apps/vasp/pps/USPP_PW91" 8 | }, 9 | "job":{ 10 | "prepend": "module load vasp/5.4.4-impi-mkl", 11 | "exec": "mpirun -n ${SLURM_NPROCS} vasp_std" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /test/test_prep_vasp.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # coding: utf-8 3 | 4 | import unittest 5 | from pyvaspflow.vasp import prep_vasp 6 | class Test_Vasp(unittest.TestCase): 7 | 8 | def test_write_incar(self): 9 | pass 10 | 11 | 12 | def test_write_kpoints(self): 13 | pass 14 | 15 | 16 | if __name__ == '__main__': 17 | unittest.main() 18 | -------------------------------------------------------------------------------- /test/test_vasp_input.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # coding: utf-8 3 | 4 | import unittest 5 | from pyvaspflow.io import vasp_input 6 | from pyvaspflow.vasp.prep_vasp import write_incar 7 | class Test_io(unittest.TestCase): 8 | 9 | def test_incar(self): 10 | incar = vasp_input.Incar() 11 | incar['EDIFF'] = '1e-7' 12 | incar['NSW'] = 1000.00 13 | incar['LCHGCAR'] = 'True' 14 | self.assertEqual(incar['EDIFF'],1e-7) 15 | self.assertEqual(incar['NSW'],1000) 16 | self.assertEqual(incar['LCHGCAR'],True) 17 | 18 | def test_auto_kpoints(self): 19 | kpoints = vasp_input.Kpoints() 20 | kpoints.automatic([1,2,3]) 21 | self.assertEqual(kpoints.kpts[0][0],[1,2,3]) 22 | 23 | def test_gamma_kpoints(self): 24 | kpoints = vasp_input.Kpoints() 25 | kpoints.gamma_automatic([1,1,1],[0.5,0.5,0.5]) 26 | self.assertEqual(kpoints.kpts_shift,[0.5,0.5,0.5]) 27 | self.assertEqual(kpoints.kpts[0],[1,1,1]) 28 | 29 | def test_potcar(self): 30 | pass 31 | 32 | 33 | if __name__ == '__main__': 34 | unittest.main() 35 | -------------------------------------------------------------------------------- /tox.ini: -------------------------------------------------------------------------------- 1 | [testenv] 2 | passenv = CI TRAVIS TRAVIS_* 3 | deps = codecov 4 | commands = codecov -e CODECOV_ENV 5 | --------------------------------------------------------------------------------