diff --git a/pyiron/atomistics/job/interactive.py b/pyiron/atomistics/job/interactive.py index 645abf4f7..5a2b62606 100644 --- a/pyiron/atomistics/job/interactive.py +++ b/pyiron/atomistics/job/interactive.py @@ -7,6 +7,7 @@ from pyiron.atomistics.structure.atoms import Atoms from pyiron.atomistics.structure.periodic_table import PeriodicTable from pyiron.atomistics.job.atomistic import AtomisticGenericJob, GenericOutput +from collections import defaultdict __author__ = "Osamu Waseda, Jan Janssen" __copyright__ = ( @@ -31,24 +32,23 @@ def __init__(self, project, job_name): self._interactive_fetch_completed = True self._interactive_species_lst = np.array([]) self._periodic_table = PeriodicTable() - self.interactive_cache = { - "cells": [], - "energy_pot": [], - "energy_tot": [], - "forces": [], - "positions": [], - "pressures": [], - "stress": [], - "steps": [], - "temperature": [], - "indices": [], - "computation_time": [], - "unwrapped_positions": [], - "atom_spin_constraints": [], - "atom_spins": [], - "magnetic_forces": [], - "volume": [], - } + self.interactive_output_functions = {'cells': self.interactive_cells_getter, + 'energy_pot': self.interactive_energy_pot_getter, + 'energy_tot': self.interactive_energy_tot_getter, + 'forces': self.interactive_forces_getter, + 'positions': self.interactive_positions_getter, + 'pressures': self.interactive_pressures_getter, + 'stress': self.interactive_stress_getter, + 'steps': self.interactive_steps_getter, + 'temperature': self.interactive_temperatures_getter, + 'indices': self.interactive_indices_getter, + 'computation_time': self.interactive_computation_time_getter, + 'unwrapped_positions': self.interactive_unwrapped_positions_getter, + 'atom_spin_constraints': self.interactive_atom_spin_constraints_getter, + 'atom_spins': self.interactive_atom_spins_getter, + 'magnetic_forces': self.interactive_magnetic_forces_getter, + 'volume': self.interactive_volume_getter} + self.interactive_cache = defaultdict(list) @property def interactive_enforce_structure_reset(self): @@ -180,58 +180,15 @@ def interactive_cells_getter(self): return self.initial_structure.cell def interactive_collect(self): - if "cells" in self.interactive_cache.keys(): - self.interactive_cache["cells"].append(self.interactive_cells_getter()) - if "energy_pot" in self.interactive_cache.keys(): - self.interactive_cache["energy_pot"].append( - self.interactive_energy_pot_getter() - ) - if "energy_tot" in self.interactive_cache.keys(): - self.interactive_cache["energy_tot"].append( - self.interactive_energy_tot_getter() - ) - if "forces" in self.interactive_cache.keys(): - self.interactive_cache["forces"].append(self.interactive_forces_getter()) - if "positions" in self.interactive_cache.keys(): - self.interactive_cache["positions"].append( - self.interactive_positions_getter() - ) - if "pressures" in self.interactive_cache.keys(): - self.interactive_cache["pressures"].append( - self.interactive_pressures_getter() - ) - if "stress" in self.interactive_cache.keys(): - self.interactive_cache["stress"].append(self.interactive_stress_getter()) - if "steps" in self.interactive_cache.keys(): - self.interactive_cache["steps"].append(self.interactive_steps_getter()) - if "temperature" in self.interactive_cache.keys(): - self.interactive_cache["temperature"].append( - self.interactive_temperatures_getter() - ) - if "computation_time" in self.interactive_cache.keys(): - self.interactive_cache["computation_time"].append( - self.interactive_time_getter() - ) - if "indices" in self.interactive_cache.keys(): - self.interactive_cache["indices"].append(self.interactive_indices_getter()) - if "atom_spins" in self.interactive_cache.keys(): - self.interactive_cache["atom_spins"].append(self.interactive_spins_getter()) - if "atom_spin_constraints" in self.interactive_cache.keys(): - if self._generic_input["fix_spin_constraint"]: - self.interactive_cache["atom_spin_constraints"].append( - self.interactive_spin_constraints_getter() - ) - if "magnetic_forces" in self.interactive_cache.keys(): - if self._generic_input["fix_spin_constraint"]: - self.interactive_cache["magnetic_forces"].append( - self.interactive_magnetic_forces_getter() - ) - if "unwrapped_positions" in self.interactive_cache.keys(): - self.interactive_cache["unwrapped_positions"].append( - self.interactive_unwrapped_positions_getter() - ) - if "volume" in self.interactive_cache.keys(): - self.interactive_cache["volume"].append(self.interactive_volume_getter()) + del_key_lst = [] + for k,v in self.interactive_output_functions.items(): + try: + self.interactive_cache[k].append(v()) + except NotImplementedError: + del_key_lst.append(k) + for k in del_key_lst: + del self.interactive_output_functions[k] + del self.interactive_cache[k] if ( len(list(self.interactive_cache.keys())) > 0 and len(self.interactive_cache[list(self.interactive_cache.keys())[0]]) @@ -376,6 +333,16 @@ def interactive_spin_constraints_getter(self): "interactive_spin_constraints_getter() is not implemented!" ) + def interactive_atom_spin_constraints_getter(self): + raise NotImplementedError( + "interactive_atom_spin_constraints_getter() is not implemented!" + ) + + def interactive_atom_spins_getter(self): + raise NotImplementedError( + "interactive_atom_spins_getter() is not implemented!" + ) + def interactive_magnetic_forces_getter(self): raise NotImplementedError( "interactive_magnetic_forces_getter() is not implemented!" @@ -403,6 +370,9 @@ def interactive_stress_getter(self): def interactive_structure_setter(self, structure): raise NotImplementedError("interactive_structure_setter() is not implemented!") + def interactive_computation_time_getter(self): + raise NotImplementedError("interactive_computation_time_getter() is not implemented!") + def interactive_temperatures_getter(self): raise NotImplementedError( "interactive_temperatures_getter() is not implemented!" diff --git a/pyiron/atomistics/structure/atoms.py b/pyiron/atomistics/structure/atoms.py index a575f2004..466e6b293 100644 --- a/pyiron/atomistics/structure/atoms.py +++ b/pyiron/atomistics/structure/atoms.py @@ -3467,7 +3467,13 @@ def wrap(self, center=(0.5, 0.5, 0.5), pbc=None, eps=1e-7): if pbc is None: pbc = self.pbc - self.positions = wrap_positions(self.positions, self.cell, pbc, center, eps) + self.positions = wrap_positions( + positions=self.positions, + cell=self.cell, + pbc=pbc, + center=center, + eps=eps + ) def write(self, filename, format=None, **kwargs): """ diff --git a/pyiron/base/project/generic.py b/pyiron/base/project/generic.py index e5bef4506..858c5e5ee 100644 --- a/pyiron/base/project/generic.py +++ b/pyiron/base/project/generic.py @@ -1032,7 +1032,7 @@ def remove(self, enable=False, enforce=False): enforce (bool): [True/False] delete jobs even though they are used in other projects - default=False enable (bool): [True/False] enable this command. """ - if not enable: + if enable is not True: raise ValueError( "To prevent users from accidentally deleting files - enable has to be set to True." ) diff --git a/pyiron/lammps/base.py b/pyiron/lammps/base.py index 79238763f..7b9296e2f 100644 --- a/pyiron/lammps/base.py +++ b/pyiron/lammps/base.py @@ -912,6 +912,12 @@ def collect_dump_file(self, file_name="dump.out", cwd=None): ) output["forces"] = np.matmul(forces, rotation_lammps2orig) + if np.all([flag in content[0].columns.values for flag in ["vx", "vy", "vz"]]): + velocities = np.array( + [np.stack((cc["vx"], cc["vy"], cc["vz"]), axis=-1) for cc in content] + ) + output["velocities"] = np.matmul(velocities, rotation_lammps2orig) + direct_unwrapped_positions = np.array( [np.stack((cc["xsu"], cc["ysu"], cc["zsu"]), axis=-1) for cc in content] ) diff --git a/pyiron/lammps/control.py b/pyiron/lammps/control.py index 6a564e52b..ae272adc4 100644 --- a/pyiron/lammps/control.py +++ b/pyiron/lammps/control.py @@ -181,8 +181,8 @@ def load_default(self, file_content=None): + "include potential.inp\n" + "fix___ensemble all nve\n" + "variable___dumptime equal 100\n" - + "dump___1 all custom ${dumptime} dump.out id type xsu ysu zsu fx fy fz\n" - + 'dump_modify___1 sort id format line "%d %d %20.15g %20.15g %20.15g %20.15g %20.15g %20.15g"\n' + + "dump___1 all custom ${dumptime} dump.out id type xsu ysu zsu fx fy fz vx vy vz\n" + + "dump_modify___1 sort id format line \"%d %d %20.15g %20.15g %20.15g %20.15g %20.15g %20.15g %20.15g %20.15g %20.15g\"\n" + "thermo_style custom step temp pe etotal pxx pxy pxz pyy pyz pzz vol\n" + "thermo_modify format float %20.15g\n" + "thermo 100\n" @@ -249,8 +249,7 @@ def calc_minimize( elif len(str_press) > 1: str_press += " couple none" self.set(fix___ensemble=r"all box/relax" + str_press) - else: - self.remove_keys(["fix___nve"]) + self.remove_keys(["fix___nve"]) self.set(min_style=style) self.set( minimize=str(e_tol) diff --git a/pyiron/lammps/interactive.py b/pyiron/lammps/interactive.py index 6035ceefc..13480befd 100644 --- a/pyiron/lammps/interactive.py +++ b/pyiron/lammps/interactive.py @@ -35,19 +35,8 @@ def __init__(self, project, job_name): self._check_opened = False self._interactive_run_command = None self._interactive_grand_canonical = True - self.interactive_cache = { - "cells": [], - "energy_pot": [], - "energy_tot": [], - "forces": [], - "positions": [], - "pressures": [], - "steps": [], - "indices": [], - "temperature": [], - "computation_time": [], - "volume": [], - } + if "stress" in self.interactive_output_functions.keys(): + del self.interactive_output_functions["stress"] @property def structure(self): diff --git a/pyiron/sphinx/base.py b/pyiron/sphinx/base.py index 8d6f5e93c..e9be822da 100644 --- a/pyiron/sphinx/base.py +++ b/pyiron/sphinx/base.py @@ -1800,7 +1800,7 @@ def to_hdf(self, hdf, force_update=False): if len(self._parse_dict["scf_energy_zero"]) == 0: self._parse_dict["scf_energy_zero"] = [ - 0.5 * (np.array(fr) + np.array(en)) + (0.5 * (np.array(fr) + np.array(en))).tolist() for fr, en in zip( self._parse_dict["scf_energy_free"], self._parse_dict["scf_energy_int"], diff --git a/pyiron/sphinx/interactive.py b/pyiron/sphinx/interactive.py index 261d74e4a..2bb285753 100644 --- a/pyiron/sphinx/interactive.py +++ b/pyiron/sphinx/interactive.py @@ -36,20 +36,6 @@ def __init__(self, project, job_name): self._interactive_write_input_files = True self._interactive_library_read = None self._interactive_fetch_completed = True - self.interactive_cache = { - "cells": [], - "energy_tot": [], - "energy_pot": [], - "forces": [], - "positions": [], - "indices": [], - "atom_spin_constraints": [], - "atom_spins": [], - "magnetic_forces": [], - "steps": [], - "computation_time": [], - "volume": [], - } @property def structure(self): diff --git a/pyiron/vasp/interactive.py b/pyiron/vasp/interactive.py index 9fb9fe3c3..e6b46f666 100644 --- a/pyiron/vasp/interactive.py +++ b/pyiron/vasp/interactive.py @@ -33,17 +33,6 @@ def __init__(self, project, job_name): super(VaspInteractive, self).__init__(project, job_name) self._interactive_write_input_files = True self._interactive_vasprun = None - self.interactive_cache = { - "cells": [], - "energy_pot": [], - "energy_tot": [], - "forces": [], - "positions": [], - "indices": [], - "steps": [], - "computation_time": [], - "volume": [], - } @property def structure(self): diff --git a/tests/sphinx/test_base.py b/tests/sphinx/test_base.py index dd18de970..7d561533d 100644 --- a/tests/sphinx/test_base.py +++ b/tests/sphinx/test_base.py @@ -6,10 +6,18 @@ import numpy as np import unittest import warnings +import scipy +import scipy.constants from pyiron.project import Project from pyiron.atomistics.structure.periodic_table import PeriodicTable from pyiron.atomistics.structure.atoms import Atoms +BOHR_TO_ANGSTROM = ( + scipy.constants.physical_constants["Bohr radius"][0] / scipy.constants.angstrom +) +HARTREE_TO_EV = scipy.constants.physical_constants["Hartree energy in eV"][0] +HARTREE_OVER_BOHR_TO_EV_OVER_ANGSTROM = HARTREE_TO_EV / BOHR_TO_ANGSTROM + class TestSphinx(unittest.TestCase): @classmethod @@ -152,7 +160,7 @@ def test_write_control(self): "scfDiag {\n", "\trhoMixing = 1.0;\n", "\tspinMixing = 1.0;\n", - "\tdEnergy = Ediff/27.21138602;\n", + "\tdEnergy = Ediff/"+str(scipy.constants.physical_constants["Hartree energy in eV"][0])+";\n", "\tmaxSteps = 400;\n", "\tblockCCG {}\n", "}\n", @@ -308,6 +316,7 @@ def test_calc_minimize(self): self.sphinx.calc_minimize(electronic_steps=100, ionic_steps=50) self.assertEqual(self.sphinx.input["Estep"], 100) self.assertEqual(self.sphinx.input["Istep"], 50) + self.assertEqual(self.sphinx._control_str['linQN']['maxSteps'], '50') def test_check_setup(self): self.assertFalse(self.sphinx.check_setup()) @@ -342,8 +351,10 @@ def test_exchange_correlation_functional(self): self.assertEqual(self.sphinx.exchange_correlation_functional, "PBE") def test_write_structure(self): + cell = (self.sphinx.structure.cell/BOHR_TO_ANGSTROM).tolist() + pos_2 = (self.sphinx.structure.positions[1]/BOHR_TO_ANGSTROM).tolist() file_content = [ - "cell = [[4.913287926190353, 0.0, 0.0], [0.0, 4.913287926190353, 0.0], [0.0, 0.0, 4.913287926190353]];\n", + "cell = "+str(cell)+";\n", "species {\n", '\telement = "Fe";\n', "\tatom {\n", @@ -352,7 +363,7 @@ def test_write_structure(self): "\t}\n", "\tatom {\n", '\t\tlabel = "spin_0.5";\n', - "\t\tcoords = [2.4566439630951766, 2.4566439630951766, 2.4566439630951766];\n", + "\t\tcoords = "+str(pos_2)+";\n", "\t}\n", "}\n", ] @@ -409,121 +420,38 @@ def test_collect_2_5(self): ) def test_collect_2_3(self): + file_location = os.path.join( + self.file_location, "../static/sphinx/sphinx_test_2_3_hdf5/sphinx_test_2_3/" + ) + residue_lst = np.loadtxt(file_location+"residue.dat")[:,1].reshape(1, -1) + residue_lst = (residue_lst*HARTREE_TO_EV).tolist() + energy_int_lst = np.loadtxt(file_location+"energy.dat")[:,2].reshape(1, -1) + energy_int_lst = (energy_int_lst*HARTREE_TO_EV).tolist() + with open(file_location+"sphinx.log") as ffile: + energy_free_lst = [[float(line.split('=')[-1])*HARTREE_TO_EV for line in ffile if line.startswith('F(')]] + energy_zero_lst = [(0.5*(np.array(ff)+np.array(uu))).tolist() for ff, uu in zip(energy_free_lst, energy_int_lst)] + eig_lst = [np.loadtxt(file_location+"eps.dat")[:, 1:].tolist()] self.sphinx_2_3.collect_output() - residue_lst = [ - [ - 12.42284127109662, - 1.5821842710240839, - 0.07949316620794639, - 0.0204451388291969, - 0.0029593198638330595, - ] - ] - energy_lst = [ - [ - -136602.11251515875, - -1013.569263492385, - -1013.1549335953392, - -1013.1571089876621, - -1013.1570690784093, - ] - ] - energy_total_lst = [ - -136617.29256368463, - -1030.8299933279204, - -1030.3610252581832, - -1030.3670225448573, - -1030.3670195193185, - ] - eig_lst = [ - [ - [ - 21.5221, - 21.5221, - 41.9680, - 41.9680, - 46.0988, - 46.3639, - 50.7003, - 50.7003, - 56.3383, - 56.3383, - 85.2211, - 86.7490, - ], - [ - 25.0401, - 30.8064, - 35.7829, - 36.4624, - 40.5134, - 43.8819, - 45.1040, - 49.5834, - 53.3100, - 56.2536, - 80.0862, - 80.8520, - ], - [ - 23.0987, - 23.1866, - 33.8188, - 34.3492, - 48.2745, - 49.0786, - 51.6559, - 53.4798, - 54.5464, - 59.0257, - 76.1849, - 82.8878, - ], - [ - 25.8051, - 26.2584, - 26.2584, - 37.4709, - 37.4709, - 47.7302, - 54.2662, - 54.2662, - 55.0636, - 55.0636, - 86.8241, - 100.1274, - ], - ] - ] - energy_structure_lst = [ - [ - -136632.47261221052, - -1048.090723163456, - -1047.5671169210273, - -1047.5769361020525, - -1047.5769699602279, - ] - ] self.assertEqual( residue_lst, self.sphinx_2_3._output_parser._parse_dict["scf_residue"] ) self.assertEqual( - energy_lst, self.sphinx_2_3._output_parser._parse_dict["scf_energy_int"] + energy_int_lst, self.sphinx_2_3._output_parser._parse_dict["scf_energy_int"] ) self.assertEqual( - energy_total_lst, - self.sphinx_2_3._output_parser._parse_dict["scf_energy_zero"][0].tolist(), + energy_zero_lst, + self.sphinx_2_3._output_parser._parse_dict["scf_energy_zero"], ) self.assertEqual( eig_lst, self.sphinx_2_3._output_parser._parse_dict["bands_eigen_values"].tolist(), ) self.assertEqual( - energy_structure_lst, + energy_free_lst, self.sphinx_2_3._output_parser._parse_dict["scf_energy_free"], ) self.assertEqual( - 3.252950781940035, self.sphinx_2_3._output_parser._parse_dict["volume"] + 21.952*BOHR_TO_ANGSTROM**3, self.sphinx_2_3._output_parser._parse_dict["volume"] ) def test_structure_parsing(self): diff --git a/tests/static/sphinx/sphinx_test_2_3_hdf5/sphinx_test_2_3/eps.dat b/tests/static/sphinx/sphinx_test_2_3_hdf5/sphinx_test_2_3/eps.dat index c922cd645..f13ac7d8f 100644 --- a/tests/static/sphinx/sphinx_test_2_3_hdf5/sphinx_test_2_3/eps.dat +++ b/tests/static/sphinx/sphinx_test_2_3_hdf5/sphinx_test_2_3/eps.dat @@ -1,6 +1,6 @@ # Eigenspectrum: all energies in eV # -ik- | i = 1 2 3 4 5 6 7 8 9 10 11 12 -1 27.051251 27.051251 47.679275 47.679275 48.192491 51.488907 56.053955 56.053955 60.878130 60.878130 89.538036 94.983550 -2 27.842676 35.155529 38.969014 41.091128 43.687889 47.794372 50.750120 54.753492 58.299910 61.583172 88.374769 90.430367 -3 23.039574 24.456253 38.191962 40.020337 52.799756 54.134834 56.760595 57.594416 59.744950 64.941011 81.737607 89.814148 -4 27.278062 27.278062 28.047874 36.913144 36.913144 51.321429 59.483435 59.483435 60.344624 60.344624 94.002533 98.814249 +1 21.5221 21.5221 41.9680 41.9680 46.0988 46.3639 50.7003 50.7003 56.3383 56.3383 85.2211 86.7490 +2 25.0401 30.8064 35.7829 36.4624 40.5134 43.8819 45.1040 49.5834 53.3100 56.2536 80.0862 80.8520 +3 23.0987 23.1866 33.8188 34.3492 48.2745 49.0786 51.6559 53.4798 54.5464 59.0257 76.1849 82.8878 +4 25.8051 26.2584 26.2584 37.4709 37.4709 47.7302 54.2662 54.2662 55.0636 55.0636 86.8241 100.1274