diff --git a/emmet-builders/emmet/builders/vasp/materials.py b/emmet-builders/emmet/builders/vasp/materials.py index e9d95a347d..23de7cef0f 100644 --- a/emmet-builders/emmet/builders/vasp/materials.py +++ b/emmet-builders/emmet/builders/vasp/materials.py @@ -230,6 +230,8 @@ def process_item(self, items: List[Dict]) -> List[Dict]: f"No valid ids found among ids {failed_ids}. This can be the case if the required " "calculation types are missing from your tasks database." ) + materials.append(MaterialsDoc.construct_deprecated_material(tasks)) + self.logger.debug(f"Produced {len(materials)} materials for {formula}") return jsanitize([mat.dict() for mat in materials], allow_bson=True) diff --git a/emmet-builders/emmet/builders/vasp/thermo.py b/emmet-builders/emmet/builders/vasp/thermo.py index 6428ffc2f9..d28aa23bbc 100644 --- a/emmet-builders/emmet/builders/vasp/thermo.py +++ b/emmet-builders/emmet/builders/vasp/thermo.py @@ -115,7 +115,9 @@ def get_items(self) -> Iterator[List[Dict]]: # Yield the chemical systems in order of increasing size # Will build them in a similar manner to fast Pourbaix - for chemsys in sorted(to_process_chemsys, key=lambda x: len(x.split("-"))): + for chemsys in sorted( + to_process_chemsys, key=lambda x: len(x.split("-")), reverse=True + ): entries = self.get_entries(chemsys) yield entries diff --git a/emmet-core/emmet/core/vasp/material.py b/emmet-core/emmet/core/vasp/material.py index c6a81f0e6d..a608ff3ffd 100644 --- a/emmet-core/emmet/core/vasp/material.py +++ b/emmet-core/emmet/core/vasp/material.py @@ -165,3 +165,61 @@ def _structure_eval(task: TaskDocument): origins=origins, entries=entries, ) + + @classmethod + def construct_deprecated_material( + cls, + task_group: List[TaskDocument], + ) -> "MaterialsDoc": + """ + Converts a group of tasks into a deprecated material + + Args: + task_group: List of task document + """ + if len(task_group) == 0: + raise Exception("Must have more than one task in the group.") + + # Metadata + last_updated = max(task.last_updated for task in task_group) + created_at = min(task.completed_at for task in task_group) + task_ids = list({task.task_id for task in task_group}) + + deprecated_tasks = {task.task_id for task in task_group} + run_types = {task.task_id: task.run_type for task in task_group} + task_types = {task.task_id: task.task_type for task in task_group} + calc_types = {task.task_id: task.calc_type for task in task_group} + + # Material ID + material_id = min([task.task_id for task in task_group]) + + # Choose any random structure for metadata + structure = SpacegroupAnalyzer( + task_group[0].output.structure, symprec=0.1 + ).get_conventional_standard_structure() + + # Initial Structures + initial_structures = [task.input.structure for task in task_group] + sm = StructureMatcher( + ltol=0.1, stol=0.1, angle_tol=0.1, scale=False, attempt_supercell=False + ) + initial_structures = [ + group[0] for group in sm.group_structures(initial_structures) + ] + + # Deprecated + deprecated = True + + return cls.from_structure( + structure=structure, + material_id=material_id, + last_updated=last_updated, + created_at=created_at, + task_ids=task_ids, + calc_types=calc_types, + run_types=run_types, + task_types=task_types, + initial_structures=initial_structures, + deprecated=deprecated, + deprecated_tasks=deprecated_tasks, + ) diff --git a/tests/emmet-core/vasp/test_materials.py b/tests/emmet-core/vasp/test_materials.py index 33222945bf..ba2883dfe7 100644 --- a/tests/emmet-core/vasp/test_materials.py +++ b/tests/emmet-core/vasp/test_materials.py @@ -32,5 +32,18 @@ def test_make_mat(test_tasks): MaterialsDoc.from_tasks(bad_task_group, use_statics=False) +def test_make_deprecated_mat(test_tasks): + bad_task_group = [ + task for task in test_tasks if task.task_type != TaskType.Structure_Optimization + ] + + material = MaterialsDoc.construct_deprecated_material(bad_task_group) + + assert material.deprecated + assert material.formula_pretty == "Si" + assert len(material.task_ids) == 3 + assert material.entries is None + + def test_schema(): MaterialsDoc.schema()