Ejemplo n.º 1
0
def tune_geometry(graph, mol):
    """Fine tune a molecular geometry, starting from a (very) poor guess of
       the initial geometry.

       Do not expect all details to be in perfect condition. A subsequent
       optimization with a more accurate level of theory is at least advisable.

       Arguments:
         graph  --  The molecular graph of the system
         mol  --  The initial guess of the coordinates
    """

    N = len(graph.numbers)
    from molmod.minimizer import Minimizer, NewtonGLineSearch

    ff = ToyFF(graph)
    x_init = mol.coordinates.ravel()

    #  level 3 geometry optimization: bond lengths + pauli
    ff.dm_reci = 0.2
    ff.bond_quad = 1.0
    minimizer = Minimizer(x_init, ff, NewtonGLineSearch, 1e-3, 1e-3, 2*N, 500, 50, do_gradient=True, verbose=False)
    x_init = minimizer.x

    #  level 4 geometry optimization: bond lengths + bending angles + pauli
    ff.bond_quad = 0.0
    ff.bond_hyper = 1.0
    ff.span_quad = 1.0
    minimizer = Minimizer(x_init, ff, NewtonGLineSearch, 1e-6, 1e-6, 2*N, 500, 50, do_gradient=True, verbose=False)
    x_init = minimizer.x

    x_opt = x_init

    mol = Molecule(graph.numbers, x_opt.reshape((N,3)))
    return mol
Ejemplo n.º 2
0
def convert_molecule_to_molmod(molecule):
    molModMolecule = Molecule(molecule.numbers,
                              molecule.coordinates,
                              molecule.label,
                              symbols=molecule.symbols)
    molModMolecule.set_default_graph()
    return molModMolecule
Ejemplo n.º 3
0
    def endElement(self, name):
        #print "END", name
        if name == 'molecule':
            if len(self.current_numbers) > 0:
                self.current_coordinates = np.array(self.current_coordinates)*angstrom
                molecule = Molecule(self.current_numbers, self.current_coordinates, self.current_title)
                molecule.extra = self.current_extra
                molecule.atoms_extra = self.current_atoms_extra

                name_to_index = {}
                for counter, name in enumerate(self.current_atom_names):
                    name_to_index[name] = counter

                edges = set()
                current_bonds_extra = {}
                for name1, name2, extra in self.current_bonds:
                    i1 = name_to_index.get(name1)
                    i2 = name_to_index.get(name2)
                    if i1 is not None and i2 is not None:
                        edge = frozenset([i1, i2])
                        if len(extra) > 0:
                            current_bonds_extra[edge] = extra
                        edges.add(edge)

                molecule.bonds_extra = current_bonds_extra
                if len(edges) == 0:
                    molecule.graph = None
                else:
                    molecule.graph = MolecularGraph(edges, self.current_numbers)
                del self.current_atom_names
                del self.current_bonds

                self.molecules.append(molecule)
            self.current_title = None
Ejemplo n.º 4
0
def load_pdb(filename):
    """
    Loads a single molecule from a pdb file.

    This function does support only a small fragment from the pdb specification.
    It assumes that there is only one molecular geometry in the pdb file.
    """
    f = file(filename)
    numbers = []
    coordinates = []
    occupancies = []
    betas = []
    for line in f:
        if line.startswith("ATOM"):
            symbol = line[76:78].strip()
            numbers.append(periodic[symbol].number)
            coordinates.append(
                [float(line[30:38]),
                 float(line[38:46]),
                 float(line[46:54])])
            occupancies.append(float(line[54:60]))
            betas.append(float(line[60:66]))
    f.close()
    if len(numbers) > 0:
        molecule = Molecule(numbers, coordinates)
        molecule.occupancies = numpy.array(occupancies)
        molecule.betas = numpy.array(betas)
        return molecule
    else:
        raise IOError("No molecule found in pdb file %s" % filename)
Ejemplo n.º 5
0
    def get_molecule(self, index=0):
        """Get a molecule from the trajectory

           Optional argument:
            | ``index``  --  The frame index [default=0]
        """
        return Molecule(self.numbers, self.geometries[index], self.titles[index], symbols=self.symbols)
Ejemplo n.º 6
0
        def test_one(xyz_fn, checks, reorder=False):
            mol = XYZFile(xyz_fn).get_molecule()
            graph = MolecularGraph.from_geometry(mol)
            zmat_gen = ZMatrixGenerator(graph)
            if reorder is False:
                self.assertArraysEqual(zmat_gen.new_index, numpy.arange(mol.size))
                self.assertArraysEqual(zmat_gen.old_index, numpy.arange(mol.size))

            zmat0 = zmat_gen.cart_to_zmat(mol.coordinates)
            for field, index, value in checks:
                self.assertAlmostEqual(zmat0[field][index], value, 2, "%s:%i %f!=%f" % (field,index,zmat0[field][index],value))

            numbers0, coordinates0 = zmat_to_cart(zmat0)
            mol0 = Molecule(numbers0, coordinates0)
            mol0.write_to_file("output/zmat_%s" % os.path.basename(xyz_fn))
            graph0 = MolecularGraph.from_geometry(mol0)
            zmat_gen0 = ZMatrixGenerator(graph0)
            self.assertArraysEqual(zmat_gen0.new_index, numpy.arange(mol.size))
            self.assertArraysEqual(zmat_gen0.old_index, numpy.arange(mol.size))

            zmat1 = zmat_gen0.cart_to_zmat(mol0.coordinates)
            for field, index, value in checks:
                self.assertAlmostEqual(zmat1[field][index], value, 2, "%s:%i %f!=%f" % (field,index,zmat1[field][index],value))

            numbers1, coordinates1 = zmat_to_cart(zmat1)

            self.assertArraysEqual(numbers0, numbers1)
            self.assertArraysAlmostEqual(coordinates0, coordinates1, 1e-5)
Ejemplo n.º 7
0
 def get_optimized_molecule(self):
     opt_coor = self.get_optimization_coordinates()
     if len(opt_coor) == 0:
         return None
     else:
         return Molecule(
             self.molecule.numbers,
             opt_coor[-1],
         )
Ejemplo n.º 8
0
    def get_first_molecule(self):
        """Get the first molecule from the trajectory

           This can be useful to configure your program before handeling the
           actual trajectory.
        """
        title, coordinates = self._first
        molecule = Molecule(self.numbers, coordinates, title, symbols=self.symbols)
        return molecule
Ejemplo n.º 9
0
 def get_first_molecule(self):
     if self._first is None:
         raise Error(
             "get_first_molecule must be called before the first iteration."
         )
     else:
         title, coordinates = self._first
         molecule = Molecule(self.numbers, coordinates, title)
         return molecule
Ejemplo n.º 10
0
 def get_optimized_molecule(self):
     """Return a molecule object of the optimal geometry"""
     opt_coor = self.get_optimization_coordinates()
     if len(opt_coor) == 0:
         return None
     else:
         return Molecule(
             self.molecule.numbers,
             opt_coor[-1],
         )
Ejemplo n.º 11
0
 def _analyze(self):
     if ("Atomic numbers"
             in self.fields) and ("Current cartesian coordinates"
                                  in self.fields):
         self.molecule = Molecule(
             self.fields["Atomic numbers"],
             numpy.reshape(self.fields["Current cartesian coordinates"],
                           (-1, 3)),
             self.title,
         )
Ejemplo n.º 12
0
 def _analyze(self):
     """Convert a few elementary fields into a molecule object"""
     if ("Atomic numbers"
             in self.fields) and ("Current cartesian coordinates"
                                  in self.fields):
         self.molecule = Molecule(
             self.fields["Atomic numbers"],
             np.reshape(self.fields["Current cartesian coordinates"],
                        (-1, 3)),
             self.title,
         )
Ejemplo n.º 13
0
def guess_geometry(graph, unitcell_active, unitcell, unitcell_reciproke):
    """Construct a molecular geometry based on a molecular graph.

       This routine does not require initial coordinates and will give a very
       rough picture of the initial geometry. Do not expect all details to be
       in perfect condition. A subsequent optimization with a more accurate
       level of theory is at least advisable.

       Arguments:
         graph  --  The molecular graph of the system
    """

    N = len(graph.numbers)
    from molmod.minimizer import Minimizer, NewtonGLineSearch

    ff = ToyFF(graph, unitcell_active, unitcell, unitcell_reciproke)
    x_init = numpy.random.normal(0,1,N*3)

    #  level 1 geometry optimization: graph based
    ff.dm_quad = 1.0
    minimizer = Minimizer(x_init, ff, NewtonGLineSearch, 1e-10, 1e-8, 2*N, 500, 50, do_gradient=True, verbose=False)
    x_init = minimizer.x

    #  level 2 geometry optimization: graph based + pauli repulsion
    ff.dm_quad = 1.0
    ff.dm_reci = 1.0
    minimizer = Minimizer(x_init, ff, NewtonGLineSearch, 1e-10, 1e-8, 2*N, 500, 50, do_gradient=True, verbose=False)
    x_init = minimizer.x

    # Add a little noise to avoid saddle points
    x_init += numpy.random.uniform(-0.01, 0.01, len(x_init))

    #  level 3 geometry optimization: bond lengths + pauli
    ff.dm_quad = 0.0
    ff.dm_reci = 0.2
    ff.bond_quad = 1.0
    minimizer = Minimizer(x_init, ff, NewtonGLineSearch, 1e-3, 1e-3, 2*N, 500, 50, do_gradient=True, verbose=False)
    x_init = minimizer.x

    #  level 4 geometry optimization: bond lengths + bending angles + pauli
    ff.bond_quad = 0.0
    ff.bond_hyper = 1.0
    ff.span_quad = 1.0
    minimizer = Minimizer(x_init, ff, NewtonGLineSearch, 1e-6, 1e-6, 2*N, 500, 50, do_gradient=True, verbose=False)
    x_init = minimizer.x

    x_opt = x_init

    mol = Molecule(graph.numbers, x_opt.reshape((N,3)))
    return mol
Ejemplo n.º 14
0
def read_cube_header(f):
    # skip the first two lines
    title = f.readline().strip()
    subtitle = f.readline().strip()

    def read_grid_line(line):
        """Read a grid line from the cube file"""
        words = line.split()
        return (int(words[0]),
                np.array([float(words[1]),
                          float(words[2]),
                          float(words[3])], float)
                # all coordinates in a cube file are in atomic units
                )

    # number of atoms and origin of the grid
    natom, origin = read_grid_line(f.readline())
    # numer of grid points in A direction and step vector A, and so on
    nrep0, axis0 = read_grid_line(f.readline())
    nrep1, axis1 = read_grid_line(f.readline())
    nrep2, axis2 = read_grid_line(f.readline())
    nrep = np.array([nrep0, nrep1, nrep2], int)
    axes = np.array([axis0, axis1, axis2])

    def read_coordinate_line(line):
        """Read an atom number and coordinate from the cube file"""
        words = line.split()
        return (int(words[0]), float(words[1]),
                np.array([float(words[2]),
                          float(words[3]),
                          float(words[4])], float)
                # all coordinates in a cube file are in atomic units
                )

    numbers = np.zeros(natom, int)
    nuclear_charges = np.zeros(natom, float)
    coordinates = np.zeros((natom, 3), float)
    for i in range(natom):
        numbers[i], nuclear_charges[i], coordinates[i] = read_coordinate_line(
            f.readline())

    molecule = Molecule(numbers, coordinates, title=title)
    return molecule, origin, axes, nrep, subtitle, nuclear_charges
Ejemplo n.º 15
0
 def get_molecule(self, index=0):
     return Molecule(self.numbers, self.geometries[index],
                     self.titles[index])
Ejemplo n.º 16
0
    def __next__(self):
        """Load the next molecule from the SDF file

           This method is part of the iterator protocol.
        """
        while True:
            title = next(self.f)
            if len(title) == 0:
                raise StopIteration
            else:
                title = title.strip()
            next(self.f)  # skip line
            next(self.f)  # skip empty line
            words = next(self.f).split()
            if len(words) < 2:
                raise FileFormatError(
                    "Expecting at least two numbers at fourth line.")
            try:
                num_atoms = int(words[0])
                num_bonds = int(words[1])
            except ValueError:
                raise FileFormatError(
                    "Expecting at least two numbers at fourth line.")

            numbers = np.zeros(num_atoms, int)
            coordinates = np.zeros((num_atoms, 3), float)
            for i in range(num_atoms):
                words = next(self.f).split()
                if len(words) < 4:
                    raise FileFormatError(
                        "Expecting at least four words on an atom line.")
                try:
                    coordinates[i, 0] = float(words[0])
                    coordinates[i, 1] = float(words[1])
                    coordinates[i, 2] = float(words[2])
                except ValueError:
                    raise FileFormatError(
                        "Coordinates must be floating point numbers.")
                atom = periodic[words[3]]
                if atom is None:
                    raise FileFormatError("Unrecognized atom symbol: %s" %
                                          words[3])
                numbers[i] = atom.number
            coordinates *= angstrom

            edges = []
            orders = np.zeros(num_bonds, int)
            for i in range(num_bonds):
                words = next(self.f).split()
                if len(words) < 3:
                    raise FileFormatError(
                        "Expecting at least three numbers on a bond line.")
                try:
                    edges.append((int(words[0]) - 1, int(words[1]) - 1))
                    orders[i] = int(words[2])
                except ValueError:
                    raise FileFormatError(
                        "Expecting at least three numbers on a bond line.")

            formal_charges = np.zeros(len(numbers), int)

            line = next(self.f)
            while line != "M  END\n":
                if line.startswith("M  CHG"):
                    words = line[6:].split(
                    )[1:]  # drop the first number which is the number of charges
                    i = 0
                    while i < len(words) - 1:
                        try:
                            formal_charges[int(words[i]) - 1] = int(words[i +
                                                                          1])
                        except ValueError:
                            raise FileFormatError(
                                "Expecting only integer formal charges.")
                        i += 2
                line = next(self.f)

            # Read on to the next molecule
            for line in self.f:
                if line == "$$$$\n":
                    break

            molecule = Molecule(numbers, coordinates, title)
            molecule.formal_charges = formal_charges
            molecule.formal_charges.setflags(write=False)
            molecule.graph = MolecularGraph(edges, numbers, orders)
            return molecule
Ejemplo n.º 17
0
def tune_geometry(graph, mol, unit_cell=None, verbose=False):
    """Fine tune a molecular geometry, starting from a (very) poor guess of
       the initial geometry.

       Do not expect all details to be in perfect condition. A subsequent
       optimization with a more accurate level of theory is at least advisable.

       Arguments:
        | ``graph``  --  The molecular graph of the system, see
                         :class:molmod.molecular_graphs.MolecularGraph
        | ``mol``  --  A :class:molmod.molecules.Molecule class with the initial
                       guess of the coordinates

       Optional argument:
        | ``unit_cell``  --  periodic boundry conditions, see
                             :class:`molmod.unit_cells.UnitCell`
        | ``verbose``  --  Show optimizer progress when True
    """

    N = len(graph.numbers)
    from molmod.minimizer import Minimizer, ConjugateGradient, \
        NewtonLineSearch, ConvergenceCondition, StopLossCondition

    search_direction = ConjugateGradient()
    line_search = NewtonLineSearch()
    convergence = ConvergenceCondition(grad_rms=1e-6, step_rms=1e-6)
    stop_loss = StopLossCondition(max_iter=500, fun_margin=1.0)

    ff = ToyFF(graph, unit_cell)
    x_init = mol.coordinates.ravel()

    #  level 3 geometry optimization: bond lengths + pauli
    ff.dm_reci = 0.2
    ff.bond_quad = 1.0
    minimizer = Minimizer(x_init,
                          ff,
                          search_direction,
                          line_search,
                          convergence,
                          stop_loss,
                          anagrad=True,
                          verbose=verbose)
    x_init = minimizer.x

    #  level 4 geometry optimization: bond lengths + bending angles + pauli
    ff.bond_quad = 0.0
    ff.bond_hyper = 1.0
    ff.span_quad = 1.0
    minimizer = Minimizer(x_init,
                          ff,
                          search_direction,
                          line_search,
                          convergence,
                          stop_loss,
                          anagrad=True,
                          verbose=verbose)
    x_init = minimizer.x

    x_opt = x_init

    mol = Molecule(graph.numbers, x_opt.reshape((N, 3)))
    return mol
Ejemplo n.º 18
0
 def stop_collecting(self):
     self.molecules.append(Molecule(self.current_atoms))
     del self.current_atoms
Ejemplo n.º 19
0
def random_dimer(molecule0, molecule1, thresholds, shoot_max):
    """Create a random dimer.

       molecule0 and molecule1 are placed in one reference frame at random
       relative positions. Interatomic distances are above the thresholds.
       Initially a dimer is created where one interatomic distance approximates
       the threshold value. Then the molecules are given an additional
       separation in the range [0, shoot_max].

       thresholds has the following format:
       {frozenset([atom_number1, atom_number2]): distance}
    """

    # apply a random rotation to molecule1
    center = np.zeros(3, float)
    angle = np.random.uniform(0, 2 * np.pi)
    axis = random_unit()
    rotation = Complete.about_axis(center, angle, axis)
    cor1 = np.dot(molecule1.coordinates, rotation.r)

    # select a random atom in each molecule
    atom0 = np.random.randint(len(molecule0.numbers))
    atom1 = np.random.randint(len(molecule1.numbers))

    # define a translation of molecule1 that brings both atoms in overlap
    delta = molecule0.coordinates[atom0] - cor1[atom1]
    cor1 += delta

    # define a random direction
    direction = random_unit()
    cor1 += 1 * direction

    # move molecule1 along this direction until all intermolecular atomic
    # distances are above the threshold values
    threshold_mat = np.zeros((len(molecule0.numbers), len(molecule1.numbers)),
                             float)
    distance_mat = np.zeros((len(molecule0.numbers), len(molecule1.numbers)),
                            float)
    for i1, n1 in enumerate(molecule0.numbers):
        for i2, n2 in enumerate(molecule1.numbers):
            threshold = thresholds.get(frozenset([n1, n2]))
            threshold_mat[i1, i2] = threshold**2
    while True:
        cor1 += 0.1 * direction
        distance_mat[:] = 0
        for i in 0, 1, 2:
            distance_mat += np.subtract.outer(molecule0.coordinates[:, i],
                                              cor1[:, i])**2
        if (distance_mat > threshold_mat).all():
            break

    # translate over a random distance [0, shoot] along the same direction
    # (if necessary repeat until no overlap is found)
    while True:
        cor1 += direction * np.random.uniform(0, shoot_max)
        distance_mat[:] = 0
        for i in 0, 1, 2:
            distance_mat += np.subtract.outer(molecule0.coordinates[:, i],
                                              cor1[:, i])**2
        if (distance_mat > threshold_mat).all():
            break

    # done
    dimer = Molecule(np.concatenate([molecule0.numbers, molecule1.numbers]),
                     np.concatenate([molecule0.coordinates, cor1]))
    dimer.direction = direction
    dimer.atom0 = atom0
    dimer.atom1 = atom1
    return dimer
Ejemplo n.º 20
0
def guess_geometry(graph, unit_cell=None, verbose=False):
    """Construct a molecular geometry based on a molecular graph.

       This routine does not require initial coordinates and will give a very
       rough picture of the initial geometry. Do not expect all details to be
       in perfect condition. A subsequent optimization with a more accurate
       level of theory is at least advisable.

       Argument:
        | ``graph``  --  The molecular graph of the system, see
                         :class:molmod.molecular_graphs.MolecularGraph

       Optional argument:
        | ``unit_cell``  --  periodic boundry conditions, see
                             :class:`molmod.unit_cells.UnitCell`
        | ``verbose``  --  Show optimizer progress when True
    """

    N = len(graph.numbers)
    from molmod.minimizer import Minimizer, ConjugateGradient, \
        NewtonLineSearch, ConvergenceCondition, StopLossCondition

    search_direction = ConjugateGradient()
    line_search = NewtonLineSearch()
    convergence = ConvergenceCondition(grad_rms=1e-6, step_rms=1e-6)
    stop_loss = StopLossCondition(max_iter=500, fun_margin=0.1)

    ff = ToyFF(graph, unit_cell)
    x_init = np.random.normal(0, 1, N * 3)

    #  level 1 geometry optimization: graph based
    ff.dm_quad = 1.0
    minimizer = Minimizer(x_init,
                          ff,
                          search_direction,
                          line_search,
                          convergence,
                          stop_loss,
                          anagrad=True,
                          verbose=verbose)
    x_init = minimizer.x

    #  level 2 geometry optimization: graph based + pauli repulsion
    ff.dm_quad = 1.0
    ff.dm_reci = 1.0
    minimizer = Minimizer(x_init,
                          ff,
                          search_direction,
                          line_search,
                          convergence,
                          stop_loss,
                          anagrad=True,
                          verbose=verbose)
    x_init = minimizer.x

    # Add a little noise to avoid saddle points
    x_init += np.random.uniform(-0.01, 0.01, len(x_init))

    #  level 3 geometry optimization: bond lengths + pauli
    ff.dm_quad = 0.0
    ff.dm_reci = 0.2
    ff.bond_quad = 1.0
    minimizer = Minimizer(x_init,
                          ff,
                          search_direction,
                          line_search,
                          convergence,
                          stop_loss,
                          anagrad=True,
                          verbose=verbose)
    x_init = minimizer.x

    #  level 4 geometry optimization: bond lengths + bending angles + pauli
    ff.bond_quad = 0.0
    ff.bond_hyper = 1.0
    ff.span_quad = 1.0
    minimizer = Minimizer(x_init,
                          ff,
                          search_direction,
                          line_search,
                          convergence,
                          stop_loss,
                          anagrad=True,
                          verbose=verbose)
    x_init = minimizer.x

    x_opt = x_init

    mol = Molecule(graph.numbers, x_opt.reshape((N, 3)))
    return mol