def test_write_vasp_poscar_direct(self): """Test if VASP5 POSCARs can be written in fractional coordinates""" u = xtal.AtTraj() u.read_snapshot_vasp('tests/POSCAR.VASP5.cartesian.unitcell') u.snaplist[0].write_snapshot_vasp('tests/POSCAR',True) v = xtal.AtTraj() v.read_snapshot_vasp('tests/POSCAR') u_mo_atoms = [atom for atom in u.snaplist[0].atomlist if atom.element == "MO"] v_mo_atoms = [atom for atom in v.snaplist[0].atomlist if atom.element == "MO"] assert np.linalg.norm(u_mo_atoms[0].fract - v_mo_atoms[0].fract) < 0.0001 os.remove('tests/POSCAR')
def test_fractal(self): """Test fractal method""" u = xtal.AtTraj() u.read_snapshot_vasp('tests/POSCAR.VASP5.unitcell') u.make_periodic(np.array([100, 100, 1])) lv0 = len(u.snaplist[0].atomlist) selatoms = [ atom for atom in u.snaplist[0].atomlist if xtal.is_sierpinski_carpet_filled(1, atom.fract) ] lv1 = len(selatoms) selatoms = [ atom for atom in u.snaplist[0].atomlist if xtal.is_sierpinski_carpet_filled(2, atom.fract) ] lv2 = len(selatoms) selatoms = [ atom for atom in u.snaplist[0].atomlist if xtal.is_sierpinski_carpet_filled(3, atom.fract) ] lv3 = len(selatoms) selatoms = [ atom for atom in u.snaplist[0].atomlist if xtal.is_sierpinski_carpet_filled(4, atom.fract) ] lv4 = len(selatoms) assert (lv0, lv1, lv2, lv3, lv4) == (30000, 26634, 23730, 21210, 18813)
def test_read_pwp_trajectory(self): """Test if a PWP trajectory can be read""" u = xtal.AtTraj() u.read_trajectory_pwp('tests/pwp_aimd') num_snapshots = len(u.snaplist) num_atoms_last_snapshot = len(u.snaplist[-1].atomlist) assert (num_snapshots, num_atoms_last_snapshot) == (101, 54)
def test_boxtoabc(self): """Test if atoms can be folded back into the supercell""" u = xtal.AtTraj() u.read_snapshot_vasp('tests/POSCAR.VASP5.unitcell') u.box_to_abc() assert np.allclose(u.abc, np.array([3.16, 3.16, 27.16]), atol=0.1) and \ np.allclose(u.ang, np.array([np.pi/2, np.pi/2, 2*np.pi/3]), atol=0.1)
def test_move_atoms(self): """Test if overlapping atoms are removed based on provided cutoff""" u = xtal.AtTraj() u.read_snapshot_vasp('tests/POSCAR.VASP5.unitcell') u.dirtocar() snapshot = u.snaplist[0] mo_atom = [atom for atom in snapshot.atomlist if atom.element == "MO"][0] s_atom_top = [atom for atom in snapshot.atomlist if atom.fract[2] > 0.15][0] s_atom_bottom = [atom for atom in snapshot.atomlist if atom.fract[2] < 0.1][0] # Establish baselines top_dist = snapshot.pbc_distance(mo_atom,s_atom_top) bot_dist = snapshot.pbc_distance(mo_atom,s_atom_bottom) # Move the top and bottom S atoms by different distances. This should increase pbc_distances s_atom_top.move(np.array([0.0,0.0,5.0])) s_atom_bottom.move(np.array([0.0,0.0,-6.0])) u.cartodir() m1_top_dist = snapshot.pbc_distance(mo_atom,s_atom_top) m1_bot_dist = snapshot.pbc_distance(mo_atom,s_atom_bottom) # Move the entire trajectory. This should not change pbc_distances u.move(np.array([0.0,0.0,9.0])) u.cartodir() m2_top_dist = snapshot.pbc_distance(mo_atom,s_atom_top) m2_bot_dist = snapshot.pbc_distance(mo_atom,s_atom_bottom) # Test all distances. Initially 2.4, Expands beyond 5.0. And then stays the same assert (top_dist < 2.41 and bot_dist < 2.41 and \ m1_top_dist > 5.0 and m1_bot_dist > 6.0 and \ np.isclose(m2_top_dist, m1_top_dist, atol=1e-5) and \ np.isclose(m2_bot_dist, m1_bot_dist, atol=1e-5))
def read_energy(outfilename): """ Read-in a multiple partially-converged structures from a PES scan (including bond-scans, angle-scans and dihedral-scans) :param outfilename: Single filename for ``stdout`` from the QChem PES scan job or a list of filenames for ``stdout`` files from partial QChem PES scan jobs :type outfilename: str :returns: ``xtal`` trajectory object with structures and converged energies along the PES scan as individual snapshots """ structure = xtal.AtTraj() energies = [] if isinstance(outfilename, list): listfilenames = outfilename else: listfilenames = [outfilename] for single_outfilename in list(listfilenames): # Read energies outfile = open(single_outfilename, 'r') for line in outfile: if 'Final energy is' in line: energy_in_Hartrees = float(line.strip().split()[-1]) energies.append(energy_in_Hartrees * convert.energy['Ha']['eV']) outfile.close() return np.array(energies)
def test_dirtocar(self): """Test if fractional units can be converted to cartesian coordinates""" u = xtal.AtTraj() u.read_snapshot_vasp('tests/POSCAR.VASP5.unitcell') u.dirtocar() zpos_atom_one = u.snaplist[0].atomlist[0].cart[2] assert (zpos_atom_one > 3.0 and zpos_atom_one < 3.1)
def _read_atomic_charges(outfilename): """ Read atomic charge information from a completed GULP job file :param outfilename: Filename of the GULP output file :type outfilename: str :returns: xtal object with optimized charge information """ structure = xtal.AtTraj() structure.box = np.zeros((3, 3)) outfile = open(outfilename, 'r') while True: oneline = outfile.readline() if not oneline: # EOF check break if 'Output for configuration' in oneline: snapshot = structure.create_snapshot(xtal.Snapshot) if 'Final charges from ReaxFF' in oneline: snapshot.atomlist = [] dummyline = outfile.readline() dummyline = outfile.readline() dummyline = outfile.readline() dummyline = outfile.readline() while True: charges = outfile.readline().strip().split() if charges[0][0] == '-': break else: atom = snapshot.create_atom(xtal.Atom) atom.charge = float(charges[-1]) return structure
def test_remove_overlap(self): """Test if overlapping atoms are removed based on provided cutoff""" u = xtal.AtTraj() u.read_snapshot_vasp('tests/POSCAR.VASP5.duplicates.unitcell') snapshot = u.snaplist[0] raw_num_atoms = len(snapshot.atomlist) # Remove all duplicate atoms closer than 0.11 snapshot.remove_overlap(0.11) pt1_pass1_num_atoms = len(snapshot.atomlist) snapshot.remove_overlap(0.11) # second pass shold not change anything pt1_pass2_num_atoms = len(snapshot.atomlist) # Remove all duplicate atoms closer than 0.21 snapshot.remove_overlap(0.21) pt2_pass1_num_atoms = len(snapshot.atomlist) snapshot.remove_overlap(0.21) # second pass shold not change anything pt2_pass2_num_atoms = len(snapshot.atomlist) # Remove all duplicate atoms closer than 0.31 snapshot.remove_overlap(0.31) pt3_pass1_num_atoms = len(snapshot.atomlist) snapshot.remove_overlap(0.31) # second pass shold not change anything pt3_pass2_num_atoms = len(snapshot.atomlist) assert (raw_num_atoms, pt1_pass1_num_atoms, pt1_pass2_num_atoms, \ pt2_pass1_num_atoms, pt2_pass2_num_atoms, \ pt3_pass1_num_atoms, pt3_pass2_num_atoms) == (6, 5, 5, 4, 4, 3, 3)
def read_atomic_charges(outfilename): """ Read-in a multiple partially-converged structures from a PES scan (including bond-scans, angle-scans and dihedral-scans) :param outfilename: Single filename for ``stdout`` from the QChem PES scan job or a list of filenames for ``stdout`` files from partial QChem PES scan jobs :type outfilename: str :returns: ``xtal`` trajectory object with structures and converged energies along the PES scan as individual snapshots """ structure = xtal.AtTraj() structure.box = np.zeros((3, 3)) energies = [] if isinstance(outfilename, list): listfilenames = outfilename else: listfilenames = [outfilename] for single_outfilename in list(listfilenames): # Read structure outfile = open(single_outfilename, 'r') while True: line = outfile.readline() if not line: # break at EOF break if 'Ground-State Mulliken Net Atomic Charges' in line: charge_array = [] dummyline = outfile.readline() dummyline = outfile.readline() dummyline = outfile.readline() while True: charges = outfile.readline().strip().split() if charges[0][0] == '-': break charge_array.append(float(charges[2])) if 'OPTIMIZATION CONVERGED' in line: snapshot = structure.create_snapshot(xtal.Snapshot) dummyline = outfile.readline() dummyline = outfile.readline() dummyline = outfile.readline() dummyline = outfile.readline() # Atomic coordinates start here atomID = 0 while True: coords = outfile.readline() if coords.strip() == '': break atom = snapshot.create_atom(xtal.Atom) atom.element, atom.cart = coords.strip().split( )[1], np.array( list(map(float, coords.strip().split()[2:5]))) atom.charge = charge_array[atomID] atomID += 1 outfile.close() return structure
def test_remap_id(self): """Test if trajectory elements can be remapped""" u = xtal.AtTraj() u.read_snapshot_vasp('tests/POSCAR.VASP5.unitcell') u.remap_id('S','TE') no_S_atoms = len([atom for atom in u.snaplist[0].atomlist if atom.element == 'S']) no_Te_atoms = len([atom for atom in u.snaplist[0].atomlist if atom.element == 'TE']) assert (no_S_atoms, no_Te_atoms) == (0,2)
def test_pbc_distance(self): """Test if distances between atoms are calculated correctly""" u = xtal.AtTraj() u.read_snapshot_vasp('tests/POSCAR.VASP5.unitcell') mo_atom = u.snaplist[0].atomlist[0] s_atom = u.snaplist[0].atomlist[1] same_atom_distance = u.snaplist[0].pbc_distance(mo_atom,mo_atom) different_atom_distance = u.snaplist[0].pbc_distance(mo_atom,s_atom) assert (same_atom_distance == 0.0 and different_atom_distance > 2.40 and different_atom_distance < 2.41)
def test_inbox(self): """Test if atoms can be folded back into the supercell""" u = xtal.AtTraj() u.read_snapshot_vasp('tests/POSCAR.VASP5.cartesian.unitcell') u.snaplist[0].atomlist[0].move(np.array([0.0,0.0,30.0])) u.cartodir() u.inbox() zpos_fract = u.snaplist[0].atomlist[0].fract[2] zpos_cart = u.snaplist[0].atomlist[0].cart[2] assert (zpos_fract < 0.3 and zpos_cart < 10.0)
def read_atomic_structure(structure_file): """ Read-in atomic structure. Currently only VASP POSCAR/CONTCAR files are supported :param structure_file: Filename of the atomic structure file :type structure_file: str """ structure = xtal.AtTraj(verbose=False) if ('POSCAR' in structure_file) or ('CONTCAR' in structure_file): structure.read_snapshot_vasp(structure_file) return structure
def test_identisort_cartesian(self): """Test non periodic identisort""" u = xtal.AtTraj() u.read_snapshot_vasp('tests/POSCAR.VASP5.unitcell') u.read_snapshot_vasp('tests/POSCAR.VASP5.randomized.unitcell') u.dirtocar() snap0 = u.snaplist[0] snap1 = u.snaplist[1] u.identical_sort(snap0, snap1, periodic=False) assert np.linalg.norm(snap0.atomlist[0].cart - snap1.atomlist[0].cart) < 0.01 and \ np.linalg.norm(snap0.atomlist[1].cart - snap1.atomlist[1].cart) < 0.01 and \ np.linalg.norm(snap0.atomlist[2].cart - snap1.atomlist[2].cart) < 0.01
def read_atomic_charges(outfilename): """ Read atomic charge information from a completed rxmd job : param outfilename : Path of the file containing information about the rxmd run : returns: xtal object with optimized charge information """ structure = xtal.AtTraj() snapshot = structure.create_snapshot(xtal.Snapshot) #outfile = open(self.path + '/DAT/000000001.xyz', 'r') natoms = None line, dummyline = None, None with open(self.path + '/DAT/000000001.xyz', 'r') as outfile: line = outfile.readline() natoms = int(line.strip().split()[0]) dummyline = outfile.readline() structure.abc = np.array([ float(dummyline[0]), float(dummyline[1]), float(dummyline[2]) ]) structure.ang = np.array([ float(dummyline[3]), float(dummyline[4]), float(dummyline[5]) ]) for i in range(natoms): charges = outfile.readline() charges = charges.strip().split() atom = snapshot.create_atom(xtal.Atom) if charges[0] == 'C': atom.element = charges[0] if charges[0] == 'H': atom.element = charges[0] if charges[0] == 'O': atom.element = charges[0] if charges[0] == 'N': atom.element = charges[0] if charges[0] == 'S': atom.element = charges[0] atom.charge = float(charges[4]) return structure
def read_scan(outfilename): """ Read-in a multiple partially-converged structures from a PES scan (including bond-scans, angle-scans and dihedral-scans) :param outfilename: Single filename for ``stdout`` from the QChem PES scan job or a list of filenames for ``stdout`` files from partial QChem PES scan jobs :type outfilename: str :returns: ``xtal`` trajectory object with structures and converged energies along the PES scan as individual snapshots """ structure = xtal.AtTraj() energies = [] if isinstance(outfilename, list): listfilenames = outfilename else: listfilenames = [outfilename] for single_outfilename in list(listfilenames): # Read energies outfile = open(single_outfilename,'r') for line in outfile: if 'Final energy is' in line: energy_in_Hartrees = float(line.strip().split()[-1]) energies.append(energy_in_Hartrees * convert.energy['Ha']['eV']) outfile.close() # Read structure outfile = open(single_outfilename,'r') for line in outfile: if 'OPTIMIZATION CONVERGED' in line: snapshot = structure.create_snapshot(xtal.Snapshot) dummyline = outfile.readline() dummyline = outfile.readline() dummyline = outfile.readline() dummyline = outfile.readline() # Atomic coordinates start here while True: coords = outfile.readline() if coords.strip()=='': break atom = snapshot.create_atom(xtal.Atom) atom.element, atom.cart = coords.strip().split()[1], np.array(list(map(float,coords.strip().split()[2:5]))) outfile.close() for counter, snapshot in enumerate(structure.snaplist): snapshot.energy = energies[counter] return structure
def read_energy(xml_file): """ Read-in energy from a VASP trajectory. Currently only vasprun.xml files are supported :param xml_file: Filename of the atomic structure file :type xml_file: str :returns: xtal trajectory with the structure in the first snapshot """ structure = xtal.AtTraj(verbose=False) if ('xml' in xml_file): structure.read_trajectory_vasp(xml_file) energies = [snapshot.energy for snapshot in structure.snaplist] return np.array(energies)
def read_ground_state(outfilename): """ Read-in a single converged structure from a QChem optimization run :param outfilename: Filename for ``stdout`` from the QChem job :type outfilename: str :returns: ``xtal`` tranjectory with a single snapshot with the converged structure and ground-state energy """ structure = xtal.AtTraj() snapshot = structure.create_snapshot(xtal.Snapshot) outfile = open(outfilename,'r') # Read energies for line in outfile: if 'Final energy is' in line: energy_in_Hartrees = float(line.strip().split()[-1]) break snapshot.energy = energy_in_Hartrees * convert.energy['Ha']['eV'] for line in outfile: if 'OPTIMIZATION CONVERGED' in line: dummyline = outfile.readline() dummyline = outfile.readline() dummyline = outfile.readline() dummyline = outfile.readline() # Atomic coordinates start here while True: coords = outfile.readline() if coords.strip()=='': break atom = snapshot.create_atom(xtal.Atom) atom.element, atom.cart = coords.strip().split()[1], np.array(list(map(float,coords.strip().split()[2:5]))) break for line in outfile: if 'Ground-State Mulliken Net Atomic Charges' in line: dummyline = outfile.readline() dummyline = outfile.readline() dummyline = outfile.readline() for atom in snapshot.atomlist: atom.charge = outfile.readline().strip().split()[2] break outfile.close() return structure
def read_atomic_charges(outfilename): """ Read atomic charge information from a completed GULP job : param outfilename : Path of the file containing information about the gulp run : returns: xtal object with optimized charge information """ structure = xtal.AtTraj() snapshot = structure.create_snapshot(xtal.Snapshot) outfile = open(outfilename, 'r') natoms = None for line in outfile: if 'Total number atoms/shells' in line: natoms = int(line.strip().split()[-1]) if 'Final charges from QEq' in line: snapshot.atomlist = [] dummyline = outfile.readline() dummyline = outfile.readline() dummyline = outfile.readline() dummyline = outfile.readline() # Atomic Charge information starts here counter = 0 while True: charges = outfile.readline() charges = charges.strip().split() atom = snapshot.create_atom(xtal.Atom) if float(charges[1]) == 1: atom.element = 'H' if float(charges[1]) == 6: atom.element = 'C' if float(charges[1]) == 7: atom.element = 'N' if float(charges[1]) == 8: atom.element = 'O' atom.charge = float(charges[2]) counter += 1 if counter == natoms: break return structure
def read_atomic_structure(structure_file): """ Read-in atomic structure. Currently VASP POSCAR/CONTCAR/XDATCAR and vasprun.xml files (or directory containing vasprun.xml files) are supported :param structure_file: Filename of the atomic structure file :type structure_file: str :returns: xtal trajectory with the structure in the first snapshot """ structure = xtal.AtTraj(verbose=False) if ('xml' in structure_file) or ('XDATCAR' in structure_file) or ( os.path.isdir(structure_file)): structure.read_trajectory_vasp(structure_file) elif ('POSCAR' in structure_file) or ('CONTCAR' in structure_file): structure.read_snapshot_vasp(structure_file) return structure
def _read_structure(outfilename): """ Read converged structure (cell and atomic positions) from the MD job :param outfilename: Path of file containing stdout of the GULP job :type outfilename: str :returns: xtal.AtTraj object with (optimized) individual structures as separate snapshots """ print(outfilename) relaxed = xtal.AtTraj() relaxed.box = np.zeros((3, 3)) # Read number of atoms, box definition and atom coordinates outfile = open(outfilename, 'r') for line in outfile: if 'NUMBER OF ATOMS' in line.strip(): snapshot = relaxed.create_snapshot(xtal.Snapshot) nextline = outfile.readline() num_atoms = int(nextline.strip()) elif 'BOX BOUNDS' in line.strip(): if 'xy' in line.strip(): l1 = outfile.readline() l2 = outfile.readline() l3 = outfile.readline() xlo_bound, xhi_bound, xy = list(map(float, l1.strip().split())) ylo_bound, yhi_bound, xz = list(map(float, l2.strip().split())) zlo_bound, zhi_bound, yz = list(map(float, l3.strip().split())) xlo = xlo_bound - np.amin([0.0, xy, xz, xy + xz]) xhi = xhi_bound - np.amax([0.0, xy, xz, xy + xz]) ylo = ylo_bound - np.amin([0.0, yz]) yhi = yhi_bound - np.amax([0.0, yz]) zlo = zlo_bound zhi = zhi_bound lx = xhi - xlo ly = yhi - ylo lz = zhi - zlo relaxed.abc = np.array([ lx, np.sqrt((ly * ly) + (xy * xy)), np.sqrt((lz * lz) + (xz * xz) + (yz * yz)) ]) cosa = ((xy * xz) + (ly * yz)) / (relaxed.abc[1] * relaxed.abc[2]) cosb = xz / relaxed.abc[2] cosc = xy / relaxed.abc[1] relaxed.ang = np.array( [np.arccos(cosa), np.arccos(cosb), np.arccos(cosc)]) relaxed.abc_to_box() else: l1 = outfile.readline() l2 = outfile.readline() l3 = outfile.readline() xlo, xhi = list(map(float, l1.strip().split())) ylo, yhi = list(map(float, l2.strip().split())) zlo, zhi = list(map(float, l3.strip().split())) lx = xhi - xlo ly = yhi - ylo lz = zhi - zlo relaxed.box[0][0] = lx relaxed.box[1][1] = ly relaxed.box[2][2] = lz elif 'ATOMS' in line.strip(): for atomID in range(num_atoms): atom_details = outfile.readline().strip().split() atom = snapshot.create_atom(xtal.Atom) atom.element = atom_details[2].upper() atom.charge = float(atom_details[4]) atom.cart = np.array(list(map(float, atom_details[5:8]))) atom.vel = np.array(list(map(float, atom_details[8:11]))) atom.force = np.array(list(map(float, atom_details[11:14]))) outfile.close() return relaxed
def error_structure_distortion(outfilename, relax_atoms=False, relax_cell=False): if not relax_atoms: # If atoms are not relaxed (i.e. single point calculation, then return 0.0) return 0.0 # In the future, add a info/warning message in the log if relax_atoms: # If atoms are leaxed, then create 2 atomic trajectories, one for each of the initial and relaxed structures initial = xtal.AtTraj() initial.abc = np.array([0.0, 0.0, 0.0]) initial.ang = np.array([0.0, 0.0, 0.0]) initial_snapshot = initial.create_snapshot(xtal.Snapshot) relaxed = xtal.AtTraj() relaxed.abc = np.array([0.0, 0.0, 0.0]) relaxed.ang = np.array([0.0, 0.0, 0.0]) relaxed_snapshot = relaxed.create_snapshot(xtal.Snapshot) # Read number of atoms outfile = open(outfilename, 'r') for line in outfile: if 'Number of irreducible atoms/shells' in line.strip(): num_atoms = int(line.strip().split()[-1]) outfile.close() for atomID in range(num_atoms): initial_snapshot.create_atom(xtal.Atom) initial_snapshot.atomlist[atomID].cart = np.array([0.0, 0.0, 0.0]) initial_snapshot.atomlist[atomID].fract = np.array([0.0, 0.0, 0.0]) relaxed_snapshot.create_atom(xtal.Atom) relaxed_snapshot.atomlist[atomID].cart = np.array([0.0, 0.0, 0.0]) relaxed_snapshot.atomlist[atomID].fract = np.array([0.0, 0.0, 0.0]) if relax_cell: # In atoms are relaxed, and simulation cell is also relaxed convert_to_cart = True # We have to read in 2 box sizes, one for the initial cell and one for the relaxed cell outfile = open(outfilename, 'r') for oneline in outfile: if 'Comparison of initial and final' in oneline: dummyline = outfile.readline() dummyline = outfile.readline() dummyline = outfile.readline() dummyline = outfile.readline() while True: data = outfile.readline().strip().split() if data[0].isdigit(): atomID = int(data[0]) - 1 if data[1] == 'x': axisID = 0 elif data[1] == 'y': axisID = 1 else: axisID = 2 if data[5] == 'Cartesian': initial_snapshot.atomlist[atomID].cart[ axisID] = float(data[2]) relaxed_snapshot.atomlist[atomID].cart[ axisID] = float(data[3]) convert_to_cart = False elif data[5] == 'Fractional': initial_snapshot.atomlist[atomID].fract[ axisID] = float(data[2]) relaxed_snapshot.atomlist[atomID].fract[ axisID] = float(data[3]) elif data[0][0] == '-': break break outfile.close() if convert_to_cart: # READ TWO CELL SIZES - ONE FOR THE INITIAL CELL, ONE FOR THE RELAXED CELL outfile = open(outfilename, 'r') for oneline in outfile: if 'Comparison of initial and final' in oneline: dummyline = outfile.readline() dummyline = outfile.readline() dummyline = outfile.readline() dummyline = outfile.readline() while True: data = outfile.readline().strip().split() if data[0] == 'a': initial.abc[0], relaxed.abc[0] = float( data[1]), float(data[2]) elif data[0] == 'b': initial.abc[1], relaxed.abc[1] = float( data[1]), float(data[2]) elif data[0] == 'c': initial.abc[2], relaxed.abc[2] = float( data[1]), float(data[2]) elif data[0] == 'alpha': initial.ang[0], relaxed.ang[0] = float( data[1]), float(data[2]) elif data[0] == 'beta': initial.ang[1], relaxed.ang[1] = float( data[1]), float(data[2]) elif data[0] == 'gamma': initial.ang[2], relaxed.ang[2] = float( data[1]), float(data[2]) elif data[0][0] == '-': break break outfile.close() initial.abc_to_box() relaxed.abc_to_box() initial.make_dircar_matrices() relaxed.make_dircar_matrices() initial.dirtocar() relaxed.dirtocar() relaxed.move(initial.snaplist[0].atomlist[0].cart - relaxed.snaplist[0].atomlist[0].cart) error = 0.0 for i in range(len(initial.snaplist[0].atomlist)): dr = initial.snaplist[0].atomlist[ i].cart - relaxed.snaplist[0].atomlist[i].cart error += np.inner(dr, dr) else: relaxed.move(initial.snaplist[0].atomlist[0].cart - relaxed.snaplist[0].atomlist[0].cart) error = 0.0 for i in range(len(initial.snaplist[0].atomlist)): dr = initial.snaplist[0].atomlist[ i].cart - relaxed.snaplist[0].atomlist[i].cart error += np.inner(dr, dr) return error else: # IF THE CELL IS NOT RELAXED. JUST THE ATOMS ARE RELAXED convert_to_cart = True outfile = open(outfilename, 'r') for oneline in outfile: if 'Comparison of initial and final' in oneline: dummyline = outfile.readline() dummyline = outfile.readline() dummyline = outfile.readline() dummyline = outfile.readline() while True: data = outfile.readline().strip().split() if data[0].isdigit(): atomID = int(data[0]) - 1 if data[1] == 'x': axisID = 0 elif data[1] == 'y': axisID = 1 else: axisID = 2 if data[5] == 'Cartesian': initial_snapshot.atomlist[atomID].cart[ axisID] = float(data[2]) relaxed_snapshot.atomlist[atomID].cart[ axisID] = float(data[3]) convert_to_cart = False elif data[5] == 'Fractional': initial_snapshot.atomlist[atomID].fract[ axisID] = float(data[2]) relaxed_snapshot.atomlist[atomID].fract[ axisID] = float(data[3]) elif data[0][0] == '-': break break outfile.close() if convert_to_cart: outfile = open( outfilename, 'r' ) ### READ A SINGLE BOX SIZE FOR THE INITIAL AND RELAXED STRUCTURES for oneline in outfile: if 'Cartesian lattice vectors (Angstroms)' in oneline: dummyline = outfile.readline() for i in range(3): initial.box[i][0:3] = list( map(float, outfile.readline().strip().split())) outfile.close() relaxed.box = initial.box initial.make_dircar_matrices() relaxed.make_dircar_matrices() initial.dirtocar() relaxed.dirtocar() relaxed.move(initial.snaplist[0].atomlist[0].cart - relaxed.snaplist[0].atomlist[0].cart) error = 0.0 for i in range(len(initial.snaplist[0].atomlist)): dr = initial.snaplist[0].atomlist[ i].cart - relaxed.snaplist[0].atomlist[i].cart error += np.inner(dr, dr) else: relaxed.move(initial.snaplist[0].atomlist[0].cart - relaxed.snaplist[0].atomlist[0].cart) error = 0.0 for i in range(len(initial.snaplist[0].atomlist)): dr = initial.snaplist[0].atomlist[ i].cart - relaxed.snaplist[0].atomlist[i].cart error += np.inner(dr, dr) return error
def _read_structure(outfilename, relax_cell=True, initial_box=None): """ Read converged structure (cell and atomic positions) from the MD job :param outfilename: Path of file containing stdout of the GULP job :type outfilename: str :param relax_cell: Flag to identify if simulation cell was relaxed during the MD job :type relax_cell: boolean :param initial_box: Initial simulation cell used for the MD job :type initial_box: 3X3 np.ndarray :returns: xtal.AtTraj object with (optimized) individual structures as separate snapshots """ relaxed = xtal.AtTraj() relaxed.box = np.zeros((3, 3)) if (not relax_cell) and (initial_box is not None): relaxed.box = initial_box # Read number of atoms outfile = open(outfilename, 'r') for line in outfile: if 'Number of irreducible atoms/shells' in line.strip(): snapshot = relaxed.create_snapshot(xtal.Snapshot) num_atoms = int(line.strip().split()[-1]) for atomID in range(num_atoms): atom = snapshot.create_atom(xtal.Atom) atom.cart = np.array([0.0, 0.0, 0.0]) atom.fract = np.array([0.0, 0.0, 0.0]) outfile.close() snapID = 0 convert_to_cart = True outfile = open(outfilename, 'r') while True: oneline = outfile.readline() if not oneline: # break for EOF break if 'Comparison of initial and final' in oneline: dummyline = outfile.readline() dummyline = outfile.readline() dummyline = outfile.readline() dummyline = outfile.readline() while True: data = outfile.readline().strip().split() if data[0].isdigit(): atomID = int(data[0]) - 1 if data[1] == 'x': axisID = 0 elif data[1] == 'y': axisID = 1 else: axisID = 2 if data[5] == 'Cartesian': relaxed.snaplist[snapID].atomlist[atomID].cart[ axisID] = float(data[3]) convert_to_cart = False elif data[5] == 'Fractional': relaxed.snaplist[snapID].atomlist[atomID].fract[ axisID] = float(data[3]) elif data[0][0] == '-': break snapID += 1 outfile.close() if convert_to_cart: if relax_cell: outfile = open(outfilename, 'r') snapID = 0 while True: oneline = outfile.readline() if not oneline: # break for EOF break if 'Final Cartesian lattice vectors (Angstroms)' in oneline: dummyline = outfile.readline() for i in range(3): relaxed.box[i][0:3] = list( map(float, outfile.readline().strip().split())) relaxed.make_dircar_matrices() relaxed.snaplist[snapID].dirtocar() snapID += 1 outfile.close() else: relaxed.make_dircar_matrices() relaxed.dirtocar() return relaxed
def read_structure(outfilename): """ Read-in a multiple partially-converged structures from a PES scan (including bond-scans, angle-scans and dihedral-scans) :param outfilename: Single filename for ``stdout`` from the QChem PES scan job or a list of filenames for ``stdout`` files from partial QChem PES scan jobs :type outfilename: str :returns: ``xtal`` trajectory object with structures and converged energies along the PES scan as individual snapshots """ structure = xtal.AtTraj() structure.box = np.zeros((3, 3)) energies = [] if isinstance(outfilename, list): listfilenames = outfilename else: listfilenames = [outfilename] for single_outfilename in list(listfilenames): # Read structure outfile = open(single_outfilename, 'r') while True: line = outfile.readline() if not line: # break at EOF break if 'OPTIMIZATION CONVERGED' in line: snapshot = structure.create_snapshot(xtal.Snapshot) dummyline = outfile.readline() dummyline = outfile.readline() dummyline = outfile.readline() dummyline = outfile.readline() # Atomic coordinates start here while True: coords = outfile.readline() if coords.strip() == '': break atom = snapshot.create_atom(xtal.Atom) atom.element, atom.cart = coords.strip().split( )[1], np.array( list(map(float, coords.strip().split()[2:5]))) xpos_this_snapshot = [ atom.cart[0] for atom in snapshot.atomlist ] ypos_this_snapshot = [ atom.cart[1] for atom in snapshot.atomlist ] zpos_this_snapshot = [ atom.cart[2] for atom in snapshot.atomlist ] offset_vector = 0.0 - np.array([ np.amin(xpos_this_snapshot), np.amin(ypos_this_snapshot), np.amin(zpos_this_snapshot) ]) snapshot.move(offset_vector) outfile.close() # Since the QChem structure is often non-periodic, we set up a box that is 50 Angstrom larger than the maximum extent of atoms xpos = [ atom.cart[0] for atom in snapshot.atomlist for snapshot in structure.snaplist ] ypos = [ atom.cart[1] for atom in snapshot.atomlist for snapshot in structure.snaplist ] zpos = [ atom.cart[2] for atom in snapshot.atomlist for snapshot in structure.snaplist ] structure.box[0][0] = np.amax(xpos) - np.amin(xpos) + 50.0 structure.box[1][1] = np.amax(ypos) - np.amin(ypos) + 50.0 structure.box[2][2] = np.amax(zpos) - np.amin(zpos) + 50.0 return structure
def test_read_vasp_poscar_direct(self): """Test if VASP5 POSCARs in direct coordinates can be read""" u = xtal.AtTraj() u.read_snapshot_vasp('tests/POSCAR.VASP5.unitcell') assert len(u.snaplist[0].atomlist) == 3
def my_error_function(rr): # Get a unique path for GULP jobs from the MPI rank. Set to '0' for serial jobs try: path = str(pool.rank) except: path = '0' # Calculate_Ground_State gt_gs = qchem.read_ground_state('ground_truths/optCHOSx.out') gt_gs_energy = gt_gs.snaplist[0].energy md_gs_job = gulp.job(path = path) ffio.write_forcefield_file(md_gs_job.path+'/FF',template,rr,verbose=False) md_gs_job.forcefield = md_gs_job.path + '/FF' md_gs_job.temporary_forcefield = False md_gs_job.structure = gt_gs md_gs_job.pbc = False md_gs_job.options['relax_atoms'] = False md_gs_job.options['relax_cell'] = False md_gs_job.write_script_file(convert_reax_forcefield) md_gs_job.run(command='gulp') md_gs_energy = gulp.read_energy(md_gs_job.path + '/' + md_gs_job.outfile) md_gs_job.cleanup() # Calculate Small Length Scan for Bond Frequencies gt_freq_scan = qchem.read_scan('ground_truths/frequency_length_scan/CHOSx.out') md_freq_scan_energies = [] gt_freq_scan_energies = [] for snapID, snapshot in enumerate(gt_freq_scan.snaplist): gt_freq_scan_energies.append(snapshot.energy) md_freq_scan_job = gulp.job(path = path) ffio.write_forcefield_file(md_freq_scan_job.path+'/FF',template,rr,verbose=False) thisstructure = xtal.AtTraj() thisstructure.snaplist.append(snapshot) md_freq_scan_job.forcefield = md_freq_scan_job.path + '/FF' md_freq_scan_job.temporary_forcefield = False md_freq_scan_job.structure = thisstructure md_freq_scan_job.pbc = False md_freq_scan_job.options['relax_atoms'] = False md_freq_scan_job.options['relax_cell'] = False md_freq_scan_job.write_script_file(convert_reax_forcefield) md_freq_scan_job.run(command='gulp') md_freq_scan_energy = gulp.read_energy(md_freq_scan_job.path + '/' + md_freq_scan_job.outfile) md_freq_scan_energies.append(md_freq_scan_energy) md_freq_scan_job.cleanup() del md_freq_scan_job # Calculate error md_freq_scan_energies = np.array(md_freq_scan_energies) gt_freq_scan_energies = np.array(gt_freq_scan_energies) md_gs_energy = np.array(md_gs_energy) gt_gs_energy = np.array(gt_gs_energy) freq_error = ezff.error_PES_scan( md_freq_scan_energies-md_gs_energy, gt_freq_scan_energies-gt_gs_energy, weights = 'minima') # Calculate Full Length Scan for Bond Dissociation Energy gt_dis_scan = qchem.read_scan(['ground_truths/dissociation_length_scan/CHOSx.run1.out', 'ground_truths/dissociation_length_scan/CHOSx.run2.out', 'ground_truths/dissociation_length_scan/CHOSx.run3.out']) md_dis_scan_energies = [] gt_dis_scan_energies = [] for snapID, snapshot in enumerate(gt_dis_scan.snaplist): gt_dis_scan_energies.append(snapshot.energy) md_dis_scan_job = gulp.job(path = path) ffio.write_forcefield_file(md_dis_scan_job.path+'/FF',template,rr,verbose=False) thisstructure = xtal.AtTraj() thisstructure.snaplist.append(snapshot) md_dis_scan_job.forcefield = md_dis_scan_job.path + '/FF' md_dis_scan_job.temporary_forcefield = False md_dis_scan_job.structure = thisstructure md_dis_scan_job.pbc = False md_dis_scan_job.options['relax_atoms'] = False md_dis_scan_job.options['relax_cell'] = False md_dis_scan_job.write_script_file(convert_reax_forcefield) md_dis_scan_job.run(command='gulp') md_dis_scan_energy = gulp.read_energy(md_dis_scan_job.path + '/' + md_dis_scan_job.outfile) md_dis_scan_energies.append(md_dis_scan_energy) md_dis_scan_job.cleanup() del md_dis_scan_job # Calculate error md_dis_scan_energies = np.array(md_dis_scan_energies) gt_dis_scan_energies = np.array(gt_dis_scan_energies) md_gs_energy = np.array(md_gs_energy) gt_gs_energy = np.array(gt_gs_energy) dis_error = ezff.error_PES_scan( md_dis_scan_energies-md_gs_energy, gt_dis_scan_energies-gt_gs_energy, weights = 'dissociation') return [freq_error, dis_error]
def test_make_periodic_vasp_poscar(self): """Test if VASP5 POSCARs an be PBC replicated""" u = xtal.AtTraj() u.read_snapshot_vasp('tests/POSCAR.VASP5.unitcell') u.make_periodic(np.array([5, 5, 3])) assert len(u.snaplist[0].atomlist) == 225