From 75e4c58526e7c4ba2b72e19d47e6595cbc7173fb Mon Sep 17 00:00:00 2001 From: Jan Janssen Date: Fri, 21 Mar 2025 09:38:29 +0100 Subject: [PATCH 1/5] Use JSON conversion for ASE atoms --- quantum_espresso_workflow.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/quantum_espresso_workflow.py b/quantum_espresso_workflow.py index 3eca694..15b82af 100644 --- a/quantum_espresso_workflow.py +++ b/quantum_espresso_workflow.py @@ -31,7 +31,7 @@ def write_input(input_dict, working_directory="."): def collect_output(working_directory="."): output = parse_pw(os.path.join(working_directory, "pwscf.xml")) return { - "structure": output["ase_structure"].todict(), + "structure": atoms_to_json_dict(atoms=output["ase_structure"]), "energy": output["energy"], "volume": output["ase_structure"].get_volume(), } From 8f5307e9e2da52539425790a0ac2bc530e83ad6e Mon Sep 17 00:00:00 2001 From: Jan Janssen Date: Fri, 21 Mar 2025 09:41:14 +0100 Subject: [PATCH 2/5] Add optimade as dependency --- environment.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/environment.yml b/environment.yml index d45b9d0..f76c3ac 100644 --- a/environment.yml +++ b/environment.yml @@ -10,4 +10,5 @@ dependencies: - matplotlib=3.10.1 - xmlschema=3.4.3 - jobflow=0.1.19 -- pygraphviz=1.14 \ No newline at end of file +- pygraphviz=1.14 +- optimade=1.2.3 From 92234c1a2e5e03a505bc2d5bceafc073df49e40e Mon Sep 17 00:00:00 2001 From: Jan Janssen Date: Fri, 21 Mar 2025 09:48:18 +0100 Subject: [PATCH 3/5] Update quantum_espresso_workflow.py --- quantum_espresso_workflow.py | 58 +++++++++++------------------------- 1 file changed, 17 insertions(+), 41 deletions(-) diff --git a/quantum_espresso_workflow.py b/quantum_espresso_workflow.py index 15b82af..dfd1ca7 100644 --- a/quantum_espresso_workflow.py +++ b/quantum_espresso_workflow.py @@ -7,6 +7,8 @@ from adis_tools.parsers import parse_pw import matplotlib.pyplot as plt import numpy as np +from optimade.adapters.structures.ase import from_ase_atoms, get_ase_atoms +from optimade.models.structures import StructureResourceAttributes, StructureResource def write_input(input_dict, working_directory="."): @@ -14,7 +16,7 @@ def write_input(input_dict, working_directory="."): os.makedirs(working_directory, exist_ok=True) write( filename=filename, - images=Atoms(**input_dict["structure"]), + images=json_to_ase(atoms_json=input_dict["structure"]), Crystal=True, kpts=input_dict["kpts"], input_data={ @@ -31,7 +33,7 @@ def write_input(input_dict, working_directory="."): def collect_output(working_directory="."): output = parse_pw(os.path.join(working_directory, "pwscf.xml")) return { - "structure": atoms_to_json_dict(atoms=output["ase_structure"]), + "structure": ase_to_json(atoms=output["ase_structure"]), "energy": output["energy"], "volume": output["ase_structure"].get_volume(), } @@ -53,12 +55,12 @@ def calculate_qe(working_directory, input_dict): def generate_structures(structure, strain_lst): structure_lst = [] for strain in strain_lst: - structure_strain = Atoms(**structure) + structure_strain = json_to_ase(atoms_json=structure) structure_strain.set_cell( structure_strain.cell * strain ** (1 / 3), scale_atoms=True ) structure_lst.append(structure_strain) - return {f"s_{i}": atoms_to_json_dict(atoms=s) for i, s in enumerate(structure_lst)} + return {f"s_{i}": ase_to_json(atoms=s) for i, s in enumerate(structure_lst)} def plot_energy_volume_curve(volume_lst, energy_lst): @@ -74,40 +76,14 @@ def get_bulk_structure(element, a, cubic): a=a, cubic=cubic, ) - return atoms_to_json_dict(atoms=ase_atoms) - - -def atoms_to_json_dict(atoms): - """ - Convert an ASE Atoms object to a fully JSON-serializable dictionary - that uses only Python base data types. - - Parameters: - ----------- - atoms : ase.Atoms - The Atoms object to convert - - Returns: - -------- - dict - A dictionary representation using only Python base types - """ - # Get the dictionary representation from ASE - atoms_dict = atoms.todict() - - # Create a new dictionary with JSON-serializable values - json_dict = {} - - # Convert numpy arrays to lists - for key, value in atoms_dict.items(): - if isinstance(value, np.ndarray): - # Convert numpy boolean values to Python booleans - if value.dtype == np.bool_ or value.dtype == bool: - json_dict[key] = value.tolist() - # Convert numpy arrays of numbers to Python lists - else: - json_dict[key] = value.tolist() - else: - json_dict[key] = value - - return json_dict + return ase_to_json(atoms=ase_atoms) + + +def ase_to_json(atoms): + struct_opt = from_ase_atoms(atoms=atoms) + return json.dumps(struct_opt.model_dump(mode="json")) + + +def json_to_ase(atoms_json): + structure_restore = StructureResourceAttributes.model_validate_json(atoms_json)) + return get_ase_atoms(optimade_structure=StructureResource(id="ase", attributes=structure_restore)) From 3a014b3179b09ff9ccd78103feaf716ec2cf99a8 Mon Sep 17 00:00:00 2001 From: Jan Janssen Date: Fri, 21 Mar 2025 09:51:09 +0100 Subject: [PATCH 4/5] Update quantum_espresso_workflow.py --- quantum_espresso_workflow.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/quantum_espresso_workflow.py b/quantum_espresso_workflow.py index dfd1ca7..e90ea50 100644 --- a/quantum_espresso_workflow.py +++ b/quantum_espresso_workflow.py @@ -85,5 +85,5 @@ def ase_to_json(atoms): def json_to_ase(atoms_json): - structure_restore = StructureResourceAttributes.model_validate_json(atoms_json)) + structure_restore = StructureResourceAttributes.model_validate_json(atoms_json) return get_ase_atoms(optimade_structure=StructureResource(id="ase", attributes=structure_restore)) From dd2f0c89cf160a34a5bdffa15b063395ce867dbf Mon Sep 17 00:00:00 2001 From: Jan Janssen Date: Fri, 21 Mar 2025 09:56:03 +0100 Subject: [PATCH 5/5] Update quantum_espresso_workflow.py --- quantum_espresso_workflow.py | 1 + 1 file changed, 1 insertion(+) diff --git a/quantum_espresso_workflow.py b/quantum_espresso_workflow.py index e90ea50..f9b8ff8 100644 --- a/quantum_espresso_workflow.py +++ b/quantum_espresso_workflow.py @@ -1,3 +1,4 @@ +import json import os import subprocess