11
$\begingroup$

I'm trying to search for substructures with RDKit.

I would like to search for structure 1 as substructure in other structures. I don't understand why it doesn't find this structure in structures 3 and 5. I assume this is not a bug in RDKit, but more the result of my limited chemistry understanding. Something with aromaticity? Something wrong with the structures? Can someone explain to me why it doesn't find structure 1 in structures 3 and 5? How should the search structure look like that I will find all structures 2-5?

enter image description here

from rdkit import Chem

smiles_list = ['C12=CC=CC=C1C3=CC=CC4=C3C2=CC=C4', 'C12=CC=CC=C1C3=CC=C4C5=C(C=CC2=C35)C6=C4C=CC=C6', 'C12=CC=CC=C1C3=CC=C4C5=C(C=CC2=C35)C=C4', 'C12=CC=CC=C1C3=CC=C4C5=C(C=CC2=C35)C6=C4C=C7CCCCC7=C6', 'C12=CC=CC=C1C3=CC=C4C5=C(C=CC2=C35)C6=C4C=C7CC8=CC=CC=C8CC7=C6']

pattern = Chem.MolFromSmiles(smiles_list[0])
for idx,smiles in enumerate(smiles_list):
    m = Chem.MolFromSmiles(smiles)
    print("Structure {}: pattern found {}".format(idx+1,m.HasSubstructMatch(pattern)))

# Result:
# Structure 1: pattern found True
# Structure 2: pattern found True
# Structure 3: pattern found False
# Structure 4: pattern found True
# Structure 5: pattern found False
$\endgroup$
4
  • 1
    $\begingroup$ thank you for pointing to this. I think I found a solution (see my answer), but I'm not sure if this solution might cause some other surprises or unexpected results. Should I discuss this on the mailing list? What do you think? $\endgroup$
    – theozh
    Commented Feb 28, 2020 at 17:41
  • $\begingroup$ @GeoffHutchison See above response. $\endgroup$ Commented Feb 28, 2020 at 21:49
  • $\begingroup$ @theozh Just a heads up, if you reply to a comment, you have to tag the person, otherwise, they won't see it. Welcome to Chem.SE! I love your question and will be following it. Very interesting work you're doing. $\endgroup$ Commented Feb 28, 2020 at 21:50
  • $\begingroup$ I just realized you're not new to chem.se, but welcome anyway! You have some seriously cool questions! $\endgroup$ Commented Feb 28, 2020 at 21:51

2 Answers 2

9
$\begingroup$

I'm not sure about why it's not matching but when I carry out substructure matches in rdkit I use SMARTS instead https://www.daylight.com/dayhtml/doc/theory/theory.smarts.html

Here is what I would have done.

from rdkit import Chem

smiles_list = ['C12=CC=CC=C1C3=CC=CC4=C3C2=CC=C4', 'C12=CC=CC=C1C3=CC=C4C5=C(C=CC2=C35)C6=C4C=CC=C6', 'C12=CC=CC=C1C3=CC=C4C5=C(C=CC2=C35)C=C4', 'C12=CC=CC=C1C3=CC=C4C5=C(C=CC2=C35)C6=C4C=C7CCCCC7=C6', 'C12=CC=CC=C1C3=CC=C4C5=C(C=CC2=C35)C6=C4C=C7CC8=CC=CC=C8CC7=C6', 'c1ccccc1']

pattern = Chem.MolFromSmarts('[#6]12~[#6][#6]~[#6][#6]~[#6]1[#6]3~[#6][#6]~[#6][#6]4~[#6]3[#6]2~[#6][#6]~[#6]4')
for idx,smiles in enumerate(smiles_list):
    m = Chem.MolFromSmiles(smiles)
    print("Structure {}: pattern found {}".format(idx+1,m.HasSubstructMatch(pattern)))

and the output

Structure 1: pattern found True
Structure 2: pattern found True
Structure 3: pattern found True
Structure 4: pattern found True
Structure 5: pattern found True
Structure 6: pattern found False

I've added a Benzene smiles to show that it's not just matching everything. The SMARTS pattern I made probably could be better I think. I hope this helps anyway.

$\endgroup$
8
  • $\begingroup$ Thank you for testing. Interesting. Then I need to check how I can reliably convert SMILES to SMARTS. Why it doesn't work with SMILES? Still a bug in RDKit? $\endgroup$
    – theozh
    Commented Feb 28, 2020 at 9:39
  • $\begingroup$ I'm not sure why it doesn't work with SMILES, I've always used the m.HasSubstructMatch method with SMARTS. But learning SMARTS is pretty easy, its similar to SMILES just follow the link in the answer. $\endgroup$
    – Unskilled
    Commented Feb 28, 2020 at 9:45
  • $\begingroup$ I just read that a SMILES is also a valid SMARTS expression. But if I use Chem.MolFromSmarts(smiles), all matches are False. $\endgroup$
    – theozh
    Commented Feb 28, 2020 at 9:55
  • $\begingroup$ Yes most SMILES patterns are valid SMARTS but the SMARTS pattern 'C12=CC=CC=C1C3=CC=CC4=C3C2=CC=C4' is not the same as '[#6]12~[#6][#6]~[#6][#6]~[#6]1[#6]3~[#6][#6]~[#6][#6]4~[#6]3[#6]2~[#6][#6]~[#6]4'. The [#6] means any carbon atom aromatic or aliphatic while in the first pattern the C means an aliphatic carbon. Since at some point rdkit will make certain carbons in your molecules aromatic it will mean that it will not match. Also ~ means any bond while = in the first pattern is a double bond rdkit will at some point change some of your molecules bonds to aromatic bonds so will not match. $\endgroup$
    – Unskilled
    Commented Feb 28, 2020 at 10:10
  • $\begingroup$ OK. I see. But how do I get a SMARTS from a SMILES? So far, couldn't find it in RDKit. From SMARTS to Mol and from Mol to SMILES, but not the other way round. OBabel? I wanted to avoid an extra tool. I need to search further. $\endgroup$
    – theozh
    Commented Feb 28, 2020 at 10:14
6
$\begingroup$

The following looks like a solution, unless anybody disproves it. Thank you @Unskilled, for pointing me in the right direction.

If you use structure 1 with smiles_1a: C12=CC=CC=C1C3=CC=CC4=C3C2=CC=C4, you will not find structures 3 and 5. If you take OpenBabel and convert smiles_1a to SMILES you get: c12ccccc1c1cccc3c1ccc3. If you take this SMILES string and convert it to mol via Chem.MolFromSmarts() you will find all structures. However, I don't want to use additional external tools.

So, in RDKit, if you convert smiles_1a to mol and this mol back to SMILES again, you get c1ccc2c(c1)-c1cccc3cccc-2c13. If you search with this, you will still not find structures 3 and 5. Probably because of the defined single bonds. However, if you replace - by ~, you get smiles_1b: c1ccc2c(c1)~c1cccc3cccc~2c13. With this, you will find also structures 3 and 5. Happy End, hopefully.

Code: (I also added Benzene to have a non-match)

from rdkit import Chem

smiles_list = ['C12=CC=CC=C1C3=CC=CC4=C3C2=CC=C4', 'C12=CC=CC=C1C3=CC=C4C5=C(C=CC2=C35)C6=C4C=CC=C6', 'C12=CC=CC=C1C3=CC=C4C5=C(C=CC2=C35)C=C4', 'C12=CC=CC=C1C3=CC=C4C5=C(C=CC2=C35)C6=C4C=C7CCCCC7=C6', 'C12=CC=CC=C1C3=CC=C4C5=C(C=CC2=C35)C6=C4C=C7CC8=CC=CC=C8CC7=C6','c1ccccc1']

def search_structure(pattern):
    for idx,smiles in enumerate(smiles_list):
        m = Chem.MolFromSmiles(smiles)
        print("Structure {}: pattern found {}".format(idx+1,m.HasSubstructMatch(pattern)))

smiles_1a  = smiles_list[0]
pattern_1a = Chem.MolFromSmiles(smiles_list[0])
smiles_1b  = Chem.MolToSmiles(pattern_1a).replace('-','~')
pattern_1b = Chem.MolFromSmarts(smiles_1b)

print("\nSMILES 1a: {}".format(smiles_1a))
search_structure(pattern_1a)
print("\nSMILES 1b: {}".format(smiles_1b))
search_structure(pattern_1b)

Result:

SMILES 1a: C12=CC=CC=C1C3=CC=CC4=C3C2=CC=C4
Structure 1: pattern found True
Structure 2: pattern found True
Structure 3: pattern found False
Structure 4: pattern found True
Structure 5: pattern found False
Structure 6: pattern found False

SMILES 1b: c1ccc2c(c1)~c1cccc3cccc~2c13
Structure 1: pattern found True
Structure 2: pattern found True
Structure 3: pattern found True
Structure 4: pattern found True
Structure 5: pattern found True
Structure 6: pattern found False
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.