Skip to content

Commit cdfc487

Browse files
committed
fix cython compilation errors (0.23 -> 3.n), SEE EXTENDED!!
here are all the solutions that were implemented: - in a couple places we were implicitly casting a double to a numpy float, now need to explicitly grad the _real_ part of the double - Cython does not allow nested function declaration inside cpdef functions, move all of these outside of their parent functions or redefine them to be purely functional where practical - similar to the above, lambda function are no longer allowed - get the same treatment. what's different here is that usually we are using lambda in sorting calls, so we can replace these with operator.itemgetter or attrgetter, where relevant. this also involves re-writing a couple reduce calls, which also used lambda - modern cython does not allow re-declaring existing Cython variables (in previous versions this was a warning I think), so I just remove these where needed. (btw Cython is super cool, actually points out both of the declaration so that you can delete one) i made these fixes while listening to The Metal by Tenacious D, Talk Too Much by Renee Rapp, BEST INTEREST by Tyler, The Creator (love the bass line), mos thoser by food house, and Doritos & Fritos by 100 Gecs
1 parent 6cb89a8 commit cdfc487

7 files changed

Lines changed: 168 additions & 163 deletions

File tree

rmgpy/kinetics/kineticsdata.pyx

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -249,9 +249,8 @@ cdef class PDepKineticsData(PDepKineticsModel):
249249
Plow = Pdata[j]
250250
Phigh = Pdata[j + 1]
251251
if Plow <= P and P <= Phigh:
252-
klow = kdata[i, j] * (kdata[i + 1, j] / kdata[i, j]) ** ((T - Tlow) / (Thigh - Tlow))
253-
khigh = kdata[i, j + 1] * (kdata[i + 1, j + 1] / kdata[i, j + 1]) ** (
254-
(T - Tlow) / (Thigh - Tlow))
252+
klow = kdata[i, j] * (kdata[i + 1, j] / kdata[i, j]) ** ((T - Tlow) / (Thigh - Tlow)).real
253+
khigh = kdata[i, j + 1] * (kdata[i + 1, j + 1] / kdata[i, j + 1]) ** ((T - Tlow) / (Thigh - Tlow)).real
255254
k = klow * (khigh / klow) ** (log(P / Plow) / log(Phigh / Plow))
256255
break
257256

rmgpy/molecule/group.py

Lines changed: 84 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,91 @@
4646
from rmgpy.molecule.graph import Vertex, Edge, Graph
4747
from rmgpy.molecule.fragment import CuttingLabel
4848

49+
# helper functions
50+
# these were originall nested inside the indicated parent function, but when we upgraded to
51+
# Cython 3 this was no longer allowed - thus, they now live here.
4952

50-
################################################################################
53+
# add_implicit_benzene
54+
def check_set(super_list, sub_list):
55+
"""
56+
Args:
57+
super_list: list to check if superset of partList
58+
sub_list: list to check if subset of superList
59+
60+
Returns: Boolean to see if super_list is a superset of sub_list
61+
62+
"""
63+
super_set = set(super_list)
64+
sub_set = set(sub_list)
65+
return super_set.issuperset(sub_set)
66+
67+
def add_cb_atom_to_ring(ring, cb_atom):
68+
"""
69+
Every 'Cb' atom belongs in exactly one benzene ring. This function checks
70+
adds the cb_atom to the ring (in connectivity order) if the cb_atom is connected
71+
to any the last or first atom in the partial ring.
72+
73+
Args:
74+
ring: list of :class:GroupAtoms representing a partial ring to merge
75+
cb_atom: :class:GroupAtom with atomtype 'Cb'
76+
77+
Returns: If cb_atom connects to the beginning or end of ring, returns a
78+
new list of the merged ring, otherwise an empty list
79+
80+
"""
81+
82+
merged_ring = []
83+
# ring already complete
84+
if len(ring) == 6: return merged_ring
85+
for atom2, bond12 in cb_atom.bonds.items():
86+
if bond12.is_benzene():
87+
if atom2 is ring[-1]:
88+
merged_ring = ring + [cb_atom]
89+
elif atom2 is ring[0]:
90+
merged_ring = [cb_atom] + ring
91+
92+
return merged_ring
93+
94+
def merge_overlapping_benzene_rings(ring1, ring2, od):
95+
"""
96+
The input arguments of rings are always in the order that the atoms appear
97+
inside the ring. That is, each atom is connected to the ones adjacent on the
98+
list.
99+
100+
Args:
101+
ring1: list of :class:GroupAtoms representing first partial ring to merge
102+
ring2: list :class:GroupAtoms representing second partial ring to merge
103+
od: in for overlap distance
104+
105+
This function tries to see if the beginning or ends of each list have the
106+
same atom objects, i.e the two part rings should be merged together.
107+
108+
Returns: If rings are mergable, returns a new list of the merged ring, otherwise
109+
an empty list
110+
111+
"""
112+
new_ring = []
113+
# ring already complete
114+
if len(ring1) == 6 or len(ring2) == 6: return new_ring
115+
116+
# start of ring1 matches end of ring2
117+
match_list1 = [x1 is x2 for x1, x2 in zip(ring1[-od:], ring2[:od])]
118+
# end of ring1 matches end of ring2
119+
match_list2 = [x1 is x2 for x1, x2 in zip(ring1[-od:], ring2[:od - 1:-1])]
120+
# start of ring1 matches end of ring2
121+
match_list3 = [x1 is x2 for x1, x2 in zip(ring1[:od], ring2[-od:])]
122+
# start of ring1 matches start of ring2
123+
match_list4 = [x1 is x2 for x1, x2 in zip(ring1[:od], ring2[od::-1])]
124+
if False not in match_list1:
125+
new_ring = ring1 + ring2[od:]
126+
elif False not in match_list2:
127+
new_ring = ring1 + ring2[-od - 1::-1]
128+
elif False not in match_list3:
129+
new_ring = ring2[:-od] + ring1
130+
elif False not in match_list4:
131+
new_ring = ring2[:od - 1:-1] + ring1
132+
133+
return new_ring
51134

52135
class GroupAtom(Vertex):
53136
"""
@@ -2531,89 +2614,6 @@ def add_implicit_benzene(self):
25312614
# Note that atomtypes like N5bd are mostly referred to as Cb in this code,
25322615
# which was first written for just carbon.
25332616

2534-
# First define some helper functions
2535-
def check_set(super_list, sub_list):
2536-
"""
2537-
Args:
2538-
super_list: list to check if superset of partList
2539-
sub_list: list to check if subset of superList
2540-
2541-
Returns: Boolean to see if super_list is a superset of sub_list
2542-
2543-
"""
2544-
super_set = set(super_list)
2545-
sub_set = set(sub_list)
2546-
return super_set.issuperset(sub_set)
2547-
2548-
def add_cb_atom_to_ring(ring, cb_atom):
2549-
"""
2550-
Every 'Cb' atom belongs in exactly one benzene ring. This function checks
2551-
adds the cb_atom to the ring (in connectivity order) if the cb_atom is connected
2552-
to any the last or first atom in the partial ring.
2553-
2554-
Args:
2555-
ring: list of :class:GroupAtoms representing a partial ring to merge
2556-
cb_atom: :class:GroupAtom with atomtype 'Cb'
2557-
2558-
Returns: If cb_atom connects to the beginning or end of ring, returns a
2559-
new list of the merged ring, otherwise an empty list
2560-
2561-
"""
2562-
2563-
merged_ring = []
2564-
# ring already complete
2565-
if len(ring) == 6: return merged_ring
2566-
for atom2, bond12 in cb_atom.bonds.items():
2567-
if bond12.is_benzene():
2568-
if atom2 is ring[-1]:
2569-
merged_ring = ring + [cb_atom]
2570-
elif atom2 is ring[0]:
2571-
merged_ring = [cb_atom] + ring
2572-
2573-
return merged_ring
2574-
2575-
def merge_overlapping_benzene_rings(ring1, ring2, od):
2576-
"""
2577-
The input arguments of rings are always in the order that the atoms appear
2578-
inside the ring. That is, each atom is connected to the ones adjacent on the
2579-
list.
2580-
2581-
Args:
2582-
ring1: list of :class:GroupAtoms representing first partial ring to merge
2583-
ring2: list :class:GroupAtoms representing second partial ring to merge
2584-
od: in for overlap distance
2585-
2586-
This function tries to see if the beginning or ends of each list have the
2587-
same atom objects, i.e the two part rings should be merged together.
2588-
2589-
Returns: If rings are mergable, returns a new list of the merged ring, otherwise
2590-
an empty list
2591-
2592-
"""
2593-
new_ring = []
2594-
# ring already complete
2595-
if len(ring1) == 6 or len(ring2) == 6: return new_ring
2596-
2597-
# start of ring1 matches end of ring2
2598-
match_list1 = [x1 is x2 for x1, x2 in zip(ring1[-od:], ring2[:od])]
2599-
# end of ring1 matches end of ring2
2600-
match_list2 = [x1 is x2 for x1, x2 in zip(ring1[-od:], ring2[:od - 1:-1])]
2601-
# start of ring1 matches end of ring2
2602-
match_list3 = [x1 is x2 for x1, x2 in zip(ring1[:od], ring2[-od:])]
2603-
# start of ring1 matches start of ring2
2604-
match_list4 = [x1 is x2 for x1, x2 in zip(ring1[:od], ring2[od::-1])]
2605-
if False not in match_list1:
2606-
new_ring = ring1 + ring2[od:]
2607-
elif False not in match_list2:
2608-
new_ring = ring1 + ring2[-od - 1::-1]
2609-
elif False not in match_list3:
2610-
new_ring = ring2[:-od] + ring1
2611-
elif False not in match_list4:
2612-
new_ring = ring2[:od - 1:-1] + ring1
2613-
2614-
return new_ring
2615-
2616-
#######################################################################################
26172617
# start of main algorithm
26182618
copy_group = deepcopy(self)
26192619
"""

rmgpy/molecule/inchi.py

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import itertools
3131
import re
3232
import warnings
33+
from operator import itemgetter
3334

3435
import cython
3536
from rdkit import Chem
@@ -614,7 +615,7 @@ def create_augmented_layers(mol):
614615
atom_indices = [atom_indices.index(i + 1) for i, atom in enumerate(molcopy.atoms)]
615616

616617
# sort the atoms based on the order of the atom indices
617-
molcopy.atoms = [x for (y, x) in sorted(zip(atom_indices, molcopy.atoms), key=lambda pair: pair[0])]
618+
molcopy.atoms = [x for (y, x) in sorted(zip(atom_indices, molcopy.atoms), key=itemgetter(0))]
618619

619620
ulayer = _create_u_layer(molcopy, auxinfo)
620621

@@ -704,17 +705,15 @@ def _convert_3_atom_2_bond_path(start, mol):
704705
"""
705706
from rmgpy.data.kinetics.family import ReactionRecipe
706707

707-
def is_valid(mol):
708-
"""Check if total bond order of oxygen atoms is smaller than 4."""
709-
710-
for at in mol.atoms:
711-
if at.number == 8:
712-
order = at.get_total_bond_order()
713-
not_correct = order >= 4
714-
if not_correct:
715-
return False
716-
717-
return True
708+
# Check if total bond order of oxygen atoms is smaller than 4
709+
is_mol_valid = True
710+
for at in mol.atoms:
711+
if at.number == 8:
712+
order = at.get_total_bond_order()
713+
not_correct = order >= 4
714+
if not_correct:
715+
is_mol_valid = False
716+
break
718717

719718
paths = pathfinder.find_allyl_end_with_charge(start)
720719

@@ -739,7 +738,7 @@ def is_valid(mol):
739738
end.charge += 1 if end.charge < 0 else -1
740739
recipe.apply_forward(mol)
741740

742-
if is_valid(mol):
741+
if is_mol_valid:
743742
# unlabel atoms so that they never cause trouble downstream
744743
for i, at in enumerate(path[::2]):
745744
at.label = ''

rmgpy/molecule/molecule.py

Lines changed: 17 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
from collections import OrderedDict, defaultdict
4242
from copy import deepcopy
4343
from urllib.parse import quote
44+
from operator import attrgetter
4445

4546
import cython
4647
import numpy as np
@@ -62,6 +63,10 @@
6263

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

66+
# helper function for sorting
67+
def _skip_first(in_tuple):
68+
return in_tuple[1:]
69+
6570
bond_orders = {'S': 1, 'D': 2, 'T': 3, 'B': 1.5}
6671

6772
globals().update({
@@ -2543,30 +2548,21 @@ def get_aromatic_rings(self, rings=None, save_order=False):
25432548
if rings is None:
25442549
rings = self.get_relevant_cycles()
25452550

2546-
def filter_fused_rings(_rings):
2547-
"""
2548-
Given a list of rings, remove ones which share more than 2 atoms.
2549-
"""
2550-
cython.declare(toRemove=set, i=cython.int, j=cython.int, toRemoveSorted=list)
2551-
2552-
if len(_rings) < 2:
2553-
return _rings
2554-
2551+
# Remove rings that share more than 3 atoms, since they cannot be planar
2552+
cython.declare(toRemove=set, j=cython.int, toRemoveSorted=list)
2553+
if len(rings) < 2:
2554+
pass
2555+
else:
25552556
to_remove = set()
2556-
for i, j in itertools.combinations(range(len(_rings)), 2):
2557-
if len(set(_rings[i]) & set(_rings[j])) > 2:
2557+
for i, j in itertools.combinations(range(len(rings)), 2):
2558+
if len(set(rings[i]) & set(rings[j])) > 2:
25582559
to_remove.add(i)
25592560
to_remove.add(j)
25602561

25612562
to_remove_sorted = sorted(to_remove, reverse=True)
25622563

25632564
for i in to_remove_sorted:
2564-
del _rings[i]
2565-
2566-
return _rings
2567-
2568-
# Remove rings that share more than 3 atoms, since they cannot be planar
2569-
rings = filter_fused_rings(rings)
2565+
del rings[i]
25702566

25712567
# Only keep rings with exactly 6 atoms, since RMG can only handle aromatic benzene
25722568
rings = [ring for ring in rings if len(ring) == 6]
@@ -2702,7 +2698,7 @@ def get_deterministic_sssr(self):
27022698
tup = (vertex, get_vertex_connectivity_value(vertex), -origin_conn_dict[vertex])
27032699
root_candidates_tups.append(tup)
27042700

2705-
root_vertex = sorted(root_candidates_tups, key=lambda tup0: tup0[1:], reverse=True)[0][0]
2701+
root_vertex = sorted(root_candidates_tups, key=_skip_first, reverse=True)[0][0]
27062702

27072703
# Get all cycles involving the root vertex
27082704
cycles = graph0.get_all_cycles(root_vertex)
@@ -2719,7 +2715,7 @@ def get_deterministic_sssr(self):
27192715
-sum([v.get_total_bond_order() for v in cycle0]))
27202716
cycle_candidate_tups.append(tup)
27212717

2722-
cycle = sorted(cycle_candidate_tups, key=lambda tup0: tup0[1:])[0][0]
2718+
cycle = sorted(cycle_candidate_tups, key=_skip_first)[0][0]
27232719

27242720
cycle_list.append(cycle)
27252721

@@ -2803,8 +2799,8 @@ def is_identical(self, other, strict=True):
28032799
if atom_ids == other_ids:
28042800
# If the two molecules have the same indices, then they might be identical
28052801
# Sort the atoms by ID
2806-
atom_list = sorted(self.atoms, key=lambda x: x.id)
2807-
other_list = sorted(other.atoms, key=lambda x: x.id)
2802+
atom_list = sorted(self.atoms, key=attrgetter('id'))
2803+
other_list = sorted(other.atoms, key=attrgetter('id'))
28082804

28092805
# If matching atom indices gives a valid mapping, then the molecules are fully identical
28102806
mapping = {}

rmgpy/molecule/resonance.py

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
"""
5353

5454
import logging
55+
from operator import attrgetter
5556

5657
import cython
5758

@@ -954,6 +955,13 @@ def generate_clar_structures(mol, save_order=False):
954955

955956
return mol_list
956957

958+
# helper functions for sorting
959+
def _sum_atom_ids(atom_list):
960+
return sum(atom.id for atom in atom_list)
961+
962+
def _tuplize_bond(bond):
963+
return (bond.atom1.id, bond.atom2.id)
964+
957965

958966
def _clar_optimization(mol, constraints=None, max_num=None, save_order=False):
959967
"""
@@ -982,7 +990,7 @@ def _clar_optimization(mol, constraints=None, max_num=None, save_order=False):
982990
molecule = mol.copy(deep=True)
983991

984992
aromatic_rings = molecule.get_aromatic_rings(save_order=save_order)[0]
985-
aromatic_rings.sort(key=lambda x: sum([atom.id for atom in x]))
993+
aromatic_rings.sort(key=_sum_atom_ids)
986994

987995
if not aromatic_rings:
988996
return []
@@ -991,13 +999,13 @@ def _clar_optimization(mol, constraints=None, max_num=None, save_order=False):
991999
atoms = set()
9921000
for ring in aromatic_rings:
9931001
atoms.update(ring)
994-
atoms = sorted(atoms, key=lambda x: x.id)
1002+
atoms = sorted(atoms, key=attrgetter('id'))
9951003

9961004
# Get list of bonds involving the ring atoms, ignoring bonds to hydrogen
9971005
bonds = set()
9981006
for atom in atoms:
9991007
bonds.update([atom.bonds[key] for key in atom.bonds.keys() if key.is_non_hydrogen()])
1000-
bonds = sorted(bonds, key=lambda x: (x.atom1.id, x.atom2.id))
1008+
bonds = sorted(bonds, key=_tuplize_bond)
10011009

10021010
# Identify exocyclic bonds, and save their bond orders
10031011
exo = []

rmgpy/pdep/reaction.pyx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -308,7 +308,7 @@ def apply_inverse_laplace_transform_method(transition_state,
308308
and abs(dens_states[r - m, s]) > 1e-12 \
309309
and abs(dens_states[r - m - 1, s]) > 1e-12:
310310
num = dens_states[r - m, s] * (dens_states[r - m - 1, s] / dens_states[r - m, s]) \
311-
** (-rem / (e_list[r - m - 1] - e_list[r - m]))
311+
** (-rem / (e_list[r - m - 1] - e_list[r - m])).real
312312
k[r, s] = freq_factor * num / dens_states[r, s]
313313

314314
elif n >= n_crit:

0 commit comments

Comments
 (0)