Esempio n. 1
0
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")
Esempio n. 2
0
 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)
Esempio n. 3
0
    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)
Esempio n. 4
0
    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
Esempio n. 5
0
    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)
Esempio n. 6
0
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)
Esempio n. 7
0
    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")
Esempio n. 8
0
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)