diff --git a/.ci_support/environment.yml b/.ci_support/environment.yml index f2db1314d..7970e98b1 100644 --- a/.ci_support/environment.yml +++ b/.ci_support/environment.yml @@ -16,3 +16,4 @@ dependencies: - randspg =0.0.1 - boto3 =1.26.32 - moto =4.0.12 +- pycp2k =0.2.2 \ No newline at end of file diff --git a/pyiron_contrib/__init__.py b/pyiron_contrib/__init__.py index 624f2daaf..3a43350a1 100644 --- a/pyiron_contrib/__init__.py +++ b/pyiron_contrib/__init__.py @@ -46,8 +46,10 @@ JOB_CLASS_DICT['StorageJob'] = 'pyiron_contrib.RDM.storagejob' JOB_CLASS_DICT['PacemakerJob'] = 'pyiron_contrib.atomistics.pacemaker.job' JOB_CLASS_DICT['MeamFit'] = 'pyiron_contrib.atomistics.meamfit.meamfit' +JOB_CLASS_DICT['Cp2kJob'] = 'pyiron_contrib.atomistics.cp2k.job' + from ._version import get_versions __version__ = get_versions()["version"] -del get_versions \ No newline at end of file +del get_versions diff --git a/pyiron_contrib/atomistics/cp2k/__init__.py b/pyiron_contrib/atomistics/cp2k/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/pyiron_contrib/atomistics/cp2k/job.py b/pyiron_contrib/atomistics/cp2k/job.py new file mode 100644 index 000000000..0b47e1099 --- /dev/null +++ b/pyiron_contrib/atomistics/cp2k/job.py @@ -0,0 +1,119 @@ +import os +from pyiron_base import DataContainer, state +from pyiron_atomistics.atomistics.structure.atoms import pyiron_to_ase, ase_to_pyiron +from pyiron_atomistics.atomistics.job.atomistic import AtomisticGenericJob +from pycp2k import CP2K + + +pyiron_dict = { + "global": { + "run_type": "ENERGY_FORCE" + }, + "force_eval": { + "method": "Quickstep", + "print_forces_section": "ON" + }, + "dft": { + "qs": { + "eps": 1.0E-10 + }, + "mgrid": { + "ngrids": 4, + "cutoff": 300, + "rel_cutoff": 60 + }, + "xc": { + "functional": "PADE" + } + }, + "scf": { + "scf_guess": "ATOMIC", + "eps": 1.0E-7, + "max": 300, + "diagonalization": { + "algorthim": "STANDARD" + }, + "mixing": { + "method": "BROYDEN_MIXING", + "alpha": 0.4, + "n_broyden": 8, + } + }, + "kind": { + "basis_set": "DZVP-GTH-PADE", + "potential": "GTH-PADE-q4" + } +} + + +class Cp2kJob(AtomisticGenericJob): + def __init__(self, project, job_name): + super(Cp2kJob, self).__init__(project, job_name) + self.__name__ = "cp2k" + self.input = DataContainer(pyiron_dict, table_name="control_dict") + + 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(Cp2kJob, self).to_hdf(hdf=hdf, group_name=group_name) + self._structure_to_hdf() + with self.project_hdf5.open("input") as hdf5_input: + self.input.to_hdf(hdf5_input) + + 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(Cp2kJob, self).from_hdf(hdf=hdf, group_name=group_name) + self._structure_from_hdf() + with self.project_hdf5.open("input") as hdf5_input: + self.input.from_hdf(hdf5_input) + + def write_input(self): + calc = CP2K() + calc.working_directory = self.working_directory + calc.project_name = "pyiron" + CP2K_INPUT = calc.CP2K_INPUT + GLOBAL = CP2K_INPUT.GLOBAL + FORCE_EVAL = CP2K_INPUT.FORCE_EVAL_add() # Repeatable items have to be first created + SUBSYS = FORCE_EVAL.SUBSYS + DFT = FORCE_EVAL.DFT + SCF = DFT.SCF + GLOBAL.Run_type = self.input["global"]["run_type"] + FORCE_EVAL.Method = self.input["force_eval"]["method"] + FORCE_EVAL.PRINT.FORCES.Section_parameters = self.input["force_eval"]["print_forces_section"] + DFT.Basis_set_file_name = os.path.join(state.settings.resource_paths[0], "cp2k", "potentials", "BASIS_SET") + DFT.Potential_file_name = os.path.join(state.settings.resource_paths[0], "cp2k", "potentials", "GTH_POTENTIALS") + DFT.QS.Eps_default = self.input["dft"]["qs"]["eps"] + DFT.MGRID.Ngrids = self.input["dft"]["mgrid"]["ngrids"] + DFT.MGRID.Cutoff = self.input["dft"]["mgrid"]["cutoff"] + DFT.MGRID.Rel_cutoff = self.input["dft"]["mgrid"]["rel_cutoff"] + DFT.XC.XC_FUNCTIONAL.Section_parameters = self.input["dft"]["xc"]["functional"] + SCF.Scf_guess = self.input["scf"]["scf_guess"] + SCF.Eps_scf = self.input["scf"]["eps"] + SCF.Max_scf = self.input["scf"]["max"] + SCF.DIAGONALIZATION.Section_parameters = "ON" + SCF.DIAGONALIZATION.Algorithm = self.input["scf"]["diagonalization"]["algorthim"] + SCF.MIXING.Section_parameters = "T" + SCF.MIXING.Method = self.input["scf"]["mixing"]["method"] + SCF.MIXING.Alpha = self.input["scf"]["mixing"]["alpha"] + SCF.MIXING.Nbroyden = self.input["scf"]["mixing"]["n_broyden"] + for el in set(self.structure.get_chemical_symbols()): + KIND = SUBSYS.KIND_add(el) + KIND.Basis_set = self.input["kind"]["basis_set"] + KIND.Potential = self.input["kind"]["potential"] + calc.create_cell(SUBSYS, pyiron_to_ase(self.structure)) + calc.create_coord(SUBSYS, pyiron_to_ase(self.structure)) + calc.write_input_file() + + def collect_output(self): + pass diff --git a/setup.py b/setup.py index 3f80c9435..e23470303 100644 --- a/setup.py +++ b/setup.py @@ -42,6 +42,7 @@ 'atomistic': [ 'ase==3.22.1', 'pyiron_atomistics==0.2.61', + 'pycp2k==0.2.2', ], 'fenics': [ 'fenics==2019.1.0',