Esempio n. 1
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)
Esempio n. 2
0
 def get_system(self, name):
     if name == "chabazite_octane":
         molecule = XYZFile("input/chabazite_octane.xyz").get_molecule()
         unit_cell = UnitCell(
             numpy.array([
                 [14.767, 0, 0],
                 [0, 23.686, 0],
                 [0, 0, 13.675],
             ])*angstrom,
             numpy.array([True, True, True], bool),
         )
         molecular_graph = MolecularGraph.from_geometry(molecule)
         return molecule.coordinates, molecular_graph, unit_cell
     elif name == "sodalite_ethane":
         molecule = XYZFile("input/sodalite_ethane.xyz").get_molecule()
         unit_cell = UnitCell(
             numpy.array([
                 [8.956, 0, 0],
                 [0, 8.956, 0],
                 [0, 0, 8.956],
             ])*angstrom,
             numpy.array([True, True, True], bool),
         )
         molecular_graph = MolecularGraph.from_geometry(molecule)
         return molecule.coordinates, molecular_graph, unit_cell
     else:
         raise Exception("Unknown system.")
Esempio n. 3
0
 def _check_topology(self):
     '''
        Check wether all topology information (bonds, bends, dihedrals,
        out-of-plane patterns and neighborlist) is present and complete if
        necessary.
     '''
     assert self.numbers is not None
     if self.bonds is None:
         molecule = Molecule(self.numbers, coordinates=self.ref.coords)
         graph = MolecularGraph.from_geometry(molecule)
         psf = PSFFile()
         psf.add_molecule(molecule)
         self.bonds = np.array(psf.bonds)
         self.bends = np.array(psf.bends)
         self.diheds = np.array(psf.dihedrals)
         self.opdists = find_opdist_patterns(graph)
         self.nlist = graph.neighbors
     else:
         graph = MolecularGraph(self.bonds, self.numbers)
         psf = PSFFile()
         psf.add_molecular_graph(graph)
         if self.bends is None:
             self.bends = np.array(psf.bends)
         if self.diheds is None:
             self.diheds = np.array(psf.dihedrals)
         if self.opdists is None:
             self.opdists = find_opdist_patterns(graph)
         if self.nlist is None:
             self.nlist = graph.neighbors
Esempio n. 4
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
Esempio n. 5
0
 def add_molecule(self,
                  molecule,
                  atom_types=None,
                  charges=None,
                  split=True):
     molecular_graph = MolecularGraph.from_geometry(molecule)
     self.add_molecular_graph(molecular_graph, atom_types, charges, split)
Esempio n. 6
0
def create_molecular_graph(selected_nodes, parent=None):
    molecule = create_molecule(selected_nodes, parent)

    atom_indexes = dict((atom,i) for i,atom in enumerate(molecule.atoms))
    bonds = list(
        bond for bond in yield_bonds(selected_nodes)
        if bond.children[0].target in atom_indexes and
           bond.children[1].target in atom_indexes
    )
    pairs = [(
        atom_indexes[bond.children[0].target],
        atom_indexes[bond.children[1].target],
    ) for bond in bonds]

    graph = MolecularGraph(pairs, molecule.numbers)
    graph.bonds = bonds
    graph.molecule = molecule
    return graph
Esempio n. 7
0
    def set_default_graph(self):
        """Set self.graph to the default graph.

           This method is equivalent to::

              mol.graph = MolecularGraph.from_geometry(mol)

           with the default options, and only works if the graph object is not
           present yet.
           See :meth:`molmod.molecular_graphs.MolecularGraph.from_geometry`
           for more fine-grained control over the assignment of bonds.
        """
        self.graph = MolecularGraph.from_geometry(self)
Esempio n. 8
0
    def set_default_graph(self):
        """Set self.graph to the default graph.

           This method is equivalent to::

              mol.graph = MolecularGraph.from_geometry(mol)

           with the default options, and only works if the graph object is not
           present yet.
           See :meth:`molmod.molecular_graphs.MolecularGraph.from_geometry`
           for more fine-grained control over the assignment of bonds.
        """
        self.graph = MolecularGraph.from_geometry(self)
Esempio n. 9
0
    def compute_rotsym(self, threshold=1e-3*angstrom):
        """Compute the rotational symmetry number.

           Optional argument:
            | ``threshold``  --  only when a rotation results in an rmsd below the given
                                 threshold, the rotation is considered to transform the
                                 molecule onto itself.
        """
        # Generate a graph with a more permissive threshold for bond lengths:
        # (is convenient in case of transition state geometries)
        graph = MolecularGraph.from_geometry(self, scaling=1.5)
        try:
            return compute_rotsym(self, graph, threshold)
        except ValueError:
            raise ValueError("The rotational symmetry number can only be computed when the graph is fully connected.")
Esempio n. 10
0
 def test_consistency(self):
     molecules = [
         XYZFile("input/cyclopentane.xyz").get_molecule(),
         XYZFile("input/funny.xyz").get_molecule(),
     ]
     for m in molecules:
         m.graph = MolecularGraph.from_geometry(m)
     dump_cml("output/tmp.cml", molecules)
     check = load_cml("output/tmp.cml")
     for m1, m2 in zip(molecules, check):
         self.assertEqual(m1.title, m2.title)
         self.assert_((m1.numbers==m2.numbers).all())
         self.assert_((m1.coordinates==m2.coordinates).all())
         self.assertEqual(m1.graph.num_nodes, m2.graph.num_nodes)
         self.assertEqual(set(m1.graph.pairs), set(m2.graph.pairs))
Esempio n. 11
0
    def compute_rotsym(self, threshold=1e-3*angstrom):
        """Compute the rotational symmetry number.

           Optional argument:
            | ``threshold``  --  only when a rotation results in an rmsd below the given
                                 threshold, the rotation is considered to transform the
                                 molecule onto itself.
        """
        # Generate a graph with a more permissive threshold for bond lengths:
        # (is convenient in case of transition state geometries)
        graph = MolecularGraph.from_geometry(self, scaling=1.5)
        try:
            return compute_rotsym(self, graph, threshold)
        except ValueError:
            raise ValueError("The rotational symmetry number can only be computed when the graph is fully connected.")
Esempio n. 12
0
    def add_molecule(self, molecule, atom_types=None, charges=None, split=True):
        """Add the graph of the molecule to the data structure

           The molecular graph is estimated from the molecular geometry based on
           interatomic distances.

           Argument:
            | ``molecule``  --  a Molecule instance

           Optional arguments:
            | ``atom_types``  --  a list with atom type strings
            | ``charges``  --  The net atom charges
            | ``split``  --  When True, the molecule is split into disconnected
                             molecules [default=True]
        """
        molecular_graph = MolecularGraph.from_geometry(molecule)
        self.add_molecular_graph(molecular_graph, atom_types, charges, split, molecule)
Esempio n. 13
0
    def add_molecule(self,
                     molecule,
                     atom_types=None,
                     charges=None,
                     split=True):
        """Add the graph of the molecule to the data structure

           The molecular graph is estimated from the molecular geometry based on
           interatomic distances.

           Argument:
            | ``molecule``  --  a Molecule instance

           Optional arguments:
            | ``atom_types``  --  a list with atom type strings
            | ``charges``  --  The net atom charges
            | ``split``  --  When True, the molecule is split into disconnected
                             molecules [default=True]
        """
        molecular_graph = MolecularGraph.from_geometry(molecule)
        self.add_molecular_graph(molecular_graph, atom_types, charges, split,
                                 molecule)
Esempio n. 14
0
def all_lone_pairs(molecule, singles=[7], doubles=[8], angle=1.910):
    """
    Returns a list with pairs (index, lone), where index indicates the
    atom and lone is a relative vector with unit length pointing along
    a lone pair on that atom.

    Arguments:
    molecule -- A molecule for which the lone pairs should be calculated.
    singles -- A list of atom number which should be treated like nitrogen.
    doubles -- A list of atom numbers which should be treated like oxygen.
    angle -- The angle between two lone pairs on the same atom. (in rad)

    Returns:
    lone_pairs -- a list with pairs (index, lone)
    """

    result = []
    mgraph = MolecularGraph(molecule)

    for index, (number, coordinate) in enumerate(
            zip(molecule.numbers, molecule.coordinates)):
        if number in singles:
            neighbors = mgraph.neighbors[index]
            result.append(
                (index,
                 lone_pair_1(molecule.coordinates[neighbors[0]] - coordinate,
                             molecule.coordinates[neighbors[1]] - coordinate,
                             molecule.coordinates[neighbors[2]] - coordinate)))
        elif number in doubles:
            neighbors = mgraph.neighbors[index]
            lone1, lone2 = lone_pair_2(
                molecule.coordinates[neighbors[0]] - coordinate,
                molecule.coordinates[neighbors[1]] - coordinate, angle)
            result.append((index, lone1))
            result.append((index, lone2))

    return result
Esempio n. 15
0
 def get_molecular_graph(self):
     """Return the molecular graph represented by the data structure"""
     return MolecularGraph(self.bonds, self.numbers)
Esempio n. 16
0
 def yield_test_molecules(self):
     for filename in ["tpa.xyz", "water.xyz", "thf_single.xyz"]:
         molecule = XYZFile(os.path.join("input", filename)).get_molecule()
         molecule.filename = filename
         graph = MolecularGraph.from_geometry(molecule)
         yield molecule, graph
Esempio n. 17
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
Esempio n. 18
0
CC30A = CritAnd(HasAtomNumber(6), HasNeighborNumbers(6,6,6,6))
CC31A = CritAnd(HasAtomNumber(6), HasNeighborNumbers(6,6,6,1))
CC32A = CritAnd(HasAtomNumber(6), HasNeighborNumbers(6,6,1,1))
CC33A = CritAnd(HasAtomNumber(6), HasNeighborNumbers(6,1,1,1))

atom_filters = {
    "CC30A": CC30A,
    "CC31A": CC31A,
    "CC32A": CC32A,
    "CC33A": CC33A,
    "HCA1": CritAnd(HasAtomNumber(1), HasNeighbors(CC31A)),
    "HCA2": CritAnd(HasAtomNumber(1), HasNeighbors(CC32A)),
    "HCA3": CritAnd(HasAtomNumber(1), HasNeighbors(CC33A)),
}

def get_atom_type(index, graph):
    for atom_type, atom_filter in atom_filters.iteritems():
        if atom_filter(index, graph):
            return atom_type
    raise ValueError("Unrecognized atom (index %i)." % index)

args = sys.argv[1:]

molecule = XYZFile(args[0]).get_molecule()
graph = MolecularGraph.from_geometry(molecule)
atom_types = [get_atom_type(index, graph) for index in xrange(molecule.size)]

psf = PSFFile()
psf.add_molecular_graph(graph, atom_types=atom_types)
psf.write_to_file(args[0].replace(".xyz", ".psf"))
Esempio n. 19
0
CC30A = CritAnd(HasAtomNumber(6), HasNeighborNumbers(6,6,6,6))
CC31A = CritAnd(HasAtomNumber(6), HasNeighborNumbers(6,6,6,1))
CC32A = CritAnd(HasAtomNumber(6), HasNeighborNumbers(6,6,1,1))
CC33A = CritAnd(HasAtomNumber(6), HasNeighborNumbers(6,1,1,1))

atom_filters = {
    "CC30A": CC30A,
    "CC31A": CC31A,
    "CC32A": CC32A,
    "CC33A": CC33A,
    "HCA1": CritAnd(HasAtomNumber(1), HasNeighbors(CC31A)),
    "HCA2": CritAnd(HasAtomNumber(1), HasNeighbors(CC32A)),
    "HCA3": CritAnd(HasAtomNumber(1), HasNeighbors(CC33A)),
}

def get_atom_type(index, graph):
    for atom_type, atom_filter in atom_filters.items():
        if atom_filter(index, graph):
            return atom_type
    raise ValueError("Unrecognized atom (index %i)." % index)

args = sys.argv[1:]

molecule = XYZFile(args[0]).get_molecule()
graph = MolecularGraph.from_geometry(molecule)
atom_types = [get_atom_type(index, graph) for index in range(molecule.size)]

psf = PSFFile()
psf.add_molecular_graph(graph, atom_types=atom_types)
psf.write_to_file(args[0].replace(".xyz", ".psf"))
Esempio n. 20
0
 def test_graph(self):
     molecules = self.get_molecules()
     for molecule in molecules:
         molecule.graph = MolecularGraph.from_geometry(molecule)
         molecule.descriptor = DistanceDescriptor(molecule.graph)
     self.do_test(molecules, margin=0.2, cutoff=10.0)
Esempio n. 21
0
 def add_molecule(self, molecule, atom_types=None, charges=None, split=True):
     molecular_graph = MolecularGraph.from_geometry(molecule)
     self.add_molecular_graph(molecular_graph, atom_types, charges, split)
Esempio n. 22
0
 def get_molecular_graph(self, labels=None):
     return MolecularGraph(self.bonds, self.numbers)
Esempio n. 23
0
 def yield_test_molecules(self):
     for filename in ["tpa.xyz", "water.xyz", "thf_single.xyz"]:
         molecule = XYZFile(os.path.join("input", filename)).get_molecule()
         molecule.filename = filename
         graph = MolecularGraph.from_geometry(molecule)
         yield molecule, graph