def main(file_name): xyz_file = XYZFile(file_name) frames = xyz_file.geometries # titles = xyz_file.titles # Unit cell, decide how to make this general matrix = np.array([[ 1.4731497044857509E+01, 3.2189795740722255E-02, 4.5577626559295564E-02 ], [ 4.2775481701113616E-02, 2.1087874593411915E+01, -2.8531114198383896E-02 ], [ 6.4054385616337750E-02, 1.3315840416191497E-02, 1.4683043045316882E+01 ]]) matrix *= angstrom cell = UnitCell(matrix) frac = UnitCell.to_fractional(cell, frames) xmin = np.min(frac[:, :, 0]) ymin = np.min(frac[:, :, 1]) zmin = np.min(frac[:, :, 2]) frac[:, :, 0] -= -0.5 # xmin frac[:, :, 1] -= -0.5 # ymin frac[:, :, 2] -= -0.5 # zmin decimals = np.modf(frac)[0] # decimals[:,:,0] += xmin # decimals[:,:,1] += ymin # decimals[:,:,2] += zmin frac_wrapped = np.where(decimals < 0, 1 + decimals, decimals) # frac_wrapped[:,:,0] += xmin # frac_wrapped[:,:,1] += ymin # frac_wrapped[:,:,2] += zmin cart_wrapped = UnitCell.to_cartesian(cell, frac_wrapped) xyz_file.geometries = cart_wrapped xyz_file.write_to_file(file_name.rsplit(".", 1)[0] + "_wrapped.xyz")
def test_distance_matrix_periodic(self): for i in xrange(1000): N = 6 unit_cell = UnitCell( numpy.random.uniform(0,1,(3,3)), numpy.random.randint(0,2,3).astype(bool), ) fractional = numpy.random.uniform(0,1,(N,3)) coordinates = unit_cell.to_cartesian(fractional) from molmod.ext import molecules_distance_matrix dm = molecules_distance_matrix(coordinates, unit_cell.matrix, unit_cell.reciprocal) for i in xrange(N): for j in xrange(i,N): delta = coordinates[j]-coordinates[i] delta = unit_cell.shortest_vector(delta) distance = numpy.linalg.norm(delta) self.assertAlmostEqual(dm[i,j], distance)
def test_distances_intra_random_periodic(self): for i in xrange(10): coordinates = numpy.random.uniform(0,1,(20,3)) while True: unit_cell = UnitCell( numpy.random.uniform(0,5,(3,3)), numpy.random.randint(0,2,3).astype(bool), ) if unit_cell.spacings.min() > 0.5: break coordinates = unit_cell.to_cartesian(coordinates)*3-unit_cell.matrix.sum(axis=1) cutoff = numpy.random.uniform(1, 6) pair_search = PairSearchIntra(coordinates, cutoff, unit_cell) self.verify_bins_intra_periodic(pair_search.bins) distances = [ (frozenset([i0, i1]), distance) for i0, i1, delta, distance in pair_search ] self.verify_distances_intra(coordinates, cutoff, distances, unit_cell)
def get_random_ff(self): N = 6 mask = numpy.zeros((N,N), bool) for i in xrange(N): for j in xrange(i): mask[i,j] = True from molmod.ext import molecules_distance_matrix while True: unit_cell = UnitCell( numpy.random.uniform(0,3,(3,3)), numpy.random.randint(0,2,3).astype(bool), ) fractional = numpy.random.uniform(0,1,(N,3)) coordinates = unit_cell.to_cartesian(fractional) if numpy.random.randint(0,2): unit_cell = None dm = molecules_distance_matrix(coordinates) else: dm = molecules_distance_matrix(coordinates, unit_cell.matrix, unit_cell.reciprocal) if dm[mask].min() > 1.0: break edges = set([]) while len(edges) < 2*N: v1 = numpy.random.randint(N) while True: v2 = numpy.random.randint(N) if v2 != v1: break edges.add(frozenset([v1,v2])) edges = tuple(edges) numbers = numpy.random.randint(6, 10, N) graph = MolecularGraph(edges, numbers) ff = ToyFF(graph, unit_cell) return ff, coordinates, dm, mask, unit_cell
def test_distances_inter_random_periodic(self): for i in xrange(10): fractional0 = numpy.random.uniform(0,1,(20,3)) fractional1 = numpy.random.uniform(0,1,(20,3)) while True: unit_cell = UnitCell( numpy.random.uniform(0,5,(3,3)), numpy.random.randint(0,2,3).astype(bool), ) if unit_cell.spacings.min() > 0.5: break coordinates0 = unit_cell.to_cartesian(fractional0)*3-unit_cell.matrix.sum(axis=1) coordinates1 = unit_cell.to_cartesian(fractional1)*3-unit_cell.matrix.sum(axis=1) cutoff = numpy.random.uniform(1, 6) pair_search = PairSearchInter(coordinates0, coordinates1, cutoff, unit_cell) self.verify_bins_inter_periodic(pair_search.bins0, pair_search.bins1) distances = [ ((i0, i1), distance) for i0, i1, delta, distance in pair_search ] self.verify_distances_inter(coordinates0, coordinates1, cutoff, distances, unit_cell)
def load_molecule_vasp(contcar, outcar_freq, outcar_energy=None, energy=None, multiplicity=1, is_periodic=True): """Load a molecule from VASP 4.6.X and 5.3.X output files Arguments: | contcar -- A CONTCAR file with the structure used as POSCAR file for the Hessian/frequency calculation in VASP. Do not use the CONTCAR file generated by the frequency calculation. Use the CONTCAR from the preceding geometry optimization instead. | outcar_freq -- The OUTCAR file of the Hessian/frequency calculation. Also the gradient and the energy are read from this file. The energy without entropy (but not the extrapolation to sigma=0) is used. Optional arguments: | outcar_energy -- When given, the (first) energy without entropy is read from this file (not the extrapolation to sigma=0) instead of reading the energy from the freq output | energy -- The potential energy, which overrides the contents of outcar_freq. | multiplicity -- The spin multiplicity of the electronic system [default=1] | is_periodic -- True when the system is periodic in three dimensions. False when the systen is nonperiodic. [default=True]. """ # auxiliary function to read energy: def read_energy_without_entropy(f): # Go to the first energy for line in f: if line.startswith( ' FREE ENERGIE OF THE ION-ELECTRON SYSTEM (eV)'): break # Skip three lines and read energy next(f) next(f) next(f) return float(next(f).split()[3]) * electronvolt # Read atomic symbols, coordinates and cell vectors from CONTCAR symbols = [] coordinates = [] with open(contcar) as f: # Skip title. next(f).strip() # Read scale for rvecs. rvec_scale = float(next(f)) # Read rvecs. VASP uses one row per cell vector. rvecs = np.fromstring(next(f) + next(f) + next(f), sep=' ').reshape(3, 3) rvecs *= rvec_scale * angstrom unit_cell = UnitCell(rvecs) # Read symbols unique_symbols = next(f).split() # Read atom counts per symbol symbol_counts = [int(w) for w in next(f).split()] assert len(symbol_counts) == len(unique_symbols) natom = sum(symbol_counts) # Construct array with atomic numbers. numbers = [] for iunique in range(len(unique_symbols)): number = periodic[unique_symbols[iunique]].number numbers.extend([number] * symbol_counts[iunique]) numbers = np.array(numbers) # Check next line while next(f) != 'Direct\n': continue # Load fractional coordinates fractional = np.zeros((natom, 3), float) for iatom in range(natom): words = next(f).split() fractional[iatom, 0] = float(words[0]) fractional[iatom, 1] = float(words[1]) fractional[iatom, 2] = float(words[2]) coordinates = unit_cell.to_cartesian(fractional) if outcar_energy is not None and energy is None: with open(outcar_energy) as f: energy = read_energy_without_entropy(f) # Read energy, gradient, Hessian and masses from outcar_freq. Note that the first # energy/force calculation is done on the unperturbed input structure. with open(outcar_freq) as f: # Loop over the POTCAR sections in the OUTCAR file number = None masses = np.zeros(natom, float) while True: line = next(f) if line.startswith(' VRHFIN ='): symbol = line[11:line.find(':')].strip() number = periodic[symbol].number elif line.startswith(' POMASS ='): mass = float(line[11:line.find(';')]) * amu masses[numbers == number] = mass elif number is not None and line.startswith( '------------------------------'): assert masses.min() > 0 break # Go to the first gradient for line in f: if line.startswith(' POSITION'): break # Skip one line and read the gradient next(f) gradient = np.zeros((natom, 3), float) gunit = electronvolt / angstrom for iatom in range(natom): words = next(f).split() gradient[iatom, 0] = -float(words[3]) * gunit gradient[iatom, 1] = -float(words[4]) * gunit gradient[iatom, 2] = -float(words[5]) * gunit if energy is None: energy = read_energy_without_entropy(f) # Go to the second derivatives for line in f: if line.startswith(' SECOND DERIVATIVES (NOT SYMMETRIZED)'): break # Skip one line. next(f) # Load free atoms (not fixed in space). keys = next(f).split() nfree_dof = len(keys) indices_free = [ 3 * int(key[:-1]) + { 'X': 0, 'Y': 1, 'Z': 2 }[key[-1]] - 3 for key in keys ] assert nfree_dof % 3 == 0 # Load the actual Hessian hunit = electronvolt / angstrom**2 hessian = np.zeros((3 * natom, 3 * natom), float) for ifree0 in range(nfree_dof): line = next(f) irow = indices_free[ifree0] # skip first col words = line.split()[1:] assert len(words) == nfree_dof for ifree1 in range(nfree_dof): icol = indices_free[ifree1] hessian[irow, icol] = -float(words[ifree1]) * hunit # Symmetrize the Hessian hessian = 0.5 * (hessian + hessian.T) return Molecule(numbers, coordinates, masses, energy, gradient, hessian, multiplicity=multiplicity, periodic=is_periodic, unit_cell=unit_cell)
def test_radius_indexes_2d_graphical(self): #uc = UnitCell(numpy.array([ # [2.0, 1.0, 0.0], # [0.0, 0.2, 0.0], # [0.0, 0.0, 10.0], #])) #radius = 0.8 uc = UnitCell(numpy.array([ [1.0, 1.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 10.0], ])) radius = 5.3 #uc = UnitCell(numpy.array([ # [1.0, 1.0, 0.0], # [0.0, 1.0, 0.0], # [0.0, 0.0, 1.0], #])) #radius = 0.9 fracs = numpy.arange(-0.5, 0.55, 0.1) import pylab from matplotlib.patches import Circle, Polygon from matplotlib.lines import Line2D pylab.clf() for i0 in fracs: for i1 in fracs: center = uc.to_cartesian([i0,i1,0.0]) pylab.gca().add_artist(Circle((center[0], center[1]), radius, fill=True, fc='#7777AA', ec='none')) pylab.gca().add_artist(Circle((0, 0), radius, fill=True, fc='#0000AA', ec='none')) ranges = uc.get_radius_ranges(radius) indexes = uc.get_radius_indexes(radius) for i in xrange(-ranges[0]-1, ranges[0]+1): start = uc.to_cartesian([i+0.5, -ranges[1]-0.5, 0]) end = uc.to_cartesian([i+0.5, ranges[1]+0.5, 0]) pylab.gca().add_artist(Line2D([start[0], end[0]], [start[1], end[1]], color="k", linewidth=1)) for i in xrange(-ranges[1]-1, ranges[1]+1): start = uc.to_cartesian([-ranges[0]-0.5, i+0.5, 0]) end = uc.to_cartesian([ranges[0]+0.5, i+0.5, 0]) pylab.gca().add_artist(Line2D([start[0], end[0]], [start[1], end[1]], color="k", linewidth=1)) for i in xrange(-ranges[0], ranges[0]+1): start = uc.to_cartesian([i, -ranges[1]-0.5, 0]) end = uc.to_cartesian([i, ranges[1]+0.5, 0]) pylab.gca().add_artist(Line2D([start[0], end[0]], [start[1], end[1]], color="k", linewidth=0.5, linestyle="--")) for i in xrange(-ranges[1], ranges[1]+1): start = uc.to_cartesian([-ranges[0]-0.5, i, 0]) end = uc.to_cartesian([ranges[0]+0.5, i, 0]) pylab.gca().add_artist(Line2D([start[0], end[0]], [start[1], end[1]], color="k", linewidth=0.5, linestyle="--")) for i0,i1,i2 in indexes: if i2 != 0: continue corners = uc.to_cartesian(numpy.array([ [i0-0.5, i1-0.5, 0.0], [i0-0.5, i1+0.5, 0.0], [i0+0.5, i1+0.5, 0.0], [i0+0.5, i1-0.5, 0.0], ])) pylab.gca().add_artist(Polygon(corners[:,:2], fill=True, ec='none', fc='r', alpha=0.5)) corners = uc.to_cartesian(numpy.array([ [-ranges[0]-0.5, -ranges[1]-0.5, 0.0], [-ranges[0]-0.5, +ranges[1]+0.5, 0.0], [+ranges[0]+0.5, +ranges[1]+0.5, 0.0], [+ranges[0]+0.5, -ranges[1]-0.5, 0.0], ])) pylab.xlim(1.1*corners[:,:2].min(), 1.1*corners[:,:2].max()) pylab.ylim(1.1*corners[:,:2].min(), 1.1*corners[:,:2].max()) #pylab.xlim(-1.5*radius, 1.5*radius) #pylab.ylim(-1.5*radius, 1.5*radius) pylab.savefig("output/radius_indexes_2d.png")
def load_molecule_vasp(contcar, outcar_freq, energy=None, multiplicity=1, is_periodic=True): """Load a molecule from VASP 4.6.X and 5.3.X output files Arguments: | contcar -- A CONTCAR file with the structure used as POSCAR file for the Hessian/frequency calculation in VASP. Do not use the CONTCAR file generated by the frequency calculation. Use the CONTCAR from the preceding geometry optimization instead. The energy without entropy (but not the extrapolation to sigma=0) is used. | outcar_freq -- The OUTCAR file of the Hessian/frequency calculation. Optional arguments: | energy -- The potential energy, which overrides the contents of outcar_freq. | multiplicity -- The spin multiplicity of the electronic system [default=1] | is_periodic -- True when the system is periodic in three dimensions. False when the systen is nonperiodic. [default=True]. """ # Read atomic symbols, coordinates and cell vectors from CONTCAR symbols = [] coordinates = [] with open(contcar) as f: # Skip title. f.next().strip() # Read scale for rvecs. rvec_scale = float(f.next()) # Read rvecs. VASP uses one row per cell vector. rvecs = np.fromstring(f.next()+f.next()+f.next(), sep=' ').reshape(3, 3) rvecs *= rvec_scale*angstrom unit_cell = UnitCell(rvecs) # Read symbols unique_symbols = f.next().split() # Read atom counts per symbol symbol_counts = [int(w) for w in f.next().split()] assert len(symbol_counts) == len(unique_symbols) natom = sum(symbol_counts) # Construct array with atomic numbers. numbers = [] for iunique in xrange(len(unique_symbols)): number = periodic[unique_symbols[iunique]].number numbers.extend([number]*symbol_counts[iunique]) numbers = np.array(numbers) # Check next line while f.next() != 'Direct\n': continue # Load fractional coordinates fractional = np.zeros((natom, 3), float) for iatom in xrange(natom): words = f.next().split() fractional[iatom, 0] = float(words[0]) fractional[iatom, 1] = float(words[1]) fractional[iatom, 2] = float(words[2]) coordinates = unit_cell.to_cartesian(fractional) # Read energy, gradient, Hessian and masses from outcar_freq. Note that the first # energy/force calculation is done on the unperturbed input structure. with open(outcar_freq) as f: # Loop over the POTCAR sections in the OUTCAR file number = None masses = np.zeros(natom, float) while True: line = f.next() if line.startswith(' VRHFIN ='): symbol = line[11:line.find(':')].strip() number = periodic[symbol].number elif line.startswith(' POMASS ='): mass = float(line[11:line.find(';')])*amu masses[numbers==number] = mass elif number is not None and line.startswith('------------------------------'): assert masses.min() > 0 break # Go to the first gradient for line in f: if line.startswith(' POSITION'): break # Skip one line and read the gradient f.next() gradient = np.zeros((natom, 3), float) gunit = electronvolt/angstrom for iatom in xrange(natom): words = f.next().split() gradient[iatom, 0] = -float(words[3])*gunit gradient[iatom, 1] = -float(words[4])*gunit gradient[iatom, 2] = -float(words[5])*gunit if energy is None: # Go to the first energy for line in f: if line.startswith(' FREE ENERGIE OF THE ION-ELECTRON SYSTEM (eV)'): break # Skip three lines and read energy f.next() f.next() f.next() energy = float(f.next().split()[3])*electronvolt # Go to the second derivatives for line in f: if line.startswith(' SECOND DERIVATIVES (NOT SYMMETRIZED)'): break # Skip one line. f.next() # Load free atoms (not fixed in space). keys = f.next().split() nfree_dof = len(keys) indices_free = [3*int(key[:-1])+{'X': 0, 'Y': 1, 'Z': 2}[key[-1]]-3 for key in keys] assert nfree_dof % 3 == 0 # Load the actual Hessian hunit = electronvolt/angstrom**2 hessian = np.zeros((3*natom, 3*natom), float) for ifree0 in xrange(nfree_dof): line = f.next() irow = indices_free[ifree0] # skip first col words = line.split()[1:] assert len(words) == nfree_dof for ifree1 in xrange(nfree_dof): icol = indices_free[ifree1] hessian[irow, icol] = -float(words[ifree1])*hunit # Symmetrize the Hessian hessian = 0.5*(hessian + hessian.T) return Molecule( numbers, coordinates, masses, energy, gradient, hessian, multiplicity=multiplicity, periodic=is_periodic, unit_cell=unit_cell)