def dict2atoms(dct, attach_calculator=False): constraint_dicts = dct.get('constraints') if constraint_dicts: constraints = [dict2constraint(c) for c in constraint_dicts] else: constraints = None atoms = Atoms(dct['numbers'], dct['positions'], cell=dct['cell'], pbc=dct['pbc'], magmoms=dct.get('initial_magmoms'), charges=dct.get('initial_charges'), tags=dct.get('tags'), masses=dct.get('masses'), momenta=dct.get('momenta'), constraint=constraints) if attach_calculator: atoms.calc = get_calculator( dct['calculator'])(**dct['calculator_parameters']) else: results = {} for prop in all_properties: if prop in dct: results[prop] = dct[prop] if results: atoms.calc = SinglePointCalculator(atoms, **results) return atoms
def dict2atoms(dct, attach_calculator=False): constraint_dicts = dct.get("constraints") if constraint_dicts: constraints = [dict2constraint(c) for c in constraint_dicts] else: constraints = None atoms = Atoms( dct["numbers"], dct["positions"], cell=dct["cell"], pbc=dct["pbc"], magmoms=dct.get("initial_magmoms"), charges=dct.get("initial_charges"), tags=dct.get("tags"), masses=dct.get("masses"), momenta=dct.get("momenta"), constraint=constraints, ) if attach_calculator: atoms.calc = get_calculator(dct["calculator"])(**dct["calculator_parameters"]) else: results = {} for prop in all_properties: if prop in dct: results[prop] = dct[prop] if results: atoms.calc = SinglePointCalculator(atoms, **results) return atoms
def dict2atoms(dct, attach_calculator=False): constraint_dicts = dct.get('constraints') if constraint_dicts: constraints = [] for c in constraint_dicts: assert c.pop('__name__') == 'ase.constraints.FixAtoms' constraints.append(FixAtoms(**c)) else: constraints = None atoms = Atoms(dct['numbers'], dct['positions'], cell=dct['cell'], pbc=dct['pbc'], magmoms=dct.get('magmoms'), charges=dct.get('charges'), tags=dct.get('tags'), masses=dct.get('masses'), momenta=dct.get('momenta'), constraint=constraints) results = dct.get('results') if attach_calculator: atoms.calc = get_calculator(dct['calculator_name'])( **dct['calculator_parameters']) elif results: atoms.calc = SinglePointCalculator(atoms, **results) return atoms
def dict2atoms(dct, attach_calculator=False): constraint_dicts = dct.get('constraints') if constraint_dicts: constraints = [dict2constraint(c) for c in constraint_dicts] else: constraints = None atoms = Atoms(dct['numbers'], dct['positions'], cell=dct['cell'], pbc=dct['pbc'], magmoms=dct.get('initial_magmoms'), charges=dct.get('initial_charges'), tags=dct.get('tags'), masses=dct.get('masses'), momenta=dct.get('momenta'), constraint=constraints) if attach_calculator: atoms.calc = get_calculator(dct['calculator'])( **dct['calculator_parameters']) else: results = {} for prop in all_properties: if prop in dct: results[prop] = dct[prop] if results: atoms.calc = SinglePointCalculator(atoms, **results) return atoms
def dict2atoms(dct, attach_calculator=False): constraint_dicts = dct.get('constraints') if constraint_dicts: constraints = [] for c in constraint_dicts: assert c.pop('__name__') == 'ase.constraints.FixAtoms' constraints.append(FixAtoms(**c)) else: constraints = None atoms = Atoms(dct['numbers'], dct['positions'], cell=dct['cell'], pbc=dct['pbc'], magmoms=dct.get('magmoms'), charges=dct.get('charges'), tags=dct.get('tags'), masses=dct.get('masses'), momenta=dct.get('momenta'), constraint=constraints) results = dct.get('results') if attach_calculator: atoms.calc = get_calculator( dct['calculator_name'])(**dct['calculator_parameters']) elif results: atoms.calc = SinglePointCalculator(atoms, **results) return atoms
def ase_task(cid, calc, atcor, ian): """Base task for inproc calculators (e.g. Psi4). For Parameters and Returns see above :func:`ase_fio_task`. :func:`ase_task` uses ``grain.subproc.subprocify`` to "asyncify" the calculator, as we assume that an inproc calculator's ``calculate`` method is CPU intensive. ``subprocify`` requires an async context to maintain a subprocess pool. This could be simply achieved by:: from grain.subproc import subprocess_pool_scope async with subprocess_pool_scope(): # Safely call subprocified functions within .. note:: Task calling this experiences an overhead for the first few runs due to ``subprocify``'s subprocess startup cost, which will be amortized later as the subprocesses are reused. """ from ase.atoms import Atoms from ase.units import Hartree as hart2ev, Bohr as b2a from .util import timeblock mol = Atoms(numbers=ian, positions=atcor) mol.calc = calc with timeblock(cid): mol._calc.calculate(mol, ['energy', 'forces'], []) return ( mol.get_potential_energy() / hart2ev, mol.get_forces() * b2a / hart2ev, )
def test_no_data_file_wrap(factory): """ If 'create_atoms' hasn't been given the appropriate 'remap yes' option, atoms falling outside of a periodic cell are not actually created. The lammpsrun calculator will then look at the thermo output and determine a discrepancy the number of atoms reported compared to the length of the ASE Atoms object and raise a RuntimeError. This problem can only possibly arise when the 'no_data_file' option for the calculator is set to True. Furthermore, note that if atoms fall outside of the box along non-periodic dimensions, create_atoms is going to refuse to create them no matter what, so you simply can't use the 'no_data_file' option if you want to allow for that scenario. """ # Make a periodic box and put one atom outside of it pos = [[0.0, 0.0, 0.0], [-2.0, 0.0, 0.0]] atoms = Atoms(symbols=["Ar"] * 2, positions=pos, cell=[10.0, 10.0, 10.0], pbc=True) # Set parameters for calculator params = {} params["pair_style"] = "lj/cut 8.0" params["pair_coeff"] = ["1 1 0.0108102 3.345"] # Don't write a data file string. This will force # ase.calculators.lammps.inputwriter.write_lammps_in to write a bunch of # 'create_atoms' commands into the LAMMPS input file params["no_data_file"] = True with factory.calc(specorder=["Ar"], **params) as calc: atoms.calc = calc atoms.get_potential_energy()
def test_lammps_neighlist_buf(factory, testdir): # this is a perfectly symmetric FCC configurations, all forces should be zero # As of 6 May 2021, if lammpslib does wrap before rotating into lammps coord system # lammps messes up the neighbor list. This may or may not be fixed in lammps eventually, # but can also be worked around by having lammpslib do the wrap just before passing coords # to lammps os.chdir(testdir) atoms = Atoms('He', cell=[[2.045, 2.045, 0.0], [2.045, 0.0, 2.045], [0.0, 2.045, 2.045]], pbc=[True] * 3) atoms *= 6 calc = factory.calc(lmpcmds=[ 'pair_style lj/cut 0.5995011000293092E+01', 'pair_coeff * * 3.0 3.0' ], atom_types={ 'H': 1, 'He': 2 }, log_file=None, keep_alive=True, lammps_header=[ 'units metal', 'atom_style atomic', 'atom_modify map array sort 0 0' ]) atoms.calc = calc f = atoms.get_forces() fmag = np.linalg.norm(f, axis=1) print(f'> 1e-6 f[{np.where(fmag > 1e-6)}] = {f[np.where(fmag > 1e-6)]}') print(f'max f[{np.argmax(fmag)}] = {np.max(fmag)}') assert len(np.where(fmag > 1e-10)[0]) == 0
def read_dacapo(filename): from ase.io.pupynere import NetCDFFile nc = NetCDFFile(filename) vars = nc.variables cell = vars['UnitCell'][-1] try: magmoms = vars['InitialAtomicMagneticMoment'][:] except KeyError: magmoms = None try: tags = vars['AtomTags'][:] except KeyError: tags = None atoms = Atoms(scaled_positions=vars['DynamicAtomPositions'][-1], symbols=[(a + b).strip() for a, b in vars['DynamicAtomSpecies'][:]], cell=cell, magmoms=magmoms, tags=tags, pbc=True) try: energy = vars['TotalEnergy'][-1] force = vars['DynamicAtomForces'][-1] except KeyError: energy = None force = None # Fixme magmoms calc = SinglePointCalculator(atoms, energy=energy, forces=force) atoms.calc = calc return atoms
def test_gfn1_xtb_3d(): """Test ASE interface to GFN1-xTB""" thr = 5.0e-6 atoms = Atoms( symbols='C4O8', positions=np.array([ [0.9441259872, 0.9437851680, 0.9543505632], [3.7179966528, 0.9556570368, 3.7316862240], [3.7159517376, 3.7149292800, 0.9692330016], [0.9529872864, 3.7220864832, 3.7296981120], [1.6213905408, 1.6190616096, 1.6313879040], [0.2656685664, 0.2694175776, 0.2776540416], [4.3914553920, 1.6346256864, 3.0545920000], [3.0440834880, 0.2764611744, 4.4080419264], [4.3910577696, 3.0416409504, 0.2881058304], [3.0399936576, 4.3879335936, 1.6497353376], [0.2741322432, 4.4003734944, 3.0573754368], [1.6312174944, 3.0434586528, 4.4023048032], ]), cell=np.array([5.68032, 5.68032, 5.68032]), pbc=np.array([True, True, True]), ) forces = np.array([ [0.05008078, 0.06731033, 0.06324782], [-0.03885473, 0.07550136, -0.06667888], [-0.06455676, -0.04199831, 0.06908718], [0.04672903, -0.06303119, -0.06002863], [-1.9460667, -1.94514641, -1.94923488], [1.92953942, 1.91109506, 1.92038457], [-1.91269913, -1.95500822, 1.94675148], [1.94009239, 1.91238163, -1.93489981], [-1.90757165, 1.94211445, 1.94655816], [1.94283273, -1.90965163, -1.95863335], [1.91207771, -1.94256232, 1.9337591], [-1.95160309, 1.94899525, -1.91031277], ]) charges = np.array([ 0.74256902, 0.74308482, 0.74305612, 0.74300613, -0.37010244, -0.37234708, -0.37134504, -0.37177066, -0.37176288, -0.37133667, -0.37178059, -0.37127074, ]) atoms.calc = XTB(method="GFN1-xTB") assert atoms.pbc.all() assert approx(atoms.get_potential_energy(), abs=thr) == -1256.768167202048 assert approx(atoms.get_forces(), abs=thr) == forces assert approx(atoms.get_charges(), abs=thr) == charges
async def dumb_fio_task(cid, calc, atcor, ian, cell=None, pbc=None): import numpy as np from ase.atoms import Atoms mol = Atoms(numbers=ian, positions=atcor, cell=cell, pbc=pbc) mol.calc = calc mol._calc.write_input(mol, ['energy', 'forces'], []) return ( 0.0, np.zeros_like(atcor), )
def __getitem__(self, i=-1): if isinstance(i, slice): return [self[j] for j in range(*i.indices(len(self)))] N = len(self.offsets) if 0 <= i < N: self.fd.seek(self.offsets[i]) try: d = pickle.load(self.fd, encoding='bytes') d = { k.decode() if isinstance(k, bytes) else k: v for k, v in d.items() } except EOFError: raise IndexError if i == N - 1: self.offsets.append(self.fd.tell()) charges = d.get('charges') magmoms = d.get('magmoms') try: constraints = [c.copy() for c in self.constraints] except Exception: constraints = [] warnings.warn('Constraints did not unpickle correctly.') atoms = Atoms(positions=d['positions'], numbers=self.numbers, cell=d['cell'], momenta=d['momenta'], magmoms=magmoms, charges=charges, tags=self.tags, masses=self.masses, pbc=self.pbc, info=unstringnify_info(d.get('info', {})), constraint=constraints) if 'energy' in d: calc = SinglePointCalculator(atoms, energy=d.get('energy', None), forces=d.get('forces', None), stress=d.get('stress', None), magmoms=magmoms) atoms.calc = calc return atoms if i >= N: for j in range(N - 1, i + 1): atoms = self[j] return atoms i = len(self) + i if i < 0: raise IndexError('Trajectory index out of range.') return self[i]
def as_ase(self): atoms = Atoms(positions=self.positions, cell=self.cell, pbc=self.pbc, numbers=self.numbers) atoms.calc = self.calc # DONE: e, f if atoms.calc is not None: atoms.calc.atoms = atoms vel = self.get_velocities() if vel is not None: atoms.set_velocities(vel) return atoms
def test_gfn1_xtb_3d(): """Test ASE interface to GFN1-xTB""" thr = 5.0e-6 atoms = Atoms( symbols="C4O8", positions=np.array([ [0.9441259872, 0.9437851680, 0.9543505632], [3.7179966528, 0.9556570368, 3.7316862240], [3.7159517376, 3.7149292800, 0.9692330016], [0.9529872864, 3.7220864832, 3.7296981120], [1.6213905408, 1.6190616096, 1.6313879040], [0.2656685664, 0.2694175776, 0.2776540416], [4.3914553920, 1.6346256864, 3.0545920000], [3.0440834880, 0.2764611744, 4.4080419264], [4.3910577696, 3.0416409504, 0.2881058304], [3.0399936576, 4.3879335936, 1.6497353376], [0.2741322432, 4.4003734944, 3.0573754368], [1.6312174944, 3.0434586528, 4.4023048032], ]), cell=np.array([5.68032, 5.68032, 5.68032]), pbc=np.array([True, True, True]), ) forces = np.array([ [-0.08831700, -0.07001294, -0.07468651], [-0.03556765, -0.02242341, +0.03047788], [+0.03228896, -0.03948204, -0.02892694], [-0.02569098, +0.03373080, -0.03161988], [-1.90306812, -1.90236730, -1.90612450], [+1.98861177, +1.96958105, +1.97849378], [-1.88898997, -1.93509024, +1.91692369], [+1.92988257, +1.95061533, -1.94116843], [-1.93844982, +1.93069254, +1.96026641], [+1.91146115, -1.88620597, -1.93901862], [+1.94936349, -1.94760369, +1.92150003], [-1.93152440, +1.91856587, -1.88611692], ]) stress = np.array([ +4.49045792e-02, +4.49168887e-02, +4.49566951e-02, +3.38245641e-05, +1.52117499e-05, +1.13328271e-04, ]) atoms.calc = TBLite(method="GFN1-xTB") assert atoms.pbc.all() assert approx(atoms.get_potential_energy(), abs=thr) == -1257.0801067985549 assert approx(atoms.get_forces(), abs=thr) == forces assert approx(atoms.get_stress(), abs=thr) == stress
def test_gfn1_xtb_0d(): """Test ASE interface to GFN1-xTB""" thr = 1.0e-5 atoms = Atoms( symbols="CHOCH2CH4CH2OH", positions=np.array([ [+1.578385, +0.147690, +0.343809], [+1.394750, +0.012968, +1.413545], [+1.359929, -1.086203, -0.359782], [+0.653845, +1.215099, -0.221322], [+1.057827, +2.180283, +0.093924], [+0.729693, +1.184864, -1.311438], [-0.817334, +1.152127, +0.208156], [-1.303525, +2.065738, -0.145828], [-0.883765, +1.159762, +1.299260], [+1.984120, -1.734446, -0.021385], [+2.616286, +0.458948, +0.206544], [-1.627725, -0.034052, -0.311301], [-2.684229, +0.151015, -0.118566], [-1.501868, -0.118146, -1.397506], [-1.324262, -1.260154, +0.333377], [-0.417651, -1.475314, +0.076637], ]), ) forces = np.array([ [-0.37070590, -0.51067739, -0.27981764], [-0.04339461, -0.09290876, +0.22940156], [+0.11141234, +0.46678720, +0.24552625], [+0.04255709, +0.19019316, -0.23531997], [-0.01897377, +0.10810803, +0.05314982], [-0.07150720, -0.05182148, -0.08413638], [+0.06631826, +0.10587709, +0.29833479], [-0.01062355, +0.02301460, -0.04964730], [+0.06610108, -0.02724994, +0.09234280], [+0.06519070, -0.19311773, -0.01152205], [+0.23879786, +0.09871398, -0.04009526], [-0.04381577, -0.49997745, +0.08672818], [-0.23259608, +0.13735636, +0.06783414], [+0.08297636, -0.09566973, -0.20602954], [-0.23686052, +0.57454371, -0.17194215], [+0.35512370, -0.23317164, +0.00519275], ]) atoms.calc = TBLite(method="GFN1-xTB") assert approx(atoms.get_potential_energy(), abs=thr) == -632.7363734598027 assert approx(atoms.get_forces(), abs=thr) == forces
def test_orca(): from ase.optimize import BFGS from ase.atoms import Atoms from ase.calculators.orca import ORCA atoms = Atoms('OHH', positions=[(0, 0, 0), (1, 0, 0), (0, 1, 0)]) atoms.calc = ORCA(label='water', orcasimpleinput='BLYP def2-SVP') opt = BFGS(atoms) opt.run(fmax=0.05) final_energy = atoms.get_potential_energy() print(final_energy) assert abs(final_energy + 2077.24420) < 1.0
def test_gfn2xtb_velocityverlet(): """Perform molecular dynamics with GFN2-xTB and Velocity Verlet Integrator""" thr = 1.0e-5 atoms = Atoms( symbols="NHCHC2H3OC2H3ONHCH3", positions=np.array([ [1.40704587284727, -1.26605342016611, -1.93713466561923], [1.85007200612454, -0.46824072777417, -1.50918242392545], [-0.03362432532150, -1.39269245193812, -1.74003582081606], [-0.56857009928108, -1.01764444489068, -2.61263467107342], [-0.44096297340282, -2.84337808903410, -1.48899734014499], [-0.47991761226058, -0.55230954385212, -0.55520222968656], [-1.51566045903090, -2.89187354810876, -1.32273881320610], [-0.18116520746778, -3.45187805987944, -2.34920431470368], [0.06989722340461, -3.23298998903001, -0.60872832703814], [-1.56668253918793, 0.00552120970194, -0.52884675001441], [1.99245341064342, -1.73097165236442, -3.08869239114486], [3.42884244212567, -1.30660069291348, -3.28712665743189], [3.87721962540768, -0.88843123009431, -2.38921453037869], [3.46548545761151, -0.56495308290988, -4.08311788302584], [4.00253374168514, -2.16970938132208, -3.61210068365649], [1.40187968630565, -2.43826111827818, -3.89034127398078], [0.40869198386066, -0.49101709352090, 0.47992424955574], [1.15591901335007, -1.16524842262351, 0.48740266650199], [0.00723492494701, 0.11692276177442, 1.73426297572793], [0.88822128447468, 0.28499001838229, 2.34645658013686], [-0.47231557768357, 1.06737634000561, 1.52286682546986], [-0.70199987915174, -0.50485938116399, 2.28058247845421], ]), ) atoms.calc = XTB(method="GFN2-xTB", cache_api=False) dyn = VelocityVerlet(atoms, timestep=1.0 * fs) dyn.run(20) assert approx(atoms.get_potential_energy(), thr) == -896.9772346260584 assert approx(atoms.get_kinetic_energy(), thr) == 0.022411127028842362 atoms.calc.set(cache_api=True) dyn.run(20) assert approx(atoms.get_potential_energy(), thr) == -896.9913862530841 assert approx(atoms.get_kinetic_energy(), thr) == 0.036580471363852810
def read_wann2kc_out(fileobj): """Reads Wannier to KC output files. Parameters ---------- fileobj : file|str A file like object or filename Yields ------ structure : Atoms The next structure from the index slice. The Atoms has a SinglePointCalculator attached with any results parsed from the file. """ if isinstance(fileobj, basestring): fileobj = open(fileobj, 'rU') # work with a copy in memory for faster random access flines = fileobj.readlines() # For the moment, provide an empty atoms object structure = Atoms() # Extract calculation results walltime = None job_done = False for line in flines: if 'JOB DONE' in line: job_done = True if 'KC_WANN :' in line: time_str = line.split()[-2] walltime = time_to_float(time_str) # Return an empty calculator object with ths solitary result 'job done' calc = SinglePointDFTCalculator(structure) calc.results['job_done'] = job_done calc.results['walltime'] = walltime structure.calc = calc yield structure
def test_molecule(): from ase.optimize import BFGS from ase.atoms import Atoms from ase.calculators.crystal import CRYSTAL with open('basis', 'w') as fd: fd.write("""6 4 0 0 6 2.0 1.0 3048.0 0.001826 456.4 0.01406 103.7 0.06876 29.23 0.2304 9.349 0.4685 3.189 0.3628 0 1 2 4.0 1.0 3.665 -0.3959 0.2365 0.7705 1.216 0.8606 0 1 1 0.0 1.0 0.26 1.0 1.0 0 3 1 0.0 1.0 0.8 1.0 """) geom = Atoms('OHH', positions=[(0, 0, 0), (1, 0, 0), (0, 1, 0)]) geom.calc = CRYSTAL( label='water', guess=True, basis='sto-3g', xc='PBE', otherkeys=['scfdir', 'anderson', ['maxcycles', '500'], ['toldee', '6'], ['tolinteg', '7 7 7 7 14'], ['fmixing', '90']]) opt = BFGS(geom) opt.run(fmax=0.05) final_energy = geom.get_potential_energy() assert abs(final_energy + 2047.34531091) < 1.0
async def ase_fio_task(cid, calc, atcor, ian, cell=None, pbc=None): """Base task for calculators implementing the `FileIOCalculator`_ interface (e.g. Gaussian, Orca, QE). .. _FileIOCalculator: https://gitlab.com/ase/ase/-/blob/master/ase/calculators/calculator.py Class ``FileIOCalculator`` is patched to enable async calculation through async subprocess. See ``monkey_patch.py`` for details. Args: cid (str): Calculation ID, for time record only calc: The calculator instance atcor (ndarray[(N,3), float]): Atom coordinate ian (ndarray[(N,), int]): Atomic numbers pbc (bool or (bool, bool, bool)): Periodic boundary conditions along each axis. Arg for ``ase.atoms.Atoms`` cell (ndarray[(3,3), float] or see ASE doc): Unit cell size. Arg for ``ase.atoms.Atoms`` Returns: Energy (in hartree) and forces (in hartree/angstrom) .. note:: Any task calling this should make sure that the calculator itself's ``calculate`` method get handled, as this only takes care of ``FileIOCalculator.calculate``. """ from ase.atoms import Atoms from ase.units import Hartree as hart2ev, Bohr as b2a from .util import timeblock mol = Atoms(numbers=ian, positions=atcor, cell=cell, pbc=pbc) mol.calc = calc with timeblock(cid): await mol._calc.acalculate(mol, ['energy', 'forces'], []) return ( mol.get_potential_energy() / hart2ev, mol.get_forces() * b2a / hart2ev, )
def get_fc2(supercell, primitive, displacements, forces, atom_list=None, options=None, log_level=0): if options is None: option_dict = {} else: option_dict = decode_options(options) structures = [] for d, f in zip(displacements, forces): structure = Atoms(cell=supercell.cell, scaled_positions=supercell.scaled_positions, numbers=supercell.numbers, pbc=True) structure.new_array('displacements', d) structure.new_array('forces', f) structure.calc = None structures.append(structure) cutoffs = [ option_dict['cutoff'], ] cs = ClusterSpace(structures[0], cutoffs) print(cs) cs.print_orbits() sc = StructureContainer(cs) for structure in structures: sc.add_structure(structure) print(sc) opt = Optimizer(sc.get_fit_data()) opt.train() print(opt) fcp = ForceConstantPotential(cs, opt.parameters) print(fcp)
def test_gfn1xtb_bfgs(): """Perform geometry optimization with GFN1-xTB and BFGS""" thr = 1.0e-5 atoms = Atoms( symbols="NHCHC2H3OC2H3ONHCH3", positions=np.array([ [1.40704587284727, -1.26605342016611, -1.93713466561923], [1.85007200612454, -0.46824072777417, -1.50918242392545], [-0.03362432532150, -1.39269245193812, -1.74003582081606], [-0.56857009928108, -1.01764444489068, -2.61263467107342], [-0.44096297340282, -2.84337808903410, -1.48899734014499], [-0.47991761226058, -0.55230954385212, -0.55520222968656], [-1.51566045903090, -2.89187354810876, -1.32273881320610], [-0.18116520746778, -3.45187805987944, -2.34920431470368], [0.06989722340461, -3.23298998903001, -0.60872832703814], [-1.56668253918793, 0.00552120970194, -0.52884675001441], [1.99245341064342, -1.73097165236442, -3.08869239114486], [3.42884244212567, -1.30660069291348, -3.28712665743189], [3.87721962540768, -0.88843123009431, -2.38921453037869], [3.46548545761151, -0.56495308290988, -4.08311788302584], [4.00253374168514, -2.16970938132208, -3.61210068365649], [1.40187968630565, -2.43826111827818, -3.89034127398078], [0.40869198386066, -0.49101709352090, 0.47992424955574], [1.15591901335007, -1.16524842262351, 0.48740266650199], [0.00723492494701, 0.11692276177442, 1.73426297572793], [0.88822128447468, 0.28499001838229, 2.34645658013686], [-0.47231557768357, 1.06737634000561, 1.52286682546986], [-0.70199987915174, -0.50485938116399, 2.28058247845421], ]), ) atoms.calc = XTB(method="GFN1-xTB", accuracy=2.0, cache_api=False) opt = BFGS(atoms) opt.run(fmax=0.1) assert approx(atoms.get_potential_energy(), thr) == -951.9006674709672 assert approx(np.linalg.norm(atoms.get_forces(), ord=2), thr) == 0.2052117803208497
def reserve(self, **key_value_pairs): """Write empty row if not already present. Usage:: id = conn.reserve(key1=value1, key2=value2, ...) Write an empty row with the given key-value pairs and return the integer id. If such a row already exists, don't write anything and return None. """ for dct in self._select([], [(key, '=', value) for key, value in key_value_pairs.items()]): return None atoms = Atoms() calc_name = key_value_pairs.pop('calculator', None) if calc_name: # Allow use of calculator key assert calc_name.lower() == calc_name # Fake calculator class: class Fake: name = calc_name def todict(self): return {} def check_state(self, atoms): return ['positions'] atoms.calc = Fake() id = self._write(atoms, key_value_pairs, {}, None) return id
def read_dacapo_text(fileobj): if isinstance(fileobj, str): fileobj = open(fileobj) lines = fileobj.readlines() i = lines.index(' Structure: A1 A2 A3\n') cell = np.array([[float(w) for w in line.split()[2:5]] for line in lines[i + 1:i + 4]]).transpose() i = lines.index(' Structure: >> Ionic positions/velocities ' + 'in cartesian coordinates <<\n') atoms = [] for line in lines[i + 4:]: words = line.split() if len(words) != 9: break Z, x, y, z = words[2:6] atoms.append(Atom(int(Z), [float(x), float(y), float(z)])) atoms = Atoms(atoms, cell=cell.tolist()) try: i = lines.index( ' DFT: CPU time Total energy\n') except ValueError: pass else: column = lines[i + 3].split().index('selfcons') - 1 try: i2 = lines.index(' ANALYSIS PART OF CODE\n', i) except ValueError: pass else: while i2 > i: if lines[i2].startswith(' DFT:'): break i2 -= 1 energy = float(lines[i2].split()[column]) atoms.calc = SinglePointCalculator(atoms, energy=energy) return atoms
def read_x2y_out(fd, calc_class): """ Reads pw2wannier/wann2kcp output files Parameters ---------- fd : file|str A file like object or filename Yields ------ structure : atoms An Atoms object with an attached SinglePointCalculator containing any parsed results """ if isinstance(fd, basestring): fd = open(fd, 'rU') flines = fd.readlines() structure = Atoms() job_done = False walltime = None for line in flines: if 'JOB DONE' in line: job_done = True if line.startswith(calc_class.__name__.upper()): time_str = line.split()[-2] walltime = time_to_float(time_str) calc = calc_class(atoms=structure) calc.results['job done'] = job_done calc.results['walltime'] = walltime structure.calc = calc yield structure
def read_projwfc_out(fd): """ Reads projwfc output files Parameters ---------- fd : file|str A file like object or filename Yields ------ structure : atoms An Atoms object with an attached SinglePointCalculator containing any parsed results """ if isinstance(fd, str): fd = open(fd, 'r') flines = fd.readlines() structure = Atoms() job_done = False walltime = None for line in flines: if 'JOB DONE' in line: job_done = True if 'PROJWFC :' in line: time_str = line.split()[-2] walltime = time_to_float(time_str) calc = Projwfc(atoms=structure) calc.results['job done'] = job_done calc.results['walltime'] = walltime structure.calc = calc yield structure
def test_gfn2_xtb_3d(): """Test ASE interface to GFN2-xTB, should fail""" thr = 5.0e-6 atoms = Atoms( symbols='C4O8', positions=np.array([ [0.9441259872, 0.9437851680, 0.9543505632], [3.7179966528, 0.9556570368, 3.7316862240], [3.7159517376, 3.7149292800, 0.9692330016], [0.9529872864, 3.7220864832, 3.7296981120], [1.6213905408, 1.6190616096, 1.6313879040], [0.2656685664, 0.2694175776, 0.2776540416], [4.3914553920, 1.6346256864, 3.0545920000], [3.0440834880, 0.2764611744, 4.4080419264], [4.3910577696, 3.0416409504, 0.2881058304], [3.0399936576, 4.3879335936, 1.6497353376], [0.2741322432, 4.4003734944, 3.0573754368], [1.6312174944, 3.0434586528, 4.4023048032], ]), cell=np.array([5.68032, 5.68032, 5.68032]), pbc=np.array([True, True, True]), ) calc = XTB(method="GFN2-xTB") atoms.calc = calc with raises(CalculationFailed): atoms.get_potential_energy() # make structure molecular atoms.set_pbc(False) assert approx(atoms.get_potential_energy(), abs=thr) == -1121.9196707084955 with raises(InputError): atoms.positions = np.zeros((len(atoms), 3)) calc.calculate(atoms=atoms, system_changes=["positions"])
def get_atoms(cmr_data): if type(cmr_data)==str: raise RuntimeError('cmr db-file: the specified cmr group file does not contain any images, only references.\n'+ 'This error could be caused by an older version of CMR - or a group file containing only references to other db-files.') positions = cmr_data.get('ase_positions') numbers = cmr_data.get('ase_atomic_numbers') symbols = cmr_data.get('ase_chemical_symbols') cell = cmr_data.get('ase_cell') pbc = cmr_data.get('ase_pbc') tags = np.array(cmr_data.get('ase_tags')) magmoms = np.array(cmr_data.get('ase_magnetic_moments')) energy = cmr_data.get('ase_potential_energy') forces = cmr_data.get('ase_forces') if numbers is None and not symbols is None: numbers = [atomic_numbers[x] for x in symbols] if numbers is None or positions is None: raise RuntimeError('cmr db-file: there is no or not enough ase data available in the specified db-file.') atoms = Atoms(positions=positions, numbers=numbers, cell=cell, pbc=pbc) if tags.any(): atoms.set_tags(list(tags)) if magmoms.any(): atoms.set_initial_magnetic_moments(magmoms) else: magmoms = None atoms.calc = SinglePointCalculator(energy, forces, None, magmoms, atoms) return atoms
def read(filename, index=None, format=None): """Read Atoms object(s) from file. filename: str Name of the file to read from. index: int or slice If the file contains several configurations, the last configuration will be returned by default. Use index=n to get configuration number n (counting from zero). format: str Used to specify the file-format. If not given, the file-format will be guessed by the *filetype* function. Known formats: ========================= ============= format short name ========================= ============= GPAW restart-file gpw Dacapo netCDF output file dacapo Old ASE netCDF trajectory nc Virtual Nano Lab file vnl ASE pickle trajectory traj ASE bundle trajectory bundle GPAW text output gpaw-text CUBE file cube XCrySDen Structure File xsf Dacapo text output dacapo-text XYZ-file xyz VASP POSCAR/CONTCAR file vasp VASP OUTCAR file vasp_out SIESTA STRUCT file struct_out ABINIT input file abinit V_Sim ascii file v_sim Protein Data Bank pdb CIF-file cif FHI-aims geometry file aims FHI-aims output file aims_out VTK XML Image Data vti VTK XML Structured Grid vts VTK XML Unstructured Grid vtu TURBOMOLE coord file tmol TURBOMOLE gradient file tmol-gradient exciting input exi AtomEye configuration cfg WIEN2k structure file struct DftbPlus input file dftb CASTEP geom file cell CASTEP output file castep CASTEP trajectory file geom ETSF format etsf.nc DFTBPlus GEN format gen CMR db/cmr-file db CMR db/cmr-file cmr LAMMPS dump file lammps EON reactant.con file eon Gromacs coordinates gro Gaussian com (input) file gaussian Gaussian output file gaussian_out Quantum espresso in file esp_in Quantum espresso out file esp_out Extended XYZ file extxyz NWChem input file nw ========================= ============= """ if isinstance(filename, str) and ('.json@' in filename or '.db@' in filename or filename.startswith('pg://') and '@' in filename): filename, index = filename.rsplit('@', 1) if index.isdigit(): index = int(index) else: if isinstance(filename, str): p = filename.rfind('@') if p != -1: try: index = string2index(filename[p + 1:]) except ValueError: pass else: filename = filename[:p] if isinstance(index, str): index = string2index(index) if format is None: format = filetype(filename) if format.startswith('gpw'): import gpaw r = gpaw.io.open(filename, 'r') positions = r.get('CartesianPositions') * Bohr numbers = r.get('AtomicNumbers') cell = r.get('UnitCell') * Bohr pbc = r.get('BoundaryConditions') tags = r.get('Tags') magmoms = r.get('MagneticMoments') energy = r.get('PotentialEnergy') * Hartree if r.has_array('CartesianForces'): forces = r.get('CartesianForces') * Hartree / Bohr else: forces = None atoms = Atoms(positions=positions, numbers=numbers, cell=cell, pbc=pbc) if tags.any(): atoms.set_tags(tags) if magmoms.any(): atoms.set_initial_magnetic_moments(magmoms) else: magmoms = None atoms.calc = SinglePointDFTCalculator(atoms, energy=energy, forces=forces, magmoms=magmoms) kpts = [] if r.has_array('IBZKPoints'): for w, kpt, eps_n, f_n in zip(r.get('IBZKPointWeights'), r.get('IBZKPoints'), r.get('Eigenvalues'), r.get('OccupationNumbers')): kpts.append( SinglePointKPoint(w, kpt[0], kpt[1], eps_n[0], f_n[0])) atoms.calc.kpts = kpts return atoms if format in ['json', 'db', 'postgresql']: from ase.db.core import connect, dict2atoms if index == slice(None, None): index = None images = [ dict2atoms(d) for d in connect(filename, format).select(index) ] if len(images) == 1: return images[0] else: return images if index is None: index = -1 if format == 'castep': from ase.io.castep import read_castep return read_castep(filename, index) if format == 'castep_cell': import ase.io.castep return ase.io.castep.read_cell(filename, index) if format == 'castep_geom': import ase.io.castep return ase.io.castep.read_geom(filename, index) if format == 'exi': from ase.io.exciting import read_exciting return read_exciting(filename, index) if format in ['xyz', 'extxyz']: from ase.io.extxyz import read_xyz return read_xyz(filename, index) if format == 'traj': from ase.io.trajectory import read_trajectory return read_trajectory(filename, index) if format == 'bundle': from ase.io.bundletrajectory import read_bundletrajectory return read_bundletrajectory(filename, index) if format == 'cube': from ase.io.cube import read_cube return read_cube(filename, index) if format == 'nc': from ase.io.netcdf import read_netcdf return read_netcdf(filename, index) if format == 'gpaw-text': from ase.io.gpawtext import read_gpaw_text return read_gpaw_text(filename, index) if format == 'dacapo-text': from ase.io.dacapo import read_dacapo_text return read_dacapo_text(filename) if format == 'dacapo': from ase.io.dacapo import read_dacapo return read_dacapo(filename) if format == 'xsf': from ase.io.xsf import read_xsf return read_xsf(filename, index) if format == 'vasp': from ase.io.vasp import read_vasp return read_vasp(filename) if format == 'vasp_out': from ase.io.vasp import read_vasp_out return read_vasp_out(filename, index) if format == 'abinit': from ase.io.abinit import read_abinit return read_abinit(filename) if format == 'v_sim': from ase.io.v_sim import read_v_sim return read_v_sim(filename) if format == 'mol': from ase.io.mol import read_mol return read_mol(filename) if format == 'pdb': from ase.io.pdb import read_pdb return read_pdb(filename, index) if format == 'cif': from ase.io.cif import read_cif return read_cif(filename, index) if format == 'struct': from ase.io.wien2k import read_struct return read_struct(filename) if format == 'struct_out': from ase.io.siesta import read_struct return read_struct(filename) if format == 'vti': from ase.io.vtkxml import read_vti return read_vti(filename) if format == 'vts': from ase.io.vtkxml import read_vts return read_vts(filename) if format == 'vtu': from ase.io.vtkxml import read_vtu return read_vtu(filename) if format == 'aims': from ase.io.aims import read_aims return read_aims(filename) if format == 'aims_out': from ase.io.aims import read_aims_output return read_aims_output(filename, index) if format == 'iwm': from ase.io.iwm import read_iwm return read_iwm(filename) if format == 'Cmdft': from ase.io.cmdft import read_I_info return read_I_info(filename) if format == 'tmol': from ase.io.turbomole import read_turbomole return read_turbomole(filename) if format == 'tmol-gradient': from ase.io.turbomole import read_turbomole_gradient return read_turbomole_gradient(filename) if format == 'cfg': from ase.io.cfg import read_cfg return read_cfg(filename) if format == 'dftb': from ase.io.dftb import read_dftb return read_dftb(filename) if format == 'sdf': from ase.io.sdf import read_sdf return read_sdf(filename) if format == 'etsf': from ase.io.etsf import ETSFReader return ETSFReader(filename).read_atoms() if format == 'gen': from ase.io.gen import read_gen return read_gen(filename) if format == 'cmr': from ase.io.cmr_io import read_db return read_db(filename, index) if format == 'lammps': from ase.io.lammpsrun import read_lammps_dump return read_lammps_dump(filename, index) if format == 'eon': from ase.io.eon import read_reactant_con return read_reactant_con(filename) if format == 'gromacs': from ase.io.gromacs import read_gromacs return read_gromacs(filename) if format == 'gaussian': from ase.io.gaussian import read_gaussian return read_gaussian(filename) if format == 'gaussian_out': from ase.io.gaussian import read_gaussian_out return read_gaussian_out(filename, index) if format == 'esp_in': from ase.io.espresso import read_espresso_in return read_espresso_in(filename) if format == 'esp_out': from ase.io.espresso import read_espresso_out return read_espresso_out(filename, index) if format == 'nw': from ase.io.nwchem import read_nwchem_input return read_nwchem_input(filename) raise RuntimeError('File format descriptor ' + format + ' not recognized!')
def _read_xyz_frame(lines, natoms, properties_parser=key_val_str_to_dict, nvec=0): # comment line line = next(lines).strip() if nvec > 0: info = {'comment': line} else: info = properties_parser(line) if line else {} pbc = None if 'pbc' in info: pbc = info['pbc'] del info['pbc'] elif 'Lattice' in info: # default pbc for extxyz file containing Lattice # is True in all directions pbc = [True, True, True] elif nvec > 0: # cell information given as pseudo-Atoms pbc = [False, False, False] cell = None if 'Lattice' in info: # NB: ASE cell is transpose of extended XYZ lattice cell = info['Lattice'].T del info['Lattice'] elif nvec > 0: # cell information given as pseudo-Atoms cell = np.zeros((3, 3)) if 'Properties' not in info: # Default set of properties is atomic symbols and positions only info['Properties'] = 'species:S:1:pos:R:3' properties, names, dtype, convs = parse_properties(info['Properties']) del info['Properties'] data = [] for ln in range(natoms): try: line = next(lines) except StopIteration: raise XYZError('ase.io.extxyz: Frame has {} atoms, expected {}' .format(len(data), natoms)) vals = line.split() row = tuple([conv(val) for conv, val in zip(convs, vals)]) data.append(row) try: data = np.array(data, dtype) except TypeError: raise XYZError('Badly formatted data ' 'or end of file reached before end of frame') # Read VEC entries if present if nvec > 0: for ln in range(nvec): try: line = next(lines) except StopIteration: raise XYZError('ase.io.adfxyz: Frame has {} cell vectors, ' 'expected {}'.format(len(cell), nvec)) entry = line.split() if not entry[0].startswith('VEC'): raise XYZError('Expected cell vector, got {}'.format(entry[0])) try: n = int(entry[0][3:]) except ValueError as e: raise XYZError('Expected VEC{}, got VEC{}' .format(ln + 1, entry[0][3:])) from e if n != ln + 1: raise XYZError('Expected VEC{}, got VEC{}' .format(ln + 1, n)) cell[ln] = np.array([float(x) for x in entry[1:]]) pbc[ln] = True if nvec != pbc.count(True): raise XYZError('Problem with number of cell vectors') pbc = tuple(pbc) arrays = {} for name in names: ase_name, cols = properties[name] if cols == 1: value = data[name] else: value = np.vstack([data[name + str(c)] for c in range(cols)]).T arrays[ase_name] = value symbols = None if 'symbols' in arrays: symbols = [s.capitalize() for s in arrays['symbols']] del arrays['symbols'] numbers = None duplicate_numbers = None if 'numbers' in arrays: if symbols is None: numbers = arrays['numbers'] else: duplicate_numbers = arrays['numbers'] del arrays['numbers'] charges = None if 'charges' in arrays: charges = arrays['charges'] del arrays['charges'] positions = None if 'positions' in arrays: positions = arrays['positions'] del arrays['positions'] atoms = Atoms(symbols=symbols, positions=positions, numbers=numbers, charges=charges, cell=cell, pbc=pbc, info=info) # Read and set constraints if 'move_mask' in arrays: if properties['move_mask'][1] == 3: cons = [] for a in range(natoms): cons.append(FixCartesian(a, mask=~arrays['move_mask'][a, :])) atoms.set_constraint(cons) elif properties['move_mask'][1] == 1: atoms.set_constraint(FixAtoms(mask=~arrays['move_mask'])) else: raise XYZError('Not implemented constraint') del arrays['move_mask'] for name, array in arrays.items(): atoms.new_array(name, array) if duplicate_numbers is not None: atoms.set_atomic_numbers(duplicate_numbers) # Load results of previous calculations into SinglePointCalculator results = {} for key in list(atoms.info.keys()): if key in per_config_properties: results[key] = atoms.info[key] # special case for stress- convert to Voigt 6-element form if key == 'stress' and results[key].shape == (3, 3): stress = results[key] stress = np.array([stress[0, 0], stress[1, 1], stress[2, 2], stress[1, 2], stress[0, 2], stress[0, 1]]) results[key] = stress for key in list(atoms.arrays.keys()): if (key in per_atom_properties and len(value.shape) >= 1 and value.shape[0] == len(atoms)): results[key] = atoms.arrays[key] if results != {}: calculator = SinglePointCalculator(atoms, **results) atoms.calc = calculator return atoms
def read_single_image(f, levcfg, imcon, natoms, is_trajectory, symbols=None): cell = zeros((3, 3)) ispbc = imcon > 0 if ispbc or is_trajectory: for j in range(3): line = f.readline() line = line.split() for i in range(3): try: cell[j, i] = float(line[i]) except ValueError: raise RuntimeError("error reading cell") if symbols: sym = symbols else: sym = [] positions = [] velocities = [] forces = [] charges = [] masses = [] disp = [] if is_trajectory: counter = range(natoms) else: from itertools import count counter = count() labels = [] mass = None ch = None d = None for a in counter: line = f.readline() if not line: a -= 1 break m = re.match(r'\s*([A-Za-z][a-z]?)(\S*)', line) assert m is not None, line symbol, label = m.group(1, 2) symbol = symbol.capitalize() if is_trajectory: ll = line.split() if len(ll) == 5: mass, ch, d = [float(i) for i in line.split()[2:5]] else: mass, ch = [float(i) for i in line.split()[2:4]] charges.append(ch) masses.append(mass) disp.append(d) if not symbols: assert symbol in chemical_symbols sym.append(symbol) # make sure label is not empty if label: labels.append(label) else: labels.append('') x, y, z = f.readline().split()[:3] positions.append([float(x), float(y), float(z)]) if levcfg > 0: vx, vy, vz = f.readline().split()[:3] velocities.append([float(vx) * dlp_v_ase, float(vy) * dlp_v_ase, float(vz) * dlp_v_ase]) if levcfg > 1: fx, fy, fz = f.readline().split()[:3] forces.append([float(fx) * dlp_f_ase, float(fy) * dlp_f_ase, float(fz) * dlp_f_ase]) if symbols and (a + 1 != len(symbols)): raise ValueError("Counter is at {} but you gave {} symbols" .format(a + 1, len(symbols))) if imcon == 0: pbc = False elif imcon == 6: pbc = [True, True, False] else: assert imcon in [1, 2, 3] pbc = True atoms = Atoms(positions=positions, symbols=sym, cell=cell, pbc=pbc, # Cell is centered around (0, 0, 0) in dlp4: celldisp=-cell.sum(axis=0) / 2) if is_trajectory: atoms.set_masses(masses) atoms.set_array(DLP4_DISP_KEY, disp, float) atoms.set_initial_charges(charges) atoms.set_array(DLP4_LABELS_KEY, labels, str) if levcfg > 0: atoms.set_velocities(velocities) if levcfg > 1: atoms.calc = SinglePointCalculator(atoms, forces=forces) return atoms
def run_tests(): import os import time from subprocess import CalledProcessError os.chdir(os.path.dirname(os.path.realpath(__file__))) from tscode.settings import (CALCULATOR, COMMANDS, DEFAULT_FF_LEVELS, DEFAULT_LEVELS, FF_CALC, FF_OPT_BOOL, PROCS) if CALCULATOR not in ('MOPAC','ORCA','GAUSSIAN','XTB'): raise Exception(f'{CALCULATOR} is not a valid calculator. Use MOPAC, ORCA, GAUSSIAN or XTB.') import numpy as np from ase.atoms import Atoms from ase.optimize import LBFGS from tscode.ase_manipulations import get_ase_calc from tscode.optimization_methods import opt_funcs_dict from tscode.utils import (HiddenPrints, clean_directory, loadbar, read_xyz, run_command, time_to_string) os.chdir('tests') t_start_run = time.perf_counter() data = read_xyz('C2H4.xyz') ########################################################################## print('\nRunning tests for TSCoDe. Settings used:') print(f'{CALCULATOR=}') if CALCULATOR != 'XTB': print(f'{CALCULATOR} COMMAND = {COMMANDS[CALCULATOR]}') print('\nTesting calculator...') ########################################################################## opt_funcs_dict[CALCULATOR](data.atomcoords[0], data.atomnos, method=DEFAULT_LEVELS[CALCULATOR], procs=PROCS, read_output=False) print(f'{CALCULATOR} raw calculator works.') ########################################################################## atoms = Atoms('HH', positions=np.array([[0, 0, 0], [0, 0, 1]])) atoms.calc = get_ase_calc((CALCULATOR, DEFAULT_LEVELS[CALCULATOR], PROCS, None)) LBFGS(atoms, logfile=None).run() clean_directory() print(f'{CALCULATOR} ASE calculator works.') ########################################################################## print(f'\n{FF_OPT_BOOL=}') ff = f'on. Calculator is {FF_CALC}. Checking its status.' if FF_OPT_BOOL else 'off.' print(f'Force Field optimization is turned {ff}') if FF_OPT_BOOL: if FF_CALC == 'OB': try: print('Trying to import the OpenBabel Python Module...') from openbabel import openbabel print('Module imported successfully.') except ImportError: raise Exception(f'Could not import OpenBabel Python module. Is standalone openbabel correctly installed?') else: # == 'XTB', 'GAUSSIAN' opt_funcs_dict[FF_CALC](data.atomcoords[0], data.atomnos, method=DEFAULT_FF_LEVELS[FF_CALC], procs=PROCS, read_output=False) print(f'{FF_CALC} FF raw calculator works.') ########################################################################## atoms.calc = get_ase_calc((FF_CALC, DEFAULT_FF_LEVELS[FF_CALC], PROCS, None)) LBFGS(atoms, logfile=None).run() clean_directory() print(f'{FF_CALC} ASE calculator works.') print('\nNo installation faults detected with the current settings. Running tests.') ########################################################################## tests = [] for f in os.listdir(): if f.endswith('.txt'): tests.append(os.path.realpath(f)) # os.chdir(os.path.dirname(os.getcwd())) # os.chdir('tscode') # # Back to ./tscode times = [] for i, f in enumerate(tests): name = f.split('\\')[-1].split('/')[-1][:-4] # trying to make it work for either Win, Linux (and Mac?) loadbar(i, len(tests), f'Running TSCoDe tests ({name}): ') t_start = time.perf_counter() try: with HiddenPrints(): run_command(f'python -m tscode {f} -n {name}') except CalledProcessError as error: print('\n\n--> An error occurred:\n') print(error.stderr.decode("utf-8")) quit() t_end = time.perf_counter() times.append(t_end-t_start) loadbar(len(tests), len(tests), f'Running TSCoDe tests ({name}): ') print() for i, f in enumerate(tests): print(' {:25s}{} s'.format(f.split('\\')[-1].split('/')[-1][:-4], round(times[i], 3))) print(f'\nTSCoDe tests completed with no errors. ({time_to_string(time.perf_counter() - t_start_run)})\n')
def read_gpaw_out(fileobj, index): notfound = [] def index_startswith(lines, string): if not isinstance(string, str): # assume it's a list for entry in string: try: return index_startswith(lines, entry) except ValueError: pass raise ValueError if string in notfound: raise ValueError for i, line in enumerate(lines): if line.startswith(string): return i notfound.append(string) raise ValueError def index_pattern(lines, pattern): repat = re.compile(pattern) if pattern in notfound: raise ValueError for i, line in enumerate(lines): if repat.match(line): return i notfound.append(pattern) raise ValueError def read_forces(lines, ii): f = [] for i in range(ii + 1, ii + 1 + len(atoms)): try: x, y, z = lines[i].split()[-3:] f.append((float(x), float(y), float(z))) except (ValueError, IndexError) as m: raise IOError('Malformed GPAW log file: %s' % m) return f, i lines = [line.lower() for line in fileobj.readlines()] images = [] while True: try: i = index_startswith(lines, 'reference energy:') Eref = float(lines[i].split()[-1]) except ValueError: Eref = None try: i = lines.index('unit cell:\n') except ValueError: pass else: if lines[i + 2].startswith(' -'): del lines[i + 2] # old format cell = [] pbc = [] for line in lines[i + 2:i + 5]: words = line.split() if len(words) == 5: # old format cell.append(float(words[2])) pbc.append(words[1] == 'yes') else: # new format with GUC cell.append([float(word) for word in words[3:6]]) pbc.append(words[2] == 'yes') try: i = lines.index('positions:\n') except ValueError: break symbols = [] positions = [] for line in lines[i + 1:]: words = line.split() if len(words) < 5: break n, symbol, x, y, z = words[:5] symbols.append(symbol.split('.')[0].title()) positions.append([float(x), float(y), float(z)]) if len(symbols): atoms = Atoms(symbols=symbols, positions=positions, cell=cell, pbc=pbc) else: atoms = Atoms(cell=cell, pbc=pbc) lines = lines[i + 5:] try: ii = index_pattern(lines, '\\d+ k-point') word = lines[ii].split() kx = int(word[2]) ky = int(word[4]) kz = int(word[6]) bz_kpts = (kx, ky, kz) ibz_kpts = int(lines[ii + 1].split()[0]) except (ValueError, TypeError, IndexError): bz_kpts = None ibz_kpts = None try: i = index_startswith(lines, 'energy contributions relative to') except ValueError: e = energy_contributions = None else: energy_contributions = {} for line in lines[i + 2:i + 8]: fields = line.split(':') energy_contributions[fields[0]] = float(fields[1]) line = lines[i + 10] assert (line.startswith('zero kelvin:') or line.startswith('extrapolated:')) e = float(line.split()[-1]) try: ii = index_pattern(lines, '(fixed )?fermi level(s)?:') except ValueError: eFermi = None else: fields = lines[ii].split() try: def strip(string): for rubbish in '[],': string = string.replace(rubbish, '') return string eFermi = [float(strip(fields[-2])), float(strip(fields[-1]))] except ValueError: eFermi = float(fields[-1]) # read Eigenvalues and occupations ii1 = ii2 = 1e32 try: ii1 = index_startswith(lines, ' band eigenvalues occupancy') except ValueError: pass try: ii2 = index_startswith(lines, ' band eigenvalues occupancy') except ValueError: pass ii = min(ii1, ii2) if ii == 1e32: kpts = None else: ii += 1 words = lines[ii].split() vals = [] while (len(words) > 2): vals.append([float(w) for w in words]) ii += 1 words = lines[ii].split() vals = np.array(vals).transpose() kpts = [SinglePointKPoint(1, 0, 0)] kpts[0].eps_n = vals[1] kpts[0].f_n = vals[2] if vals.shape[0] > 3: kpts.append(SinglePointKPoint(1, 1, 0)) kpts[1].eps_n = vals[3] kpts[1].f_n = vals[4] # read charge try: ii = index_startswith(lines, 'total charge:') except ValueError: q = None else: q = float(lines[ii].split()[2]) # read dipole moment try: ii = index_startswith(lines, 'dipole moment:') except ValueError: dipole = None else: line = lines[ii] for x in '()[],': line = line.replace(x, '') dipole = np.array([float(c) for c in line.split()[2:5]]) try: ii = index_startswith(lines, 'local magnetic moments') except ValueError: magmoms = None else: magmoms = [] for j in range(ii + 1, ii + 1 + len(atoms)): magmom = lines[j].split()[-1].rstrip(')') magmoms.append(float(magmom)) try: ii = lines.index('forces in ev/ang:\n') except ValueError: f = None else: f, i = read_forces(lines, ii) try: ii = index_startswith(lines, 'vdw correction:') except ValueError: pass else: line = lines[ii + 1] assert line.startswith('energy:') e = float(line.split()[-1]) f, i = read_forces(lines, ii + 3) if len(images) > 0 and e is None: break if q is not None and len(atoms) > 0: n = len(atoms) atoms.set_initial_charges([q / n] * n) if magmoms is not None: atoms.set_initial_magnetic_moments(magmoms) if e is not None or f is not None: calc = SinglePointDFTCalculator(atoms, energy=e, forces=f, dipole=dipole, magmoms=magmoms, efermi=eFermi, bzkpts=bz_kpts, ibzkpts=ibz_kpts) calc.eref = Eref calc.name = 'gpaw' if energy_contributions is not None: calc.energy_contributions = energy_contributions if kpts is not None: calc.kpts = kpts atoms.calc = calc images.append(atoms) lines = lines[i:] if len(images) == 0: raise IOError('Corrupted GPAW-text file!') return images[index]