Esempio n. 1
0
    def get_resonance_hybrid(self):
        """
        Returns a molecule object with bond orders that are the average 
        of all the resonance structures.
        """
        # get labeled resonance isomers
        self.generate_resonance_structures(keep_isomorphic=True)

        # only consider reactive molecules as representative structures
        molecules = [mol for mol in self.molecule if mol.reactive]

        # return if no resonance
        if len(molecules) == 1:
            return molecules[0]

        # create a sorted list of atom objects for each resonance structure
        cython.declare(
            atomsFromStructures=list,
            oldAtoms=list,
            newAtoms=list,
            numResonanceStructures=cython.short,
            structureNum=cython.short,
            oldBondOrder=cython.float,
            index1=cython.short,
            index2=cython.short,
            newMol=Molecule,
            oldMol=Molecule,
            atom1=Atom,
            atom2=Atom,
            bond=Bond,
            atoms=list,
        )

        atoms_from_structures = []
        for new_mol in molecules:
            new_mol.atoms.sort(key=lambda atom: atom.id)
            atoms_from_structures.append(new_mol.atoms)

        num_resonance_structures = len(molecules)

        # make original structure with no bonds
        new_mol = Molecule()
        original_atoms = atoms_from_structures[0]
        for atom1 in original_atoms:
            atom = new_mol.add_atom(Atom(atom1.element))
            atom.id = atom1.id

        new_atoms = new_mol.atoms

        # initialize bonds to zero order
        for index1, atom1 in enumerate(original_atoms):
            for atom2 in atom1.bonds:
                index2 = original_atoms.index(atom2)
                bond = Bond(new_atoms[index1], new_atoms[index2], 0)
                new_mol.add_bond(bond)

        # set bonds to the proper value
        for structureNum, oldMol in enumerate(molecules):
            old_atoms = atoms_from_structures[structureNum]

            for index1, atom1 in enumerate(old_atoms):
                # make bond orders average of resonance structures
                for atom2 in atom1.bonds:
                    index2 = old_atoms.index(atom2)

                    new_bond = new_mol.get_bond(new_atoms[index1],
                                                new_atoms[index2])
                    old_bond_order = oldMol.get_bond(
                        old_atoms[index1], old_atoms[index2]).get_order_num()
                    new_bond.apply_action(
                        ('CHANGE_BOND', None,
                         old_bond_order / num_resonance_structures / 2))
                # set radicals in resonance hybrid to maximum of all structures
                if atom1.radical_electrons > 0:
                    new_atoms[index1].radical_electrons = max(
                        atom1.radical_electrons,
                        new_atoms[index1].radical_electrons)
        new_mol.update_atomtypes(log_species=False, raise_exception=False)
        return new_mol