Пример #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")
Пример #2
0
 def from_cell_str(cls, unit_cell_str, sub=slice(None)):
     sub = fix_slice(sub)
     if "," in unit_cell_str:
         parameters = list(parse_unit(word) for word in unit_cell_str.split(",") if len(word) > 0)
         if len(parameters) == 1:
             a = parameters[0]
             single = numpy.array([[a,0,0],[0,a,0],[0,0,a]], float)
         elif len(parameters) == 3:
             a,b,c = parameters
             single = numpy.array([[[a,0,0],[0,b,0],[0,0,c]]], float)
         elif len(parameters) == 6:
             a,b,c,alpha,beta,gamma = parameters
             uc = UnitCell(
                 numpy.array([[1,0,0],[0,1,0],[0,0,1]], float),
                 numpy.array([True, True, True]),
             )
             uc.set_parameterst(numpy.array([a,b,c]), numpy.array([alpha,beta,gamma]))
             single = uc.cell
         elif len(parameters) == 9:
             single = numpy.array(parameters,float).reshape((3,3)).transpose()
         else:
             raise ValueError("If the --cell option contains comma's, one, three, six or nine value(s) are expected.")
         data = single.reshape((3,3,1))
     else:
         data = [
             [
                 load_track("%s.%s.%s" % (unit_cell_str, v, c), sub)
                 for v in "abc"
             ]
             for c in "xyz"
         ]
     return cls(data)
Пример #3
0
 def test_radius_indexes_2d(self):
     uc = UnitCell(numpy.identity(3, float), numpy.array([True, True, False]))
     indexes = uc.get_radius_indexes(0.5)
     expected_indexes = numpy.array([
         [-1, -1,  0],
         [-1,  0,  0],
         [-1,  1,  0],
         [ 0, -1,  0],
         [ 0,  0,  0],
         [ 0,  1,  0],
         [ 1, -1,  0],
         [ 1,  0,  0],
         [ 1,  1,  0],
     ])
     self.assertArraysEqual(indexes, expected_indexes)
Пример #4
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)
Пример #5
0
 def test_default_graph_periodic(self):
     molecule = Molecule.from_file("input/lau.xyz")
     uc = UnitCell.from_parameters3(
         numpy.array([14.587, 12.877, 7.613])*angstrom,
         numpy.array([90.000, 111.159, 90.000])*deg
     )
     uc = uc.alignment_c*uc
     molecule = molecule.copy_with(unit_cell=uc)
     molecule.set_default_graph()
     self.assertEqual(molecule.graph.num_edges, 4*molecule.size/3)
Пример #6
0
 def test_parameters(self):
     for counter in xrange(100):
         in_lengths = numpy.random.uniform(0.5, 1, (3,))
         in_angles = numpy.random.uniform(0.3, numpy.pi/2, (3,))
         try:
             uc = UnitCell.from_parameters3(in_lengths, in_angles)
         except ValueError, e:
             continue
         out_lengths, out_angles = uc.parameters
         self.assertArraysAlmostEqual(in_lengths, out_lengths)
         self.assertArraysAlmostEqual(in_angles, out_angles)
Пример #7
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
Пример #8
0
    def _setup_grid(self, cutoff, unit_cell, grid):
        """Choose a proper grid for the binning process"""
        if grid is None:
            # automatically choose a decent grid
            if unit_cell is None:
                grid = cutoff / 2.9
            else:
                # The following would be faster, but it is not reliable
                # enough yet.
                #grid = unit_cell.get_optimal_subcell(cutoff/2.0)
                divisions = np.ceil(unit_cell.spacings / cutoff)
                divisions[divisions < 1] = 1
                grid = unit_cell / divisions

        if isinstance(grid, float):
            grid_cell = UnitCell(
                np.array([[grid, 0, 0], [0, grid, 0], [0, 0, grid]]))
        elif isinstance(grid, UnitCell):
            grid_cell = grid
        else:
            raise TypeError(
                "Grid must be None, a float or a UnitCell instance.")

        if unit_cell is not None:
            # The columns of integer_matrix are the unit cell vectors in
            # fractional coordinates of the grid cell.
            integer_matrix = grid_cell.to_fractional(
                unit_cell.matrix.transpose()).transpose()
            if abs((integer_matrix - np.round(integer_matrix)) *
                   self.unit_cell.active).max() > 1e-6:
                raise ValueError(
                    "The unit cell vectors are not an integer linear combination of grid cell vectors."
                )
            integer_matrix = integer_matrix.round()
            integer_cell = UnitCell(integer_matrix, unit_cell.active)
        else:
            integer_cell = None

        return grid_cell, integer_cell
Пример #9
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)
Пример #10
0
    def _setup_grid(self, cutoff, unit_cell, grid):
        """Choose a proper grid for the binning process"""
        if grid is None:
            # automatically choose a decent grid
            if unit_cell is None:
                grid = cutoff/2.9
            else:
                # The following would be faster, but it is not reliable
                # enough yet.
                #grid = unit_cell.get_optimal_subcell(cutoff/2.0)
                divisions = numpy.ceil(unit_cell.spacings/cutoff)
                divisions[divisions<1] = 1
                grid = unit_cell/divisions

        if isinstance(grid, float):
            grid_cell = UnitCell(numpy.array([
                [grid, 0, 0],
                [0, grid, 0],
                [0, 0, grid]
            ]))
        elif isinstance(grid, UnitCell):
            grid_cell = grid
        else:
            raise TypeError("Grid must be None, a float or a UnitCell instance.")

        if unit_cell is not None:
            # The columns of integer_matrix are the unit cell vectors in
            # fractional coordinates of the grid cell.
            integer_matrix = grid_cell.to_fractional(unit_cell.matrix.transpose()).transpose()
            if abs((integer_matrix - numpy.round(integer_matrix))*self.unit_cell.active).max() > 1e-6:
                raise ValueError("The unit cell vectors are not an integer linear combination of grid cell vectors.")
            integer_matrix = integer_matrix.round()
            integer_cell = UnitCell(integer_matrix, unit_cell.active)
        else:
            integer_cell = None

        return grid_cell, integer_cell
Пример #11
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)
Пример #12
0
def iter_unit_cells(unit_cell_str, sub=None):
    sub = fix_slice(sub)
    if len(unit_cell_str) == 0:
        uc = UnitCell(
            numpy.array([[1,0,0],[0,1,0],[0,0,1]], float),
            numpy.array([False,False,False]),
        )
        while True:
            yield uc
    if "," in unit_cell_str:
        parameters = list(parse_unit(word) for word in unit_cell_str.split(",") if len(word) > 0)
        if len(parameters) == 1:
            a= parameters[0]
            uc = UnitCell(
                numpy.array([[a,0,0],[0,a,0],[0,0,a]], float),
                numpy.array([True, True, True]),
            )
        elif len(parameters) == 3:
            a,b,c = parameters
            uc = UnitCell(
                numpy.array([[a,0,0],[0,b,0],[0,0,c]], float),
                numpy.array([True, True, True]),
            )
        elif len(parameters) == 6:
            a,b,c,alpha,beta,gamma = parameters
            uc = UnitCell.from_parameters3(
                numpy.array([a,b,c]),
                numpy.array([alpha,beta,gamma])
            )
        elif len(parameters) == 9:
            uc = UnitCell(
                numpy.array(parameters, float).reshape((3,3)),
                numpy.array([True, True, True]),
            )
        else:
            raise ValueError("If the --cell option contains comma's, one, three, six or nine value(s) are expected.")
        while True:
            yield uc
    else:
        filenames = ["%s.%s" % (unit_cell_str, suffix) for suffix in ["a.x", "a.y", "a.z", "b.x", "b.y", "b.z", "c.x", "c.y", "c.z"]]
        dtype = numpy.dtype([("cell", float, (3,3))])
        mtr = MultiTracksReader(filenames, dtype, sub=sub)
        for row in mtr:
            yield UnitCell(
                numpy.array(row["cell"], float),
                numpy.array([True, True, True]),
            )
Пример #13
0
    def test_distances_intra_lau_periodic(self):
        coordinates = XYZFile("input/lau.xyz").geometries[0]
        cutoff = periodic.max_radius*2
        unit_cell = UnitCell.from_parameters3(
            numpy.array([14.59, 12.88, 7.61])*angstrom,
            numpy.array([ 90.0, 111.0, 90.0])*deg,
        )

        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)
Пример #14
0
    def apply_to(self, x, columns=False):
        """Apply this transformation to the given object

           The argument can be several sorts of objects:

           * ``numpy.array`` with shape (3, )
           * ``numpy.array`` with shape (N, 3)
           * ``numpy.array`` with shape (3, N), use ``columns=True``
           * ``Translation``
           * ``Rotation``
           * ``Complete``
           * ``UnitCell``

           In case of arrays, the 3D vectors are transformed. In case of trans-
           formations, a transformation is returned that consists of this
           transformation applied AFTER the given translation. In case of a unit
           cell, a unit cell with rotated cell vectors is returned. (The
           translational part does not affect the unit cell.)

           This method is equivalent to self*x.
        """
        if isinstance(x, numpy.ndarray) and len(
                x.shape) == 2 and x.shape[0] == 3 and columns:
            return numpy.dot(self.r, x) + self.t.reshape((3, 1))
        if isinstance(x, numpy.ndarray) and (
                x.shape == (3, ) or
            (len(x.shape) == 2 and x.shape[1] == 3)) and not columns:
            return numpy.dot(x, self.r.transpose()) + self.t
        elif isinstance(x, Complete):
            return Complete(numpy.dot(self.r, x.r),
                            numpy.dot(self.r, x.t) + self.t)
        elif isinstance(x, Translation):
            return Complete(self.r, numpy.dot(self.r, x.t) + self.t)
        elif isinstance(x, Rotation):
            return Complete(numpy.dot(self.r, x.r), self.t)
        elif isinstance(x, UnitCell):
            return UnitCell(numpy.dot(self.r, x.matrix), x.active)
        else:
            raise ValueError("Can not apply this rotation to %s" % x)
Пример #15
0
def load_molecule_cp2k(fn_sp, fn_freq, multiplicity=1, is_periodic=True):
    """Load a molecule with the Hessian from a CP2K computation

       Arguments:
        | fn_sp   --  The filename of the single point .out file containing the
                      energy and the forces.
        | fn_freq  --  The filename of the frequency .out file containing the
                       hessian

       Optional arguments:
        | 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 aperiodic. [default=True]
        | unit_cell  --  The unit cell vectors for periodic structures
    """

    # auxiliary routine to read atoms
    def atom_helper(f):
        # skip some lines
        for i in xrange(3):
            f.readline()
        # read the atom lines until an empty line is encountered
        numbers = []
        coordinates = []
        masses = []
        while True:
            line = f.readline()
            if len(line.strip()) == 0:
                break
            symbol = line[14:19].strip()[:2]
            atom = periodic[symbol]
            if atom is None:
                symbol = symbol[:1]
                atom = periodic[symbol]
            if atom is None:
                numbers.append(0)
            else:
                numbers.append(atom.number)
            coordinates.append(
                [float(line[22:33]),
                 float(line[34:45]),
                 float(line[46:57])])
            masses.append(float(line[72:]))

        numbers = np.array(numbers)
        coordinates = np.array(coordinates) * angstrom
        masses = np.array(masses) * amu
        return numbers, coordinates, masses

    # auxiliary routine to read forces
    def force_helper(f, skip, offset):
        # skip some lines
        for i in xrange(skip):
            f.readline()
        # Read the actual forces
        tmp = []
        while True:
            line = f.readline()
            if line == "\n":
                break
            if line == "":
                raise IOError("End of file while reading gradient (forces).")
            words = line.split()
            try:
                tmp.append([
                    float(words[offset]),
                    float(words[offset + 1]),
                    float(words[offset + 2])
                ])
            except StandardError:
                break
        return -np.array(tmp)  # force to gradient

    # go through the single point file: energy and gradient
    energy = None
    gradient = None
    with open(fn_sp) as f:
        while True:
            line = f.readline()
            if line == "":
                break
            if line.startswith(" ENERGY|"):
                energy = float(line[58:])
            elif line.startswith(" MODULE") and "ATOMIC COORDINATES" in line:
                numbers, coordinates, masses = atom_helper(f)
            elif line.startswith(" FORCES|"):
                gradient = force_helper(f, 0, 1)
                break
            elif line.startswith(' ATOMIC FORCES in [a.u.]'):
                gradient = force_helper(f, 2, 3)
                break
        if energy is None or gradient is None:
            raise IOError(
                "Could not read energy and/or gradient (forces) from single point file."
            )

    # go through the freq file: lattic vectors and hessian
    with open(fn_freq) as f:
        vectors = np.zeros((3, 3), float)
        for line in f:
            if line.startswith(" CELL"):
                break
        for axis in range(3):
            line = f.next()
            vectors[:, axis] = np.array(
                [float(line[29:39]),
                 float(line[39:49]),
                 float(line[49:59])])
        unit_cell = UnitCell(vectors * angstrom)

        free_indices = _load_free_low(f)
        if len(free_indices) > 0:
            total_size = coordinates.size
            free_size = len(free_indices)
            hessian = np.zeros((total_size, total_size), float)
            i2 = 0
            while i2 < free_size:
                num_cols = min(5, free_size - i2)
                f.next()  # skip two lines
                f.next()
                for j in xrange(free_size):
                    line = f.next()
                    words = line.split()
                    for i1 in xrange(num_cols):
                        hessian[free_indices[i2 + i1], free_indices[j]] = \
                            float(words[i1 + 2])
                i2 += num_cols
        else:
            raise IOError("Could not read hessian from freq file.")

    # symmetrize
    hessian = 0.5 * (hessian + hessian.transpose())
    # cp2k prints a transformed hessian, here we convert it back to the normal
    # hessian in atomic units.
    conv = 1e-3 * np.array([masses, masses, masses]).transpose().ravel()**0.5
    hessian *= conv
    hessian *= conv.reshape((-1, 1))

    return Molecule(numbers,
                    coordinates,
                    masses,
                    energy,
                    gradient,
                    hessian,
                    multiplicity,
                    0,
                    is_periodic,
                    unit_cell=unit_cell)
Пример #16
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)
Пример #17
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)
Пример #18
0
 def test_add_periodicities(self):
     for counter in xrange(100):
         uc0 = UnitCell(numpy.identity(3, float), numpy.zeros(3,bool))
         uc1 = uc0.add_cell_vector(numpy.random.uniform(-2,2,3))
         uc2 = uc1.add_cell_vector(numpy.random.uniform(-2,2,3))
         uc3 = uc2.add_cell_vector(numpy.random.uniform(-2,2,3))
Пример #19
0
 def test_shortest_vector(self):
     raise SkipTest
     # simple cases
     uc = UnitCell(numpy.identity(3,float)*3)
     self.assertArraysAlmostEqual(uc.shortest_vector([3, 0, 1]), numpy.array([0, 0, 1]))
     self.assertArraysAlmostEqual(uc.shortest_vector([-3, 0, 1]), numpy.array([0, 0, 1]))
     self.assertArraysAlmostEqual(uc.shortest_vector([-2, 0, 1]), numpy.array([1, 0, 1]))
     self.assertArraysAlmostEqual(uc.shortest_vector([-1.6, 1, 1]), numpy.array([1.4, 1, 1]))
     self.assertArraysAlmostEqual(uc.shortest_vector([-1.4, 1, 1]), numpy.array([-1.4, 1, 1]))
     # simple cases
     uc = UnitCell(numpy.identity(3,float)*3, numpy.array([True, False, False]))
     self.assertArraysAlmostEqual(uc.shortest_vector([3, 0, 1]), numpy.array([0, 0, 1]))
     self.assertArraysAlmostEqual(uc.shortest_vector([3, 0, 3]), numpy.array([0, 0, 3]))
     # random tests
     for uc_counter in xrange(1000):
         uc = self.get_random_uc(full=False)
         for r_counter in xrange(10):
             r0 = numpy.random.normal(0, 10, 3)
             r1 = uc.shortest_vector(r0)
             change = r1 - r0
             self.assert_(numpy.dot(change, r0) <= 0)
             #self.assert_(numpy.linalg.norm(r0) >= numpy.linalg.norm(r1))
             index = uc.to_fractional(r0-r1)
             self.assertArraysAlmostEqual(index, numpy.round(index), doabs=True)
             index = uc.to_fractional(r1)
             self.assert_(index.max()<0.5)
             self.assert_(index.max()>=-0.5)
         r0 = numpy.random.normal(0, 10, (10,3))
         r1 = uc.shortest_vector(r0)
         for i in xrange(10):
             r1_row_bis = uc.shortest_vector(r0[i])
             self.assertArraysAlmostEqual(r1_row_bis, r1[i], doabs=True)
Пример #20
0
 def test_shortest_vector_trivial(self):
     uc = UnitCell(numpy.identity(3, float))
     half = numpy.array([0.5,0.5,0.5])
     self.assertArraysEqual(uc.shortest_vector(half), -half)
     self.assertArraysEqual(uc.shortest_vector(-half), -half)
Пример #21
0
 def test_shortest_vector_aperiodic(self):
     unit_cell = UnitCell(numpy.identity(3, float), numpy.zeros(3, bool))
     shortest = unit_cell.shortest_vector(numpy.ones(3, float))
     expected = numpy.ones(3, float)
     self.assertArraysAlmostEqual(shortest, expected)
Пример #22
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")
Пример #23
0
 def test_radius_ranges_2d(self):
     uc = UnitCell(numpy.identity(3, float), numpy.array([True, True, False]))
     self.assertArraysEqual(uc.get_radius_ranges(3), numpy.array([3,3,0]))