import numpy as np
import warnings
from pyiron.gpaw.pyiron_ase import AseJob
from pyiron.atomistics.structure.atoms import pyiron_to_ase
from pyiron.base.generic.parameters import GenericParameters
from pyiron.base.settings.generic import Settings
from ase import Atoms
s = Settings()
try:
from gpaw import GPAW, PW, MethfesselPaxton
except ImportError:
pass
[docs]class GpawJob(AseJob):
def __init__(self, project, job_name):
super(GpawJob, self).__init__(project, job_name)
self.__name__ = "GpawJob"
self.input = GpawInput()
@property
def structure(self):
return self._structure
@structure.setter
def structure(self, basis):
if not isinstance(basis, Atoms):
basis = pyiron_to_ase(basis)
self._structure = basis
@property
def encut(self):
return self.plane_wave_cutoff
@encut.setter
def encut(self, val):
self.plane_wave_cutoff = val
@property
def plane_wave_cutoff(self):
return self.input["encut"]
@plane_wave_cutoff.setter
def plane_wave_cutoff(self, val):
self.input["encut"] = val
[docs] def get_k_mesh_by_cell(self, kpoints_per_reciprocal_angstrom, cell=None):
if cell is None:
if self.structure is None:
raise AssertionError('structure not set')
cell = self.structure.cell
latlens = np.linalg.norm(cell, axis=-1)
kmesh = np.rint( 2 * np.pi / latlens * kpoints_per_reciprocal_angstrom)
if kmesh.min() <= 0:
raise AssertionError("kpoint per angstrom too low")
return [int(k) for k in kmesh]
[docs] def set_kpoints(
self,
mesh=None,
scheme="MP",
center_shift=None,
symmetry_reduction=True,
manual_kpoints=None,
weights=None,
reciprocal=True,
kpoints_per_reciprocal_angstrom=None,
):
"""
Function to setup the k-points
Args:
mesh (list): Size of the mesh (ignored if scheme is not set to 'MP' or kpoints_per_reciprocal_angstrom is set)
scheme (str): Type of k-point generation scheme (MP/GP(gamma point)/Manual/Line)
center_shift (list): Shifts the center of the mesh from the gamma point by the given vector in relative
coordinates
symmetry_reduction (boolean): Tells if the symmetry reduction is to be applied to the k-points
manual_kpoints (list/numpy.ndarray): Manual list of k-points
weights(list/numpy.ndarray): Manually supplied weights to each k-point in case of the manual mode
reciprocal (bool): Tells if the supplied values are in reciprocal (direct) or cartesian coordinates (in
reciprocal space)
kpoints_per_reciprocal_angstrom (float): Number of kpoint per angstrom in each direction
"""
if kpoints_per_reciprocal_angstrom is not None:
if mesh is not None:
warnings.warn("mesh value is overwritten by kpoints_per_reciprocal_angstrom")
mesh = self.get_k_mesh_by_cell(kpoints_per_reciprocal_angstrom=kpoints_per_reciprocal_angstrom)
if mesh is not None:
if np.min(mesh) <= 0:
raise ValueError("mesh values must be larger than 0")
if center_shift is not None:
if np.min(center_shift) < 0 or np.max(center_shift) > 1:
warnings.warn("center_shift is given in relative coordinates")
self._set_kpoints(
mesh=mesh,
scheme=scheme,
center_shift=center_shift,
symmetry_reduction=symmetry_reduction,
manual_kpoints=manual_kpoints,
weights=weights,
reciprocal=reciprocal,
)
# Backward compatibility
[docs] def get_encut(self):
return self.encut
[docs] def set_encut(self, encut):
"""
Sets the plane-wave energy cutoff
Args:
encut (float): The energy cutoff in eV
"""
self.plane_wave_cutoff = encut
def _set_kpoints(
self,
mesh=None,
scheme="MP",
center_shift=None,
symmetry_reduction=True,
manual_kpoints=None,
weights=None,
reciprocal=True,
):
if scheme != "MP":
raise ValueError("Currently only MP is supported in the pyiron wrapper.")
if center_shift is not None:
raise ValueError("centershift is not implemented in the pyiron wrapper.")
if not symmetry_reduction:
raise ValueError(
"symmetry_reduction is not implemented in the pyiron wrapper."
)
if manual_kpoints is not None:
raise ValueError(
"manual_kpoints are not implemented in the pyiron wrapper."
)
if weights is not None:
raise ValueError("weights are not implemented in the pyiron wrapper.")
if not reciprocal:
raise ValueError("reciprocal is not implemented in the pyiron wrapper.")
self.input["kpoints"] = mesh
[docs] def collect_output(self):
pass
[docs] def run_static(self):
pre_run_mode = self.server.run_mode
self.server.run_mode.interactive = True
self.run_if_interactive()
self.interactive_close()
self.server.run_mode = pre_run_mode
[docs] def run_if_scheduler(self):
self._create_working_directory()
super(GpawJob, self).run_if_scheduler()
[docs] def run_if_interactive(self):
if self.structure.calc is None:
kpoints = self.input["kpoints"]
if isinstance(kpoints, str):
kpoints = (
self.input["kpoints"].replace("[", "").replace("]", "").split()
)
self._create_working_directory()
calc = GPAW(
mode=PW(float(self.input["encut"])),
xc=self.input["potential"],
occupations=MethfesselPaxton(width=float(self.input["sigma"])),
kpts=kpoints,
txt=self.working_directory + "/" + self.job_name + ".txt",
)
self.structure.set_calculator(calc)
self.status.running = True
self.structure.calc.calculate(self.structure)
self.interactive_collect()
[docs] def to_hdf(self, hdf=None, group_name=None):
"""
Store the ExampleJob object in the HDF5 File
Args:
hdf (ProjectHDFio): HDF5 group object - optional
group_name (str): HDF5 subgroup name - optional
"""
super(GpawJob, self).to_hdf(hdf=hdf, group_name=group_name)
with self.project_hdf5.open("input") as hdf5_input:
self.input.to_hdf(hdf5_input)
[docs] def from_hdf(self, hdf=None, group_name=None):
"""
Restore the ExampleJob object in the HDF5 File
Args:
hdf (ProjectHDFio): HDF5 group object - optional
group_name (str): HDF5 subgroup name - optional
"""
super(GpawJob, self).from_hdf(hdf=hdf, group_name=group_name)
with self.project_hdf5.open("input") as hdf5_input:
self.input.from_hdf(hdf5_input)