Skip to content

Commit e7df20b

Browse files
committed
resolved merge conflict
1 parent 5678d23 commit e7df20b

3 files changed

Lines changed: 85 additions & 2 deletions

File tree

rmgpy/data/kinetics/family.py

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,31 @@ def copy(self):
213213
other.is_forward = self.is_forward
214214

215215
return other
216+
217+
def check_if_spin_allowed(self):
218+
# get the combined spin for reactants and products
219+
reactants_combined_spin, products_combined_spin = self.calculate_combined_spin()
220+
# check if there are any matches for combined spin between reactants and products
221+
if reactants_combined_spin.intersection(products_combined_spin) != set([]):
222+
return True
223+
else:
224+
logging.debug(f"Reactants combined spin is {reactants_combined_spin}, but the products combined spin is {products_combined_spin}")
225+
return False
226+
227+
def calculate_combined_spin(self):
228+
if len(self.reactants) == 1:
229+
reactant_combined_spin = {self.reactants[0].multiplicity}
230+
elif len(self.reactants) == 2:
231+
reactant_combined_spin = set([self.reactants[0].multiplicity + self.reactants[1].multiplicity -1, np.abs(self.reactants[0].multiplicity-self.reactants[1].multiplicity)+1])
232+
else:
233+
return None
234+
if len(self.products) == 1:
235+
product_combined_spin = {self.products[0].multiplicity}
236+
elif len(self.products) == 2:
237+
product_combined_spin = set([self.products[0].multiplicity + self.products[1].multiplicity -1, np.abs(self.products[0].multiplicity-self.products[1].multiplicity)+1])
238+
else:
239+
return None
240+
return reactant_combined_spin, product_combined_spin
216241

217242
def apply_solvent_correction(self, solvent):
218243
"""
@@ -1678,7 +1703,7 @@ def is_molecule_forbidden(self, molecule):
16781703

16791704
return False
16801705

1681-
def _create_reaction(self, reactants, products, is_forward):
1706+
def _create_reaction(self, reactants, products, is_forward, check_spin = True):
16821707
"""
16831708
Create and return a new :class:`Reaction` object containing the
16841709
provided `reactants` and `products` as lists of :class:`Molecule`
@@ -1713,7 +1738,11 @@ def _create_reaction(self, reactants, products, is_forward):
17131738
for key, species_list in zip(['reactants', 'products'], [reaction.reactants, reaction.products]):
17141739
for species in species_list:
17151740
reaction.labeled_atoms[key] = dict(reaction.labeled_atoms[key], **species.get_all_labeled_atoms())
1716-
1741+
if check_spin:
1742+
if not reaction.check_if_spin_allowed():
1743+
logging.warn("Did not create the following reaction, which violates conservation of spin...")
1744+
logging.warn(str(reaction))
1745+
return None
17171746
return reaction
17181747

17191748
def _match_reactant_to_template(self, reactant, template_reactant):

rmgpy/molecule/molecule.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@
5959
from rmgpy.molecule.kekulize import kekulize
6060
from rmgpy.molecule.pathfinder import find_shortest_path
6161
from rmgpy.molecule.fragment import CuttingLabel
62+
from rmgpy.molecule.util import generate_closed_shell_singlet, generate_singlet_diradicals
6263

6364
################################################################################
6465

@@ -3005,6 +3006,20 @@ def get_desorbed_molecules(self):
30053006
logging.debug("After removing from surface:\n" + desorbed_molecule.to_adjacency_list())
30063007

30073008
return desorbed_molecules
3009+
def update_to_closed_shell_singlet(self):
3010+
for i in range(len(self.atoms)):
3011+
self.atoms[i].id = i
3012+
assert self.multiplicity == 1 and self.get_radical_count()>0
3013+
radical_center_ids = [x.id for x in self.atoms if x.radical_electrons > 0]
3014+
# remove radicals from radical centers (2)
3015+
for radical_center_id in radical_center_ids:
3016+
self.atoms[radical_center_id].decrement_radical()
3017+
# add removed radicals (2) to one of the radical sites as a lone pair (1)
3018+
self.atoms[radical_center_ids[0]].increment_lone_pairs()
3019+
# pick the best resonance structure
3020+
self.generate_resonance_structures()
3021+
self.reactive = True
3022+
30083023

30093024
# this variable is used to name atom IDs so that there are as few conflicts by
30103025
# using the entire space of integer objects

rmgpy/molecule/util.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,3 +179,42 @@ def swap(to_be_swapped, sample):
179179
new_partner = (to_be_swapped - sample).pop()
180180

181181
return central, original, new_partner
182+
183+
def generate_closed_shell_singlet(m: Molecule):
184+
for i in range(len(m.atoms)):
185+
m.atoms[i].id = i
186+
assert m.multiplicity == 1 and m.get_radical_count()>0
187+
radical_center_ids = [x.id for x in m.atoms if x.radical_electrons > 0]
188+
# remove radicals from radical centers (2)
189+
for radical_center_id in radical_center_ids:
190+
m.atoms[radical_center_id].decrement_radical()
191+
# add removed radicals (2) to one of the radical sites as a lone pair (1)
192+
m.atoms[radical_center_ids[0]].increment_lone_pairs()
193+
# pick the best resonance structure
194+
print([x.smiles for x in m.generate_resonance_structures()])
195+
return m.generate_resonance_structures()[0]
196+
197+
def generate_singlet_diradicals(m: Molecule):
198+
for i in range(len(m.atoms)):
199+
m.atoms[i].id = i
200+
201+
singlet_diradicals = []
202+
for edge in m.get_all_edges():
203+
204+
M = m.copy(deep=True)
205+
if edge.get_order_num() > 1: # find a pi bond
206+
atom1_id = edge.atom1.id
207+
atom2_id = edge.atom2.id
208+
M.atoms[atom1_id].increment_radical() # add a radical to each atom of the pi bond
209+
M.atoms[atom2_id].increment_radical()
210+
M.get_bond(M.atoms[atom1_id], M.atoms[atom2_id]).decrement_order() # remove 1 pi bond
211+
potential_singlet_diradicals = M.generate_resonance_structures() # generate resonance structures
212+
213+
for potential_singlet_diradical in potential_singlet_diradicals: # find all resonance structures with non-neighboring radical sites
214+
radical_center_ids = sorted([x.id for x in potential_singlet_diradical.atoms if x.radical_electrons==1])
215+
potential_singlet_diradical_edges = potential_singlet_diradical.get_all_edges()
216+
potential_singlet_diradical_edge_ids = [sorted([x.atom1.id, x.atom2.id]) for x in potential_singlet_diradical_edges]
217+
if radical_center_ids not in potential_singlet_diradical_edge_ids:
218+
if potential_singlet_diradical not in singlet_diradicals:
219+
singlet_diradicals.append(potential_singlet_diradical)
220+
return singlet_diradicals

0 commit comments

Comments
 (0)