Skip to content

Commit

Permalink
Nodes for the atomistics package
Browse files Browse the repository at this point in the history
Example:
```
from pyiron_workflow import Workflow
from pyiron_workflow.atomistics_library.calculatornodes import get_emt, calc_with_calculator
from pyiron_workflow.atomistics_library.tasknodes import get_evcurve_task_generator, analyse_structures, generate_structures, get_bulk

wf = Workflow("evcurve")
wf.get_structure = get_bulk(element="Al")
wf.get_task_generator = get_evcurve_task_generator(structure=wf.get_structure)
wf.generate_structures = generate_structures(instance=wf.get_task_generator)
wf.get_calculator = get_emt()
wf.calc_with_calculator = calc_with_calculator(task_dict=wf.generate_structures, calculator=wf.get_calculator)
wf.fit = analyse_structures(instance=wf.get_task_generator, output_dict=wf.calc_with_calculator)

wf.draw()

wf.run()
```
As the workflows in the `atomistics` package all follow the same pattern of (0) initializing the generator, (1) generating atomic structures, (2) evaluate the atomic structures with a simulation code and (3) analyse the results, the integration was rather straight forward.
  • Loading branch information
jan-janssen committed Nov 15, 2023
1 parent 7b02bc0 commit af12c58
Show file tree
Hide file tree
Showing 3 changed files with 193 additions and 0 deletions.
Empty file.
113 changes: 113 additions & 0 deletions pyiron_workflow/atomistics_library/calculatornodes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
from ase.units import Ry

from pyiron_workflow.function import single_value_node


@single_value_node(output_labels="calculator")
def get_emt():
from ase.calculators.emt import EMT
return EMT()


@single_value_node(output_labels="calculator")
def get_abinit(
label='abinit_evcurve',
nbands=32,
ecut=10 * Ry,
kpts=(3, 3, 3),
toldfe=1.0e-2,
v8_legacy_format=False,
):
from ase.calculators.abinit import Abinit
return Abinit(
label=label,
nbands=nbands,
ecut=ecut,
kpts=kpts,
toldfe=toldfe,
v8_legacy_format=v8_legacy_format,
)


@single_value_node(output_labels="calculator")
def get_gpaw(
xc="PBE",
encut=300,
kpts=(3, 3, 3)
):
from gpaw import GPAW, PW
return GPAW(
xc=xc,
mode=PW(encut),
kpts=kpts
)


@single_value_node(output_labels="calculator")
def get_quantum_espresso(
pseudopotentials={"Al": "Al.pbe-n-kjpaw_psl.1.0.0.UPF"},
tstress=True,
tprnfor=True,
kpts=(3, 3, 3),
):
from ase.calculators.espresso import Espresso
return Espresso(
pseudopotentials=pseudopotentials,
tstress=tstress,
tprnfor=tprnfor,
kpts=kpts,
)


@single_value_node(output_labels="calculator")
def get_siesta(
label="siesta",
xc="PBE",
mesh_cutoff=200 * Ry,
energy_shift=0.01 * Ry,
basis_set="DZ",
kpts=(5, 5, 5),
fdf_arguments={"DM.MixingWeight": 0.1, "MaxSCFIterations": 100},
pseudo_path="",
pseudo_qualifier="",
):
from ase.calculators.siesta import Siesta
return Siesta(
label=label,
xc=xc,
mesh_cutoff=mesh_cutoff,
energy_shift=energy_shift,
basis_set=basis_set,
kpts=kpts,
fdf_arguments=fdf_arguments,
pseudo_path=pseudo_path,
pseudo_qualifier=pseudo_qualifier,
)


@single_value_node(output_labels="energy_dict")
def calc_with_calculator(task_dict, calculator):
from atomistics.calculators.ase import evaluate_with_ase
return evaluate_with_ase(
task_dict=task_dict,
ase_calculator=calculator
)


@single_value_node(output_labels="lammps_potential_dataframe")
def get_lammps_potential(potential_name, structure, resource_path):
from atomistics.calculators.lammps import get_potential_dataframe
df_pot = get_potential_dataframe(
structure=structure,
resource_path=resource_path
)
return df_pot[df_pot.Name == potential_name].iloc[0]


@single_value_node(output_labels="energy_dict")
def get_lammps(task_dict, potential_dataframe):
from atomistics.calculators.lammps import evaluate_with_lammps
return evaluate_with_lammps(
task_dict=task_dict,
potential_dataframe=potential_dataframe,
)
80 changes: 80 additions & 0 deletions pyiron_workflow/atomistics_library/tasknodes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
from phonopy.units import VaspToTHz
from pyiron_workflow.function import single_value_node


@single_value_node(output_labels="task_generator")
def get_elastic_matrix_task_generator(
structure,
num_of_point=5,
eps_range=0.05,
sqrt_eta=True,
fit_order=2
):
from atomistics.workflows.elastic.workflow import ElasticMatrixWorkflow
return ElasticMatrixWorkflow(
structure=structure,
num_of_point=num_of_point,
eps_range=eps_range,
sqrt_eta=sqrt_eta,
fit_order=fit_order,
)


@single_value_node(output_labels="task_generator")
def get_evcurve_task_generator(
structure,
num_points=11,
fit_type='polynomial',
fit_order=3,
vol_range=0.05,
axes=['x', 'y', 'z'],
strains=None
):
from atomistics.workflows.evcurve.workflow import EnergyVolumeCurveWorkflow
return EnergyVolumeCurveWorkflow(
structure=structure,
num_points=num_points,
fit_type=fit_type,
fit_order=fit_order,
vol_range=vol_range,
axes=axes,
strains=strains,
)


@single_value_node(output_labels="task_generator")
def get_phonons_task_generator(
structure,
interaction_range=10,
factor=VaspToTHz,
displacement=0.01,
dos_mesh=20,
primitive_matrix=None,
number_of_snapshots=None,
):
from atomistics.workflows.phonons.workflow import PhonopyWorkflow
return PhonopyWorkflow(
structure=structure,
interaction_range=interaction_range,
factor=factor,
displacement=displacement,
dos_mesh=dos_mesh,
primitive_matrix=primitive_matrix,
number_of_snapshots=number_of_snapshots,
)


@single_value_node(output_labels="result_dict")
def analyse_structures(instance, output_dict):
return instance.analyse_structures(output_dict=output_dict)


@single_value_node(output_labels="task_dict")
def generate_structures(instance):
return instance.generate_structures()


@single_value_node(output_labels="structure")
def get_bulk(element):
from ase.build import bulk
return bulk(element, a=4.00, cubic=True)

0 comments on commit af12c58

Please sign in to comment.