def read_cube(in_file): """ Read a cube file and return a Mol and a CubeGrid object Parameters ---------- in_file : str Input file name Returns ------- out_mol : Mol object The atoms in the cube file out_cub : CubeGrid object The grid in the cube file where all distances are in Angstrom """ vectors = np.zeros((3, 3)) xyz_nums = [0, 0, 0] values = [] out_mol = Mol([]) ind = 0 natoms = 0 with open(in_file) as lines: for line in lines: if ind == 2: natoms = int(line.split()[0]) origin = np.array([float(i) for i in line.split()[1:]]) / pt.bohrconv if ind == 3: xyz_nums[0] = int(line.split()[0]) vectors[0] = np.array([float(i) for i in line.split()[1:] ]) / pt.bohrconv if ind == 4: xyz_nums[1] = int(line.split()[0]) vectors[1] = np.array([float(i) for i in line.split()[1:] ]) / pt.bohrconv if ind == 5: xyz_nums[2] = int(line.split()[0]) vectors[2] = np.array([float(i) for i in line.split()[1:] ]) / pt.bohrconv out_cub = CubeGrid(vectors, xyz_nums[0], xyz_nums[1], xyz_nums[2], origin) out_cub.set_grid_coord() if 6 <= ind < (6 + natoms): line_s = line.split() new_atom = Atom() new_atom.elem = per.num_to_elem(int(line_s[0])) new_atom.set_pos([float(i) / pt.bohrconv for i in line_s[2:]]) out_mol.append(new_atom) if ind >= (6 + natoms): values.extend([float(i) for i in line.split()]) ind += 1 values_arr = np.array(values) out_cub.grid[:, 3] = values_arr return out_cub, out_mol
def test(): from fromage.utils.atom import Atom from fromage.utils.mol import Mol mol_a = Mol([Atom("C", 1)]) mol_b = Mol([Atom("C", 2)]) mol_c = Mol([Atom("C", 3)]) mol_d = Mol([Atom("C", 4)]) lis = [mol_a, mol_b, mol_c, mol_d] print(all_dimers(lis))
def test_fit_to_pot(benz_pot_cub, benz_clust_char): print(benz_pot_cub.grid) sample_point = Atom("", 0, 0, 0) sample_point.es = 0.17671 print(benz_clust_char.es_pot([0, 0, 0])) fixed_atoms = benz_clust_char.select(0) var_atoms = Mol([i for i in benz_clust_char if i not in fixed_atoms]) fi.fit_points(var_atoms, fixed_atoms, Mol([sample_point])) out_clust = var_atoms + fixed_atoms print(out_clust.es_pot([0, 0, 0])) return
def read_points(in_name): """ Read point charges from an in-house Ewald.c output. The modified version of Ewald.c is needed. The extension is .pts-cry Parameters ---------- in_name : str Name of the file to read Returns ------- points : Mol object Point charges in the file. They have element "point" """ with open(in_name) as pts_file: pts_content = pts_file.readlines() # store point charges here points = Mol([]) for line in pts_content: xIn, yIn, zIn, qIn = map(float, line.split()) point = Atom("point", xIn, yIn, zIn, qIn) points.append(point) return points
def read_qe(in_name): """ Read the final positions of a QE calculation. Parameters ---------- in_name : str Name of the file to read Returns ------- atoms : list of Atom objects Last set of atoms in the file """ with open(in_name) as file_qe: content = file_qe.readlines() last_pos = 0 for line in content[::-1]: if "ATOMIC_POSITIONS" in line.split(): last_pos = content[::-1].index(line) break atoms = [] for line in content[-last_pos:]: if line == "End final coordinates\n": break elem, xPos, yPos, zPos = line.split() atom_2_add = Atom(elem, xPos, yPos, zPos, 0) atoms.append(atom_2_add) return atoms
def read_gauss(in_name): """ Read atoms in a Gaussian input file. The format is quite strict, better modify this function before using it. Parameters ---------- in_name : str Name of the file to read Returns ------- atoms : list of Atom objects Last set of atoms in the file """ with open(in_name) as file_gauss: content = file_gauss.readlines() for line in content: if line != "\n": if line.split()[0].isdigit(): last_pos = content.index(line) break atoms = [] for line in content[last_pos + 1:]: if line == "\n" or not line: break elem, xPos, yPos, zPos = line.split() atom_2_add = Atom(elem, xPos, yPos, zPos, 0) atoms.append(atom_2_add) return atoms
def read_g_pos(in_name): """ Read positions from a Gaussian log file. Parameters ---------- in_name : str Name of the file to read Returns ------- atoms : list of Atom objects Atomic positions at the beginning of the file for a single point .log """ with open(in_name) as gauss_file: content = gauss_file.readlines() # Input orientation for i, line in enumerate(content): if 'Input orientation:' in line: ori_line = i break atoms = [] for line in content[ori_line + 5:]: if not line.strip()[0].isdigit(): # if line not number break line_bits = [float(i) for i in line.split()] symbol = per.num_to_elem(line_bits[1]) atom_to_add = Atom(symbol, line_bits[3], line_bits[4], line_bits[5], 0) atoms.append(atom_to_add) return atoms
def read_vasp(in_name): """ Read VASP POSCAR-like file. The real use of this function is to handle one file which contains both coordinates and vectors. The actual VASP program is not used anywhere else. Make sure the "lattice constant" scaling is set to 1.0, "selective dynamics" is not enabled and the file is in Cartesian coordinates. Parameters ---------- in_name : str Name of the file to read Returns ------- M : 3x3 matrix Lattice vectors atoms : list of Atom types Atoms in the file """ with open(in_name) as vasp_file: vasp_content = vasp_file.readlines() # lattice vectors vec1 = vasp_content[2].split() vec2 = vasp_content[3].split() vec3 = vasp_content[4].split() # matrix from vectors M = np.zeros((3, 3)) M[0] = vec1 M[1] = vec2 M[2] = vec3 # reads names of elements and amounts species = vasp_content[5].split() amounts_str = vasp_content[6].split() amounts = map(int, amounts_str) # make Atom objects from file atoms = [] for element in species: # position of the first and last atom of one kind # in the vasp file firstAt = 8 + sum(amounts[:species.index(element)]) lastAt = 8 + sum(amounts[:species.index(element) + 1]) for line in vasp_content: if vasp_content.index(line) in range(firstAt, lastAt): xAtom, yAtom, zAtom = map(float, line.split()) atoms.append(Atom(element, xAtom, yAtom, zAtom)) return M, atoms
def test_fit_benz_clust(benz_clust_char): sample_point = Atom("", 0, 0, 0) sample_point2 = Atom("", 0.1, 0, 0) sample_point.es = 0 sample_point2.es = 0 fi.fit_points(benz_clust_char, None, Mol([sample_point, sample_point2])) return
def test_fit_benz_clust_shell(benz_clust_char): sample_point = Atom("", 0, 0, 0) sample_point2 = Atom("", 0.1, 0, 0) sample_point.es = 0 sample_point2.es = 0 fixed_atoms = benz_clust_char.select(0) var_atoms = Mol([i for i in benz_clust_char if i not in fixed_atoms]) fi.fit_points(var_atoms, fixed_atoms, Mol([sample_point, sample_point2])) return
def test_same_atoms_as(): mol_a_lis = [Atom("C", 1., 0., 0.), Atom("H", 1., 1., 1.)] mol_b_lis = [Atom("H", 1., 1., 1.), Atom("C", 1., 0., 0.)] mol_c_lis = [Atom("C", 1., 0., 0.), Atom("C", 1., 1., 1.)] mol_a = Mol(mol_a_lis) mol_b = Mol(mol_b_lis) mol_c = Mol(mol_c_lis) assert mol_a.same_atoms_as(mol_b) == True assert mol_a.same_atoms_as(mol_c) == False
def read_xyz(in_name): """ Read a .xyz file. Works for files containing several configurations e.g. a relaxation trajectory. Parameters ---------- in_name : str Name of the file to read Returns ------- atom_step = list of lists of Atom objects Each element of the list represents a configuration of atoms """ with open(in_name) as xyz_file: xyz_content = xyz_file.readlines() # main list where each element is a relaxation step atom_step = [] for i, line in enumerate(xyz_content): # if the line is the amount of atoms in the system if line.strip(): if line.split()[0].isdigit(): # list of atom objects inside on relaxation step atoms = [] # from 2 lines after the amount of atoms to the last atom line # for the relaxation step for line_in_step in xyz_content[i + 2:i + int(line) + 2]: elemAtom = line_in_step.split()[0] xAtom, yAtom, zAtom = map(float, line_in_step.split()[1:]) atoms.append(Atom(elemAtom, xAtom, yAtom, zAtom)) atom_step.append(atoms) xyz_file.close() return atom_step
def array2atom(template, pos): """ Turn an array of the form x1, y1, z1, x2, y2, z2 etc. into a list of Atom objects Parameters ---------- template : list of Atom objects A list of the same length of the desired one used to determine the elements of the atoms pos : list of floats List of coordinates of the form x1, y1, z1, x2, y2, z2 etc. Returns ------- out_atoms : list of Atom objects Resulting atoms """ sliced_pos = [pos[i:i + 3] for i in range(0, len(pos), 3)] out_atoms = [] for atom in zip(template, sliced_pos): new_atom = Atom(atom[0].elem, atom[1][0], atom[1][1], atom[1][2], 0) out_atoms.append(new_atom) return out_atoms
def o_at(): """Return am O Atom object at x = 0.8""" out_at = Atom("O", 0.8, 0.0, 0.0) return out_at
def test_sample(benz_pot_cub, benz_cell): pts = fi.shell_region(benz_pot_cub.grid, benz_cell, 0.2, 0.7) out_mol = Mol([]) for point in pts: out_mol.append(Atom("point", point[0], point[1], point[2]))
def c_o(): c_at = Atom("C", 0.0, 0.0, 0.0) o_at = Atom("O", 1.0, 0.0, 0.0) out_mol = Mol([c_at, o_at]) return out_mol
def c_o(): """CO Mol object""" c_at = Atom("C", 0.0, 0.0, 0.0) o_at = Atom("O", 1.0, 0.0, 0.0) out_mol = Mol([c_at, o_at]) return out_mol
def newat(): """Atom object C at origin""" return Atom("C", 0.0, 0.0, 0.0)
def c_at(): """Return a C Atom object at origin""" out_at = Atom("C", 0.0, 0.0, 0.0) return out_at
def o_at_outside(): """Return am O Atom object outside of the 111 cell""" out_at = Atom("O", 2.1, -0.3, 1.4) return out_at