This first part is only needed as we have to mock FHI-aims here as we cannot run it directly in a jupyter notebook:

import warnings

from mock_aims import TEST_DIR, mock_aims

ref_paths = {
    "Relaxation calculation": "phonon-relax-si",
    "phonon static aims 1/1": "phonon-disp-si",
    "SCF Calculation": "phonon-energy-si",
    "phonon static aims anharmonicity quant. 1/1": "anharm-si-full",
}

Phonon Workflow Tutorial with FHI-aims

This tutorial has been written based on the VASP version.

Background

The Phonon workflow is based on the finite displacement approach as implemented in Phonopy.

If you want to read more about Phonopy, please read Togo’s paper: https://doi.org/10.7566/JPSJ.92.012001

Let’s run the workflow

Now, we load a structure and other important functions and classes for running the phonon workflow.

from jobflow import JobStore, run_locally
from maggma.stores import MemoryStore
from pymatgen.core import SETTINGS, Structure

from atomate2.aims.flows.phonons import PhononMaker

warnings.filterwarnings("ignore")

job_store = JobStore(MemoryStore(), additional_stores={"data": MemoryStore()})
si_structure = Structure.from_file(TEST_DIR / "structures" / "Si_diamond.cif")
SETTINGS["AIMS_SPECIES_DIR"] = TEST_DIR / "../aims/species_dir/tight"

Then one can use the PhononMaker to generate a Flow. For testing here, we are choosing a very small supercell length (min_length). Ideally, a larger cell should be chosen. For non-metallic systems with more than one element, one might need to add the non-analytical term correction considering very long-ranging forces by computing the BORN charges with the born_maker. Of course, the structure should also be relaxed in advance with the bulk_relax_maker. Please make sure this is done very accurately. For FHI-aims a born_maker still needs to be implemented.

phonon_maker = PhononMaker(
    min_length=3.0,
    generate_frequencies_eigenvectors_kwargs={"tstep": 100},
    create_thermal_displacements=True,
    store_force_constants=True,
    born_maker=None,
    use_symmetrized_structure="primitive",
)
flow = phonon_maker.make(si_structure)

The phonon run will first perform a bulk relaxation, then the displacements are generated and run.

flow.draw_graph().show()

We now run the flow with run_locally. We mock the run here. Normally, you would simply use run_locally without the with mock_aims

with mock_aims(ref_paths=ref_paths) as mf:
    run_locally(
        flow,
        create_folders=True,
        ensure_success=True,
        raise_immediately=True,
        store=job_store,
    )
from pymatgen.phonon.bandstructure import PhononBandStructureSymmLine
from pymatgen.phonon.dos import PhononDos
from pymatgen.phonon.plotter import PhononBSPlotter, PhononDosPlotter

job_store.connect()

result = job_store.query_one(
    {"name": "generate_frequencies_eigenvectors"},
    load=True,
    sort={"completed_at": -1},  # to get the latest computation
)
ph_bs = PhononBandStructureSymmLine.from_dict(
    result["output"]["phonon_bandstructure"]
)  # get pymatgen bandstructure object
ph_dos = PhononDos.from_dict(
    result["output"]["phonon_dos"]
)  # get pymatgen phonon dos object

# initialize dos plotter and visualize dos plot
dos_plot = PhononDosPlotter()
dos_plot.add_dos(label="a", dos=ph_dos)
dos_plot.get_plot()

# initialize Phonon bandstructure plotter and visualize band structure plot
bs_plot = PhononBSPlotter(bs=ph_bs)
bs_plot.get_plot()

One can run the same workflow with a forcefield or VASP as well.

Anharmonicity Quantification

Now that we have a phonon calculation completed, we can quantify the anharmonicty (\(\sigma^A\)) using the method first proposed in this paper: Phys. Rev. Materials 4, 083809 DOI: https://doi.org/10.1103/PhysRevMaterials.4.083809

from atomate2.aims.flows.anharmonicity import AnharmonicityMaker
from atomate2.common.schemas.phonons import PhononBSDOSDoc

anharm_quant_maker = AnharmonicityMaker(phonon_maker=phonon_maker)
phonon_doc = PhononBSDOSDoc(**result["output"])

anharm_flow = anharm_quant_maker.make_from_phonon_doc(
    phonon_doc=phonon_doc,
    one_shot_approx=False,
    seed=1234,
)
with mock_aims(ref_paths=ref_paths) as mf:
    run_locally(
        anharm_flow,
        create_folders=True,
        ensure_success=True,
        raise_immediately=True,
        store=job_store,
    )
result_anharm = job_store.query_one(
    {"name": "get_sigmas"},
    load=True,
    sort={"completed_at": -1},  # to get the latest computation
)
print(f"The estimated anharmonicity is {result_anharm['output']['full']}")  # noqa: T201

We can also use the oneshot method to approximate \(\sigma^A\)

anharm_os_flow = anharm_quant_maker.make_from_phonon_doc(
    phonon_doc=phonon_doc,
    one_shot_approx=True,
    seed=1234,
)
ref_paths = {
    "Relaxation calculation": "phonon-relax-si",
    "phonon static aims 1/1": "phonon-disp-si",
    "SCF Calculation": "phonon-energy-si",
    "phonon static aims anharmonicity quant. 1/1": "anharm-os-si",
}
with mock_aims(ref_paths=ref_paths) as mf:
    run_locally(
        anharm_os_flow,
        create_folders=True,
        ensure_success=True,
        raise_immediately=True,
        store=job_store,
    )
result_anharm = job_store.query_one(
    {"name": "get_sigmas"},
    load=True,
    sort={"completed_at": -1},  # to get the latest computation
)
print(f"The estimated one-shot anharmonicity is {result_anharm['output']['one-shot']}")  # noqa: T201