From a7f9d5e2659bdc77456ed746af69f6ee6ba91c1e Mon Sep 17 00:00:00 2001 From: Richard West Date: Wed, 1 Feb 2017 10:50:39 -0500 Subject: [PATCH 1/9] Snapshots (PNGs and CSVs) now track moles not mole fractions. Unsure if this has consequences on flux diagrams or sensitivity analyses, etc. but I think it's a helpful start towards making more sense of simulation outputs, especially for two-phase heterogeneous systems. --- rmgpy/rmg/listener.py | 8 ++++---- rmgpy/solver/base.pyx | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/rmgpy/rmg/listener.py b/rmgpy/rmg/listener.py index 9cfcf47458..6510562dd1 100644 --- a/rmgpy/rmg/listener.py +++ b/rmgpy/rmg/listener.py @@ -36,7 +36,7 @@ class SimulationProfileWriter(object): """ SimulationProfileWriter listens to a ReactionSystem subject - and writes the species mole fractions as a function of the reaction time + and writes the species mole numbers as a function of the reaction time to a csv file. @@ -70,7 +70,7 @@ def update(self, reactionSystem): Writes to a csv file: - header row with species names - - each row with mole fractions of the core species in the given reaction system. + - each row with number of moles of the core species in the given reaction system. """ filename = os.path.join( @@ -103,7 +103,7 @@ class SimulationProfilePlotter(object): A new instance of the class can be appended to a subject as follows: reactionSystem = ... - listener = SimulationProfilPlotter() + listener = SimulationProfilePlotter() reactionSystem.attach(listener) Whenever the subject calls the .notify() method, the @@ -145,4 +145,4 @@ def update(self, reactionSystem): ) ) - SimulationPlot(csvFile=csvFile, numSpecies=10, ylabel='Mole Fraction').plot(pngFile) + SimulationPlot(csvFile=csvFile, numSpecies=10, ylabel='Moles').plot(pngFile) diff --git a/rmgpy/solver/base.pyx b/rmgpy/solver/base.pyx index eb844bf658..35373ece61 100644 --- a/rmgpy/solver/base.pyx +++ b/rmgpy/solver/base.pyx @@ -697,7 +697,7 @@ cdef class ReactionSystem(DASx): # Copy the initial conditions to use in evaluating conversions y0 = self.y.copy() - # a list with the time, Volume, mole fractions of core species + # a list with the time, Volume, number of moles of core species self.snapshots = [] if sensitivity: @@ -785,7 +785,7 @@ cdef class ReactionSystem(DASx): snapshot = [self.t, self.V] - snapshot.extend(y_coreSpecies / numpy.sum(y_coreSpecies)) + snapshot.extend(y_coreSpecies) self.snapshots.append(snapshot) # Get the characteristic flux From a18692e5c2356d0a8ffa1e844ea6bcb888c51a53 Mon Sep 17 00:00:00 2001 From: Richard West Date: Thu, 31 Jan 2019 22:51:06 -0500 Subject: [PATCH 2/9] Brief notes in documentation about change of 'solver' output. --- documentation/source/users/rmg/output.rst | 1 + documentation/source/users/rmg/releaseNotes.rst | 10 ++++++++++ 2 files changed, 11 insertions(+) diff --git a/documentation/source/users/rmg/output.rst b/documentation/source/users/rmg/output.rst index 5b044f11e5..ce2b94214a 100755 --- a/documentation/source/users/rmg/output.rst +++ b/documentation/source/users/rmg/output.rst @@ -42,3 +42,4 @@ network. The Solver Folder ------------------ RMG currently includes a solver for isothermal batch reactors. This is in fact a critical part of the model enlargement algorithm. If you have included simulations in your input file, the solutions will be located in ``/solver``. You will probably only be interested in the files with the largest number tags. +Please note that up to and including RMG-Py version 2.3.0 these files showed mole fraction of each species at each step, but they now show amount (number of moles) of each species; you must divide by the sum if you wish to get a mole fraction. diff --git a/documentation/source/users/rmg/releaseNotes.rst b/documentation/source/users/rmg/releaseNotes.rst index 11a9bd6054..e97def6dac 100644 --- a/documentation/source/users/rmg/releaseNotes.rst +++ b/documentation/source/users/rmg/releaseNotes.rst @@ -4,6 +4,16 @@ Release Notes ************* + +RMG-Py Version 2.3.... +====================== +(pre-release development version) + +- Miscellaneous changes: + - Output files in 'solver' directory now show species amounts (numbers of moles) not mole fractions. + + + RMG-Py Version 2.3.0 ==================== Date: Dec 20, 2018 From 61c948842d241f371fad44e5c0e2d8146291871a Mon Sep 17 00:00:00 2001 From: Richard West Date: Fri, 18 Jan 2019 16:47:17 -0500 Subject: [PATCH 3/9] Add quadruple bonds A combination of commits with these messages: replaced part of the adjlist in the test that I accidentally deleted added in a quadruple bond to orders Added in quadruple bond type in converter added in more instances of quadruple bonds Adding Cq to R and R!H atom types added in todos to add unit tests for quadruple bonded elements --- rmgpy/molecule/atomtype.pxd | 1 + rmgpy/molecule/atomtype.py | 236 ++++++++++++++++------------- rmgpy/molecule/atomtypeTest.py | 4 +- rmgpy/molecule/atomtypedatabase.py | 21 ++- rmgpy/molecule/converter.py | 7 +- rmgpy/molecule/draw.py | 15 +- rmgpy/molecule/group.py | 27 +++- rmgpy/molecule/groupTest.py | 13 +- rmgpy/molecule/molecule.pxd | 2 + rmgpy/molecule/molecule.py | 17 ++- rmgpy/molecule/moleculeTest.py | 21 ++- 11 files changed, 234 insertions(+), 130 deletions(-) diff --git a/rmgpy/molecule/atomtype.pxd b/rmgpy/molecule/atomtype.pxd index c01555f3c7..4ffc4d463a 100644 --- a/rmgpy/molecule/atomtype.pxd +++ b/rmgpy/molecule/atomtype.pxd @@ -46,6 +46,7 @@ cdef class AtomType: cdef public list oDouble cdef public list sDouble cdef public list triple + cdef public list quadruple cdef public list benzene cdef public list lonePairs cdef public list charge diff --git a/rmgpy/molecule/atomtype.py b/rmgpy/molecule/atomtype.py index 64f67cab26..a44c16b6e6 100644 --- a/rmgpy/molecule/atomtype.py +++ b/rmgpy/molecule/atomtype.py @@ -76,6 +76,7 @@ class AtomType: 'oDouble' ''list'' The number of double bonds to oxygen 'sDouble' ''list'' The number of double bonds to sulfur 'triple' ''list'' The total number of triple bonds on the atom + 'quadruple' ''list'' The total number of quadruple bonds on the atom 'benzene' ''list'' The total number of benzene bonds on the atom 'lonePairs' ''list'' The number of lone pairs on the atom 'charge' ''list'' The partial charge of the atom @@ -91,6 +92,7 @@ def __init__(self, label='', generic=None, specific=None, oDouble=None, sDouble=None, triple=None, + quadruple=None, benzene=None, lonePairs=None, charge=None): @@ -111,6 +113,7 @@ def __init__(self, label='', generic=None, specific=None, self.oDouble = oDouble or [] self.sDouble = sDouble or [] self.triple = triple or [] + self.quadruple = quadruple or [] self.benzene = benzene or [] self.lonePairs = lonePairs or [] self.charge = charge or [] @@ -140,6 +143,7 @@ def __reduce__(self): 'oDouble': self.oDouble, 'sDouble': self.sDouble, 'triple': self.triple, + 'quadruple': self.quadruple, 'benzene': self.benzene, 'lonePairs': self.lonePairs, 'charge': self.charge @@ -167,11 +171,13 @@ def __setstate__(self, d): self.oDouble = d['oDouble'] self.sDouble = d['sDouble'] self.triple = d['triple'] + self.quadruple = d['quadruple'] self.benzene = d['benzene'] self.lonePairs = d['lonePairs'] self.charge = d['charge'] - def setActions(self, incrementBond, decrementBond, formBond, breakBond, incrementRadical, decrementRadical, incrementLonePair, decrementLonePair): + def setActions(self, incrementBond, decrementBond, formBond, breakBond, incrementRadical, decrementRadical, + incrementLonePair, decrementLonePair): self.incrementBond = incrementBond self.decrementBond = decrementBond self.formBond = formBond @@ -206,6 +212,7 @@ def getFeatures(self): self.oDouble, self.sDouble, self.triple, + self.quadruple, self.benzene, self.lonePairs, self.charge] @@ -236,10 +243,10 @@ def getFeatures(self): 'R!H', 'Val4','Val5','Val6','Val7', 'He','Ne','Ar', - 'C','Ca','Cs','Csc','Cd','CO','CS','Cdd','Cdc','Ct','Cb','Cbf','C2s','C2sc','C2d','C2dc','C2tc', + 'C','Ca','Cs','Csc','Cd','CO','CS','Cdd','Cdc','Ct','Cb','Cbf','Cq','C2s','C2sc','C2d','C2dc','C2tc', 'N','N0sc','N1s','N1sc','N1dc','N3s','N3sc','N3d','N3t','N3b','N5sc','N5dc','N5ddc','N5dddc','N5tc','N5b','N5bd', 'O','Oa','O0sc','O2s','O2sc','O2d','O4sc','O4dc','O4tc','O4b', - 'Si','Sis','Sid','Sidd','Sit','SiO','Sib','Sibf', + 'Si','Sis','Sid','Sidd','Sit','SiO','Sib','Sibf','Siq', 'S','Sa','S0sc','S2s','S2sc','S2d','S2dc','S2tc','S4s','S4sc','S4d','S4dd','S4dc','S4b','S4t','S4tdc','S6s','S6sc','S6d','S6dd','S6ddd','S6dc','S6t','S6td','S6tt','S6tdc', 'Cl','Cl1s', 'I','I1s', @@ -248,18 +255,18 @@ def getFeatures(self): atomTypes['R!H'] = AtomType(label='R!H', generic=['R'], specific=[ 'Val4','Val5','Val6','Val7', 'He','Ne','Ar', - 'C','Ca','Cs','Csc','Cd','CO','CS','Cdd','Cdc','Ct','Cb','Cbf','C2s','C2sc','C2d','C2dc','C2tc', + 'C','Ca','Cs','Csc','Cd','CO','CS','Cdd','Cdc','Ct','Cb','Cbf','Cq','C2s','C2sc','C2d','C2dc','C2tc', 'N','N0sc','N1s','N1sc','N1dc','N3s','N3sc','N3d','N3t','N3b','N5sc','N5dc','N5ddc','N5dddc','N5tc','N5b','N5bd', 'O','Oa','O0sc','O2s','O2sc','O2d','O4sc','O4dc','O4tc','O4b', - 'Si','Sis','Sid','Sidd','Sit','SiO','Sib','Sibf', + 'Si','Sis','Sid','Sidd','Sit','SiO','Sib','Sibf','Siq', 'S','Sa','S0sc','S2s','S2sc','S2d','S2dc','S2tc','S4s','S4sc','S4d','S4dd','S4dc','S4b','S4t','S4tdc','S6s','S6sc','S6d','S6dd','S6ddd','S6dc','S6t','S6td','S6tt','S6tdc', 'Cl','Cl1s', 'I','I1s', 'F','F1s']) atomTypes['Val4'] = AtomType(label='Val4', generic=['R','R!H'], specific=[ - 'C','Ca','Cs','Csc','Cd','CO','CS','Cdd','Cdc','Ct','Cb','Cbf','C2s','C2sc','C2d','C2dc','C2tc', - 'Si','Sis','Sid','Sidd','Sit','SiO','Sib','Sibf']) + 'C','Ca','Cs','Csc','Cd','CO','CS','Cq','Cdd','Cdc','Ct','Cb','Cbf','C2s','C2sc','C2d','C2dc','C2tc', + 'Si','Sis','Sid','Sidd','Sit','SiO','Sib','Sibf','Siq']) atomTypes['Val5'] = AtomType(label='Val5', generic=['R','R!H'], specific=[ 'N','N0sc','N1s','N1sc','N1dc','N3s','N3sc','N3d','N3t','N3b','N5sc','N5dc','N5ddc','N5dddc','N5tc','N5b','N5bd']) @@ -279,241 +286,248 @@ def getFeatures(self): atomTypes['Ne' ] = AtomType('Ne', generic=['R','R!H'], specific=[]) atomTypes['Ar' ] = AtomType('Ar', generic=['R','R!H'], specific=[]) -atomTypes['C' ] = AtomType('C', generic=['R','R!H','Val4'], specific=['Ca','Cs','Csc','Cd','CO','CS','Cdd','Cdc','Ct','Cb','Cbf','C2s','C2sc','C2d','C2dc','C2tc'], - single=[], allDouble=[], rDouble=[], oDouble=[], sDouble=[], triple=[], benzene=[], lonePairs=[], charge=[]) +atomTypes['C' ] = AtomType('C', generic=['R','R!H','Val4'], specific=['Ca','Cs','Csc','Cd','CO','Cq','CS','Cdd','Cdc','Ct','Cb','Cbf','C2s','C2sc','C2d','C2dc','C2tc'], + single=[], allDouble=[], rDouble=[], oDouble=[], sDouble=[], triple=[], quadruple=[], benzene=[], lonePairs=[], charge=[]) # todo: double check to see if quadruple should be blank or 0 for all of these as well as being 1 for quadruple atomTypes['Ca' ] = AtomType('Ca', generic=['R','R!H','C','Val4'], specific=[], # (shared electrons = 4) - single=[0], allDouble=[0], rDouble=[], oDouble=[], sDouble=[], triple=[0], benzene=[0], lonePairs=[2], charge=[0]) + single=[0], allDouble=[0], rDouble=[], oDouble=[], sDouble=[], triple=[0], quadruple=[], benzene=[0], lonePairs=[2], charge=[0]) # examples for Ca: atomic carbon (closed shell) atomTypes['Cs' ] = AtomType('Cs', generic=['R','R!H','C','Val4'], specific=[], # (shared electrons = 4-8) - single=[0,1,2,3,4], allDouble=[0], rDouble=[0], oDouble=[0], sDouble=[0], triple=[0], benzene=[0], lonePairs=[0], charge=[0]) + single=[0,1,2,3,4], allDouble=[0], rDouble=[0], oDouble=[0], sDouble=[0], triple=[0], quadruple=[], benzene=[0], lonePairs=[0], charge=[0]) # examples for Cs: C, CC, atomTypes['Csc' ] = AtomType('Csc', generic=['R','R!H','C','Val4'], specific=[], # (shared electrons = 3-6) - single=[0,1,2,3], allDouble=[0], rDouble=[], oDouble=[], sDouble=[], triple=[0], benzene=[0], lonePairs=[0], charge=[+1]) + single=[0,1,2,3], allDouble=[0], rDouble=[], oDouble=[], sDouble=[], triple=[0], quadruple=[], benzene=[0], lonePairs=[0], charge=[+1]) # examples for Csc: C1=CCC([O-])[CH+]1, O[O+]=C[C+]C([O-])[O-] atomTypes['Cd' ] = AtomType('Cd', generic=['R','R!H','C','Val4'], specific=[], # (shared electrons = 6-8) - single=[0,1,2], allDouble=[1], rDouble=[1], oDouble=[0], sDouble=[0], triple=[0], benzene=[0], lonePairs=[0], charge=[0]) + single=[0,1,2], allDouble=[1], rDouble=[1], oDouble=[0], sDouble=[0], triple=[0], quadruple=[], benzene=[0], lonePairs=[0], charge=[0]) # examples for Cd: C=C, C=N atomTypes['Cdc' ] = AtomType('Cdc', generic=['R','R!H','C','Val4'], specific=[], # (shared electrons = 6) - single=[0,1], allDouble=[1], rDouble=[0,1], oDouble=[0,1], sDouble=[0,1], triple=[0], benzene=[0], lonePairs=[0], charge=[+1]) + single=[0,1], allDouble=[1], rDouble=[0,1], oDouble=[0,1], sDouble=[0,1], triple=[0], quadruple=[], benzene=[0], lonePairs=[0], charge=[+1]) # examples for Cdc: [CH+]=C=[CH-], [CH+]=N[O-] (one of the res structures of Fulminic acid) atomTypes['CO' ] = AtomType('CO', generic=['R','R!H','C','Val4'], specific=[], # (shared electrons = 6-8) - single=[0,1,2], allDouble=[1], rDouble=[0], oDouble=[1], sDouble=[0], triple=[0], benzene=[0], lonePairs=[0], charge=[0]) + single=[0,1,2], allDouble=[1], rDouble=[0], oDouble=[1], sDouble=[0], triple=[0], quadruple=[], benzene=[0], lonePairs=[0], charge=[0]) # examples for CO: C=O atomTypes['CS' ] = AtomType('CS', generic=['R','R!H','C','Val4'], specific=[], # (shared electrons = 6-8) - single=[0,1,2], allDouble=[1], rDouble=[0], oDouble=[0], sDouble=[1], triple=[0], benzene=[0], lonePairs=[0], charge=[0]) + single=[0,1,2], allDouble=[1], rDouble=[0], oDouble=[0], sDouble=[1], triple=[0], quadruple=[], benzene=[0], lonePairs=[0], charge=[0]) # examples for CS: C=S atomTypes['Cdd' ] = AtomType('Cdd', generic=['R','R!H','C','Val4'], specific=[], # (shared electrons = 8) - single=[0], allDouble=[2], rDouble=[0,1,2], oDouble=[0,1,2], sDouble=[0,1,2], triple=[0], benzene=[0], lonePairs=[0], charge=[0]) + single=[0], allDouble=[2], rDouble=[0,1,2], oDouble=[0,1,2], sDouble=[0,1,2], triple=[0], quadruple=[], benzene=[0], lonePairs=[0], charge=[0]) # examples for Cdd: O=C=O, C=C=C atomTypes['Ct' ] = AtomType('Ct', generic=['R','R!H','C','Val4'], specific=[], # (shared electrons = 7-8) - single=[0,1], allDouble=[0], rDouble=[], oDouble=[], sDouble=[], triple=[1], benzene=[0], lonePairs=[0], charge=[0]) + single=[0,1], allDouble=[0], rDouble=[], oDouble=[], sDouble=[], triple=[1], quadruple=[], benzene=[0], lonePairs=[0], charge=[0]) # examples for Ct: C#C, C#N atomTypes['Cb' ] = AtomType('Cb', generic=['R','R!H','C','Val4'], specific=[], - single=[0,1], allDouble=[0], rDouble=[], oDouble=[], sDouble=[], triple=[0], benzene=[1,2], lonePairs=[], charge=[]) + single=[0,1], allDouble=[0], rDouble=[], oDouble=[], sDouble=[], triple=[0], quadruple=[], benzene=[1,2], lonePairs=[], charge=[]) # examples for Cb: benzene (C6H6) atomTypes['Cbf' ] = AtomType('Cbf', generic=['R','R!H','C','Val4'], specific=[], - single=[0], allDouble=[0], rDouble=[], oDouble=[], sDouble=[], triple=[0], benzene=[3], lonePairs=[], charge=[]) + single=[0], allDouble=[0], rDouble=[], oDouble=[], sDouble=[], triple=[0], quadruple=[], benzene=[3], lonePairs=[], charge=[]) # examples for Cbf: Naphthalene +atomTypes['Cq' ] = AtomType('Cq', generic=['R','R!H','C','Val4'], specific=[], + single=[0], allDouble=[0], rDouble=[0], oDouble=[0], sDouble=[0], triple=[0], quadruple=[1], benzene=[0], lonePairs=[], charge=[]) +# examples for Cq: C2 atomTypes['C2s' ] = AtomType('C2s', generic=['R','R!H','C','Val4'], specific=[], # (shared electrons = 4-6) - single=[0,1,2], allDouble=[0], rDouble=[], oDouble=[], sDouble=[], triple=[0], benzene=[0], lonePairs=[1], charge=[0]) + single=[0,1,2], allDouble=[0], rDouble=[], oDouble=[], sDouble=[], triple=[0], quadruple=[], benzene=[0], lonePairs=[1], charge=[0]) # examples for C2s: singlet[CH2] atomTypes['C2sc'] = AtomType('C2sc', generic=['R','R!H','C','Val4'], specific=[], # (shared electrons = 5-8) - single=[0,1,2,3], allDouble=[0], rDouble=[], oDouble=[], sDouble=[], triple=[0], benzene=[0], lonePairs=[1], charge=[-1]) + single=[0,1,2,3], allDouble=[0], rDouble=[], oDouble=[], sDouble=[], triple=[0], quadruple=[], benzene=[0], lonePairs=[1], charge=[-1]) # examples for C2sc: [CH2-][N+]#N atomTypes['C2d' ] = AtomType('C2d', generic=['R','R!H','C','Val4'], specific=[], # (shared electrons = 6) - single=[0], allDouble=[1], rDouble=[], oDouble=[], sDouble=[], triple=[0], benzene=[0], lonePairs=[1], charge=[0]) + single=[0], allDouble=[1], rDouble=[], oDouble=[], sDouble=[], triple=[0], quadruple=[], benzene=[0], lonePairs=[1], charge=[0]) # examples for C2d: singlet[C]=C atomTypes['C2dc'] = AtomType('C2dc', generic=['R','R!H','C','Val4'], specific=[], # (shared electrons = 7-8) - single=[0,1], allDouble=[1], rDouble=[], oDouble=[], sDouble=[], triple=[0], benzene=[0], lonePairs=[1], charge=[-1]) + single=[0,1], allDouble=[1], rDouble=[], oDouble=[], sDouble=[], triple=[0], quadruple=[], benzene=[0], lonePairs=[1], charge=[-1]) # examples for C2dc: C=[C-][N+]#N, [CH-]=[N+]=O, [CH+]=C=[CH-] atomTypes['C2tc'] = AtomType('C2tc', generic=['R','R!H','C','Val4'], specific=[], # (shared electrons = 8) - single=[0], allDouble=[0], rDouble=[], oDouble=[], sDouble=[], triple=[1], benzene=[0], lonePairs=[1], charge=[-1]) + single=[0], allDouble=[0], rDouble=[], oDouble=[], sDouble=[], triple=[1], quadruple=[], benzene=[0], lonePairs=[1], charge=[-1]) # examples for C2tc: [C-]#[O+], H[N+]#[C-] atomTypes['N' ] = AtomType('N', generic=['R','R!H','Val5'], specific=['N0sc','N1s','N1sc','N1dc','N3s','N3sc','N3d','N3t','N3b','N5sc','N5dc','N5ddc','N5dddc','N5tc','N5b','N5bd'], - single=[], allDouble=[], rDouble=[], oDouble=[], sDouble=[], triple=[], benzene=[], lonePairs=[], charge=[]) + single=[], allDouble=[], rDouble=[], oDouble=[], sDouble=[], triple=[], quadruple=[], benzene=[], lonePairs=[], charge=[]) atomTypes['N0sc'] = AtomType('N0sc', generic=['R','R!H','N','Val5'], specific=[], # (shared electrons = 7-8) - single=[0,1], allDouble=[0], rDouble=[0], oDouble=[0], sDouble=[0], triple=[0], benzene=[0], lonePairs=[3], charge=[-2]) + single=[0,1], allDouble=[0], rDouble=[0], oDouble=[0], sDouble=[0], triple=[0], quadruple=[], benzene=[0], lonePairs=[3], charge=[-2]) # examples for N0sc: [NH+]#[N+][N-2] with adjList 1 N u0 p0 c+1 {2,S} {3,T}; 2 H u0 p0 c0 {1,S}; 3 N u0 p0 c+1 {1,T} {4,S}; 4 N u0 p3 c-2 {3,S} atomTypes['N1s' ] = AtomType('N1s', generic=['R','R!H','N','Val5'], specific=[], # (shared electrons = 5-6) - single=[0,1], allDouble=[0], rDouble=[0], oDouble=[0], sDouble=[0], triple=[0], benzene=[0], lonePairs=[2], charge=[0]) + single=[0,1], allDouble=[0], rDouble=[0], oDouble=[0], sDouble=[0], triple=[0], quadruple=[], benzene=[0], lonePairs=[2], charge=[0]) # examples for N1s: closed shell N-N, closed shell NH atomTypes['N1sc'] = AtomType('N1sc', generic=['R','R!H','N','Val5'], specific=[], # (shared electrons = 6-8) - single=[0,1,2], allDouble=[0], rDouble=[], oDouble=[], sDouble=[], triple=[0], benzene=[0], lonePairs=[2], charge=[-1]) + single=[0,1,2], allDouble=[0], rDouble=[], oDouble=[], sDouble=[], triple=[0], quadruple=[], benzene=[0], lonePairs=[2], charge=[-1]) # examples for N1sc: [NH-][S+]=C, [NH-][N+]#C atomTypes['N1dc'] = AtomType('N1dc', generic=['R','R!H','N','Val5'], specific=[], # (shared electrons = 8) - single=[0], allDouble=[1], rDouble=[], oDouble=[], sDouble=[], triple=[0], benzene=[0], lonePairs=[2], charge=[-1]) + single=[0], allDouble=[1], rDouble=[], oDouble=[], sDouble=[], triple=[0],quadruple=[], benzene=[0], lonePairs=[2], charge=[-1]) # examples for N1dc: [N-]=[N+]=N terminal nitrogen on azide (two lone pairs), [N-]=[NH+], [N-]=[SH+] atomTypes['N3s' ] = AtomType('N3s', generic=['R','R!H','N','Val5'], specific=[], # (shared electrons = 5-8) - single=[0,1,2,3], allDouble=[0], rDouble=[0], oDouble=[0], sDouble=[0], triple=[0], benzene=[0], lonePairs=[1], charge=[0]) + single=[0,1,2,3], allDouble=[0], rDouble=[0], oDouble=[0], sDouble=[0], triple=[0], quadruple=[], benzene=[0], lonePairs=[1], charge=[0]) # examples for N3s: NH3, NH2, NH, N, C[NH]... atomTypes['N3sc'] = AtomType('N3sc', generic=['R','R!H','N','Val5'], specific=[], # (shared electrons = 4-6) - single=[0,1,2], allDouble=[0], rDouble=[0], oDouble=[0], sDouble=[0], triple=[0], benzene=[0], lonePairs=[1], charge=[+1]) + single=[0,1,2], allDouble=[0], rDouble=[0], oDouble=[0], sDouble=[0], triple=[0], quadruple=[], benzene=[0], lonePairs=[1], charge=[+1]) # examples for N3sc: !! N3sc should eventually be deleted, see #1206 atomTypes['N3d' ] = AtomType('N3d', generic=['R','R!H','N','Val5'], specific=[], # (shared electrons = 7-8) - single=[0,1], allDouble=[1], rDouble=[], oDouble=[], sDouble=[], triple=[0], benzene=[0], lonePairs=[1], charge=[0]) + single=[0,1], allDouble=[1], rDouble=[], oDouble=[], sDouble=[], triple=[0], quadruple=[], benzene=[0], lonePairs=[1], charge=[0]) # examples for N3d: N=O, N=N, C=N, [O]N=O, [N]=O, [N]=C atomTypes['N3t' ] = AtomType('N3t', generic=['R','R!H','N','Val5'], specific=[], # (shared electrons = 8) - single=[0], allDouble=[0], rDouble=[0], oDouble=[0], sDouble=[0], triple=[1], benzene=[0], lonePairs=[1], charge=[0]) + single=[0], allDouble=[0], rDouble=[0], oDouble=[0], sDouble=[0], triple=[1], quadruple=[], benzene=[0], lonePairs=[1], charge=[0]) # examples for N3t: N2, N#C, N#[C], N#CC atomTypes['N3b' ] = AtomType('N3b', generic=['R','R!H','N','Val5'], specific=[], - single=[0], allDouble=[0], rDouble=[0], oDouble=[0], sDouble=[0], triple=[0], benzene=[2], lonePairs=[1], charge=[0]) + single=[0], allDouble=[0], rDouble=[0], oDouble=[0], sDouble=[0], triple=[0], quadruple=[], benzene=[2], lonePairs=[1], charge=[0]) # examples for N3b: Oxazole, Pyradine, Pyrazine, 1,3,5-Triazine, Benzimidazole, Purine atomTypes['N5sc'] = AtomType('N5sc', generic=['R','R!H','N','Val5'], specific=[], # (shared electrons = 4-8) single=[0,1,2,3,4], allDouble=[0], rDouble=[0], oDouble=[0], sDouble=[0], triple=[0], benzene=[0], lonePairs=[0], charge=[+1,+2]) # examples for N5sc: [NH3+][O-] atomTypes['N5dc'] = AtomType('N5dc', generic=['R','R!H','N','Val5'], specific=[], # (shared electrons = 6-8) - single=[0,1,2], allDouble=[1], rDouble=[], oDouble=[], sDouble=[], triple=[0], benzene=[0], lonePairs=[0], charge=[+1]) + single=[0,1,2], allDouble=[1], rDouble=[], oDouble=[], sDouble=[], triple=[0], quadruple=[], benzene=[0], lonePairs=[0], charge=[+1]) # examples for N5dc: O[N+](=O)(O-) nitrate group, [N+](=O)(O)[O-], O=[N+][O-], [N+](=O)(O[N+](=O)[O-])[O-], C=[N+]=[SH-], [NH2+]=[SH-] atomTypes['N5ddc'] = AtomType('N5ddc', generic=['R','R!H','N','Val5'], specific=[], # (shared electrons = 8) - single=[0], allDouble=[2], rDouble=[], oDouble=[], sDouble=[], triple=[0], benzene=[0], lonePairs=[0], charge=[+1]) + single=[0], allDouble=[2], rDouble=[], oDouble=[], sDouble=[], triple=[0], quadruple=[], benzene=[0], lonePairs=[0], charge=[+1]) # examples for N5ddc: N=[N+]=[N-] center nitrogen on azide, [N-]=[N+]=O, C=[N+]=[SH-] atomTypes['N5dddc'] = AtomType('N5dddc', generic=['R','R!H','N','Val5'], specific=[], # (shared electrons = 6) - single=[0], allDouble=[3], rDouble=[], oDouble=[], sDouble=[], triple=[0], benzene=[0], lonePairs=[0], charge=[-1]) + single=[0], allDouble=[3], rDouble=[], oDouble=[], sDouble=[], triple=[0], quadruple=[], benzene=[0], lonePairs=[0], charge=[-1]) # examples for N5dddc: C=[N-](=C)=[NH2+] atomTypes['N5tc'] = AtomType('N5tc', generic=['R','R!H','N','Val5'], specific=[], # (shared electrons = 7-8) - single=[0,1], allDouble=[0], rDouble=[0], oDouble=[0], sDouble=[0], triple=[1], benzene=[0], lonePairs=[0], charge=[+1]) + single=[0,1], allDouble=[0], rDouble=[0], oDouble=[0], sDouble=[0], triple=[1], quadruple=[], benzene=[0], lonePairs=[0], charge=[+1]) # examples for N5tc: C[N+]#[C-] isocyano group, N#[N+][O-], [NH+]#[C-] (note that C- has p1 here), [N+]#[C-] (note that C- has p1 here), [O-][N+]#C (one of the res structures of Fulminic acid), C[N+]#[C-] (note that C- has p1 here) atomTypes['N5b' ] = AtomType('N5b', generic=['R','R!H','N','Val5'], specific=[], - single=[0,1], allDouble=[0], rDouble=[0], oDouble=[0], sDouble=[0], triple=[0], benzene=[2], lonePairs=[0], charge=[0,+1]) + single=[0,1], allDouble=[0], rDouble=[0], oDouble=[0], sDouble=[0], triple=[0], quadruple=[], benzene=[2], lonePairs=[0], charge=[0,+1]) # examples for N5b: Pyrrole, Indole, Benzimidazole, Purine; Note that this is the only N atomType with valence 5 which isn't necessarily charged. atomTypes['N5bd'] = AtomType('N5bd', generic=['R','R!H','N','Val5'], specific=[], - single=[0], allDouble=[1], rDouble=[], oDouble=[], sDouble=[], triple=[0], benzene=[2], lonePairs=[0], charge=[0]) + single=[0], allDouble=[1], rDouble=[], oDouble=[], sDouble=[], triple=[0], quadruple=[], benzene=[2], lonePairs=[0], charge=[0]) # examples for N5bd: AdjList """1 N u0 p0 c0 {2,B} {6,B} {7,D} 2 C u0 p0 {1,B} {3,B} {8,S} 3 C u0 p0 {2,B} {4,B} {9,S} 4 C u0 p0 {3,B} {5,B} {10,S} 5 C u0 p0 {4,B} {6,B} {11,S} 6 N u0 p1 {1,B} {5,B} 7 O u0 p2 c0 {1,D} 8 H u0 p0 {2,S} 9 H u0 p0 {3,S} 10 H u0 p0 {4,S} 11 H u0 p0 {5,S}""" atomTypes['O' ] = AtomType('O', generic=['R','R!H','Val6'], specific=['Oa','O0sc','O2s','O2sc','O2d','O4sc','O4dc','O4tc','O4b'], - single=[], allDouble=[], rDouble=[], oDouble=[], sDouble=[], triple=[], benzene=[], lonePairs=[], charge=[]) + single=[], allDouble=[], rDouble=[], oDouble=[], sDouble=[], triple=[], quadruple=[], benzene=[], lonePairs=[], charge=[]) atomTypes['Oa' ] = AtomType('Oa', generic=['R','R!H','O','Val6'], specific=[], # (shared electrons = 6) - single=[0], allDouble=[0], rDouble=[], oDouble=[], sDouble=[], triple=[0], benzene=[0], lonePairs=[3], charge=[0]) + single=[0], allDouble=[0], rDouble=[], oDouble=[], sDouble=[], triple=[0], quadruple=[0], benzene=[0], lonePairs=[3], charge=[0]) # examples for Oa: atomic oxygen (closed shell) atomTypes['O0sc'] = AtomType('O0sc', generic=['R','R!H','O','Val6'], specific=[], # (shared electrons = 8) - single=[0,1], allDouble=[0], rDouble=[], oDouble=[], sDouble=[], triple=[0], benzene=[0], lonePairs=[3], charge=[-1]) + single=[0,1], allDouble=[0], rDouble=[], oDouble=[], sDouble=[], triple=[0], quadruple=[], benzene=[0], lonePairs=[3], charge=[-1]) # examples for O0sc: Nitric acid O[N+](=O)([O-]) atomTypes['O2s' ] = AtomType('O2s', generic=['R','R!H','O','Val6'], specific=[], # (shared electrons = 8) - single=[0,1,2], allDouble=[0], rDouble=[], oDouble=[], sDouble=[], triple=[0], benzene=[0], lonePairs=[2], charge=[0]) + single=[0,1,2], allDouble=[0], rDouble=[], oDouble=[], sDouble=[], triple=[0], quadruple=[], benzene=[0], lonePairs=[2], charge=[0]) # examples for O2s: H2O, OH, CH3OH atomTypes['O2sc'] = AtomType('O2sc', generic=['R','R!H','O','Val6'], specific=[], # (shared electrons = 6) - single=[0,1], allDouble=[0], rDouble=[], oDouble=[], sDouble=[], triple=[0], benzene=[0], lonePairs=[2], charge=[+1]) + single=[0,1], allDouble=[0], rDouble=[], oDouble=[], sDouble=[], triple=[0], quadruple=[], benzene=[0], lonePairs=[2], charge=[+1]) # examples for O2sc: C=[S-][O+] atomTypes['O2d' ] = AtomType('O2d', generic=['R','R!H','O','Val6'], specific=[], # (shared electrons = 8) - single=[0], allDouble=[1], rDouble=[], oDouble=[], sDouble=[], triple=[0], benzene=[0], lonePairs=[2], charge=[0]) + single=[0], allDouble=[1], rDouble=[], oDouble=[], sDouble=[], triple=[0], quadruple=[], benzene=[0], lonePairs=[2], charge=[0]) # examples for O2d: CO2, CH2O atomTypes['O4sc'] = AtomType('O4sc', generic=['R','R!H','O','Val6'], specific=[], # (shared electrons = 5-8) - single=[0,1,2,3], allDouble=[0], rDouble=[], oDouble=[], sDouble=[], triple=[0], benzene=[0], lonePairs=[1], charge=[+1]) + single=[0,1,2,3], allDouble=[0], rDouble=[], oDouble=[], sDouble=[], triple=[0], quadruple=[], benzene=[0], lonePairs=[1], charge=[+1]) # examples for O4sc: [O-][OH+]C atomTypes['O4dc'] = AtomType('O4dc', generic=['R','R!H','O','Val6'], specific=[], # (shared electrons = 7-8) - single=[0,1], allDouble=[1], rDouble=[], oDouble=[], sDouble=[], triple=[0], benzene=[0], lonePairs=[1], charge=[+1]) + single=[0,1], allDouble=[1], rDouble=[], oDouble=[], sDouble=[], triple=[0], quadruple=[], benzene=[0], lonePairs=[1], charge=[+1]) # examples for O4dc: the positively charged O in ozone [O-][O+]=O atomTypes['O4tc'] = AtomType('O4tc', generic=['R','R!H','O','Val6'], specific=[], # (shared electrons = 8) - single=[0], allDouble=[0], rDouble=[], oDouble=[], sDouble=[], triple=[1], benzene=[0], lonePairs=[1], charge=[+1]) + single=[0], allDouble=[0], rDouble=[], oDouble=[], sDouble=[], triple=[1], quadruple=[], benzene=[0], lonePairs=[1], charge=[+1]) # examples for O4tc: [C-]#[O+] atomTypes['O4b' ] = AtomType('O4b', generic=['R','R!H','O','Val6'], specific=[], - single=[0], allDouble=[0], rDouble=[0], oDouble=[0], sDouble=[0], triple=[0], benzene=[2], lonePairs=[1], charge=[0]) + single=[0], allDouble=[0], rDouble=[0], oDouble=[0], sDouble=[0], triple=[0], quadruple=[], benzene=[2], lonePairs=[1], charge=[0]) # examples for S4b: Furane, Benzofurane, Benzo[c]thiophene, Oxazole... -atomTypes['Si' ] = AtomType('Si', generic=['R','R!H','Val4'], specific=['Sis','Sid','Sidd','Sit','SiO','Sib','Sibf'], - single=[], allDouble=[], rDouble=[], oDouble=[], sDouble=[], triple=[], benzene=[], lonePairs=[], charge=[]) +atomTypes['Ne' ] = AtomType('Ne', generic=['R','R!H'], specific=[]) +atomTypes['Si' ] = AtomType('Si', generic=['R','R!H','Val4'], specific=['Sis','Sid','Sidd','Sit','SiO','Sib','Sibf','Siq'], + single=[], allDouble=[], rDouble=[], oDouble=[], sDouble=[], triple=[], quadruple=[], benzene=[], lonePairs=[], charge=[]) atomTypes['Sis' ] = AtomType('Sis', generic=['R','R!H','Si','Val4'], specific=[], - single=[], allDouble=[0], rDouble=[], oDouble=[], sDouble=[], triple=[0], benzene=[0], lonePairs=[], charge=[]) + single=[], allDouble=[0], rDouble=[], oDouble=[], sDouble=[], triple=[0], quadruple=[], benzene=[0], lonePairs=[], charge=[]) atomTypes['SiO' ] = AtomType('SiO', generic=['R','R!H','Si','Val4'], specific=[], - single=[], allDouble=[1], rDouble=[], oDouble=[1], sDouble=[], triple=[0], benzene=[0], lonePairs=[], charge=[]) + single=[], allDouble=[1], rDouble=[], oDouble=[1], sDouble=[], triple=[0], quadruple=[], benzene=[0], lonePairs=[], charge=[]) atomTypes['Sid' ] = AtomType('Sid', generic=['R','R!H','Si','Val4'], specific=[], - single=[], allDouble=[1], rDouble=[], oDouble=[0], sDouble=[], triple=[0], benzene=[0], lonePairs=[], charge=[]) + single=[], allDouble=[1], rDouble=[], oDouble=[0], sDouble=[], triple=[0], quadruple=[], benzene=[0], lonePairs=[], charge=[]) atomTypes['Sidd'] = AtomType('Sidd', generic=['R','R!H','Si','Val4'], specific=[], - single=[], allDouble=[2], rDouble=[0,1,2], oDouble=[0,1,2], sDouble=[0,1,2], triple=[0], benzene=[0], lonePairs=[], charge=[]) + single=[], allDouble=[2], rDouble=[0,1,2], oDouble=[0,1,2], sDouble=[0,1,2], triple=[0], quadruple=[], benzene=[0], lonePairs=[], charge=[]) atomTypes['Sit' ] = AtomType('Sit', generic=['R','R!H','Si','Val4'], specific=[], - single=[], allDouble=[0], rDouble=[], oDouble=[], sDouble=[], triple=[1], benzene=[0], lonePairs=[], charge=[]) + single=[], allDouble=[0], rDouble=[], oDouble=[], sDouble=[], triple=[1], quadruple=[], benzene=[0], lonePairs=[], charge=[]) atomTypes['Sib' ] = AtomType('Sib', generic=['R','R!H','Si','Val4'], specific=[], - single=[], allDouble=[0], rDouble=[], oDouble=[], sDouble=[], triple=[0], benzene=[2], lonePairs=[], charge=[]) + single=[], allDouble=[0], rDouble=[], oDouble=[], sDouble=[], triple=[0], quadruple=[], benzene=[2], lonePairs=[], charge=[]) atomTypes['Sibf'] = AtomType('Sibf', generic=['R','R!H','Si','Val4'], specific=[], - single=[], allDouble=[0], rDouble=[], oDouble=[], sDouble=[], triple=[0], benzene=[3], lonePairs=[], charge=[]) + single=[], allDouble=[0], rDouble=[], oDouble=[], sDouble=[], triple=[0], quadruple=[], benzene=[3], lonePairs=[], charge=[]) +atomTypes['Siq' ] = AtomType('Siq', generic=['R','R!H','Si','Val4'], specific=[], + single=[0], allDouble=[0], rDouble=[0], oDouble=[0], sDouble=[0], triple=[0], quadruple=[1], benzene=[0], lonePairs=[], charge=[]) atomTypes['S' ] = AtomType('S', generic=['R','R!H','Val6'], specific=['Sa','S0sc','S2s','S2sc','S2d','S2dc','S2tc','S4s','S4sc','S4d','S4dd','S4dc','S4b','S4t','S4tdc','S6s','S6sc','S6d','S6dd','S6ddd','S6dc','S6t','S6td','S6tt','S6tdc'], - single=[], allDouble=[], rDouble=[], oDouble=[], sDouble=[], triple=[], benzene=[], lonePairs=[], charge=[]) + single=[], allDouble=[], rDouble=[], oDouble=[], sDouble=[], triple=[], quadruple=[], benzene=[], lonePairs=[], charge=[]) atomTypes['Sa' ] = AtomType('Sa', generic=['R','R!H','S','Val6'], specific=[], # (shared electrons = 6) - single=[0], allDouble=[0], rDouble=[0], oDouble=[0], sDouble=[0], triple=[0], benzene=[0], lonePairs=[3], charge=[0]) + single=[0], allDouble=[0], rDouble=[0], oDouble=[0], sDouble=[0], triple=[0], quadruple=[], benzene=[0], lonePairs=[3], charge=[0]) # examples for Sa: atomic sulfur (closed shell) atomTypes['S0sc'] = AtomType('S0sc', generic=['R','R!H','S','Val6'], specific=[], # (shared electrons = 7-8) - single=[0,1], allDouble=[0], rDouble=[], oDouble=[], sDouble=[], triple=[0], benzene=[0], lonePairs=[3], charge=[-1]) + single=[0,1], allDouble=[0], rDouble=[], oDouble=[], sDouble=[], triple=[0], quadruple=[], benzene=[0], lonePairs=[3], charge=[-1]) # examples for S0sc: [S-][S+]=S atomTypes['S2s' ] = AtomType('S2s', generic=['R','R!H','S','Val6'], specific=[], # (shared electrons = 6-8) - single=[0,1,2], allDouble=[0], rDouble=[0], oDouble=[0], sDouble=[0], triple=[0], benzene=[0], lonePairs=[2], charge=[0]) + single=[0,1,2], allDouble=[0], rDouble=[0], oDouble=[0], sDouble=[0], triple=[0], quadruple=[], benzene=[0], lonePairs=[2], charge=[0]) # examples for S2s: [S], [SH], S {H2S}, [S][S], SS {H2S2}, SSC, CSSC, SO {HSOH}... atomTypes['S2sc'] = AtomType('S2sc', generic=['R','R!H','S','Val6'], specific=[], # (shared electrons = 7-10) - single=[0,1,2,3], allDouble=[0], rDouble=[0], oDouble=[0], sDouble=[0], triple=[0], benzene=[0], lonePairs=[2], charge=[-1,+1]) + single=[0,1,2,3], allDouble=[0], rDouble=[0], oDouble=[0], sDouble=[0], triple=[0], quadruple=[], benzene=[0], lonePairs=[2], charge=[-1,+1]) # examples for S2sc: N#[N+][S-](O)O atomTypes['S2d' ] = AtomType('S2d', generic=['R','R!H','S','Val6'], specific=[], # (shared electrons = 8) - single=[0], allDouble=[1], rDouble=[], oDouble=[], sDouble=[], triple=[0], benzene=[0], lonePairs=[2], charge=[0]) + single=[0], allDouble=[1], rDouble=[], oDouble=[], sDouble=[], triple=[0], quadruple=[], benzene=[0], lonePairs=[2], charge=[0]) # examples for S2d: S=S, C=S, S=O, S=N, S=C=S, S=C=O, S=C=S... atomTypes['S2dc'] = AtomType('S2dc', generic=['R','R!H','S','Val6'], specific=[], - single=[0,1], allDouble=[1,2], rDouble=[], oDouble=[], sDouble=[], triple=[0], benzene=[0], lonePairs=[2], charge=[-1]) + single=[0,1], allDouble=[1,2], rDouble=[], oDouble=[], sDouble=[], triple=[0], quadruple=[], benzene=[0], lonePairs=[2], charge=[-1]) # *Composite atomType; examples for S2dc: [SH-]=[N+] atomTypes['S2tc'] = AtomType('S2tc', generic=['R','R!H','S','Val6'], specific=[], # (shared electrons = 10) - single=[0], allDouble=[0], rDouble=[], oDouble=[], sDouble=[], triple=[1], benzene=[0], lonePairs=[2], charge=[-1]) + single=[0], allDouble=[0], rDouble=[], oDouble=[], sDouble=[], triple=[1], quadruple=[], benzene=[0], lonePairs=[2], charge=[-1]) # examples for S2tc: [S-]#[NH+] atomTypes['S4s' ] = AtomType('S4s', generic=['R','R!H','S','Val6'], specific=[], # (shared electrons = 6-10) - single=[0,1,2,3,4], allDouble=[0], rDouble=[0], oDouble=[0], sDouble=[0], triple=[0], benzene=[0], lonePairs=[1], charge=[0]) + single=[0,1,2,3,4], allDouble=[0], rDouble=[0], oDouble=[0], sDouble=[0], triple=[0], quadruple=[], benzene=[0], lonePairs=[1], charge=[0]) # examples for S4s: H4S, SH3CH3... atomTypes['S4sc'] = AtomType('S4sc', generic=['R','R!H','S','Val6'], specific=[], # (shared electrons = 5-8) - single=[0,1,2,3,4,5], allDouble=[0], rDouble=[0], oDouble=[0], sDouble=[0], triple=[0], benzene=[0], lonePairs=[1], charge=[-1,+1]) + single=[0,1,2,3,4,5], allDouble=[0], rDouble=[0], oDouble=[0], sDouble=[0], triple=[0], quadruple=[], benzene=[0], lonePairs=[1], charge=[-1,+1]) # examples for S4sc: CS[S+]([O-])C, O[SH..-][N+]#N atomTypes['S4d' ] = AtomType('S4d', generic=['R','R!H','S','Val6'], specific=[], # (shared electrons = 8-10) - single=[0,1,2], allDouble=[1], rDouble=[], oDouble=[], sDouble=[], triple=[0], benzene=[0], lonePairs=[1], charge=[0]) + single=[0,1,2], allDouble=[1], rDouble=[], oDouble=[], sDouble=[], triple=[0], quadruple=[], benzene=[0], lonePairs=[1], charge=[0]) # examples for S4d: O=S(O)O {Sulfurous acid} atomTypes['S4dd'] = AtomType('S4dd', generic=['R','R!H','S','Val6'], specific=[], # (shared electrons = 10) - single=[0], allDouble=[2], rDouble=[], oDouble=[], sDouble=[], triple=[0], benzene=[0], lonePairs=[1], charge=[0]) + single=[0], allDouble=[2], rDouble=[], oDouble=[], sDouble=[], triple=[0], quadruple=[], benzene=[0], lonePairs=[1], charge=[0]) # examples for S4dd: O=S=O atomTypes['S4dc'] = AtomType('S4dc', generic=['R','R!H','S','Val6'], specific=[], - single=[0,1,2,3,4,5], allDouble=[1,2], rDouble=[], oDouble=[], sDouble=[], triple=[0], benzene=[0], lonePairs=[1], charge=[-1,+1]) + single=[0,1,2,3,4,5], allDouble=[1,2], rDouble=[], oDouble=[], sDouble=[], triple=[0], quadruple=[], benzene=[0], lonePairs=[1], charge=[-1,+1]) # *Composite atomType; examples for S4dc: [CH2-][S+]=C {where the [CH2-] has a lone pair}, [O+][S-](=O)=O, [O-][S+]=C, [NH-][S+]=C {where the [NH-] has two lone pairs}, [O-][S+]=O atomTypes['S4b' ] = AtomType('S4b', generic=['R','R!H','S','Val6'], specific=[], - single=[0], allDouble=[0], rDouble=[0], oDouble=[0], sDouble=[0], triple=[0], benzene=[2], lonePairs=[1], charge=[0]) + single=[0], allDouble=[0], rDouble=[0], oDouble=[0], sDouble=[0], triple=[0], quadruple=[], benzene=[2], lonePairs=[1], charge=[0]) # examples for S4b: Thiophene, Benzothiophene, Benzo[c]thiophene, Thiazole, Benzothiazole... atomTypes['S4t' ] = AtomType('S4t', generic=['R','R!H','S','Val6'], specific=[], # (shared electrons = 10) - single=[0,1], allDouble=[0], rDouble=[0], oDouble=[0], sDouble=[0], triple=[1], benzene=[0], lonePairs=[1], charge=[0]) + single=[0,1], allDouble=[0], rDouble=[0], oDouble=[0], sDouble=[0], triple=[1], quadruple=[], benzene=[0], lonePairs=[1], charge=[0]) # examples for S4t: C#S, C#SO, C#[S] atomTypes['S4tdc'] = AtomType('S4tdc',generic=['R','R!H','S','Val6'], specific=[], - single=[0,1,2], allDouble=[0,1,2], rDouble=[], oDouble=[], sDouble=[], triple=[1,2], benzene=[0], lonePairs=[1], charge=[-1,+1]) + single=[0,1,2], allDouble=[0,1,2], rDouble=[], oDouble=[], sDouble=[], triple=[1,2], quadruple=[], benzene=[0], lonePairs=[1], charge=[-1,+1]) # *Composite atomType; examples for S4tdc: [C-]#[S+] atomTypes['S6s' ] = AtomType('S6s', generic=['R','R!H','S','Val6'], specific=[], # (shared electrons = 6-12) - single=[0,1,2,3,4,5,6], allDouble=[0], rDouble=[0], oDouble=[0], sDouble=[0], triple=[0], benzene=[0], lonePairs=[0], charge=[0]) + single=[0,1,2,3,4,5,6], allDouble=[0], rDouble=[0], oDouble=[0], sDouble=[0], triple=[0], quadruple=[0], benzene=[0], lonePairs=[0], charge=[0]) # examples for S6s: H6S, F6S atomTypes['S6sc'] = AtomType('S6sc', generic=['R','R!H','S','Val6'], specific=[], # (shared electrons = 7-14) - single=[0,1,2,3,4,5,6,7], allDouble=[0], rDouble=[0], oDouble=[0], sDouble=[0], triple=[0], benzene=[0], lonePairs=[0], charge=[-1,+1,+2]) + single=[0,1,2,3,4,5,6,7], allDouble=[0], rDouble=[0], oDouble=[0], sDouble=[0], triple=[0], quadruple=[0], benzene=[0], lonePairs=[0], charge=[-1,+1,+2]) # examples for S6sc: [O-][S+2](O)(O)[O-]CS(=O) atomTypes['S6d' ] = AtomType('S6d', generic=['R','R!H','S','Val6'], specific=[], # (shared electrons = 8-12) - single=[0,1,2,3,4], allDouble=[1], rDouble=[], oDouble=[], sDouble=[], triple=[0], benzene=[0], lonePairs=[0], charge=[0]) + single=[0,1,2,3,4], allDouble=[1], rDouble=[], oDouble=[], sDouble=[], triple=[0], quadruple=[], benzene=[0], lonePairs=[0], charge=[0]) # examples for S6d: [SH4]=O, SF4=O, [SH4]=C, C[SH3]=C... atomTypes['S6dd'] = AtomType('S6dd', generic=['R','R!H','S','Val6'], specific=[], # (shared electrons = 10-12) - single=[0,1,2], allDouble=[2], rDouble=[], oDouble=[], sDouble=[], triple=[0], benzene=[0], lonePairs=[0], charge=[0]) + single=[0,1,2], allDouble=[2], rDouble=[], oDouble=[], sDouble=[], triple=[0], quadruple=[], benzene=[0], lonePairs=[0], charge=[0]) # examples for S6dd: S(=O)(=O)(O)O {H2SO4, Sulfuric acid}, Perfluorooctanesulfonic acid, Pyrosulfuric acid, Thiosulfuric acid {middle S}, OS(=O)(=O)OOS(=O)(=O)O atomTypes['S6ddd'] = AtomType('S6ddd', generic=['R','R!H','S','Val6'], specific=[], # (shared electrons = 12) - single=[0], allDouble=[3], rDouble=[], oDouble=[], sDouble=[], triple=[0], benzene=[0], lonePairs=[0], charge=[0]) + single=[0], allDouble=[3], rDouble=[], oDouble=[], sDouble=[], triple=[0], quadruple=[], benzene=[0], lonePairs=[0], charge=[0]) # examples for S6ddd: O=S(=O)(=O) atomTypes['S6dc'] = AtomType('S6dc', generic=['R','R!H','S','Val6'], specific=[], - single=[0,1,2,3,4,5], allDouble=[1,2,3], rDouble=[], oDouble=[], sDouble=[], triple=[0], benzene=[0], lonePairs=[0], charge=[-1,+1,+2]) + single=[0,1,2,3,4,5], allDouble=[1,2,3], rDouble=[], oDouble=[], sDouble=[], triple=[0], quadruple=[0], benzene=[0], lonePairs=[0], charge=[-1,+1,+2]) # *Composite atomType; examples for S6dc: O=[S+2]([O-])[O-], [CH-]=[SH3+], [CH-]=[SH2+]O, [CH-][SH2+], O=[S+](=O)[O-], [OH+]=[S-](=O)=O atomTypes['S6t' ] = AtomType('S6t', generic=['R','R!H','S','Val6'], specific=[], # (shared electrons = 9-12) - single=[0,1,2,3], allDouble=[0], rDouble=[], oDouble=[], sDouble=[], triple=[1], benzene=[0], lonePairs=[0], charge=[0]) + single=[0,1,2,3], allDouble=[0], rDouble=[], oDouble=[], sDouble=[], triple=[1], quadruple=[], benzene=[0], lonePairs=[0], charge=[0]) # examples for S6t: H3S#N atomTypes['S6td'] = AtomType('S6td', generic=['R','R!H','S','Val6'], specific=[], # (shared electrons = 11-12) - single=[0,1], allDouble=[1], rDouble=[], oDouble=[], sDouble=[], triple=[1], benzene=[0], lonePairs=[0], charge=[0]) + single=[0,1], allDouble=[1], rDouble=[], oDouble=[], sDouble=[], triple=[1], quadruple=[], benzene=[0], lonePairs=[0], charge=[0]) # examples for S6td: HS(=O)#N atomTypes['S6tt'] = AtomType('S6tt', generic=['R','R!H','S','Val6'], specific=[], # (shared electrons = 12) - single=[0], allDouble=[0], rDouble=[], oDouble=[], sDouble=[], triple=[2], benzene=[0], lonePairs=[0], charge=[0]) + single=[0], allDouble=[0], rDouble=[], oDouble=[], sDouble=[], triple=[2], quadruple=[], benzene=[0], lonePairs=[0], charge=[0]) # examples for S6tt: N#S#N atomTypes['S6tdc'] = AtomType('S6tdc',generic=['R','R!H','S','Val6'], specific=[], - single=[0,1,2,3,4], allDouble=[0,1,2], rDouble=[], oDouble=[], sDouble=[], triple=[1,2], benzene=[0], lonePairs=[0], charge=[-1,+1]) + single=[0,1,2,3,4], allDouble=[0,1,2], rDouble=[], oDouble=[], sDouble=[], triple=[1,2], quadruple=[], benzene=[0], lonePairs=[0], charge=[-1,+1]) # *Composite atomType; examples for S6tdc: [SH2+]#[C-], [N-]=[S+]#N atomTypes['Cl' ] = AtomType('Cl', generic=['R','R!H','Val7'], specific=['Cl1s']) atomTypes['Cl1s'] = AtomType('Cl1s', generic=['R','R!H','Cl','Val7'], specific=[], - single=[0,1], allDouble=[0], rDouble=[], oDouble=[], sDouble=[], triple=[0], benzene=[0], lonePairs=[3], charge=[0]) + single=[0,1], allDouble=[0], rDouble=[], oDouble=[], sDouble=[], triple=[0], quadruple=[0], benzene=[0], lonePairs=[3], charge=[0]) # examples for Cl1s: HCl, [Cl] +atomTypes['Ar' ] = AtomType('Ar', generic=['R','R!H'], specific=[]) atomTypes['I' ] = AtomType('I', generic=['R','R!H','Val7'], specific=['I1s']) atomTypes['I1s'] = AtomType('I1s', generic=['R','R!H','I','Val7'], specific=[], - single=[0,1], allDouble=[0], rDouble=[], oDouble=[], sDouble=[], triple=[0], benzene=[0], lonePairs=[3], charge=[0]) + single=[0,1], allDouble=[0], rDouble=[], oDouble=[], sDouble=[], triple=[0], quadruple=[0], benzene=[0], lonePairs=[3], charge=[0]) # examples for I1s: HI, [I], IO, CH3I, I2 atomTypes['F' ] = AtomType('F', generic=['R','R!H','Val7'], specific=['F1s']) @@ -543,7 +557,7 @@ def getFeatures(self): atomTypes['CO' ].setActions(incrementBond=['Cdd','C2tc'], decrementBond=['Cs'], formBond=['CO','Cdc'], breakBond=['CO'], incrementRadical=['CO'], decrementRadical=['CO'], incrementLonePair=['C2d'], decrementLonePair=[]) atomTypes['CS' ].setActions(incrementBond=['Cdd','C2tc'], decrementBond=['Cs'], formBond=['CS','Cdc'], breakBond=['CS'], incrementRadical=['CS'], decrementRadical=['CS'], incrementLonePair=['C2d'], decrementLonePair=[]) atomTypes['Cdd' ].setActions(incrementBond=[], decrementBond=['Cd','CO','CS'], formBond=[], breakBond=[], incrementRadical=[], decrementRadical=[], incrementLonePair=[], decrementLonePair=[]) -atomTypes['Ct' ].setActions(incrementBond=[], decrementBond=['Cd','CO','CS'], formBond=['Ct'], breakBond=['Ct'], incrementRadical=['Ct'], decrementRadical=['Ct'], incrementLonePair=['C2tc'],decrementLonePair=[]) +atomTypes['Ct' ].setActions(incrementBond=['Cq'], decrementBond=['Cd','CO','CS'], formBond=['Ct'], breakBond=['Ct'], incrementRadical=['Ct'], decrementRadical=['Ct'], incrementLonePair=['C2tc'],decrementLonePair=[]) atomTypes['Cb' ].setActions(incrementBond=['Cbf'], decrementBond=[], formBond=['Cb'], breakBond=['Cb'], incrementRadical=['Cb'], decrementRadical=['Cb'], incrementLonePair=[], decrementLonePair=[]) atomTypes['Cbf' ].setActions(incrementBond=[], decrementBond=['Cb'], formBond=[], breakBond=['Cb'], incrementRadical=[], decrementRadical=[], incrementLonePair=[], decrementLonePair=[]) atomTypes['C2s' ].setActions(incrementBond=['C2d'], decrementBond=[], formBond=['C2s'], breakBond=['C2s'], incrementRadical=['C2s'], decrementRadical=['C2s'], incrementLonePair=['Ca'], decrementLonePair=['Cs']) @@ -551,6 +565,7 @@ def getFeatures(self): atomTypes['C2d' ].setActions(incrementBond=['C2tc'], decrementBond=['C2s'], formBond=['C2dc'], breakBond=[], incrementRadical=[], decrementRadical=[], incrementLonePair=[], decrementLonePair=['Cd','CO','CS']) atomTypes['C2dc'].setActions(incrementBond=[], decrementBond=['C2sc'], formBond=[], breakBond=['C2d'], incrementRadical=[], decrementRadical=[], incrementLonePair=[], decrementLonePair=['Cdc']) atomTypes['C2tc'].setActions(incrementBond=[], decrementBond=['C2d'], formBond=[], breakBond=[], incrementRadical=[], decrementRadical=[], incrementLonePair=[], decrementLonePair=['Ct']) +atomTypes['Cq' ].setActions(incrementBond=[], decrementBond=['Ct'], formBond=[], breakBond=[], incrementRadical=[], decrementRadical=[], incrementLonePair=[], decrementLonePair=[]) atomTypes['N' ].setActions(incrementBond=['N'], decrementBond=['N'], formBond=['N'], breakBond=['N'], incrementRadical=['N'], decrementRadical=['N'], incrementLonePair=['N'], decrementLonePair=['N']) atomTypes['N0sc'].setActions(incrementBond=[], decrementBond=[], formBond=['N0sc'], breakBond=['N0sc'], incrementRadical=['N0sc'], decrementRadical=['N0sc'], incrementLonePair=[], decrementLonePair=['N1s','N1sc']) @@ -581,14 +596,17 @@ def getFeatures(self): atomTypes['O4tc'].setActions(incrementBond=[], decrementBond=['O4dc'], formBond=[], breakBond=[], incrementRadical=[], decrementRadical=[], incrementLonePair=[], decrementLonePair=[]) atomTypes['O4b' ].setActions(incrementBond=[], decrementBond=[], formBond=[], breakBond=[], incrementRadical=[], decrementRadical=[], incrementLonePair=[], decrementLonePair=[]) +atomTypes['Ne' ].setActions(incrementBond=[], decrementBond=[], formBond=[], breakBond=[], incrementRadical=['Ne'], decrementRadical=['Ne'], incrementLonePair=[], decrementLonePair=[]) + atomTypes['Si' ].setActions(incrementBond=['Si'], decrementBond=['Si'], formBond=['Si'], breakBond=['Si'], incrementRadical=['Si'], decrementRadical=['Si'], incrementLonePair=[], decrementLonePair=[]) atomTypes['Sis' ].setActions(incrementBond=['Sid','SiO'], decrementBond=[], formBond=['Sis'], breakBond=['Sis'], incrementRadical=['Sis'], decrementRadical=['Sis'], incrementLonePair=[], decrementLonePair=[]) atomTypes['Sid' ].setActions(incrementBond=['Sidd','Sit'], decrementBond=['Sis'], formBond=['Sid'], breakBond=['Sid'], incrementRadical=['Sid'], decrementRadical=['Sid'], incrementLonePair=[], decrementLonePair=[]) atomTypes['Sidd'].setActions(incrementBond=[], decrementBond=['Sid','SiO'], formBond=[], breakBond=[], incrementRadical=[], decrementRadical=[], incrementLonePair=[], decrementLonePair=[]) -atomTypes['Sit' ].setActions(incrementBond=[], decrementBond=['Sid'], formBond=['Sit'], breakBond=['Sit'], incrementRadical=['Sit'], decrementRadical=['Sit'], incrementLonePair=[], decrementLonePair=[]) +atomTypes['Sit' ].setActions(incrementBond=['Siq'], decrementBond=['Sid'], formBond=['Sit'], breakBond=['Sit'], incrementRadical=['Sit'], decrementRadical=['Sit'], incrementLonePair=[], decrementLonePair=[]) atomTypes['SiO' ].setActions(incrementBond=['Sidd'], decrementBond=['Sis'], formBond=['SiO'], breakBond=['SiO'], incrementRadical=['SiO'], decrementRadical=['SiO'], incrementLonePair=[], decrementLonePair=[]) atomTypes['Sib' ].setActions(incrementBond=[], decrementBond=[], formBond=['Sib'], breakBond=['Sib'], incrementRadical=['Sib'], decrementRadical=['Sib'], incrementLonePair=[], decrementLonePair=[]) atomTypes['Sibf'].setActions(incrementBond=[], decrementBond=[], formBond=[], breakBond=[], incrementRadical=[], decrementRadical=[], incrementLonePair=[], decrementLonePair=[]) +atomTypes['Siq' ].setActions(incrementBond=[], decrementBond=['Sit'], formBond=[], breakBond=[], incrementRadical=[], decrementRadical=[], incrementLonePair=[], decrementLonePair=[]) atomTypes['S' ].setActions(incrementBond=['S'], decrementBond=['S'], formBond=['S'], breakBond=['S'], incrementRadical=['S'], decrementRadical=['S'], incrementLonePair=['S'], decrementLonePair=['S']) atomTypes['S0sc'].setActions(incrementBond=['S0sc'], decrementBond=['S0sc'], formBond=['S0sc'], breakBond=['Sa','S0sc'], incrementRadical=['S0sc'], decrementRadical=['S0sc'], incrementLonePair=[], decrementLonePair=['S2s','S2sc','S2dc','S2tc']) @@ -633,8 +651,9 @@ def getFeatures(self): for atomType in atomTypes.values(): for items in [atomType.generic, atomType.specific, - atomType.incrementBond, atomType.decrementBond, atomType.formBond, - atomType.breakBond, atomType.incrementRadical, atomType.decrementRadical, atomType.incrementLonePair, atomType.decrementLonePair]: + atomType.incrementBond, atomType.decrementBond, atomType.formBond, + atomType.breakBond, atomType.incrementRadical, atomType.decrementRadical, atomType.incrementLonePair, + atomType.decrementLonePair]: for index in range(len(items)): items[index] = atomTypes[items[index]] @@ -644,15 +663,20 @@ def getFeatures(atom, bonds): Returns a list of features needed to determine atomType for :class:'Atom' or :class:'GroupAtom' object 'atom and with local bond structure `bonds`, a ``dict`` containing atom-bond pairs. - """ cython.declare(single=cython.int, allDouble=cython.int, rDouble=cython.int, sDouble=cython.int, oDouble=cython.int, triple=cython.int, - benzene=cython.int) + benzene=cython.int, quadruple=cython.int) cython.declare(features=cython.list) # Count numbers of each higher-order bond type - single = 0; rDouble = 0; oDouble = 0; sDouble = 0; triple = 0; benzene = 0 + single = 0; + rDouble = 0; + oDouble = 0; + sDouble = 0; + triple = 0; + benzene = 0; + quadruple = 0 for atom2, bond12 in bonds.iteritems(): if bond12.isSingle(): single += 1 @@ -664,12 +688,18 @@ def getFeatures(atom, bonds): else: # rDouble is for double bonds NOT to oxygen or Sulfur rDouble += 1 - elif bond12.isTriple(): triple += 1 - elif bond12.isBenzene(): benzene += 1 + elif bond12.isTriple(): + triple += 1 + elif bond12.isBenzene(): + benzene += 1 + elif bond12.isQuadruple(): + quadruple += 1 # allDouble is for all double bonds, to anything allDouble = rDouble + oDouble + sDouble - features = [single, allDouble, rDouble, oDouble, sDouble, triple, benzene, atom.lonePairs, atom.charge] + # Warning: some parts of code assume this list matches the list returned by countBonds() + # possibly the two methods could be merged or one could call the other. + features = [single, allDouble, rDouble, oDouble, sDouble, triple, quadruple, benzene, atom.lonePairs, atom.charge] return features @@ -704,11 +734,11 @@ def getAtomType(atom, bonds): oDouble = molFeatureList[3] sDouble = molFeatureList[4] triple = molFeatureList[5] - benzene = molFeatureList[6] - lonePairs = molFeatureList[7] - charge = molFeatureList[8] + quadruple = molFeatureList[6] + benzene = molFeatureList[7] + lonePairs = molFeatureList[8] + charge = molFeatureList[9] raise AtomTypeError( 'Unable to determine atom type for atom {0}, which has {1:d} single bonds, {2:d} double bonds to C, {3:d} double bonds to O, {4:d} double bonds to S, {5:d} triple bonds, {6:d} benzene bonds, {7:d} lone pairs, and {8:d} charge.'.format( - atom, single, rDouble, oDouble, sDouble, triple, benzene, lonePairs, charge)) - + atom, single, rDouble, oDouble, sDouble, triple, quadruple, benzene, lonePairs, charge)) diff --git a/rmgpy/molecule/atomtypeTest.py b/rmgpy/molecule/atomtypeTest.py index 2e9f6d2703..20bd6e4cd2 100644 --- a/rmgpy/molecule/atomtypeTest.py +++ b/rmgpy/molecule/atomtypeTest.py @@ -523,7 +523,7 @@ def testCarbonTypes(self): self.assertEqual(self.atomType(self.mol59, 0), 'C2dc') self.assertEqual(self.atomType(self.mol60, 2), 'C2dc') self.assertEqual(self.atomType(self.mol20, 0), 'C2tc') - self.assertEqual(self.atomType(self.mol29, 0), 'C2tc') + self.assertEqual(self.atomType(self.mol29, 0), 'C2tc') # todo: add in a ciq unit test? def testNitrogenTypes(self): """ @@ -571,7 +571,7 @@ def testSiliconTypes(self): self.assertEqual(self.atomType(self.mol4, 1), 'SiO') self.assertEqual(self.atomType(self.mol4, 5), 'Sid') self.assertEqual(self.atomType(self.mol4, 4), 'Sidd') - self.assertEqual(self.atomType(self.mol4, 7), 'Sit') + self.assertEqual(self.atomType(self.mol4, 7), 'Sit') #todo: add in Siq unit test? def testSulfurTypes(self): """ diff --git a/rmgpy/molecule/atomtypedatabase.py b/rmgpy/molecule/atomtypedatabase.py index 021c9755df..bea1cc2cbe 100644 --- a/rmgpy/molecule/atomtypedatabase.py +++ b/rmgpy/molecule/atomtypedatabase.py @@ -34,11 +34,12 @@ """ class AbstractAtomType(object): - def __init__(self, element = None, label=None, double=-1, triple=-1, benzene=-1, lp=-1, chrg=-1): + def __init__(self, element = None, label=None, double=-1, triple=-1, quadruple=-1, benzene=-1, lp=-1, chrg=-1): self.element = element self.label = label self.double = double self.triple = triple + self.quadruple = quadruple self.benzene = benzene self.lp = lp self.chrg = chrg @@ -61,37 +62,43 @@ def __init__(self, *args, **kwargs): class Xs(AbstractAtomType): def __init__(self, *args, **kwargs): super(self.__class__, self).__init__(*args, **kwargs) - self.double, self.triple, self.benzene = 0, 0, 0 + self.double, self.triple, self.benzene, self.quadruple = 0, 0, 0, 0 self.label = 's' class Xd(AbstractAtomType): def __init__(self, *args, **kwargs): super(self.__class__, self).__init__(*args, **kwargs) - self.double, self.triple, self.benzene = 1, 0, 0 + self.double, self.triple, self.benzene, self.quadruple = 1, 0, 0, 0 self.label = 'd' class Xdd(AbstractAtomType): def __init__(self, *args, **kwargs): super(self.__class__, self).__init__(*args, **kwargs) - self.double, self.triple, self.benzene = 2, 0, 0 + self.double, self.triple, self.benzene, self.quadruple = 2, 0, 0, 0 self.label = 'dd' class Xt(AbstractAtomType): def __init__(self, *args, **kwargs): super(self.__class__, self).__init__(*args, **kwargs) - self.double, self.triple, self.benzene = 0, 1, 0 + self.double, self.triple, self.benzene, self.quadruple = 0, 1, 0, 0 self.label = 't' +class Xq(AbstractAtomType): + def __init__(self, *args, **kwargs): + super(self.__class__, self).__init__(*args, **kwargs) + self.double, self.triple, self.benzene, self.quadruple = 0, 0, 0, 1 + self.label = 'q' + class Xb(AbstractAtomType): def __init__(self, *args, **kwargs): super(self.__class__, self).__init__(*args, **kwargs) - self.double, self.triple, self.benzene = 0, 0, 2 + self.double, self.triple, self.benzene, self.quadruple = 0, 0, 2, 0 self.label = 'b' class Xbf(AbstractAtomType): def __init__(self, *args, **kwargs): super(self.__class__, self).__init__(*args, **kwargs) - self.double, self.triple, self.benzene = 0, 0, 3 + self.double, self.triple, self.benzene, self.quadruple = 0, 0, 3, 0 self.label = 'bf' def create_atom_types(): diff --git a/rmgpy/molecule/converter.py b/rmgpy/molecule/converter.py index be87c22ba7..75d85b4523 100644 --- a/rmgpy/molecule/converter.py +++ b/rmgpy/molecule/converter.py @@ -81,7 +81,7 @@ def toRDKitMol(mol, removeHs=True, returnMapping=False, sanitize=True): rdAtomIndices[atom] = index rdBonds = Chem.rdchem.BondType - orders = {'S': rdBonds.SINGLE, 'D': rdBonds.DOUBLE, 'T': rdBonds.TRIPLE, 'B': rdBonds.AROMATIC} + orders = {'S': rdBonds.SINGLE, 'D': rdBonds.DOUBLE, 'T': rdBonds.TRIPLE, 'B': rdBonds.AROMATIC, 'Q': rdBonds.QUADRUPLE} # Add the bonds for atom1 in mol.vertices: for atom2, bond in atom1.edges.iteritems(): @@ -154,6 +154,7 @@ def fromRDKitMol(mol, rdkitmol): if rdbondtype.name == 'SINGLE': order = 1 elif rdbondtype.name == 'DOUBLE': order = 2 elif rdbondtype.name == 'TRIPLE': order = 3 + elif rdbondtype.name == 'QUADRUPLE': order = 4 elif rdbondtype.name == 'AROMATIC': order = 1.5 bond = mm.Bond(mol.vertices[i], mol.vertices[j], order) @@ -221,7 +222,7 @@ def toOBMol(mol, returnMapping=False): a.SetIsotope(atom.element.isotope) a.SetFormalCharge(atom.charge) obAtomIds[atom] = a.GetId() - orders = {1: 1, 2: 2, 3: 3, 1.5: 5} + orders = {1: 1, 2: 2, 3: 3, 4: 4, 1.5: 5} for atom1 in mol.vertices: for atom2, bond in atom1.edges.iteritems(): index1 = atoms.index(atom1) @@ -274,7 +275,7 @@ def fromOBMol(mol, obmol): for obbond in openbabel.OBMolBondIter(obmol): # Process bond type oborder = obbond.GetBondOrder() - if oborder not in [1,2,3] and obbond.IsAromatic() : + if oborder not in [1,2,3,4] and obbond.IsAromatic() : oborder = 1.5 bond = mm.Bond(mol.vertices[obbond.GetBeginAtomIdx() - 1], mol.vertices[obbond.GetEndAtomIdx() - 1], oborder)#python array indices start at 0 diff --git a/rmgpy/molecule/draw.py b/rmgpy/molecule/draw.py index 99c5f3a41f..17dcca932a 100644 --- a/rmgpy/molecule/draw.py +++ b/rmgpy/molecule/draw.py @@ -1046,7 +1046,15 @@ def __renderBond(self, atom1, atom2, bond, cr): dv = math.sin(angle + math.pi / 2) if (self.symbols[atom1] != '' or \ self.symbols[atom2] != ''): - if bond.isTriple(): + if bond.isQuadruple(): + # Draw quadruple bond centered on bond axis + du *= 1.5; dv *= 1.5 + self.__drawLine(cr, x1 - du, y1 - dv, x2 - du, y2 - dv) + self.__drawLine(cr, x1 + du, y1 + dv, x2 + du, y2 + dv) + du *= 2.2; dv *= 2.2 + self.__drawLine(cr, x1 - du, y1 - dv, x2 - du, y2 - dv) + self.__drawLine(cr, x1 + du, y1 + dv, x2 + du, y2 + dv) + elif bond.isTriple(): # Draw triple bond centered on bond axis du *= 3; dv *= 3 self.__drawLine(cr, x1 - du, y1 - dv, x2 - du, y2 - dv) @@ -1087,6 +1095,11 @@ def __renderBond(self, atom1, atom2, bond, cr): du *= 3; dv *= 3; dx = 2 * dx / bondLength; dy = 2 * dy / bondLength self.__drawLine(cr, x1 - du + dx, y1 - dv + dy, x2 - du - dx, y2 - dv - dy) self.__drawLine(cr, x1 + du + dx, y1 + dv + dy, x2 + du - dx, y2 + dv - dy, dashed=True) + elif bond.isQuadruple(): + du *= 3; dv *= 3; dx = 2 * dx / bondLength; dy = 2 * dy / bondLength + self.__drawLine(cr, x1 - du + dx, y1 - dv + dy, x2 - du - dx, y2 - dv - dy) + self.__drawLine(cr, x1 + du + dx, y1 + dv + dy, x2 + du - dx, y2 + dv - dy) + self.__drawLine(cr, x1 + 2 * du + dx, y1 + 2 * dv + dy, x2 + 2 * du - dx, y2 + 2 * dv - dy) def __renderAtom(self, symbol, atom, x0, y0, cr, heavyFirst=True, drawLonePairs=False): """ diff --git a/rmgpy/molecule/group.py b/rmgpy/molecule/group.py index 1693c69972..9bd67772d5 100644 --- a/rmgpy/molecule/group.py +++ b/rmgpy/molecule/group.py @@ -499,7 +499,7 @@ def countBonds(self, wildcards = False): options for bond orders will not be counted """ #count up number of bonds - single = 0; rDouble = 0; oDouble = 0; sDouble = 0; triple = 0; benzene = 0 + single = 0; rDouble = 0; oDouble = 0; sDouble = 0; triple = 0; quadruple = 0; benzene = 0 for atom2, bond12 in self.bonds.iteritems(): if not wildcards and len(bond12.order) > 1: continue @@ -515,11 +515,13 @@ def countBonds(self, wildcards = False): # rDouble is for double bonds NOT to oxygen or Sulfur rDouble += 1 if bond12.isTriple(wildcards = True): triple += 1 + if bond12.isQuadruple(wildcards=True): quadruple += 1 if bond12.isBenzene(wildcards = True): benzene += 1 allDouble = rDouble + oDouble + sDouble - return [single, allDouble, rDouble, oDouble, sDouble, triple, benzene] + # Warning: some parts of code assume this matches precisely the list returned by getFeatures() + return [single, allDouble, rDouble, oDouble, sDouble, triple, quadruple, benzene] def makeSampleAtom(self): """ @@ -658,6 +660,8 @@ def getOrderStr(self): values.append('D') elif value == 3: values.append('T') + elif value == 4: + values.append('Q') elif value == 1.5: values.append('B') elif value == 0: @@ -679,6 +683,8 @@ def setOrderStr(self, newOrder): values.append(2) elif value == 'T': values.append(3) + elif value == 'Q': + values.append(4) elif value == 'B': values.append(1.5) elif value == 'H': @@ -752,6 +758,21 @@ def isTriple(self, wildcards = False): else: return abs(self.order[0]-3) <= 1e-9 and len(self.order) == 1 + def isQuadruple(self, wildcards = False): + """ + Return ``True`` if the bond represents a quadruple bond or ``False`` if + not. If `wildcards` is ``False`` we return False anytime there is more + than one bond order, otherwise we return ``True`` if any of the options + are quadruple. + """ + if wildcards: + for order in self.order: + if abs(order-4) <= 1e-9: + return True + else: return False + else: + return abs(self.order[0]-4) <= 1e-9 and len(self.order) == 1 + def isBenzene(self, wildcards = False): """ Return ``True`` if the bond represents a benzene bond or ``False`` if @@ -789,7 +810,7 @@ def __changeBond(self, order): in bond order. `order` is normally 1 or -1, but can be any value """ newOrder = [value + order for value in self.order] - if any([value < 0 or value > 3 for value in newOrder]): + if any([value < 0 or value > 4 for value in newOrder]): raise ActionError('Unable to update Bond due to CHANGE_BOND action: Invalid resulting order "{0}".'.format(newOrder)) # Change any modified benzene orders to the appropriate stable order newOrder = set(newOrder) diff --git a/rmgpy/molecule/groupTest.py b/rmgpy/molecule/groupTest.py index 17f8e9ce98..e1c5a4a1da 100644 --- a/rmgpy/molecule/groupTest.py +++ b/rmgpy/molecule/groupTest.py @@ -354,13 +354,16 @@ def testCountBonds(self): 3 C ux {1,S} {5,D} 4 C u[0,1] {2,B} 5 O u0 {3,D} +6 C u0 {7,Q} +7 C u0 {6,Q} """ test = Group().fromAdjacencyList(adjlist) - #returns a list of [single, allDouble, rDouble, oDouble, sDouble, triple, benzene] - self.assertListEqual([1,0,0,0,0,0,0], test.atoms[0].countBonds()) - self.assertListEqual([1,1,1,0,0,1,0], test.atoms[0].countBonds(wildcards = True)) - self.assertListEqual([0,0,0,0,0,0,1], test.atoms[3].countBonds()) - self.assertListEqual([1,1,0,1,0,0,0], test.atoms[2].countBonds()) + #returns a list of [single, allDouble, rDouble, oDouble, sDouble, triple, quadruple, benzene] + self.assertListEqual([1,0,0,0,0,0,0,0], test.atoms[0].countBonds()) + self.assertListEqual([1,1,1,0,0,1,0,0], test.atoms[0].countBonds(wildcards = True)) + self.assertListEqual([0,0,0,0,0,0,0,1], test.atoms[3].countBonds()) + self.assertListEqual([1,1,0,1,0,0,0,0], test.atoms[2].countBonds()) + self.assertListEqual([0,0,0,0,0,0,1,0], test.atoms[5].countBonds()) def testHasWildcards(self): """ diff --git a/rmgpy/molecule/molecule.pxd b/rmgpy/molecule/molecule.pxd index 3c37d9d453..59c3544082 100644 --- a/rmgpy/molecule/molecule.pxd +++ b/rmgpy/molecule/molecule.pxd @@ -115,6 +115,8 @@ cdef class Bond(Edge): cpdef bint isTriple(self) except -2 + cpdef bint isQuadruple(self) except -2 + cpdef bint isBenzene(self) except -2 cpdef incrementOrder(self) diff --git a/rmgpy/molecule/molecule.py b/rmgpy/molecule/molecule.py index f0d88d7419..bf3e51a722 100644 --- a/rmgpy/molecule/molecule.py +++ b/rmgpy/molecule/molecule.py @@ -552,6 +552,8 @@ def getOrderStr(self): return 'D' elif self.isTriple(): return 'T' + elif self.isQuadruple(): + return 'Q' elif self.isHydrogenBond(): return 'H' else: @@ -569,6 +571,8 @@ def setOrderStr(self, newOrder): self.order = 3 elif newOrder == 'B': self.order = 1.5 + elif newOrder == 'Q': + self.order = 4 elif newOrder == 'H': self.order = 0 else: @@ -638,6 +642,13 @@ def isTriple(self): """ return self.isOrder(3) + def isQuadruple(self): + """ + Return ``True`` if the bond represents a quadruple bond or ``False`` if + not. + """ + return self.isOrder(4) + def isBenzene(self): """ Return ``True`` if the bond represents a benzene bond or ``False`` if @@ -657,11 +668,11 @@ def incrementOrder(self): Update the bond as a result of applying a CHANGE_BOND action to increase the order by one. """ - if self.order <=2.0001: + if self.order <=3.0001: self.order += 1 else: raise gr.ActionError('Unable to increment Bond due to CHANGE_BOND action: '+\ - 'Bond order "{0}" is greater than 2.'.format(self.order)) + 'Bond order "{0}" is greater than 3.'.format(self.order)) def decrementOrder(self): """ @@ -681,7 +692,7 @@ def __changeBond(self, order): in bond order, and can be any real number. """ self.order += order - if self.order < -0.0001 or self.order >3.0001: + if self.order < -0.0001 or self.order >4.0001: raise gr.ActionError('Unable to update Bond due to CHANGE_BOND action: Invalid resulting order "{0}".'.format(self.order)) def applyAction(self, action): diff --git a/rmgpy/molecule/moleculeTest.py b/rmgpy/molecule/moleculeTest.py index c77082af95..4ee847a466 100644 --- a/rmgpy/molecule/moleculeTest.py +++ b/rmgpy/molecule/moleculeTest.py @@ -298,7 +298,7 @@ def setUp(self): A method called before each unit test in this class. """ self.bond = Bond(atom1=None, atom2=None, order=2) - self.orderList = [1,2,3,1.5, 0.30000000000000004] + self.orderList = [1,2,3,4,1.5, 0.30000000000000004] def testGetOrderStr(self): """ @@ -394,6 +394,17 @@ def testIsBenzene(self): else: self.assertFalse(bond.isBenzene()) + def testIsQuadruple(self): + """ + Test the Bond.isQuadruple() method. + """ + for order in self.orderList: + bond = Bond(None, None, order=order) + if order == 4: + self.assertTrue(bond.isQuadruple()) + else: + self.assertFalse(bond.isQuadruple()) + def testIncrementOrder(self): """ Test the Bond.incrementOrder() method. @@ -406,8 +417,10 @@ def testIncrementOrder(self): self.assertTrue(bond.isDouble()) elif order == 2: self.assertTrue(bond.isTriple()) + elif order == 3: + self.assertTrue(bond.isQuadruple()) except ActionError: - self.assertTrue(order >= 3) + self.assertTrue(order >= 4) # or benzene?? def testDecrementOrder(self): """ @@ -421,6 +434,8 @@ def testDecrementOrder(self): self.assertTrue(bond.isSingle()) elif order == 3: self.assertTrue(bond.isDouble()) + elif order == 'Q': + self.assertTrue(bond.isTriple()) except ActionError: self.assertTrue(order < 1) @@ -463,7 +478,7 @@ def testApplyActionIncrementBond(self): try: bond.applyAction(action) except ActionError: - self.assertTrue(3 <= order0,'Test failed with order {0}'.format(order0)) + self.assertTrue(4 <= order0,'Test failed with order {0}'.format(order0)) def testApplyActionDecrementBond(self): """ From 765ea4a99ee991505ab32c42a2ba14e33246f182 Mon Sep 17 00:00:00 2001 From: Emily Mazeau Date: Mon, 12 Mar 2018 14:43:27 -0400 Subject: [PATCH 4/9] Updates since AtomType.getFeatures() now includes quadruple bonds It's unfortunate how fragile this code is, using integer indexing. Had to change getFeatures to include Benzene in its corrcect spot, --- rmgpy/molecule/group.py | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/rmgpy/molecule/group.py b/rmgpy/molecule/group.py index 9bd67772d5..c6a2e859ef 100644 --- a/rmgpy/molecule/group.py +++ b/rmgpy/molecule/group.py @@ -1824,7 +1824,7 @@ def addImplicitAtomsFromAtomType(self): for atom1 in copyGroup.atoms: atomtypeFeatureList = atom1.atomType[0].getFeatures() - lonePairsRequired[atom1]=atomtypeFeatureList[7] + lonePairsRequired[atom1] = atomtypeFeatureList[8] #set to 0 required if empty list atomtypeFeatureList = [featureList if featureList else [0] for featureList in atomtypeFeatureList] @@ -1833,9 +1833,10 @@ def addImplicitAtomsFromAtomType(self): oDoubleRequired = atomtypeFeatureList[3] sDoubleRequired = atomtypeFeatureList[4] tripleRequired = atomtypeFeatureList[5] + quadrupleRequired = atomtypeFeatureList[6] #count up number of bonds - single = 0; rDouble = 0; oDouble = 0; sDouble = 0; triple = 0; benzene = 0 + single = 0; rDouble = 0; oDouble = 0; sDouble = 0; triple = 0; quadruple = 0; benzene = 0 for atom2, bond12 in atom1.bonds.iteritems(): # Count numbers of each higher-order bond type if bond12.isSingle(): @@ -1849,6 +1850,7 @@ def addImplicitAtomsFromAtomType(self): # rDouble is for double bonds NOT to oxygen or Sulfur rDouble += 1 elif bond12.isTriple(): triple += 1 + elif bond12.isQuadruple(): quadruple += 1 elif bond12.isBenzene(): benzene += 1 @@ -1872,6 +1874,11 @@ def addImplicitAtomsFromAtomType(self): newAtom = GroupAtom(atomType=[atomTypes['C']], radicalElectrons=[0], charge=[], label='', lonePairs=None) newBond = GroupBond(atom1, newAtom, order=[3]) implicitAtoms[newAtom] = newBond + while quadruple < quadrupleRequired[0]: + quadruple +=1 + newAtom = GroupAtom(atomType=[atomTypes['C']], radicalElectrons=[0], charge=[], label='', lonePairs=None) + newBond = GroupBond(atom1, newAtom, order=[4]) + implicitAtoms[newAtom] = newBond for atom, bond in implicitAtoms.iteritems(): copyGroup.addAtom(atom) @@ -2276,24 +2283,28 @@ def pickWildcards(self): requiredFeatures1.reverse() requiredFeatures2.reverse() - #required features are a now list of [benzene, triple, sDouble, oDouble, rDouble, allDouble, single] + #required features are a now list of [benzene, quadruple, triple, sDouble, oDouble, rDouble, allDouble, single] for index, (feature1, feature2) in enumerate(zip(requiredFeatures1[:-1], requiredFeatures2[:-1])): if feature1 > 0 or feature2 > 0: if index == 0 and 1.5 in bond12.order: #benzene bonds bond12.order = [1.5] atom2.bonds[atom1].order = bond12.order break - elif index == 1 and 3 in bond12.order: #triple bond + elif index == 1 and 4 in bond12.order: #quadruple bond + bond12.order = [4] + atom2.bonds[atom1].order = bond12.order + break + elif index == 2 and 3 in bond12.order: #triple bond bond12.order = [3] atom2.bonds[atom1].order = bond12.order break - elif index > 1 and 2 in bond12.order: #any case of double bonds - if index == 2: #sDouble bonds + elif index > 2 and 2 in bond12.order: #any case of double bonds + if index == 3: #sDouble bonds if (feature1 > 0 and atom2.isSulfur()) or (feature2 > 0 and atom1.isSulfur()): bond12.order = [2] atom2.bonds[atom1].order = bond12.order break - elif index == 3: #oDoubleBonds + elif index == 4: #oDoubleBonds if (feature1 > 0 and atom2.isOxygen()) or (feature2 > 0 and atom1.isOxygen()): bond12.order = [2] atom2.bonds[atom1].order = bond12.order From 996cb3495fd9b9728d3783c17e0b1774e26e253e Mon Sep 17 00:00:00 2001 From: Emily Mazeau Date: Tue, 29 May 2018 12:00:56 -0400 Subject: [PATCH 5/9] changed H bonds to 0.1 in the definitions A combination of several commits, with these messages: changed the remove H bonds to remove anything close to 0.1 Hydrogen-bonds now have order 0.1 This way of doing things is a bit fragile, and not very satisfying. But I think this fixes at least a couple of places where this change needs to be made. Detect 0.1 bond orders (for H bonds) more robustly. Now passes last unit test. (It was something like 0.1000000000000149) --- rmgpy/molecule/molecule.py | 18 +++++++++++++----- rmgpy/molecule/moleculeTest.py | 2 +- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/rmgpy/molecule/molecule.py b/rmgpy/molecule/molecule.py index bf3e51a722..9e402fa56c 100644 --- a/rmgpy/molecule/molecule.py +++ b/rmgpy/molecule/molecule.py @@ -661,7 +661,7 @@ def isHydrogenBond(self): Return ``True`` if the bond represents a hydrogen bond or ``False`` if not. """ - return self.isOrder(0) + return self.isOrder(0.1) def incrementOrder(self): """ @@ -719,13 +719,21 @@ def get_bond_string(self): the atom labels in alphabetical order (i.e. 'C-H' is possible but not 'H-C') :return: str """ - bond_symbol_mapping = {0: '~', 1: '-', 1.5: ':', 2: '=', 3: '#'} + bond_symbol_mapping = {0.1: '~', 1: '-', 1.5: ':', 2: '=', 3: '#'} atom_labels = [self.atom1.symbol, self.atom2.symbol] atom_labels.sort() try: bond_symbol = bond_symbol_mapping[self.getOrderNum()] except KeyError: - bond_symbol = ''.format(self.getOrderNum()) + # Direct lookup didn't work, but before giving up try + # with the isOrder() method which allows a little latitude + # for floating point errors. + for order,symbol in bond_symbol_mapping.iteritems(): + if self.isOrder(order): + bond_symbol = symbol + break + else: # didn't break + bond_symbol = ''.format(self.getOrderNum()) return '{0}{1}{2}'.format(atom_labels[0], bond_symbol, atom_labels[1]) @@ -1581,7 +1589,7 @@ def find_H_bonds(self): atm_cov = atm_covs[0] if (atm_cov.isOxygen() or atm_cov.isNitrogen()): #this H can be H-bonded for k,atm2 in enumerate(ONatoms): - if all([q.order != 0 for q in atm2.bonds.values()]): #atm2 not already H bonded + if all([not numpy.isclose(0.1, q.order) for q in atm2.bonds.values()]): #atm2 not already H bonded dist = len(find_shortest_path(atm1,atm2))-1 if dist > 3: j = ONinds[k] @@ -1626,7 +1634,7 @@ def remove_H_bonds(self): for j,atm2 in enumerate(atoms): if j Date: Sun, 20 Jan 2019 00:44:07 -0500 Subject: [PATCH 6/9] Hydrogen bonds have order 0.1 (instead of 0) (more) --- rmgpy/molecule/adjlist.py | 4 +++- rmgpy/molecule/group.py | 2 +- rmgpy/molecule/molecule.py | 8 ++++---- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/rmgpy/molecule/adjlist.py b/rmgpy/molecule/adjlist.py index b67cca2ca1..e98d87ce8f 100644 --- a/rmgpy/molecule/adjlist.py +++ b/rmgpy/molecule/adjlist.py @@ -35,6 +35,7 @@ import logging import warnings import re +import numpy as np from .molecule import Atom, Bond, getAtomType from .group import GroupAtom, GroupBond from .element import getElement, PeriodicSystem @@ -89,7 +90,8 @@ def check_partial_charge(atom): theoretical = valence - order - atom.radicalElectrons - 2*atom.lonePairs - if atom.charge != theoretical: + if not (-0.301 < atom.charge - theoretical < 0.301): + # It should be 0, but -0.1 is caused by a Hydrogen bond raise InvalidAdjacencyListError( ('Invalid valency for atom {symbol} ({type}) with {radicals} unpaired electrons, ' '{lonePairs} pairs of electrons, {charge} charge, and bonds [{bonds}].' diff --git a/rmgpy/molecule/group.py b/rmgpy/molecule/group.py index c6a2e859ef..c363f3560f 100644 --- a/rmgpy/molecule/group.py +++ b/rmgpy/molecule/group.py @@ -688,7 +688,7 @@ def setOrderStr(self, newOrder): elif value == 'B': values.append(1.5) elif value == 'H': - values.append(0) + values.append(0.1) else: # try to see if an float disguised as a string was input by mistake try: diff --git a/rmgpy/molecule/molecule.py b/rmgpy/molecule/molecule.py index 9e402fa56c..ab216565d9 100644 --- a/rmgpy/molecule/molecule.py +++ b/rmgpy/molecule/molecule.py @@ -574,7 +574,7 @@ def setOrderStr(self, newOrder): elif newOrder == 'Q': self.order = 4 elif newOrder == 'H': - self.order = 0 + self.order = 0.1 else: # try to see if an float disguised as a string was input by mistake try: @@ -1613,13 +1613,13 @@ def generate_H_bonded_structures(self): Hbonds = self.find_H_bonds() for i,bd1 in enumerate(Hbonds): molc = self.copy(deep=True) - molc.addBond(Bond(molc.atoms[bd1[0]],molc.atoms[bd1[1]],order=0)) + molc.addBond(Bond(molc.atoms[bd1[0]],molc.atoms[bd1[1]],order=0.1)) structs.append(molc) for j,bd2 in enumerate(Hbonds): if j Date: Sun, 20 Jan 2019 00:47:52 -0500 Subject: [PATCH 7/9] Adding van der Waals bonds (which have order 0) Reaction recipes can make Van der Waals bonds (with order 0) Remove 'vdW' from bond types accepted (should be 0). This is a hold-over from when bond types were strings not floating point numbers. --- rmgpy/data/kinetics/family.py | 9 ++++++++- rmgpy/molecule/group.pxd | 2 ++ rmgpy/molecule/group.py | 36 +++++++++++++++++++++++++++++++++++ rmgpy/molecule/molecule.pxd | 4 ++++ rmgpy/molecule/molecule.py | 22 +++++++++++++++++++++ 5 files changed, 72 insertions(+), 1 deletion(-) diff --git a/rmgpy/data/kinetics/family.py b/rmgpy/data/kinetics/family.py index 3827222436..0af8f7f3be 100644 --- a/rmgpy/data/kinetics/family.py +++ b/rmgpy/data/kinetics/family.py @@ -301,7 +301,9 @@ def __apply(self, struct, doForward, unique): elif (action[0] == 'FORM_BOND' and doForward) or (action[0] == 'BREAK_BOND' and not doForward): if struct.hasBond(atom1, atom2): raise InvalidActionError('Attempted to create an existing bond.') - bond = GroupBond(atom1, atom2, order=[1]) if pattern else Bond(atom1, atom2, order=1) + if info not in (1, 0): # Can only form single or vdW bonds + raise InvalidActionError('Attempted to create bond of type {:!r}'.format(info)) + bond = GroupBond(atom1, atom2, order=[info]) if pattern else Bond(atom1, atom2, order=info) struct.addBond(bond) atom1.applyAction(['FORM_BOND', label1, info, label2]) atom2.applyAction(['FORM_BOND', label1, info, label2]) @@ -1402,11 +1404,16 @@ def applyRecipe(self, reactantStructures, forward=True, unique=True): # reaction templates return None + # Remove vdW bonds + for struct in productStructures: + struct.removeVanDerWaalsBonds() + # Make sure we don't create a different net charge between reactants and products reactant_net_charge = product_net_charge = 0 for struc in reactantStructures: struc.update() reactant_net_charge += struc.getNetCharge() + for struct in productStructures: # If product structures are Molecule objects, update their atom types # If product structures are Group objects and the reaction is in certain families diff --git a/rmgpy/molecule/group.pxd b/rmgpy/molecule/group.pxd index 8fe1268e8f..36934712de 100644 --- a/rmgpy/molecule/group.pxd +++ b/rmgpy/molecule/group.pxd @@ -139,6 +139,8 @@ cdef class Group(Graph): cpdef removeBond(self, GroupBond bond) + cpdef removeVanDerWaalsBonds(self) + cpdef sortAtoms(self) cpdef list sortByConnectivity(self, list atomList) diff --git a/rmgpy/molecule/group.py b/rmgpy/molecule/group.py index c363f3560f..18ed1b3881 100644 --- a/rmgpy/molecule/group.py +++ b/rmgpy/molecule/group.py @@ -170,6 +170,9 @@ def __formBond(self, order): where `order` specifies the order of the forming bond, and should be 1 (since we only allow forming of single bonds). """ + if order == 0: + # no change to atom types! + return if order != 1: raise ActionError('Unable to update GroupAtom due to FORM_BOND action: Invalid order "{0}".'.format(order)) atomType = [] @@ -186,6 +189,9 @@ def __breakBond(self, order): where `order` specifies the order of the breaking bond, and should be 1 (since we only allow breaking of single bonds). """ + if order == 0: + # no change to atom types! + return if order != 1: raise ActionError('Unable to update GroupAtom due to BREAK_BOND action: Invalid order "{0}".'.format(order)) atomType = [] @@ -665,6 +671,8 @@ def getOrderStr(self): elif value == 1.5: values.append('B') elif value == 0: + values.append('vdW') + elif value == 0.1: values.append('H') else: raise TypeError('Bond order number {} is not hardcoded as a string'.format(value)) @@ -685,6 +693,8 @@ def setOrderStr(self, newOrder): values.append(3) elif value == 'Q': values.append(4) + elif value == 'vdW': + values.append(0) elif value == 'B': values.append(1.5) elif value == 'H': @@ -773,6 +783,22 @@ def isQuadruple(self, wildcards = False): else: return abs(self.order[0]-4) <= 1e-9 and len(self.order) == 1 + def isVanDerWaals(self, wildcards = False): + """ + Return ``True`` if the bond represents a van der Waals bond or ``False`` if + not. If `wildcards` is ``False`` we return False anytime there is more + than one bond order, otherwise we return ``True`` if any of the options + are van der Waals. + """ + if wildcards: + for order in self.order: + if abs(order[0]) <= 1e-9: + return True + else: + return False + else: + return abs(self.order[0]) <= 1e-9 and len(self.order) == 1 + def isBenzene(self, wildcards = False): """ Return ``True`` if the bond represents a benzene bond or ``False`` if @@ -1027,6 +1053,16 @@ def removeBond(self, bond): """ return self.removeEdge(bond) + def removeVanDerWaalsBonds(self): + """ + Remove all bonds that are definitely only van der Waals bonds. + """ + cython.declare(atom=GroupAtom, bond=GroupBond) + for atom in self.atoms: + for bond in atom.edges.values(): + if bond.isVanDerWaals(wildcards=False): + self.removeBond(bond) + def sortAtoms(self): """ Sort the atoms in the graph. This can make certain operations, e.g. diff --git a/rmgpy/molecule/molecule.pxd b/rmgpy/molecule/molecule.pxd index 59c3544082..7fe22c99a4 100644 --- a/rmgpy/molecule/molecule.pxd +++ b/rmgpy/molecule/molecule.pxd @@ -109,6 +109,8 @@ cdef class Bond(Edge): cpdef bint isOrder(self, float otherOrder) + cpdef bint isVanDerWaals(self) except -2 + cpdef bint isSingle(self) except -2 cpdef bint isDouble(self) except -2 @@ -155,6 +157,8 @@ cdef class Molecule(Graph): cpdef removeBond(self, Bond bond) + cpdef removeVanDerWaalsBonds(self) + cpdef sortAtoms(self) cpdef str getFormula(self) diff --git a/rmgpy/molecule/molecule.py b/rmgpy/molecule/molecule.py index ab216565d9..392a96a39d 100644 --- a/rmgpy/molecule/molecule.py +++ b/rmgpy/molecule/molecule.py @@ -554,6 +554,8 @@ def getOrderStr(self): return 'T' elif self.isQuadruple(): return 'Q' + elif self.isVanDerWaals(): + return 'vdW' elif self.isHydrogenBond(): return 'H' else: @@ -573,6 +575,8 @@ def setOrderStr(self, newOrder): self.order = 1.5 elif newOrder == 'Q': self.order = 4 + elif newOrder == 'vdW': + self.order = 0 elif newOrder == 'H': self.order = 0.1 else: @@ -610,6 +614,14 @@ def copy(self): b.order = self.order return b + + def isVanDerWaals(self): + """ + Return ``True`` if the bond represents a van der Waals bond or + ``False`` if not. + """ + return self.isOrder(0) or self.order == 'vdW' #todo: remove 'vdW' + def isOrder(self, otherOrder): """ Return ``True`` if the bond is of order otherOrder or ``False`` if @@ -900,6 +912,16 @@ def removeBond(self, bond): self._fingerprint = None return self.removeEdge(bond) + def removeVanDerWaalsBonds(self): + """ + Remove all van der Waals bonds. + """ + cython.declare(atom=Atom, bond=Bond) + for atom in self.atoms: + for bond in atom.edges.values(): + if bond.isVanDerWaals(): + self.removeBond(bond) + def sortAtoms(self): """ Sort the atoms in the graph. This can make certain operations, e.g. From f419f8ab3d7c9d6cc4b9885741a3fba7141a5e12 Mon Sep 17 00:00:00 2001 From: Richard West Date: Fri, 25 Jan 2019 09:37:23 -0500 Subject: [PATCH 8/9] Minor comments added to molecule/groupTest unit tests. --- rmgpy/molecule/groupTest.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/rmgpy/molecule/groupTest.py b/rmgpy/molecule/groupTest.py index e1c5a4a1da..79a0d2e480 100644 --- a/rmgpy/molecule/groupTest.py +++ b/rmgpy/molecule/groupTest.py @@ -403,7 +403,7 @@ def setUp(self): A method called before each unit test in this class. """ self.bond = GroupBond(None, None, order=[2]) - self.orderList = [[1], [2], [3], [1.5], [1,2], [2,1], [2,3], [1,2,3]] + self.orderList = [[1], [2], [3], [1.5], [1,2], [2,1], [2,3], [1,2,3]] # todo : unit tests for vdw def testGetOrderStr(self): """ @@ -499,6 +499,9 @@ def testApplyActionBreakBond(self): def testApplyActionFormBond(self): """ Test the GroupBond.applyAction() method for a FORM_BOND action. + + Tests that forming a bond between things already bonded, raises + an ActionError """ action = ['FORM_BOND', '*1', 1, '*2'] for order0 in self.orderList: From 7ff2527de7dec8e31cf55a063a655cf9a9b78767 Mon Sep 17 00:00:00 2001 From: Richard West Date: Mon, 28 Jan 2019 21:25:20 -0500 Subject: [PATCH 9/9] More helpful error logging when failing to load reaction library. Might not make a difference if you could see the logging.info call two lines earlier, but when running unit tests (databaseTest) that is not necessarily the case. --- rmgpy/data/kinetics/database.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/rmgpy/data/kinetics/database.py b/rmgpy/data/kinetics/database.py index 331a2dacf3..c4cfdedab5 100644 --- a/rmgpy/data/kinetics/database.py +++ b/rmgpy/data/kinetics/database.py @@ -248,7 +248,11 @@ def loadLibraries(self, path, libraries=None): label=os.path.dirname(library_file)[len(path)+1:] logging.info('Loading kinetics library {0} from {1}...'.format(label, library_file)) library = KineticsLibrary(label=label) - library.load(library_file, self.local_context, self.global_context) + try: + library.load(library_file, self.local_context, self.global_context) + except: + logging.error("Problem loading reaction library {0!r}".format(library_file)) + raise self.libraries[library.label] = library self.libraryOrder.append((library.label,'Reaction Library'))