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)
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)
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