Skip to content

Commit

Permalink
Merge pull request materialsproject#182 from Zhuoying/main
Browse files Browse the repository at this point in the history
Correct calcs_reversed to real reverse order
  • Loading branch information
utf authored Oct 14, 2022
2 parents 3cdbb3f + 16fab9b commit 9dcf355
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 41 deletions.
57 changes: 32 additions & 25 deletions src/atomate2/vasp/schemas/task.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,14 +52,16 @@ class AnalysisSummary(BaseModel):
errors: List[str] = Field(None, description="Errors from the VASP drone")

@classmethod
def from_vasp_calc_docs(cls, calc_docs: List[Calculation]) -> "AnalysisSummary":
def from_vasp_calc_docs(
cls, calcs_reversed: List[Calculation]
) -> "AnalysisSummary":
"""
Create analysis summary from VASP calculation documents.
Parameters
----------
calc_docs
VASP calculation documents.
calcs_reversed
A list of VASP calculation documents in reverse order .
Returns
-------
Expand All @@ -68,8 +70,8 @@ def from_vasp_calc_docs(cls, calc_docs: List[Calculation]) -> "AnalysisSummary":
"""
from atomate2.vasp.schemas.calculation import Status

initial_vol = calc_docs[0].input.structure.lattice.volume
final_vol = calc_docs[-1].output.structure.lattice.volume
initial_vol = calcs_reversed[-1].input.structure.lattice.volume
final_vol = calcs_reversed[0].output.structure.lattice.volume
delta_vol = final_vol - initial_vol
percent_delta_vol = 100 * delta_vol / initial_vol
warnings = []
Expand All @@ -80,13 +82,13 @@ def from_vasp_calc_docs(cls, calc_docs: List[Calculation]) -> "AnalysisSummary":
f"Volume change > {SETTINGS.VASP_VOLUME_CHANGE_WARNING_TOL * 100}%"
)

final_calc = calc_docs[-1]
final_calc = calcs_reversed[0]
max_force = None
if final_calc.has_vasp_completed == Status.SUCCESS:
# max force and valid structure checks
structure = final_calc.output.structure
# do not check max force for MD run
if calc_docs[-1].input.parameters.get("IBRION", -1) != 0:
if calcs_reversed[0].input.parameters.get("IBRION", -1) != 0:
max_force = _get_max_force(final_calc)
warnings.extend(_get_drift_warnings(final_calc))
if not structure.is_valid():
Expand Down Expand Up @@ -348,6 +350,11 @@ def from_directory(
calcs_reversed.append(calc_doc)
all_vasp_objects.append(vasp_objects)

# Reverse the list of calculations in the order: newest calc is the first
# To match with calcs_reversed, all_vasp_objects is also reversed.
calcs_reversed.reverse()
all_vasp_objects.reverse()

analysis = AnalysisSummary.from_vasp_calc_docs(calcs_reversed)
transformations, icsd_id, tags, author = _parse_transformations(dir_name)
custodian = _parse_custodian(dir_name)
Expand All @@ -361,13 +368,13 @@ def from_directory(

# only store objects from last calculation
# TODO: make this an option
vasp_objects = all_vasp_objects[-1]
vasp_objects = all_vasp_objects[0]
included_objects = None
if vasp_objects:
included_objects = list(vasp_objects.keys())

doc = cls.from_structure(
structure=calcs_reversed[-1].output.structure,
structure=calcs_reversed[0].output.structure,
include_structure=True,
dir_name=dir_name,
calcs_reversed=calcs_reversed,
Expand All @@ -379,10 +386,10 @@ def from_directory(
icsd_id=icsd_id,
tags=tags,
author=author,
completed_at=calcs_reversed[-1].completed_at,
input=InputSummary.from_vasp_calc_doc(calcs_reversed[0]),
completed_at=calcs_reversed[0].completed_at,
input=InputSummary.from_vasp_calc_doc(calcs_reversed[-1]),
output=OutputSummary.from_vasp_calc_doc(
calcs_reversed[-1], vasp_objects.get(VaspObject.TRAJECTORY) # type: ignore
calcs_reversed[0], vasp_objects.get(VaspObject.TRAJECTORY) # type: ignore
),
state=_get_state(calcs_reversed, analysis),
entry=cls.get_entry(calcs_reversed),
Expand All @@ -395,15 +402,15 @@ def from_directory(

@staticmethod
def get_entry(
calc_docs: List[Calculation], job_id: Optional[str] = None
calcs_reversed: List[Calculation], job_id: Optional[str] = None
) -> ComputedEntry:
"""
Get a computed entry from a list of VASP calculation documents.
Parameters
----------
calc_docs
A list of VASP calculation documents.
calcs_reversed
A list of VASP calculation documents in a reverse order.
job_id
The job identifier.
Expand All @@ -415,16 +422,16 @@ def get_entry(
entry_dict = {
"correction": 0.0,
"entry_id": job_id,
"composition": calc_docs[-1].output.structure.composition,
"energy": calc_docs[-1].output.energy,
"composition": calcs_reversed[0].output.structure.composition,
"energy": calcs_reversed[0].output.energy,
"parameters": {
"potcar_spec": calc_docs[-1].input.potcar_spec,
"potcar_spec": calcs_reversed[0].input.potcar_spec,
# Required to be compatible with MontyEncoder for the ComputedEntry
"run_type": str(calc_docs[-1].run_type),
"run_type": str(calcs_reversed[0].run_type),
},
"data": {
"oxide_type": oxide_type(calc_docs[-1].output.structure),
"aspherical": calc_docs[-1].input.parameters.get("LASPH", False),
"oxide_type": oxide_type(calcs_reversed[0].output.structure),
"aspherical": calcs_reversed[0].input.parameters.get("LASPH", False),
"last_updated": datetime_str(),
},
}
Expand Down Expand Up @@ -566,17 +573,17 @@ def _get_drift_warnings(calc_doc: Calculation) -> List[str]:
return warnings


def _get_state(calc_docs: List[Calculation], analysis: AnalysisSummary) -> Status:
def _get_state(calcs_reversed: List[Calculation], analysis: AnalysisSummary) -> Status:
"""Get state from calculation documents and relaxation analysis."""
all_calcs_completed = all(
[c.has_vasp_completed == Status.SUCCESS for c in calc_docs]
[c.has_vasp_completed == Status.SUCCESS for c in calcs_reversed]
)
if len(analysis.errors) == 0 and all_calcs_completed:
return Status.SUCCESS # type: ignore
return Status.FAILED # type: ignore


def _get_run_stats(calc_docs: List[Calculation]) -> Dict[str, RunStatistics]:
def _get_run_stats(calcs_reversed: List[Calculation]) -> Dict[str, RunStatistics]:
"""Get summary of runtime statistics for each calculation in this task."""
run_stats = {}
total = dict(
Expand All @@ -588,7 +595,7 @@ def _get_run_stats(calc_docs: List[Calculation]) -> Dict[str, RunStatistics]:
total_time=0.0,
cores=0,
)
for calc_doc in calc_docs:
for calc_doc in calcs_reversed:
stats = calc_doc.output.run_stats
run_stats[calc_doc.task_name] = stats
total["average_memory"] = max(total["average_memory"], stats.average_memory)
Expand Down
22 changes: 11 additions & 11 deletions tests/vasp/schemas/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,34 +43,34 @@ class SchemaTestData:
class SiOptimizeDouble(SchemaTestData):
folder = "Si_old_double_relax"
task_files = {
"relax1": {
"vasprun_file": "vasprun.xml.relax1.gz",
"outcar_file": "OUTCAR.relax1.gz",
"volumetric_files": ["CHGCAR.relax1.gz"],
"contcar_file": "CONTCAR.relax1.gz",
},
"relax2": {
"vasprun_file": "vasprun.xml.relax2.gz",
"outcar_file": "OUTCAR.relax2.gz",
"volumetric_files": ["CHGCAR.relax2.gz"],
"contcar_file": "CONTCAR.relax2.gz",
},
"relax1": {
"vasprun_file": "vasprun.xml.relax1.gz",
"outcar_file": "OUTCAR.relax1.gz",
"volumetric_files": ["CHGCAR.relax1.gz"],
"contcar_file": "CONTCAR.relax1.gz",
},
}
objects = {"relax1": []}
objects = {"relax2": []}
task_doc = {
"calcs_reversed": [
{
"output": {
"vbm": 5.6149,
"cbm": 6.2649,
"bandgap": 0.65,
"vbm": 5.6147,
"cbm": 6.2652,
"bandgap": 0.6505,
"is_gap_direct": False,
"is_metal": False,
"transition": "(0.000,0.000,0.000)-(0.375,0.375,0.000)",
"direct_gap": 2.5561,
"run_stats": {
"average_memory": 0,
"max_memory": 28640.0,
"max_memory": 28096.0,
"cores": 16,
},
},
Expand Down
4 changes: 2 additions & 2 deletions tests/vasp/schemas/test_calculation.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ def test_calculation_input(vasp_test_dir, object_name, task_name):
@pytest.mark.parametrize(
"object_name,task_name",
[
pytest.param("SiOptimizeDouble", "relax1", id="SiOptimizeDouble"),
pytest.param("SiOptimizeDouble", "relax2", id="SiOptimizeDouble"),
pytest.param("SiStatic", "standard", id="SiStatic"),
pytest.param("SiNonSCFUniform", "standard", id="SiNonSCFUniform"),
],
Expand Down Expand Up @@ -133,7 +133,7 @@ def test_run_statistics(vasp_test_dir, object_name, task_name):
@pytest.mark.parametrize(
"object_name,task_name",
[
pytest.param("SiOptimizeDouble", "relax1", id="SiOptimizeDouble"),
pytest.param("SiOptimizeDouble", "relax2", id="SiOptimizeDouble"),
pytest.param("SiStatic", "standard", id="SiStatic"),
pytest.param("SiNonSCFUniform", "standard", id="SiNonSCFUniform"),
],
Expand Down
8 changes: 5 additions & 3 deletions tests/vasp/schemas/test_task.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,14 @@ def test_analysis_summary(vasp_test_dir, object_name):
test_object = get_test_object(object_name)
dir_name = vasp_test_dir / test_object.folder / "outputs"

calcs_docs = []
calcs_reversed = []
for task_name, files in test_object.task_files.items():
doc, _ = Calculation.from_vasp_files(dir_name, task_name, **files)
calcs_docs.append(doc)
calcs_reversed.append(doc)
## The 2 tasks of double-relaxation have been reversed in "/atomate2/tests/vasp/schemas/conftest.py" for "SiOptimizeDouble"
## task_files are in the order of {"relax2","relax1"}

test_doc = AnalysisSummary.from_vasp_calc_docs(calcs_docs)
test_doc = AnalysisSummary.from_vasp_calc_docs(calcs_reversed)
valid_doc = test_object.task_doc["analysis"]
assert_schemas_equal(test_doc, valid_doc)

Expand Down

0 comments on commit 9dcf355

Please sign in to comment.