Skip to content

Latest commit

 

History

History
67 lines (60 loc) · 4.17 KB

evcurve.md

File metadata and controls

67 lines (60 loc) · 4.17 KB

Energy Volume Curve

Based on previous work from the ADIS 2023 workshop the calculation of an energy volume curve with the quantum espresso density functional theory (DFT) simulation code is implemented in the Python Workflow Definition.

Workflow

An energy-volume curve is computed by relaxing a bulk crystal structure, straining it to a series of volumes and computing the total energy at each volume with a self-consistent-field (SCF) calculation. The pipeline is implemented as five Python functions in workflow.py:

def get_bulk_structure(element, a, cubic):
    # build an ASE bulk crystal structure, e.g. Al

def calculate_qe(working_directory, input_dict):
    # write a pw.x input file, run "pw.x -in input.pwi > output.pwo" and parse the pwscf.xml output;
    # input_dict["calculation"] selects "vc-relax" (cell + geometry relaxation) or "scf" (single-point energy)

def generate_structures(structure, strain_lst):
    # apply each volumetric strain in strain_lst to a structure, returning one structure per strain

def plot_energy_volume_curve(volume_lst, energy_lst):
    # plot energy against volume and save it as evcurve.png

write_input/collect_output handle the file-based pw.x input/output (.pwi/.pwo/.xml files), and ase_to_json/json_to_ase (de)serialize ASE Atoms objects to/from OPTIMADE-JSON strings, so structures can be passed between functions as plain JSON data instead of Python objects.

The workflow combines these functions as: get_bulk_structure -> calculate_qe (vc-relax, once) -> generate_structures -> calculate_qe (scf, once per strained structure) -> plot_energy_volume_curve. With five strains this means one relaxation followed by five independent SCF calculations that fan out from generate_structures and feed back into a single plot.

workflow.json

workflow.json encodes this fan-out as five separate workflow.calculate_qe function nodes, each connected to its own strained structure and its own working_directory input, all reading the same shared inputs (pseudopotentials, kpts, calculation, smearing) via python_workflow_definition.shared.get_dict. An excerpt showing the pattern for two of the five strained calculations:

{
  "nodes": [
    {"id": 2, "type": "function", "value": "workflow.generate_structures"},
    {"id": 3, "type": "function", "value": "workflow.calculate_qe"},
    {"id": 4, "type": "function", "value": "workflow.calculate_qe"},
    {"id": 19, "type": "input", "value": "strain_0", "name": "working_directory_1"},
    {"id": 20, "type": "function", "value": "python_workflow_definition.shared.get_dict"},
    {"id": 22, "type": "input", "value": "strain_1", "name": "working_directory_2"},
    {"id": 23, "type": "function", "value": "python_workflow_definition.shared.get_dict"}
  ],
  "edges": [
    {"target": 3, "targetPort": "working_directory", "source": 19, "sourcePort": null},
    {"target": 20, "targetPort": "structure", "source": 2, "sourcePort": "s_0"},
    {"target": 3, "targetPort": "input_dict", "source": 20, "sourcePort": null},
    {"target": 4, "targetPort": "working_directory", "source": 22, "sourcePort": null},
    {"target": 23, "targetPort": "structure", "source": 2, "sourcePort": "s_1"},
    {"target": 4, "targetPort": "input_dict", "source": 23, "sourcePort": null}
  ]
}

Node 2 (generate_structures) exposes one output port per strain (s_0, s_1, ...); each port is wired into its own get_dict/calculate_qe pair. The energy and volume outputs of all five calculate_qe nodes are collected back into lists with python_workflow_definition.shared.get_list before being passed to plot_energy_volume_curve.

Requirements

Running this workflow (rather than just loading/inspecting the JSON) requires the Quantum Espresso pw.x binary, matching pseudopotential files (see espresso/pseudo) and the Python dependencies listed in environment.yml.