Example #1
0
 def penalty_for_o4tc_test(self):
     """Test that an O4tc atomtype with octet 8 gets penalized in the electronegativity heuristic"""
     adj = """
     1 S u0 p1 c0 {2,S} {3,T}
     2 O u0 p3 c-1 {1,S}
     3 O u0 p1 c+1 {1,T}
     """
     mol = Molecule().from_adjacency_list(adj)
     octet_deviation = get_octet_deviation(mol)
     self.assertEqual(octet_deviation, 0)
     self.assertEqual(mol.vertices[2].atomtype.label, 'O4tc')
     mol_list = generate_resonance_structures(mol)
     self.assertEqual(len(mol_list), 2)
     for mol in mol_list:
         if mol.reactive:
             for atom in mol.vertices:
                 self.assertTrue(atom.charge == 0)
 def penalty_for_O4tc_test(self):
     """Test that an O4tc atomType with octet 8 gets penalized in the electronegativity heuristic"""
     adj = """
     1 S u0 p1 c0 {2,S} {3,T}
     2 O u0 p3 c-1 {1,S}
     3 O u0 p1 c+1 {1,T}
     """
     mol = Molecule().fromAdjacencyList(adj)
     octet_deviation = get_octet_deviation(mol)
     self.assertEqual(octet_deviation, 0)
     self.assertEqual(mol.vertices[2].atomType.label, 'O4tc')
     mol_list = generate_resonance_structures(mol)
     self.assertEqual(len(mol_list), 2)
     for mol in mol_list:
         if mol.reactive:
             for atom in mol.vertices:
                 self.assertTrue(atom.charge == 0)
Example #3
0
 def penalty_for_s_triple_s_test(self):
     """Test that an S#S substructure in a molecule gets penalized in the octet deviation score"""
     adj = """
     1  C u0 p0 c0 {3,S} {5,S} {6,S} {7,S}
     2  C u0 p0 c0 {4,S} {8,S} {9,S} {10,S}
     3  S u0 p0 c0 {1,S} {4,T} {11,D}
     4  S u0 p1 c0 {2,S} {3,T}
     5  H u0 p0 c0 {1,S}
     6  H u0 p0 c0 {1,S}
     7  H u0 p0 c0 {1,S}
     8  H u0 p0 c0 {2,S}
     9  H u0 p0 c0 {2,S}
     10 H u0 p0 c0 {2,S}
     11 O u0 p2 c0 {3,D}
     """
     mol = Molecule().from_adjacency_list(adj)
     octet_deviation = get_octet_deviation(mol)
     self.assertEqual(octet_deviation, 1.0)
 def penalty_for_s_triple_s_test(self):
     """Test that an S#S substructure in a molecule gets penalized in the octet deviation score"""
     adj = """
     1  C u0 p0 c0 {3,S} {5,S} {6,S} {7,S}
     2  C u0 p0 c0 {4,S} {8,S} {9,S} {10,S}
     3  S u0 p0 c0 {1,S} {4,T} {11,D}
     4  S u0 p1 c0 {2,S} {3,T}
     5  H u0 p0 c0 {1,S}
     6  H u0 p0 c0 {1,S}
     7  H u0 p0 c0 {1,S}
     8  H u0 p0 c0 {2,S}
     9  H u0 p0 c0 {2,S}
     10 H u0 p0 c0 {2,S}
     11 O u0 p2 c0 {3,D}
     """
     mol = Molecule().fromAdjacencyList(adj)
     octet_deviation = get_octet_deviation(mol)
     self.assertEqual(octet_deviation, 3.0)
Example #5
0
def _generate_resonance_structures(mol_list, method_list, keep_isomorphic=False, copy=False, filter_structures=True):
    """
    Iteratively generate all resonance structures for a list of starting molecules using the specified methods.

    Args:
        mol_list             starting list of molecules
        method_list          list of resonance structure algorithms
        keep_isomorphic      if False, removes any structures that give is_isomorphic=True (default)
                            if True, only remove structures that give is_identical=True
        copy                if False, append new resonance structures to input list (default)
                            if True, make a new list with all of the resonance structures
    """
    cython.declare(index=cython.int, molecule=Molecule, new_mol_list=list, new_mol=Molecule, mol=Molecule)

    if copy:
        # Make a copy of the list so we don't modify the input list
        mol_list = mol_list[:]

    min_octet_deviation = min(filtration.get_octet_deviation_list(mol_list))
    min_charge_span = min(filtration.get_charge_span_list(mol_list))

    # Iterate over resonance structures
    index = 0
    while index < len(mol_list):
        molecule = mol_list[index]
        new_mol_list = []

        # On-the-fly filtration: Extend methods only for molecule that don't deviate too much from the octet rule
        # (a +2 distance from the minimal deviation is used, octet deviations per species are in increments of 2)
        # Sometimes rearranging the structure requires an additional higher charge span structure, so allow
        # structures with a +1 higher charge span compared to the minimum, e.g., [O-]S#S[N+]#N
        # This is run by default even if filter_structures=False.
        octet_deviation = filtration.get_octet_deviation(molecule)
        charge_span = molecule.get_charge_span()
        if octet_deviation <= min_octet_deviation + 2 and charge_span <= min_charge_span + 1:
            for method in method_list:
                new_mol_list.extend(method(molecule))
            if octet_deviation < min_octet_deviation:
                # update min_octet_deviation to make this criterion tighter
                min_octet_deviation = octet_deviation
            if charge_span < min_charge_span:
                # update min_charge_span to make this criterion tighter
                min_charge_span = charge_span

        for new_mol in new_mol_list:
            # Append to structure list if unique
            for mol in mol_list:
                if not keep_isomorphic and mol.is_isomorphic(new_mol):
                    break
                elif keep_isomorphic and mol.is_identical(new_mol):
                    break
            else:
                mol_list.append(new_mol)

        # Move to the next resonance structure
        index += 1

    # check net charge
    for mol in mol_list:
        if mol.get_net_charge() != 0:
            raise ResonanceError('Resonance generation gave a net charged molecule:\n{0}'
                                 'Ions are not yet supported in RMG.'.format(
                mol.to_adjacency_list()))

    return mol_list