@@ -1935,11 +1935,7 @@ def _scissors(self,
19351935 added_radical = list ()
19361936 for mol , label in zip ([mol1 , mol2 ], [label1 , label2 ]):
19371937 for atom in mol .atoms :
1938- theoretical_charge = elements .PeriodicSystem .valence_electrons [atom .symbol ] \
1939- - atom .get_total_bond_order () \
1940- - atom .radical_electrons - \
1941- 2 * atom .lone_pairs
1942- if theoretical_charge == atom .charge + 1 :
1938+ if get_atom_theoretical_charge (atom ) == atom .charge + 1 :
19431939 # we're missing a radical electron on this atom
19441940 if label not in added_radical or label == 'H' :
19451941 atom .radical_electrons += 1
@@ -2708,3 +2704,64 @@ def split_mol(mol: Molecule) -> Tuple[List[Molecule], List[List[int]]]:
27082704 molecules .append (Molecule (atoms = [mol .atoms [index ] for index in frag_indices ]))
27092705 fragments .append (frag_indices )
27102706 return molecules , fragments
2707+
2708+
2709+ def get_atom_theoretical_charge (atom : Atom ) -> float :
2710+ """
2711+ Get the theoretical charge of an atom based on its electronic properties.
2712+
2713+ Args:
2714+ atom (Atom): The atom to check.
2715+
2716+ Returns:
2717+ float: The theoretical charge of the atom.
2718+ """
2719+ return elements .PeriodicSystem .valence_electrons [atom .symbol ] \
2720+ - atom .get_total_bond_order () \
2721+ - atom .radical_electrons - \
2722+ 2 * atom .lone_pairs
2723+
2724+
2725+ def fix_mol_electronic_configuration (mol : Optional [Molecule ] = None ) -> Optional [Molecule ]:
2726+ """
2727+ Fix the electronic configuration (number of radicals, lone pairs, and formal charges) of a Molecule object
2728+ that was perceived from xyz. Assumes the multiplicity attribute of the given molecule is correct.
2729+
2730+ Args:
2731+ mol (Molecule, optional): The molecule to fix.
2732+
2733+ Returns:
2734+ Molecule: The fixed molecule.
2735+ """
2736+ if mol is None :
2737+ return None
2738+ multiplicity = mol .multiplicity
2739+ n_radicals = mol .get_radical_count ()
2740+ if n_radicals + 1 > mol .multiplicity :
2741+ # Find adjacent atoms with opposite-spin radicals, and pair the radicals up into a bond.
2742+ mols = mol .generate_resonance_structures (keep_isomorphic = False , filter_structures = True , save_order = True )
2743+ for structure in mols + [mol ]:
2744+ structure .multiplicity = multiplicity
2745+ visited = list ()
2746+ updated = False
2747+ for mol_1 in mols :
2748+ mol_1 .multiplicity = mol .multiplicity
2749+ for atom_1 in mol_1 .atoms :
2750+ if atom_1 not in visited and atom_1 .radical_electrons >= 1 :
2751+ for atom_2 , bond in atom_1 .edges .items ():
2752+ if atom_2 .radical_electrons >= 1 :
2753+ atom_1 .radical_electrons -= 1
2754+ atom_2 .radical_electrons -= 1
2755+ bond .order += 1
2756+ visited .append (atom_2 )
2757+ updated = True
2758+ break
2759+ visited .append (atom_1 )
2760+ # Update formal charges.
2761+ for atom in mol_1 .atoms :
2762+ theoretical_charge = get_atom_theoretical_charge (atom )
2763+ if theoretical_charge != atom .charge :
2764+ atom .charge = theoretical_charge
2765+ if updated :
2766+ return mol_1
2767+ return mols [0 ]
0 commit comments