Coverage for /builds/kinetik161/ase/ase/io/acemolecule.py: 98.61%
72 statements
« prev ^ index » next coverage.py v7.2.7, created at 2023-12-10 11:04 +0000
« prev ^ index » next coverage.py v7.2.7, created at 2023-12-10 11:04 +0000
1import numpy as np
3import ase.units
4from ase.atoms import Atoms
5from ase.calculators.singlepoint import SinglePointCalculator
6from ase.data import chemical_symbols
7from ase.io import read
10def parse_geometry(filename):
11 '''Read atoms geometry from ACE-Molecule log file and put it to self.data.
12 Parameters
13 ==========
14 filename: ACE-Molecule log file.
16 Returns
17 =======
18 Dictionary of parsed geometry data.
19 retval["Atomic_numbers"]: list of atomic numbers
20 retval["Positions"]: list of [x, y, z] coordinates for each atoms.
21 '''
22 with open(filename) as fd:
23 lines = fd.readlines()
24 start_line = 0
25 end_line = 0
26 for i, line in enumerate(lines):
27 if line == '==================== Atoms =====================\n':
28 start_line = i
29 if start_line != 0 and len(line.split('=')) > 3:
30 end_line = i
31 if not start_line == end_line:
32 break
33 atoms = []
34 positions = []
35 for i in range(start_line + 1, end_line):
36 atomic_number = lines[i].split()[0]
37 atoms.append(str(chemical_symbols[int(atomic_number)]))
38 xyz = [float(n) for n in lines[i].split()[1:4]]
39 positions.append(xyz)
41 return {"Atomic_numbers": atoms, "Positions": positions}
44def read_acemolecule_out(filename):
45 '''Interface to ACEMoleculeReader, return values for corresponding quantity
47 Parameters
48 ==========
49 filename: ACE-Molecule log file.
50 quantity: One of atoms, energy, forces, excitation-energy.
52 Returns
53 =======
54 - quantity = 'excitation-energy':
55 returns None. This is placeholder function to run TDDFT calculations
56 without IndexError.
57 - quantity = 'energy':
58 returns energy as float value.
59 - quantity = 'forces':
60 returns force of each atoms as numpy array of shape (natoms, 3).
61 - quantity = 'atoms':
62 returns ASE atoms object.
63 '''
64 data = parse_geometry(filename)
65 atom_symbol = np.array(data["Atomic_numbers"])
66 positions = np.array(data["Positions"])
67 atoms = Atoms(atom_symbol, positions=positions)
68 energy = None
69 forces = None
70 excitation_energy = None
71# results = {}
72# if len(results)<1:
73 with open(filename) as fd:
74 lines = fd.readlines()
76 for i in range(len(lines) - 1, 1, -1):
77 line = lines[i].split()
78 if len(line) > 2:
79 if line[0] == 'Total' and line[1] == 'energy':
80 energy = float(line[3])
81 break
82 # energy must be modified, hartree to eV
83 energy *= ase.units.Hartree
85 forces = []
86 for i in range(len(lines) - 1, 1, -1):
87 if '!============================' in lines[i]:
88 endline_num = i
89 if '! Force:: List of total force in atomic unit' in lines[i]:
90 startline_num = i + 2
91 for j in range(startline_num, endline_num):
92 forces.append(lines[j].split()[3:6])
93 convert = ase.units.Hartree / ase.units.Bohr
94 forces = np.array(forces, dtype=float) * convert
95 break
96 if not len(forces) > 0:
97 forces = None
99 # Set calculator to
100 calc = SinglePointCalculator(atoms, energy=energy, forces=forces)
101 atoms.calc = calc
103 results = {}
104 results['energy'] = energy
105 results['atoms'] = atoms
106 results['forces'] = forces
107 results['excitation-energy'] = excitation_energy
108 return results
111def read_acemolecule_input(filename):
112 '''Reads a ACE-Molecule input file
113 Parameters
114 ==========
115 filename: ACE-Molecule input file name
117 Returns
118 =======
119 ASE atoms object containing geometry only.
120 '''
121 with open(filename) as fd:
122 for line in fd:
123 if len(line.split('GeometryFilename')) > 1:
124 geometryfile = line.split()[1]
125 break
126 atoms = read(geometryfile, format='xyz')
127 return atoms