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")
Beispiel #2
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
Beispiel #3
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)
Beispiel #4
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)
Beispiel #5
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)