11import pytest
22import copy
3- from conftest import get_test_object
3+ from conftest import get_test_object , test_data_task_docs
44from pymatgen .io .validation import ValidationDoc
55from emmet .core .tasks import TaskDoc
66from monty .serialization import loadfn
@@ -19,15 +19,16 @@ def run_check(
1919 error_message_to_search_for : str ,
2020 should_the_check_pass : bool ,
2121 vasprun_parameters_to_change : dict = {}, # for changing the parameters read from vasprun.xml
22- incar_settings_to_change : dict = {}, # for directly changing the INCAR file
22+ incar_settings_to_change : dict = {}, # for directly changing the INCAR file,
23+ validation_doc_kwargs : dict = {}, # any kwargs to pass to the ValidationDoc class
2324):
2425 for key , value in vasprun_parameters_to_change .items ():
2526 task_doc .input .parameters [key ] = value
2627
2728 for key , value in incar_settings_to_change .items ():
2829 task_doc .calcs_reversed [0 ].input .incar [key ] = value
2930
30- validation_doc = ValidationDoc .from_task_doc (task_doc )
31+ validation_doc = ValidationDoc .from_task_doc (task_doc , ** validation_doc_kwargs )
3132 has_specified_error = any ([error_message_to_search_for in reason for reason in validation_doc .reasons ])
3233
3334 assert (not has_specified_error ) if should_the_check_pass else has_specified_error
@@ -44,7 +45,7 @@ def test_validation_doc_from_directory(test_dir, object_name):
4445 dir_name = test_dir / "vasp" / test_object .folder
4546 test_validation_doc = ValidationDoc .from_directory (dir_name = dir_name )
4647
47- task_doc = TaskDoc . from_directory ( dir_name )
48+ task_doc = test_data_task_docs [ object_name ]
4849 valid_validation_doc = ValidationDoc .from_task_doc (task_doc )
4950
5051 # The attributes below will always be different because the objects are created at
@@ -64,9 +65,8 @@ def test_validation_doc_from_directory(test_dir, object_name):
6465 ],
6566)
6667def test_potcar_validation (test_dir , object_name ):
67- test_object = get_test_object (object_name )
68- dir_name = test_dir / "vasp" / test_object .folder
69- task_doc = TaskDoc .from_directory (dir_name )
68+
69+ task_doc = test_data_task_docs [object_name ]
7070
7171 correct_potcar_summary_stats = loadfn (test_dir / "vasp" / "Si_potcar_spec.json.gz" )
7272
@@ -91,9 +91,7 @@ def test_potcar_validation(test_dir, object_name):
9191 ],
9292)
9393def test_scf_incar_checks (test_dir , object_name ):
94- test_object = get_test_object (object_name )
95- dir_name = test_dir / "vasp" / test_object .folder
96- task_doc = TaskDoc .from_directory (dir_name )
94+ task_doc = test_data_task_docs [object_name ]
9795 task_doc .calcs_reversed [0 ].output .structure ._charge = 0.0 # patch for old test files
9896
9997 # Pay *very* close attention to whether a tag is modified in the incar or in the vasprun.xml's parameters!
@@ -311,10 +309,8 @@ def test_scf_incar_checks(test_dir, object_name):
311309 pytest .param ("SiNonSCFUniform" , id = "SiNonSCFUniform" ),
312310 ],
313311)
314- def test_nscf_incar_checks (test_dir , object_name ):
315- test_object = get_test_object (object_name )
316- dir_name = test_dir / "vasp" / test_object .folder
317- task_doc = TaskDoc .from_directory (dir_name )
312+ def test_nscf_incar_checks (object_name ):
313+ task_doc = test_data_task_docs [object_name ]
318314 task_doc .calcs_reversed [0 ].output .structure ._charge = 0.0 # patch for old test files
319315
320316 # ICHARG check
@@ -338,10 +334,8 @@ def test_nscf_incar_checks(test_dir, object_name):
338334 pytest .param ("SiNonSCFUniform" , id = "SiNonSCFUniform" ),
339335 ],
340336)
341- def test_nscf_kpoints_checks (test_dir , object_name ):
342- test_object = get_test_object (object_name )
343- dir_name = test_dir / "vasp" / test_object .folder
344- task_doc = TaskDoc .from_directory (dir_name )
337+ def test_nscf_kpoints_checks (object_name ):
338+ task_doc = test_data_task_docs [object_name ]
345339 task_doc .calcs_reversed [0 ].output .structure ._charge = 0.0 # patch for old test files
346340
347341 # Explicit kpoints for NSCF calc check (this should not raise any flags for NSCF calcs)
@@ -367,10 +361,8 @@ def test_nscf_kpoints_checks(test_dir, object_name):
367361 # pytest.param("SiStatic", id="SiStatic"),
368362 ],
369363)
370- def test_common_error_checks (test_dir , object_name ):
371- test_object = get_test_object (object_name )
372- dir_name = test_dir / "vasp" / test_object .folder
373- task_doc = TaskDoc .from_directory (dir_name )
364+ def test_common_error_checks (object_name ):
365+ task_doc = test_data_task_docs [object_name ]
374366 task_doc .calcs_reversed [0 ].output .structure ._charge = 0.0 # patch for old test files
375367
376368 # METAGGA and GGA tag check (should never be set together)
@@ -461,10 +453,8 @@ def _update_kpoints_for_test(task_doc: TaskDoc, kpoints_updates: dict):
461453 pytest .param ("SiOptimizeDouble" , id = "SiOptimizeDouble" ),
462454 ],
463455)
464- def test_kpoints_checks (test_dir , object_name ):
465- test_object = get_test_object (object_name )
466- dir_name = test_dir / "vasp" / test_object .folder
467- task_doc = TaskDoc .from_directory (dir_name )
456+ def test_kpoints_checks (object_name ):
457+ task_doc = test_data_task_docs [object_name ]
468458 task_doc .calcs_reversed [0 ].output .structure ._charge = 0.0 # patch for old test files
469459
470460 # Valid mesh type check (should flag HCP structures)
@@ -524,10 +514,8 @@ def test_kpoints_checks(test_dir, object_name):
524514 pytest .param ("SiOptimizeDouble" , id = "SiOptimizeDouble" ),
525515 ],
526516)
527- def test_vasp_version_check (test_dir , object_name ):
528- test_object = get_test_object (object_name )
529- dir_name = test_dir / "vasp" / test_object .folder
530- task_doc = TaskDoc .from_directory (dir_name )
517+ def test_vasp_version_check (object_name ):
518+ task_doc = test_data_task_docs [object_name ]
531519 task_doc .calcs_reversed [0 ].output .structure ._charge = 0.0 # patch for old test files
532520
533521 vasp_version_list = [
@@ -568,10 +556,65 @@ def test_task_document(test_dir):
568556 valid_docs = {}
569557 for calc in calcs :
570558 valid_docs [calc ] = ValidationDoc .from_task_doc (TaskDocument (** calcs [calc ]))
559+ # quickly check that `from_dict` and `from_task_doc` give same document
560+ assert set (ValidationDoc .from_dict (calcs [calc ]).reasons ) == set (valid_docs [calc ].reasons )
571561
572562 assert valid_docs ["compliant" ].valid
573563 assert not valid_docs ["non-compliant" ].valid
574564
575565 expected_reasons = ["KPOINTS" , "ENCUT" , "ENAUG" ]
576566 for expected_reason in expected_reasons :
577- assert any (expected_reason in reason for reason in valid_docs ["non-compliant" ].reasons )
567+ assert any (expected_reason in reason for reason in valid_docs ["non-compliant" ].reasons )
568+
569+ def test_fast_mode ():
570+ task_doc = test_data_task_docs ["SiStatic" ]
571+ valid_doc = ValidationDoc .from_task_doc (task_doc ,check_potcar = False )
572+
573+ # Without POTCAR check, this doc is valid
574+ assert valid_doc .valid
575+
576+ # Now introduce sequence of changes to test how fast validation works
577+ # Check order:
578+ # 1. VASP version
579+ # 2. Common errors (known bugs, missing output, etc.)
580+ # 3. K-point density
581+ # 4. POTCAR check
582+ # 5. INCAR check
583+
584+ og_kpoints = task_doc .calcs_reversed [0 ].input .kpoints
585+ # Introduce series of errors, then ablate them
586+ # use unacceptable version and set METAGGA and GGA simultaneously ->
587+ # should only get version error in reasons
588+ task_doc .calcs_reversed [0 ].vasp_version = "4.0.0"
589+ task_doc .input .parameters ["NBANDS" ] = - 5
590+ bad_incar_updates = {"METAGGA" : "R2SCAN" , "GGA" : "PE" ,}
591+ task_doc .calcs_reversed [0 ].input .incar .update (bad_incar_updates )
592+
593+ _update_kpoints_for_test (task_doc , {"kpoints" : [[1 ,1 ,2 ]]})
594+
595+ valid_doc = ValidationDoc .from_task_doc (task_doc , check_potcar = True , fast = True )
596+ assert len (valid_doc .reasons ) == 1
597+ assert "VASP VERSION" in valid_doc .reasons [0 ]
598+
599+ # Now correct version, should just get METAGGA / GGA bug
600+ task_doc .calcs_reversed [0 ].vasp_version = "6.3.2"
601+ valid_doc = ValidationDoc .from_task_doc (task_doc , check_potcar = True , fast = True )
602+ assert len (valid_doc .reasons ) == 1
603+ assert "KNOWN BUG" in valid_doc .reasons [0 ]
604+
605+ # Now remove GGA tag, get k-point density error
606+ task_doc .calcs_reversed [0 ].input .incar .pop ("GGA" )
607+ valid_doc = ValidationDoc .from_task_doc (task_doc , check_potcar = True , fast = True )
608+ assert len (valid_doc .reasons ) == 1
609+ assert "INPUT SETTINGS --> KPOINTS or KSPACING:" in valid_doc .reasons [0 ]
610+
611+ # Now restore k-points and check POTCAR --> get error
612+ _update_kpoints_for_test (task_doc , og_kpoints )
613+ valid_doc = ValidationDoc .from_task_doc (task_doc , check_potcar = True , fast = True )
614+ assert len (valid_doc .reasons ) == 1
615+ assert "PSEUDOPOTENTIALS" in valid_doc .reasons [0 ]
616+
617+ # Without POTCAR check, should get INCAR check error for NGX
618+ valid_doc = ValidationDoc .from_task_doc (task_doc , check_potcar = False , fast = True )
619+ assert len (valid_doc .reasons ) == 1
620+ assert "NBANDS" in valid_doc .reasons [0 ]
0 commit comments