Repository: materialsproject/custodian
Pull request #139 (2019-11-20 19:18:47)

update teterror to handle KSPACING
## Summary

VASP now [recommends](https://www.vasp.at/wiki/index.php/KSPACING) setting KSPACING in the INCAR file rather than supplying KPOINTS manually. This PR updates the teterror handler to accommodate calculations that use KSPACING instead of an explicit KPOINTS file.

The correction action is to reduce the KSPACING to 80% of its original value, which approximately doubles the number of kpoints.

See also pymatgen PR # [1678](https://github.com/materialsproject/pymatgen/pull/1678))


Patch:
diff --git a/custodian/vasp/handlers.py b/custodian/vasp/handlers.py
index 3c84c513..0172fd54 100644
--- a/custodian/vasp/handlers.py
+++ b/custodian/vasp/handlers.py
@@ -160,8 +160,13 @@ class VaspErrorHandler(ErrorHandler):
         vi = VaspInput.from_directory(".")
 
         if self.errors.intersection(["tet", "dentet"]):
-            actions.append({"dict": "INCAR",
-                            "action": {"_set": {"ISMEAR": 0, "SIGMA": 0.05}}})
+            if vi["INCAR"].get("KSPACING"):
+                # decrease KSPACING by 20% in each direction (approximately double no. of kpoints)
+                actions.append({"dict": "INCAR",
+                                "action": {"_set": {"KSPACING": vi["INCAR"].get("KSPACING")*0.8}}})
+            else:
+                actions.append({"dict": "INCAR",
+                                "action": {"_set": {"ISMEAR": 0, "SIGMA": 0.05}}})
 
         if "inv_rot_mat" in self.errors:
             actions.append({"dict": "INCAR",
@@ -219,11 +224,11 @@ class VaspErrorHandler(ErrorHandler):
             else:
                 actions.append({"dict": "INCAR",
                                 "action": {"_set": {"ISYM": 0}}})
-
-                if vi["KPOINTS"].style == Kpoints.supported_modes.Monkhorst:
-                    actions.append({"dict": "KPOINTS",
-                                    "action": {
-                                        "_set": {"generation_style": "Gamma"}}})
+                if vi["KPOINTS"] is not None:
+                    if vi["KPOINTS"].style == Kpoints.supported_modes.Monkhorst:
+                        actions.append({"dict": "KPOINTS",
+                                        "action": {
+                                            "_set": {"generation_style": "Gamma"}}})
 
                 # Based on VASP forum's recommendation, you should delete the
                 # CHGCAR and WAVECAR when dealing with this error.
@@ -297,16 +302,18 @@ class VaspErrorHandler(ErrorHandler):
 
         if self.errors.intersection(["tetirr", "incorrect_shift"]):
 
-            if vi["KPOINTS"].style == Kpoints.supported_modes.Monkhorst:
-                actions.append({"dict": "KPOINTS",
-                                "action": {
-                                    "_set": {"generation_style": "Gamma"}}})
+            if vi["KPOINTS"] is not None:
+                if vi["KPOINTS"].style == Kpoints.supported_modes.Monkhorst:
+                    actions.append({"dict": "KPOINTS",
+                                    "action": {
+                                        "_set": {"generation_style": "Gamma"}}})
 
         if "rot_matrix" in self.errors:
-            if vi["KPOINTS"].style == Kpoints.supported_modes.Monkhorst:
-                actions.append({"dict": "KPOINTS",
-                                "action": {
-                                    "_set": {"generation_style": "Gamma"}}})
+            if vi["KPOINTS"] is not None:
+                if vi["KPOINTS"].style == Kpoints.supported_modes.Monkhorst:
+                    actions.append({"dict": "KPOINTS",
+                                    "action": {
+                                        "_set": {"generation_style": "Gamma"}}})
             else:
                 actions.append({"dict": "INCAR",
                                 "action": {"_set": {"ISYM": 0}}})
@@ -723,6 +730,10 @@ class MeshSymmetryErrorHandler(ErrorHandler):
               " lattices."
 
         vi = VaspInput.from_directory('.')
+        # disregard this error if KSPACING is set and no KPOINTS file is generated
+        if vi["INCAR"].get('KSPACING', False):
+            return False
+
         # According to VASP admins, you can disregard this error
         # if symmetry is off
         # Also disregard if automatic KPOINT generation is used


Test patch:
diff --git a/custodian/vasp/tests/test_handlers.py b/custodian/vasp/tests/test_handlers.py
index 61356d35..ba9de8c5 100644
--- a/custodian/vasp/tests/test_handlers.py
+++ b/custodian/vasp/tests/test_handlers.py
@@ -269,6 +269,16 @@ class VaspErrorHandlerTest(unittest.TestCase):
         self.assertEqual(h.correct()["errors"], ["point_group"])
         i = Incar.from_file("INCAR")
         self.assertEqual(i["ISYM"], 0)
+    
+    def test_too_large_kspacing(self):
+        shutil.copy("INCAR.kspacing", "INCAR")
+        vi = VaspInput.from_directory(".")
+        h = VaspErrorHandler("vasp.teterror")
+        h.check()
+        d = h.correct()
+        self.assertEqual(d["errors"], ['tet'])
+        self.assertEqual(d["actions"],
+                         [{'action': {"_set": {"KSPACING": vi["INCAR"].get("KSPACING")*0.8}},'dict': 'INCAR'}])
 
     def tearDown(self):
         os.chdir(test_dir)
diff --git a/test_files/INCAR.kspacing b/test_files/INCAR.kspacing
new file mode 100644
index 00000000..6df19d99
--- /dev/null
+++ b/test_files/INCAR.kspacing
@@ -0,0 +1,25 @@
+ALGO = Fast
+EDIFF = 0.0004
+ENCUT = 520
+IBRION = 2
+ICHARG = 1
+ISIF = 3
+ISMEAR = -5
+KSPACING = 2
+ISPIN = 2
+LDAU = True
+LDAUJ = 0 0 0 0
+LDAUL = 0 2 2 0
+LDAUTYPE = 2
+LDAUU = 0 4.0 6 0
+LMAXMIX = 4
+LORBIT = 11
+LREAL = Auto
+LWAVE = False
+MAGMOM = 2*0.6 1*5 5*0.6
+NELM = 100
+NELMIN = 6
+NPAR = 1
+NSW = 99
+PREC = Accurate
+SIGMA = 0.05