From 576be70893f4197e016d85a0c562f76ccd696465 Mon Sep 17 00:00:00 2001 From: matteoferla Date: Wed, 9 Dec 2020 15:57:54 +0000 Subject: [PATCH 01/32] :flags: now tests are pretty --- README.md | 32 ++++-- documentation/covalents.md | 56 +++++++++ documentation/covid.md | 4 +- documentation/logging_and_debugging.md | 5 + .../{fragmenstein.md => monster/monster.md} | 25 ++-- .../monster_full.md} | 2 +- .../monster_partial.md} | 2 +- documentation/{ => monster}/no_template.md | 8 +- .../note_about_merging_operations.md | 16 +-- .../{ => monster}/three_modes_compared.md | 20 ++-- documentation/victor.md | 6 +- documentation/wip.md | 14 ++- fragmenstein/mpro/data/hit_mols/Mpro-6lze.mol | 74 ++++++++++++ fragmenstein/mpro/data/hit_mols/Mpro-6m0k.mol | 76 +++++++++++++ fragmenstein/mpro/data/hit_mols/Mpro-6m2n.mol | 47 ++++++++ fragmenstein/mpro/data/hit_mols/Mpro-6w63.mol | 76 +++++++++++++ fragmenstein/mpro/data/hit_mols/Mpro-6wnp.mol | 81 +++++++++++++ fragmenstein/mpro/data/hit_mols/Mpro-6wtj.mol | 64 +++++++++++ fragmenstein/mpro/data/hit_mols/Mpro-6wtk.mol | 64 +++++++++++ fragmenstein/mpro/data/hit_mols/Mpro-6wtt.mol | 64 +++++++++++ fragmenstein/mpro/data/hit_mols/Mpro-6xa4.mol | 20 ++++ fragmenstein/mpro/data/hit_mols/Mpro-6xb0.mol | 20 ++++ fragmenstein/mpro/data/hit_mols/Mpro-6xb1.mol | 20 ++++ fragmenstein/mpro/data/hit_mols/Mpro-6xb2.mol | 23 ++++ fragmenstein/mpro/data/hit_mols/Mpro-6xbg.mol | 13 +++ fragmenstein/mpro/data/hit_mols/Mpro-6xbh.mol | 27 +++++ fragmenstein/mpro/data/hit_mols/Mpro-6xbi.mol | 23 ++++ fragmenstein/mpro/data/hit_mols/Mpro-6xch.mol | 26 +++++ fragmenstein/mpro/data/hit_mols/Mpro-6xfn.mol | 22 ++++ fragmenstein/mpro/data/hit_mols/Mpro-6xhm.mol | 75 ++++++++++++ fragmenstein/mpro/data/hit_mols/Mpro-6xkf.mol | 18 +++ fragmenstein/mpro/data/hit_mols/Mpro-6xmk.mol | 68 +++++++++++ fragmenstein/mpro/data/hit_mols/Mpro-6xqs.mol | 107 ++++++++++++++++++ fragmenstein/mpro/data/hit_mols/Mpro-6xqt.mol | 106 +++++++++++++++++ fragmenstein/mpro/data/hit_mols/Mpro-6xqu.mol | 81 +++++++++++++ fragmenstein/mpro/data/hit_mols/Mpro-6xr3.mol | 91 +++++++++++++++ fragmenstein/mpro/data/hit_mols/Mpro-6y2f.mol | 94 +++++++++++++++ fragmenstein/mpro/data/hit_mols/Mpro-6y2g.mol | 94 +++++++++++++++ fragmenstein/mpro/data/hit_mols/Mpro-6ynq.mol | 30 +++++ fragmenstein/mpro/data/hit_mols/Mpro-6yt8.mol | 24 ++++ fragmenstein/mpro/data/hit_mols/Mpro-6yvf.mol | 68 +++++++++++ fragmenstein/mpro/data/hit_mols/Mpro-6yz6.mol | 16 +++ fragmenstein/mpro/data/hit_mols/Mpro-6zrt.mol | 107 ++++++++++++++++++ fragmenstein/mpro/data/hit_mols/Mpro-6zru.mol | 81 +++++++++++++ fragmenstein/mpro/data/hit_mols/Mpro-7aku.mol | 57 ++++++++++ fragmenstein/mpro/data/hit_mols/Mpro-7bqy.mol | 22 ++++ fragmenstein/mpro/data/hit_mols/Mpro-7brp.mol | 81 +++++++++++++ fragmenstein/mpro/data/hit_mols/Mpro-7buy.mol | 22 ++++ fragmenstein/mpro/data/hit_mols/Mpro-7c6s.mol | 81 +++++++++++++ fragmenstein/mpro/data/hit_mols/Mpro-7c6u.mol | 64 +++++++++++ fragmenstein/mpro/data/hit_mols/Mpro-7c7p.mol | 57 ++++++++++ fragmenstein/mpro/data/hit_mols/Mpro-7c8b.mol | 6 + fragmenstein/mpro/data/hit_mols/Mpro-7c8r.mol | 96 ++++++++++++++++ fragmenstein/mpro/data/hit_mols/Mpro-7c8t.mol | 93 +++++++++++++++ fragmenstein/mpro/data/hit_mols/Mpro-7c8u.mol | 64 +++++++++++ fragmenstein/mpro/data/hit_mols/Mpro-7cbt.mol | 64 +++++++++++ fragmenstein/mpro/data/hit_mols/Mpro-7com.mol | 81 +++++++++++++ fragmenstein/mpro/data/hit_mols/Mpro-7cx9.mol | 30 +++++ fragmenstein/mpro/data/hit_mols/Mpro-7d1m.mol | 6 + fragmenstein/mpro/data/hit_mols/Mpro-7d1o.mol | 106 +++++++++++++++++ fragmenstein/mpro/data/hit_mols/Mpro-7d3i.mol | 74 ++++++++++++ fragmenstein/mpro/data/hit_mols/Mpro-7jkv.mol | 91 +++++++++++++++ fragmenstein/mpro/data/hit_mols/Mpro-7jr4.mol | 12 ++ fragmenstein/mpro/data/hit_mols/Mpro-7ju7.mol | 81 +++++++++++++ fragmenstein/mpro/data/hit_mols/Mpro-7jyc.mol | 106 +++++++++++++++++ fragmenstein/mpro/data/hit_mols/Mpro-7k40.mol | 81 +++++++++++++ fragmenstein/mpro/data/hit_mols/Mpro-7k6d.mol | 107 ++++++++++++++++++ fragmenstein/mpro/data/hit_mols/Mpro-7k6e.mol | 107 ++++++++++++++++++ fragmenstein/mpro/data/hit_mols/Mpro-7kfj.mol | 31 +++++ .../mpro/data/hit_mols/Mpro-x10082.mol | 56 +++++++++ .../mpro/data/hit_mols/Mpro-x10178.mol | 42 +++++++ .../mpro/data/hit_mols/Mpro-x10296.mol | 44 +++++++ .../mpro/data/hit_mols/Mpro-x10306.mol | 50 ++++++++ .../mpro/data/hit_mols/Mpro-x10329.mol | 46 ++++++++ .../mpro/data/hit_mols/Mpro-x10338.mol | 49 ++++++++ .../mpro/data/hit_mols/Mpro-x10355.mol | 59 ++++++++++ .../mpro/data/hit_mols/Mpro-x10396.mol | 46 ++++++++ .../mpro/data/hit_mols/Mpro-x10419.mol | 59 ++++++++++ .../mpro/data/hit_mols/Mpro-x10466.mol | 47 ++++++++ .../mpro/data/hit_mols/Mpro-x10473.mol | 38 +++++++ .../mpro/data/hit_mols/Mpro-x10474.mol | 37 ++++++ .../mpro/data/hit_mols/Mpro-x10476.mol | 41 +++++++ .../mpro/data/hit_mols/Mpro-x10478.mol | 41 +++++++ .../mpro/data/hit_mols/Mpro-x10484.mol | 46 ++++++++ .../mpro/data/hit_mols/Mpro-x10488.mol | 52 +++++++++ .../mpro/data/hit_mols/Mpro-x10494.mol | 44 +++++++ .../mpro/data/hit_mols/Mpro-x10506.mol | 59 ++++++++++ .../mpro/data/hit_mols/Mpro-x10513.mol | 49 ++++++++ .../mpro/data/hit_mols/Mpro-x10525.mol | 61 ++++++++++ .../mpro/data/hit_mols/Mpro-x10535.mol | 47 ++++++++ .../mpro/data/hit_mols/Mpro-x10555.mol | 41 +++++++ .../mpro/data/hit_mols/Mpro-x10559.mol | 41 +++++++ .../mpro/data/hit_mols/Mpro-x10565.mol | 42 +++++++ .../mpro/data/hit_mols/Mpro-x10566.mol | 47 ++++++++ .../mpro/data/hit_mols/Mpro-x10575.mol | 41 +++++++ .../mpro/data/hit_mols/Mpro-x10598.mol | 44 +++++++ .../mpro/data/hit_mols/Mpro-x10604.mol | 40 +++++++ .../mpro/data/hit_mols/Mpro-x10606.mol | 42 +++++++ .../mpro/data/hit_mols/Mpro-x10610.mol | 40 +++++++ .../mpro/data/hit_mols/Mpro-x10626.mol | 41 +++++++ .../mpro/data/hit_mols/Mpro-x10638.mol | 53 +++++++++ .../mpro/data/hit_mols/Mpro-x10645.mol | 51 +++++++++ .../mpro/data/hit_mols/Mpro-x10678.mol | 51 +++++++++ .../mpro/data/hit_mols/Mpro-x10679.mol | 49 ++++++++ .../mpro/data/hit_mols/Mpro-x10700.mol | 48 ++++++++ .../mpro/data/hit_mols/Mpro-x10710.mol | 48 ++++++++ .../mpro/data/hit_mols/Mpro-x10723.mol | 42 +++++++ .../mpro/data/hit_mols/Mpro-x10728.mol | 57 ++++++++++ .../mpro/data/hit_mols/Mpro-x10733.mol | 49 ++++++++ .../mpro/data/hit_mols/Mpro-x10756.mol | 53 +++++++++ .../mpro/data/hit_mols/Mpro-x10787.mol | 51 +++++++++ .../mpro/data/hit_mols/Mpro-x10789.mol | 55 +++++++++ .../mpro/data/hit_mols/Mpro-x10800.mol | 53 +++++++++ .../mpro/data/hit_mols/Mpro-x10801.mol | 41 +++++++ .../mpro/data/hit_mols/Mpro-x10812.mol | 30 +++++ .../mpro/data/hit_mols/Mpro-x10820.mol | 62 ++++++++++ .../mpro/data/hit_mols/Mpro-x10834.mol | 46 ++++++++ .../mpro/data/hit_mols/Mpro-x10856.mol | 48 ++++++++ .../mpro/data/hit_mols/Mpro-x10862.mol | 59 ++++++++++ .../mpro/data/hit_mols/Mpro-x10870.mol | 71 ++++++++++++ .../mpro/data/hit_mols/Mpro-x10871.mol | 68 +++++++++++ .../mpro/data/hit_mols/Mpro-x10876.mol | 64 +++++++++++ .../mpro/data/hit_mols/Mpro-x10888.mol | 48 ++++++++ .../mpro/data/hit_mols/Mpro-x10889.mol | 52 +++++++++ .../mpro/data/hit_mols/Mpro-x10898.mol | 52 +++++++++ .../mpro/data/hit_mols/Mpro-x10899.mol | 59 ++++++++++ .../mpro/data/hit_mols/Mpro-x10900.mol | 44 +++++++ .../mpro/data/hit_mols/Mpro-x10906.mol | 52 +++++++++ .../mpro/data/hit_mols/Mpro-x10942.mol | 51 +++++++++ .../mpro/data/hit_mols/Mpro-x10959.mol | 49 ++++++++ .../mpro/data/hit_mols/Mpro-x10976.mol | 42 +++++++ .../mpro/data/hit_mols/Mpro-x10995.mol | 50 ++++++++ .../mpro/data/hit_mols/Mpro-x10996.mol | 40 +++++++ .../mpro/data/hit_mols/Mpro-x11001.mol | 38 +++++++ .../mpro/data/hit_mols/Mpro-x11011.mol | 42 +++++++ .../mpro/data/hit_mols/Mpro-x11013.mol | 42 +++++++ .../mpro/data/hit_mols/Mpro-x11025.mol | 40 +++++++ .../mpro/data/hit_mols/Mpro-x11041.mol | 44 +++++++ .../mpro/data/hit_mols/Mpro-x11044.mol | 42 +++++++ .../mpro/data/hit_mols/Mpro-x11159.mol | 50 ++++++++ .../mpro/data/hit_mols/Mpro-x11164.mol | 66 +++++++++++ .../mpro/data/hit_mols/Mpro-x11186.mol | 50 ++++++++ .../mpro/data/hit_mols/Mpro-x11204.mol | 40 +++++++ .../mpro/data/hit_mols/Mpro-x11208.mol | 53 +++++++++ .../mpro/data/hit_mols/Mpro-x11212.mol | 45 ++++++++ .../mpro/data/hit_mols/Mpro-x11223.mol | 47 ++++++++ .../mpro/data/hit_mols/Mpro-x11225.mol | 55 +++++++++ .../mpro/data/hit_mols/Mpro-x11231.mol | 56 +++++++++ .../mpro/data/hit_mols/Mpro-x11233.mol | 52 +++++++++ .../mpro/data/hit_mols/Mpro-x11254.mol | 57 ++++++++++ .../mpro/data/hit_mols/Mpro-x11258.mol | 53 +++++++++ .../mpro/data/hit_mols/Mpro-x11271.mol | 46 ++++++++ .../mpro/data/hit_mols/Mpro-x11294.mol | 61 ++++++++++ .../mpro/data/hit_mols/Mpro-x11313.mol | 59 ++++++++++ .../mpro/data/hit_mols/Mpro-x11317.mol | 44 +++++++ .../mpro/data/hit_mols/Mpro-x11318.mol | 46 ++++++++ .../mpro/data/hit_mols/Mpro-x11339.mol | 36 ++++++ .../mpro/data/hit_mols/Mpro-x11346.mol | 42 +++++++ .../mpro/data/hit_mols/Mpro-x11354.mol | 49 ++++++++ .../mpro/data/hit_mols/Mpro-x11366.mol | 60 ++++++++++ .../mpro/data/hit_mols/Mpro-x11368.mol | 42 +++++++ .../mpro/data/hit_mols/Mpro-x11372.mol | 50 ++++++++ .../mpro/data/hit_mols/Mpro-x11417.mol | 46 ++++++++ .../mpro/data/hit_mols/Mpro-x11424.mol | 47 ++++++++ .../mpro/data/hit_mols/Mpro-x11426.mol | 38 +++++++ .../mpro/data/hit_mols/Mpro-x11427.mol | 44 +++++++ .../mpro/data/hit_mols/Mpro-x11428.mol | 40 +++++++ .../mpro/data/hit_mols/Mpro-x11431.mol | 49 ++++++++ .../mpro/data/hit_mols/Mpro-x11432.mol | 51 +++++++++ .../mpro/data/hit_mols/Mpro-x11454.mol | 47 ++++++++ .../mpro/data/hit_mols/Mpro-x11458.mol | 51 +++++++++ .../mpro/data/hit_mols/Mpro-x11473.mol | 40 +++++++ .../mpro/data/hit_mols/Mpro-x11475.mol | 47 ++++++++ .../mpro/data/hit_mols/Mpro-x11485.mol | 42 +++++++ .../mpro/data/hit_mols/Mpro-x11488.mol | 50 ++++++++ .../mpro/data/hit_mols/Mpro-x11493.mol | 47 ++++++++ .../mpro/data/hit_mols/Mpro-x11498.mol | 56 +++++++++ .../mpro/data/hit_mols/Mpro-x11499.mol | 49 ++++++++ .../mpro/data/hit_mols/Mpro-x11541.mol | 53 +++++++++ .../mpro/data/hit_mols/Mpro-x11562.mol | 52 +++++++++ .../mpro/data/hit_mols/Mpro-x11564.mol | 61 ++++++++++ .../mpro/data/hit_mols/Mpro-x11579.mol | 50 ++++++++ .../mpro/data/hit_mols/Mpro-x11587.mol | 57 ++++++++++ .../mpro/data/hit_mols/Mpro-x11612.mol | 56 +++++++++ .../mpro/data/hit_mols/Mpro-x11642.mol | 68 +++++++++++ .../mpro/data/hit_mols/Mpro-x11723.mol | 59 ++++++++++ .../mpro/data/hit_mols/Mpro-x11743.mol | 52 +++++++++ .../mpro/data/hit_mols/Mpro-x11764.mol | 57 ++++++++++ .../mpro/data/hit_mols/Mpro-x11790.mol | 66 +++++++++++ .../mpro/data/hit_mols/Mpro-x11797.mol | 64 +++++++++++ .../mpro/data/hit_mols/Mpro-x11798.mol | 68 +++++++++++ .../mpro/data/hit_mols/Mpro-x11801.mol | 52 +++++++++ .../mpro/data/hit_mols/Mpro-x11809.mol | 49 ++++++++ .../mpro/data/hit_mols/Mpro-x11831.mol | 56 +++++++++ .../mpro/data/hit_mols/Mpro-x11894.mol | 55 +++++++++ .../mpro/data/hit_mols/Mpro-x12025.mol | 60 ++++++++++ .../mpro/data/hit_mols/Mpro-x12073.mol | 58 ++++++++++ .../mpro/data/hit_mols/Mpro-x12080.mol | 31 +++++ .../mpro/data/hit_mols/Mpro-x2971.mol | 52 +++++++++ .../mpro/data/hit_mols/Mpro-x3325.mol | 31 +++++ .../mpro/data/hit_mols/Mpro-x3348.mol | 53 +++++++++ test.py | 107 +++++++++++++++++- 202 files changed, 10189 insertions(+), 59 deletions(-) create mode 100644 documentation/covalents.md rename documentation/{fragmenstein.md => monster/monster.md} (84%) rename documentation/{fragmenstein_full.md => monster/monster_full.md} (99%) rename documentation/{fragmenstein_partial.md => monster/monster_partial.md} (98%) rename documentation/{ => monster}/no_template.md (94%) rename documentation/{ => monster}/note_about_merging_operations.md (67%) rename documentation/{ => monster}/three_modes_compared.md (82%) create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-6lze.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-6m0k.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-6m2n.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-6w63.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-6wnp.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-6wtj.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-6wtk.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-6wtt.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-6xa4.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-6xb0.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-6xb1.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-6xb2.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-6xbg.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-6xbh.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-6xbi.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-6xch.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-6xfn.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-6xhm.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-6xkf.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-6xmk.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-6xqs.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-6xqt.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-6xqu.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-6xr3.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-6y2f.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-6y2g.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-6ynq.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-6yt8.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-6yvf.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-6yz6.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-6zrt.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-6zru.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-7aku.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-7bqy.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-7brp.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-7buy.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-7c6s.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-7c6u.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-7c7p.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-7c8b.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-7c8r.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-7c8t.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-7c8u.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-7cbt.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-7com.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-7cx9.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-7d1m.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-7d1o.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-7d3i.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-7jkv.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-7jr4.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-7ju7.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-7jyc.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-7k40.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-7k6d.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-7k6e.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-7kfj.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x10082.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x10178.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x10296.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x10306.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x10329.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x10338.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x10355.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x10396.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x10419.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x10466.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x10473.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x10474.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x10476.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x10478.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x10484.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x10488.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x10494.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x10506.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x10513.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x10525.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x10535.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x10555.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x10559.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x10565.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x10566.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x10575.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x10598.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x10604.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x10606.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x10610.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x10626.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x10638.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x10645.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x10678.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x10679.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x10700.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x10710.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x10723.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x10728.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x10733.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x10756.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x10787.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x10789.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x10800.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x10801.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x10812.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x10820.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x10834.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x10856.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x10862.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x10870.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x10871.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x10876.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x10888.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x10889.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x10898.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x10899.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x10900.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x10906.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x10942.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x10959.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x10976.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x10995.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x10996.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x11001.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x11011.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x11013.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x11025.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x11041.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x11044.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x11159.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x11164.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x11186.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x11204.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x11208.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x11212.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x11223.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x11225.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x11231.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x11233.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x11254.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x11258.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x11271.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x11294.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x11313.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x11317.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x11318.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x11339.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x11346.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x11354.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x11366.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x11368.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x11372.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x11417.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x11424.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x11426.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x11427.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x11428.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x11431.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x11432.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x11454.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x11458.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x11473.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x11475.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x11485.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x11488.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x11493.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x11498.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x11499.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x11541.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x11562.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x11564.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x11579.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x11587.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x11612.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x11642.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x11723.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x11743.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x11764.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x11790.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x11797.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x11798.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x11801.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x11809.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x11831.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x11894.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x12025.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x12073.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x12080.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x2971.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x3325.mol create mode 100644 fragmenstein/mpro/data/hit_mols/Mpro-x3348.mol diff --git a/README.md b/README.md index 4e1a520..601d41e 100644 --- a/README.md +++ b/README.md @@ -3,13 +3,19 @@ Scaffold hopping between bound compounds by stitching them together like a reani -## Aim -Given a followup molecule (SMILES) and a series of hits it makes a spatially stitched together version of the followup based on the hits. +## Stitched molecules + +Fragmenstein can perform two different tasks. + +* **Merge** hits +* **Place** a given followup molecule (SMILES) based on series of hits + Like Frankenstein's creation it may violate the laws of chemistry. Planar trigonal topologies may be tetrahedral, bonds unnaturally long _etc._ This monstrosity is therefore then energy minimised with strong constraints. -Here is [an interactive example of mapped molecules](https://michelanglo.sgc.ox.ac.uk/r/fragmenstein). +## Place +Here is [an interactive example of placed molecules](https://michelanglo.sgc.ox.ac.uk/r/fragmenstein). It is rather tolerant to erroneous/excessive submissions (by automatically excluding them) and can energy minimise strained conformations. @@ -21,7 +27,7 @@ For example, note here that the benzene and the pyridine rings overlap, not the -### Side role: follow prediction +### Merge It can also merge fragment hits by itself and find the best scoring mergers. It uses the same overlapping position clustering, but also has a decent amount of impossible/uncommon chemistry prevention. @@ -30,28 +36,30 @@ As a consequence, it is not really a docking algorithm as it does not find the p within a given volume. Consequently, it is a method to find how faithful is a given followup to the hits provided. Hence the minimised pose should be assessed by the RMSD metric and the ∆∆G score used solely as a cutoff —lower than zero. +## Installation + ## Dramatis personae > Victor, the pipeline, requires my [rdkit to params module](https://github.com/matteoferla/rdkit_to_params). There are three main classes, named after characters from the Fragmenstein book and movies: -* ``Fragmenstein`` makes the stitched together molecules — [documentation](documentation/fragmenstein.md) +* ``Monster`` makes the stitched together molecules — [documentation](documentation/monster/monster.md) * ``Igor`` uses PyRosetta to minimise in the protein the fragmenstein followup — [documentation](documentation/igor.md) * ``Victor`` is a pipeline that calls the parts, with several features, such as warhead switching —[documentation](documentation/victor.md) An honourable mention goes to: * ``mRMSD`` is a multiple RMSD variant which does not align and bases which atoms to use on coordinates —[documentation](documentation/mrmsd.md) -* ``rectifier`` is a class that corrects mistakes in the molecule automatically merged by ``Fragmenstein``. +* ``Rectifier`` is a class that corrects mistakes in the molecule automatically merged by ``Fragmenstein``. In the absence of `pyrosetta` (which requires an academic licence), all bar ``Igor`` work. -## Work in progress +## Features -Some changes to the algorithm may happen, see [wip.md](documentation/wip.md) for more or drop me (matteo) an email. +* [Covalent hits](documentation/covalents.md) -## Laboratory +## Origin > See [Fragmenstein and COVID moonshot](documentation/covid.md). @@ -61,6 +69,12 @@ fragment based screening. [This dataset](https://github.com/postera-ai/COVID_moonshot_submissions) has some unique peculiarities that potentially are not encountered in other projects. +## Work in progress + +Some changes to the algorithm may happen, see [wip.md](documentation/wip.md) for more or drop me (matteo) an email. + + + ## Autogenerated documentations For more see the source code or the [Sphinx converted documentation](documentation/sphinx-docs.md). diff --git a/documentation/covalents.md b/documentation/covalents.md new file mode 100644 index 0000000..2240b93 --- /dev/null +++ b/documentation/covalents.md @@ -0,0 +1,56 @@ +## Covalent + +Covalent forms of a molecule are marked within the `Chem.Mol` instances in fragmenstein with a "dummy atom". +This is element symbol `*` within RDKit and smiles, but `R` in a mol file and PDB file. + +This is essential for the params file (topology file for the ligand). + +Consequently, hits are best extracted with `Victor.extract_mols` or `Victor.extract_mol`. +Fragalysis does not do this, so the hits from there will be treated as regular compounds. + +## Monster + +A molecule with a single atom is passed to `attachement` argument of `Monster`, +then the covalent linker if absent in the hits is anchored to that atom. +If you know a ligand that is covalent `Victor.find_attachment` can be used to extract the attachment atom. + +## Warheads + +Victor has a cysteine reactive warheads operations +In the class attribute `.warhead_definitions` are stored conversions and atom names +(cf. MProVictor for an example). + +**acrylamide** `C(=O)C=C` => `C(=O)CC*` +**chloroacetamide** `C(=O)C[Cl]` => `C(=O)C*` +**nitrile** `C(#N)` => `C(=N)*` +**vinylsulfonamide** `S(=O)(=O)C=C` => `S(=O)(=O)CC*` +**bromoalkyne** `C#C[Br]` => `C(=C)*` + +Additionally, `.possible_definitions` contains two (or more) that may be added experimentally (don't currently work). + +**aurothiol** `S[Au]P(CC)(CC)CC` => `S[Au]*` +**aldehyde** `[C:H1]=O` => `C(O)*` + +There is a quick way to get a warhead definition too + + Victor.get_warhead_definition(warhead_name) + +In terms of Rosetta constraints (restraints), these can be added with + + Victor.add_constraint_to_warhead(name=constrain_name, constraint=constraint) + +For example: + +* _chloroacetamide_: `AtomPair H 145A OY 1B HARMONIC 2.1 0.2` +* _nitrile_: `AtomPair H 145A NX 1B HARMONIC 2.1 0.2` +* _acrylamide_: `AtomPair H 143A OZ 1B HARMONIC 2.1 0.2` +* _vinylsulfonamide_: `AtomPair H 143A OZ1 1B HARMONIC 2.1 0.2` + +Currently, only cysteine details are known to `Victor`. Cf. `.covalent_definitions`. + +To convert a react_ive_ SMILES to a dummy-atom–marked react_ed_ SMILES: + + Victor.make_all_warhead_combinations(smiles, warhead_name) + +### Untested backdoor +The default dummy atom can be overridden with `Monster.dummy:Chem.Mol` and `Fragmenstein.dummy_symbol:str`. diff --git a/documentation/covid.md b/documentation/covid.md index 12a3411..d684eb3 100644 --- a/documentation/covid.md +++ b/documentation/covid.md @@ -8,7 +8,7 @@ However, there are some problems: * the form does not have a `no inspiration hit` option, so many users submitted `x0072` the first as inspiration when submitting docked libraries. * the inspiration hits are common to a group of submissions by a user, even if one went into one and another to another. * some pockets have many hits, so a large amount of not fully overlapping hits are submitted -* some users submitted a mispelt hit +* some users submitted a mispelt hit code ## Custom class @@ -28,7 +28,7 @@ For an example of the script used, see [covid.py](../covid.py). Note that this script runs on multiple cores. For a fews smiles, which takes about 30 seconds each there is no need. Also note that some molecules get stuck due to incorrectly entered inspirations. -For a comparision of how the three method fair with the daset see [three modes compared](three_modes_compared.md). +For a comparision of how the three method fair with the daset see [three modes compared](monster/three_modes_compared.md). ## Over-inspired problem diff --git a/documentation/logging_and_debugging.md b/documentation/logging_and_debugging.md index 5cb63b6..295f273 100644 --- a/documentation/logging_and_debugging.md +++ b/documentation/logging_and_debugging.md @@ -38,3 +38,8 @@ at each step: for i, mod in enumerate(victor.modifications): pymol.cmd.read_molstr(Chem.MolToMolBlock(mod, kekulize=False), f'step{i}') pymol.cmd.save('test.pse') + +The `Monster` class can trip up, and this can happen at various steps. +`victor.modifications` contains a stack of the various step, such as the collapsed rings to the rectification. + + diff --git a/documentation/fragmenstein.md b/documentation/monster/monster.md similarity index 84% rename from documentation/fragmenstein.md rename to documentation/monster/monster.md index 7ebbedb..6191821 100644 --- a/documentation/fragmenstein.md +++ b/documentation/monster/monster.md @@ -1,17 +1,20 @@ # Fragmenstein ## Description +> NB. The class `Monster` was formerly called `Fragmenstein` + + The `Fragmenstein` class places the followup placing algorithm. One problem in doing so is mapping atoms from the hits to the followup. Three modes were tested. The three modes rely heavily on mapping one-to-one atomic coordinates of overlapping atoms between hits -within a 2Å radius (see [Position Mapping code](../fragmenstein/monster/positional_mapping.py)). +within a 2Å radius (see [Position Mapping code](../../fragmenstein/monster/positional_mapping.py)). - +
-x0692 common with x0305 -x0305 common with x0692 +x0692 common with x0305 +x0305 common with x0692
The three have different strengths. And which is better depends actually on the dataset. @@ -24,7 +27,7 @@ All three of these modes place the atoms of the followup and "project" the missi ## Mapping modes ### Full merging -> The main documentation for this mode can be found [here](fragmenstein_full.md). +> The main documentation for this mode can be found [here](monster_full.md). The inspiration hits are merged creating a new merged template and the followup is mapped onto this. This makes it much faster than the unmerged mode, so sliding scale of MCS mappings is done @@ -32,7 +35,7 @@ This makes it much faster than the unmerged mode, so sliding scale of MCS mappin This was the primary method used, until partial mapping was introduced to overcome the incorrect hit issue. -![grid](../images/grid.jpg) +![grid](../../images/grid.jpg) #### Pros @@ -48,11 +51,11 @@ This was the primary method used, until partial mapping was introduced to overco * Sensitive to too many and to incorrect hits (a COVID moonshot dataset problem) * Ring overlaps can result in really odd rings(∗) -∗ See [work in progress](wip.md) for the ring collapsing code which aims to fix this. +∗ See [work in progress](../wip.md) for the ring collapsing code which aims to fix this. ### Partial mapping -> The main documentation for this mode can be found [here](fragmenstein_partial.md). +> The main documentation for this mode can be found [here](monster_partial.md). As above but inconsistent hits are excluded. The "inconsistent" hits (`dodgies` in the code) are those who when seen in trio of hits do not map consistently. @@ -114,15 +117,15 @@ Consequently, this is not possible. Therefore in the case of sidechains that are novel in the followup a optimised conformer is a aligned against the half placed followup using the 3-4 atoms that are the closest neighbours within the half-placed structure and the side chain position copied from there for each bit. -fragments of x0305 -fragments of x0305 +fragments of x0305 +fragments of x0305 ### Imperfect projection The projection approach is not perfect, but it is not constrained so generally gets fixed without issue during minimisation. This problem is quite apparent in the cases where atoms connecting to the sulfur are added: -![deviant](../images/S_deviant.png) +![deviant](../../images/S_deviant.png) The way the projection is done is via a single conformer. diff --git a/documentation/fragmenstein_full.md b/documentation/monster/monster_full.md similarity index 99% rename from documentation/fragmenstein_full.md rename to documentation/monster/monster_full.md index f3dea64..75e2de9 100644 --- a/documentation/fragmenstein_full.md +++ b/documentation/monster/monster_full.md @@ -84,7 +84,7 @@ This step is needed to avoid weird matches with the followup. ## Issues to be aware of -> See also [work in progress](wip.md) +> See also [work in progress](../wip.md) Here is an example with a few issues. diff --git a/documentation/fragmenstein_partial.md b/documentation/monster/monster_partial.md similarity index 98% rename from documentation/fragmenstein_partial.md rename to documentation/monster/monster_partial.md index 191126e..e34aa44 100644 --- a/documentation/fragmenstein_partial.md +++ b/documentation/monster/monster_partial.md @@ -66,7 +66,7 @@ Gives 5 ['x1093', 'x0395', 'x0967', 'x0107'] 10 ['x0395', 'x1093', 'x0967', 'x0434'] -![toomany](../images/dodgy_killer.png) +![toomany](../../images/dodgy_killer.png) x1093 and x0107 are removed at 2 Å due to the ring. Consequently, the code implemented to get rid of dodgy mappings does not include rings. diff --git a/documentation/no_template.md b/documentation/monster/no_template.md similarity index 94% rename from documentation/no_template.md rename to documentation/monster/no_template.md index a8babd7..47720b8 100644 --- a/documentation/no_template.md +++ b/documentation/monster/no_template.md @@ -18,7 +18,7 @@ What happens is that all rings are replaced with a single atom that can be unpac ``Ring`` class in ``core._collapse_ring`` does exactly that (inherited by ``Frankenstein``). -![collapse](../images/atom_collapse.png) +![collapse](../../images/atom_collapse.png) But it can be a bit unpredictable in the upacking step after merging, therefore it is not implemented in Victor with SMILES @@ -54,7 +54,7 @@ Where `ori` is the original index. All ringcore atoms have an origin of -1. ## Logging -> See [logging_and_debugging.md](logging_and_debugging.md) for more. +> See [logging_and_debugging.md](../logging_and_debugging.md) for more. The correct logging is via Victor's journal. The logging log `Fragmenstein`. @@ -70,13 +70,13 @@ A issue arises merging different warheads. In which case they can be ignore, kep Bonding to a warhead is forbidden. Therefore, mergers may link up in unexpected ways, such as this, wherein two hits actually have different warheads. -![harmony](../images/harmonising_warheads.png) +![harmony](../../images/harmonising_warheads.png) ## Mad ones If two rings intersect perpendicularly (_e.g._ `x0708-x2193`) the resulting bonding will be unexpected ("emergency bonding" warning appears). -![cross-ring](../images/cross_ring.png) +![cross-ring](../../images/cross_ring.png) I have no idea how to resolve this or whether it should be. diff --git a/documentation/note_about_merging_operations.md b/documentation/monster/note_about_merging_operations.md similarity index 67% rename from documentation/note_about_merging_operations.md rename to documentation/monster/note_about_merging_operations.md index ce8ea12..7552403 100644 --- a/documentation/note_about_merging_operations.md +++ b/documentation/monster/note_about_merging_operations.md @@ -21,18 +21,4 @@ However, the ring collapse code deals with odd ring sizes. ## Mapping Also, mapping is done by the class `GPM` in `positional_mapping.py`. -This is used by both SMILES no-merging mode and the automerging mode. - -## Future idea -This is all a bit messy. - -~One _likely_ future change is moving ring corrections to `Rectifier`.~ —Done. - -Furthermore, the module is called `fragmenstein`, -which contains a class `Fragmenstein`, yet the pipeline is called `Victor`. - -One _possible_ future change could be to break up the class `Fragmenstein` -into its two main modes (no-merge SMILES and automerging) and -removing the less productive options. - -Feedback welcome! \ No newline at end of file +This is used by both SMILES no-merging mode and the automerging mode. \ No newline at end of file diff --git a/documentation/three_modes_compared.md b/documentation/monster/three_modes_compared.md similarity index 82% rename from documentation/three_modes_compared.md rename to documentation/monster/three_modes_compared.md index e78cbba..5680eb1 100644 --- a/documentation/three_modes_compared.md +++ b/documentation/monster/three_modes_compared.md @@ -4,14 +4,14 @@ > but the conclusion is the same. `none` mode of merging —i.e. mapping the followup molecule to each hit is the best > even when there are incorrect inspiration hits. -As [discussed](../README.md), it has three main parts: +As [discussed](../../README.md), it has three main parts: * the pipeline (Victor class) * the minimiser (Egor class) and * the followup placing algorithm (Fragmenstein class) -The latter has three modes as discussed in [the fragmenstein page](fragmenstein.md): "full-merging", "partial-merging" and "no-merging" for mapping. +The latter has three modes as discussed in [the fragmenstein page](monster.md): "full-merging", "partial-merging" and "no-merging" for mapping. -Each has advantages and disadvantage. For the [covid](covid.md) data, an analysis was done to figure out which. +Each has advantages and disadvantage. For the [covid](../covid.md) data, an analysis was done to figure out which. 50 followups were randomly chosen and placed with the three modes (165 total poses were done, +10% for safety). @@ -26,24 +26,24 @@ The medians of the various scores are: No merging mapping is better for both number of atoms used and the ∆∆G_bind. It scored worse for time and slightly for RMSD. -![compare-N-atoms.png](../images/compare-N-atoms.png) -![compare-rmsd.png](../images/compare-rmsd.png) -![compare-∆∆G.png](../images/compare-∆∆G.png) -![compare-runtime.png](../images/compare-runtime.png) +![compare-N-atoms.png](../../images/compare-N-atoms.png) +![compare-rmsd.png](../../images/compare-rmsd.png) +![compare-∆∆G.png](../../images/compare-∆∆G.png) +![compare-runtime.png](../../images/compare-runtime.png) It is clear that the no merging mapping when it fails it fails badly. So let's look solely at all ∆∆G < 0 ones: -![compare-∆∆G2.png](../images/compare-∆∆G2.png) +![compare-∆∆G2.png](../../images/compare-∆∆G2.png) The outliers in ∆∆G are caused by erroneous hits being claimed to be inspirations. Here is one of these, WAR-XCH-b6889685-63 in the same colours as the graphs: -![image](../images/WAR-XCH-b6889685-63.png) +![image](../../images/WAR-XCH-b6889685-63.png) Namely the outlier is chosen as an inspiration and the bond length is not violated as the atoms from the mapped parts are not neighbours, so the 3 Å limit does not apply. Curiously, full-merger mapped to one cluster, while partial merger to the loner. The time problem is substantial for the none. -![compare-timeproblem.png](../images/compare-timeproblem.png). +![compare-timeproblem.png](../../images/compare-timeproblem.png). These are the offenders: | | name | mode | ∆∆G | comRMSD | N_constrained_atoms | runtime | N_hits | diff --git a/documentation/victor.md b/documentation/victor.md index d30c28e..8a08afe 100644 --- a/documentation/victor.md +++ b/documentation/victor.md @@ -1,12 +1,12 @@ # Victor -Victor is a pipeline class. This has many features and can be rather complicated in its setup: but then a point and click +Victor is the overarching class. This has many features and can be rather complicated in its setup: but then a point and click solution that works universally without customisation is a bad solution for molecular modelling. Victor does the following steps: * Is given a followup to test and the mol objects of its inspiration and the pdb template file. -* Calls Fragmenstein class +* Calls Monster class * Parameterises the mol * Generates the constraints * Calls Igor @@ -15,7 +15,7 @@ Victor does the following steps: Whereas each instance call of Victor can be customised with various arguments, such as `smiles` and `hits` etc. Core settings controlling its behaviour can be set via class attributes: -The following control fragmenstein and are described in [Fragmenstein class documentation](fragmenstein.md). +The following control fragmenstein and are described in [Fragmenstein class documentation](monster/monster.md). * `fragmenstein_merging_mode` * `fragmenstein_debug_draw` diff --git a/documentation/wip.md b/documentation/wip.md index 0349a00..c9080a7 100644 --- a/documentation/wip.md +++ b/documentation/wip.md @@ -1,4 +1,16 @@ * `test.py` and the various jupyter notebook I have need to go into a proper testing suite. * Complete validation classmethod * The mapping function can get stuck on nasty submissions in the MCS call. thread. -* Figures need remaking to reflect the current code \ No newline at end of file +* Figures need remaking to reflect the current code + +## Future idea +This is all a bit messy. + +Furthermore, the module is called `fragmenstein`, +which contains a class `Fragmenstein`, yet the pipeline is called `Victor`. + +One _possible_ future change could be to break up the class `Fragmenstein` +into its two main modes (no-merge SMILES and automerging) and +removing the less productive options. + +Feedback welcome! \ No newline at end of file diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-6lze.mol b/fragmenstein/mpro/data/hit_mols/Mpro-6lze.mol new file mode 100644 index 0000000..04d0872 --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-6lze.mol @@ -0,0 +1,74 @@ + + RDKit 3D + + 33 36 0 0 0 0 0 0 0 0999 V2000 + 9.0870 1.8140 22.4930 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.1810 7.0460 25.7240 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.1680 7.6080 24.4470 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.1360 6.7900 23.3350 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.1240 5.3830 23.5010 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.1430 4.8300 24.7520 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.1710 5.6670 25.8880 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.1210 3.4170 24.5720 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.0760 3.1930 23.2060 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.0970 4.3690 22.5810 N 0 0 0 0 0 0 0 0 0 0 0 0 + 8.9540 1.7420 21.3310 O 0 0 0 0 0 0 0 0 0 0 0 0 + 9.3390 0.6000 23.3010 N 0 0 0 0 0 0 0 0 0 0 0 0 + 9.4100 -0.6490 22.6270 C 0 0 2 0 0 0 0 0 0 0 0 0 + 8.0590 -1.0890 22.0810 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.0560 -0.8910 22.6710 O 0 0 0 0 0 0 0 0 0 0 0 0 + 9.9220 -1.7470 23.6010 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.3190 -1.3780 24.2560 C 0 0 2 0 0 0 0 0 0 0 0 0 + 12.3750 -1.1980 23.1580 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.7490 -0.9120 23.7720 C 0 0 0 0 0 0 0 0 0 0 0 0 + 14.1630 -2.0110 24.7490 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.0960 -2.2660 25.8230 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.7180 -2.5110 25.2050 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.3670 0.8420 17.1750 O 0 0 0 0 0 0 0 0 0 0 0 0 + 5.7420 0.8700 18.1650 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.4940 1.7310 18.4570 N 0 0 0 0 0 0 0 0 0 0 0 0 + 4.1450 1.4440 19.6460 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.9480 -0.0010 20.0810 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.0050 0.0070 19.4980 C 0 0 1 0 0 0 0 0 0 0 0 0 + 6.4230 -1.5020 19.0130 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.8690 -2.3340 20.2290 C 0 0 2 0 0 0 0 0 0 0 0 0 + 8.1140 -1.8150 20.8270 N 0 0 0 0 0 0 0 0 0 0 0 0 + 6.9430 -3.8160 19.8740 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.9370 -4.3710 19.5930 O 0 0 0 0 0 0 0 0 0 0 0 0 + 3 2 2 0 + 4 3 1 0 + 5 4 2 0 + 6 5 1 0 + 7 6 2 0 + 7 2 1 0 + 8 6 1 0 + 9 8 2 0 + 9 1 1 0 + 10 9 1 0 + 10 5 1 0 + 11 1 2 0 + 12 1 1 0 + 13 12 1 0 + 14 13 1 0 + 15 14 2 0 + 13 16 1 1 + 17 16 1 6 + 18 17 1 0 + 19 18 1 0 + 20 19 1 0 + 21 20 1 0 + 22 21 1 0 + 22 17 1 0 + 24 23 2 0 + 25 24 1 0 + 26 25 1 0 + 27 26 1 0 + 28 27 1 0 + 28 24 1 0 + 28 29 1 6 + 30 29 1 6 + 31 30 1 0 + 31 14 1 0 + 32 30 1 0 + 33 32 2 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-6m0k.mol b/fragmenstein/mpro/data/hit_mols/Mpro-6m0k.mol new file mode 100644 index 0000000..993384f --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-6m0k.mol @@ -0,0 +1,76 @@ + + RDKit 3D + + 34 37 0 0 0 0 0 0 0 0999 V2000 + 9.2120 1.7660 22.3390 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.0470 6.9430 25.7890 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.8650 7.5430 24.5350 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.8270 6.7570 23.3790 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.9740 5.3490 23.4840 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.1530 4.7630 24.7100 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.1930 5.5650 25.8910 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.2630 3.3610 24.4730 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.1360 3.1630 23.0890 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.9720 4.3500 22.5160 N 0 0 0 0 0 0 0 0 0 0 0 0 + 9.0530 1.6850 21.1780 O 0 0 0 0 0 0 0 0 0 0 0 0 + 9.5140 0.5390 23.1410 N 0 0 0 0 0 0 0 0 0 0 0 0 + 9.6240 -0.7690 22.4640 C 0 0 2 0 0 0 0 0 0 0 0 0 + 8.2660 -1.3580 22.1320 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.4210 -1.4650 22.9490 O 0 0 0 0 0 0 0 0 0 0 0 0 + 10.4630 -1.6660 23.3550 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.7950 -0.9290 23.5110 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.0440 -0.1620 24.6270 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.7360 -1.0030 22.4940 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.2480 0.5130 24.7430 C 0 0 0 0 0 0 0 0 0 0 0 0 + 14.1900 0.4290 23.7300 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.9380 -0.3270 22.6100 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.5080 1.2600 25.8500 F 0 0 0 0 0 0 0 0 0 0 0 0 + 6.1640 0.8170 17.0960 O 0 0 0 0 0 0 0 0 0 0 0 0 + 5.6690 0.8990 18.1490 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.5000 1.8180 18.5590 N 0 0 0 0 0 0 0 0 0 0 0 0 + 4.2900 1.5900 19.7880 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.1080 0.1450 20.1920 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.0680 0.0770 19.4750 C 0 0 1 0 0 0 0 0 0 0 0 0 + 6.3410 -1.5240 19.0850 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.8030 -2.3510 20.3060 C 0 0 2 0 0 0 0 0 0 0 0 0 + 8.0430 -1.7710 20.7630 N 0 0 0 0 0 0 0 0 0 0 0 0 + 6.9690 -3.7960 19.9110 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.0010 -4.4230 19.6630 O 0 0 0 0 0 0 0 0 0 0 0 0 + 3 2 2 0 + 4 3 1 0 + 5 4 2 0 + 6 5 1 0 + 7 6 2 0 + 7 2 1 0 + 8 6 1 0 + 9 8 2 0 + 9 1 1 0 + 10 9 1 0 + 10 5 1 0 + 11 1 2 0 + 12 1 1 0 + 13 12 1 0 + 14 13 1 0 + 15 14 2 0 + 13 16 1 1 + 17 16 1 0 + 18 17 2 0 + 19 17 1 0 + 20 18 1 0 + 21 20 2 0 + 22 21 1 0 + 22 19 2 0 + 23 20 1 0 + 25 24 2 0 + 26 25 1 0 + 27 26 1 0 + 28 27 1 0 + 29 28 1 0 + 29 25 1 0 + 29 30 1 6 + 31 30 1 6 + 32 31 1 0 + 32 14 1 0 + 33 31 1 0 + 34 33 2 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-6m2n.mol b/fragmenstein/mpro/data/hit_mols/Mpro-6m2n.mol new file mode 100644 index 0000000..bd64041 --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-6m2n.mol @@ -0,0 +1,47 @@ + + RDKit 3D + + 20 22 0 0 0 0 0 0 0 0999 V2000 + 11.3190 -3.4180 24.9280 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.3000 -3.7820 25.8300 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.3260 -1.7880 23.3300 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.2010 -0.5520 22.8120 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.1620 -0.2130 21.8810 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.1830 -1.1600 20.6310 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.6460 -3.6500 21.8320 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.0450 0.9350 21.4040 O 0 0 0 0 0 0 0 0 0 0 0 0 + 8.2630 -1.3050 21.5350 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.4510 -2.5640 22.1070 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.5980 -3.4800 20.9430 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.7830 -4.5180 20.6400 O 0 0 0 0 0 0 0 0 0 0 0 0 + 6.3710 -2.2330 20.3430 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.3400 -2.0640 19.4640 O 0 0 0 0 0 0 0 0 0 0 0 0 + 6.9530 0.0350 20.0450 O 0 0 0 0 0 0 0 0 0 0 0 0 + 9.4760 -2.7960 22.9960 O 0 0 0 0 0 0 0 0 0 0 0 0 + 11.3710 -2.1810 24.2860 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.4300 -1.3220 24.5810 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.4060 -1.6980 25.4830 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.3410 -2.9240 26.1050 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 2 0 + 4 3 2 0 + 5 4 1 0 + 8 5 2 0 + 9 6 2 0 + 9 5 1 0 + 10 9 1 0 + 10 7 2 0 + 11 7 1 0 + 12 11 1 0 + 13 11 2 0 + 13 6 1 0 + 14 13 1 0 + 15 6 1 0 + 16 10 1 0 + 16 3 1 0 + 17 3 1 0 + 17 1 1 0 + 18 17 2 0 + 19 18 1 0 + 20 19 2 0 + 20 2 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-6w63.mol b/fragmenstein/mpro/data/hit_mols/Mpro-6w63.mol new file mode 100644 index 0000000..60a492c --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-6w63.mol @@ -0,0 +1,76 @@ + + RDKit 3D + + 34 37 0 0 0 0 0 0 0 0999 V2000 + 6.1990 -2.5110 21.6400 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.6830 -0.0530 21.5290 C 0 0 1 0 0 0 0 0 0 0 0 0 + 7.9160 0.8930 21.6290 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.9490 2.8720 22.8920 C 0 0 1 0 0 0 0 0 0 0 0 0 + 8.2800 4.1940 23.2580 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.3040 5.2720 23.6120 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.1250 4.8210 24.7840 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.7640 3.4620 24.5890 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.8180 2.3720 24.0590 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.1980 0.2130 20.1350 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.1310 1.0250 19.9760 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.7010 1.3130 18.7060 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.3640 0.7730 17.6200 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.8400 -0.3230 19.0520 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.4140 -1.5060 22.5530 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.4370 -1.3110 23.9380 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.6500 -1.4230 24.6280 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.8250 -1.7420 23.9350 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.1860 -1.8620 24.7150 C 0 0 2 0 0 0 0 0 0 0 0 0 + 12.3980 -0.5520 25.4810 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.4060 -2.0830 23.7970 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.1190 -3.0300 25.6960 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.7840 -1.9390 22.5560 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.5660 -1.8260 21.8620 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.5690 -3.9520 22.0610 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.6950 -4.3940 22.7290 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.4230 -6.0810 22.3670 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.1120 -1.3810 21.8550 N 0 0 0 0 0 0 0 0 0 0 0 0 + 7.8890 1.9160 22.6860 N 0 0 0 0 0 0 0 0 0 0 0 0 + 6.4290 -0.0250 17.7990 N 0 0 0 0 0 0 0 0 0 0 0 0 + 7.5810 -5.7050 22.9060 N 0 0 0 0 0 0 0 0 0 0 0 0 + 5.8010 -5.0010 21.8550 N 0 0 0 0 0 0 0 0 0 0 0 0 + 5.1600 -2.2760 21.1300 O 0 0 0 0 0 0 0 0 0 0 0 0 + 8.8300 0.8180 20.8480 O 0 0 0 0 0 0 0 0 0 0 0 0 + 2 3 1 6 + 5 4 1 0 + 6 5 1 0 + 7 6 1 0 + 8 7 1 0 + 9 8 1 0 + 9 4 1 0 + 10 2 1 0 + 11 10 2 0 + 12 11 1 0 + 13 12 2 0 + 14 10 1 0 + 16 15 2 0 + 17 16 1 0 + 18 17 2 0 + 19 18 1 0 + 19 20 1 1 + 21 19 1 0 + 22 19 1 0 + 23 18 1 0 + 24 23 2 0 + 24 15 1 0 + 25 1 1 0 + 26 25 2 0 + 28 2 1 0 + 28 1 1 0 + 28 15 1 0 + 29 3 1 0 + 4 29 1 1 + 30 13 1 0 + 30 14 2 0 + 31 27 1 0 + 31 26 1 0 + 32 27 2 0 + 32 25 1 0 + 33 1 2 0 + 34 3 2 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-6wnp.mol b/fragmenstein/mpro/data/hit_mols/Mpro-6wnp.mol new file mode 100644 index 0000000..bf8f799 --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-6wnp.mol @@ -0,0 +1,81 @@ + + RDKit 3D + + 37 39 0 0 0 0 0 0 0 0999 V2000 + 11.3570 4.3130 23.4860 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.0290 5.3760 22.7310 N 0 0 0 0 0 0 0 0 0 0 0 0 + 11.7670 3.9090 24.5400 O 0 0 0 0 0 0 0 0 0 0 0 0 + 13.2650 6.0100 23.2480 C 0 0 1 0 0 0 0 0 0 0 0 0 + 14.2540 4.9430 23.7780 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.9120 6.7920 22.0770 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.8660 6.9780 24.3930 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.1360 3.7720 22.8800 N 0 0 0 0 0 0 0 0 0 0 0 0 + 9.4660 2.7110 23.5740 C 0 0 1 0 0 0 0 0 0 0 0 0 + 7.9680 2.9420 23.7960 C 0 0 2 0 0 0 0 0 0 0 0 0 + 7.3540 1.6310 24.3630 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.2790 3.3810 22.4830 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.8940 4.0750 24.8530 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.7040 1.4540 22.7090 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.3770 1.3870 21.5590 O 0 0 0 0 0 0 0 0 0 0 0 0 + 10.3650 0.2790 23.2840 N 0 0 0 0 0 0 0 0 0 0 0 0 + 10.7770 0.2090 24.5610 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.6120 -1.1310 22.5630 C 0 0 1 0 0 0 0 0 0 0 0 0 + 11.5530 -1.7140 23.2940 C 0 0 2 0 0 0 0 0 0 0 0 0 + 11.8280 -0.9160 24.5740 C 0 0 1 0 0 0 0 0 0 0 0 0 + 12.9920 -1.3320 23.6540 C 0 0 2 0 0 0 0 0 0 0 0 0 + 13.5480 -0.1140 22.8670 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.8800 -2.5350 24.0250 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.1940 -1.7070 22.5410 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.5250 -1.7700 23.5210 O 0 0 0 0 0 0 0 0 0 0 0 0 + 8.6880 -2.1230 21.2250 N 0 0 0 0 0 0 0 0 0 0 0 0 + 7.3380 -2.6840 21.0690 C 0 0 1 0 0 0 0 0 0 0 0 0 + 6.4280 -1.7620 20.2370 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.1670 -0.4710 21.0850 C 0 0 2 0 0 0 0 0 0 0 0 0 + 5.2990 -0.6980 22.3450 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.0420 0.4190 20.5190 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.4150 0.4860 21.9270 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.2970 -4.7860 21.2810 O 0 0 0 0 0 0 0 0 0 0 0 0 + 7.4550 -4.0650 20.4290 C 0 0 1 0 0 0 0 0 0 0 0 0 + 5.3130 -4.6280 19.5280 O 0 0 0 0 0 0 0 0 0 0 0 0 + 6.0800 -4.7590 20.4380 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.6970 -5.5560 21.5960 N 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 1 0 + 3 1 2 0 + 4 2 1 0 + 4 5 1 1 + 6 4 1 0 + 7 4 1 0 + 8 1 1 0 + 9 8 1 6 + 10 9 1 0 + 10 11 1 1 + 12 10 1 0 + 13 10 1 0 + 14 9 1 0 + 15 14 2 0 + 16 14 1 0 + 17 16 1 0 + 18 16 1 0 + 19 18 1 6 + 20 17 1 6 + 20 19 1 0 + 21 20 1 0 + 21 19 1 0 + 21 22 1 6 + 23 21 1 0 + 18 24 1 1 + 25 24 2 0 + 26 24 1 0 + 27 26 1 0 + 27 28 1 6 + 29 28 1 6 + 30 29 1 0 + 31 29 1 0 + 32 31 1 0 + 32 30 1 0 + 34 33 1 1 + 34 27 1 0 + 36 35 2 0 + 36 34 1 0 + 37 36 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-6wtj.mol b/fragmenstein/mpro/data/hit_mols/Mpro-6wtj.mol new file mode 100644 index 0000000..677e078 --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-6wtj.mol @@ -0,0 +1,64 @@ + + RDKit 3D + + 29 30 0 0 0 0 0 0 0 0999 V2000 + 8.4290 3.9360 22.4730 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.2190 3.0200 23.2180 O 0 0 0 0 0 0 0 0 0 0 0 0 + 9.6630 1.8960 22.4860 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.6300 1.8950 21.3020 O 0 0 0 0 0 0 0 0 0 0 0 0 + 6.9260 3.7010 22.7180 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.9880 4.4910 22.0560 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.6230 4.3080 22.2680 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.1980 3.3160 23.1380 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.1310 2.5170 23.8010 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.4950 2.7070 23.5970 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.1690 0.7190 23.2000 N 0 0 0 0 0 0 0 0 0 0 0 0 + 10.3080 -0.5180 22.4580 C 0 0 2 0 0 0 0 0 0 0 0 0 + 8.9040 -0.9670 22.0460 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.9950 -0.8650 22.8030 O 0 0 0 0 0 0 0 0 0 0 0 0 + 10.9320 -1.6000 23.3090 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.3960 -1.2380 23.5590 C 0 0 2 0 0 0 0 0 0 0 0 0 + 13.1510 -1.2050 22.2360 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.0400 -2.2540 24.5090 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.7200 -1.5110 20.6930 N 0 0 0 0 0 0 0 0 0 0 0 0 + 7.4070 -1.9630 20.2300 C 0 0 2 0 0 0 0 0 0 0 0 0 + 7.6110 -3.4440 19.8910 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.3830 -4.0880 19.7260 O 0 0 0 0 0 0 0 0 0 0 0 0 + 6.9640 -1.1440 19.0030 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.5370 0.3130 19.4100 C 0 0 2 0 0 0 0 0 0 0 0 0 + 5.2830 0.2630 20.3050 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.6190 1.5680 20.1110 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.9660 1.9760 18.6970 N 0 0 0 0 0 0 0 0 0 0 0 0 + 6.1710 1.1600 18.2960 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.7160 1.2390 17.2460 O 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 1 0 + 3 2 1 0 + 4 3 1 0 + 5 1 1 0 + 6 5 1 0 + 7 6 1 0 + 8 7 1 0 + 9 8 1 0 + 10 9 1 0 + 10 5 1 0 + 11 3 1 0 + 12 11 1 0 + 13 12 1 0 + 14 13 1 0 + 12 15 1 1 + 16 15 1 0 + 16 17 1 6 + 18 16 1 0 + 19 13 1 0 + 20 19 1 0 + 20 21 1 6 + 22 21 1 0 + 23 20 1 0 + 24 23 1 6 + 25 24 1 0 + 26 25 1 0 + 27 26 1 0 + 28 27 1 0 + 28 24 1 0 + 29 28 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-6wtk.mol b/fragmenstein/mpro/data/hit_mols/Mpro-6wtk.mol new file mode 100644 index 0000000..1d24266 --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-6wtk.mol @@ -0,0 +1,64 @@ + + RDKit 3D + + 29 30 0 0 0 0 0 0 0 0999 V2000 + 8.4040 4.0330 22.4170 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.2690 3.0950 23.0080 O 0 0 0 0 0 0 0 0 0 0 0 0 + 9.5910 1.9480 22.2450 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.4960 1.9330 21.0560 O 0 0 0 0 0 0 0 0 0 0 0 0 + 6.9140 3.6990 22.6630 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.5200 2.5490 23.3520 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.1630 2.2870 23.5460 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.1920 3.1640 23.0600 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.5730 4.3110 22.3730 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.9300 4.5680 22.1760 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.0630 0.7700 22.9560 N 0 0 0 0 0 0 0 0 0 0 0 0 + 10.2720 -0.4900 22.2870 C 0 0 2 0 0 0 0 0 0 0 0 0 + 8.9130 -0.9980 21.8240 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.0270 -1.0230 22.6020 O 0 0 0 0 0 0 0 0 0 0 0 0 + 10.8460 -1.4620 23.3100 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.3550 -1.2470 23.4520 C 0 0 2 0 0 0 0 0 0 0 0 0 + 13.0280 -1.5400 22.1190 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.9540 -2.1800 24.5180 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.6840 -1.4430 20.4560 N 0 0 0 0 0 0 0 0 0 0 0 0 + 7.3630 -1.9300 20.0790 C 0 0 2 0 0 0 0 0 0 0 0 0 + 7.4900 -3.3980 19.6400 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.2500 -4.0520 19.6320 O 0 0 0 0 0 0 0 0 0 0 0 0 + 6.8440 -1.0970 18.9130 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.4580 0.2990 19.4260 C 0 0 2 0 0 0 0 0 0 0 0 0 + 5.2800 0.1820 20.4000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.3110 1.3260 20.0030 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.7040 1.7360 18.6820 N 0 0 0 0 0 0 0 0 0 0 0 0 + 6.0100 1.1140 18.3140 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.6040 1.2620 17.2820 O 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 1 0 + 3 2 1 0 + 4 3 2 0 + 5 1 1 0 + 6 5 2 0 + 7 6 1 0 + 8 7 2 0 + 9 8 1 0 + 10 9 2 0 + 10 5 1 0 + 11 3 1 0 + 12 11 1 0 + 13 12 1 0 + 14 13 2 0 + 12 15 1 1 + 16 15 1 0 + 16 17 1 6 + 18 16 1 0 + 19 13 1 0 + 20 19 1 0 + 20 21 1 6 + 22 21 1 0 + 23 20 1 0 + 24 23 1 6 + 25 24 1 0 + 26 25 1 0 + 27 26 1 0 + 28 27 1 0 + 28 24 1 0 + 29 28 2 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-6wtt.mol b/fragmenstein/mpro/data/hit_mols/Mpro-6wtt.mol new file mode 100644 index 0000000..7d45be3 --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-6wtt.mol @@ -0,0 +1,64 @@ + + RDKit 3D + + 29 30 0 0 0 0 0 0 0 0999 V2000 + 11.0940 3.7500 23.7860 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.9230 3.4840 22.8570 O 0 0 0 0 0 0 0 0 0 0 0 0 + 9.8790 2.1890 22.1940 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.4500 2.1460 21.0270 O 0 0 0 0 0 0 0 0 0 0 0 0 + 12.1420 4.7760 23.3440 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.6560 5.7560 24.2330 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.5980 6.7160 23.8110 C 0 0 0 0 0 0 0 0 0 0 0 0 + 14.0600 6.7050 22.4830 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.5690 5.7440 21.6000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.6280 4.7950 22.0310 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.3810 0.9970 22.8860 N 0 0 0 0 0 0 0 0 0 0 0 0 + 10.4530 -0.2930 22.1700 C 0 0 2 0 0 0 0 0 0 0 0 0 + 9.0730 -0.6900 21.9370 C 0 0 1 0 0 0 0 0 0 0 0 0 + 8.2500 -0.2340 22.7250 O 0 0 0 0 0 0 0 0 0 0 0 0 + 11.1780 -1.3950 22.9780 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.6200 -0.9640 23.3860 C 0 0 2 0 0 0 0 0 0 0 0 0 + 13.4770 -0.5200 22.1450 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.3480 -2.0570 24.1820 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.7570 -1.4790 20.7850 N 0 0 0 0 0 0 0 0 0 0 0 0 + 7.3680 -1.9690 20.3790 C 0 0 2 0 0 0 0 0 0 0 0 0 + 7.3980 -3.4270 19.7690 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.1220 -3.8210 19.2800 O 0 0 0 0 0 0 0 0 0 0 0 0 + 6.6930 -1.0160 19.3140 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.4470 0.4610 19.7650 C 0 0 2 0 0 0 0 0 0 0 0 0 + 5.0710 0.7020 20.4340 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.5310 2.0450 19.8680 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.2880 2.2380 18.6310 N 0 0 0 0 0 0 0 0 0 0 0 0 + 6.3940 1.3680 18.5080 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.1640 1.3380 17.5760 O 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 1 0 + 3 2 1 0 + 4 3 1 0 + 5 1 1 0 + 6 5 1 0 + 7 6 1 0 + 8 7 1 0 + 9 8 1 0 + 10 5 1 0 + 10 9 1 0 + 11 3 1 0 + 12 11 1 0 + 13 12 1 0 + 13 14 1 6 + 12 15 1 1 + 16 15 1 0 + 16 17 1 6 + 18 16 1 0 + 19 13 1 0 + 20 19 1 0 + 20 21 1 6 + 22 21 1 0 + 23 20 1 0 + 24 23 1 6 + 25 24 1 0 + 26 25 1 0 + 27 26 1 0 + 28 27 1 0 + 28 24 1 0 + 29 28 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-6xa4.mol b/fragmenstein/mpro/data/hit_mols/Mpro-6xa4.mol new file mode 100644 index 0000000..8313d13 --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-6xa4.mol @@ -0,0 +1,20 @@ + + RDKit 3D + + 8 7 0 0 0 0 0 0 0 0999 V2000 + -0.3670 4.0080 -6.0110 C 0 0 0 0 0 0 0 0 0 0 0 0 + -1.0840 3.6960 -5.0920 O 0 0 0 0 0 0 0 0 0 0 0 0 + -1.1510 4.3540 -7.2920 C 0 0 2 0 0 0 0 0 0 0 0 0 + -1.8460 3.0130 -7.6810 C 0 0 0 0 0 0 0 0 0 0 0 0 + -2.7250 3.1480 -8.8440 C 0 0 0 0 0 0 0 0 0 0 0 0 + -3.5470 1.5150 -9.2000 S 0 0 0 0 0 0 0 0 0 0 0 0 + -5.3280 1.8600 -9.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + -0.2530 4.8680 -8.3840 N 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 1 0 + 3 1 1 0 + 4 3 1 0 + 5 4 1 0 + 6 5 1 0 + 7 6 1 0 + 3 8 1 6 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-6xb0.mol b/fragmenstein/mpro/data/hit_mols/Mpro-6xb0.mol new file mode 100644 index 0000000..e386943 --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-6xb0.mol @@ -0,0 +1,20 @@ + + RDKit 3D + + 8 7 0 0 0 0 0 0 0 0999 V2000 + 6.3590 -5.0420 17.0070 N 0 0 0 0 0 0 0 0 0 0 0 0 + 7.7710 -5.3760 16.9150 C 0 0 2 0 0 0 0 0 0 0 0 0 + 7.9560 -6.7280 16.2460 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.2100 -7.6710 16.4200 O 0 0 0 0 0 0 0 0 0 0 0 0 + 8.4580 -5.3540 18.2900 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.3040 -3.7520 19.0070 S 0 0 0 0 0 0 0 0 0 0 0 0 + 7.0770 -4.0130 20.2030 O 0 0 0 0 0 0 0 0 0 0 0 0 + 5.9580 -4.8900 19.7340 O 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 1 1 + 3 2 1 0 + 4 3 1 0 + 5 2 1 0 + 6 5 1 0 + 7 6 1 0 + 8 7 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-6xb1.mol b/fragmenstein/mpro/data/hit_mols/Mpro-6xb1.mol new file mode 100644 index 0000000..df4584a --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-6xb1.mol @@ -0,0 +1,20 @@ + + RDKit 3D + + 8 7 0 0 0 0 0 0 0 0999 V2000 + 6.3410 -5.0300 16.9440 N 0 0 0 0 0 0 0 0 0 0 0 0 + 7.7520 -5.3350 16.8540 C 0 0 2 0 0 0 0 0 0 0 0 0 + 7.9750 -6.6850 16.1940 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.2540 -7.6490 16.3860 O 0 0 0 0 0 0 0 0 0 0 0 0 + 8.4390 -5.2880 18.2290 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.3770 -3.6690 18.9300 S 0 0 0 0 0 0 0 0 0 0 0 0 + 6.7670 -3.5910 19.5870 O 0 0 0 0 0 0 0 0 0 0 0 0 + 6.3490 -4.7790 20.4050 O 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 1 1 + 3 2 1 0 + 4 3 1 0 + 5 2 1 0 + 6 5 1 0 + 7 6 1 0 + 8 7 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-6xb2.mol b/fragmenstein/mpro/data/hit_mols/Mpro-6xb2.mol new file mode 100644 index 0000000..7e850e5 --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-6xb2.mol @@ -0,0 +1,23 @@ + + RDKit 3D + + 9 9 0 0 0 0 0 0 0 0999 V2000 + 18.2490 -12.9110 -6.0510 O 0 0 0 0 0 0 0 0 0 0 0 0 + 18.9610 -14.9350 -5.1340 N 0 0 0 0 0 0 0 0 0 0 0 0 + 16.6340 -14.6410 -5.3560 C 0 0 0 0 0 0 0 0 0 0 0 0 + 18.9980 -16.9710 -4.0360 O 0 0 0 0 0 0 0 0 0 0 0 0 + 18.0130 -14.0170 -5.5770 C 0 0 0 0 0 0 0 0 0 0 0 0 + 18.3850 -16.1090 -4.6470 C 0 0 0 0 0 0 0 0 0 0 0 0 + 16.9180 -16.1080 -5.0130 C 0 0 0 0 0 0 0 0 0 0 0 0 + 20.4190 -14.7260 -5.1690 C 0 0 0 0 0 0 0 0 0 0 0 0 + 20.8480 -13.2600 -5.1410 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5 1 2 0 + 5 3 1 0 + 5 2 1 0 + 6 4 2 0 + 6 2 1 0 + 7 6 1 0 + 7 3 1 0 + 8 2 1 0 + 9 8 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-6xbg.mol b/fragmenstein/mpro/data/hit_mols/Mpro-6xbg.mol new file mode 100644 index 0000000..27f44f1 --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-6xbg.mol @@ -0,0 +1,13 @@ + + RDKit 3D + + 4 4 0 0 0 0 0 0 0 0999 V2000 + 2.9560 3.5030 -10.4830 N 0 0 0 0 0 0 0 0 0 0 0 0 + 4.1130 2.6990 -10.4400 C 0 0 1 0 0 0 0 0 0 0 0 0 + 4.0440 1.2430 -10.9320 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.8380 2.2940 -11.7240 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 1 6 + 3 2 1 0 + 4 3 1 0 + 4 2 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-6xbh.mol b/fragmenstein/mpro/data/hit_mols/Mpro-6xbh.mol new file mode 100644 index 0000000..be56d6e --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-6xbh.mol @@ -0,0 +1,27 @@ + + RDKit 3D + + 11 11 0 0 0 0 0 0 0 0999 V2000 + 1.9560 10.8610 -9.4180 O 0 0 0 0 0 0 0 0 0 0 0 0 + 2.4310 10.1380 -10.2270 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.5910 10.3250 -10.9080 N 0 0 0 0 0 0 0 0 0 0 0 0 + 3.8840 9.2560 -11.8980 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2.9050 8.1420 -11.6930 C 0 0 0 0 0 0 0 0 0 0 0 0 + 1.8390 8.7880 -10.7330 C 0 0 1 0 0 0 0 0 0 0 0 0 + 1.3490 7.9320 -9.5730 C 0 0 0 0 0 0 0 0 0 0 0 0 + 0.6470 6.6260 -10.0580 C 0 0 2 0 0 0 0 0 0 0 0 0 + -0.5600 6.8970 -10.8210 N 0 0 0 0 0 0 0 0 0 0 0 0 + 0.3620 5.7320 -8.8040 C 0 0 0 0 0 0 0 0 0 0 0 0 + 1.4130 5.2300 -8.2190 O 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 2 0 + 3 2 1 0 + 4 3 1 0 + 5 4 1 0 + 6 5 1 0 + 6 2 1 0 + 6 7 1 1 + 8 7 1 0 + 8 9 1 1 + 10 8 1 0 + 11 10 2 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-6xbi.mol b/fragmenstein/mpro/data/hit_mols/Mpro-6xbi.mol new file mode 100644 index 0000000..dda238d --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-6xbi.mol @@ -0,0 +1,23 @@ + + RDKit 3D + + 9 9 0 0 0 0 0 0 0 0999 V2000 + -6.0720 11.4680 -14.6230 C 0 0 0 0 0 0 0 0 0 0 0 0 + -6.5940 11.3990 -15.9010 C 0 0 0 0 0 0 0 0 0 0 0 0 + -5.7250 11.0110 -16.9610 C 0 0 0 0 0 0 0 0 0 0 0 0 + -4.7470 11.0770 -14.3820 C 0 0 0 0 0 0 0 0 0 0 0 0 + -4.3680 10.6140 -16.7190 C 0 0 0 0 0 0 0 0 0 0 0 0 + -3.8170 10.6420 -15.4180 C 0 0 2 0 0 0 0 0 0 0 0 0 + -2.2930 9.0890 -13.9300 C 0 0 0 0 0 0 0 0 0 0 0 0 + -2.6510 9.5200 -12.8340 O 0 0 0 0 0 0 0 0 0 0 0 0 + -2.3550 10.1170 -15.0390 O 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 1 0 + 3 2 1 0 + 4 1 1 0 + 5 3 1 0 + 6 5 1 0 + 6 4 1 0 + 8 7 1 0 + 9 7 1 0 + 6 9 1 1 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-6xch.mol b/fragmenstein/mpro/data/hit_mols/Mpro-6xch.mol new file mode 100644 index 0000000..28c09ba --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-6xch.mol @@ -0,0 +1,26 @@ + + RDKit 3D + + 11 10 0 0 0 0 0 0 0 0999 V2000 + 0.3280 5.3070 -8.1010 N 0 0 0 0 0 0 0 0 0 0 0 0 + -0.0950 5.2440 -6.7210 C 0 0 2 0 0 0 0 0 0 0 0 0 + 1.0690 4.9270 -5.7390 C 0 0 0 0 0 0 0 0 0 0 0 0 + 0.6300 4.7730 -4.4150 O 0 0 0 0 0 0 0 0 0 0 0 0 + -1.1870 4.1890 -6.5120 C 0 0 0 0 0 0 0 0 0 0 0 0 + -1.9150 3.9070 -7.8080 C 0 0 0 0 0 0 0 0 0 0 0 0 + -3.3220 4.4990 -7.7290 C 0 0 0 0 0 0 0 0 0 0 0 0 + -3.2950 5.9410 -7.5790 N 0 0 0 0 0 0 0 0 0 0 0 0 + -4.4350 6.7060 -7.4840 C 0 0 0 0 0 0 0 0 0 0 0 0 + -5.6800 6.1180 -7.5280 N 0 0 0 0 0 0 0 0 0 0 0 0 + -4.3290 8.0760 -7.3420 N 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 1 6 + 3 2 1 0 + 4 3 1 0 + 5 2 1 0 + 6 5 1 0 + 7 6 1 0 + 8 7 1 0 + 9 8 1 0 + 10 9 1 0 + 11 9 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-6xfn.mol b/fragmenstein/mpro/data/hit_mols/Mpro-6xfn.mol new file mode 100644 index 0000000..45baccb --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-6xfn.mol @@ -0,0 +1,22 @@ + + RDKit 3D + + 9 8 0 0 0 0 0 0 0 0999 V2000 + -2.7170 1.6270 -13.0940 C 0 0 0 0 0 0 0 0 0 0 0 0 + -1.5050 2.3250 -12.4510 C 0 0 0 0 0 0 0 0 0 0 0 0 + -0.4600 2.7130 -13.4860 C 0 0 0 0 0 0 0 0 0 0 0 0 + -0.6770 4.0890 -14.2120 C 0 0 2 0 0 0 0 0 0 0 0 0 + -1.9150 4.4970 -14.1720 N 0 0 0 0 0 0 0 0 0 0 0 0 + -0.2160 3.9060 -15.8320 C 0 0 2 0 0 0 0 0 0 0 0 0 + 1.1240 4.3000 -15.7070 O 0 0 0 0 0 0 0 0 0 0 0 0 + -0.9070 4.9940 -16.8190 C 0 0 0 0 0 0 0 0 0 0 0 0 + -2.0630 5.0540 -17.0910 O 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 1 0 + 3 2 1 0 + 4 3 1 0 + 4 5 1 6 + 6 4 1 0 + 6 7 1 1 + 8 6 1 0 + 9 8 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-6xhm.mol b/fragmenstein/mpro/data/hit_mols/Mpro-6xhm.mol new file mode 100644 index 0000000..eb01745 --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-6xhm.mol @@ -0,0 +1,75 @@ + + RDKit 3D + + 34 36 0 0 0 0 0 0 0 0999 V2000 + 10.3890 5.6960 28.4020 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.3190 4.9330 27.1910 O 0 0 0 0 0 0 0 0 0 0 0 0 + 9.8980 5.5730 26.0560 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.5720 6.9210 25.9710 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.0970 7.4550 24.7790 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.9260 6.6570 23.6540 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.2580 5.3110 23.7420 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.2060 4.3210 22.7810 N 0 0 0 0 0 0 0 0 0 0 0 0 + 9.6230 3.1320 23.3520 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.9580 3.3530 24.6690 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.7500 4.7480 24.9320 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.6200 1.9070 22.5390 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.2250 1.9270 21.3770 O 0 0 0 0 0 0 0 0 0 0 0 0 + 10.0380 0.7900 23.1490 N 0 0 0 0 0 0 0 0 0 0 0 0 + 10.0200 -0.5010 22.4740 C 0 0 1 0 0 0 0 0 0 0 0 0 + 10.7810 -1.5540 23.2860 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.3010 -1.4270 23.2450 C 0 0 2 0 0 0 0 0 0 0 0 0 + 12.8450 -1.8600 21.9140 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.9720 -2.2260 24.3600 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.6020 -0.9690 22.1430 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.6990 -0.8870 22.9790 O 0 0 0 0 0 0 0 0 0 0 0 0 + 8.4240 -1.5010 20.9240 N 0 0 0 0 0 0 0 0 0 0 0 0 + 7.1750 -2.1530 20.5400 C 0 0 1 0 0 0 0 0 0 0 0 0 + 6.5680 -1.4750 19.3090 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.9730 -0.0960 19.6660 C 0 0 2 0 0 0 0 0 0 0 0 0 + 4.8160 -0.1290 20.6920 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.8710 0.9590 20.2420 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.1620 1.0800 18.8210 N 0 0 0 0 0 0 0 0 0 0 0 0 + 5.3650 0.6210 18.4720 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.9020 0.7830 17.3850 O 0 0 0 0 0 0 0 0 0 0 0 0 + 7.3950 -3.6650 20.3560 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.1850 -4.3280 19.9970 O 0 0 0 0 0 0 0 0 0 0 0 0 + 7.9280 -4.2880 21.6510 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.1790 -5.6840 21.5430 O 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 1 0 + 3 2 1 0 + 4 3 2 0 + 5 4 1 0 + 6 5 2 0 + 7 6 1 0 + 8 7 1 0 + 9 8 1 0 + 10 9 2 0 + 11 10 1 0 + 11 7 2 0 + 11 3 1 0 + 12 9 1 0 + 13 12 2 0 + 14 12 1 0 + 15 14 1 0 + 15 16 1 1 + 17 16 1 0 + 17 18 1 6 + 19 17 1 0 + 20 15 1 0 + 21 20 2 0 + 22 20 1 0 + 23 22 1 0 + 23 24 1 6 + 25 24 1 6 + 26 25 1 0 + 27 26 1 0 + 28 27 1 0 + 29 28 1 0 + 29 25 1 0 + 30 29 2 0 + 31 23 1 0 + 32 31 2 0 + 33 31 1 0 + 34 33 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-6xkf.mol b/fragmenstein/mpro/data/hit_mols/Mpro-6xkf.mol new file mode 100644 index 0000000..3c1d6cc --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-6xkf.mol @@ -0,0 +1,18 @@ + + RDKit 3D + + 7 6 0 0 0 0 0 0 0 0999 V2000 + 6.2040 -4.8890 16.8640 N 0 0 0 0 0 0 0 0 0 0 0 0 + 7.6120 -5.2450 16.7910 C 0 0 1 0 0 0 0 0 0 0 0 0 + 8.2820 -5.2470 18.1630 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.3160 -3.6370 18.8650 S 0 0 0 0 0 0 0 0 0 0 0 0 + 7.8430 -6.6130 16.1630 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.1190 -7.5790 16.3980 O 0 0 0 0 0 0 0 0 0 0 0 0 + 7.0600 -3.5690 19.6920 O 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 1 1 + 3 2 1 0 + 4 3 1 0 + 5 2 1 0 + 6 5 1 0 + 7 4 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-6xmk.mol b/fragmenstein/mpro/data/hit_mols/Mpro-6xmk.mol new file mode 100644 index 0000000..1bc6aa9 --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-6xmk.mol @@ -0,0 +1,68 @@ + + RDKit 3D + + 31 32 0 0 0 0 0 0 0 0999 V2000 + 9.0270 7.6270 24.9210 C 0 0 2 0 0 0 0 0 0 0 0 0 + 10.0770 6.4890 25.1750 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.5650 5.1270 24.6880 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.0350 5.1470 23.2390 C 0 0 1 0 0 0 0 0 0 0 0 0 + 8.5240 3.7580 22.8150 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.5320 1.5680 22.6270 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.1580 -0.7750 22.4500 C 0 0 1 0 0 0 0 0 0 0 0 0 + 10.9890 -1.7890 23.2770 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.4180 -1.3380 23.5740 C 0 0 1 0 0 0 0 0 0 0 0 0 + 13.2860 -2.4170 24.1880 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.1260 -0.8090 22.3450 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.7620 -1.3380 22.0830 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.2340 -2.3790 20.4570 C 0 0 1 0 0 0 0 0 0 0 0 0 + 6.6150 -1.5490 19.2690 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.0740 -0.2100 19.7630 C 0 0 1 0 0 0 0 0 0 0 0 0 + 5.5600 0.6810 18.6670 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.9040 0.8390 20.3630 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.8660 -0.3320 20.7080 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.4780 -3.8990 20.0410 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.9560 6.2320 23.1200 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.4790 7.5970 23.4830 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.5540 8.8290 25.1920 F 0 0 0 0 0 0 0 0 0 0 0 0 + 8.0120 7.5420 25.7960 F 0 0 0 0 0 0 0 0 0 0 0 0 + 10.0850 0.4740 23.1910 N 0 0 0 0 0 0 0 0 0 0 0 0 + 8.4900 -1.8300 20.8530 N 0 0 0 0 0 0 0 0 0 0 0 0 + 4.3820 1.2510 19.0110 N 0 0 0 0 0 0 0 0 0 0 0 0 + 9.2840 2.6770 23.3680 O 0 0 0 0 0 0 0 0 0 0 0 0 + 6.2290 0.8120 17.6200 O 0 0 0 0 0 0 0 0 0 0 0 0 + 6.2490 -4.4610 19.7300 O 0 0 0 0 0 0 0 0 0 0 0 0 + 7.8650 -1.3230 22.9210 O 0 0 0 0 0 0 0 0 0 0 0 0 + 9.2320 1.5590 21.4330 O 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 1 0 + 3 2 1 0 + 4 3 1 0 + 4 5 1 1 + 7 8 1 1 + 9 8 1 0 + 9 10 1 6 + 11 9 1 0 + 12 7 1 0 + 13 14 1 6 + 15 14 1 6 + 16 15 1 0 + 18 17 1 0 + 18 15 1 0 + 19 13 1 0 + 20 4 1 0 + 21 20 1 0 + 21 1 1 0 + 1 22 1 1 + 23 1 1 0 + 24 7 1 0 + 24 6 1 0 + 25 13 1 0 + 25 12 1 0 + 26 17 1 0 + 26 16 1 0 + 27 6 1 0 + 27 5 1 0 + 28 16 1 0 + 29 19 1 0 + 30 12 1 0 + 31 6 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-6xqs.mol b/fragmenstein/mpro/data/hit_mols/Mpro-6xqs.mol new file mode 100644 index 0000000..59b6d37 --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-6xqs.mol @@ -0,0 +1,107 @@ + + RDKit 3D + + 49 53 0 0 0 0 0 0 0 0999 V2000 + 12.6520 8.1870 26.0530 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.9580 9.7760 27.6820 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.4440 8.7890 28.5210 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.1880 7.7260 24.6500 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.1080 7.2000 26.9010 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.9630 8.4520 23.7380 O 0 0 0 0 0 0 0 0 0 0 0 0 + 12.5570 9.4500 26.4500 N 0 0 0 0 0 0 0 0 0 0 0 0 + 13.5130 7.5220 28.1190 N 0 0 0 0 0 0 0 0 0 0 0 0 + 12.0580 6.2840 24.5200 N 0 0 0 0 0 0 0 0 0 0 0 0 + 11.5690 5.6980 23.2950 C 0 0 2 0 0 0 0 0 0 0 0 0 + 10.8240 4.4870 23.8560 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.9800 4.0380 24.9650 O 0 0 0 0 0 0 0 0 0 0 0 0 + 12.6400 5.2120 22.2930 C 0 0 1 0 0 0 0 0 0 0 0 0 + 13.5170 6.3870 21.7610 C 0 0 0 0 0 0 0 0 0 0 0 0 + 14.5370 5.8250 20.7520 C 0 0 0 0 0 0 0 0 0 0 0 0 + 15.4500 4.7830 21.4450 C 0 0 0 0 0 0 0 0 0 0 0 0 + 14.6680 3.6120 22.0820 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.4560 4.0880 22.9420 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.8450 3.8590 22.9660 N 0 0 0 0 0 0 0 0 0 0 0 0 + 9.1740 2.7020 23.5010 C 0 0 1 0 0 0 0 0 0 0 0 0 + 7.6530 2.9100 23.5620 C 0 0 2 0 0 0 0 0 0 0 0 0 + 7.0890 3.4140 22.2110 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.3570 3.9840 24.6250 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.9840 1.5660 23.9840 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.5150 1.5070 22.6300 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.2540 1.4250 21.4540 O 0 0 0 0 0 0 0 0 0 0 0 0 + 9.3190 -1.5990 22.4970 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.2150 0.3780 23.2860 N 0 0 0 0 0 0 0 0 0 0 0 0 + 8.7440 -1.9080 23.4950 O 0 0 0 0 0 0 0 0 0 0 0 0 + 10.5560 -0.8270 22.5810 C 0 0 1 0 0 0 0 0 0 0 0 0 + 11.7160 -1.5280 23.4030 C 0 0 2 0 0 0 0 0 0 0 0 0 + 11.7930 -0.6850 24.6890 C 0 0 2 0 0 0 0 0 0 0 0 0 + 13.1380 -1.3660 22.4940 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.8160 -0.3200 23.0100 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.6220 0.2510 24.5430 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.3120 -0.1220 24.4270 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.0800 -5.6270 21.8510 N 0 0 0 0 0 0 0 0 0 0 0 0 + 8.7440 -1.9460 21.2070 N 0 0 0 0 0 0 0 0 0 0 0 0 + 7.4760 -2.6720 21.1940 C 0 0 2 0 0 0 0 0 0 0 0 0 + 7.5930 -4.0780 20.6010 C 0 0 2 0 0 0 0 0 0 0 0 0 + 6.5710 -1.7710 20.3460 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.8840 -0.7870 21.3310 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.2460 0.3500 20.4880 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.2500 -4.8120 20.6630 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.8830 -6.4060 22.1240 C 0 0 1 0 0 0 0 0 0 0 0 0 + 4.5580 -6.5820 23.6130 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.8120 -5.5370 22.7790 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.5330 -4.7900 21.3440 O 0 0 0 0 0 0 0 0 0 0 0 0 + 5.4210 -4.7390 19.7930 O 0 0 0 0 0 0 0 0 0 0 0 0 + 3 2 2 0 + 4 1 1 0 + 5 1 1 0 + 6 4 2 0 + 7 1 2 0 + 7 2 1 0 + 8 5 2 0 + 8 3 1 0 + 9 4 1 0 + 10 9 1 1 + 11 10 1 0 + 12 11 2 0 + 13 10 1 0 + 13 14 1 1 + 15 14 1 0 + 16 15 1 0 + 17 16 1 0 + 18 17 1 0 + 18 13 1 0 + 19 11 1 0 + 20 19 1 6 + 21 20 1 0 + 21 22 1 6 + 23 21 1 0 + 24 21 1 0 + 25 20 1 0 + 26 25 2 0 + 28 25 1 0 + 29 27 2 0 + 30 28 1 0 + 30 27 1 1 + 31 30 1 0 + 32 31 1 0 + 31 33 1 6 + 34 33 1 0 + 35 28 1 0 + 32 35 1 6 + 36 34 1 0 + 36 32 1 0 + 38 27 1 0 + 39 38 1 0 + 40 39 1 0 + 39 41 1 6 + 42 41 1 0 + 43 42 1 0 + 44 37 1 0 + 44 40 1 0 + 45 37 1 1 + 46 45 1 0 + 47 46 1 0 + 47 45 1 0 + 40 48 1 1 + 49 44 2 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-6xqt.mol b/fragmenstein/mpro/data/hit_mols/Mpro-6xqt.mol new file mode 100644 index 0000000..7f3df75 --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-6xqt.mol @@ -0,0 +1,106 @@ + + RDKit 3D + + 49 52 0 0 0 0 0 0 0 0999 V2000 + 11.7080 4.3580 22.9390 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.1970 3.7880 23.8670 O 0 0 0 0 0 0 0 0 0 0 0 0 + 12.4190 5.4380 22.1920 N 0 0 0 0 0 0 0 0 0 0 0 0 + 13.7920 5.9220 22.5540 C 0 0 2 0 0 0 0 0 0 0 0 0 + 14.1920 6.9310 21.4720 C 0 0 0 0 0 0 0 0 0 0 0 0 + 14.7940 4.7410 22.6990 C 0 0 0 0 0 0 0 0 0 0 0 0 + 14.4440 6.1620 20.1670 C 0 0 0 0 0 0 0 0 0 0 0 0 + 15.5240 4.2580 21.4270 C 0 0 0 0 0 0 0 0 0 0 0 0 + 15.7190 5.3350 20.3540 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.6410 6.6920 23.9090 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.3520 8.0260 23.9030 S 0 0 2 0 0 0 0 0 0 0 0 0 + 11.3740 7.4510 22.9500 O 0 0 0 0 0 0 0 0 0 0 0 0 + 13.1460 9.2360 23.4360 O 0 0 0 0 0 0 0 0 0 0 0 0 + 11.7500 8.1450 25.6610 C 0 0 1 0 0 0 0 0 0 0 0 0 + 11.0520 6.7980 26.0650 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.9770 8.4140 26.5950 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.7470 9.3430 25.7050 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.3320 4.0040 22.4940 N 0 0 0 0 0 0 0 0 0 0 0 0 + 9.6670 2.9460 23.2210 C 0 0 1 0 0 0 0 0 0 0 0 0 + 8.1740 3.2700 23.4710 C 0 0 1 0 0 0 0 0 0 0 0 0 + 7.3980 2.0110 23.9140 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.1850 4.2850 24.6310 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.4650 3.8500 22.2290 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.8620 1.6580 22.4200 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.5320 1.5380 21.2720 O 0 0 0 0 0 0 0 0 0 0 0 0 + 10.4960 0.4950 23.1320 N 0 0 0 0 0 0 0 0 0 0 0 0 + 10.9100 0.4620 24.3970 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.7280 -0.8760 22.3920 C 0 0 1 0 0 0 0 0 0 0 0 0 + 11.7070 -1.5130 23.0850 C 0 0 2 0 0 0 0 0 0 0 0 0 + 11.8440 -0.7780 24.4480 C 0 0 1 0 0 0 0 0 0 0 0 0 + 13.1210 -1.2320 23.6820 C 0 0 1 0 0 0 0 0 0 0 0 0 + 13.9340 -2.3610 24.3680 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.8830 -0.0580 23.0240 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.3560 -1.5680 22.3530 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.7780 -1.7400 23.3700 O 0 0 0 0 0 0 0 0 0 0 0 0 + 8.7050 -1.9510 21.0560 N 0 0 0 0 0 0 0 0 0 0 0 0 + 7.3910 -2.5510 21.1000 C 0 0 1 0 0 0 0 0 0 0 0 0 + 6.3040 -1.6680 20.4090 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.8190 -0.2240 20.0300 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.7480 0.9100 19.8270 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.2430 0.9720 18.3510 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.4870 -4.5880 21.1350 O 0 0 0 0 0 0 0 0 0 0 0 0 + 7.5720 -3.8730 20.4310 C 0 0 1 0 0 0 0 0 0 0 0 0 + 5.4130 -4.5450 19.7700 O 0 0 0 0 0 0 0 0 0 0 0 0 + 6.0630 -5.5650 21.7690 N 0 0 0 0 0 0 0 0 0 0 0 0 + 4.8140 -6.2010 22.0570 C 0 0 2 0 0 0 0 0 0 0 0 0 + 3.7970 -5.2080 22.6650 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.4690 -6.2690 23.5560 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.2880 -4.6510 20.6040 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 2 0 + 3 1 1 0 + 4 3 1 0 + 5 4 1 0 + 6 4 1 0 + 7 5 1 0 + 8 6 1 0 + 9 8 1 0 + 9 7 1 0 + 4 10 1 1 + 11 10 1 1 + 12 11 2 0 + 13 11 2 0 + 14 11 1 0 + 14 15 1 1 + 16 14 1 0 + 17 14 1 0 + 18 1 1 0 + 19 18 1 6 + 20 19 1 0 + 20 21 1 1 + 22 20 1 0 + 23 20 1 0 + 24 19 1 0 + 25 24 2 0 + 26 24 1 0 + 27 26 1 0 + 28 26 1 0 + 29 28 1 6 + 30 29 1 0 + 30 27 1 6 + 31 30 1 0 + 31 29 1 0 + 31 32 1 1 + 33 31 1 0 + 28 34 1 1 + 35 34 2 0 + 36 34 1 0 + 37 36 1 0 + 37 38 1 6 + 39 38 1 0 + 40 39 1 0 + 41 40 1 0 + 43 42 1 1 + 43 37 1 0 + 46 45 1 1 + 47 46 1 0 + 48 46 1 0 + 48 47 1 0 + 49 44 2 0 + 49 45 1 0 + 49 43 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-6xqu.mol b/fragmenstein/mpro/data/hit_mols/Mpro-6xqu.mol new file mode 100644 index 0000000..d469b0a --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-6xqu.mol @@ -0,0 +1,81 @@ + + RDKit 3D + + 37 39 0 0 0 0 0 0 0 0999 V2000 + 11.3500 4.8360 23.2170 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.9040 5.7880 22.4250 N 0 0 0 0 0 0 0 0 0 0 0 0 + 11.6830 4.6160 24.3880 O 0 0 0 0 0 0 0 0 0 0 0 0 + 13.1260 6.5730 22.7300 C 0 0 1 0 0 0 0 0 0 0 0 0 + 14.3100 5.6310 22.9040 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.3900 7.5160 21.5670 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.9050 7.3740 24.0050 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.3720 4.1430 22.5830 N 0 0 0 0 0 0 0 0 0 0 0 0 + 9.7010 3.0670 23.2860 C 0 0 1 0 0 0 0 0 0 0 0 0 + 8.2080 3.3930 23.5780 C 0 0 2 0 0 0 0 0 0 0 0 0 + 7.5410 2.1960 24.2580 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.4500 3.7170 22.2900 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.1260 4.6040 24.5090 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.9170 1.7800 22.4720 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.7010 1.7800 21.2720 O 0 0 0 0 0 0 0 0 0 0 0 0 + 10.3390 0.6760 23.1070 N 0 0 0 0 0 0 0 0 0 0 0 0 + 10.7660 0.5180 24.5020 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.4100 -0.5740 22.3560 C 0 0 1 0 0 0 0 0 0 0 0 0 + 11.3810 -1.4470 23.1790 C 0 0 2 0 0 0 0 0 0 0 0 0 + 11.5580 -0.7810 24.5300 C 0 0 1 0 0 0 0 0 0 0 0 0 + 12.7480 -0.9740 23.6200 C 0 0 2 0 0 0 0 0 0 0 0 0 + 13.3930 0.2500 22.9600 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.7530 -2.0730 23.9670 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.0220 -1.2270 22.2770 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.3160 -1.3350 23.2720 O 0 0 0 0 0 0 0 0 0 0 0 0 + 8.6620 -1.6640 21.0640 N 0 0 0 0 0 0 0 0 0 0 0 0 + 7.3880 -2.3100 20.7770 C 0 0 1 0 0 0 0 0 0 0 0 0 + 6.7160 -1.5860 19.6080 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.5540 -0.0790 19.7730 C 0 0 2 0 0 0 0 0 0 0 0 0 + 5.5410 0.4160 20.8160 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.8210 0.6700 18.6440 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.6320 0.9130 19.6360 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.5690 -4.2240 21.3820 O 0 0 0 0 0 0 0 0 0 0 0 0 + 7.6420 -3.7880 20.4110 C 0 0 1 0 0 0 0 0 0 0 0 0 + 5.4620 -4.4480 19.7220 O 0 0 0 0 0 0 0 0 0 0 0 0 + 6.3650 -4.5930 20.5540 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.3060 -5.4740 21.5380 N 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 1 0 + 3 1 2 0 + 4 2 1 0 + 4 5 1 1 + 6 4 1 0 + 7 4 1 0 + 8 1 1 0 + 9 8 1 6 + 10 9 1 0 + 10 11 1 1 + 12 10 1 0 + 13 10 1 0 + 14 9 1 0 + 15 14 2 0 + 16 14 1 0 + 17 16 1 0 + 18 16 1 0 + 19 18 1 6 + 20 17 1 6 + 20 19 1 0 + 21 20 1 0 + 21 19 1 0 + 21 22 1 6 + 23 21 1 0 + 18 24 1 1 + 25 24 2 0 + 26 24 1 0 + 27 26 1 0 + 27 28 1 6 + 29 28 1 6 + 30 29 1 0 + 31 29 1 0 + 32 31 1 0 + 32 30 1 0 + 34 33 1 1 + 34 27 1 0 + 36 35 2 0 + 36 34 1 0 + 37 36 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-6xr3.mol b/fragmenstein/mpro/data/hit_mols/Mpro-6xr3.mol new file mode 100644 index 0000000..93c877e --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-6xr3.mol @@ -0,0 +1,91 @@ + + RDKit 3D + + 41 45 0 0 0 0 0 0 0 0999 V2000 + 7.4750 -3.3140 20.0370 C 0 0 2 0 0 0 0 0 0 0 0 0 + 7.9970 -4.0250 21.2910 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.9510 -4.8010 23.4360 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.4150 -5.0240 24.7250 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.1670 -5.7190 25.6620 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.4470 -6.1750 25.3310 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.9770 -5.9500 24.0570 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.2240 -5.2470 23.0990 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.3710 -1.8180 20.3550 C 0 0 2 0 0 0 0 0 0 0 0 0 + 6.8760 -1.0450 19.1540 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.4000 0.3980 19.5610 C 0 0 2 0 0 0 0 0 0 0 0 0 + 5.4080 0.4510 20.3650 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.5730 1.8870 19.9700 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.9340 1.1690 18.2220 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.9860 -0.7970 21.9740 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.4220 -0.3950 22.2620 C 0 0 2 0 0 0 0 0 0 0 0 0 + 11.1180 -1.5050 23.0650 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.5890 -1.2360 23.3210 C 0 0 1 0 0 0 0 0 0 0 0 0 + 13.1710 -2.2300 24.3210 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.3870 -1.3160 22.0150 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.1460 2.0580 22.2890 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.2050 3.3720 23.0240 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.5170 3.5280 24.3720 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.4650 4.9160 24.6430 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.6640 5.6760 25.8270 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.2600 5.7530 28.1300 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.5250 7.0530 25.7750 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.1880 7.6850 24.5770 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.9790 6.9370 23.4160 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.1210 5.5320 23.4690 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.2210 -4.0790 22.4220 N 0 0 0 0 0 0 0 0 0 0 0 0 + 4.7410 2.0870 18.6590 N 0 0 0 0 0 0 0 0 0 0 0 0 + 8.7000 -1.3780 20.7010 N 0 0 0 0 0 0 0 0 0 0 0 0 + 10.4710 0.8500 22.9840 N 0 0 0 0 0 0 0 0 0 0 0 0 + 9.9770 4.5750 22.5020 N 0 0 0 0 0 0 0 0 0 0 0 0 + 6.2480 -3.8790 19.6930 O 0 0 0 0 0 0 0 0 0 0 0 0 + 6.3930 1.0720 17.1410 O 0 0 0 0 0 0 0 0 0 0 0 0 + 11.0170 4.9750 26.9890 O 0 0 0 0 0 0 0 0 0 0 0 0 + 9.7910 2.0010 21.1450 O 0 0 0 0 0 0 0 0 0 0 0 0 + 8.1000 -0.6280 22.7550 O 0 0 0 0 0 0 0 0 0 0 0 0 + 9.5020 -4.7700 21.5140 S 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 1 0 + 4 3 2 0 + 5 4 1 0 + 6 5 2 0 + 7 6 1 0 + 8 7 2 0 + 8 3 1 0 + 9 1 1 0 + 9 10 1 6 + 11 10 1 6 + 12 11 1 0 + 13 12 1 0 + 14 11 1 0 + 16 15 1 0 + 16 17 1 1 + 18 17 1 0 + 18 19 1 1 + 20 18 1 0 + 22 21 1 0 + 23 22 2 0 + 24 23 1 0 + 25 24 2 0 + 27 25 1 0 + 28 27 2 0 + 29 28 1 0 + 30 24 1 0 + 30 29 2 0 + 31 2 2 0 + 31 3 1 0 + 32 13 1 0 + 32 14 1 0 + 33 9 1 0 + 33 15 1 0 + 34 21 1 0 + 34 16 1 0 + 35 22 1 0 + 35 30 1 0 + 1 36 1 1 + 37 14 2 0 + 38 25 1 0 + 38 26 1 0 + 39 21 2 0 + 40 15 2 0 + 41 2 1 0 + 41 8 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-6y2f.mol b/fragmenstein/mpro/data/hit_mols/Mpro-6y2f.mol new file mode 100644 index 0000000..f0ef990 --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-6y2f.mol @@ -0,0 +1,94 @@ + + RDKit 3D + + 43 46 0 0 0 0 0 0 0 0999 V2000 + 8.6590 5.6930 24.4740 O 0 0 0 0 0 0 0 0 0 0 0 0 + 8.5410 5.4110 23.2930 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.9450 6.3630 22.3730 O 0 0 0 0 0 0 0 0 0 0 0 0 + 7.1730 7.5190 22.7460 C 0 0 1 0 0 0 0 0 0 0 0 0 + 8.0780 8.4480 23.5730 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.6790 8.2170 21.4700 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.9360 7.1120 23.5600 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.9340 4.2660 22.7250 N 0 0 0 0 0 0 0 0 0 0 0 0 + 9.4030 3.1590 23.3490 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.5720 1.9740 22.4920 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.2920 2.0120 21.2550 O 0 0 0 0 0 0 0 0 0 0 0 0 + 9.6900 3.0500 24.7230 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.1280 1.8480 25.2410 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.3070 0.7480 24.4090 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.0550 0.7870 23.0780 N 0 0 0 0 0 0 0 0 0 0 0 0 + 10.1890 -0.3760 22.2000 C 0 0 1 0 0 0 0 0 0 0 0 0 + 11.0330 -1.5130 22.7930 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.4690 -1.0530 23.0550 C 0 0 1 0 0 0 0 0 0 0 0 0 + 13.5870 -2.0890 23.0880 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.4060 -1.2230 21.8480 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.7820 -0.8280 21.9120 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.9000 -0.6760 22.7570 O 0 0 0 0 0 0 0 0 0 0 0 0 + 8.5590 -1.3980 20.7160 N 0 0 0 0 0 0 0 0 0 0 0 0 + 7.2900 -1.9390 20.3390 C 0 0 1 0 0 0 0 0 0 0 0 0 + 6.7020 -1.3160 19.0340 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.2590 0.0830 19.3400 C 0 0 1 0 0 0 0 0 0 0 0 0 + 5.8600 0.9600 18.1740 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.4710 0.9700 17.1090 O 0 0 0 0 0 0 0 0 0 0 0 0 + 4.8090 1.7190 18.5260 N 0 0 0 0 0 0 0 0 0 0 0 0 + 4.3970 1.5180 19.9200 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.0190 0.1640 20.2390 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.6130 -3.4290 20.3700 C 0 0 1 0 0 0 0 0 0 0 0 0 + 8.3890 -3.8870 21.5410 O 0 0 0 0 0 0 0 0 0 0 0 0 + 6.3630 -4.2020 20.4940 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.5390 -4.0580 19.6100 O 0 0 0 0 0 0 0 0 0 0 0 0 + 6.3570 -5.0160 21.5890 N 0 0 0 0 0 0 0 0 0 0 0 0 + 5.2780 -5.9310 21.9600 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.2780 -5.2540 22.8890 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.5020 -3.9730 23.3930 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.5760 -3.3810 24.2550 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2.4120 -4.0680 24.6210 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2.1780 -5.3510 24.1230 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.1110 -5.9360 23.2610 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 2 0 + 3 2 1 0 + 4 3 1 0 + 4 5 1 1 + 6 4 1 0 + 7 4 1 0 + 8 2 1 0 + 9 8 1 0 + 10 9 1 0 + 11 10 2 0 + 12 9 2 0 + 13 12 1 0 + 14 13 2 0 + 15 14 1 0 + 15 10 1 0 + 16 15 1 0 + 16 17 1 1 + 18 17 1 6 + 19 18 1 0 + 20 19 1 0 + 20 18 1 0 + 21 16 1 0 + 22 21 2 0 + 23 21 1 0 + 24 23 1 0 + 24 25 1 6 + 26 25 1 6 + 27 26 1 0 + 28 27 2 0 + 29 27 1 0 + 30 29 1 0 + 31 30 1 0 + 31 26 1 0 + 32 24 1 0 + 32 33 1 1 + 34 32 1 0 + 35 34 2 0 + 36 34 1 0 + 37 36 1 0 + 38 37 1 0 + 39 38 2 0 + 40 39 1 0 + 41 40 2 0 + 42 41 1 0 + 43 42 2 0 + 43 38 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-6y2g.mol b/fragmenstein/mpro/data/hit_mols/Mpro-6y2g.mol new file mode 100644 index 0000000..e8d5a31 --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-6y2g.mol @@ -0,0 +1,94 @@ + + RDKit 3D + + 43 46 0 0 0 0 0 0 0 0999 V2000 + 9.3310 5.7940 24.4470 O 0 0 0 0 0 0 0 0 0 0 0 0 + 9.1520 5.5370 23.2650 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.6750 6.5430 22.3480 O 0 0 0 0 0 0 0 0 0 0 0 0 + 7.6680 7.4230 22.8040 C 0 0 2 0 0 0 0 0 0 0 0 0 + 6.6850 6.6960 23.7350 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.8560 7.9150 21.6180 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.4370 8.5610 23.4810 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.3630 4.3640 22.7300 N 0 0 0 0 0 0 0 0 0 0 0 0 + 9.7980 3.2800 23.3950 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.9500 2.0590 22.5670 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.6760 2.0510 21.3030 O 0 0 0 0 0 0 0 0 0 0 0 0 + 10.0780 3.2180 24.7650 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.5060 2.0300 25.3400 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.6610 0.9000 24.5780 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.4130 0.9230 23.2590 N 0 0 0 0 0 0 0 0 0 0 0 0 + 10.4710 -0.2470 22.4130 C 0 0 1 0 0 0 0 0 0 0 0 0 + 11.3030 -1.4070 22.9710 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.7410 -1.0090 23.3090 C 0 0 2 0 0 0 0 0 0 0 0 0 + 13.6600 -0.5710 22.1690 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.8640 -1.9330 22.8330 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.0250 -0.6680 22.1670 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.0930 -0.5280 23.0070 O 0 0 0 0 0 0 0 0 0 0 0 0 + 8.8060 -1.1790 20.9730 N 0 0 0 0 0 0 0 0 0 0 0 0 + 7.4680 -1.7140 20.6010 C 0 0 1 0 0 0 0 0 0 0 0 0 + 6.9250 -1.0460 19.3230 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.4580 0.4130 19.5270 C 0 0 1 0 0 0 0 0 0 0 0 0 + 6.0000 1.0770 18.2160 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.6300 1.0360 17.1300 O 0 0 0 0 0 0 0 0 0 0 0 0 + 4.8430 1.7080 18.4430 N 0 0 0 0 0 0 0 0 0 0 0 0 + 4.2560 1.4690 19.7680 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.2800 0.5560 20.4850 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.7700 -3.2130 20.4240 C 0 0 1 0 0 0 0 0 0 0 0 0 + 8.4860 -3.8780 21.5080 O 0 0 0 0 0 0 0 0 0 0 0 0 + 6.5390 -3.9920 20.1780 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.9600 -3.9070 19.1210 O 0 0 0 0 0 0 0 0 0 0 0 0 + 6.1090 -4.8470 20.9630 N 0 0 0 0 0 0 0 0 0 0 0 0 + 6.2970 -5.3560 22.2560 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.0520 -4.9720 23.0350 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.9960 -5.8670 23.1430 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2.8800 -5.5180 23.9110 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2.8100 -4.2760 24.5740 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.8710 -3.3840 24.4540 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.9880 -3.7250 23.6950 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 2 0 + 3 2 1 0 + 4 3 1 0 + 4 5 1 1 + 6 4 1 0 + 7 4 1 0 + 8 2 1 0 + 9 8 1 0 + 10 9 1 0 + 11 10 2 0 + 12 9 2 0 + 13 12 1 0 + 14 13 2 0 + 15 14 1 0 + 15 10 1 0 + 16 15 1 0 + 16 17 1 1 + 18 17 1 6 + 19 18 1 0 + 20 19 1 0 + 20 18 1 0 + 21 16 1 0 + 22 21 2 0 + 23 21 1 0 + 24 23 1 0 + 24 25 1 6 + 26 25 1 6 + 27 26 1 0 + 28 27 2 0 + 29 27 1 0 + 30 29 1 0 + 31 30 1 0 + 31 26 1 0 + 32 24 1 0 + 32 33 1 1 + 34 32 1 0 + 35 34 2 0 + 36 34 1 0 + 37 36 1 0 + 38 37 1 0 + 39 38 2 0 + 40 39 1 0 + 41 40 2 0 + 42 41 1 0 + 43 42 2 0 + 43 38 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-6ynq.mol b/fragmenstein/mpro/data/hit_mols/Mpro-6ynq.mol new file mode 100644 index 0000000..7d1fe61 --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-6ynq.mol @@ -0,0 +1,30 @@ + + RDKit 3D + + 12 13 0 0 0 0 0 0 0 0999 V2000 + 6.2810 -0.4080 18.7140 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.2910 0.5390 19.5590 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.7690 -2.3980 18.5260 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.7080 -1.6780 19.3380 C 0 0 1 0 0 0 0 0 0 0 0 0 + 7.1910 -1.4430 20.7470 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.1100 -0.8110 21.6570 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.2300 0.3210 20.9510 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.3700 1.1200 21.7260 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.5940 2.1130 21.1120 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.6640 2.3230 19.7130 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.5140 1.5330 18.9320 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.6670 -0.1000 17.6320 O 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 1 0 + 4 3 1 6 + 4 1 1 0 + 5 4 1 0 + 6 5 1 0 + 7 2 2 0 + 7 6 1 0 + 8 7 1 0 + 9 8 2 0 + 10 9 1 0 + 11 10 2 0 + 11 2 1 0 + 12 1 2 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-6yt8.mol b/fragmenstein/mpro/data/hit_mols/Mpro-6yt8.mol new file mode 100644 index 0000000..b78f85e --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-6yt8.mol @@ -0,0 +1,24 @@ + + RDKit 3D + + 9 10 0 0 0 0 0 0 0 0999 V2000 + 6.6020 -4.0420 22.8900 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.6030 -3.7130 23.8220 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.6400 -4.6850 24.1430 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.7210 -5.9430 23.5150 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.7380 -6.1980 22.6030 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.6570 -5.2390 22.3150 N 0 0 0 0 0 0 0 0 0 0 0 0 + 7.6560 -5.5610 21.3930 O 0 0 0 0 0 0 0 0 0 0 0 0 + 7.8480 -2.8490 22.4460 S 0 0 0 0 0 0 0 0 0 0 0 0 + 8.9460 -4.0000 21.0880 Zn 0 0 0 0 0 2 0 0 0 0 0 0 + 2 1 1 0 + 3 2 1 0 + 4 3 1 0 + 5 4 1 0 + 6 5 1 0 + 6 1 1 0 + 7 6 1 0 + 8 1 1 0 + 9 7 1 0 + 9 8 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-6yvf.mol b/fragmenstein/mpro/data/hit_mols/Mpro-6yvf.mol new file mode 100644 index 0000000..532fbf5 --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-6yvf.mol @@ -0,0 +1,68 @@ + + RDKit 3D + + 30 33 0 0 0 0 0 0 0 0999 V2000 + 21.4580 -25.9600 18.3680 C 0 0 0 0 0 0 0 0 0 0 0 0 + 21.1780 -25.6860 19.7110 C 0 0 0 0 0 0 0 0 0 0 0 0 + 21.6450 -24.5900 20.2910 N 0 0 0 0 0 0 0 0 0 0 0 0 + 22.4070 -23.7020 19.5930 C 0 0 0 0 0 0 0 0 0 0 0 0 + 22.9370 -22.4530 20.2810 N 0 0 0 0 0 0 0 0 0 0 0 0 + 22.6440 -22.1840 21.6500 C 0 0 0 0 0 0 0 0 0 0 0 0 + 21.8290 -23.1200 22.4000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 21.3200 -24.3350 21.7350 C 0 0 0 0 0 0 0 0 0 0 0 0 + 20.6530 -25.1140 22.3390 O 0 0 0 0 0 0 0 0 0 0 0 0 + 23.1930 -20.9700 22.2280 N 0 0 0 0 0 0 0 0 0 0 0 0 + 23.0090 -20.5190 23.5870 C 0 0 0 0 0 0 0 0 0 0 0 0 + 24.3060 -20.0480 24.2490 C 0 0 0 0 0 0 0 0 0 0 0 0 + 25.0230 -19.1250 23.4630 O 0 0 0 0 0 0 0 0 0 0 0 0 + 25.2840 -19.6390 22.1790 C 0 0 0 0 0 0 0 0 0 0 0 0 + 23.9950 -20.0450 21.4660 C 0 0 0 0 0 0 0 0 0 0 0 0 + 22.7280 -23.9070 18.2560 C 0 0 0 0 0 0 0 0 0 0 0 0 + 22.2490 -25.0540 17.6120 C 0 0 0 0 0 0 0 0 0 0 0 0 + 23.5820 -22.8880 17.5020 C 0 0 1 0 0 0 0 0 0 0 0 0 + 25.0210 -23.3980 17.3950 C 0 0 0 0 0 0 0 0 0 0 0 0 + 20.9090 -27.2250 17.7130 C 0 0 0 0 0 0 0 0 0 0 0 0 + 23.0450 -22.6860 16.1630 N 0 0 0 0 0 0 0 0 0 0 0 0 + 21.8620 -21.8720 15.9410 C 0 0 0 0 0 0 0 0 0 0 0 0 + 20.2460 -20.9330 14.4280 C 0 0 0 0 0 0 0 0 0 0 0 0 + 21.3720 -21.7090 14.6540 C 0 0 0 0 0 0 0 0 0 0 0 0 + 19.6040 -20.3190 15.4900 C 0 0 0 0 0 0 0 0 0 0 0 0 + 21.2160 -21.2550 17.0010 C 0 0 0 0 0 0 0 0 0 0 0 0 + 20.0890 -20.4790 16.7770 C 0 0 0 0 0 0 0 0 0 0 0 0 + 22.0730 -22.3800 13.4750 C 0 0 0 0 0 0 0 0 0 0 0 0 + 23.0170 -23.1880 13.6840 O 0 0 0 0 0 0 0 0 0 0 0 0 + 21.7080 -22.1210 12.2960 O 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 2 0 + 3 2 1 0 + 4 3 1 0 + 5 4 2 0 + 6 5 1 0 + 7 6 2 0 + 8 3 1 0 + 8 7 1 0 + 9 8 2 0 + 10 6 1 0 + 11 10 1 0 + 12 11 1 0 + 13 12 1 0 + 14 13 1 0 + 15 14 1 0 + 15 10 1 0 + 16 4 1 0 + 17 1 1 0 + 17 16 2 0 + 18 16 1 0 + 18 19 1 6 + 20 1 1 0 + 21 18 1 0 + 22 21 1 0 + 24 23 2 0 + 24 22 1 0 + 25 23 1 0 + 26 22 2 0 + 27 25 2 0 + 27 26 1 0 + 28 24 1 0 + 29 28 2 0 + 30 28 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-6yz6.mol b/fragmenstein/mpro/data/hit_mols/Mpro-6yz6.mol new file mode 100644 index 0000000..05b2ac7 --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-6yz6.mol @@ -0,0 +1,16 @@ + + RDKit 3D + + 5 5 0 0 0 0 0 0 0 0999 V2000 + 7.2990 -22.4830 29.4990 N 0 0 0 0 0 0 0 0 0 0 0 0 + 6.4990 -21.5820 28.8950 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.9520 -20.3450 29.1850 N 0 0 0 0 0 0 0 0 0 0 0 0 + 8.0340 -20.4610 29.9760 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.2570 -21.8130 30.1750 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 2 0 + 3 2 1 0 + 4 3 1 0 + 5 1 1 0 + 5 4 2 0 +M CHG 1 1 1 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-6zrt.mol b/fragmenstein/mpro/data/hit_mols/Mpro-6zrt.mol new file mode 100644 index 0000000..4f21a49 --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-6zrt.mol @@ -0,0 +1,107 @@ + + RDKit 3D + + 49 53 0 0 0 0 0 0 0 0999 V2000 + 12.8300 8.2830 25.6060 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.1900 10.0060 27.0380 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.5700 9.1130 28.0140 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.3960 7.7830 24.2620 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.1880 7.3830 26.5930 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.4230 8.5100 23.2690 O 0 0 0 0 0 0 0 0 0 0 0 0 + 12.8130 9.6030 25.8260 N 0 0 0 0 0 0 0 0 0 0 0 0 + 13.5650 7.7910 27.8070 N 0 0 0 0 0 0 0 0 0 0 0 0 + 11.9700 6.5170 24.2570 N 0 0 0 0 0 0 0 0 0 0 0 0 + 11.7530 5.6740 23.0990 C 0 0 2 0 0 0 0 0 0 0 0 0 + 10.8550 4.5370 23.6000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.0820 4.0330 24.6960 O 0 0 0 0 0 0 0 0 0 0 0 0 + 13.1590 5.3340 22.5650 C 0 0 2 0 0 0 0 0 0 0 0 0 + 13.5680 6.3000 21.4430 C 0 0 0 0 0 0 0 0 0 0 0 0 + 14.6380 5.7080 20.5220 C 0 0 0 0 0 0 0 0 0 0 0 0 + 15.5550 4.7600 21.2680 C 0 0 0 0 0 0 0 0 0 0 0 0 + 14.7810 3.5510 21.7700 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.3350 3.8760 22.1510 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.8470 4.1330 22.8260 N 0 0 0 0 0 0 0 0 0 0 0 0 + 9.0840 2.9450 23.1790 C 0 0 1 0 0 0 0 0 0 0 0 0 + 7.5780 3.2140 23.3240 C 0 0 2 0 0 0 0 0 0 0 0 0 + 7.3390 4.2010 24.4660 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.8560 1.9110 23.6800 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.9590 3.7920 22.0480 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.4640 1.7700 22.2620 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.1250 1.6970 21.0920 O 0 0 0 0 0 0 0 0 0 0 0 0 + 9.1280 -1.3920 22.2040 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.1600 0.7750 22.8230 N 0 0 0 0 0 0 0 0 0 0 0 0 + 8.6500 -1.8130 23.2570 O 0 0 0 0 0 0 0 0 0 0 0 0 + 10.3890 -0.5240 22.1870 C 0 0 1 0 0 0 0 0 0 0 0 0 + 11.5670 -1.1000 22.9870 C 0 0 2 0 0 0 0 0 0 0 0 0 + 11.5030 -0.4070 24.3740 C 0 0 2 0 0 0 0 0 0 0 0 0 + 12.9900 -0.8030 22.4650 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.5160 0.2960 23.3810 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.7180 0.8770 24.1710 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.9710 -0.1210 24.7110 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.1570 -5.3140 21.7740 N 0 0 0 0 0 0 0 0 0 0 0 0 + 8.5650 -1.6220 21.0180 N 0 0 0 0 0 0 0 0 0 0 0 0 + 7.2770 -2.3160 20.8660 C 0 0 2 0 0 0 0 0 0 0 0 0 + 7.5390 -3.7760 20.5220 C 0 0 2 0 0 0 0 0 0 0 0 0 + 6.4160 -1.7110 19.7440 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.0700 -0.2290 19.7720 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.8010 0.3210 18.3500 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.2780 -4.5920 20.6530 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.0010 -6.1280 22.0260 C 0 0 1 0 0 0 0 0 0 0 0 0 + 4.6660 -6.4380 23.4440 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.8120 -5.4930 22.6660 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.5270 -4.3510 21.3220 O 0 0 0 0 0 0 0 0 0 0 0 0 + 5.4420 -4.5970 19.7520 O 0 0 0 0 0 0 0 0 0 0 0 0 + 3 2 2 0 + 4 1 1 0 + 5 1 1 0 + 6 4 2 0 + 7 2 1 0 + 7 1 2 0 + 8 5 2 0 + 8 3 1 0 + 9 4 1 0 + 10 9 1 1 + 11 10 1 0 + 12 11 2 0 + 13 10 1 0 + 13 14 1 6 + 15 14 1 0 + 16 15 1 0 + 17 16 1 0 + 18 17 1 0 + 18 13 1 0 + 19 11 1 0 + 20 19 1 6 + 21 20 1 0 + 21 22 1 1 + 23 21 1 0 + 24 21 1 0 + 25 20 1 0 + 26 25 2 0 + 28 25 1 0 + 29 27 2 0 + 30 28 1 0 + 30 27 1 1 + 31 30 1 0 + 32 31 1 0 + 31 33 1 6 + 34 33 1 0 + 35 28 1 0 + 32 35 1 6 + 36 34 1 0 + 36 32 1 0 + 38 27 1 0 + 39 38 1 0 + 40 39 1 0 + 39 41 1 6 + 42 41 1 0 + 43 42 1 0 + 44 40 1 0 + 44 37 1 0 + 45 37 1 1 + 46 45 1 0 + 47 46 1 0 + 47 45 1 0 + 40 48 1 1 + 49 44 2 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-6zru.mol b/fragmenstein/mpro/data/hit_mols/Mpro-6zru.mol new file mode 100644 index 0000000..72df1aa --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-6zru.mol @@ -0,0 +1,81 @@ + + RDKit 3D + + 37 39 0 0 0 0 0 0 0 0999 V2000 + 11.4700 4.8450 23.1030 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.1150 5.7230 22.3100 N 0 0 0 0 0 0 0 0 0 0 0 0 + 11.7050 4.7070 24.3110 O 0 0 0 0 0 0 0 0 0 0 0 0 + 13.3220 6.5050 22.6560 C 0 0 2 0 0 0 0 0 0 0 0 0 + 13.1040 7.2380 23.9770 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.5610 7.5190 21.5350 C 0 0 0 0 0 0 0 0 0 0 0 0 + 14.4790 5.5110 22.7650 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.5130 4.1230 22.4750 N 0 0 0 0 0 0 0 0 0 0 0 0 + 9.7740 3.0750 23.1430 C 0 0 1 0 0 0 0 0 0 0 0 0 + 8.3290 3.4870 23.4560 C 0 0 2 0 0 0 0 0 0 0 0 0 + 7.5150 3.8520 22.2150 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.3200 4.7150 24.3730 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.6520 2.3150 24.1610 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.9130 1.7880 22.3320 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.5570 1.7020 21.1600 O 0 0 0 0 0 0 0 0 0 0 0 0 + 10.4030 0.7220 22.9770 N 0 0 0 0 0 0 0 0 0 0 0 0 + 10.8530 0.6230 24.3740 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.4870 -0.5270 22.2320 C 0 0 1 0 0 0 0 0 0 0 0 0 + 11.3720 -1.4040 23.0760 C 0 0 2 0 0 0 0 0 0 0 0 0 + 11.5550 -0.7080 24.4130 C 0 0 1 0 0 0 0 0 0 0 0 0 + 12.7420 -0.9230 23.4840 C 0 0 1 0 0 0 0 0 0 0 0 0 + 13.7560 -1.9500 23.9590 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.3580 0.2480 22.7340 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.1040 -1.1360 22.1460 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.5040 -1.4040 23.1860 O 0 0 0 0 0 0 0 0 0 0 0 0 + 8.6380 -1.3710 20.9130 N 0 0 0 0 0 0 0 0 0 0 0 0 + 7.3150 -1.9760 20.6620 C 0 0 1 0 0 0 0 0 0 0 0 0 + 6.4910 -1.0450 19.7660 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.0570 0.2110 20.5230 C 0 0 1 0 0 0 0 0 0 0 0 0 + 4.7960 0.9750 20.0730 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.3950 0.0350 21.9050 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.4650 1.2020 21.5620 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.3480 -4.0710 21.1040 O 0 0 0 0 0 0 0 0 0 0 0 0 + 7.4830 -3.4430 20.2050 C 0 0 1 0 0 0 0 0 0 0 0 0 + 5.4570 -4.2980 19.3850 O 0 0 0 0 0 0 0 0 0 0 0 0 + 6.2510 -4.2550 20.2870 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.0590 -5.0370 21.5010 N 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 1 0 + 3 1 2 0 + 4 2 1 0 + 4 5 1 1 + 6 4 1 0 + 7 4 1 0 + 8 1 1 0 + 9 8 1 6 + 10 9 1 0 + 10 11 1 6 + 12 10 1 0 + 13 10 1 0 + 14 9 1 0 + 15 14 2 0 + 16 14 1 0 + 17 16 1 0 + 18 16 1 0 + 19 18 1 6 + 20 17 1 6 + 20 19 1 0 + 21 20 1 0 + 21 19 1 0 + 21 22 1 1 + 23 21 1 0 + 18 24 1 1 + 25 24 2 0 + 26 24 1 0 + 27 26 1 0 + 27 28 1 6 + 29 28 1 6 + 30 29 1 0 + 31 29 1 0 + 32 30 1 0 + 32 31 1 0 + 34 33 1 1 + 34 27 1 0 + 36 35 2 0 + 36 34 1 0 + 37 36 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-7aku.mol b/fragmenstein/mpro/data/hit_mols/Mpro-7aku.mol new file mode 100644 index 0000000..b113799 --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-7aku.mol @@ -0,0 +1,57 @@ + + RDKit 3D + + 26 26 0 0 0 0 0 0 0 0999 V2000 + 10.7780 -1.4280 23.1080 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.7120 -1.6460 24.6490 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.2900 1.8620 21.9520 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.3920 4.5730 21.9580 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.1350 4.6070 21.3700 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.2780 3.5190 21.4760 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.9310 2.3500 22.7570 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.9190 2.2210 18.7020 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.8340 0.7580 19.1430 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.1260 0.2930 19.8400 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.4560 -1.0620 19.2310 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.1070 -2.1480 20.1830 C 0 0 1 0 0 0 0 0 0 0 0 0 + 8.7210 -0.9910 21.7220 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.1430 -0.5060 22.0910 C 0 0 1 0 0 0 0 0 0 0 0 0 + 12.2410 -1.1020 23.2950 C 0 0 1 0 0 0 0 0 0 0 0 0 + 13.0620 -1.7780 22.1940 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.1770 3.3770 23.3220 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.7950 3.4390 22.6520 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.6780 2.3950 22.1710 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.9100 -3.3920 19.4650 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.4330 -1.7230 20.4560 N 0 0 0 0 0 0 0 0 0 0 0 0 + 10.0400 0.8160 22.6530 N 0 0 0 0 0 0 0 0 0 0 0 0 + 7.8150 -0.7600 22.4610 O 0 0 0 0 0 0 0 0 0 0 0 0 + 8.7420 1.6170 20.9310 O 0 0 0 0 0 0 0 0 0 0 0 0 + 9.2040 3.1810 22.4350 O 0 0 0 0 0 0 0 0 0 0 0 0 + 6.5540 -4.5280 20.0590 O 0 0 0 0 0 0 0 0 0 0 0 0 + 5 4 2 0 + 6 5 1 0 + 9 8 1 0 + 10 9 1 0 + 11 10 1 0 + 12 11 1 6 + 14 13 1 0 + 14 1 1 1 + 15 1 1 0 + 15 2 1 1 + 16 15 1 0 + 18 17 1 0 + 18 7 2 0 + 18 4 1 0 + 19 6 2 0 + 19 7 1 0 + 20 12 1 0 + 21 13 1 0 + 21 12 1 0 + 22 14 1 0 + 22 3 1 0 + 23 13 2 0 + 24 3 2 0 + 25 17 1 0 + 25 3 1 0 + 26 20 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-7bqy.mol b/fragmenstein/mpro/data/hit_mols/Mpro-7bqy.mol new file mode 100644 index 0000000..33ac546 --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-7bqy.mol @@ -0,0 +1,22 @@ + + RDKit 3D + + 8 8 0 0 0 0 0 0 0 0999 V2000 + -0.1530 5.3720 -16.1580 C 0 0 0 0 0 0 0 0 0 0 0 0 + 0.0040 5.1200 -17.4900 C 0 0 0 0 0 0 0 0 0 0 0 0 + 0.5870 3.8550 -18.1100 C 0 0 0 0 0 0 0 0 0 0 0 0 + -0.4430 6.1930 -18.1630 O 0 0 0 0 0 0 0 0 0 0 0 0 + -0.8840 7.1300 -17.2420 N 0 0 0 0 0 0 0 0 0 0 0 0 + -0.7060 6.6230 -16.0210 C 0 0 0 0 0 0 0 0 0 0 0 0 + -1.0580 7.3140 -14.7050 C 0 0 0 0 0 0 0 0 0 0 0 0 + -0.4660 8.3660 -14.3380 O 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 1 0 + 3 2 1 0 + 4 2 1 0 + 5 4 1 0 + 6 1 1 0 + 6 5 1 0 + 7 6 1 0 + 8 7 1 0 +M CHG 1 8 -1 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-7brp.mol b/fragmenstein/mpro/data/hit_mols/Mpro-7brp.mol new file mode 100644 index 0000000..0f3184b --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-7brp.mol @@ -0,0 +1,81 @@ + + RDKit 3D + + 37 39 0 0 0 0 0 0 0 0999 V2000 + 11.3460 4.8400 22.9230 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.8870 5.9170 22.0710 N 0 0 0 0 0 0 0 0 0 0 0 0 + 11.8170 4.5780 23.9780 O 0 0 0 0 0 0 0 0 0 0 0 0 + 13.0810 6.6920 22.4720 C 0 0 2 0 0 0 0 0 0 0 0 0 + 14.2480 5.6800 22.5630 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.9030 7.4000 23.8360 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.3630 7.7250 21.3510 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.1710 4.0990 22.4220 N 0 0 0 0 0 0 0 0 0 0 0 0 + 9.6200 3.0570 23.2370 C 0 0 1 0 0 0 0 0 0 0 0 0 + 8.1760 3.4230 23.6490 C 0 0 1 0 0 0 0 0 0 0 0 0 + 7.5060 2.2100 24.3360 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.2120 4.6350 24.6080 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.3560 3.8090 22.3990 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.6620 1.7540 22.4470 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.0990 1.6220 21.4220 O 0 0 0 0 0 0 0 0 0 0 0 0 + 10.4690 0.6090 23.0040 N 0 0 0 0 0 0 0 0 0 0 0 0 + 11.3040 0.5640 24.2880 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.6710 -0.7510 22.4200 C 0 0 1 0 0 0 0 0 0 0 0 0 + 11.2900 -1.7490 23.3620 C 0 0 2 0 0 0 0 0 0 0 0 0 + 11.4750 -0.9000 24.6500 C 0 0 1 0 0 0 0 0 0 0 0 0 + 12.5540 -0.8620 23.5260 C 0 0 2 0 0 0 0 0 0 0 0 0 + 13.1070 0.1850 22.4540 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.7560 -1.7070 24.0560 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.2470 -1.3210 22.2840 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.5600 -1.4180 23.2350 O 0 0 0 0 0 0 0 0 0 0 0 0 + 8.7130 -1.7910 20.9800 N 0 0 0 0 0 0 0 0 0 0 0 0 + 7.3650 -2.3390 20.9650 C 0 0 1 0 0 0 0 0 0 0 0 0 + 6.4330 -1.4400 20.1330 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.0820 -0.1210 20.9680 C 0 0 1 0 0 0 0 0 0 0 0 0 + 5.0990 0.6970 20.2960 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.4260 -0.4250 22.2160 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.3730 0.7750 21.7800 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.3410 -4.5130 21.0490 O 0 0 0 0 0 0 0 0 0 0 0 0 + 7.4190 -3.7340 20.3620 C 0 0 1 0 0 0 0 0 0 0 0 0 + 5.3280 -4.3480 19.4680 O 0 0 0 0 0 0 0 0 0 0 0 0 + 6.0360 -4.3950 20.4040 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.6060 -5.0790 21.6250 N 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 1 0 + 3 1 2 0 + 4 2 1 0 + 4 5 1 1 + 6 4 1 0 + 7 4 1 0 + 8 1 1 0 + 9 8 1 6 + 10 9 1 0 + 10 11 1 1 + 12 10 1 0 + 13 10 1 0 + 14 9 1 0 + 15 14 2 0 + 16 14 1 0 + 17 16 1 0 + 18 16 1 0 + 19 18 1 6 + 20 19 1 0 + 20 17 1 6 + 21 20 1 0 + 21 19 1 0 + 21 22 1 6 + 23 21 1 0 + 18 24 1 1 + 25 24 2 0 + 26 24 1 0 + 27 26 1 0 + 27 28 1 6 + 29 28 1 6 + 30 29 1 0 + 31 29 1 0 + 32 30 1 0 + 32 31 1 0 + 34 33 1 1 + 34 27 1 0 + 36 35 2 0 + 36 34 1 0 + 37 36 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-7buy.mol b/fragmenstein/mpro/data/hit_mols/Mpro-7buy.mol new file mode 100644 index 0000000..57a98f3 --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-7buy.mol @@ -0,0 +1,22 @@ + + RDKit 3D + + 9 8 0 0 0 0 0 0 0 0999 V2000 + 6.8050 -3.9060 20.1170 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.1340 -2.1470 21.3440 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.3940 -2.0180 22.8500 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.8550 -2.2100 23.2890 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.8060 -1.0990 22.8630 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.1120 -1.0770 23.6570 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.3540 -1.1790 22.7730 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.8650 -2.8360 21.1060 N 0 0 0 0 0 0 0 0 0 0 0 0 + 5.8080 -4.5110 19.9060 O 0 0 0 0 0 0 0 0 0 0 0 0 + 3 2 1 0 + 4 3 1 0 + 5 4 1 0 + 6 5 1 0 + 7 6 1 0 + 8 2 1 0 + 8 1 1 0 + 9 1 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-7c6s.mol b/fragmenstein/mpro/data/hit_mols/Mpro-7c6s.mol new file mode 100644 index 0000000..bdba5e2 --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-7c6s.mol @@ -0,0 +1,81 @@ + + RDKit 3D + + 37 39 0 0 0 0 0 0 0 0999 V2000 + 11.3280 4.4190 23.3410 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.0960 5.1450 22.4970 N 0 0 0 0 0 0 0 0 0 0 0 0 + 11.5190 4.3360 24.5690 O 0 0 0 0 0 0 0 0 0 0 0 0 + 13.3240 5.8880 22.8480 C 0 0 1 0 0 0 0 0 0 0 0 0 + 13.9560 6.4170 21.5680 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.9570 7.0510 23.7590 C 0 0 0 0 0 0 0 0 0 0 0 0 + 14.2930 4.9500 23.5550 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.3000 3.7720 22.7580 N 0 0 0 0 0 0 0 0 0 0 0 0 + 9.6190 2.6750 23.4240 C 0 0 1 0 0 0 0 0 0 0 0 0 + 8.1500 3.0090 23.7390 C 0 0 2 0 0 0 0 0 0 0 0 0 + 7.3890 3.4120 22.4720 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.0790 4.1670 24.7370 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.4600 1.7900 24.3580 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.8090 1.4100 22.5890 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.3850 1.3270 21.4400 O 0 0 0 0 0 0 0 0 0 0 0 0 + 10.4900 0.3950 23.1470 N 0 0 0 0 0 0 0 0 0 0 0 0 + 11.1420 0.4180 24.4640 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.5910 -0.8860 22.4460 C 0 0 1 0 0 0 0 0 0 0 0 0 + 11.5770 -1.6860 23.2770 C 0 0 2 0 0 0 0 0 0 0 0 0 + 11.9060 -0.8890 24.5230 C 0 0 1 0 0 0 0 0 0 0 0 0 + 12.9790 -1.1710 23.5060 C 0 0 1 0 0 0 0 0 0 0 0 0 + 14.0250 -2.2120 23.8410 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.5330 -0.0230 22.6890 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.2400 -1.5880 22.4210 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.6340 -1.8190 23.4670 O 0 0 0 0 0 0 0 0 0 0 0 0 + 8.7670 -1.9080 21.2130 N 0 0 0 0 0 0 0 0 0 0 0 0 + 7.4560 -2.5500 21.0380 C 0 0 1 0 0 0 0 0 0 0 0 0 + 6.5260 -1.6230 20.2600 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.1470 -0.4100 21.0940 C 0 0 1 0 0 0 0 0 0 0 0 0 + 5.0460 0.5140 20.5650 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.2500 -0.6350 22.3170 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.6580 0.7420 22.0240 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.5220 -4.7270 21.1040 O 0 0 0 0 0 0 0 0 0 0 0 0 + 7.5660 -3.9480 20.3960 C 0 0 1 0 0 0 0 0 0 0 0 0 + 5.4120 -4.4130 19.5080 O 0 0 0 0 0 0 0 0 0 0 0 0 + 6.2150 -4.6500 20.3840 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.8870 -5.6380 21.4300 N 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 1 0 + 3 1 2 0 + 4 2 1 0 + 4 5 1 6 + 6 4 1 0 + 7 4 1 0 + 8 1 1 0 + 9 8 1 6 + 10 9 1 0 + 10 11 1 6 + 12 10 1 0 + 13 10 1 0 + 14 9 1 0 + 15 14 2 0 + 16 14 1 0 + 17 16 1 0 + 18 16 1 0 + 19 18 1 6 + 20 19 1 0 + 20 17 1 6 + 21 20 1 0 + 21 19 1 0 + 21 22 1 1 + 23 21 1 0 + 18 24 1 1 + 25 24 2 0 + 26 24 1 0 + 27 26 1 0 + 27 28 1 6 + 29 28 1 6 + 30 29 1 0 + 31 29 1 0 + 32 30 1 0 + 32 31 1 0 + 34 33 1 1 + 34 27 1 0 + 36 35 2 0 + 36 34 1 0 + 37 36 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-7c6u.mol b/fragmenstein/mpro/data/hit_mols/Mpro-7c6u.mol new file mode 100644 index 0000000..9b7bd23 --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-7c6u.mol @@ -0,0 +1,64 @@ + + RDKit 3D + + 29 30 0 0 0 0 0 0 0 0999 V2000 + 8.9260 3.9930 22.9620 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.4530 2.7170 23.4090 O 0 0 0 0 0 0 0 0 0 0 0 0 + 9.4910 1.7300 22.5010 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.1070 1.8360 21.3590 O 0 0 0 0 0 0 0 0 0 0 0 0 + 7.4310 3.9530 22.8160 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.6770 2.9980 23.4750 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.2980 2.9690 23.3380 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.6630 3.8960 22.5480 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.4000 4.8530 21.8900 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.7800 4.8810 22.0230 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.0250 0.6190 23.0380 N 0 0 0 0 0 0 0 0 0 0 0 0 + 10.0970 -0.6160 22.2770 C 0 0 2 0 0 0 0 0 0 0 0 0 + 8.7130 -1.1350 21.8840 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.7760 -1.0660 22.6780 O 0 0 0 0 0 0 0 0 0 0 0 0 + 10.8590 -1.6830 23.0600 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.2940 -1.3170 23.4390 C 0 0 1 0 0 0 0 0 0 0 0 0 + 12.9240 -2.4080 24.2900 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.1330 -1.0570 22.1980 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.5940 -1.6470 20.6550 N 0 0 0 0 0 0 0 0 0 0 0 0 + 7.3460 -2.2130 20.1390 C 0 0 2 0 0 0 0 0 0 0 0 0 + 7.5600 -3.6780 19.7980 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.3750 -4.2980 19.3540 O 0 0 0 0 0 0 0 0 0 0 0 0 + 6.8690 -1.4170 18.9200 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.4830 0.0100 19.3040 C 0 0 2 0 0 0 0 0 0 0 0 0 + 5.2460 0.1720 20.1730 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.8240 1.6090 19.9090 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.2690 1.8160 18.5350 N 0 0 0 0 0 0 0 0 0 0 0 0 + 6.1740 0.9280 18.1350 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.6930 0.8760 17.0080 O 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 1 0 + 3 2 1 0 + 4 3 1 0 + 5 1 1 0 + 6 5 1 0 + 7 6 1 0 + 8 7 1 0 + 9 8 1 0 + 10 9 1 0 + 10 5 1 0 + 11 3 1 0 + 12 11 1 0 + 13 12 1 0 + 14 13 1 0 + 12 15 1 1 + 16 15 1 0 + 16 17 1 6 + 18 16 1 0 + 19 13 1 0 + 20 19 1 0 + 20 21 1 6 + 22 21 1 0 + 23 20 1 0 + 24 23 1 6 + 25 24 1 0 + 26 25 1 0 + 27 26 1 0 + 28 27 1 0 + 28 24 1 0 + 29 28 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-7c7p.mol b/fragmenstein/mpro/data/hit_mols/Mpro-7c7p.mol new file mode 100644 index 0000000..b9504f7 --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-7c7p.mol @@ -0,0 +1,57 @@ + + RDKit 3D + + 25 27 0 0 0 0 0 0 0 0999 V2000 + 9.6140 0.7940 23.9980 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.7680 0.9020 23.1250 O 0 0 0 0 0 0 0 0 0 0 0 0 + 10.4300 -0.1820 23.9600 N 0 0 0 0 0 0 0 0 0 0 0 0 + 11.3110 -0.4820 25.0960 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.2580 -1.5660 24.6030 C 0 0 2 0 0 0 0 0 0 0 0 0 + 13.6940 -1.0580 24.5250 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.8960 -0.5970 23.0890 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.9880 -1.5200 22.2880 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.8220 -1.9110 23.1900 C 0 0 2 0 0 0 0 0 0 0 0 0 + 10.5210 -1.1560 22.8550 C 0 0 1 0 0 0 0 0 0 0 0 0 + 9.2550 -2.0060 22.7740 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.9620 -2.7440 23.7250 O 0 0 0 0 0 0 0 0 0 0 0 0 + 8.5150 -1.8910 21.7320 N 0 0 0 0 0 0 0 0 0 0 0 0 + 7.2170 -2.5910 21.5430 C 0 0 1 0 0 0 0 0 0 0 0 0 + 6.2440 -1.5430 20.8990 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.8840 -0.5810 19.8680 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.8630 0.2340 19.0470 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.4270 -3.9000 20.7480 C 0 0 1 0 0 0 0 0 0 0 0 0 + 8.3430 -4.7740 21.4670 O 0 0 0 0 0 0 0 0 0 0 0 0 + 6.0990 -4.6030 20.5100 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.4800 -4.4100 19.5030 O 0 0 0 0 0 0 0 0 0 0 0 0 + 5.5850 -5.4190 21.3210 N 0 0 0 0 0 0 0 0 0 0 0 0 + 6.0440 -5.8420 22.6250 C 0 0 2 0 0 0 0 0 0 0 0 0 + 4.9530 -6.7600 23.1860 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.1370 -5.3550 23.7470 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 2 0 + 3 1 1 0 + 4 3 1 0 + 5 4 1 6 + 6 5 1 0 + 7 6 1 0 + 8 7 1 0 + 9 8 1 6 + 9 5 1 0 + 10 3 1 0 + 10 9 1 0 + 10 11 1 1 + 12 11 2 0 + 13 11 1 0 + 14 13 1 0 + 14 15 1 6 + 16 15 1 0 + 17 16 1 0 + 18 14 1 0 + 18 19 1 1 + 20 18 1 0 + 21 20 2 0 + 22 20 1 0 + 23 22 1 6 + 24 23 1 0 + 25 24 1 0 + 25 23 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-7c8b.mol b/fragmenstein/mpro/data/hit_mols/Mpro-7c8b.mol new file mode 100644 index 0000000..2d52bbc --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-7c8b.mol @@ -0,0 +1,6 @@ + + RDKit 3D + + 1 0 0 0 0 0 0 0 0 0999 V2000 + 2.1230 4.8310 -6.2440 C 0 0 0 0 0 0 0 0 0 0 0 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-7c8r.mol b/fragmenstein/mpro/data/hit_mols/Mpro-7c8r.mol new file mode 100644 index 0000000..9a50864 --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-7c8r.mol @@ -0,0 +1,96 @@ + + RDKit 3D + + 45 46 0 0 0 0 0 0 0 0999 V2000 + 6.6130 -7.3810 23.9710 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.9230 -6.4900 22.9300 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.9760 -5.7250 22.4250 O 0 0 0 0 0 0 0 0 0 0 0 0 + 6.8180 -5.1150 21.1970 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.0990 -5.5450 20.3610 O 0 0 0 0 0 0 0 0 0 0 0 0 + 7.7030 -3.9100 21.0730 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.6280 -3.0880 19.7980 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.3940 -1.6340 20.2190 C 0 0 2 0 0 0 0 0 0 0 0 0 + 7.0030 -0.7110 19.0490 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.7670 0.6760 19.4430 C 0 0 2 0 0 0 0 0 0 0 0 0 + 5.5770 0.7910 20.3970 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.0370 2.0170 20.1360 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.3030 2.2850 18.6100 N 0 0 0 0 0 0 0 0 0 0 0 0 + 6.3210 1.5200 18.1760 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.7910 1.4960 17.0810 O 0 0 0 0 0 0 0 0 0 0 0 0 + 8.6880 -1.2210 20.7210 N 0 0 0 0 0 0 0 0 0 0 0 0 + 8.9240 -0.7170 22.0600 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.0250 -0.6150 22.8410 O 0 0 0 0 0 0 0 0 0 0 0 0 + 10.3800 -0.3240 22.3820 C 0 0 2 0 0 0 0 0 0 0 0 0 + 11.0720 -1.3430 23.2640 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.6040 -1.4040 23.1690 C 0 0 2 0 0 0 0 0 0 0 0 0 + 13.1600 -2.0860 24.4120 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.3150 -0.0720 22.9500 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.3160 0.9450 23.0760 N 0 0 0 0 0 0 0 0 0 0 0 0 + 9.9620 2.1820 22.3580 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.7270 2.1620 21.2140 O 0 0 0 0 0 0 0 0 0 0 0 0 + 9.8970 3.5160 23.1420 C 0 0 1 0 0 0 0 0 0 0 0 0 + 10.9560 4.4070 22.6370 N 0 0 0 0 0 0 0 0 0 0 0 0 + 12.0340 4.6990 23.5610 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.8110 4.5220 24.6970 O 0 0 0 0 0 0 0 0 0 0 0 0 + 13.3330 5.0380 23.1390 O 0 0 0 0 0 0 0 0 0 0 0 0 + 13.9550 6.3070 23.1880 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.5290 7.2380 24.3250 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.3240 8.5910 24.0350 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.9380 9.4710 25.0410 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.7760 9.0130 26.3500 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.9920 7.6700 26.6450 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.3800 6.7870 25.6390 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.5490 4.2130 23.0140 C 0 0 1 0 0 0 0 0 0 0 0 0 + 7.4280 3.2510 23.4480 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.5930 5.3580 23.8210 O 0 0 0 0 0 0 0 0 0 0 0 0 + 8.1040 6.5820 23.3290 C 0 0 1 0 0 0 0 0 0 0 0 0 + 7.9430 7.6150 24.4440 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.1350 7.1080 22.3460 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.6980 6.4640 22.7220 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 1 0 + 3 2 1 0 + 4 3 1 0 + 5 4 2 0 + 6 4 1 0 + 7 6 1 0 + 8 7 1 6 + 9 8 1 0 + 10 9 1 6 + 11 10 1 0 + 12 11 1 0 + 13 12 1 0 + 14 13 1 0 + 14 10 1 0 + 15 14 2 0 + 16 8 1 0 + 17 16 1 0 + 18 17 2 0 + 19 17 1 0 + 19 20 1 1 + 21 20 1 0 + 21 22 1 1 + 23 21 1 0 + 24 19 1 0 + 25 24 1 0 + 26 25 2 0 + 27 25 1 0 + 27 28 1 6 + 29 28 1 0 + 30 29 2 0 + 31 29 1 0 + 32 31 1 0 + 33 32 1 0 + 34 33 2 0 + 35 34 1 0 + 36 35 2 0 + 37 36 1 0 + 38 37 2 0 + 38 33 1 0 + 39 27 1 0 + 39 40 1 1 + 41 39 1 0 + 42 41 1 0 + 42 43 1 1 + 44 42 1 0 + 45 42 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-7c8t.mol b/fragmenstein/mpro/data/hit_mols/Mpro-7c8t.mol new file mode 100644 index 0000000..fd72dd6 --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-7c8t.mol @@ -0,0 +1,93 @@ + + RDKit 3D + + 43 45 0 0 0 0 0 0 0 0999 V2000 + 13.1700 6.6950 26.1080 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.2850 6.8200 24.7160 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.9760 8.0360 24.1110 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.5360 9.1160 24.8870 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.4140 8.9850 26.2650 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.7370 7.7740 26.8710 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.7760 5.6300 23.8730 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.7710 5.1420 23.0050 O 0 0 0 0 0 0 0 0 0 0 0 0 + 11.8190 4.2370 23.4970 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.6330 3.9950 22.7100 N 0 0 0 0 0 0 0 0 0 0 0 0 + 9.6040 3.1780 23.2820 C 0 0 2 0 0 0 0 0 0 0 0 0 + 9.6460 1.8430 22.5590 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.8090 0.6140 23.3020 N 0 0 0 0 0 0 0 0 0 0 0 0 + 9.8250 -0.6630 22.6800 C 0 0 2 0 0 0 0 0 0 0 0 0 + 8.4610 -1.0450 22.1240 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.3950 -1.7110 20.8720 N 0 0 0 0 0 0 0 0 0 0 0 0 + 7.1400 -2.1150 20.2930 C 0 0 2 0 0 0 0 0 0 0 0 0 + 7.3620 -3.4820 19.7680 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.0980 -4.1040 19.8930 O 0 0 0 0 0 0 0 0 0 0 0 0 + 6.7220 -1.1940 19.1320 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.4270 0.2100 19.5680 C 0 0 2 0 0 0 0 0 0 0 0 0 + 5.1890 0.2570 20.4670 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.6690 1.7120 20.2380 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.0080 1.9920 18.8690 N 0 0 0 0 0 0 0 0 0 0 0 0 + 6.1070 1.0680 18.3950 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.6000 1.0730 17.2740 O 0 0 0 0 0 0 0 0 0 0 0 0 + 7.4670 -0.8410 22.7410 O 0 0 0 0 0 0 0 0 0 0 0 0 + 10.3710 -1.7920 23.5480 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.6050 -1.4200 24.4090 C 0 0 2 0 0 0 0 0 0 0 0 0 + 12.7260 -0.9050 23.4900 C 0 0 0 0 0 0 0 0 0 0 0 0 + 14.1070 -0.9620 24.1610 C 0 0 0 0 0 0 0 0 0 0 0 0 + 14.4060 -2.3640 24.7170 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.3630 -2.8730 25.7090 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.9100 -2.6650 25.2690 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.5490 1.8110 21.3940 O 0 0 0 0 0 0 0 0 0 0 0 0 + 8.2960 3.9370 23.0810 C 0 0 1 0 0 0 0 0 0 0 0 0 + 7.1180 3.0530 23.4890 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.3910 5.1770 23.8260 O 0 0 0 0 0 0 0 0 0 0 0 0 + 7.8550 6.3830 23.3180 C 0 0 1 0 0 0 0 0 0 0 0 0 + 7.8220 7.4070 24.4520 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.7660 6.9780 22.2540 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.4540 6.1970 22.7140 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.9330 3.6700 24.5380 O 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 2 0 + 3 2 1 0 + 4 3 2 0 + 5 4 1 0 + 6 5 2 0 + 6 1 1 0 + 7 2 1 0 + 8 7 1 0 + 9 8 1 0 + 10 9 1 0 + 11 10 1 6 + 12 11 1 0 + 13 12 1 0 + 14 13 1 0 + 15 14 1 0 + 16 15 1 0 + 17 16 1 0 + 17 18 1 6 + 19 18 1 0 + 20 17 1 0 + 21 20 1 6 + 22 21 1 0 + 23 22 1 0 + 24 23 1 0 + 25 24 1 0 + 25 21 1 0 + 26 25 2 0 + 27 15 2 0 + 14 28 1 1 + 29 28 1 6 + 30 29 1 0 + 31 30 1 0 + 32 31 1 0 + 33 32 1 0 + 34 33 1 0 + 34 29 1 0 + 35 12 2 0 + 36 11 1 0 + 36 37 1 1 + 38 36 1 0 + 39 38 1 0 + 39 40 1 1 + 41 39 1 0 + 42 39 1 0 + 43 9 2 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-7c8u.mol b/fragmenstein/mpro/data/hit_mols/Mpro-7c8u.mol new file mode 100644 index 0000000..703aa4a --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-7c8u.mol @@ -0,0 +1,64 @@ + + RDKit 3D + + 29 30 0 0 0 0 0 0 0 0999 V2000 + 8.8200 3.4280 23.5600 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.6920 3.0820 22.4570 O 0 0 0 0 0 0 0 0 0 0 0 0 + 9.5110 1.8640 21.9220 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.9070 1.6580 20.8920 O 0 0 0 0 0 0 0 0 0 0 0 0 + 7.4250 3.7340 23.0940 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.1790 4.7880 22.2280 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.8830 5.0720 21.8170 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.8260 4.3200 22.2780 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.0570 3.2730 23.1380 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.3510 2.9820 23.5470 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.1050 0.9160 22.6680 N 0 0 0 0 0 0 0 0 0 0 0 0 + 10.2170 -0.4400 22.1630 C 0 0 2 0 0 0 0 0 0 0 0 0 + 8.8600 -1.0940 21.9090 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.1270 -1.3840 22.8540 O 0 0 0 0 0 0 0 0 0 0 0 0 + 11.0370 -1.2980 23.1220 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.4980 -0.8760 23.2760 C 0 0 1 0 0 0 0 0 0 0 0 0 + 13.2410 -1.8590 24.1530 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.1910 -0.7410 21.9300 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.5560 -1.3420 20.6300 N 0 0 0 0 0 0 0 0 0 0 0 0 + 7.3030 -1.9440 20.1680 C 0 0 2 0 0 0 0 0 0 0 0 0 + 7.5370 -3.4300 19.8550 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.2890 -4.1180 19.7470 O 0 0 0 0 0 0 0 0 0 0 0 0 + 6.7590 -1.1390 18.9820 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.3780 0.2820 19.3840 C 0 0 2 0 0 0 0 0 0 0 0 0 + 5.1690 0.4290 20.3010 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.5580 1.7680 19.9100 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.0180 1.9520 18.5370 N 0 0 0 0 0 0 0 0 0 0 0 0 + 6.0400 1.1700 18.2020 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.6380 1.1790 17.1080 O 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 1 0 + 3 2 1 0 + 4 3 1 0 + 5 1 1 0 + 6 5 1 0 + 7 6 1 0 + 8 7 1 0 + 9 8 1 0 + 10 9 1 0 + 10 5 1 0 + 11 3 1 0 + 12 11 1 0 + 13 12 1 0 + 14 13 1 0 + 12 15 1 1 + 16 15 1 0 + 16 17 1 1 + 18 16 1 0 + 19 13 1 0 + 20 19 1 0 + 20 21 1 6 + 22 21 1 0 + 23 20 1 0 + 24 23 1 6 + 25 24 1 0 + 26 25 1 0 + 27 26 1 0 + 28 27 1 0 + 28 24 1 0 + 29 28 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-7cbt.mol b/fragmenstein/mpro/data/hit_mols/Mpro-7cbt.mol new file mode 100644 index 0000000..04bd676 --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-7cbt.mol @@ -0,0 +1,64 @@ + + RDKit 3D + + 29 30 0 0 0 0 0 0 0 0999 V2000 + 10.4230 4.1820 22.5280 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.1360 3.1320 23.4250 O 0 0 0 0 0 0 0 0 0 0 0 0 + 9.8150 1.9110 22.8000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.3410 1.8460 21.7160 O 0 0 0 0 0 0 0 0 0 0 0 0 + 9.1680 5.0660 22.3440 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.2770 6.4670 22.3790 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.1430 7.2550 22.2180 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.9120 6.6320 22.0070 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.7970 5.2370 21.9600 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.9300 4.4520 22.1350 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.0860 0.6650 23.4850 N 0 0 0 0 0 0 0 0 0 0 0 0 + 10.2930 -0.4750 22.6380 C 0 0 2 0 0 0 0 0 0 0 0 0 + 8.8970 -0.9140 22.1210 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.8360 -0.8250 22.6970 O 0 0 0 0 0 0 0 0 0 0 0 0 + 10.9670 -1.6260 23.3450 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.4260 -1.2580 23.6110 C 0 0 2 0 0 0 0 0 0 0 0 0 + 13.2200 -0.7360 22.4130 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.1820 -2.5150 24.0830 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.8720 -1.5200 20.7990 N 0 0 0 0 0 0 0 0 0 0 0 0 + 7.5940 -1.9800 20.2490 C 0 0 2 0 0 0 0 0 0 0 0 0 + 7.8360 -3.4560 20.0470 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.7100 -4.1440 19.7740 O 0 0 0 0 0 0 0 0 0 0 0 0 + 7.1770 -1.1570 19.0510 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.7640 0.3180 19.4400 C 0 0 2 0 0 0 0 0 0 0 0 0 + 5.5810 0.3170 20.4510 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.5460 1.2210 19.9230 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.9820 1.6660 18.5360 N 0 0 0 0 0 0 0 0 0 0 0 0 + 6.3460 1.0840 18.2740 C 0 0 1 0 0 0 0 0 0 0 0 0 + 6.9840 1.3000 17.3100 O 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 1 0 + 3 2 1 0 + 4 3 1 0 + 5 1 1 0 + 6 5 1 0 + 7 6 1 0 + 8 7 1 0 + 9 8 1 0 + 10 9 1 0 + 10 5 1 0 + 11 3 1 0 + 12 11 1 0 + 13 12 1 0 + 14 13 1 0 + 12 15 1 1 + 16 15 1 0 + 16 17 1 6 + 18 16 1 0 + 19 13 1 0 + 20 19 1 0 + 20 21 1 6 + 22 21 1 0 + 23 20 1 0 + 24 23 1 6 + 25 24 1 0 + 26 25 1 0 + 27 26 1 0 + 28 27 1 0 + 28 24 1 0 + 28 29 1 1 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-7com.mol b/fragmenstein/mpro/data/hit_mols/Mpro-7com.mol new file mode 100644 index 0000000..7c1a574 --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-7com.mol @@ -0,0 +1,81 @@ + + RDKit 3D + + 37 39 0 0 0 0 0 0 0 0999 V2000 + 11.2530 4.3940 23.3750 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.8140 5.3580 22.7630 N 0 0 0 0 0 0 0 0 0 0 0 0 + 11.6700 3.9620 24.4490 O 0 0 0 0 0 0 0 0 0 0 0 0 + 12.9980 6.0940 23.2290 C 0 0 1 0 0 0 0 0 0 0 0 0 + 14.1990 5.1780 23.4380 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.3920 7.1010 22.1690 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.7140 6.8720 24.5140 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.2120 3.9110 22.8320 N 0 0 0 0 0 0 0 0 0 0 0 0 + 9.4990 2.7650 23.3930 C 0 0 1 0 0 0 0 0 0 0 0 0 + 8.0210 3.0170 23.6910 C 0 0 2 0 0 0 0 0 0 0 0 0 + 7.2470 3.4470 22.4350 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.9300 4.1580 24.7030 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.4400 1.7470 24.3290 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.7510 1.5400 22.5490 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.4190 1.5520 21.3690 O 0 0 0 0 0 0 0 0 0 0 0 0 + 10.3930 0.5100 23.1360 N 0 0 0 0 0 0 0 0 0 0 0 0 + 10.9730 0.4620 24.4830 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.5970 -0.7580 22.4290 C 0 0 1 0 0 0 0 0 0 0 0 0 + 11.5940 -1.5830 23.2460 C 0 0 2 0 0 0 0 0 0 0 0 0 + 11.7810 -0.8380 24.5640 C 0 0 1 0 0 0 0 0 0 0 0 0 + 12.9610 -0.9820 23.5910 C 0 0 2 0 0 0 0 0 0 0 0 0 + 13.5100 0.2710 22.9000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 14.0000 -1.9920 24.0620 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.2860 -1.4770 22.4240 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.6970 -1.6810 23.4810 O 0 0 0 0 0 0 0 0 0 0 0 0 + 8.8450 -1.8200 21.2930 N 0 0 0 0 0 0 0 0 0 0 0 0 + 7.5410 -2.4610 21.1420 C 0 0 1 0 0 0 0 0 0 0 0 0 + 6.8380 -1.4040 20.2850 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.4690 -1.0040 20.8180 C 0 0 2 0 0 0 0 0 0 0 0 0 + 5.1240 0.4420 20.4830 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.4220 -0.6600 22.3110 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.8980 0.7270 21.9570 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.6930 -4.6380 21.1390 O 0 0 0 0 0 0 0 0 0 0 0 0 + 7.6720 -3.8550 20.4980 C 0 0 1 0 0 0 0 0 0 0 0 0 + 5.5690 -4.5330 19.7120 O 0 0 0 0 0 0 0 0 0 0 0 0 + 6.3660 -4.6110 20.6360 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.1190 -5.2980 21.6870 N 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 1 0 + 3 1 2 0 + 4 2 1 0 + 4 5 1 1 + 6 4 1 0 + 7 4 1 0 + 8 1 1 0 + 9 8 1 6 + 10 9 1 0 + 10 11 1 6 + 12 10 1 0 + 13 10 1 0 + 14 9 1 0 + 15 14 2 0 + 16 14 1 0 + 17 16 1 0 + 18 16 1 0 + 19 18 1 6 + 20 19 1 0 + 20 17 1 6 + 21 20 1 0 + 21 19 1 0 + 21 22 1 6 + 23 21 1 0 + 18 24 1 1 + 25 24 2 0 + 26 24 1 0 + 27 26 1 0 + 27 28 1 6 + 29 28 1 6 + 30 29 1 0 + 31 29 1 0 + 32 30 1 0 + 32 31 1 0 + 34 33 1 1 + 34 27 1 0 + 36 35 2 0 + 36 34 1 0 + 37 36 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-7cx9.mol b/fragmenstein/mpro/data/hit_mols/Mpro-7cx9.mol new file mode 100644 index 0000000..03a6fe4 --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-7cx9.mol @@ -0,0 +1,30 @@ + + RDKit 3D + + 12 13 0 0 0 0 0 0 0 0999 V2000 + 9.4050 -4.1880 20.5110 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.3260 -3.8850 20.9670 O 0 0 0 0 0 0 0 0 0 0 0 0 + 10.6340 -3.6650 21.0800 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.8610 -3.9340 20.5110 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.0140 -3.3880 21.0630 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.9560 -2.5720 22.1720 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.6840 -2.3180 22.7150 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.5320 -2.8650 22.1640 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.4240 -2.4740 22.8480 N 0 0 0 0 0 0 0 0 0 0 0 0 + 9.9130 -1.6660 23.8690 N 0 0 0 0 0 0 0 0 0 0 0 0 + 11.2210 -1.6030 23.7480 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.3560 -0.4530 25.1830 I 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 2 0 + 3 1 1 0 + 4 3 2 0 + 5 4 1 0 + 6 5 2 0 + 7 6 1 0 + 8 3 1 0 + 8 7 2 0 + 9 8 1 0 + 10 9 1 0 + 11 10 2 0 + 11 7 1 0 + 12 11 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-7d1m.mol b/fragmenstein/mpro/data/hit_mols/Mpro-7d1m.mol new file mode 100644 index 0000000..a78af8a --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-7d1m.mol @@ -0,0 +1,6 @@ + + RDKit 3D + + 1 0 0 0 0 0 0 0 0 0999 V2000 + 8.0110 -4.5810 21.1280 O 0 0 0 0 0 0 0 0 0 0 0 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-7d1o.mol b/fragmenstein/mpro/data/hit_mols/Mpro-7d1o.mol new file mode 100644 index 0000000..19df892 --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-7d1o.mol @@ -0,0 +1,106 @@ + + RDKit 3D + + 49 52 0 0 0 0 0 0 0 0999 V2000 + 11.8090 4.3550 22.7130 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.2140 4.0210 23.8400 O 0 0 0 0 0 0 0 0 0 0 0 0 + 12.5130 5.1430 21.8700 N 0 0 0 0 0 0 0 0 0 0 0 0 + 13.8280 5.7560 22.1430 C 0 0 1 0 0 0 0 0 0 0 0 0 + 14.8870 4.6660 22.3810 C 0 0 0 0 0 0 0 0 0 0 0 0 + 14.2650 6.6170 20.9470 C 0 0 0 0 0 0 0 0 0 0 0 0 + 15.1810 3.8490 21.1320 C 0 0 0 0 0 0 0 0 0 0 0 0 + 14.5640 5.7900 19.7050 C 0 0 0 0 0 0 0 0 0 0 0 0 + 15.6220 4.7460 19.9930 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.7210 6.6400 23.4100 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.5860 8.0100 23.3830 S 0 0 2 0 0 0 0 0 0 0 0 0 + 11.3570 7.5890 22.7790 O 0 0 0 0 0 0 0 0 0 0 0 0 + 13.2630 9.1640 22.8720 O 0 0 0 0 0 0 0 0 0 0 0 0 + 12.2020 8.3870 25.1000 C 0 0 2 0 0 0 0 0 0 0 0 0 + 13.4410 8.9850 25.7590 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.8230 7.0920 25.8080 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.0500 9.3800 25.1580 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.6140 3.9370 22.2420 N 0 0 0 0 0 0 0 0 0 0 0 0 + 9.8410 2.9360 22.9580 C 0 0 1 0 0 0 0 0 0 0 0 0 + 8.4010 3.3860 23.2610 C 0 0 1 0 0 0 0 0 0 0 0 0 + 8.4200 4.5770 24.2240 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.6680 3.8080 21.9850 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.6250 2.2430 23.9220 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.9260 1.6120 22.2000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.4330 1.4710 21.0840 O 0 0 0 0 0 0 0 0 0 0 0 0 + 10.5920 0.6080 22.7920 N 0 0 0 0 0 0 0 0 0 0 0 0 + 11.2300 0.6670 24.1140 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.7150 -0.6890 22.1270 C 0 0 1 0 0 0 0 0 0 0 0 0 + 11.7730 -1.4220 22.9310 C 0 0 2 0 0 0 0 0 0 0 0 0 + 12.0180 -0.6240 24.1980 C 0 0 1 0 0 0 0 0 0 0 0 0 + 13.1370 -0.8350 23.2160 C 0 0 1 0 0 0 0 0 0 0 0 0 + 14.2490 -1.7850 23.6080 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.6260 0.3000 22.3410 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.3940 -1.4510 22.1810 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.8710 -1.7300 23.2580 O 0 0 0 0 0 0 0 0 0 0 0 0 + 8.8520 -1.7580 21.0020 N 0 0 0 0 0 0 0 0 0 0 0 0 + 7.4940 -2.3100 20.8880 C 0 0 1 0 0 0 0 0 0 0 0 0 + 6.5810 -1.3090 20.1750 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.4710 0.0200 20.8860 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.7620 1.0640 20.0610 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.3690 0.6730 19.6300 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.5230 -4.5050 20.6920 O 0 0 0 0 0 0 0 0 0 0 0 0 + 7.4920 -3.6730 20.1700 C 0 0 1 0 0 0 0 0 0 0 0 0 + 5.3600 -4.3510 19.3640 O 0 0 0 0 0 0 0 0 0 0 0 0 + 5.8830 -4.8930 21.5000 N 0 0 0 0 0 0 0 0 0 0 0 0 + 4.6370 -5.5620 21.7580 C 0 0 2 0 0 0 0 0 0 0 0 0 + 3.6740 -4.8960 22.6770 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.4120 -6.1070 23.1240 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.1490 -4.3380 20.3140 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 2 0 + 3 1 1 0 + 4 3 1 0 + 5 4 1 0 + 6 4 1 0 + 7 5 1 0 + 8 6 1 0 + 9 7 1 0 + 9 8 1 0 + 4 10 1 1 + 11 10 1 1 + 12 11 2 0 + 13 11 2 0 + 14 11 1 0 + 14 15 1 1 + 16 14 1 0 + 17 14 1 0 + 18 1 1 0 + 19 18 1 6 + 20 19 1 0 + 20 21 1 1 + 22 20 1 0 + 23 20 1 0 + 24 19 1 0 + 25 24 2 0 + 26 24 1 0 + 27 26 1 0 + 28 26 1 0 + 29 28 1 6 + 30 29 1 0 + 30 27 1 6 + 31 30 1 0 + 31 29 1 0 + 31 32 1 1 + 33 31 1 0 + 28 34 1 1 + 35 34 2 0 + 36 34 1 0 + 37 36 1 0 + 37 38 1 6 + 39 38 1 0 + 40 39 1 0 + 41 40 1 0 + 43 42 1 1 + 43 37 1 0 + 46 45 1 1 + 47 46 1 0 + 48 46 1 0 + 48 47 1 0 + 49 44 2 0 + 49 45 1 0 + 49 43 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-7d3i.mol b/fragmenstein/mpro/data/hit_mols/Mpro-7d3i.mol new file mode 100644 index 0000000..f02308c --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-7d3i.mol @@ -0,0 +1,74 @@ + + RDKit 3D + + 33 36 0 0 0 0 0 0 0 0999 V2000 + 10.4730 -0.2430 22.0640 C 0 0 1 0 0 0 0 0 0 0 0 0 + 7.8190 -3.1930 19.7420 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.0580 -0.8740 18.8990 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.7100 1.8630 19.8400 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.1720 1.3620 18.1210 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.6460 3.5180 22.4770 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.7790 5.6740 23.3530 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.5770 8.0060 22.7780 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.6250 2.0850 20.8710 O 0 0 0 0 0 0 0 0 0 0 0 0 + 10.2370 2.1650 21.9260 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.5730 1.0970 22.6440 N 0 0 0 0 0 0 0 0 0 0 0 0 + 11.0860 1.1010 24.0210 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.5470 -0.3150 24.2500 C 0 0 2 0 0 0 0 0 0 0 0 0 + 13.0570 -0.3850 24.0730 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.3450 -1.3580 22.9300 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.0310 -2.0380 22.6070 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.9150 -1.1700 23.1720 C 0 0 2 0 0 0 0 0 0 0 0 0 + 9.0800 -0.6160 21.6740 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.1450 -0.3070 22.3920 O 0 0 0 0 0 0 0 0 0 0 0 0 + 8.9410 -1.2100 20.4940 N 0 0 0 0 0 0 0 0 0 0 0 0 + 7.6480 -1.7030 20.0540 C 0 0 2 0 0 0 0 0 0 0 0 0 + 6.5540 -3.7740 19.4250 O 0 0 0 0 0 0 0 0 0 0 0 0 + 6.6940 0.5700 19.2890 C 0 0 1 0 0 0 0 0 0 0 0 0 + 5.5630 0.6710 20.3110 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.1080 2.0890 18.4590 N 0 0 0 0 0 0 0 0 0 0 0 0 + 6.7010 1.3550 17.0250 O 0 0 0 0 0 0 0 0 0 0 0 0 + 9.4270 4.2300 23.0390 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.2820 6.6730 22.5320 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.0640 8.9460 21.9700 F 0 0 0 0 0 0 0 0 0 0 0 0 + 10.3530 8.3630 23.8690 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.8800 7.3620 24.6720 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.6400 7.7100 25.7180 F 0 0 0 0 0 0 0 0 0 0 0 0 + 10.5950 6.0150 24.4270 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10 9 2 0 + 10 6 1 0 + 11 10 1 0 + 11 1 1 0 + 12 11 1 0 + 13 12 1 6 + 14 13 1 0 + 15 14 1 0 + 16 15 1 0 + 17 1 1 0 + 17 16 1 6 + 17 13 1 0 + 1 18 1 1 + 19 18 2 0 + 20 18 1 0 + 21 20 1 0 + 21 3 1 6 + 21 2 1 0 + 22 2 2 0 + 23 5 1 0 + 23 3 1 6 + 24 4 1 0 + 24 23 1 0 + 25 4 1 0 + 25 5 1 0 + 26 5 2 0 + 27 6 1 0 + 27 7 1 0 + 28 8 2 0 + 28 7 1 0 + 29 8 1 0 + 30 8 1 0 + 31 30 2 0 + 32 31 1 0 + 33 31 1 0 + 33 7 2 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-7jkv.mol b/fragmenstein/mpro/data/hit_mols/Mpro-7jkv.mol new file mode 100644 index 0000000..bb4387d --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-7jkv.mol @@ -0,0 +1,91 @@ + + RDKit 3D + + 41 45 0 0 0 0 0 0 0 0999 V2000 + 7.3990 -3.5400 20.1760 C 0 0 2 0 0 0 0 0 0 0 0 0 + 7.9300 -4.1900 21.2960 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.9080 -4.9810 23.4480 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.4430 -5.2850 24.7230 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.3320 -5.9700 25.6280 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.6500 -6.3400 25.2390 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.1410 -6.0060 23.9820 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.2450 -5.3330 23.1130 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.2450 -1.9830 20.3920 C 0 0 2 0 0 0 0 0 0 0 0 0 + 6.5710 -1.2720 19.1900 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.1480 0.1580 19.5830 C 0 0 2 0 0 0 0 0 0 0 0 0 + 4.9920 0.1800 20.6300 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.1450 1.4720 20.2330 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.5040 0.8820 18.4110 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.7140 -0.8460 22.0260 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.1480 -0.4270 22.3050 C 0 0 2 0 0 0 0 0 0 0 0 0 + 10.8700 -1.5260 23.0920 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.3470 -1.1910 23.1650 C 0 0 2 0 0 0 0 0 0 0 0 0 + 13.0210 -1.3930 21.7960 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.9840 -2.0700 24.2920 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.8620 2.0810 22.3880 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.9140 3.2720 23.1190 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.2840 3.5260 24.4330 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.0860 4.8730 24.6550 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.2450 5.7120 25.7430 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.8480 5.9510 28.1240 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.9580 7.0800 25.6520 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.4480 7.5940 24.4550 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.2840 6.7710 23.3550 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.5990 5.4530 23.4640 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.1850 -4.2920 22.4440 N 0 0 0 0 0 0 0 0 0 0 0 0 + 4.4310 1.5610 18.7810 N 0 0 0 0 0 0 0 0 0 0 0 0 + 8.5490 -1.3930 20.8150 N 0 0 0 0 0 0 0 0 0 0 0 0 + 10.1620 0.9060 22.9890 N 0 0 0 0 0 0 0 0 0 0 0 0 + 9.4520 4.4770 22.5570 N 0 0 0 0 0 0 0 0 0 0 0 0 + 6.1520 -4.0300 19.7870 O 0 0 0 0 0 0 0 0 0 0 0 0 + 5.9460 0.9280 17.2590 O 0 0 0 0 0 0 0 0 0 0 0 0 + 10.7470 5.1300 26.9020 O 0 0 0 0 0 0 0 0 0 0 0 0 + 9.4870 2.0100 21.2060 O 0 0 0 0 0 0 0 0 0 0 0 0 + 7.8050 -0.7960 22.8680 O 0 0 0 0 0 0 0 0 0 0 0 0 + 9.5390 -4.7930 21.5330 S 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 1 0 + 4 3 2 0 + 5 4 1 0 + 6 5 2 0 + 7 6 1 0 + 8 7 2 0 + 8 3 1 0 + 9 1 1 0 + 9 10 1 6 + 11 10 1 6 + 12 11 1 0 + 13 12 1 0 + 14 11 1 0 + 16 15 1 0 + 16 17 1 1 + 18 17 1 0 + 18 19 1 6 + 20 18 1 0 + 22 21 1 0 + 23 22 2 0 + 24 23 1 0 + 25 24 2 0 + 27 25 1 0 + 28 27 2 0 + 29 28 1 0 + 30 24 1 0 + 30 29 2 0 + 31 2 2 0 + 31 3 1 0 + 32 13 1 0 + 32 14 1 0 + 33 9 1 0 + 33 15 1 0 + 34 21 1 0 + 34 16 1 0 + 35 22 1 0 + 35 30 1 0 + 1 36 1 1 + 37 14 2 0 + 38 25 1 0 + 38 26 1 0 + 39 21 2 0 + 40 15 2 0 + 41 2 1 0 + 41 8 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-7jr4.mol b/fragmenstein/mpro/data/hit_mols/Mpro-7jr4.mol new file mode 100644 index 0000000..da79487 --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-7jr4.mol @@ -0,0 +1,12 @@ + + RDKit 3D + + 4 3 0 0 0 0 0 0 0 0999 V2000 + 17.8200 -17.9740 30.0980 N 0 0 0 0 0 0 0 0 0 0 0 0 + 16.5960 -18.5020 29.4710 C 0 0 0 0 0 0 0 0 0 0 0 0 + 16.8120 -19.9450 29.0280 C 0 0 0 0 0 0 0 0 0 0 0 0 + 17.9420 -20.3610 28.8930 O 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 1 0 + 3 2 1 0 + 4 3 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-7ju7.mol b/fragmenstein/mpro/data/hit_mols/Mpro-7ju7.mol new file mode 100644 index 0000000..9ca3306 --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-7ju7.mol @@ -0,0 +1,81 @@ + + RDKit 3D + + 36 40 0 0 0 0 0 0 0 0999 V2000 + 7.1800 -8.3230 33.0960 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.1840 -9.4490 32.9470 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.7930 -10.6350 32.3480 N 0 0 0 0 0 0 0 0 0 0 0 0 + 7.8270 -11.1910 33.2230 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.3480 -10.2870 31.0450 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.3640 -9.1780 31.1850 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.7950 -7.9770 31.8110 N 0 0 0 0 0 0 0 0 0 0 0 0 + 6.8770 -7.2520 30.9180 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.5770 -6.2700 29.9980 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.1390 -6.6930 28.7980 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.7890 -5.8060 27.9570 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.6900 -4.9240 30.3320 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.3390 -4.0330 29.4890 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.9020 -4.4670 28.2960 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.6020 -3.5190 27.3720 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.6210 -2.3120 27.6010 O 0 0 0 0 0 0 0 0 0 0 0 0 + 10.2010 -4.0660 26.2870 N 0 0 0 0 0 0 0 0 0 0 0 0 + 10.8810 -3.3520 25.2770 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.1720 -2.8510 24.1890 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.2460 -3.1070 25.3870 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.8980 -2.3840 24.4030 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.2050 -1.8780 23.2960 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.9380 -1.1080 22.2350 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.8330 -2.1290 23.1950 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.1340 -1.6210 22.0760 N 0 0 0 0 0 0 0 0 0 0 0 0 + 8.8490 -1.1800 22.0090 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.2510 -0.9360 20.8760 N 0 0 0 0 0 0 0 0 0 0 0 0 + 7.8890 -0.8510 23.4190 S 0 0 0 0 0 0 0 0 0 0 0 0 + 6.6500 -0.2230 22.3980 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.0120 -0.3240 21.0920 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.2630 0.1670 19.9190 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.0410 0.8270 20.0290 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.3990 1.2950 18.8960 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.0020 1.0850 17.6690 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.1740 0.4560 17.5310 N 0 0 0 0 0 0 0 0 0 0 0 0 + 6.7870 0.0160 18.6430 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 1 0 + 3 2 1 0 + 4 3 1 0 + 5 3 1 0 + 6 5 1 0 + 7 6 1 0 + 7 1 1 0 + 8 7 1 0 + 9 8 1 0 + 10 9 2 0 + 11 10 1 0 + 12 9 1 0 + 13 12 2 0 + 14 11 2 0 + 14 13 1 0 + 15 14 1 0 + 16 15 2 0 + 17 15 1 0 + 18 17 1 0 + 19 18 2 0 + 20 18 1 0 + 21 20 2 0 + 22 21 1 0 + 23 22 1 0 + 24 19 1 0 + 24 22 2 0 + 25 24 1 0 + 26 25 1 0 + 27 26 2 0 + 28 26 1 0 + 29 28 1 0 + 30 27 1 0 + 30 29 2 0 + 31 30 1 0 + 32 31 2 0 + 33 32 1 0 + 34 33 2 0 + 35 34 1 0 + 36 35 2 0 + 36 31 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-7jyc.mol b/fragmenstein/mpro/data/hit_mols/Mpro-7jyc.mol new file mode 100644 index 0000000..1c64585 --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-7jyc.mol @@ -0,0 +1,106 @@ + + RDKit 3D + + 49 52 0 0 0 0 0 0 0 0999 V2000 + 11.7590 4.4760 22.6850 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.2280 4.0760 23.7740 O 0 0 0 0 0 0 0 0 0 0 0 0 + 12.4310 5.2730 21.8350 N 0 0 0 0 0 0 0 0 0 0 0 0 + 13.7460 5.8770 22.0980 C 0 0 2 0 0 0 0 0 0 0 0 0 + 14.1210 6.7510 20.8960 C 0 0 0 0 0 0 0 0 0 0 0 0 + 14.8330 4.8140 22.2890 C 0 0 0 0 0 0 0 0 0 0 0 0 + 14.4450 5.9340 19.6530 C 0 0 0 0 0 0 0 0 0 0 0 0 + 15.0920 4.0010 21.0300 C 0 0 0 0 0 0 0 0 0 0 0 0 + 15.5380 4.9280 19.9250 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.6580 6.7220 23.4130 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.5640 8.1250 23.3560 S 0 0 2 0 0 0 0 0 0 0 0 0 + 11.3510 7.7720 22.6720 O 0 0 0 0 0 0 0 0 0 0 0 0 + 13.2890 9.2490 22.8470 O 0 0 0 0 0 0 0 0 0 0 0 0 + 12.0610 8.4910 25.0530 C 0 0 1 0 0 0 0 0 0 0 0 0 + 11.2220 7.3400 25.5970 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.3420 8.6560 25.8690 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.2450 9.7780 25.0630 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.5120 4.1650 22.2890 N 0 0 0 0 0 0 0 0 0 0 0 0 + 9.7500 3.1240 22.9570 C 0 0 1 0 0 0 0 0 0 0 0 0 + 8.3220 3.5900 23.2490 C 0 0 1 0 0 0 0 0 0 0 0 0 + 7.5610 2.4580 23.9220 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.3950 4.7800 24.2030 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.5390 4.0120 22.0060 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.9150 1.8160 22.1700 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.5670 1.7460 21.0050 O 0 0 0 0 0 0 0 0 0 0 0 0 + 10.4210 0.7570 22.8250 N 0 0 0 0 0 0 0 0 0 0 0 0 + 10.8120 0.7490 24.2540 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.6020 -0.5510 22.1880 C 0 0 1 0 0 0 0 0 0 0 0 0 + 11.5270 -1.2980 23.1070 C 0 0 2 0 0 0 0 0 0 0 0 0 + 11.6770 -0.4880 24.3850 C 0 0 1 0 0 0 0 0 0 0 0 0 + 12.8750 -0.7410 23.4860 C 0 0 1 0 0 0 0 0 0 0 0 0 + 13.8880 -1.7380 24.0120 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.5330 0.4050 22.7450 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.2770 -1.2730 22.1360 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.6150 -1.3760 23.1620 O 0 0 0 0 0 0 0 0 0 0 0 0 + 8.8470 -1.7010 20.9450 N 0 0 0 0 0 0 0 0 0 0 0 0 + 7.5040 -2.2890 20.7860 C 0 0 1 0 0 0 0 0 0 0 0 0 + 6.6160 -1.3580 19.9410 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.2290 -0.0520 20.6300 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.1270 0.7110 19.9370 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.2350 0.6820 18.4490 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.5220 -4.4940 20.9210 O 0 0 0 0 0 0 0 0 0 0 0 0 + 7.5730 -3.7350 20.2150 C 0 0 1 0 0 0 0 0 0 0 0 0 + 5.4370 -4.4650 19.4800 O 0 0 0 0 0 0 0 0 0 0 0 0 + 6.0610 -5.0140 21.5950 N 0 0 0 0 0 0 0 0 0 0 0 0 + 4.9040 -5.8260 21.8460 C 0 0 2 0 0 0 0 0 0 0 0 0 + 3.6910 -5.1690 22.4120 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.4950 -6.0950 23.2580 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.2630 -4.4340 20.3870 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 2 0 + 3 1 1 0 + 4 3 1 0 + 5 4 1 0 + 6 4 1 0 + 7 5 1 0 + 8 6 1 0 + 9 8 1 0 + 9 7 1 0 + 4 10 1 1 + 11 10 1 1 + 12 11 2 0 + 13 11 2 0 + 14 11 1 0 + 14 15 1 1 + 16 14 1 0 + 17 14 1 0 + 18 1 1 0 + 19 18 1 6 + 20 19 1 0 + 20 21 1 1 + 22 20 1 0 + 23 20 1 0 + 24 19 1 0 + 25 24 2 0 + 26 24 1 0 + 27 26 1 0 + 28 26 1 0 + 29 28 1 6 + 30 27 1 6 + 30 29 1 0 + 31 30 1 0 + 31 29 1 0 + 31 32 1 1 + 33 31 1 0 + 28 34 1 1 + 35 34 2 0 + 36 34 1 0 + 37 36 1 0 + 37 38 1 6 + 39 38 1 0 + 40 39 1 0 + 41 40 1 0 + 43 42 1 1 + 43 37 1 0 + 46 45 1 1 + 47 46 1 0 + 48 46 1 0 + 48 47 1 0 + 49 44 2 0 + 49 45 1 0 + 49 43 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-7k40.mol b/fragmenstein/mpro/data/hit_mols/Mpro-7k40.mol new file mode 100644 index 0000000..7d58b14 --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-7k40.mol @@ -0,0 +1,81 @@ + + RDKit 3D + + 37 39 0 0 0 0 0 0 0 0999 V2000 + 11.4460 4.9710 23.3380 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.9890 6.0090 22.5790 N 0 0 0 0 0 0 0 0 0 0 0 0 + 11.7170 4.7450 24.4840 O 0 0 0 0 0 0 0 0 0 0 0 0 + 13.1880 6.7850 22.9580 C 0 0 1 0 0 0 0 0 0 0 0 0 + 14.3450 5.7230 22.8450 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.2930 7.8620 21.8810 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.1570 7.3470 24.3580 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.4100 4.3030 22.6790 N 0 0 0 0 0 0 0 0 0 0 0 0 + 9.7340 3.2400 23.3240 C 0 0 1 0 0 0 0 0 0 0 0 0 + 8.2350 3.5100 23.5650 C 0 0 2 0 0 0 0 0 0 0 0 0 + 7.5560 2.2700 24.1890 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.4460 3.8670 22.2780 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.1410 4.6890 24.5740 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.9010 2.0090 22.4610 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.5830 1.9560 21.2540 O 0 0 0 0 0 0 0 0 0 0 0 0 + 10.3600 0.8170 23.0370 N 0 0 0 0 0 0 0 0 0 0 0 0 + 10.7600 0.6800 24.3990 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.4910 -0.4670 22.2860 C 0 0 1 0 0 0 0 0 0 0 0 0 + 11.4210 -1.2600 23.0780 C 0 0 2 0 0 0 0 0 0 0 0 0 + 11.5700 -0.5900 24.4510 C 0 0 1 0 0 0 0 0 0 0 0 0 + 12.8010 -0.8720 23.5890 C 0 0 2 0 0 0 0 0 0 0 0 0 + 13.4120 0.3210 22.8530 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.7450 -2.0080 23.9650 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.1160 -1.0040 22.1830 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.3820 -1.0300 23.1740 O 0 0 0 0 0 0 0 0 0 0 0 0 + 8.7550 -1.5450 20.9280 N 0 0 0 0 0 0 0 0 0 0 0 0 + 7.4240 -2.0670 20.7620 C 0 0 1 0 0 0 0 0 0 0 0 0 + 6.5860 -1.2180 19.8190 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.1380 -0.0180 20.7030 C 0 0 2 0 0 0 0 0 0 0 0 0 + 5.2530 -0.1770 21.9620 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.0820 0.8330 20.0980 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.5500 1.1010 21.5250 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.3740 -4.2520 21.3010 O 0 0 0 0 0 0 0 0 0 0 0 0 + 7.5570 -3.5520 20.4610 C 0 0 1 0 0 0 0 0 0 0 0 0 + 5.4580 -4.2240 19.5210 O 0 0 0 0 0 0 0 0 0 0 0 0 + 6.2900 -4.3140 20.3400 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.0110 -5.1500 21.4830 N 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 1 0 + 3 1 2 0 + 4 2 1 0 + 4 5 1 1 + 6 4 1 0 + 7 4 1 0 + 8 1 1 0 + 9 8 1 6 + 10 9 1 0 + 10 11 1 1 + 12 10 1 0 + 13 10 1 0 + 14 9 1 0 + 15 14 2 0 + 16 14 1 0 + 17 16 1 0 + 18 16 1 0 + 19 18 1 6 + 20 17 1 6 + 20 19 1 0 + 21 20 1 0 + 21 19 1 0 + 21 22 1 6 + 23 21 1 0 + 18 24 1 1 + 25 24 2 0 + 26 24 1 0 + 27 26 1 0 + 27 28 1 6 + 29 28 1 6 + 30 29 1 0 + 31 29 1 0 + 32 31 1 0 + 32 30 1 0 + 34 33 1 1 + 34 27 1 0 + 36 35 2 0 + 36 34 1 0 + 37 36 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-7k6d.mol b/fragmenstein/mpro/data/hit_mols/Mpro-7k6d.mol new file mode 100644 index 0000000..c1b2f2a --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-7k6d.mol @@ -0,0 +1,107 @@ + + RDKit 3D + + 49 53 0 0 0 0 0 0 0 0999 V2000 + 12.8650 8.2200 25.7860 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.6160 7.7520 27.9300 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.6230 9.1290 28.2260 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.3960 7.7160 24.4530 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.8470 9.6010 26.0880 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.1280 8.4860 23.5360 O 0 0 0 0 0 0 0 0 0 0 0 0 + 13.2190 7.2940 26.7150 N 0 0 0 0 0 0 0 0 0 0 0 0 + 13.2410 10.0440 27.3070 N 0 0 0 0 0 0 0 0 0 0 0 0 + 12.2250 6.3620 24.3310 N 0 0 0 0 0 0 0 0 0 0 0 0 + 11.6940 5.7620 23.1090 C 0 0 2 0 0 0 0 0 0 0 0 0 + 10.8880 4.5750 23.6800 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.1130 4.1130 24.8300 O 0 0 0 0 0 0 0 0 0 0 0 0 + 12.7720 5.1710 22.1520 C 0 0 2 0 0 0 0 0 0 0 0 0 + 13.7210 4.1710 22.8360 C 0 0 0 0 0 0 0 0 0 0 0 0 + 14.8060 3.6690 21.8910 C 0 0 0 0 0 0 0 0 0 0 0 0 + 15.5550 4.8140 21.2060 C 0 0 0 0 0 0 0 0 0 0 0 0 + 14.5750 5.7100 20.4690 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.5720 6.2780 21.4560 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.9240 4.0160 22.8730 N 0 0 0 0 0 0 0 0 0 0 0 0 + 9.2080 2.8700 23.3660 C 0 0 1 0 0 0 0 0 0 0 0 0 + 7.6500 3.1330 23.3810 C 0 0 1 0 0 0 0 0 0 0 0 0 + 6.9310 1.8940 23.9120 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.3880 4.2550 24.4080 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.0670 3.5100 22.0120 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.5780 1.6140 22.5130 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.3570 1.5860 21.3110 O 0 0 0 0 0 0 0 0 0 0 0 0 + 9.2580 -1.5390 22.3490 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.2030 0.5090 23.0770 N 0 0 0 0 0 0 0 0 0 0 0 0 + 8.6500 -1.7950 23.3910 O 0 0 0 0 0 0 0 0 0 0 0 0 + 10.5570 -0.7170 22.3550 C 0 0 1 0 0 0 0 0 0 0 0 0 + 11.6210 -1.4250 23.2130 C 0 0 2 0 0 0 0 0 0 0 0 0 + 11.7680 -0.5400 24.4760 C 0 0 2 0 0 0 0 0 0 0 0 0 + 12.9900 -1.4160 22.5110 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.6450 -0.0970 22.9210 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.5530 0.3750 24.4940 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.1000 0.2130 24.3180 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.0900 -5.5720 21.7740 N 0 0 0 0 0 0 0 0 0 0 0 0 + 8.7060 -1.9180 21.1430 N 0 0 0 0 0 0 0 0 0 0 0 0 + 7.4350 -2.6450 21.2010 C 0 0 2 0 0 0 0 0 0 0 0 0 + 7.5900 -4.0310 20.5290 C 0 0 2 0 0 0 0 0 0 0 0 0 + 6.2630 -1.8890 20.5390 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.3380 -0.3710 20.6320 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.0440 0.2310 19.2650 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.2790 -4.8400 20.6130 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.9400 -6.3660 22.0640 C 0 0 1 0 0 0 0 0 0 0 0 0 + 4.6050 -6.6510 23.5220 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.7340 -5.7070 22.7250 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.5440 -4.7380 21.2280 O 0 0 0 0 0 0 0 0 0 0 0 0 + 5.4340 -4.7710 19.7150 O 0 0 0 0 0 0 0 0 0 0 0 0 + 3 2 2 0 + 4 1 1 0 + 5 1 1 0 + 6 4 2 0 + 7 1 2 0 + 7 2 1 0 + 8 5 2 0 + 8 3 1 0 + 9 4 1 0 + 10 9 1 1 + 11 10 1 0 + 12 11 2 0 + 13 10 1 0 + 13 14 1 1 + 15 14 1 0 + 16 15 1 0 + 17 16 1 0 + 18 13 1 0 + 18 17 1 0 + 19 11 1 0 + 20 19 1 6 + 21 20 1 0 + 21 22 1 1 + 23 21 1 0 + 24 21 1 0 + 25 20 1 0 + 26 25 2 0 + 28 25 1 0 + 29 27 2 0 + 30 28 1 0 + 30 27 1 1 + 31 30 1 0 + 32 31 1 0 + 31 33 1 6 + 34 33 1 0 + 35 28 1 0 + 32 35 1 6 + 36 34 1 0 + 36 32 1 0 + 38 27 1 0 + 39 38 1 0 + 40 39 1 0 + 39 41 1 6 + 42 41 1 0 + 43 42 1 0 + 44 37 1 0 + 44 40 1 0 + 45 37 1 1 + 46 45 1 0 + 47 46 1 0 + 47 45 1 0 + 40 48 1 1 + 49 44 2 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-7k6e.mol b/fragmenstein/mpro/data/hit_mols/Mpro-7k6e.mol new file mode 100644 index 0000000..ee2b3d1 --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-7k6e.mol @@ -0,0 +1,107 @@ + + RDKit 3D + + 49 53 0 0 0 0 0 0 0 0999 V2000 + 12.7840 8.1740 25.7790 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.6280 7.7550 27.8770 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.5570 9.1300 28.1800 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.2980 7.6670 24.4520 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.6890 9.5540 26.0900 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.0300 8.4600 23.5640 O 0 0 0 0 0 0 0 0 0 0 0 0 + 13.2320 7.2660 26.6800 N 0 0 0 0 0 0 0 0 0 0 0 0 + 13.0980 10.0310 27.2900 N 0 0 0 0 0 0 0 0 0 0 0 0 + 12.1240 6.3170 24.2830 N 0 0 0 0 0 0 0 0 0 0 0 0 + 11.5880 5.7510 23.0470 C 0 0 2 0 0 0 0 0 0 0 0 0 + 10.8100 4.5450 23.6290 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.0680 4.1060 24.7730 O 0 0 0 0 0 0 0 0 0 0 0 0 + 12.6860 5.1900 22.0730 C 0 0 2 0 0 0 0 0 0 0 0 0 + 13.5730 4.1090 22.7130 C 0 0 0 0 0 0 0 0 0 0 0 0 + 14.7580 3.6520 21.8620 C 0 0 0 0 0 0 0 0 0 0 0 0 + 15.5240 4.7760 21.1690 C 0 0 0 0 0 0 0 0 0 0 0 0 + 14.5760 5.7390 20.4810 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.5900 6.2930 21.4930 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.8290 3.9410 22.8640 N 0 0 0 0 0 0 0 0 0 0 0 0 + 9.1330 2.7880 23.3960 C 0 0 1 0 0 0 0 0 0 0 0 0 + 7.5780 3.0780 23.3940 C 0 0 1 0 0 0 0 0 0 0 0 0 + 6.8360 1.8320 23.8890 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.2510 4.2370 24.3570 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.0420 3.4940 22.0180 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.5070 1.5180 22.5510 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.2440 1.4810 21.3480 O 0 0 0 0 0 0 0 0 0 0 0 0 + 9.2370 -1.6100 22.3610 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.1890 0.4290 23.0890 N 0 0 0 0 0 0 0 0 0 0 0 0 + 8.6820 -1.9040 23.4130 O 0 0 0 0 0 0 0 0 0 0 0 0 + 10.5400 -0.7980 22.3640 C 0 0 1 0 0 0 0 0 0 0 0 0 + 11.6100 -1.5180 23.2160 C 0 0 2 0 0 0 0 0 0 0 0 0 + 11.8220 -0.6110 24.4400 C 0 0 2 0 0 0 0 0 0 0 0 0 + 12.9500 -1.5690 22.4910 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.6140 -0.2230 22.7950 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.5800 0.2840 24.4940 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.1140 0.1760 24.1860 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.9710 -5.5810 21.7730 N 0 0 0 0 0 0 0 0 0 0 0 0 + 8.6430 -1.9410 21.1560 N 0 0 0 0 0 0 0 0 0 0 0 0 + 7.3660 -2.6510 21.1780 C 0 0 2 0 0 0 0 0 0 0 0 0 + 7.5370 -4.0630 20.5340 C 0 0 2 0 0 0 0 0 0 0 0 0 + 6.2740 -1.8500 20.4190 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.2430 -0.3480 20.7340 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.8340 0.2460 20.6690 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.2270 -4.8690 20.6090 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.8030 -6.3700 22.0400 C 0 0 1 0 0 0 0 0 0 0 0 0 + 4.4500 -6.7040 23.4870 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.6080 -5.7070 22.7260 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.5210 -4.7360 21.2630 O 0 0 0 0 0 0 0 0 0 0 0 0 + 5.4410 -4.8210 19.6670 O 0 0 0 0 0 0 0 0 0 0 0 0 + 3 2 2 0 + 4 1 1 0 + 5 1 1 0 + 6 4 2 0 + 7 1 2 0 + 7 2 1 0 + 8 5 2 0 + 8 3 1 0 + 9 4 1 0 + 10 9 1 1 + 11 10 1 0 + 12 11 2 0 + 13 10 1 0 + 13 14 1 1 + 15 14 1 0 + 16 15 1 0 + 17 16 1 0 + 18 13 1 0 + 18 17 1 0 + 19 11 1 0 + 20 19 1 6 + 21 20 1 0 + 21 22 1 1 + 23 21 1 0 + 24 21 1 0 + 25 20 1 0 + 26 25 2 0 + 28 25 1 0 + 29 27 2 0 + 30 28 1 0 + 30 27 1 1 + 31 30 1 0 + 32 31 1 0 + 31 33 1 6 + 34 33 1 0 + 35 28 1 0 + 32 35 1 6 + 36 34 1 0 + 36 32 1 0 + 38 27 1 0 + 39 38 1 0 + 40 39 1 0 + 39 41 1 6 + 42 41 1 0 + 43 42 1 0 + 44 37 1 0 + 44 40 1 0 + 45 37 1 1 + 46 45 1 0 + 47 46 1 0 + 47 45 1 0 + 40 48 1 1 + 49 44 2 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-7kfj.mol b/fragmenstein/mpro/data/hit_mols/Mpro-7kfj.mol new file mode 100644 index 0000000..90dded1 --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-7kfj.mol @@ -0,0 +1,31 @@ + + RDKit 3D + + 13 13 0 0 0 0 0 0 0 0999 V2000 + -1.0650 6.6200 -2.6380 O 0 0 0 0 0 0 0 0 0 0 0 0 + -1.9300 6.9540 -1.5600 C 0 0 2 0 0 0 0 0 0 0 0 0 + -1.2060 7.2300 -0.3600 O 0 0 0 0 0 0 0 0 0 0 0 0 + -2.8160 5.7580 -1.2440 C 0 0 0 0 0 0 0 0 0 0 0 0 + -2.2220 4.4480 -1.6350 N 0 0 0 0 0 0 0 0 0 0 0 0 + -2.4860 3.3700 -0.6430 C 0 0 0 0 0 0 0 0 0 0 0 0 + -1.2820 3.0410 0.2330 C 0 0 1 0 0 0 0 0 0 0 0 0 + -1.6840 2.3940 1.5450 C 0 0 0 0 0 0 0 0 0 0 0 0 + -1.4890 0.8810 1.5290 C 0 0 0 0 0 0 0 0 0 0 0 0 + -0.0380 0.4820 1.2970 C 0 0 0 0 0 0 0 0 0 0 0 0 + 0.6910 1.4890 0.4300 C 0 0 2 0 0 0 0 0 0 0 0 0 + 1.2880 2.4570 1.2670 F 0 0 0 0 0 0 0 0 0 0 0 0 + -0.2750 2.1710 -0.5140 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 1 6 + 3 2 1 0 + 4 2 1 0 + 5 4 1 0 + 6 5 1 0 + 7 6 1 6 + 8 7 1 0 + 9 8 1 0 + 10 9 1 0 + 11 10 1 0 + 11 12 1 1 + 13 11 1 0 + 13 7 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x10082.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x10082.mol new file mode 100644 index 0000000..d34d4a1 --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x10082.mol @@ -0,0 +1,56 @@ + + RDKit 3D + + 25 26 0 0 0 0 0 0 0 0999 V2000 + 7.2500 -1.7220 21.4450 N 0 0 0 0 0 0 0 0 0 0 0 0 + 8.0390 -0.6810 20.7370 C 0 0 1 0 0 0 0 0 0 0 0 0 + 7.0900 -0.0550 19.7320 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.9220 0.5620 20.1460 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.0900 1.1600 19.2220 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.4600 1.1280 17.8980 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.5860 0.5620 17.4660 N 0 0 0 0 0 0 0 0 0 0 0 0 + 7.3670 -0.0210 18.3760 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.7380 0.3890 21.5910 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.5910 1.1250 21.1100 O 0 0 0 0 0 0 0 0 0 0 0 0 + 8.2950 0.4730 22.8530 N 0 0 0 0 0 0 0 0 0 0 0 0 + 8.8760 1.3190 23.9170 C 0 0 1 0 0 0 0 0 0 0 0 0 + 8.0720 1.1020 25.1920 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.3270 0.9080 24.1330 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.7910 2.7780 23.4830 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.8630 -2.7090 22.2850 C 0 0 2 0 0 0 0 0 0 0 0 0 + 7.0840 -3.6620 22.9310 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.6650 -4.5480 23.8230 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.0240 -4.4940 24.1080 C 0 0 1 0 0 0 0 0 0 0 0 0 + 9.7980 -3.5610 23.4330 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.2340 -2.6850 22.5240 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.6300 -5.3730 25.1810 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.2180 -4.8500 26.5700 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.9930 -5.4800 27.0700 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.0510 -6.0070 27.4420 N 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 1 1 + 3 2 1 0 + 4 3 1 0 + 5 4 1 0 + 6 5 1 0 + 7 6 1 0 + 8 7 1 0 + 8 3 1 0 + 9 2 1 0 + 10 9 1 0 + 11 9 1 0 + 12 11 1 0 + 12 13 1 1 + 14 12 1 0 + 15 12 1 0 + 16 1 1 1 + 17 16 1 0 + 18 17 1 0 + 19 18 1 0 + 20 19 1 0 + 21 20 1 0 + 21 16 1 0 + 19 22 1 1 + 23 22 1 0 + 24 23 1 0 + 25 24 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x10178.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x10178.mol new file mode 100644 index 0000000..25d49d3 --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x10178.mol @@ -0,0 +1,42 @@ + + RDKit 3D + + 18 19 0 0 0 0 0 0 0 0999 V2000 + 14.4760 -2.0930 20.5250 N 0 0 0 0 0 0 0 0 0 0 0 0 + 13.7510 -1.5330 21.2040 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.7940 -0.8500 22.0330 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.1710 0.1690 22.9060 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.2980 0.8690 23.6400 N 0 0 0 0 0 0 0 0 0 0 0 0 + 10.9940 0.5780 23.4970 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.4400 -1.1460 21.9140 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.5120 -0.4040 22.6260 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.1560 -0.6130 22.2970 N 0 0 0 0 0 0 0 0 0 0 0 0 + 8.4480 0.0500 21.3640 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.8500 1.0680 20.8080 O 0 0 0 0 0 0 0 0 0 0 0 0 + 7.1010 -0.5620 21.0360 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.4490 0.1220 19.8570 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.9220 -0.0680 18.5690 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.3980 0.5160 17.4850 N 0 0 0 0 0 0 0 0 0 0 0 0 + 5.3510 1.3320 17.6690 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.8040 1.5920 18.9120 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.3630 0.9720 20.0140 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 3 0 + 3 2 1 0 + 4 3 2 0 + 5 4 1 0 + 6 5 2 0 + 7 3 1 0 + 8 7 2 0 + 8 6 1 0 + 9 8 1 0 + 10 9 1 0 + 11 10 2 0 + 12 10 1 0 + 13 12 1 0 + 14 13 2 0 + 15 14 1 0 + 16 15 2 0 + 17 16 1 0 + 18 17 2 0 + 18 13 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x10296.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x10296.mol new file mode 100644 index 0000000..cd392ba --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x10296.mol @@ -0,0 +1,44 @@ + + RDKit 3D + + 19 20 0 0 0 0 0 0 0 0999 V2000 + 7.4210 -2.4970 18.2970 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.8270 -1.1010 18.7460 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.7130 -0.0910 18.4770 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.6880 0.1670 19.4550 N 0 0 0 0 0 0 0 0 0 0 0 0 + 5.6250 -0.4270 20.7540 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.7500 0.6570 21.8360 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.9610 1.7950 21.5680 N 0 0 0 0 0 0 0 0 0 0 0 0 + 4.9500 2.6760 22.4710 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.2410 3.4880 22.6870 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.2000 3.0900 23.6170 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.3340 3.8610 23.8400 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.3940 4.7090 22.0500 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.5240 5.4780 22.2800 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.4670 5.0840 23.2050 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.5600 5.8750 23.4070 F 0 0 0 0 0 0 0 0 0 0 0 0 + 4.7810 2.2740 20.2520 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.6620 1.1360 19.2310 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.6640 0.4990 17.4590 O 0 0 0 0 0 0 0 0 0 0 0 0 + 8.7750 -3.5190 18.6220 S 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 1 0 + 3 2 1 0 + 4 3 1 0 + 5 4 1 0 + 6 5 1 0 + 7 6 1 0 + 8 7 1 0 + 9 8 1 0 + 10 9 2 0 + 11 10 1 0 + 12 9 1 0 + 13 12 2 0 + 14 11 2 0 + 14 13 1 0 + 15 14 1 0 + 16 7 1 0 + 17 16 1 0 + 17 4 1 0 + 18 3 2 0 + 1 19 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x10306.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x10306.mol new file mode 100644 index 0000000..bf70c2f --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x10306.mol @@ -0,0 +1,50 @@ + + RDKit 3D + + 22 23 0 0 0 0 0 0 0 0999 V2000 + 7.3720 -2.6430 18.3720 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.3760 -2.7830 19.5010 C 0 0 2 0 0 0 0 0 0 0 0 0 + 5.3000 -3.3120 19.3620 O 0 0 0 0 0 0 0 0 0 0 0 0 + 6.7320 -2.2110 20.6650 N 0 0 0 0 0 0 0 0 0 0 0 0 + 6.2360 -2.7180 21.9420 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.6660 -1.0930 20.8150 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.8240 -1.5120 21.6980 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.3680 -2.1020 22.9750 N 0 0 0 0 0 0 0 0 0 0 0 0 + 7.4150 -3.2210 22.7570 C 0 0 1 0 0 0 0 0 0 0 0 0 + 6.9920 -3.9130 24.0540 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.0050 -5.0750 23.9010 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.4660 -6.1210 22.8770 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.7430 -5.7300 25.2460 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.5190 -2.4810 23.8100 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.6840 -1.5220 23.7200 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.6880 -1.7270 22.7790 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.7090 -0.8060 22.6560 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.9610 -1.0910 21.4780 Cl 0 0 0 0 0 0 0 0 0 0 0 0 + 12.7730 0.3150 23.4540 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.7870 0.5070 24.4090 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.7530 -0.4050 24.5410 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.8400 -3.3780 18.4350 S 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 1 0 + 2 3 1 6 + 4 2 1 0 + 5 4 1 0 + 6 4 1 0 + 7 6 1 0 + 8 7 1 0 + 9 8 1 0 + 9 5 1 0 + 9 10 1 1 + 11 10 1 0 + 11 12 1 0 + 13 11 1 0 + 14 8 1 0 + 15 14 1 0 + 16 15 1 0 + 17 16 1 0 + 18 17 1 0 + 19 17 1 0 + 20 19 1 0 + 21 15 1 0 + 21 20 1 0 + 1 22 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x10329.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x10329.mol new file mode 100644 index 0000000..b6860a9 --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x10329.mol @@ -0,0 +1,46 @@ + + RDKit 3D + + 20 21 0 0 0 0 0 0 0 0999 V2000 + 13.8460 -1.6370 21.2240 Cl 0 0 0 0 0 0 0 0 0 0 0 0 + 12.7220 -0.7620 22.2210 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.2000 0.1570 23.1290 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.3040 0.7600 23.9980 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.9520 0.4670 23.9210 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.3770 -1.0540 22.1220 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.4710 -0.4160 22.9620 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.9810 -0.5770 22.7200 C 0 0 2 0 0 0 0 0 0 0 0 0 + 8.5430 -2.0490 22.6960 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.6120 -2.7020 24.0590 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.6050 0.2120 21.4610 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.0890 1.3130 21.2200 O 0 0 0 0 0 0 0 0 0 0 0 0 + 7.7280 -0.3930 20.6270 N 0 0 0 0 0 0 0 0 0 0 0 0 + 6.6410 0.0040 19.8260 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.6260 0.8690 20.2900 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.2750 0.9850 21.7510 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.8760 1.5410 19.3290 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.0830 1.3950 18.0140 N 0 0 0 0 0 0 0 0 0 0 0 0 + 6.0590 0.5480 17.5740 N 0 0 0 0 0 0 0 0 0 0 0 0 + 6.7760 -0.1260 18.4470 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 1 0 + 3 2 2 0 + 4 3 1 0 + 5 4 2 0 + 6 2 1 0 + 7 6 2 0 + 7 5 1 0 + 8 7 1 0 + 8 9 1 6 + 10 9 1 0 + 11 8 1 0 + 12 11 2 0 + 13 11 1 0 + 14 13 1 0 + 15 14 2 0 + 16 15 1 0 + 17 15 1 0 + 18 17 2 0 + 19 18 1 0 + 20 19 2 0 + 20 14 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x10338.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x10338.mol new file mode 100644 index 0000000..cecab55 --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x10338.mol @@ -0,0 +1,49 @@ + + RDKit 3D + + 21 23 0 0 0 0 0 0 0 0999 V2000 + 13.8540 -1.8330 21.2640 Cl 0 0 0 0 0 0 0 0 0 0 0 0 + 12.7040 -0.9920 22.2500 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.1490 0.0020 23.1040 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.2360 0.6930 23.8800 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.3730 -1.3260 22.1470 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.4540 -0.6120 22.9020 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.8970 0.3860 23.7470 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.8320 1.0540 24.3150 O 0 0 0 0 0 0 0 0 0 0 0 0 + 8.6470 0.2250 24.1410 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.9490 -0.6360 22.9160 C 0 0 1 0 0 0 0 0 0 0 0 0 + 8.5030 0.0570 21.6310 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.0390 1.0860 21.2190 O 0 0 0 0 0 0 0 0 0 0 0 0 + 7.4600 -0.5250 21.0350 N 0 0 0 0 0 0 0 0 0 0 0 0 + 6.7560 0.0610 19.9710 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.5680 0.7530 20.2400 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.0620 0.9380 21.6510 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.9250 1.7920 21.7320 O 0 0 0 0 0 0 0 0 0 0 0 0 + 7.2170 -0.0080 18.6620 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.5650 0.5400 17.6360 N 0 0 0 0 0 0 0 0 0 0 0 0 + 5.4230 1.1850 17.8980 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.8890 1.3080 19.1640 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 1 0 + 3 2 2 0 + 4 3 1 0 + 5 2 1 0 + 6 5 2 0 + 7 6 1 0 + 7 4 2 0 + 8 7 1 0 + 9 8 1 0 + 10 9 1 0 + 10 6 1 0 + 10 11 1 6 + 12 11 2 0 + 13 11 1 0 + 14 13 1 0 + 15 14 2 0 + 16 15 1 0 + 17 16 1 0 + 18 14 1 0 + 19 18 2 0 + 20 19 1 0 + 21 20 2 0 + 21 15 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x10355.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x10355.mol new file mode 100644 index 0000000..143141b --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x10355.mol @@ -0,0 +1,59 @@ + + RDKit 3D + + 26 28 0 0 0 0 0 0 0 0999 V2000 + 1.5650 3.1090 21.3900 F 0 0 0 0 0 0 0 0 0 0 0 0 + 2.5590 2.2400 21.0370 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.0870 2.3480 19.7760 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2.9970 1.3340 21.9650 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.0200 0.4740 21.6090 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.5880 0.5300 20.3350 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.1290 1.4980 19.4210 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.7620 1.6280 18.1890 N 0 0 0 0 0 0 0 0 0 0 0 0 + 5.8410 0.8840 17.7900 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.4440 1.1730 16.7520 O 0 0 0 0 0 0 0 0 0 0 0 0 + 6.2570 -0.1440 18.6910 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.6710 -0.3470 19.9010 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.0490 -1.5480 20.7050 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.2920 -2.5150 20.8040 O 0 0 0 0 0 0 0 0 0 0 0 0 + 7.2140 -1.4920 21.3510 N 0 0 0 0 0 0 0 0 0 0 0 0 + 7.5680 -2.4540 22.3860 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.0420 -2.4850 22.6600 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.4670 -1.1350 22.9090 O 0 0 0 0 0 0 0 0 0 0 0 0 + 10.8050 -0.8320 22.8400 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.1340 0.4910 23.1920 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.0740 1.2720 23.5680 O 0 0 0 0 0 0 0 0 0 0 0 0 + 10.3270 2.6420 23.8720 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.7950 -1.6950 22.3960 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.1010 -1.2390 22.2790 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.4250 0.0580 22.6270 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.4490 0.9280 23.0900 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 1 0 + 3 2 2 0 + 4 2 1 0 + 5 4 2 0 + 6 5 1 0 + 7 6 2 0 + 7 3 1 0 + 8 7 1 0 + 9 8 1 0 + 10 9 2 0 + 11 9 1 0 + 12 6 1 0 + 12 11 2 0 + 13 12 1 0 + 14 13 2 0 + 15 13 1 0 + 16 15 1 0 + 17 16 1 0 + 18 17 1 0 + 19 18 1 0 + 20 19 2 0 + 21 20 1 0 + 22 21 1 0 + 23 19 1 0 + 24 23 2 0 + 25 24 1 0 + 26 25 2 0 + 26 20 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x10396.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x10396.mol new file mode 100644 index 0000000..e44ba44 --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x10396.mol @@ -0,0 +1,46 @@ + + RDKit 3D + + 20 21 0 0 0 0 0 0 0 0999 V2000 + 8.7020 -2.2040 22.4690 F 0 0 0 0 0 0 0 0 0 0 0 0 + 10.8170 0.2440 23.9290 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.3980 0.6180 17.5410 N 0 0 0 0 0 0 0 0 0 0 0 0 + 12.6730 -0.9820 22.3200 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.4260 0.8570 20.1630 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.1050 -0.0670 23.2600 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.9160 1.0410 21.5700 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.3920 -0.6500 22.9540 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.8040 1.4980 19.0960 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.4080 -0.0750 21.4830 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.2710 -0.5450 20.9300 N 0 0 0 0 0 0 0 0 0 0 0 0 + 9.0120 0.9180 21.1050 O 0 0 0 0 0 0 0 0 0 0 0 0 + 6.5580 0.0770 19.8780 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.9250 -0.8810 22.6970 C 0 0 1 0 0 0 0 0 0 0 0 0 + 6.9960 -0.0120 18.5580 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.1640 0.5350 24.0810 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.3380 -1.2880 22.1620 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.3160 1.3540 17.8230 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.1690 -0.5630 23.7860 F 0 0 0 0 0 0 0 0 0 0 0 0 + 13.8430 -1.7900 21.3170 Cl 0 0 0 0 0 0 0 0 0 0 0 0 + 6 4 1 0 + 7 5 1 0 + 8 2 2 0 + 9 5 1 0 + 11 10 1 0 + 12 10 2 0 + 13 5 2 0 + 13 11 1 0 + 14 10 1 0 + 14 8 1 0 + 14 1 1 6 + 15 13 1 0 + 15 3 2 0 + 16 2 1 0 + 16 6 2 0 + 17 8 1 0 + 17 4 2 0 + 18 9 2 0 + 18 3 1 0 + 19 14 1 0 + 20 4 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x10419.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x10419.mol new file mode 100644 index 0000000..3a1dd8c --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x10419.mol @@ -0,0 +1,59 @@ + + RDKit 3D + + 26 28 0 0 0 0 0 0 0 0999 V2000 + 6.6750 1.0560 16.9850 O 0 0 0 0 0 0 0 0 0 0 0 0 + 6.0370 0.7540 17.9880 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.2750 -0.4230 18.7530 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.0940 1.6160 18.4900 N 0 0 0 0 0 0 0 0 0 0 0 0 + 4.4280 1.4360 19.6940 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.7130 0.3060 20.4770 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.0660 0.1480 21.7070 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.1160 1.0660 22.1160 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2.8090 2.1500 21.3230 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.4650 2.3520 20.1180 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.6590 -0.6650 19.9380 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.8440 -1.9850 20.5980 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.2410 -2.9620 20.1830 O 0 0 0 0 0 0 0 0 0 0 0 0 + 6.7090 -2.0960 21.6740 N 0 0 0 0 0 0 0 0 0 0 0 0 + 6.8810 -3.3540 22.3850 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.5620 -0.9860 22.0990 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.9850 -1.2010 21.6630 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.7540 -1.2590 22.8700 O 0 0 0 0 0 0 0 0 0 0 0 0 + 11.0350 -0.7890 22.8180 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.2460 0.4970 23.3540 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.1190 1.1370 23.7980 O 0 0 0 0 0 0 0 0 0 0 0 0 + 10.2770 2.3590 24.5150 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.0920 -1.4940 22.2680 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.3510 -0.9230 22.2440 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.5660 0.3280 22.7870 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.5220 1.0410 23.3530 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 2 0 + 3 2 1 0 + 4 2 1 0 + 5 4 1 0 + 6 5 2 0 + 7 6 1 0 + 8 7 2 0 + 9 8 1 0 + 10 9 2 0 + 10 5 1 0 + 11 6 1 0 + 11 3 2 0 + 12 11 1 0 + 13 12 2 0 + 14 12 1 0 + 15 14 1 0 + 16 14 1 0 + 17 16 1 0 + 18 17 1 0 + 19 18 1 0 + 20 19 2 0 + 21 20 1 0 + 22 21 1 0 + 23 19 1 0 + 24 23 2 0 + 25 24 1 0 + 26 25 2 0 + 26 20 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x10466.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x10466.mol new file mode 100644 index 0000000..d93d495 --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x10466.mol @@ -0,0 +1,47 @@ + + RDKit 3D + + 20 22 0 0 0 0 0 0 0 0999 V2000 + 8.8630 0.9240 21.1580 O 0 0 0 0 0 0 0 0 0 0 0 0 + 8.4870 -0.2020 21.4710 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.9020 -0.8460 22.7800 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.3790 -0.6430 23.0160 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.8310 0.3000 23.9310 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.1670 0.6670 23.9700 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.0790 0.0760 23.1060 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.3040 -1.2780 22.1930 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.6320 -0.9080 22.2470 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.7740 -1.7250 21.2130 Cl 0 0 0 0 0 0 0 0 0 0 0 0 + 7.6600 -0.9440 20.7110 N 0 0 0 0 0 0 0 0 0 0 0 0 + 6.9960 -0.3420 19.6490 N 0 0 0 0 0 0 0 0 0 0 0 0 + 5.8120 0.3840 19.7450 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.5970 0.8590 18.4500 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.5960 0.3930 17.5880 N 0 0 0 0 0 0 0 0 0 0 0 0 + 7.3960 -0.3050 18.3540 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.0470 0.8060 20.8250 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.0330 1.7250 20.5780 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.7970 2.2030 19.2860 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.5730 1.7750 18.2130 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 2 0 + 3 2 1 0 + 4 3 1 0 + 5 4 2 0 + 6 5 1 0 + 7 6 2 0 + 8 4 1 0 + 9 8 2 0 + 9 7 1 0 + 10 9 1 0 + 11 2 1 0 + 12 11 1 0 + 13 12 1 0 + 14 13 2 0 + 15 14 1 0 + 16 15 2 0 + 16 12 1 0 + 17 13 1 0 + 18 17 2 0 + 19 18 1 0 + 20 19 2 0 + 20 14 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x10473.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x10473.mol new file mode 100644 index 0000000..dfe5759 --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x10473.mol @@ -0,0 +1,38 @@ + + RDKit 3D + + 16 17 0 0 0 0 0 0 0 0999 V2000 + 9.4990 1.0660 21.0970 O 0 0 0 0 0 0 0 0 0 0 0 0 + 9.0660 0.0080 21.5430 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.7900 -0.7390 22.6360 C 0 0 1 0 0 0 0 0 0 0 0 0 + 11.2350 -1.0020 22.1800 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.1920 -1.5680 23.2250 C 0 0 1 0 0 0 0 0 0 0 0 0 + 13.6140 -1.8030 22.8500 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.2680 -0.6910 23.7810 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.7430 0.1170 23.9040 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.9340 -0.5880 21.1130 N 0 0 0 0 0 0 0 0 0 0 0 0 + 7.0890 -0.0730 20.1020 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.8670 0.5270 20.4520 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.4240 0.6660 21.8870 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.0920 1.0470 19.4230 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.5420 0.9640 18.1200 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.7060 0.4020 17.7750 N 0 0 0 0 0 0 0 0 0 0 0 0 + 7.4560 -0.1070 18.7560 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 2 0 + 3 2 1 0 + 4 3 1 0 + 5 4 1 6 + 6 5 1 0 + 7 6 1 0 + 7 5 1 0 + 3 8 1 1 + 9 2 1 0 + 10 9 1 0 + 11 10 2 0 + 12 11 1 0 + 13 11 1 0 + 14 13 2 0 + 15 14 1 0 + 16 15 2 0 + 16 10 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x10474.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x10474.mol new file mode 100644 index 0000000..a0ed13d --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x10474.mol @@ -0,0 +1,37 @@ + + RDKit 3D + + 16 16 0 0 0 0 0 0 0 0999 V2000 + 9.6230 0.9960 21.0670 O 0 0 0 0 0 0 0 0 0 0 0 0 + 9.1040 0.0010 21.5550 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.6590 -0.6500 22.8000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.8440 -1.5810 22.5160 C 0 0 2 0 0 0 0 0 0 0 0 0 + 10.9530 -2.6280 23.6210 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.1620 -0.7720 22.3100 C 0 0 2 0 0 0 0 0 0 0 0 0 + 13.3480 -1.6350 21.9120 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.5130 0.0860 23.5150 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.9850 -0.5710 21.0730 N 0 0 0 0 0 0 0 0 0 0 0 0 + 7.1520 -0.0250 20.0640 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.9310 0.5950 20.4180 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.5330 0.8210 21.8540 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.1230 1.0530 19.3830 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.5510 0.9260 18.0770 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.7160 0.3680 17.7280 N 0 0 0 0 0 0 0 0 0 0 0 0 + 7.4920 -0.1020 18.7110 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 2 0 + 3 2 1 0 + 4 3 1 0 + 4 5 1 1 + 6 4 1 0 + 6 7 1 1 + 8 6 1 0 + 9 2 1 0 + 10 9 1 0 + 11 10 2 0 + 12 11 1 0 + 13 11 1 0 + 14 13 2 0 + 15 14 1 0 + 16 15 2 0 + 16 10 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x10476.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x10476.mol new file mode 100644 index 0000000..11c6d2e --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x10476.mol @@ -0,0 +1,41 @@ + + RDKit 3D + + 17 19 0 0 0 0 0 0 0 0999 V2000 + 9.6050 1.0450 21.1260 O 0 0 0 0 0 0 0 0 0 0 0 0 + 9.1400 0.0620 21.7010 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.8370 -0.5860 22.8650 C 0 0 1 0 0 0 0 0 0 0 0 0 + 10.9010 -1.5980 22.4260 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.2350 -0.8840 22.7310 C 0 0 2 0 0 0 0 0 0 0 0 0 + 13.3860 -1.0190 21.7900 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.4320 -1.6750 23.1440 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.9740 0.4890 23.3970 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.4940 0.4350 23.8140 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.9800 -0.5270 21.3510 N 0 0 0 0 0 0 0 0 0 0 0 0 + 7.1470 -0.0680 20.3090 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.8870 0.4750 20.6200 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.4000 0.6040 22.0420 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.5590 -0.0960 18.9750 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.8150 0.3780 17.9670 N 0 0 0 0 0 0 0 0 0 0 0 0 + 5.6170 0.8890 18.2750 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.1200 0.9520 19.5630 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 2 0 + 3 2 1 6 + 4 3 1 0 + 5 4 1 6 + 6 5 1 0 + 7 6 1 0 + 7 5 1 0 + 8 5 1 0 + 9 3 1 0 + 9 8 1 0 + 10 2 1 0 + 11 10 1 0 + 12 11 2 0 + 13 12 1 0 + 14 11 1 0 + 15 14 2 0 + 16 15 1 0 + 17 16 2 0 + 17 12 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x10478.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x10478.mol new file mode 100644 index 0000000..44b8ffc --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x10478.mol @@ -0,0 +1,41 @@ + + RDKit 3D + + 17 19 0 0 0 0 0 0 0 0999 V2000 + 9.7010 0.9020 21.2180 O 0 0 0 0 0 0 0 0 0 0 0 0 + 9.2010 -0.1550 21.5950 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.0310 -0.6410 21.1450 N 0 0 0 0 0 0 0 0 0 0 0 0 + 7.2060 -0.0860 20.1410 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.5920 -0.0650 18.8000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.8300 0.4430 17.8250 N 0 0 0 0 0 0 0 0 0 0 0 0 + 5.6380 0.9410 18.1730 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.1660 0.9610 19.4700 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.9530 0.4520 20.4950 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.4930 0.5280 21.9290 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.8810 -1.0540 22.6020 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.3710 -0.7370 22.8790 C 0 0 1 0 0 0 0 0 0 0 0 0 + 11.7620 0.3840 23.8490 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.5780 -0.3440 24.9070 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.3570 -1.4000 24.1480 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.3970 -1.8240 23.0370 C 0 0 2 0 0 0 0 0 0 0 0 0 + 12.3620 -0.9830 21.7890 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 2 0 + 3 2 1 0 + 4 3 1 0 + 5 4 2 0 + 6 5 1 0 + 7 6 2 0 + 8 7 1 0 + 9 8 2 0 + 9 4 1 0 + 10 9 1 0 + 11 2 1 0 + 12 11 1 6 + 13 12 1 0 + 14 13 1 0 + 15 14 1 0 + 16 15 1 1 + 16 12 1 0 + 17 16 1 0 + 17 12 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x10484.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x10484.mol new file mode 100644 index 0000000..093bd0a --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x10484.mol @@ -0,0 +1,46 @@ + + RDKit 3D + + 20 21 0 0 0 0 0 0 0 0999 V2000 + 9.2450 0.5750 21.0850 O 0 0 0 0 0 0 0 0 0 0 0 0 + 8.3280 0.1310 21.7690 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.0350 0.1400 21.3830 N 0 0 0 0 0 0 0 0 0 0 0 0 + 6.4710 0.2660 20.0900 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.1990 0.0150 18.9250 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.8060 0.3960 17.7050 N 0 0 0 0 0 0 0 0 0 0 0 0 + 5.6450 1.0500 17.6130 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.8420 1.3290 18.6980 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.2360 0.9270 19.9710 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.3790 1.2380 21.1710 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.5530 -0.3840 23.1760 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.6520 -1.4680 23.3170 C 0 0 2 0 0 0 0 0 0 0 0 0 + 9.3860 -2.5550 22.2650 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.5180 -2.1240 24.6960 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.0380 -0.8250 23.1730 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.3810 0.2840 23.9440 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.6080 0.9090 23.7790 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.5140 0.4280 22.8560 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.1990 -0.6800 22.1010 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.9690 -1.3010 22.2520 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 2 0 + 3 2 1 0 + 4 3 1 0 + 5 4 2 0 + 6 5 1 0 + 7 6 2 0 + 8 7 1 0 + 9 8 2 0 + 9 4 1 0 + 10 9 1 0 + 11 2 1 0 + 12 11 1 0 + 12 13 1 6 + 14 12 1 0 + 15 12 1 0 + 16 15 2 0 + 17 16 1 0 + 18 17 2 0 + 19 18 1 0 + 20 19 2 0 + 20 15 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x10488.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x10488.mol new file mode 100644 index 0000000..d6d111e --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x10488.mol @@ -0,0 +1,52 @@ + + RDKit 3D + + 22 25 0 0 0 0 0 0 0 0999 V2000 + 10.5590 -0.5060 23.1740 N 0 0 0 0 0 0 0 0 0 0 0 0 + 6.4150 0.6260 17.4050 N 0 0 0 0 0 0 0 0 0 0 0 0 + 11.4100 1.5050 23.7200 N 0 0 0 0 0 0 0 0 0 0 0 0 + 10.3370 0.7820 23.5960 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.1440 -0.5140 20.9250 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.4460 0.6060 23.3470 O 0 0 0 0 0 0 0 0 0 0 0 0 + 7.7090 -0.3860 25.1690 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.4580 0.1590 19.7610 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.9370 0.0090 18.4710 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.3620 1.4330 17.6110 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.8090 1.6530 18.8600 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.6620 -1.6730 22.5400 C 0 0 1 0 0 0 0 0 0 0 0 0 + 8.9220 1.2420 23.8420 C 0 0 2 0 0 0 0 0 0 0 0 0 + 8.4370 0.9540 25.2730 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.8390 -0.5500 23.0340 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.9840 -1.3700 21.9040 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.0110 0.4920 21.6540 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.9810 0.4790 23.0080 N 0 0 0 0 0 0 0 0 0 0 0 0 + 8.6730 1.3090 21.0310 O 0 0 0 0 0 0 0 0 0 0 0 0 + 7.0300 -0.3070 23.8180 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.3720 1.0050 19.9450 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.9460 -1.9830 23.2490 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4 1 1 0 + 4 3 2 0 + 6 3 1 0 + 8 5 1 0 + 9 8 1 0 + 9 2 2 0 + 10 2 1 0 + 11 10 2 0 + 13 4 1 1 + 14 13 1 0 + 14 7 1 0 + 15 1 2 0 + 12 15 1 1 + 15 6 1 0 + 16 12 1 0 + 17 5 1 0 + 18 17 1 0 + 18 13 1 0 + 19 17 2 0 + 20 18 1 0 + 20 7 1 0 + 21 11 1 0 + 21 8 2 0 + 22 16 1 0 + 22 12 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x10494.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x10494.mol new file mode 100644 index 0000000..10a335c --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x10494.mol @@ -0,0 +1,44 @@ + + RDKit 3D + + 19 20 0 0 0 0 0 0 0 0999 V2000 + 6.3940 0.5650 17.5250 N 0 0 0 0 0 0 0 0 0 0 0 0 + 7.2910 -0.4540 20.9640 N 0 0 0 0 0 0 0 0 0 0 0 0 + 5.4910 0.9700 20.1390 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.1920 -0.1460 23.0900 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.4360 -0.5660 22.8790 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.8470 1.5500 19.0540 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.4430 0.0270 21.4720 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.6020 0.1550 19.8860 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.0400 -0.0360 18.5540 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.3230 0.4490 23.9900 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.3130 -1.1830 21.9950 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.9570 0.2310 23.8910 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.6710 -0.9810 22.1240 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.9970 1.2220 21.5420 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.1000 -0.7970 18.2670 N 0 0 0 0 0 0 0 0 0 0 0 0 + 9.0310 1.0020 21.0130 O 0 0 0 0 0 0 0 0 0 0 0 0 + 8.9450 -0.7180 22.6940 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.3220 1.3230 17.7840 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.7530 -1.8930 21.1110 Cl 0 0 0 0 0 0 0 0 0 0 0 0 + 6 3 1 0 + 7 2 1 0 + 8 3 2 0 + 8 2 1 0 + 9 8 1 0 + 9 1 2 0 + 10 4 2 0 + 11 5 1 0 + 12 5 2 0 + 12 10 1 0 + 13 11 2 0 + 13 4 1 0 + 14 3 1 0 + 15 9 1 0 + 16 7 2 0 + 17 7 1 0 + 17 5 1 0 + 18 6 2 0 + 18 1 1 0 + 19 13 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x10506.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x10506.mol new file mode 100644 index 0000000..da38a4b --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x10506.mol @@ -0,0 +1,59 @@ + + RDKit 3D + + 26 28 0 0 0 0 0 0 0 0999 V2000 + 10.9860 5.1030 22.8730 N 0 0 0 0 0 0 0 0 0 0 0 0 + 6.9840 -2.2390 20.8790 N 0 0 0 0 0 0 0 0 0 0 0 0 + 8.8510 -1.7840 23.0110 N 0 0 0 0 0 0 0 0 0 0 0 0 + 10.0170 5.7560 23.5170 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.3940 0.9310 23.0940 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.8520 -1.0570 20.8830 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.9520 -3.9210 19.7850 O 0 0 0 0 0 0 0 0 0 0 0 0 + 10.0890 -2.0810 23.7540 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.2740 4.8130 23.4860 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.3390 0.1400 23.5930 C 0 0 1 0 0 0 0 0 0 0 0 0 + 13.4000 -1.0530 22.1800 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.9010 2.2650 24.1140 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.0790 2.2990 23.4230 C 0 0 2 0 0 0 0 0 0 0 0 0 + 6.6410 -2.6560 22.2470 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.6490 -2.9170 19.7580 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.4310 0.3170 22.3910 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.9210 -2.9410 23.0480 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.1370 -1.3970 21.6070 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.1950 -2.3970 18.4400 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.7250 5.9350 22.7680 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.4450 0.9760 24.2200 N 0 0 0 0 0 0 0 0 0 0 0 0 + 10.1720 6.1740 24.6620 O 0 0 0 0 0 0 0 0 0 0 0 0 + 11.2840 -1.2420 23.3590 C 0 0 2 0 0 0 0 0 0 0 0 0 + 12.8620 3.5060 22.9960 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.3430 -1.8170 22.6520 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.6590 -3.3420 18.3770 S 0 0 0 0 0 0 0 0 0 0 0 0 + 4 1 1 0 + 6 2 1 0 + 8 3 1 0 + 9 1 1 0 + 10 5 1 0 + 13 12 1 0 + 13 5 1 0 + 14 2 1 0 + 15 7 1 0 + 15 2 1 0 + 16 11 1 0 + 16 5 1 0 + 17 14 1 0 + 17 3 1 0 + 18 6 1 0 + 18 3 1 0 + 19 15 1 0 + 20 4 1 0 + 21 12 1 0 + 10 21 1 6 + 22 4 1 0 + 23 8 1 6 + 23 10 1 0 + 13 24 1 6 + 24 9 1 0 + 25 23 1 0 + 25 11 1 0 + 19 26 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x10513.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x10513.mol new file mode 100644 index 0000000..363e4d3 --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x10513.mol @@ -0,0 +1,49 @@ + + RDKit 3D + + 21 23 0 0 0 0 0 0 0 0999 V2000 + 7.1690 -2.8440 21.2720 N 0 0 0 0 0 0 0 0 0 0 0 0 + 12.4080 -0.8000 22.4070 C 0 0 2 0 0 0 0 0 0 0 0 0 + 7.2290 -4.9880 24.2750 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.3100 -1.9500 21.5400 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.5410 0.2350 23.3260 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.1880 -1.4600 22.3290 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.6780 -3.1870 20.0600 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.1250 -1.1200 23.1580 C 0 0 1 0 0 0 0 0 0 0 0 0 + 10.2970 -0.1040 24.0880 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.4500 -3.8290 23.5310 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.2780 -4.6490 25.4570 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.4730 -2.7710 18.8490 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.4830 -3.3140 22.4970 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.1380 -5.3870 25.2400 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.5110 -3.5000 24.7200 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.5830 -1.2520 21.5760 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.6160 -3.7570 19.9410 O 0 0 0 0 0 0 0 0 0 0 0 0 + 8.7620 -1.7800 22.9980 C 0 0 2 0 0 0 0 0 0 0 0 0 + 11.4970 0.5770 24.1690 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.5940 -3.0720 23.7610 C 0 0 2 0 0 0 0 0 0 0 0 0 + 8.9420 -3.4040 18.5120 S 0 0 0 0 0 0 0 0 0 0 0 0 + 4 1 1 0 + 5 2 1 0 + 6 2 1 0 + 7 1 1 0 + 8 6 1 6 + 9 8 1 0 + 10 3 1 0 + 12 7 1 0 + 13 1 1 0 + 13 10 1 0 + 14 11 1 0 + 14 3 1 0 + 15 11 1 0 + 2 16 1 1 + 17 7 1 0 + 18 4 1 6 + 18 8 1 0 + 19 9 1 0 + 19 5 1 0 + 20 18 1 0 + 20 15 1 1 + 20 10 1 0 + 12 21 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x10525.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x10525.mol new file mode 100644 index 0000000..954f1d0 --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x10525.mol @@ -0,0 +1,61 @@ + + RDKit 3D + + 27 29 0 0 0 0 0 0 0 0999 V2000 + 7.4330 -1.4970 21.5150 N 0 0 0 0 0 0 0 0 0 0 0 0 + 11.3450 0.5820 23.1380 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.8410 -0.4620 20.0600 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.2080 0.3120 21.7940 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.8170 -1.0420 22.2900 O 0 0 0 0 0 0 0 0 0 0 0 0 + 10.0390 -3.1670 23.5090 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.5570 1.0750 16.9180 O 0 0 0 0 0 0 0 0 0 0 0 0 + 12.6290 1.1110 23.1960 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.1240 -0.6500 22.4790 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2.6370 2.0600 21.2400 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.1910 -1.3170 21.8910 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.4560 -0.7520 21.9220 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.9650 0.7740 17.9530 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.2730 -1.6260 20.8740 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.1450 1.1220 22.1000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2.5260 0.9350 23.2960 F 0 0 0 0 0 0 0 0 0 0 0 0 + 7.8770 -2.4600 22.5160 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.3900 -0.2630 18.8310 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.7740 0.4150 20.5240 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.2970 1.3900 19.6310 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.3500 2.5620 24.0520 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.9060 1.5310 18.3860 N 0 0 0 0 0 0 0 0 0 0 0 0 + 10.2200 1.2180 23.5900 O 0 0 0 0 0 0 0 0 0 0 0 0 + 5.5660 -2.6230 20.9840 O 0 0 0 0 0 0 0 0 0 0 0 0 + 9.1780 -1.9660 23.2170 C 0 0 2 0 0 0 0 0 0 0 0 0 + 13.6730 0.4500 22.5690 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.2270 2.2020 19.9960 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8 2 2 0 + 9 5 1 0 + 9 2 1 0 + 11 9 2 0 + 12 11 1 0 + 13 7 2 0 + 14 3 1 0 + 14 1 1 0 + 15 10 1 0 + 15 4 2 0 + 16 15 1 0 + 17 1 1 0 + 18 13 1 0 + 18 3 2 0 + 19 4 1 0 + 19 3 1 0 + 20 19 2 0 + 22 20 1 0 + 22 13 1 0 + 23 21 1 0 + 23 2 1 0 + 24 14 2 0 + 25 17 1 0 + 25 6 1 6 + 25 5 1 0 + 26 12 2 0 + 26 8 1 0 + 27 20 1 0 + 27 10 2 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x10535.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x10535.mol new file mode 100644 index 0000000..0d5e74a --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x10535.mol @@ -0,0 +1,47 @@ + + RDKit 3D + + 20 22 0 0 0 0 0 0 0 0999 V2000 + 6.2550 0.3790 20.0870 C 0 0 2 0 0 0 0 0 0 0 0 0 + 5.5170 1.2360 17.5970 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.8950 -0.6260 22.2810 N 0 0 0 0 0 0 0 0 0 0 0 0 + 6.5780 0.4240 17.7000 N 0 0 0 0 0 0 0 0 0 0 0 0 + 4.7720 1.6500 18.6860 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.9480 -0.4740 23.4370 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.8600 1.4150 21.1910 O 0 0 0 0 0 0 0 0 0 0 0 0 + 12.5510 -1.2080 22.3350 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.2820 0.4320 21.6120 C 0 0 1 0 0 0 0 0 0 0 0 0 + 11.9820 0.1780 24.1900 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.0300 -1.7200 22.4050 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.8490 -1.3450 21.8700 N 0 0 0 0 0 0 0 0 0 0 0 0 + 8.2990 -2.8000 22.9070 O 0 0 0 0 0 0 0 0 0 0 0 0 + 11.2280 -1.2920 21.9500 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.8210 0.0540 21.4630 C 0 0 2 0 0 0 0 0 0 0 0 0 + 10.2700 -0.6170 22.7040 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.9160 0.0050 18.9250 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.1510 1.2070 19.9430 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.6440 0.1060 23.8330 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.7470 -2.0840 21.4220 Cl 0 0 0 0 0 0 0 0 0 0 0 0 + 4 2 1 0 + 5 2 1 0 + 8 6 1 0 + 9 7 1 6 + 9 3 1 0 + 10 6 1 0 + 11 3 1 0 + 12 11 1 0 + 13 11 1 0 + 14 8 1 0 + 15 9 1 0 + 15 1 1 0 + 15 12 1 6 + 16 3 1 0 + 16 14 1 0 + 17 4 1 0 + 1 17 1 6 + 18 5 1 0 + 18 1 1 0 + 19 16 1 0 + 19 10 1 0 + 20 8 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x10555.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x10555.mol new file mode 100644 index 0000000..37cd272 --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x10555.mol @@ -0,0 +1,41 @@ + + RDKit 3D + + 17 19 0 0 0 0 0 0 0 0999 V2000 + 9.8140 0.4670 21.0300 O 0 0 0 0 0 0 0 0 0 0 0 0 + 8.9700 0.1530 21.8520 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.3390 -0.4050 23.2090 C 0 0 2 0 0 0 0 0 0 0 0 0 + 10.8310 -0.8470 23.4020 C 0 0 1 0 0 0 0 0 0 0 0 0 + 11.8970 -1.1330 22.3030 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.7390 0.0290 22.8270 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.8740 0.0790 24.0870 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.3040 -2.0980 24.1480 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.9200 -1.8540 23.5190 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.6500 0.3780 21.6820 N 0 0 0 0 0 0 0 0 0 0 0 0 + 6.8930 0.4600 20.4860 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.5420 0.8520 20.5660 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.8500 1.0640 21.8890 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.4350 0.2010 19.2230 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.7650 0.3740 18.0800 N 0 0 0 0 0 0 0 0 0 0 0 0 + 5.5030 0.8060 18.1700 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.8600 1.0420 19.3680 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 2 0 + 3 2 1 6 + 4 3 1 0 + 4 5 1 6 + 6 5 1 0 + 7 4 1 0 + 7 6 1 0 + 8 4 1 0 + 9 8 1 0 + 9 3 1 0 + 10 2 1 0 + 11 10 1 0 + 12 11 2 0 + 13 12 1 0 + 14 11 1 0 + 15 14 2 0 + 16 15 1 0 + 17 16 2 0 + 17 12 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x10559.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x10559.mol new file mode 100644 index 0000000..28a23b0 --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x10559.mol @@ -0,0 +1,41 @@ + + RDKit 3D + + 17 19 0 0 0 0 0 0 0 0999 V2000 + 9.1390 1.1260 21.0330 O 0 0 0 0 0 0 0 0 0 0 0 0 + 8.5830 0.1560 21.5280 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.0860 -0.4980 22.7900 C 0 0 2 0 0 0 0 0 0 0 0 0 + 10.3220 0.1540 23.4620 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.1830 -0.8390 22.6580 C 0 0 1 0 0 0 0 0 0 0 0 0 + 12.3120 -1.3480 23.4020 C 0 0 2 0 0 0 0 0 0 0 0 0 + 13.5070 -0.4730 23.6100 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.6030 -1.6610 22.7120 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.9540 -1.7710 22.6120 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.4670 -0.4000 21.0210 N 0 0 0 0 0 0 0 0 0 0 0 0 + 6.7370 0.1290 19.9410 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.5410 0.8280 20.1890 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.0360 1.0750 21.5880 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.1940 0.0190 18.6280 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.5590 0.5610 17.5840 N 0 0 0 0 0 0 0 0 0 0 0 0 + 5.4140 1.2060 17.8270 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.8710 1.3520 19.0910 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 2 0 + 3 2 1 6 + 4 3 1 0 + 5 4 1 1 + 6 5 1 0 + 6 7 1 1 + 8 7 1 0 + 8 6 1 0 + 9 3 1 0 + 9 5 1 0 + 10 2 1 0 + 11 10 1 0 + 12 11 2 0 + 13 12 1 0 + 14 11 1 0 + 15 14 2 0 + 16 15 1 0 + 17 16 2 0 + 17 12 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x10565.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x10565.mol new file mode 100644 index 0000000..e229690 --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x10565.mol @@ -0,0 +1,42 @@ + + RDKit 3D + + 18 19 0 0 0 0 0 0 0 0999 V2000 + 9.8110 0.3790 24.2470 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.4140 0.4510 17.3770 N 0 0 0 0 0 0 0 0 0 0 0 0 + 12.0580 -0.6150 23.0160 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.2850 0.7920 19.9260 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.1950 0.4090 23.9360 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.7070 1.0390 21.2960 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.6750 -0.6130 23.2840 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.7800 1.4530 18.8120 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.0590 -0.3260 21.4520 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.9430 -0.7340 20.8260 N 0 0 0 0 0 0 0 0 0 0 0 0 + 8.7890 0.5730 21.0320 O 0 0 0 0 0 0 0 0 0 0 0 0 + 6.3740 -0.0690 19.7230 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.3190 -1.0230 22.7720 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.8960 -0.2070 18.4360 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.0590 0.8940 24.5660 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.8200 -1.1210 22.6850 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.3710 1.2640 17.5800 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.7560 -1.5080 22.1910 I 0 0 0 0 0 0 0 0 0 0 0 0 + 5 3 1 0 + 6 4 1 0 + 7 1 2 0 + 8 4 1 0 + 10 9 1 0 + 11 9 2 0 + 12 4 2 0 + 12 10 1 0 + 13 9 1 0 + 13 7 1 0 + 14 12 1 0 + 14 2 2 0 + 15 1 1 0 + 15 5 2 0 + 16 7 1 0 + 16 3 2 0 + 17 8 2 0 + 17 2 1 0 + 18 3 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x10566.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x10566.mol new file mode 100644 index 0000000..8412971 --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x10566.mol @@ -0,0 +1,47 @@ + + RDKit 3D + + 20 22 0 0 0 0 0 0 0 0999 V2000 + 8.8190 0.4980 21.0970 O 0 0 0 0 0 0 0 0 0 0 0 0 + 8.1070 -0.4330 21.4810 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.9420 -0.7700 20.9000 N 0 0 0 0 0 0 0 0 0 0 0 0 + 6.3400 -0.0590 19.8450 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.8370 -0.1420 18.5430 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.3340 0.5590 17.5230 N 0 0 0 0 0 0 0 0 0 0 0 0 + 5.2910 1.3580 17.7790 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.7180 1.4890 19.0300 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.2510 0.7900 20.1070 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.7270 1.0110 21.5030 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.4480 -1.2600 22.7030 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.6520 -0.6670 23.3900 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.9290 -0.9860 22.9470 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.0480 -0.3100 23.4150 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.4200 -0.6950 22.9100 C 0 0 2 0 0 0 0 0 0 0 0 0 + 13.5900 -1.3650 21.5790 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.8300 -2.1340 22.8150 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.8770 0.6990 24.3510 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.6160 1.0030 24.8350 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.5110 0.3160 24.3600 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 2 0 + 3 2 1 0 + 4 3 1 0 + 5 4 2 0 + 6 5 1 0 + 7 6 2 0 + 8 7 1 0 + 9 8 2 0 + 9 4 1 0 + 10 9 1 0 + 11 2 1 0 + 12 11 1 0 + 13 12 2 0 + 14 13 1 0 + 15 14 1 1 + 16 15 1 0 + 17 16 1 0 + 17 15 1 0 + 18 14 2 0 + 19 18 1 0 + 20 19 2 0 + 20 12 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x10575.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x10575.mol new file mode 100644 index 0000000..b231c23 --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x10575.mol @@ -0,0 +1,41 @@ + + RDKit 3D + + 17 19 0 0 0 0 0 0 0 0999 V2000 + 6.6040 0.3150 17.7860 N 0 0 0 0 0 0 0 0 0 0 0 0 + 5.7910 0.7080 20.4470 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.7810 -1.6960 23.7080 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.2080 -0.0310 22.6410 C 0 0 1 0 0 0 0 0 0 0 0 0 + 5.0070 1.1290 19.3780 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.9500 0.2690 21.5780 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.0020 0.0520 20.1430 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.3590 -0.1120 18.8030 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.9130 0.0820 23.9950 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.5260 -2.0250 22.9650 C 0 0 2 0 0 0 0 0 0 0 0 0 + 12.0580 -1.0510 21.8810 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.4410 -1.3280 24.2570 C 0 0 1 0 0 0 0 0 0 0 0 0 + 5.3710 0.9930 21.8680 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.8430 -0.3920 21.1890 N 0 0 0 0 0 0 0 0 0 0 0 0 + 9.3250 1.3170 21.0670 O 0 0 0 0 0 0 0 0 0 0 0 0 + 9.7210 -0.3830 22.7110 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.4450 0.9140 18.0850 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5 2 1 0 + 7 2 2 0 + 8 7 1 0 + 8 1 2 0 + 9 4 1 0 + 10 3 1 6 + 11 10 1 0 + 11 4 1 0 + 12 10 1 0 + 12 9 1 6 + 12 3 1 0 + 13 2 1 0 + 14 7 1 0 + 14 6 1 0 + 15 6 2 0 + 16 6 1 0 + 4 16 1 1 + 17 5 2 0 + 17 1 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x10598.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x10598.mol new file mode 100644 index 0000000..f95ebd6 --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x10598.mol @@ -0,0 +1,44 @@ + + RDKit 3D + + 19 20 0 0 0 0 0 0 0 0999 V2000 + 13.1230 -1.6730 22.0220 F 0 0 0 0 0 0 0 0 0 0 0 0 + 12.9470 -1.6440 23.3630 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.7600 -2.4250 24.1520 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.6080 -2.3560 25.5270 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.6720 -1.5030 26.0770 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.8620 -0.7310 25.2550 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.9720 -0.8040 23.8660 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.0240 -0.0080 22.9940 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.8780 -0.8460 22.3800 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.0290 -0.0370 21.4230 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.3730 1.0780 21.0420 O 0 0 0 0 0 0 0 0 0 0 0 0 + 7.8960 -0.6360 21.0110 N 0 0 0 0 0 0 0 0 0 0 0 0 + 7.0520 -0.0640 20.0190 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.8590 0.5930 20.3990 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.4700 0.7680 21.8460 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.3810 -0.0980 18.6630 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.6280 0.4440 17.7000 N 0 0 0 0 0 0 0 0 0 0 0 0 + 5.4900 1.0400 18.0740 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.0750 1.1360 19.3860 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 1 0 + 3 2 2 0 + 4 3 1 0 + 5 4 2 0 + 6 5 1 0 + 7 6 2 0 + 7 2 1 0 + 8 7 1 0 + 9 8 1 0 + 10 9 1 0 + 11 10 2 0 + 12 10 1 0 + 13 12 1 0 + 14 13 2 0 + 15 14 1 0 + 16 13 1 0 + 17 16 2 0 + 18 17 1 0 + 19 18 2 0 + 19 14 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x10604.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x10604.mol new file mode 100644 index 0000000..63314a2 --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x10604.mol @@ -0,0 +1,40 @@ + + RDKit 3D + + 17 18 0 0 0 0 0 0 0 0999 V2000 + 6.8250 -0.0710 17.7640 O 0 0 0 0 0 0 0 0 0 0 0 0 + 6.0980 0.5150 18.5460 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.1470 1.4350 18.3170 N 0 0 0 0 0 0 0 0 0 0 0 0 + 4.5910 1.9270 19.4790 N 0 0 0 0 0 0 0 0 0 0 0 0 + 5.2080 1.2920 20.4220 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.1240 0.4220 19.9170 N 0 0 0 0 0 0 0 0 0 0 0 0 + 6.9240 -0.4460 20.6400 N 0 0 0 0 0 0 0 0 0 0 0 0 + 8.0870 -0.0080 21.1660 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.6650 1.0100 20.7900 O 0 0 0 0 0 0 0 0 0 0 0 0 + 8.6230 -0.8430 22.3120 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.0510 -0.4840 22.6590 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.1040 -1.2110 22.1130 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.4040 -0.7930 22.3220 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.7070 -1.6970 21.5940 Cl 0 0 0 0 0 0 0 0 0 0 0 0 + 10.3400 0.6210 23.4520 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.6520 1.0250 23.6560 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.6970 0.3230 23.0760 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 2 0 + 3 2 1 0 + 4 3 1 0 + 5 4 2 0 + 6 5 1 0 + 6 2 1 0 + 7 6 1 0 + 8 7 1 0 + 9 8 2 0 + 10 8 1 0 + 11 10 1 0 + 12 11 2 0 + 13 12 1 0 + 14 13 1 0 + 15 11 1 0 + 16 15 2 0 + 17 16 1 0 + 17 13 2 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x10606.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x10606.mol new file mode 100644 index 0000000..e56433d --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x10606.mol @@ -0,0 +1,42 @@ + + RDKit 3D + + 18 19 0 0 0 0 0 0 0 0999 V2000 + 8.6370 -1.4190 23.3910 S 0 0 1 0 0 0 0 0 0 0 0 0 + 12.7540 0.4430 23.1140 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.8740 -5.3600 25.2320 N 0 0 0 0 0 0 0 0 0 0 0 0 + 8.2980 -3.5880 26.7390 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.1890 -1.2740 22.4590 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.6950 -0.3520 23.2340 O 0 0 0 0 0 0 0 0 0 0 0 0 + 7.4750 -2.6450 27.5790 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.8100 0.9630 23.9870 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.6410 -4.8480 27.2190 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.2550 -0.7250 23.3240 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.4230 -1.9580 24.9160 N 0 0 0 0 0 0 0 0 0 0 0 0 + 8.5870 -2.5370 22.5000 O 0 0 0 0 0 0 0 0 0 0 0 0 + 8.7640 -3.2290 25.4630 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.5580 0.3810 24.1020 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.5490 -4.1500 24.7630 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.4330 -0.6790 22.3760 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.4160 -5.6870 26.4440 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.6410 -1.3890 21.3440 Cl 0 0 0 0 0 0 0 0 0 0 0 0 + 6 1 2 0 + 7 4 1 0 + 8 2 2 0 + 9 4 1 0 + 10 1 1 0 + 10 5 1 0 + 1 11 1 1 + 12 1 2 0 + 13 11 1 0 + 13 4 2 0 + 14 10 2 0 + 14 8 1 0 + 15 13 1 0 + 15 3 2 0 + 16 5 2 0 + 16 2 1 0 + 17 9 2 0 + 17 3 1 0 + 18 16 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x10610.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x10610.mol new file mode 100644 index 0000000..38b83d2 --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x10610.mol @@ -0,0 +1,40 @@ + + RDKit 3D + + 17 18 0 0 0 0 0 0 0 0999 V2000 + 11.7180 0.8950 23.7460 N 0 0 0 0 0 0 0 0 0 0 0 0 + 10.9050 0.1980 23.3650 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.8310 -0.6380 22.8010 C 0 0 1 0 0 0 0 0 0 0 0 0 + 10.4530 -1.9590 22.3330 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.4220 -2.7940 23.4860 O 0 0 0 0 0 0 0 0 0 0 0 0 + 9.1600 -2.5470 24.1080 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.8750 -1.0650 23.9470 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.2200 0.1830 21.6490 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.9400 0.9230 21.0040 O 0 0 0 0 0 0 0 0 0 0 0 0 + 7.8870 0.1960 21.5380 N 0 0 0 0 0 0 0 0 0 0 0 0 + 7.0980 0.3560 20.3740 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.7420 0.6710 20.5240 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.1280 0.9080 21.8800 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.5970 0.1680 19.0790 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.8690 0.3420 17.9710 N 0 0 0 0 0 0 0 0 0 0 0 0 + 5.5940 0.7080 18.1300 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.9960 0.8680 19.3650 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 3 0 + 3 2 1 1 + 4 3 1 0 + 5 4 1 0 + 6 5 1 0 + 7 6 1 0 + 7 3 1 0 + 8 3 1 0 + 9 8 2 0 + 10 8 1 0 + 11 10 1 0 + 12 11 2 0 + 13 12 1 0 + 14 11 1 0 + 15 14 2 0 + 16 15 1 0 + 17 16 2 0 + 17 12 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x10626.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x10626.mol new file mode 100644 index 0000000..7fcf695 --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x10626.mol @@ -0,0 +1,41 @@ + + RDKit 3D + + 17 19 0 0 0 0 0 0 0 0999 V2000 + 9.5910 1.1780 21.1750 O 0 0 0 0 0 0 0 0 0 0 0 0 + 9.4450 -0.0180 21.4210 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.4400 -0.7890 22.2610 C 0 0 2 0 0 0 0 0 0 0 0 0 + 10.9940 -0.0690 23.4830 C 0 0 1 0 0 0 0 0 0 0 0 0 + 11.3030 -0.8840 24.7430 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.7500 -1.3800 24.8210 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.1370 -2.1510 23.5740 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.0050 -1.2920 22.3100 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.8680 -0.2580 22.2820 C 0 0 1 0 0 0 0 0 0 0 0 0 + 8.4120 -0.7530 20.9640 N 0 0 0 0 0 0 0 0 0 0 0 0 + 7.4310 -0.2290 20.0750 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.1930 0.2220 20.5850 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.8290 0.0690 22.0420 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.6650 -0.0940 18.7030 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.7860 0.4400 17.8460 N 0 0 0 0 0 0 0 0 0 0 0 0 + 5.6220 0.8660 18.3460 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.2950 0.7930 19.6840 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 2 0 + 3 2 1 6 + 4 3 1 0 + 4 5 1 1 + 6 5 1 0 + 7 6 1 0 + 8 7 1 0 + 9 3 1 0 + 9 8 1 1 + 9 4 1 0 + 10 2 1 0 + 11 10 1 0 + 12 11 2 0 + 13 12 1 0 + 14 11 1 0 + 15 14 2 0 + 16 15 1 0 + 17 16 2 0 + 17 12 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x10638.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x10638.mol new file mode 100644 index 0000000..89f584a --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x10638.mol @@ -0,0 +1,53 @@ + + RDKit 3D + + 23 25 0 0 0 0 0 0 0 0999 V2000 + 6.3370 0.6770 17.3380 N 0 0 0 0 0 0 0 0 0 0 0 0 + 9.2990 -0.3590 23.3840 N 0 0 0 0 0 0 0 0 0 0 0 0 + 5.2030 0.9180 19.8930 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.7810 0.3910 24.2570 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.4210 0.7200 24.1680 O 0 0 0 0 0 0 0 0 0 0 0 0 + 8.6380 0.5630 24.1710 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.6890 1.6100 18.8040 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.0590 -0.2610 21.3050 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.2920 0.0660 19.6590 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.8190 -0.0220 18.3710 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.4060 0.2900 24.3110 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.7750 -1.0380 22.3550 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.4780 1.4310 25.0760 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.4660 -0.2570 23.2510 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.3990 -1.1500 22.3890 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.6570 1.1560 21.2790 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.8920 -0.6280 20.7330 N 0 0 0 0 0 0 0 0 0 0 0 0 + 8.7070 0.7280 20.9810 O 0 0 0 0 0 0 0 0 0 0 0 0 + 10.7750 0.8960 25.3670 O 0 0 0 0 0 0 0 0 0 0 0 0 + 8.4990 -1.1470 22.4540 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.2850 1.4760 17.5680 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.7020 -0.4400 23.3610 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.6710 -1.9440 21.1670 Cl 0 0 0 0 0 0 0 0 0 0 0 0 + 6 5 2 0 + 6 2 1 0 + 7 3 1 0 + 9 3 2 0 + 10 9 1 0 + 10 1 2 0 + 11 4 2 0 + 13 6 1 0 + 14 12 2 0 + 14 4 1 0 + 15 12 1 0 + 16 3 1 0 + 17 9 1 0 + 17 8 1 0 + 18 8 2 0 + 19 13 1 0 + 19 11 1 0 + 20 8 1 0 + 20 2 1 0 + 21 7 2 0 + 21 1 1 0 + 22 2 1 0 + 22 15 2 0 + 22 11 1 0 + 23 12 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x10645.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x10645.mol new file mode 100644 index 0000000..643e68b --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x10645.mol @@ -0,0 +1,51 @@ + + RDKit 3D + + 22 24 0 0 0 0 0 0 0 0999 V2000 + 5.0570 0.9160 21.2740 N 0 0 0 0 0 0 0 0 0 0 0 0 + 7.5040 -0.4110 20.8580 N 0 0 0 0 0 0 0 0 0 0 0 0 + 3.7970 1.1990 21.7100 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.1400 0.8810 23.8120 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.9630 1.3290 20.9730 O 0 0 0 0 0 0 0 0 0 0 0 0 + 9.1280 -0.4020 22.6540 C 0 0 1 0 0 0 0 0 0 0 0 0 + 5.5470 0.7480 19.9540 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.7520 0.0540 19.7550 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.2420 -0.0600 18.4580 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.4920 1.1570 17.6130 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.8480 0.4360 23.5520 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.9530 -0.6350 22.1700 C 0 0 0 0 0 0 0 0 0 0 0 0 + 14.0050 -1.2130 21.5330 F 0 0 0 0 0 0 0 0 0 0 0 0 + 9.3690 0.5470 23.8820 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.2090 0.3550 23.1020 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.6880 -1.1000 21.8840 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.6420 1.2550 23.2020 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.6350 0.4870 17.4000 N 0 0 0 0 0 0 0 0 0 0 0 0 + 2.8470 1.3960 20.9500 O 0 0 0 0 0 0 0 0 0 0 0 0 + 8.5360 0.2620 21.4130 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.9020 1.3080 18.8530 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.6450 -0.5140 22.5920 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3 1 1 0 + 7 1 1 0 + 8 7 2 0 + 8 2 1 0 + 9 8 1 0 + 11 4 2 0 + 13 12 1 0 + 14 11 1 0 + 14 6 1 0 + 15 12 2 0 + 15 4 1 0 + 16 12 1 0 + 17 3 1 0 + 18 10 1 0 + 18 9 2 0 + 19 3 2 0 + 20 5 2 0 + 20 2 1 0 + 6 20 1 6 + 21 10 2 0 + 21 7 1 0 + 22 11 1 0 + 22 6 1 0 + 22 16 2 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x10678.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x10678.mol new file mode 100644 index 0000000..95433cb --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x10678.mol @@ -0,0 +1,51 @@ + + RDKit 3D + + 22 24 0 0 0 0 0 0 0 0999 V2000 + 7.1260 -2.9200 21.4030 N 0 0 0 0 0 0 0 0 0 0 0 0 + 6.7620 -3.2770 20.1530 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.7320 -3.2730 23.7210 C 0 0 2 0 0 0 0 0 0 0 0 0 + 12.3550 -0.8580 22.2470 C 0 0 2 0 0 0 0 0 0 0 0 0 + 8.0650 -1.8410 21.7470 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.6270 0.3820 24.1690 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.6170 -4.0840 23.5080 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.4110 -0.2810 24.1340 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.1400 -1.2200 23.1450 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.6310 -4.9230 25.2390 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.1220 -1.5070 22.2000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.5400 -3.5770 22.5830 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.4220 -1.2800 21.3770 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.7400 -3.7110 24.5800 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.5270 -5.7170 25.0360 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.2980 -2.4410 19.0060 C 0 0 0 0 0 0 0 0 0 0 0 0 + 14.2930 -1.6030 20.7120 N 0 0 0 0 0 0 0 0 0 0 0 0 + 6.0070 -4.2110 19.9390 O 0 0 0 0 0 0 0 0 0 0 0 0 + 12.5960 0.1080 23.2210 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.7720 -1.8910 23.1110 C 0 0 2 0 0 0 0 0 0 0 0 0 + 7.5250 -5.3070 24.1690 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.7740 -3.3860 18.6720 S 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 1 0 + 5 1 1 0 + 7 3 1 0 + 8 6 1 0 + 9 8 1 0 + 11 9 1 0 + 11 4 1 0 + 12 1 1 0 + 12 7 1 0 + 4 13 1 1 + 14 10 1 0 + 3 14 1 1 + 15 10 1 0 + 16 2 1 0 + 17 13 1 0 + 18 2 1 0 + 19 6 1 0 + 19 4 1 0 + 20 5 1 0 + 20 9 1 6 + 20 3 1 0 + 21 15 1 0 + 21 7 1 0 + 16 22 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x10679.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x10679.mol new file mode 100644 index 0000000..60df890 --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x10679.mol @@ -0,0 +1,49 @@ + + RDKit 3D + + 21 23 0 0 0 0 0 0 0 0999 V2000 + 6.4540 0.6380 17.3960 N 0 0 0 0 0 0 0 0 0 0 0 0 + 9.5470 -0.6250 23.3930 N 0 0 0 0 0 0 0 0 0 0 0 0 + 5.3250 0.7620 19.9700 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.8570 0.5670 23.9250 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.3060 0.1570 24.4990 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.7630 1.4420 18.8970 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.1610 -0.3820 21.4060 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.4590 -0.0260 19.7080 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.9830 -0.0520 18.4140 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.4940 0.2980 24.0440 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.9900 -0.8980 22.0390 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.4520 0.7320 24.9250 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.6040 -0.0210 22.9200 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.6360 -1.1760 22.1020 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.8060 0.9720 21.3700 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.0480 -0.7630 20.7560 N 0 0 0 0 0 0 0 0 0 0 0 0 + 8.8200 0.6170 21.1170 O 0 0 0 0 0 0 0 0 0 0 0 0 + 8.5240 -1.2730 22.5820 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.3550 1.3600 17.6500 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.8990 -0.5640 23.1060 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.9560 -1.7120 20.8460 Cl 0 0 0 0 0 0 0 0 0 0 0 0 + 5 2 1 0 + 6 3 1 0 + 8 3 2 0 + 9 8 1 0 + 9 1 2 0 + 10 4 2 0 + 12 5 2 0 + 12 10 1 0 + 13 11 2 0 + 13 4 1 0 + 14 11 1 0 + 15 3 1 0 + 16 8 1 0 + 16 7 1 0 + 17 7 2 0 + 18 7 1 0 + 18 2 1 0 + 19 6 2 0 + 19 1 1 0 + 20 2 1 0 + 20 14 2 0 + 20 10 1 0 + 21 11 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x10700.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x10700.mol new file mode 100644 index 0000000..2735d88 --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x10700.mol @@ -0,0 +1,48 @@ + + RDKit 3D + + 21 22 0 0 0 0 0 0 0 0999 V2000 + 7.0480 -1.4110 21.5390 N 0 0 0 0 0 0 0 0 0 0 0 0 + 11.1060 0.4070 23.0960 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.5720 0.6130 20.4000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.3530 -1.1160 22.7480 O 0 0 0 0 0 0 0 0 0 0 0 0 + 7.3650 -2.3800 22.5800 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.4700 1.2430 16.8700 O 0 0 0 0 0 0 0 0 0 0 0 0 + 12.4530 0.7460 23.0660 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.7090 -0.9160 22.8150 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.6640 -1.8810 22.5390 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.0040 -1.5250 22.5060 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.5830 -0.3110 19.9730 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.8990 0.9670 17.9330 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.9370 -1.5000 20.8080 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.2730 1.6410 19.5810 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.2160 -0.1300 18.7720 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.4090 2.6500 23.5740 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.9150 1.8080 18.3960 N 0 0 0 0 0 0 0 0 0 0 0 0 + 10.0820 1.2750 23.3660 O 0 0 0 0 0 0 0 0 0 0 0 0 + 5.2010 -2.4840 20.8470 O 0 0 0 0 0 0 0 0 0 0 0 0 + 8.8400 -2.4540 22.8390 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.3930 -0.2240 22.7610 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5 1 1 0 + 7 2 2 0 + 8 4 1 0 + 8 2 1 0 + 9 8 2 0 + 10 9 1 0 + 11 3 1 0 + 12 6 2 0 + 13 11 1 0 + 13 1 1 0 + 14 3 2 0 + 15 12 1 0 + 15 11 2 0 + 17 14 1 0 + 17 12 1 0 + 18 16 1 0 + 18 2 1 0 + 19 13 2 0 + 20 5 1 0 + 20 4 1 0 + 21 10 2 0 + 21 7 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x10710.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x10710.mol new file mode 100644 index 0000000..b4a33b4 --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x10710.mol @@ -0,0 +1,48 @@ + + RDKit 3D + + 21 22 0 0 0 0 0 0 0 0999 V2000 + 8.1660 -3.0910 20.4100 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.1010 -1.6800 20.9650 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.2270 -0.9100 20.5920 O 0 0 0 0 0 0 0 0 0 0 0 0 + 9.0060 -1.3340 21.9150 N 0 0 0 0 0 0 0 0 0 0 0 0 + 8.6450 -0.2280 22.8210 C 0 0 2 0 0 0 0 0 0 0 0 0 + 8.5850 1.1480 22.1570 C 0 0 1 0 0 0 0 0 0 0 0 0 + 9.3590 1.4540 21.2530 O 0 0 0 0 0 0 0 0 0 0 0 0 + 7.5720 1.9340 22.5640 N 0 0 0 0 0 0 0 0 0 0 0 0 + 7.7430 3.3020 22.7400 N 0 0 0 0 0 0 0 0 0 0 0 0 + 8.7700 4.0720 23.1340 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.8570 5.2600 22.8180 O 0 0 0 0 0 0 0 0 0 0 0 0 + 9.8110 3.3880 23.9650 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.2690 -2.0760 22.0490 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.3500 -1.2030 22.6250 C 0 0 1 0 0 0 0 0 0 0 0 0 + 12.6530 -1.2370 22.1340 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.5910 -0.3180 22.5750 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.2510 0.6090 23.5330 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.9690 0.6330 24.0570 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.0030 -0.2590 23.6010 C 0 0 1 0 0 0 0 0 0 0 0 0 + 9.5650 -0.1970 24.0480 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.6660 -3.1420 18.7590 S 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 1 0 + 3 2 1 0 + 4 2 1 0 + 5 4 1 0 + 6 5 1 0 + 6 7 1 6 + 8 6 1 0 + 9 8 1 0 + 10 9 1 0 + 11 10 1 0 + 12 10 1 0 + 13 4 1 0 + 14 13 1 6 + 15 14 1 0 + 16 15 1 0 + 17 16 1 0 + 18 17 1 0 + 19 18 1 6 + 19 14 1 0 + 5 20 1 1 + 20 19 1 0 + 1 21 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x10723.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x10723.mol new file mode 100644 index 0000000..aad2c4c --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x10723.mol @@ -0,0 +1,42 @@ + + RDKit 3D + + 18 19 0 0 0 0 0 0 0 0999 V2000 + 11.0020 0.3760 23.6650 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.5000 0.5960 17.3770 N 0 0 0 0 0 0 0 0 0 0 0 0 + 11.4030 -1.1440 21.8920 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.3070 0.6360 23.8280 N 0 0 0 0 0 0 0 0 0 0 0 0 + 5.4930 0.8310 19.9920 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.7470 -0.9000 22.0580 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.9740 1.0240 21.3940 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.4930 -0.4890 22.7120 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.8600 1.4360 18.9120 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.4880 0.0120 21.3030 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.3600 -0.5110 20.7890 N 0 0 0 0 0 0 0 0 0 0 0 0 + 9.0540 0.9900 20.8290 O 0 0 0 0 0 0 0 0 0 0 0 0 + 6.6530 0.0800 19.7220 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.0050 -0.6880 22.5450 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.1100 -0.0050 18.4050 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.1730 0.0140 23.0180 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.3860 1.2910 17.6430 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.8990 -1.8260 21.1380 Cl 0 0 0 0 0 0 0 0 0 0 0 0 + 4 1 2 0 + 6 3 1 0 + 7 5 1 0 + 8 3 2 0 + 8 1 1 0 + 9 5 1 0 + 11 10 1 0 + 12 10 2 0 + 13 11 1 0 + 13 5 2 0 + 14 10 1 0 + 14 8 1 0 + 15 13 1 0 + 15 2 2 0 + 16 6 2 0 + 16 4 1 0 + 17 9 2 0 + 17 2 1 0 + 18 6 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x10728.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x10728.mol new file mode 100644 index 0000000..53ea4b7 --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x10728.mol @@ -0,0 +1,57 @@ + + RDKit 3D + + 25 27 0 0 0 0 0 0 0 0999 V2000 + 7.8270 -2.1730 24.3460 N 0 0 0 0 0 0 0 0 0 0 0 0 + 11.8680 -1.3190 22.7790 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.7100 -0.1530 25.4450 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.3890 -4.3470 20.3200 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.5710 -5.0730 19.7910 O 0 0 0 0 0 0 0 0 0 0 0 0 + 11.5230 -2.2980 25.5170 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.6090 -0.9010 24.4550 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.4760 -5.7920 22.3030 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.0320 -2.6300 25.1680 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.7120 0.7530 26.6200 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.6350 -0.0010 25.6510 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.9830 -1.1430 23.8090 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.1680 -3.2730 23.6040 C 0 0 1 0 0 0 0 0 0 0 0 0 + 7.7860 -3.7000 22.2820 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.9140 -2.2260 24.8800 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.4920 -1.3770 23.4460 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.9250 -3.1460 19.5670 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.7230 -4.4840 24.4330 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.3880 1.0980 25.9650 C 0 0 2 0 0 0 0 0 0 0 0 0 + 6.8650 -4.5850 21.5600 N 0 0 0 0 0 0 0 0 0 0 0 0 + 4.5360 1.7710 26.8850 O 0 0 0 0 0 0 0 0 0 0 0 0 + 10.4090 -2.4930 24.4860 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.9490 -1.2550 25.1030 C 0 0 2 0 0 0 0 0 0 0 0 0 + 5.8170 -5.4110 23.6210 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.4950 -3.5520 18.7620 S 0 0 0 0 0 0 0 0 0 0 0 0 + 5 4 1 0 + 7 3 1 0 + 9 1 1 0 + 11 10 1 0 + 12 2 1 0 + 13 1 1 1 + 14 13 1 0 + 15 12 1 0 + 15 6 1 0 + 16 2 1 0 + 17 4 1 0 + 18 13 1 0 + 19 3 1 0 + 19 10 1 0 + 20 8 1 0 + 20 4 1 0 + 20 14 1 0 + 19 21 1 1 + 22 16 1 0 + 22 9 1 0 + 22 6 1 0 + 23 11 1 0 + 23 7 1 0 + 23 1 1 6 + 24 8 1 0 + 24 18 1 0 + 17 25 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x10733.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x10733.mol new file mode 100644 index 0000000..234f37f --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x10733.mol @@ -0,0 +1,49 @@ + + RDKit 3D + + 21 23 0 0 0 0 0 0 0 0999 V2000 + 6.4170 0.6060 17.4340 N 0 0 0 0 0 0 0 0 0 0 0 0 + 9.8070 -0.6960 23.2950 N 0 0 0 0 0 0 0 0 0 0 0 0 + 5.4190 0.7660 20.0550 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.0970 0.5280 23.8880 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.5470 0.0510 24.4200 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.8270 1.4640 19.0070 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.3500 -0.4070 21.3520 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.5350 -0.0350 19.7480 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.9900 -0.0770 18.4290 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.7410 0.2170 24.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.2480 -0.8480 21.9600 C 0 0 0 0 0 0 0 0 0 0 0 0 + 14.0160 -1.4310 21.0020 F 0 0 0 0 0 0 0 0 0 0 0 0 + 10.6840 0.6180 24.8810 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.8540 0.0100 22.8510 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.9140 -1.1840 22.0070 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.9060 0.9160 21.4650 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.1830 -0.7580 20.7750 N 0 0 0 0 0 0 0 0 0 0 0 0 + 8.9920 0.5990 21.0510 O 0 0 0 0 0 0 0 0 0 0 0 0 + 8.8010 -1.3430 22.4590 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.3520 1.3600 17.7350 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.1630 -0.6220 23.0310 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5 2 1 0 + 6 3 1 0 + 8 3 2 0 + 9 8 1 0 + 9 1 2 0 + 10 4 2 0 + 12 11 1 0 + 13 5 2 0 + 13 10 1 0 + 14 11 2 0 + 14 4 1 0 + 15 11 1 0 + 16 3 1 0 + 17 8 1 0 + 17 7 1 0 + 18 7 2 0 + 19 7 1 0 + 19 2 1 0 + 20 6 2 0 + 20 1 1 0 + 21 2 1 0 + 21 15 2 0 + 21 10 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x10756.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x10756.mol new file mode 100644 index 0000000..836f104 --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x10756.mol @@ -0,0 +1,53 @@ + + RDKit 3D + + 23 25 0 0 0 0 0 0 0 0999 V2000 + 6.5180 0.4830 17.5430 N 0 0 0 0 0 0 0 0 0 0 0 0 + 12.0000 4.6810 22.9300 N 0 0 0 0 0 0 0 0 0 0 0 0 + 5.6360 0.5760 20.2100 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.5740 0.3590 22.5390 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.7980 2.4360 23.5330 O 0 0 0 0 0 0 0 0 0 0 0 0 + 10.9110 -0.4980 22.5650 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.9120 1.1740 19.1830 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.2660 0.7130 23.1500 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.7250 -0.0560 21.4000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.8270 -0.0880 19.8600 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.2140 -0.1090 18.5190 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.5550 3.3910 22.4830 C 0 0 2 0 0 0 0 0 0 0 0 0 + 13.2270 -0.8640 21.9900 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.9060 -1.2860 22.0030 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.5830 1.1460 23.1040 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.8830 4.1220 22.2640 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.1820 0.7030 21.6410 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.6380 -0.6520 20.8700 N 0 0 0 0 0 0 0 0 0 0 0 0 + 9.1030 1.0660 21.0750 O 0 0 0 0 0 0 0 0 0 0 0 0 + 13.2840 6.5890 22.4460 O 0 0 0 0 0 0 0 0 0 0 0 0 + 9.4530 -0.8830 22.4430 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.3850 1.1080 17.8870 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.0780 5.3820 22.5360 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7 3 1 0 + 8 6 1 0 + 10 3 2 0 + 11 10 1 0 + 11 1 2 0 + 12 5 1 1 + 12 2 1 0 + 13 4 2 0 + 14 13 1 0 + 14 6 2 0 + 15 8 2 0 + 15 5 1 0 + 15 4 1 0 + 16 12 1 0 + 17 3 1 0 + 18 10 1 0 + 18 9 1 0 + 19 9 2 0 + 21 9 1 0 + 21 6 1 0 + 22 7 2 0 + 22 1 1 0 + 23 16 1 0 + 23 2 1 0 + 23 20 2 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x10787.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x10787.mol new file mode 100644 index 0000000..8a0c3b9 --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x10787.mol @@ -0,0 +1,51 @@ + + RDKit 3D + + 22 24 0 0 0 0 0 0 0 0999 V2000 + 6.6710 0.5290 17.5810 N 0 0 0 0 0 0 0 0 0 0 0 0 + 5.5480 0.6850 20.1520 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.4600 -0.4610 22.9480 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.6330 -2.5110 24.5270 O 0 0 0 0 0 0 0 0 0 0 0 0 + 8.1150 -0.5190 24.1650 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.9500 1.3020 19.0610 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.3620 -1.1650 22.1570 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.4850 -0.1070 21.5540 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.7290 -0.0460 19.9120 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.2420 -0.0950 18.6160 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.2850 0.8680 23.8070 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.5970 -2.3040 22.9790 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.5590 -1.9220 24.0170 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.9340 0.5520 23.7770 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.1830 0.1690 23.0140 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.9890 0.8660 21.5420 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.3940 -0.6600 20.9940 N 0 0 0 0 0 0 0 0 0 0 0 0 + 9.0510 0.8780 21.0950 O 0 0 0 0 0 0 0 0 0 0 0 0 + 8.9680 -0.7690 22.8570 C 0 0 1 0 0 0 0 0 0 0 0 0 + 5.5410 1.2080 17.8140 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.7040 -0.8460 22.2060 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.8200 -1.7760 21.2500 Cl 0 0 0 0 0 0 0 0 0 0 0 0 + 6 2 1 0 + 7 3 2 0 + 9 2 2 0 + 10 9 1 0 + 10 1 2 0 + 13 12 1 0 + 13 5 1 0 + 13 4 2 0 + 14 3 1 0 + 14 11 2 0 + 15 11 1 0 + 16 2 1 0 + 17 9 1 0 + 17 8 1 0 + 18 8 2 0 + 19 8 1 6 + 19 12 1 0 + 19 5 1 0 + 19 3 1 0 + 20 6 2 0 + 20 1 1 0 + 21 15 2 0 + 21 7 1 0 + 22 21 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x10789.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x10789.mol new file mode 100644 index 0000000..cd6380b --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x10789.mol @@ -0,0 +1,55 @@ + + RDKit 3D + + 24 26 0 0 0 0 0 0 0 0999 V2000 + 6.4450 0.6200 17.2780 N 0 0 0 0 0 0 0 0 0 0 0 0 + 11.8150 4.7520 22.2420 N 0 0 0 0 0 0 0 0 0 0 0 0 + 5.4130 0.7960 19.8850 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.1310 0.5890 22.7130 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.4580 2.7430 23.5140 O 0 0 0 0 0 0 0 0 0 0 0 0 + 10.4400 -0.1620 22.6350 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.7930 1.4330 18.8130 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.8040 1.0940 23.1100 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.3810 0.1880 21.2540 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.5880 0.0630 19.6100 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.0470 -0.0020 18.2970 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.7240 3.5710 22.3730 C 0 0 2 0 0 0 0 0 0 0 0 0 + 12.7520 -0.6640 22.2750 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.4290 -1.0500 22.2290 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.1380 1.4630 23.1280 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.8040 4.5710 22.7960 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.8710 0.9490 21.2830 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.3520 -0.4680 20.6750 N 0 0 0 0 0 0 0 0 0 0 0 0 + 8.7910 1.2770 20.8660 O 0 0 0 0 0 0 0 0 0 0 0 0 + 12.9320 6.7920 21.9180 O 0 0 0 0 0 0 0 0 0 0 0 0 + 8.9820 -0.5130 22.4560 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.3390 1.3270 17.5500 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.8430 5.6200 22.2640 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.9810 -1.8050 21.8110 Cl 0 0 0 0 0 0 0 0 0 0 0 0 + 7 3 1 0 + 8 6 1 0 + 10 3 2 0 + 11 10 1 0 + 11 1 2 0 + 12 5 1 1 + 12 2 1 0 + 13 4 2 0 + 14 6 2 0 + 14 13 1 0 + 15 8 2 0 + 15 5 1 0 + 15 4 1 0 + 16 12 1 0 + 17 3 1 0 + 18 10 1 0 + 18 9 1 0 + 19 9 2 0 + 21 9 1 0 + 21 6 1 0 + 22 7 2 0 + 22 1 1 0 + 23 16 1 0 + 23 2 1 0 + 23 20 2 0 + 24 13 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x10800.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x10800.mol new file mode 100644 index 0000000..832e2de --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x10800.mol @@ -0,0 +1,53 @@ + + RDKit 3D + + 23 25 0 0 0 0 0 0 0 0999 V2000 + 6.4300 0.0840 21.0400 N 0 0 0 0 0 0 0 0 0 0 0 0 + 7.8500 -0.7620 22.5820 N 0 0 0 0 0 0 0 0 0 0 0 0 + 13.8720 -2.0390 24.8760 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.9640 0.3500 19.7400 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.9830 0.5600 25.8040 O 0 0 0 0 0 0 0 0 0 0 0 0 + 11.4290 -1.7930 23.5490 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.8000 1.0960 19.6110 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.0010 -0.8770 23.4880 C 0 0 1 0 0 0 0 0 0 0 0 0 + 8.4110 1.2820 24.6370 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.7520 0.1740 18.6060 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.3590 1.4630 17.3360 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.8570 -2.9340 25.1290 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.4690 -0.9070 23.2940 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.4860 0.5320 23.8670 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.6400 -2.8110 24.4720 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.6780 -1.0260 23.9590 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.5120 -1.5910 24.7580 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.7290 -0.0360 21.4520 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.4640 0.7130 17.4190 N 0 0 0 0 0 0 0 0 0 0 0 0 + 8.6770 0.5190 20.8880 O 0 0 0 0 0 0 0 0 0 0 0 0 + 10.1230 -1.6860 22.7980 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.5010 1.6760 18.3930 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.4720 -0.7450 25.4690 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4 1 1 0 + 7 4 2 0 + 8 2 1 0 + 9 5 1 0 + 10 4 1 0 + 12 3 2 0 + 13 6 1 0 + 14 9 1 0 + 14 8 1 0 + 15 12 1 0 + 15 6 2 0 + 16 13 2 0 + 16 3 1 0 + 17 8 1 0 + 18 1 1 0 + 18 2 1 0 + 19 11 1 0 + 19 10 2 0 + 20 18 2 0 + 8 21 1 6 + 21 6 1 0 + 22 11 2 0 + 22 7 1 0 + 23 17 1 0 + 23 5 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x10801.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x10801.mol new file mode 100644 index 0000000..762798c --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x10801.mol @@ -0,0 +1,41 @@ + + RDKit 3D + + 17 19 0 0 0 0 0 0 0 0999 V2000 + 9.1360 0.8800 20.9730 O 0 0 0 0 0 0 0 0 0 0 0 0 + 8.5270 -0.0640 21.4610 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.9770 -0.7240 22.7410 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.3260 -1.4250 22.6360 C 0 0 1 0 0 0 0 0 0 0 0 0 + 11.5900 -0.5710 22.3810 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.3020 -1.2560 23.5620 C 0 0 2 0 0 0 0 0 0 0 0 0 + 13.3370 -0.7060 24.4860 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.6580 -1.8840 23.6030 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.9490 -1.8530 23.9860 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.3840 -0.5590 20.9540 N 0 0 0 0 0 0 0 0 0 0 0 0 + 6.6470 0.0050 19.8900 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.4890 0.7520 20.1660 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.9900 0.9580 21.5740 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.0680 -0.1200 18.5650 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.4230 0.4380 17.5360 N 0 0 0 0 0 0 0 0 0 0 0 0 + 5.3180 1.1420 17.8100 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.8270 1.3250 19.0880 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 2 0 + 3 2 1 0 + 4 3 1 1 + 5 4 1 0 + 6 5 1 6 + 7 6 1 0 + 8 7 1 0 + 8 6 1 0 + 9 4 1 0 + 9 6 1 0 + 10 2 1 0 + 11 10 1 0 + 12 11 2 0 + 13 12 1 0 + 14 11 1 0 + 15 14 2 0 + 16 15 1 0 + 17 16 2 0 + 17 12 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x10812.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x10812.mol new file mode 100644 index 0000000..4b84cf9 --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x10812.mol @@ -0,0 +1,30 @@ + + RDKit 3D + + 12 13 0 0 0 0 0 0 0 0999 V2000 + 5.6700 -3.3810 23.5200 C 0 0 2 0 0 0 0 0 0 0 0 0 + 5.9110 -4.1250 22.3470 C 0 0 2 0 0 0 0 0 0 0 0 0 + 5.1970 -5.3630 22.4840 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.1530 -4.9730 19.5630 O 0 0 0 0 0 0 0 0 0 0 0 0 + 6.3090 -2.1700 23.7680 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.8250 -4.1250 24.3070 N 0 0 0 0 0 0 0 0 0 0 0 0 + 7.4850 -2.4140 21.6740 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.8150 -3.6080 21.4030 C 0 0 2 0 0 0 0 0 0 0 0 0 + 7.2300 -1.7050 22.8400 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.9670 -4.2410 20.0630 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.5560 -5.3140 23.6770 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.2240 -3.8220 18.9240 S 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 1 0 + 2 3 1 1 + 1 5 1 1 + 6 1 1 0 + 8 7 1 0 + 8 2 1 0 + 9 7 1 0 + 9 5 1 0 + 8 10 1 6 + 10 4 1 0 + 11 6 1 0 + 11 3 1 0 + 10 12 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x10820.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x10820.mol new file mode 100644 index 0000000..dbfd630 --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x10820.mol @@ -0,0 +1,62 @@ + + RDKit 3D + + 27 30 0 0 0 0 0 0 0 0999 V2000 + 13.5360 -0.7640 21.8790 S 0 0 0 0 0 0 0 0 0 0 0 0 + 8.7350 -4.9280 26.0030 N 0 0 0 0 0 0 0 0 0 0 0 0 + 7.4980 -0.4620 18.8090 N 0 0 0 0 0 0 0 0 0 0 0 0 + 7.0250 -0.4060 20.0790 N 0 0 0 0 0 0 0 0 0 0 0 0 + 8.8450 -3.7540 25.2790 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.8750 -0.5330 22.1610 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.1080 0.8340 21.1700 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.6220 0.3890 23.1390 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.9830 -2.6790 25.5070 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.7770 -3.6710 24.2520 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.8370 2.0760 19.5230 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.8480 -2.5380 23.4610 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.0130 -1.4500 23.7040 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.9410 0.4090 23.0960 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.8160 -0.9750 21.1470 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.0470 1.6690 20.8400 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.8220 0.9320 23.6730 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.7200 0.0780 21.7790 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.9440 0.4180 20.1400 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.7590 0.8360 18.8260 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.6900 -5.1960 26.9660 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.2440 -0.2180 23.0050 N 0 0 0 0 0 0 0 0 0 0 0 0 + 8.9750 1.1160 21.1830 O 0 0 0 0 0 0 0 0 0 0 0 0 + 10.2130 0.7140 23.5690 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.0650 -1.5370 24.7240 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.6950 1.6740 18.5060 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.7450 0.2770 18.0450 N 0 0 0 0 0 0 0 0 0 0 0 0 + 4 3 1 0 + 5 2 1 0 + 6 1 1 0 + 8 6 2 0 + 9 5 2 0 + 10 5 1 0 + 12 10 2 0 + 13 12 1 0 + 14 1 1 0 + 15 4 1 0 + 16 11 2 0 + 16 7 1 0 + 17 14 2 0 + 17 8 1 0 + 18 15 1 0 + 19 7 2 0 + 19 4 1 0 + 20 19 1 0 + 21 2 1 0 + 22 18 1 0 + 22 13 1 0 + 23 18 2 0 + 24 22 1 0 + 24 8 1 0 + 25 13 2 0 + 25 9 1 0 + 26 11 1 0 + 26 20 2 0 + 27 20 1 0 + 27 3 2 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x10834.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x10834.mol new file mode 100644 index 0000000..ad3d200 --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x10834.mol @@ -0,0 +1,46 @@ + + RDKit 3D + + 20 21 0 0 0 0 0 0 0 0999 V2000 + 6.5030 0.5050 17.2760 N 0 0 0 0 0 0 0 0 0 0 0 0 + 5.5530 0.6780 19.8750 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.0460 0.0700 23.1950 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.8290 1.1040 21.0650 O 0 0 0 0 0 0 0 0 0 0 0 0 + 10.3150 -0.4750 22.9700 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.8770 1.3180 18.8470 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.3400 0.0340 21.4190 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.7180 -0.0660 19.6030 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.1360 -0.1150 18.2770 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.1300 0.7400 23.9920 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.2330 -1.1720 22.1930 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.7760 0.4590 23.8880 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.5800 -0.8990 22.3290 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.0230 1.4550 21.5500 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.3950 -0.6260 20.7090 N 0 0 0 0 0 0 0 0 0 0 0 0 + 5.2050 0.7330 21.1980 O 0 0 0 0 0 0 0 0 0 0 0 0 + 8.3110 -1.9370 22.8910 O 0 0 0 0 0 0 0 0 0 0 0 0 + 8.8300 -0.6260 22.7060 C 0 0 1 0 0 0 0 0 0 0 0 0 + 13.8290 -1.9700 21.3830 Br 0 0 0 0 0 0 0 0 0 0 0 0 + 5.3990 1.2010 17.5740 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6 2 1 0 + 7 4 2 0 + 8 2 2 0 + 9 8 1 0 + 9 1 2 0 + 10 3 2 0 + 11 5 1 0 + 12 5 2 0 + 12 10 1 0 + 13 11 2 0 + 13 3 1 0 + 15 8 1 0 + 15 7 1 0 + 16 14 1 0 + 16 2 1 0 + 18 7 1 0 + 18 17 1 6 + 18 5 1 0 + 19 13 1 0 + 20 6 2 0 + 20 1 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x10856.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x10856.mol new file mode 100644 index 0000000..764ff58 --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x10856.mol @@ -0,0 +1,48 @@ + + RDKit 3D + + 21 22 0 0 0 0 0 0 0 0999 V2000 + 7.6940 -3.0690 23.4740 N 0 0 0 0 0 0 0 0 0 0 0 0 + 6.5220 0.6710 17.4690 N 0 0 0 0 0 0 0 0 0 0 0 0 + 5.3500 1.1980 17.8420 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.1380 -0.4200 23.8140 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.0840 -2.1690 21.5870 O 0 0 0 0 0 0 0 0 0 0 0 0 + 7.2310 -1.7420 21.5030 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.1470 0.3830 24.3360 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.4170 -1.3790 22.8350 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.7320 -1.5050 22.3850 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.7290 -0.7260 22.9410 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.7000 0.6840 20.1590 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.2870 0.1340 18.4260 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.9260 0.0870 19.7740 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.9050 1.2220 19.1500 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.3580 0.9570 21.6030 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.4240 0.7730 24.9930 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.6390 -0.8240 20.6000 N 0 0 0 0 0 0 0 0 0 0 0 0 + 7.8260 -0.3430 24.1990 O 0 0 0 0 0 0 0 0 0 0 0 0 + 8.3450 -2.3580 22.3650 C 0 0 1 0 0 0 0 0 0 0 0 0 + 13.5460 -1.0850 22.4900 Br 0 0 0 0 0 0 0 0 0 0 0 0 + 11.4500 0.2260 23.8970 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3 2 2 0 + 6 5 2 0 + 7 4 2 0 + 8 4 1 0 + 9 8 2 0 + 10 9 1 0 + 12 2 1 0 + 13 12 2 0 + 13 11 1 0 + 14 3 1 0 + 14 11 2 0 + 15 11 1 0 + 17 13 1 0 + 17 6 1 0 + 18 16 1 0 + 18 4 1 0 + 19 6 1 0 + 19 8 1 0 + 19 1 1 1 + 20 10 1 0 + 21 7 1 0 + 21 10 2 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x10862.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x10862.mol new file mode 100644 index 0000000..9372a88 --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x10862.mol @@ -0,0 +1,59 @@ + + RDKit 3D + + 26 28 0 0 0 0 0 0 0 0999 V2000 + 8.3370 -0.2310 21.9250 N 0 0 0 0 0 0 0 0 0 0 0 0 + 4.7370 -0.1050 21.5500 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.5900 -0.2400 24.3810 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.1870 -0.4840 22.4640 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.1840 1.6000 20.6280 O 0 0 0 0 0 0 0 0 0 0 0 0 + 3.4680 2.1670 20.5260 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.9230 0.4570 23.0710 C 0 0 1 0 0 0 0 0 0 0 0 0 + 6.0360 1.0180 18.2290 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.2010 0.8330 22.6760 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.0700 -0.1080 19.2560 C 0 0 1 0 0 0 0 0 0 0 0 0 + 7.4960 -0.4870 19.6760 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.7290 0.5400 22.2290 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.4290 0.5770 22.9510 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.5560 -0.3360 22.3250 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.0810 1.6530 21.7520 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.3380 0.0290 23.4280 F 0 0 0 0 0 0 0 0 0 0 0 0 + 5.1120 0.3920 20.3050 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.0690 1.7600 23.2960 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.5620 -1.4330 24.5370 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.0720 1.8940 18.6010 N 0 0 0 0 0 0 0 0 0 0 0 0 + 7.2030 -0.1710 24.6400 O 0 0 0 0 0 0 0 0 0 0 0 0 + 6.7850 1.1360 17.2660 O 0 0 0 0 0 0 0 0 0 0 0 0 + 4.4890 1.5390 19.8170 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.0260 0.3930 20.7860 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.5690 -1.7540 21.5680 Br 0 0 0 0 0 0 0 0 0 0 0 0 + 12.4420 1.8900 23.1570 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7 3 1 1 + 7 1 1 0 + 10 8 1 0 + 10 11 1 1 + 12 2 2 0 + 13 7 1 0 + 13 4 2 0 + 14 9 2 0 + 14 4 1 0 + 15 6 2 0 + 15 12 1 0 + 16 12 1 0 + 17 2 1 0 + 17 10 1 0 + 18 13 1 0 + 20 8 1 0 + 21 19 1 0 + 21 3 1 0 + 22 8 2 0 + 23 20 1 0 + 23 17 2 0 + 23 6 1 0 + 24 11 1 0 + 24 5 2 0 + 24 1 1 0 + 25 14 1 0 + 26 18 2 0 + 26 9 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x10870.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x10870.mol new file mode 100644 index 0000000..4c1d387 --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x10870.mol @@ -0,0 +1,71 @@ + + RDKit 3D + + 31 35 0 0 0 0 0 0 0 0999 V2000 + 13.5210 -1.9810 24.8020 S 0 0 0 0 0 0 0 0 0 0 0 0 + 7.2240 -0.1730 19.8320 N 0 0 0 0 0 0 0 0 0 0 0 0 + 9.5600 -0.2980 22.6840 N 0 0 0 0 0 0 0 0 0 0 0 0 + 6.5890 0.4560 17.8610 N 0 0 0 0 0 0 0 0 0 0 0 0 + 8.0760 -0.8520 20.7870 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.7350 -1.8680 23.1050 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.3230 -5.9050 27.3270 C 0 0 1 0 0 0 0 0 0 0 0 0 + 6.6260 -3.5510 27.6420 O 0 0 0 0 0 0 0 0 0 0 0 0 + 10.7230 0.4170 23.1970 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.6910 0.9490 18.7790 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.3620 0.8710 21.1860 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.1310 -3.4500 25.1050 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.2090 1.6290 21.0210 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.8060 2.0510 19.7560 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.7940 -1.0310 22.5480 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.0380 -1.3800 23.4670 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.9140 -6.2040 26.8850 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.8830 -4.5500 26.9750 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.4520 -2.6920 23.2400 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.8950 -0.4820 23.5050 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.1870 -0.9130 24.7680 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.1890 -5.9470 28.3170 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.1660 -1.1140 24.5200 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.0240 0.1160 21.4960 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.5000 -0.2160 18.5030 N 0 0 0 0 0 0 0 0 0 0 0 0 + 9.2870 1.2040 21.0030 O 0 0 0 0 0 0 0 0 0 0 0 0 + 6.0870 0.5430 20.0490 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.5410 1.7200 18.6250 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.7180 -2.1390 25.3340 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.0040 -3.7160 24.0550 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.6880 -4.5460 25.8850 N 0 0 0 0 0 0 0 0 0 0 0 0 + 5 2 1 0 + 6 1 1 0 + 9 3 1 0 + 10 4 1 0 + 13 11 2 0 + 14 13 1 0 + 15 6 2 0 + 16 3 1 0 + 17 7 1 0 + 7 18 1 6 + 18 8 2 0 + 19 16 2 0 + 20 9 1 0 + 20 15 1 0 + 21 20 2 0 + 21 1 1 0 + 22 17 1 0 + 22 7 1 0 + 23 16 1 0 + 24 5 1 0 + 24 3 1 0 + 25 4 2 0 + 25 2 1 0 + 26 24 2 0 + 27 11 1 0 + 27 10 2 0 + 27 2 1 0 + 28 14 2 0 + 28 10 1 0 + 29 23 2 0 + 29 12 1 0 + 30 19 1 0 + 30 12 2 0 + 31 18 1 0 + 31 12 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x10871.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x10871.mol new file mode 100644 index 0000000..c988515 --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x10871.mol @@ -0,0 +1,68 @@ + + RDKit 3D + + 30 33 0 0 0 0 0 0 0 0999 V2000 + 13.5130 -1.7140 22.7350 S 0 0 0 0 0 0 0 0 0 0 0 0 + 8.5080 -4.2010 26.2080 N 0 0 0 0 0 0 0 0 0 0 0 0 + 7.4480 -0.2190 18.4950 N 0 0 0 0 0 0 0 0 0 0 0 0 + 7.0890 -0.0820 19.7970 N 0 0 0 0 0 0 0 0 0 0 0 0 + 8.1140 -5.6360 28.0760 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.5480 -0.1130 24.4700 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.6820 2.1100 19.3490 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.0050 1.4850 20.9620 O 0 0 0 0 0 0 0 0 0 0 0 0 + 8.0270 -1.8480 25.5730 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.8420 -4.3290 27.3810 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.6380 0.9760 18.5760 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.9530 -1.0230 23.5070 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.3790 -2.3110 23.1970 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.1520 -3.3510 24.0770 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.1950 -0.7370 22.2780 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.7620 0.0590 23.2970 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.1450 1.0410 20.9570 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.5000 1.7230 18.2940 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.5020 0.8770 23.1670 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.5420 -1.0510 24.3240 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.0000 1.7730 20.6650 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.8030 0.4120 21.5040 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.8890 -6.2170 28.7460 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.3680 0.0840 22.7040 N 0 0 0 0 0 0 0 0 0 0 0 0 + 7.0820 -3.4830 27.8460 O 0 0 0 0 0 0 0 0 0 0 0 0 + 8.2400 -0.8060 24.6850 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.5120 -3.1220 25.2890 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.9120 -0.6450 20.8480 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.9460 0.6500 19.8930 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.5890 0.4160 17.7520 N 0 0 0 0 0 0 0 0 0 0 0 0 + 4 3 1 0 + 10 5 1 0 + 10 2 1 0 + 13 12 2 0 + 14 13 1 0 + 15 1 1 0 + 16 15 2 0 + 16 6 1 0 + 18 7 1 0 + 18 11 2 0 + 19 16 1 0 + 20 6 2 0 + 20 1 1 0 + 21 17 1 0 + 21 7 2 0 + 22 8 2 0 + 23 5 1 0 + 24 22 1 0 + 24 19 1 0 + 24 12 1 0 + 25 10 2 0 + 26 12 1 0 + 26 9 2 0 + 27 14 2 0 + 27 9 1 0 + 27 2 1 0 + 28 22 1 0 + 28 4 1 0 + 29 17 2 0 + 29 11 1 0 + 29 4 1 0 + 30 11 1 0 + 30 3 2 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x10876.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x10876.mol new file mode 100644 index 0000000..5d65ab3 --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x10876.mol @@ -0,0 +1,64 @@ + + RDKit 3D + + 28 31 0 0 0 0 0 0 0 0999 V2000 + 9.0340 1.4370 20.9780 O 0 0 0 0 0 0 0 0 0 0 0 0 + 8.8100 0.3950 21.5740 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.2090 0.1950 22.8660 N 0 0 0 0 0 0 0 0 0 0 0 0 + 9.6220 1.3740 23.6210 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.0910 1.6710 23.4570 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.6600 2.9080 23.0350 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.0320 2.8560 22.9120 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.6200 1.2940 23.3250 S 0 0 0 0 0 0 0 0 0 0 0 0 + 12.0460 0.7170 23.6510 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.0950 -1.0460 23.5590 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.8250 -1.0800 24.9220 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.7540 -2.2880 25.5950 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.4960 -2.2170 22.9310 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.4540 -3.4250 23.6030 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.0770 -3.4850 24.9500 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.0640 -4.6820 25.6270 N 0 0 0 0 0 0 0 0 0 0 0 0 + 8.1360 -4.9060 26.7260 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.4350 -5.9090 24.9480 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.9750 -0.7060 20.9150 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.1080 -0.1660 19.8880 N 0 0 0 0 0 0 0 0 0 0 0 0 + 5.9580 0.5510 20.0150 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.1880 0.9420 21.1000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.0520 1.6960 20.8400 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.7100 2.0540 19.5380 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.4940 1.6630 18.4600 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.6270 0.8960 18.7090 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.5740 0.3710 17.8620 N 0 0 0 0 0 0 0 0 0 0 0 0 + 7.4510 -0.2680 18.5790 N 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 2 0 + 3 2 1 0 + 4 3 1 0 + 5 4 1 0 + 6 5 1 0 + 7 6 2 0 + 8 7 1 0 + 9 8 1 0 + 9 5 2 0 + 10 3 1 0 + 11 10 2 0 + 12 11 1 0 + 13 10 1 0 + 14 13 2 0 + 15 14 1 0 + 15 12 2 0 + 16 15 1 0 + 17 16 1 0 + 18 16 1 0 + 19 2 1 0 + 20 19 1 0 + 21 20 1 0 + 22 21 2 0 + 23 22 1 0 + 24 23 2 0 + 25 24 1 0 + 26 25 2 0 + 26 21 1 0 + 27 26 1 0 + 28 27 2 0 + 28 20 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x10888.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x10888.mol new file mode 100644 index 0000000..6d6c615 --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x10888.mol @@ -0,0 +1,48 @@ + + RDKit 3D + + 21 22 0 0 0 0 0 0 0 0999 V2000 + 13.9260 -1.7790 21.4810 Cl 0 0 0 0 0 0 0 0 0 0 0 0 + 12.8250 -0.6710 22.2460 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.3110 0.5160 22.7580 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.4170 1.4060 23.3340 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.0690 1.0960 23.4030 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.4840 -0.9950 22.3040 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.5860 -0.1050 22.8870 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.0870 -0.4080 22.8990 C 0 0 1 0 0 0 0 0 0 0 0 0 + 8.8970 -1.8200 22.8740 O 0 0 0 0 0 0 0 0 0 0 0 0 + 8.4100 0.1600 24.1650 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.9790 -0.3120 24.3830 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.4650 0.2490 21.6230 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.9020 1.3150 21.2210 O 0 0 0 0 0 0 0 0 0 0 0 0 + 7.4220 -0.3860 21.0410 N 0 0 0 0 0 0 0 0 0 0 0 0 + 6.6710 0.1280 19.9570 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.5360 0.9240 20.2120 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.0270 1.1660 21.6100 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.9030 1.5060 19.1190 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.4010 1.2940 17.8500 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.4650 0.5260 17.5930 N 0 0 0 0 0 0 0 0 0 0 0 0 + 7.0740 -0.0490 18.6340 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 1 0 + 3 2 2 0 + 4 3 1 0 + 5 4 2 0 + 6 2 1 0 + 7 6 2 0 + 7 5 1 0 + 8 7 1 0 + 8 9 1 6 + 10 8 1 0 + 11 10 1 0 + 12 8 1 0 + 13 12 2 0 + 14 12 1 0 + 15 14 1 0 + 16 15 2 0 + 17 16 1 0 + 18 16 1 0 + 19 18 2 0 + 20 19 1 0 + 21 20 2 0 + 21 15 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x10889.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x10889.mol new file mode 100644 index 0000000..011b6ba --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x10889.mol @@ -0,0 +1,52 @@ + + RDKit 3D + + 23 24 0 0 0 0 0 0 0 0999 V2000 + 6.6280 -5.3320 21.8720 S 0 0 2 0 0 0 0 0 0 0 0 0 + 7.5340 -4.0120 22.1040 N 0 0 0 0 0 0 0 0 0 0 0 0 + 6.6990 0.5490 17.6000 N 0 0 0 0 0 0 0 0 0 0 0 0 + 7.7620 -3.5060 23.4660 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.9190 -1.2850 21.9740 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.2390 -5.3320 20.4940 O 0 0 0 0 0 0 0 0 0 0 0 0 + 5.5810 1.0690 18.1250 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.0520 -2.7100 23.6470 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.2090 0.4590 20.3380 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.3740 -0.0990 19.8210 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.3900 -0.9370 21.9580 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.7640 -1.0820 22.7240 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.0640 0.4290 23.2040 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.5690 -0.0250 18.4410 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.0600 -0.5330 22.2100 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.9280 0.6320 23.9650 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.1870 -5.1610 22.8520 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.3530 -0.7520 20.6140 N 0 0 0 0 0 0 0 0 0 0 0 0 + 7.3780 -6.4410 22.3750 O 0 0 0 0 0 0 0 0 0 0 0 0 + 7.6010 -0.4100 22.7410 O 0 0 0 0 0 0 0 0 0 0 0 0 + 5.2950 1.0490 19.4790 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.4990 -1.8780 22.4330 C 0 0 1 0 0 0 0 0 0 0 0 0 + 10.7860 -0.1220 23.7290 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 1 0 + 4 2 1 0 + 6 1 2 0 + 7 3 2 0 + 8 4 1 0 + 10 9 1 0 + 12 5 2 0 + 14 10 2 0 + 14 3 1 0 + 15 13 2 0 + 15 5 1 0 + 16 13 1 0 + 1 17 1 1 + 18 10 1 0 + 18 11 1 0 + 19 1 2 0 + 20 11 2 0 + 21 9 2 0 + 21 7 1 0 + 22 12 1 0 + 22 11 1 0 + 22 8 1 1 + 23 12 1 0 + 23 16 2 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x10898.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x10898.mol new file mode 100644 index 0000000..080f7ab --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x10898.mol @@ -0,0 +1,52 @@ + + RDKit 3D + + 22 25 0 0 0 0 0 0 0 0999 V2000 + 5.5300 0.5620 19.2650 N 0 0 0 0 0 0 0 0 0 0 0 0 + 7.1740 -0.1150 20.8190 N 0 0 0 0 0 0 0 0 0 0 0 0 + 6.6980 0.4960 17.4070 N 0 0 0 0 0 0 0 0 0 0 0 0 + 4.7870 2.0770 21.1570 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.8050 0.0100 23.4400 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.1420 0.9090 20.9720 O 0 0 0 0 0 0 0 0 0 0 0 0 + 6.8210 0.3310 19.5790 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.8390 0.6070 24.2300 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.6280 -0.7320 22.6700 C 0 0 2 0 0 0 0 0 0 0 0 0 + 7.7360 -0.2020 23.8140 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.2560 1.1280 24.2920 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.4930 0.9380 20.2440 C 0 0 1 0 0 0 0 0 0 0 0 0 + 10.1000 -0.5330 22.9770 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.5070 0.6580 17.9060 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.7730 2.2300 20.0690 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.0880 -1.1490 22.2120 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.4170 -0.8620 22.4470 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.5530 0.2880 18.4760 N 0 0 0 0 0 0 0 0 0 0 0 0 + 9.6060 1.0230 24.7890 O 0 0 0 0 0 0 0 0 0 0 0 0 + 8.4030 0.0070 21.3490 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.4970 0.3460 23.9890 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.6320 -1.6250 21.4600 Cl 0 0 0 0 0 0 0 0 0 0 0 0 + 7 2 1 0 + 7 1 1 0 + 8 5 2 0 + 10 9 1 0 + 11 10 1 0 + 12 4 1 0 + 12 1 1 6 + 13 9 1 0 + 14 3 2 0 + 14 1 1 0 + 15 12 1 0 + 15 4 1 0 + 16 13 1 0 + 17 16 2 0 + 17 5 1 0 + 18 7 2 0 + 18 3 1 0 + 19 11 1 0 + 20 6 2 0 + 20 2 1 0 + 9 20 1 6 + 21 19 1 0 + 21 13 2 0 + 21 8 1 0 + 22 17 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x10899.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x10899.mol new file mode 100644 index 0000000..62d81eb --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x10899.mol @@ -0,0 +1,59 @@ + + RDKit 3D + + 26 28 0 0 0 0 0 0 0 0999 V2000 + 6.9120 0.8160 24.9010 O 0 0 0 0 0 0 0 0 0 0 0 0 + 5.5890 0.8420 25.4470 S 0 0 0 0 0 0 0 0 0 0 0 0 + 5.3900 1.2550 26.8020 O 0 0 0 0 0 0 0 0 0 0 0 0 + 4.7190 1.8350 24.5200 N 0 0 0 0 0 0 0 0 0 0 0 0 + 3.2910 1.9940 24.8080 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2.6620 3.0950 23.9880 C 0 0 0 0 0 0 0 0 0 0 0 0 + 1.1860 3.2360 24.2740 C 0 0 0 0 0 0 0 0 0 0 0 0 + 0.2520 2.4750 23.5810 C 0 0 0 0 0 0 0 0 0 0 0 0 + -1.1020 2.5740 23.8720 C 0 0 0 0 0 0 0 0 0 0 0 0 + -1.5380 3.4410 24.8550 C 0 0 0 0 0 0 0 0 0 0 0 0 + -0.6220 4.2130 25.5430 C 0 0 0 0 0 0 0 0 0 0 0 0 + 0.7320 4.1100 25.2550 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.9060 -0.7850 25.2640 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.2050 -1.3010 26.3480 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.5960 -2.5460 26.2550 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.6900 -3.2950 25.0910 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.4100 -2.7810 24.0180 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.0240 -1.5230 24.0740 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.7040 -1.1330 22.9280 N 0 0 0 0 0 0 0 0 0 0 0 0 + 4.7130 -3.5090 22.4620 S 0 0 0 0 0 0 0 0 0 0 0 0 + 5.6120 -2.0700 22.0250 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.2050 -1.8730 20.7930 N 0 0 0 0 0 0 0 0 0 0 0 0 + 6.1840 -2.7590 19.7470 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.5750 -3.8260 19.7560 O 0 0 0 0 0 0 0 0 0 0 0 0 + 6.9980 -2.3290 18.5480 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.3590 -3.4390 18.8060 S 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 1 0 + 3 2 1 0 + 4 2 1 0 + 5 4 1 0 + 6 5 1 0 + 7 6 1 0 + 8 7 1 0 + 9 8 1 0 + 10 9 1 0 + 11 10 1 0 + 12 11 1 0 + 12 7 1 0 + 13 2 1 0 + 14 13 1 0 + 15 14 1 0 + 16 15 1 0 + 17 16 1 0 + 18 17 1 0 + 18 13 1 0 + 19 18 1 0 + 20 17 1 0 + 21 20 1 0 + 21 19 1 0 + 22 21 1 0 + 23 22 1 0 + 24 23 1 0 + 25 23 1 0 + 25 26 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x10900.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x10900.mol new file mode 100644 index 0000000..e252243 --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x10900.mol @@ -0,0 +1,44 @@ + + RDKit 3D + + 19 20 0 0 0 0 0 0 0 0999 V2000 + 7.4080 -0.5430 20.8980 N 0 0 0 0 0 0 0 0 0 0 0 0 + 12.3200 0.8110 23.7810 N 0 0 0 0 0 0 0 0 0 0 0 0 + 9.0490 -0.8020 22.6750 C 0 0 1 0 0 0 0 0 0 0 0 0 + 13.2060 0.1380 23.0350 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.0360 1.0320 21.5110 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.5030 -0.0150 21.4810 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.8590 1.3560 19.0210 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.3850 1.2180 17.7530 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.1620 0.0000 18.5200 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.0250 0.4820 23.6650 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.4730 -1.2120 22.0730 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.5380 -0.5080 22.8210 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.8090 -0.8870 22.1810 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.2450 -0.5470 23.9510 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.5260 0.5690 17.4910 N 0 0 0 0 0 0 0 0 0 0 0 0 + 9.0380 1.0120 21.0860 O 0 0 0 0 0 0 0 0 0 0 0 0 + 5.5200 0.7870 20.1050 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.7040 0.0680 19.8360 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.9800 -1.7870 21.2550 Cl 0 0 0 0 0 0 0 0 0 0 0 0 + 4 2 2 0 + 6 1 1 0 + 6 3 1 0 + 8 7 2 0 + 10 2 1 0 + 12 3 1 0 + 12 11 1 0 + 12 10 2 0 + 13 11 2 0 + 13 4 1 0 + 3 14 1 1 + 15 8 1 0 + 15 9 2 0 + 16 6 2 0 + 17 7 1 0 + 17 5 1 0 + 18 17 2 0 + 18 9 1 0 + 18 1 1 0 + 19 13 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x10906.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x10906.mol new file mode 100644 index 0000000..0b9c19f --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x10906.mol @@ -0,0 +1,52 @@ + + RDKit 3D + + 22 25 0 0 0 0 0 0 0 0999 V2000 + 8.4550 0.9300 21.0760 O 0 0 0 0 0 0 0 0 0 0 0 0 + 8.1270 -0.2550 21.1120 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.6500 -1.2150 22.1800 C 0 0 1 0 0 0 0 0 0 0 0 0 + 10.1360 -1.5560 21.9360 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.0310 -0.7380 22.8330 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.6550 -0.8790 24.2130 O 0 0 0 0 0 0 0 0 0 0 0 0 + 8.3470 -0.5950 23.5290 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.3660 -0.4880 24.4760 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.1400 0.0800 25.7190 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.8910 0.5920 26.0200 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.0890 -0.0780 23.8500 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.8880 0.5190 25.0790 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.3330 1.2260 25.4370 Cl 0 0 0 0 0 0 0 0 0 0 0 0 + 7.4510 -0.8480 20.0980 N 0 0 0 0 0 0 0 0 0 0 0 0 + 6.6890 -0.3900 19.0750 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.7370 0.5940 19.2350 N 0 0 0 0 0 0 0 0 0 0 0 0 + 5.4560 1.0160 17.9670 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.1430 0.3500 17.0890 N 0 0 0 0 0 0 0 0 0 0 0 0 + 6.9220 -0.5640 17.7860 N 0 0 0 0 0 0 0 0 0 0 0 0 + 5.0750 1.0040 20.4950 C 0 0 2 0 0 0 0 0 0 0 0 0 + 3.8370 1.8270 20.4080 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.1150 2.4390 20.8880 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 2 0 + 3 2 1 6 + 4 3 1 0 + 5 4 1 0 + 6 5 1 0 + 7 3 1 0 + 8 7 2 0 + 8 6 1 0 + 9 8 1 0 + 10 9 2 0 + 11 7 1 0 + 12 11 2 0 + 12 10 1 0 + 13 12 1 0 + 14 2 1 0 + 15 14 1 0 + 16 15 1 0 + 17 16 1 0 + 18 17 2 0 + 19 18 1 0 + 19 15 2 0 + 20 16 1 6 + 21 20 1 0 + 22 21 1 0 + 22 20 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x10942.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x10942.mol new file mode 100644 index 0000000..e0f1f41 --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x10942.mol @@ -0,0 +1,51 @@ + + RDKit 3D + + 22 24 0 0 0 0 0 0 0 0999 V2000 + 6.3990 0.5040 17.6290 N 0 0 0 0 0 0 0 0 0 0 0 0 + 5.5510 0.8090 20.2770 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.3650 0.6160 24.0110 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.2400 1.0830 21.2960 O 0 0 0 0 0 0 0 0 0 0 0 0 + 8.2180 -0.1450 24.0780 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.8610 1.4000 19.2280 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.6170 0.0830 21.6330 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.7030 0.0710 19.9700 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.0450 -0.0920 18.6310 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.0080 0.3250 23.9630 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.7250 -0.9130 22.2230 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.8510 1.1510 24.5170 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.2260 0.0050 23.1180 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.3820 -1.2230 22.1750 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.9980 0.8740 21.6790 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.6140 -0.4150 20.9070 N 0 0 0 0 0 0 0 0 0 0 0 0 + 5.6970 1.8000 22.4950 O 0 0 0 0 0 0 0 0 0 0 0 0 + 10.2290 0.9600 24.9000 O 0 0 0 0 0 0 0 0 0 0 0 0 + 8.9880 -0.7300 22.8740 C 0 0 1 0 0 0 0 0 0 0 0 0 + 5.3290 1.2410 17.9390 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.4900 -0.5760 23.0290 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.8160 -1.7150 21.1260 Cl 0 0 0 0 0 0 0 0 0 0 0 0 + 6 2 1 0 + 7 4 2 0 + 8 2 2 0 + 9 8 1 0 + 9 1 2 0 + 10 3 2 0 + 12 5 1 0 + 13 11 2 0 + 13 3 1 0 + 14 11 1 0 + 15 2 1 0 + 16 8 1 0 + 16 7 1 0 + 17 15 1 0 + 18 12 1 0 + 18 10 1 0 + 19 7 1 6 + 19 5 1 0 + 20 6 2 0 + 20 1 1 0 + 21 19 1 0 + 21 14 2 0 + 21 10 1 0 + 22 11 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x10959.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x10959.mol new file mode 100644 index 0000000..a85a411 --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x10959.mol @@ -0,0 +1,49 @@ + + RDKit 3D + + 21 23 0 0 0 0 0 0 0 0999 V2000 + 8.8320 0.7700 21.0150 O 0 0 0 0 0 0 0 0 0 0 0 0 + 8.3040 -0.3070 21.2970 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.7970 -1.1710 22.4420 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.2370 -0.8740 22.7830 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.5700 0.0940 23.7260 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.8910 0.4830 23.9060 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.8990 -0.0960 23.1450 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.2520 -1.4840 22.0580 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.5560 -1.0780 22.2330 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.8010 -1.8260 21.2690 Cl 0 0 0 0 0 0 0 0 0 0 0 0 + 7.1980 -0.7710 20.6870 N 0 0 0 0 0 0 0 0 0 0 0 0 + 6.4650 -0.1290 19.6710 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.3490 0.6880 20.0260 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.8640 0.8390 21.3530 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.7610 1.6070 21.6180 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.1040 2.2770 20.5950 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.5510 2.1870 19.3050 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.6820 1.3900 18.9870 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.1920 1.2550 17.6750 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.2400 0.5020 17.3540 N 0 0 0 0 0 0 0 0 0 0 0 0 + 6.8450 -0.1720 18.3360 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 2 0 + 3 2 1 0 + 4 3 1 0 + 5 4 2 0 + 6 5 1 0 + 7 6 2 0 + 8 4 1 0 + 9 8 2 0 + 9 7 1 0 + 10 9 1 0 + 11 2 1 0 + 12 11 1 0 + 13 12 1 0 + 14 13 2 0 + 15 14 1 0 + 16 15 2 0 + 17 16 1 0 + 18 17 2 0 + 18 13 1 0 + 19 18 1 0 + 20 19 2 0 + 21 20 1 0 + 21 12 2 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x10976.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x10976.mol new file mode 100644 index 0000000..cf3ac88 --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x10976.mol @@ -0,0 +1,42 @@ + + RDKit 3D + + 18 19 0 0 0 0 0 0 0 0999 V2000 + 13.7920 -1.7850 21.2310 Cl 0 0 0 0 0 0 0 0 0 0 0 0 + 12.5780 -1.0370 22.2290 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.9600 -0.1340 23.1970 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.9840 0.4050 24.0210 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.6500 0.0720 23.8360 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.2570 -1.3860 22.0410 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.2730 -0.8140 22.8360 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.8160 -1.0990 22.5540 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.3650 -0.2930 21.3540 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.9460 0.7310 21.0110 O 0 0 0 0 0 0 0 0 0 0 0 0 + 7.2690 -0.7650 20.7330 N 0 0 0 0 0 0 0 0 0 0 0 0 + 6.5460 -0.1030 19.7190 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.9350 -0.1340 18.3850 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.3060 0.5460 17.4230 N 0 0 0 0 0 0 0 0 0 0 0 0 + 5.2540 1.2960 17.7800 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.4520 0.6860 20.0560 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.7880 1.4150 19.0830 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.6170 2.3040 19.4310 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 1 0 + 3 2 2 0 + 4 3 1 0 + 5 4 2 0 + 6 2 1 0 + 7 5 1 0 + 7 6 2 0 + 8 7 1 0 + 9 8 1 0 + 10 9 2 0 + 11 9 1 0 + 12 11 1 0 + 13 12 2 0 + 14 13 1 0 + 15 14 2 0 + 16 12 1 0 + 17 15 1 0 + 17 16 2 0 + 18 17 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x10995.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x10995.mol new file mode 100644 index 0000000..af2e31e --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x10995.mol @@ -0,0 +1,50 @@ + + RDKit 3D + + 22 23 0 0 0 0 0 0 0 0999 V2000 + 14.3590 -0.2740 22.8130 F 0 0 0 0 0 0 0 0 0 0 0 0 + 13.4650 -1.2520 22.8290 C 0 0 2 0 0 0 0 0 0 0 0 0 + 13.9720 -2.2740 23.5200 F 0 0 0 0 0 0 0 0 0 0 0 0 + 13.3670 -1.6490 21.5570 F 0 0 0 0 0 0 0 0 0 0 0 0 + 12.1490 -0.7880 23.3930 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.0820 0.0920 24.4630 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.8320 0.4640 24.9260 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.6980 -0.0440 24.3120 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.0640 -1.2930 22.7860 N 0 0 0 0 0 0 0 0 0 0 0 0 + 9.8560 -0.9190 23.2410 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.6760 -1.4610 22.4720 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.2600 -0.4960 21.3800 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.9210 0.5050 21.1150 O 0 0 0 0 0 0 0 0 0 0 0 0 + 7.1030 -0.8130 20.7670 N 0 0 0 0 0 0 0 0 0 0 0 0 + 6.4950 -0.0750 19.7290 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.3520 0.6920 19.9970 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.7980 0.8450 21.3960 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.4430 2.2700 21.7660 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.0000 -0.0880 18.4320 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.4400 0.5810 17.4200 N 0 0 0 0 0 0 0 0 0 0 0 0 + 5.3340 1.2870 17.6840 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.7630 1.3730 18.9360 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 1 6 + 3 2 1 0 + 4 2 1 0 + 5 2 1 0 + 6 5 2 0 + 7 6 1 0 + 8 7 2 0 + 9 5 1 0 + 10 8 1 0 + 10 9 2 0 + 11 10 1 0 + 12 11 1 0 + 13 12 2 0 + 14 12 1 0 + 15 14 1 0 + 16 15 2 0 + 17 16 1 0 + 18 17 1 0 + 19 15 1 0 + 20 19 2 0 + 21 20 1 0 + 22 21 2 0 + 22 16 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x10996.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x10996.mol new file mode 100644 index 0000000..2154e64 --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x10996.mol @@ -0,0 +1,40 @@ + + RDKit 3D + + 17 18 0 0 0 0 0 0 0 0999 V2000 + 5.3010 1.3240 17.9310 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.0550 -1.0240 22.3790 N 0 0 0 0 0 0 0 0 0 0 0 0 + 6.3840 0.6060 17.6000 N 0 0 0 0 0 0 0 0 0 0 0 0 + 12.9240 0.0460 23.4780 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.4230 -1.3250 22.1740 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.6910 -0.8630 22.4660 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.7790 1.3680 19.2090 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.8550 0.4630 24.2580 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.3250 -0.7180 20.9060 N 0 0 0 0 0 0 0 0 0 0 0 0 + 6.5510 -0.0910 19.8980 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.0640 0.7570 20.9540 O 0 0 0 0 0 0 0 0 0 0 0 0 + 8.5220 -0.2560 21.3810 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.4110 0.6430 20.2070 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.3490 -0.8420 22.9140 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.9850 -0.0870 18.5730 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.5710 0.0150 23.9870 C 0 0 0 0 0 0 0 0 0 0 0 0 + 14.0330 -1.4590 21.5350 Cl 0 0 0 0 0 0 0 0 0 0 0 0 + 3 1 2 0 + 6 5 1 0 + 6 4 2 0 + 7 1 1 0 + 8 4 1 0 + 10 9 1 0 + 12 11 2 0 + 12 9 1 0 + 12 2 1 0 + 13 7 2 0 + 13 10 1 0 + 14 2 1 0 + 14 5 2 0 + 15 10 2 0 + 15 3 1 0 + 16 14 1 0 + 16 8 2 0 + 17 6 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x11001.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x11001.mol new file mode 100644 index 0000000..f3f4cce --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x11001.mol @@ -0,0 +1,38 @@ + + RDKit 3D + + 16 17 0 0 0 0 0 0 0 0999 V2000 + 5.9670 -5.3200 19.7390 O 0 0 0 0 0 0 0 0 0 0 0 0 + 6.6700 -4.5060 20.3180 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.2770 -3.2660 19.6850 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.2870 -2.4990 19.0300 O 0 0 0 0 0 0 0 0 0 0 0 0 + 7.8580 -2.5680 20.8970 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.4910 -1.3390 21.0660 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.9720 -4.5170 21.6380 N 0 0 0 0 0 0 0 0 0 0 0 0 + 7.6690 -3.3820 22.0130 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.1050 -2.9980 23.2770 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.7300 -1.7750 23.4330 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.9050 -0.9520 22.3300 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.6250 0.6440 22.5460 S 0 0 0 0 0 0 0 0 0 0 0 0 + 10.8790 0.4550 23.2180 O 0 0 0 0 0 0 0 0 0 0 0 0 + 9.6080 1.2960 21.2700 O 0 0 0 0 0 0 0 0 0 0 0 0 + 8.6920 1.5030 23.5270 N 0 0 0 0 0 0 0 0 0 0 0 0 + 8.6760 -3.5410 18.6780 S 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 2 0 + 3 2 1 0 + 3 4 1 6 + 5 3 1 0 + 6 5 2 0 + 7 2 1 0 + 8 7 1 0 + 8 5 1 0 + 9 8 2 0 + 10 9 1 0 + 11 6 1 0 + 11 10 2 0 + 12 11 1 0 + 13 12 2 0 + 14 12 2 0 + 12 15 1 0 + 3 16 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x11011.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x11011.mol new file mode 100644 index 0000000..846a857 --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x11011.mol @@ -0,0 +1,42 @@ + + RDKit 3D + + 18 19 0 0 0 0 0 0 0 0999 V2000 + 10.4270 0.7730 22.9480 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.2680 0.5680 17.3890 N 0 0 0 0 0 0 0 0 0 0 0 0 + 12.5670 -0.9160 22.5810 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.1220 1.0140 19.9030 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.7770 0.3180 23.1620 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.5120 1.3200 21.2470 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.2470 -0.4470 22.3040 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.6770 1.6940 18.7740 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.9880 -0.8080 21.7830 N 0 0 0 0 0 0 0 0 0 0 0 0 + 6.7430 -0.6540 20.9280 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.2880 1.1830 20.9380 O 0 0 0 0 0 0 0 0 0 0 0 0 + 6.1620 0.0840 19.7440 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.0810 0.0020 21.2060 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.6770 -0.0980 18.4730 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.6930 1.1570 23.3600 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.3240 -1.3070 22.1280 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.2800 1.4540 17.5560 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.8650 -2.0690 22.5630 Cl 0 0 0 0 0 0 0 0 0 0 0 0 + 5 3 1 0 + 6 4 1 0 + 7 1 2 0 + 8 4 1 0 + 9 7 1 0 + 12 4 2 0 + 12 10 1 0 + 13 11 2 0 + 13 10 1 0 + 13 9 1 0 + 14 12 1 0 + 14 2 2 0 + 15 1 1 0 + 15 5 2 0 + 16 7 1 0 + 16 3 2 0 + 17 8 2 0 + 17 2 1 0 + 18 3 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x11013.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x11013.mol new file mode 100644 index 0000000..ef2451c --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x11013.mol @@ -0,0 +1,42 @@ + + RDKit 3D + + 18 19 0 0 0 0 0 0 0 0999 V2000 + 13.8310 -1.7830 21.3510 Cl 0 0 0 0 0 0 0 0 0 0 0 0 + 12.5970 -1.0080 22.3120 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.9690 -0.0950 23.2760 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.9890 0.4210 24.1120 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.6620 0.0570 23.9450 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.2770 -1.3730 22.1250 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.2870 -0.8200 22.9340 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.8270 -1.0710 22.6300 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.3620 -0.1880 21.4870 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.0540 0.7340 21.0620 O 0 0 0 0 0 0 0 0 0 0 0 0 + 7.1460 -0.5020 20.9870 N 0 0 0 0 0 0 0 0 0 0 0 0 + 6.4810 0.1370 19.9100 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.3230 0.9030 20.1500 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.7940 1.1330 21.5430 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.8920 0.0420 18.5840 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.2550 0.6130 17.5730 N 0 0 0 0 0 0 0 0 0 0 0 0 + 5.1270 1.3440 17.8120 N 0 0 0 0 0 0 0 0 0 0 0 0 + 4.6830 1.4790 19.0570 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 1 0 + 3 2 2 0 + 4 3 1 0 + 5 4 2 0 + 6 2 1 0 + 7 5 1 0 + 7 6 2 0 + 8 7 1 0 + 9 8 1 0 + 10 9 2 0 + 11 9 1 0 + 12 11 1 0 + 13 12 2 0 + 14 13 1 0 + 15 12 1 0 + 16 15 2 0 + 17 16 1 0 + 18 17 2 0 + 18 13 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x11025.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x11025.mol new file mode 100644 index 0000000..c6a4712 --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x11025.mol @@ -0,0 +1,40 @@ + + RDKit 3D + + 17 18 0 0 0 0 0 0 0 0999 V2000 + 13.5800 -1.6760 21.4460 Cl 0 0 0 0 0 0 0 0 0 0 0 0 + 12.3510 -0.8590 22.3690 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.7250 0.0880 23.2940 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.7450 0.6650 24.0870 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.4140 0.3230 23.9120 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.0280 -1.2090 22.1810 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.0380 -0.5890 22.9380 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.5820 -0.7990 22.6000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.2220 -0.0340 21.3420 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.9510 0.8380 20.8720 O 0 0 0 0 0 0 0 0 0 0 0 0 + 7.0360 -0.3980 20.7700 N 0 0 0 0 0 0 0 0 0 0 0 0 + 6.5900 0.1230 19.5400 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.5840 1.0330 19.3140 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.7390 1.8300 20.2540 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.0700 -0.2400 18.2810 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.4010 0.3910 17.3250 N 0 0 0 0 0 0 0 0 0 0 0 0 + 5.4870 1.1660 17.9800 N 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 1 0 + 3 2 2 0 + 4 3 1 0 + 5 4 2 0 + 6 2 1 0 + 7 5 1 0 + 7 6 2 0 + 8 7 1 0 + 9 8 1 0 + 10 9 2 0 + 11 9 1 0 + 12 11 1 0 + 13 12 2 0 + 14 13 1 0 + 15 12 1 0 + 16 15 2 0 + 17 16 1 0 + 17 13 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x11041.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x11041.mol new file mode 100644 index 0000000..7ec5b08 --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x11041.mol @@ -0,0 +1,44 @@ + + RDKit 3D + + 19 20 0 0 0 0 0 0 0 0999 V2000 + 7.2140 -0.4880 20.9820 N 0 0 0 0 0 0 0 0 0 0 0 0 + 5.2720 1.2860 17.8020 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.3900 -0.0510 21.5010 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.4480 -1.1050 21.9640 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.0340 -0.8520 22.6170 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.1940 0.1960 23.0020 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.2430 0.8130 23.8000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.9040 0.4700 23.6830 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.9850 0.0320 18.6440 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.3620 0.9590 20.1710 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.5100 0.2000 19.9430 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.7340 1.4980 19.0540 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.8270 1.2260 21.5550 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.6420 -1.7580 21.4360 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.3810 0.5700 17.5800 N 0 0 0 0 0 0 0 0 0 0 0 0 + 8.9400 0.9620 21.0830 O 0 0 0 0 0 0 0 0 0 0 0 0 + 12.7770 -0.7660 22.1030 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.4940 -0.4910 22.7670 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.9660 -1.6640 21.2090 Cl 0 0 0 0 0 0 0 0 0 0 0 0 + 3 1 1 0 + 5 3 1 0 + 7 6 2 0 + 8 7 1 0 + 11 10 2 0 + 11 9 1 0 + 11 1 1 0 + 12 10 1 0 + 12 2 2 0 + 13 10 1 0 + 14 1 1 0 + 15 2 1 0 + 15 9 2 0 + 16 3 2 0 + 17 6 1 0 + 17 4 2 0 + 18 5 1 0 + 18 8 2 0 + 18 4 1 0 + 19 17 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x11044.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x11044.mol new file mode 100644 index 0000000..4db45d3 --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x11044.mol @@ -0,0 +1,42 @@ + + RDKit 3D + + 18 19 0 0 0 0 0 0 0 0999 V2000 + 7.7400 -0.3460 21.3140 N 0 0 0 0 0 0 0 0 0 0 0 0 + 5.5590 1.0330 18.0650 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.2960 -0.0500 23.1570 C 0 0 1 0 0 0 0 0 0 0 0 0 + 8.8380 0.3060 21.7460 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.8370 -0.2330 23.1970 C 0 0 2 0 0 0 0 0 0 0 0 0 + 12.8840 -1.4270 22.2830 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.3880 -1.6950 23.6950 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.9000 -0.6190 24.6490 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.7750 0.8510 20.4450 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.3540 -0.1110 18.8960 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.9560 0.1040 20.2160 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.0690 1.2930 19.3310 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.3200 1.2300 21.8310 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.8140 1.0820 24.0660 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.6850 0.3520 17.8350 N 0 0 0 0 0 0 0 0 0 0 0 0 + 9.3770 1.2010 21.1130 O 0 0 0 0 0 0 0 0 0 0 0 0 + 11.3570 -1.3180 22.2440 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.3750 -0.4900 24.6150 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4 1 1 0 + 4 3 1 0 + 5 3 1 0 + 7 6 1 0 + 8 7 1 0 + 11 10 1 0 + 11 9 2 0 + 11 1 1 0 + 12 9 1 0 + 12 2 2 0 + 13 9 1 0 + 3 14 1 1 + 15 10 2 0 + 15 2 1 0 + 16 4 2 0 + 5 17 1 6 + 17 6 1 0 + 18 5 1 0 + 18 8 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x11159.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x11159.mol new file mode 100644 index 0000000..df15abd --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x11159.mol @@ -0,0 +1,50 @@ + + RDKit 3D + + 21 24 0 0 0 0 0 0 0 0999 V2000 + 8.9170 1.3450 21.1440 O 0 0 0 0 0 0 0 0 0 0 0 0 + 8.4570 0.2610 21.4900 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.8130 -0.3900 22.8300 C 0 0 1 0 0 0 0 0 0 0 0 0 + 10.3260 -0.4460 22.9140 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.0840 -1.1160 21.9580 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.4670 -1.0460 21.9740 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.1140 -0.2970 22.9300 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.3870 0.3590 23.9150 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.0020 0.2580 23.9160 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.3600 0.8450 24.9810 O 0 0 0 0 0 0 0 0 0 0 0 0 + 9.0240 0.3580 25.2360 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.1580 0.3970 23.9970 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.5480 -0.4210 20.7340 N 0 0 0 0 0 0 0 0 0 0 0 0 + 7.0640 0.0010 19.5060 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.8030 0.5200 19.3450 N 0 0 0 0 0 0 0 0 0 0 0 0 + 5.7360 0.8710 18.0290 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.8540 0.6170 17.4210 N 0 0 0 0 0 0 0 0 0 0 0 0 + 7.7110 0.0510 18.3570 N 0 0 0 0 0 0 0 0 0 0 0 0 + 4.7860 0.7670 20.3810 C 0 0 1 0 0 0 0 0 0 0 0 0 + 4.9780 1.9210 21.2990 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.9300 1.9740 20.2360 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 2 0 + 3 2 1 6 + 4 3 1 0 + 5 4 2 0 + 6 5 1 0 + 7 6 2 0 + 8 7 1 0 + 9 4 1 0 + 9 8 2 0 + 10 9 1 0 + 11 10 1 0 + 12 11 1 0 + 12 3 1 0 + 13 2 1 0 + 14 13 1 0 + 15 14 1 0 + 16 15 1 0 + 17 16 2 0 + 18 17 1 0 + 18 14 2 0 + 19 15 1 6 + 20 19 1 0 + 21 20 1 0 + 21 19 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x11164.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x11164.mol new file mode 100644 index 0000000..7ede864 --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x11164.mol @@ -0,0 +1,66 @@ + + RDKit 3D + + 29 32 0 0 0 0 0 0 0 0999 V2000 + 9.2990 1.3720 21.0770 O 0 0 0 0 0 0 0 0 0 0 0 0 + 9.0280 0.3070 21.6190 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.0470 -0.6580 20.9800 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.1130 0.0140 20.0030 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.3890 0.0280 18.6450 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.5690 0.5400 17.7190 N 0 0 0 0 0 0 0 0 0 0 0 0 + 5.4140 1.0690 18.1460 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.0480 1.1160 19.4770 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.9150 0.5830 20.4120 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.6110 -0.0740 22.7920 N 0 0 0 0 0 0 0 0 0 0 0 0 + 10.8190 0.6240 23.2190 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.9710 -0.3140 23.4290 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.8220 -0.9180 22.4530 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.6250 -1.7670 23.1520 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.2530 -0.7620 24.6630 N 0 0 0 0 0 0 0 0 0 0 0 0 + 13.2610 -1.6560 24.4760 N 0 0 0 0 0 0 0 0 0 0 0 0 + 13.8030 -2.3730 25.6240 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.1160 -1.1330 23.6170 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.5080 -2.4550 23.3900 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.1420 -3.4500 24.2790 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.3810 -3.1610 25.4120 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.9650 -1.8430 25.6070 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.3230 -0.8410 24.7250 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.0790 -4.2100 26.4160 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.0570 -5.1070 26.6460 N 0 0 0 0 0 0 0 0 0 0 0 0 + 8.8560 -6.0110 27.6220 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.7090 -6.0670 28.3930 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.7100 -5.1520 28.1360 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.8840 -4.2120 27.1340 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 2 0 + 3 2 1 0 + 4 3 1 0 + 5 4 2 0 + 6 5 1 0 + 7 6 2 0 + 8 7 1 0 + 9 8 2 0 + 9 4 1 0 + 10 2 1 0 + 11 10 1 0 + 12 11 1 0 + 13 12 1 0 + 14 13 2 0 + 15 12 2 0 + 16 15 1 0 + 16 14 1 0 + 17 16 1 0 + 18 10 1 0 + 19 18 2 0 + 20 19 1 0 + 21 20 2 0 + 22 21 1 0 + 23 22 2 0 + 23 18 1 0 + 24 21 1 0 + 25 24 2 0 + 26 25 1 0 + 27 26 2 0 + 28 27 1 0 + 29 24 1 0 + 29 28 2 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x11186.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x11186.mol new file mode 100644 index 0000000..3d30acd --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x11186.mol @@ -0,0 +1,50 @@ + + RDKit 3D + + 21 24 0 0 0 0 0 0 0 0999 V2000 + 8.6790 1.2810 21.1400 O 0 0 0 0 0 0 0 0 0 0 0 0 + 8.2770 0.1370 21.3180 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.7130 -0.7110 22.5140 C 0 0 2 0 0 0 0 0 0 0 0 0 + 8.2250 -0.0540 23.8010 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.3710 0.6690 24.3270 O 0 0 0 0 0 0 0 0 0 0 0 0 + 10.2150 -0.6500 22.6940 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.5150 0.2720 23.6750 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.8170 0.6380 23.9690 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.8450 0.0320 23.2680 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.2480 -1.2750 22.0120 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.5480 -0.9350 22.3230 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.8420 -1.8170 21.5810 Cl 0 0 0 0 0 0 0 0 0 0 0 0 + 7.3960 -0.4700 20.4800 N 0 0 0 0 0 0 0 0 0 0 0 0 + 6.8790 0.0620 19.3330 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.6440 0.6620 19.2950 N 0 0 0 0 0 0 0 0 0 0 0 0 + 5.5170 1.0800 17.9970 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.5720 0.7730 17.2980 N 0 0 0 0 0 0 0 0 0 0 0 0 + 7.4510 0.1170 18.1430 N 0 0 0 0 0 0 0 0 0 0 0 0 + 4.7000 0.8640 20.4170 C 0 0 1 0 0 0 0 0 0 0 0 0 + 5.0510 1.8610 21.4680 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.9530 2.1520 20.4920 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 2 0 + 3 2 1 6 + 4 3 1 0 + 5 4 1 0 + 6 3 1 0 + 7 6 2 0 + 7 5 1 0 + 8 7 1 0 + 9 8 2 0 + 10 6 1 0 + 11 10 2 0 + 11 9 1 0 + 12 11 1 0 + 13 2 1 0 + 14 13 1 0 + 15 14 1 0 + 16 15 1 0 + 17 16 2 0 + 18 17 1 0 + 18 14 2 0 + 19 15 1 6 + 20 19 1 0 + 21 20 1 0 + 21 19 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x11204.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x11204.mol new file mode 100644 index 0000000..833570d --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x11204.mol @@ -0,0 +1,40 @@ + + RDKit 3D + + 17 18 0 0 0 0 0 0 0 0999 V2000 + 10.7060 -0.4720 23.3430 Br 0 0 0 0 0 0 0 0 0 0 0 0 + 9.1160 -1.3710 22.8350 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.1560 -2.2500 21.7720 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.0230 -2.9970 21.4730 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.8000 -4.1100 20.4750 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.4530 -5.2310 21.0520 O 0 0 0 0 0 0 0 0 0 0 0 0 + 6.3160 -4.3810 20.6720 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.6640 -5.1880 20.0240 O 0 0 0 0 0 0 0 0 0 0 0 0 + 5.8610 -3.6350 21.7050 N 0 0 0 0 0 0 0 0 0 0 0 0 + 6.8560 -2.8290 22.2140 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.9720 -1.1840 23.5880 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.8240 -1.9210 23.2910 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.6440 -1.7290 24.1790 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.6480 -2.4080 24.1380 O 0 0 0 0 0 0 0 0 0 0 0 0 + 5.8300 -0.7260 25.0420 O 0 0 0 0 0 0 0 0 0 0 0 0 + 4.7840 -0.5140 26.0220 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.3210 -3.5780 18.7750 S 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 1 0 + 3 2 2 0 + 4 3 1 0 + 5 4 1 0 + 5 6 1 1 + 7 5 1 0 + 8 7 2 0 + 9 7 1 0 + 10 9 1 0 + 10 4 2 0 + 11 2 1 0 + 12 11 2 0 + 12 10 1 0 + 13 12 1 0 + 14 13 2 0 + 15 13 1 0 + 16 15 1 0 + 5 17 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x11208.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x11208.mol new file mode 100644 index 0000000..fa391d5 --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x11208.mol @@ -0,0 +1,53 @@ + + RDKit 3D + + 23 25 0 0 0 0 0 0 0 0999 V2000 + 5.6630 -4.5300 19.8570 O 0 0 0 0 0 0 0 0 0 0 0 0 + 6.4190 -3.8880 20.5720 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.0510 -3.0020 21.5280 N 0 0 0 0 0 0 0 0 0 0 0 0 + 7.9360 -3.9540 20.5030 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.3440 -5.1830 21.0840 O 0 0 0 0 0 0 0 0 0 0 0 0 + 8.3100 -2.8730 21.4940 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.1470 -2.3920 22.0910 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.5440 -2.3550 21.8690 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.6170 -1.3840 22.8540 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.4640 -0.9100 23.4600 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.2110 -1.3960 23.0850 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.0120 -0.8200 23.7520 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.9010 -1.2760 23.6690 O 0 0 0 0 0 0 0 0 0 0 0 0 + 6.3260 0.2460 24.4950 O 0 0 0 0 0 0 0 0 0 0 0 0 + 5.3930 0.5850 25.5630 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.2130 0.8850 26.7830 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.7560 1.7740 27.7510 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.4790 0.3340 26.9280 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.2750 0.6740 28.0100 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.8100 1.5760 28.9520 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.5470 2.1450 28.8320 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.0770 3.1950 29.8080 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.4100 -3.5780 18.7620 S 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 2 0 + 3 2 1 0 + 4 2 1 0 + 4 5 1 1 + 6 4 1 0 + 7 6 2 0 + 7 3 1 0 + 8 6 1 0 + 9 8 2 0 + 10 9 1 0 + 11 10 2 0 + 11 7 1 0 + 12 11 1 0 + 13 12 2 0 + 14 12 1 0 + 15 14 1 0 + 16 15 1 0 + 17 16 2 0 + 18 16 1 0 + 19 18 2 0 + 20 19 1 0 + 21 20 2 0 + 21 17 1 0 + 22 21 1 0 + 4 23 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x11212.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x11212.mol new file mode 100644 index 0000000..0246100 --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x11212.mol @@ -0,0 +1,45 @@ + + RDKit 3D + + 19 21 0 0 0 0 0 0 0 0999 V2000 + 11.8310 0.2370 22.7280 Br 0 0 0 0 0 0 0 0 0 0 0 0 + 10.2050 -0.1920 21.8410 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.0210 -1.4790 21.3700 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.8150 -1.8010 20.7650 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.3250 -3.0590 20.1120 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.4130 -4.1670 20.9930 O 0 0 0 0 0 0 0 0 0 0 0 0 + 9.2280 0.7840 21.7110 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.0150 0.4560 21.1240 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.8120 -0.8450 20.6750 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.6540 -1.4260 20.1480 N 0 0 0 0 0 0 0 0 0 0 0 0 + 6.8620 -2.7440 19.8260 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.0160 -3.5200 19.4300 O 0 0 0 0 0 0 0 0 0 0 0 0 + 5.3780 -0.7380 19.9790 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.4390 0.3470 18.9550 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.4590 1.3010 18.9000 N 0 0 0 0 0 0 0 0 0 0 0 0 + 4.8440 2.0150 17.9020 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.9660 1.6050 17.3340 O 0 0 0 0 0 0 0 0 0 0 0 0 + 6.3680 0.4710 18.0580 N 0 0 0 0 0 0 0 0 0 0 0 0 + 9.0950 -3.2520 18.4280 S 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 1 0 + 3 2 2 0 + 4 3 1 0 + 5 4 1 0 + 5 6 1 1 + 7 2 1 0 + 8 7 2 0 + 9 8 1 0 + 9 4 2 0 + 10 9 1 0 + 11 10 1 0 + 11 5 1 0 + 12 11 2 0 + 13 10 1 0 + 14 13 1 0 + 15 14 1 0 + 16 15 2 0 + 17 16 1 0 + 18 14 2 0 + 18 17 1 0 + 5 19 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x11223.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x11223.mol new file mode 100644 index 0000000..d8ec507 --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x11223.mol @@ -0,0 +1,47 @@ + + RDKit 3D + + 20 22 0 0 0 0 0 0 0 0999 V2000 + 24.8570 -27.9390 20.0950 Cl 0 0 0 0 0 0 0 0 0 0 0 0 + 24.3490 -27.2070 18.6030 C 0 0 0 0 0 0 0 0 0 0 0 0 + 24.7430 -27.7820 17.4120 C 0 0 0 0 0 0 0 0 0 0 0 0 + 24.3510 -27.2130 16.2140 C 0 0 0 0 0 0 0 0 0 0 0 0 + 23.5700 -26.0690 16.2410 C 0 0 0 0 0 0 0 0 0 0 0 0 + 23.1130 -25.2970 15.1880 N 0 0 0 0 0 0 0 0 0 0 0 0 + 22.4060 -24.2260 15.6960 C 0 0 0 0 0 0 0 0 0 0 0 0 + 21.8490 -23.1530 14.9940 C 0 0 0 0 0 0 0 0 0 0 0 0 + 21.8690 -23.1540 13.4830 C 0 0 0 0 0 0 0 0 0 0 0 0 + 23.5580 -26.0720 18.6510 C 0 0 0 0 0 0 0 0 0 0 0 0 + 23.1550 -25.4860 17.4540 C 0 0 0 0 0 0 0 0 0 0 0 0 + 22.3900 -24.3020 17.1000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 21.7530 -23.2930 17.8180 C 0 0 0 0 0 0 0 0 0 0 0 0 + 21.2060 -22.2230 17.1340 C 0 0 0 0 0 0 0 0 0 0 0 0 + 21.2660 -22.1170 15.7430 C 0 0 0 0 0 0 0 0 0 0 0 0 + 20.7380 -20.8620 15.0550 C 0 0 1 0 0 0 0 0 0 0 0 0 + 19.8860 -20.0110 15.9880 C 0 0 0 0 0 0 0 0 0 0 0 0 + 21.8450 -20.0200 14.4450 C 0 0 0 0 0 0 0 0 0 0 0 0 + 21.8070 -19.6520 13.2890 O 0 0 0 0 0 0 0 0 0 0 0 0 + 22.8130 -19.7210 15.2690 O 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 1 0 + 3 2 2 0 + 4 3 1 0 + 5 4 2 0 + 6 5 1 0 + 7 6 1 0 + 8 7 1 0 + 9 8 1 0 + 10 2 1 0 + 11 5 1 0 + 11 10 2 0 + 12 7 2 0 + 12 11 1 0 + 13 12 1 0 + 14 13 2 0 + 15 14 1 0 + 15 8 2 0 + 16 15 1 0 + 16 17 1 1 + 18 16 1 0 + 19 18 1 0 + 20 18 2 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x11225.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x11225.mol new file mode 100644 index 0000000..ef9c8a2 --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x11225.mol @@ -0,0 +1,55 @@ + + RDKit 3D + + 24 26 0 0 0 0 0 0 0 0999 V2000 + 9.1940 1.0050 21.0390 O 0 0 0 0 0 0 0 0 0 0 0 0 + 8.8760 -0.1690 21.2100 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.7440 -0.7180 20.7150 N 0 0 0 0 0 0 0 0 0 0 0 0 + 6.8530 -0.0840 19.8120 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.0970 -0.0760 18.4380 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.3140 0.5450 17.5500 N 0 0 0 0 0 0 0 0 0 0 0 0 + 5.2340 1.1760 18.0200 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.9020 1.2280 19.3600 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.7170 0.5980 20.2950 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.4040 0.6930 21.7660 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.7600 -1.1320 21.9910 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.0600 -0.6920 23.4350 C 0 0 2 0 0 0 0 0 0 0 0 0 + 11.0070 -1.5790 24.2050 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.2810 -1.2140 24.5540 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.1050 -2.4600 25.3980 S 0 0 0 0 0 0 0 0 0 0 0 0 + 11.7680 -3.5060 25.3220 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.7190 -2.9030 24.6460 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.8120 -0.3350 24.1580 N 0 0 0 0 0 0 0 0 0 0 0 0 + 7.9020 -1.4560 24.4490 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.5240 -0.9580 24.8930 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.6330 -0.0150 26.0780 C 0 0 2 0 0 0 0 0 0 0 0 0 + 5.3560 0.5730 26.3620 O 0 0 0 0 0 0 0 0 0 0 0 0 + 7.6630 1.0750 25.8380 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.9970 0.4910 25.3610 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 2 0 + 3 2 1 0 + 4 3 1 0 + 5 4 2 0 + 6 5 1 0 + 7 6 2 0 + 8 7 1 0 + 9 8 2 0 + 9 4 1 0 + 10 9 1 0 + 11 2 1 0 + 12 11 1 6 + 13 12 1 0 + 14 13 2 0 + 15 14 1 0 + 16 15 1 0 + 17 16 2 0 + 17 13 1 0 + 18 12 1 0 + 19 18 1 0 + 20 19 1 0 + 21 20 1 0 + 21 22 1 6 + 23 21 1 0 + 24 23 1 0 + 24 18 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x11231.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x11231.mol new file mode 100644 index 0000000..7a700fb --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x11231.mol @@ -0,0 +1,56 @@ + + RDKit 3D + + 24 27 0 0 0 0 0 0 0 0999 V2000 + 8.8580 1.3790 21.0310 O 0 0 0 0 0 0 0 0 0 0 0 0 + 8.3060 0.3010 21.2470 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.7280 -0.6240 22.3880 C 0 0 2 0 0 0 0 0 0 0 0 0 + 8.1890 -0.0420 23.6880 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.2620 0.8040 24.1910 O 0 0 0 0 0 0 0 0 0 0 0 0 + 10.2170 -0.5120 22.6080 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.4500 0.3450 23.6660 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.7290 0.6660 24.0840 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.8040 0.1110 23.4070 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.2950 -1.0800 21.9430 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.5720 -0.7530 22.3490 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.9240 -1.4250 21.4870 Cl 0 0 0 0 0 0 0 0 0 0 0 0 + 7.4030 -0.2290 20.3880 N 0 0 0 0 0 0 0 0 0 0 0 0 + 6.6760 0.2090 19.3240 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.9340 1.3980 19.3220 N 0 0 0 0 0 0 0 0 0 0 0 0 + 5.7040 1.6190 17.9860 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.2160 0.6780 17.2490 N 0 0 0 0 0 0 0 0 0 0 0 0 + 6.8180 -0.2370 18.0910 N 0 0 0 0 0 0 0 0 0 0 0 0 + 5.3520 2.1910 20.3760 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.9700 2.3750 20.4120 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.4200 3.2750 21.3150 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.2320 3.9820 22.1800 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.6010 3.7870 22.1580 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.1680 2.8910 21.2630 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 2 0 + 3 2 1 6 + 4 3 1 0 + 5 4 1 0 + 6 3 1 0 + 7 6 2 0 + 7 5 1 0 + 8 7 1 0 + 9 8 2 0 + 10 6 1 0 + 11 10 2 0 + 11 9 1 0 + 12 11 1 0 + 13 2 1 0 + 14 13 1 0 + 15 14 1 0 + 16 15 1 0 + 17 16 2 0 + 18 17 1 0 + 18 14 2 0 + 19 15 1 0 + 20 19 2 0 + 21 20 1 0 + 22 21 2 0 + 23 22 1 0 + 24 19 1 0 + 24 23 2 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x11233.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x11233.mol new file mode 100644 index 0000000..a78bc11 --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x11233.mol @@ -0,0 +1,52 @@ + + RDKit 3D + + 22 25 0 0 0 0 0 0 0 0999 V2000 + 9.1730 1.1690 21.0800 O 0 0 0 0 0 0 0 0 0 0 0 0 + 8.6750 0.1160 21.4540 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.6620 -0.4930 20.7560 N 0 0 0 0 0 0 0 0 0 0 0 0 + 7.1450 -0.0340 19.5630 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.8900 0.5000 19.4590 N 0 0 0 0 0 0 0 0 0 0 0 0 + 4.9080 0.7150 20.5400 C 0 0 1 0 0 0 0 0 0 0 0 0 + 5.0450 1.9300 21.3860 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.9350 1.8300 20.3910 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.7730 0.8500 18.1480 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.8590 0.5730 17.4910 N 0 0 0 0 0 0 0 0 0 0 0 0 + 7.7450 0.0010 18.3870 N 0 0 0 0 0 0 0 0 0 0 0 0 + 9.1270 -0.5590 22.7680 C 0 0 1 0 0 0 0 0 0 0 0 0 + 8.8600 -2.0730 22.8830 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.6440 -0.3740 22.7940 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.4490 -0.9820 21.8420 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.8090 -0.7270 21.7970 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.3860 0.1370 22.7020 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.6110 0.7440 23.6800 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.2530 0.4680 23.7260 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.5590 1.0360 24.7640 O 0 0 0 0 0 0 0 0 0 0 0 0 + 9.2070 1.3820 24.4150 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.4270 0.1710 23.9430 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 2 0 + 3 2 1 0 + 4 3 1 0 + 5 4 1 0 + 6 5 1 6 + 7 6 1 0 + 8 7 1 0 + 8 6 1 0 + 9 5 1 0 + 10 9 2 0 + 11 10 1 0 + 11 4 2 0 + 12 2 1 0 + 12 13 1 6 + 14 12 1 0 + 15 14 2 0 + 16 15 1 0 + 17 16 2 0 + 18 17 1 0 + 19 14 1 0 + 19 18 2 0 + 20 19 1 0 + 21 20 1 0 + 22 21 1 0 + 22 12 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x11254.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x11254.mol new file mode 100644 index 0000000..ae4eeb6 --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x11254.mol @@ -0,0 +1,57 @@ + + RDKit 3D + + 25 27 0 0 0 0 0 0 0 0999 V2000 + 5.0930 1.0900 17.7200 Br 0 0 0 0 0 0 0 0 0 0 0 0 + 5.6610 -0.0100 19.1510 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.9750 -1.3220 18.8940 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.3900 -2.1330 19.9420 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.8590 -3.5550 19.9410 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.8120 -4.4250 19.5620 O 0 0 0 0 0 0 0 0 0 0 0 0 + 7.1140 -3.8060 21.4200 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.3710 -4.8730 21.9420 O 0 0 0 0 0 0 0 0 0 0 0 0 + 5.7380 0.5220 20.4190 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.1290 -0.2850 21.4850 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.1100 0.2900 22.8810 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.4700 -1.6190 21.2180 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.0290 -2.5980 22.0650 N 0 0 0 0 0 0 0 0 0 0 0 0 + 7.4920 -2.3910 23.4330 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.8560 -1.7490 23.5060 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.2640 -1.1140 24.6730 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.4810 -0.4610 24.7330 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.9320 0.2480 25.8140 O 0 0 0 0 0 0 0 0 0 0 0 0 + 10.1220 0.2490 26.9970 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.7020 -1.7320 22.4030 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.9340 -1.1050 22.4480 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.3330 -0.4660 23.6150 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.5410 0.1510 23.7990 O 0 0 0 0 0 0 0 0 0 0 0 0 + 13.4830 0.1160 22.7290 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.3670 -3.5940 18.8050 S 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 1 0 + 3 2 2 0 + 4 3 1 0 + 5 4 1 0 + 5 6 1 6 + 7 5 1 0 + 8 7 2 0 + 9 2 1 0 + 10 9 2 0 + 11 10 1 0 + 12 10 1 0 + 12 4 2 0 + 13 12 1 0 + 13 7 1 0 + 14 13 1 0 + 15 14 1 0 + 16 15 2 0 + 17 16 1 0 + 18 17 1 0 + 19 18 1 0 + 20 15 1 0 + 21 20 2 0 + 22 17 2 0 + 22 21 1 0 + 23 22 1 0 + 24 23 1 0 + 5 25 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x11258.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x11258.mol new file mode 100644 index 0000000..1cd171c --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x11258.mol @@ -0,0 +1,53 @@ + + RDKit 3D + + 23 25 0 0 0 0 0 0 0 0999 V2000 + 5.3870 1.0960 17.8210 Br 0 0 0 0 0 0 0 0 0 0 0 0 + 6.0810 -0.0300 19.1800 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.2140 -1.3800 18.9210 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.7840 -2.1880 19.8940 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.1840 -3.6340 19.8780 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.0800 -4.5080 19.7590 O 0 0 0 0 0 0 0 0 0 0 0 0 + 7.7910 -3.8410 21.2570 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.2660 -4.8720 21.6930 O 0 0 0 0 0 0 0 0 0 0 0 0 + 6.4730 0.5290 20.3850 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.0230 -0.2810 21.3640 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.1750 -1.6400 21.1080 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.7280 -2.6420 21.9210 N 0 0 0 0 0 0 0 0 0 0 0 0 + 8.2400 -2.4380 23.2770 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.4390 -1.5200 23.3300 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.2990 -1.3970 22.2390 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.3440 -0.4880 22.2550 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.5600 0.2950 23.3630 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.7410 0.1760 24.4750 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.6800 -0.7210 24.4510 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.8080 -0.8980 25.5020 O 0 0 0 0 0 0 0 0 0 0 0 0 + 8.6100 0.1850 26.4300 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.8580 -0.3360 27.5940 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.6000 -3.4190 18.6900 S 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 1 0 + 3 2 2 0 + 4 3 1 0 + 5 4 1 0 + 5 6 1 6 + 7 5 1 0 + 8 7 2 0 + 9 2 1 0 + 10 9 2 0 + 11 10 1 0 + 11 4 2 0 + 12 11 1 0 + 12 7 1 0 + 13 12 1 0 + 14 13 1 0 + 15 14 2 0 + 16 15 1 0 + 17 16 2 0 + 18 17 1 0 + 19 18 2 0 + 19 14 1 0 + 20 19 1 0 + 21 20 1 0 + 22 21 1 0 + 5 23 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x11271.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x11271.mol new file mode 100644 index 0000000..bf2bc1e --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x11271.mol @@ -0,0 +1,46 @@ + + RDKit 3D + + 20 21 0 0 0 0 0 0 0 0999 V2000 + 8.6590 0.4760 20.9290 O 0 0 0 0 0 0 0 0 0 0 0 0 + 8.0260 -0.5590 21.1320 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.4850 -1.5920 22.1380 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.7580 -1.0970 22.7720 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.9850 -1.3950 22.1940 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.1390 -0.8970 22.7550 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.6700 -1.3400 22.0600 Cl 0 0 0 0 0 0 0 0 0 0 0 0 + 12.1170 -0.0980 23.8810 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.7130 -0.3090 23.9170 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.8920 0.1700 24.4700 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.9930 0.8180 25.6740 O 0 0 0 0 0 0 0 0 0 0 0 0 + 9.8130 0.9720 26.4690 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.8630 -0.8610 20.5250 N 0 0 0 0 0 0 0 0 0 0 0 0 + 6.2520 -0.0570 19.5480 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.1550 0.7530 19.8920 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.6340 0.8360 21.3050 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.6130 1.5480 18.8880 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.1770 1.5340 17.6290 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.2360 0.7810 17.3000 N 0 0 0 0 0 0 0 0 0 0 0 0 + 6.7530 -0.0070 18.2480 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 2 0 + 3 2 1 0 + 4 3 1 0 + 5 4 2 0 + 6 5 1 0 + 7 6 1 0 + 8 6 2 0 + 9 4 1 0 + 10 9 2 0 + 10 8 1 0 + 11 10 1 0 + 12 11 1 0 + 13 2 1 0 + 14 13 1 0 + 15 14 2 0 + 16 15 1 0 + 17 15 1 0 + 18 17 2 0 + 19 18 1 0 + 20 19 2 0 + 20 14 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x11294.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x11294.mol new file mode 100644 index 0000000..2d3fc93 --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x11294.mol @@ -0,0 +1,61 @@ + + RDKit 3D + + 27 29 0 0 0 0 0 0 0 0999 V2000 + 6.4570 0.9790 16.8630 O 0 0 0 0 0 0 0 0 0 0 0 0 + 5.8320 0.7390 17.8990 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.2030 -0.2690 18.8250 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.7710 1.5270 18.2640 N 0 0 0 0 0 0 0 0 0 0 0 0 + 4.1200 1.4470 19.4890 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.5560 0.4960 20.4390 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.9680 0.5260 21.7200 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.4920 -0.3550 22.6280 O 0 0 0 0 0 0 0 0 0 0 0 0 + 3.9140 -0.3980 23.9320 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2.9510 1.4260 22.0100 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2.5070 2.3090 21.0410 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.0900 2.3320 19.7880 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.6230 -0.4310 20.0400 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.0390 -1.6110 20.8540 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.3220 -2.6050 20.9470 O 0 0 0 0 0 0 0 0 0 0 0 0 + 7.2080 -1.5080 21.4880 N 0 0 0 0 0 0 0 0 0 0 0 0 + 7.6390 -2.4690 22.4910 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.1250 -2.4550 22.6830 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.5470 -1.0830 22.7330 O 0 0 0 0 0 0 0 0 0 0 0 0 + 10.8910 -0.8090 22.7950 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.2310 0.4370 23.3590 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.1690 1.1980 23.7710 O 0 0 0 0 0 0 0 0 0 0 0 0 + 10.4110 2.5720 24.0850 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.8870 -1.6330 22.2880 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.2050 -1.2070 22.3090 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.5400 0.0150 22.8600 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.5620 0.8360 23.4010 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 2 0 + 3 2 1 0 + 4 2 1 0 + 5 4 1 0 + 6 5 2 0 + 7 6 1 0 + 8 7 1 0 + 9 8 1 0 + 10 7 2 0 + 11 10 1 0 + 12 11 2 0 + 12 5 1 0 + 13 6 1 0 + 13 3 2 0 + 14 13 1 0 + 15 14 2 0 + 16 14 1 0 + 17 16 1 0 + 18 17 1 0 + 19 18 1 0 + 20 19 1 0 + 21 20 2 0 + 22 21 1 0 + 23 22 1 0 + 24 20 1 0 + 25 24 2 0 + 26 25 1 0 + 27 26 2 0 + 27 21 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x11313.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x11313.mol new file mode 100644 index 0000000..d8d8903 --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x11313.mol @@ -0,0 +1,59 @@ + + RDKit 3D + + 26 28 0 0 0 0 0 0 0 0999 V2000 + 6.3470 1.1130 16.7210 O 0 0 0 0 0 0 0 0 0 0 0 0 + 5.7570 0.8350 17.7680 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.1700 -0.1840 18.6610 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.6960 1.5940 18.1820 N 0 0 0 0 0 0 0 0 0 0 0 0 + 4.0810 1.4760 19.4280 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.5390 0.5040 20.3520 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.9530 0.4540 21.6370 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.4640 -0.4380 22.7390 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2.9050 1.3250 21.9310 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2.4450 2.2420 21.0080 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.0320 2.3300 19.7600 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.6240 -0.4020 19.8880 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.0960 -1.6150 20.6280 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.4940 -2.6850 20.5560 O 0 0 0 0 0 0 0 0 0 0 0 0 + 7.2060 -1.4780 21.3510 N 0 0 0 0 0 0 0 0 0 0 0 0 + 7.6570 -2.5100 22.2740 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.1490 -2.4920 22.4230 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.5210 -1.1670 22.8310 O 0 0 0 0 0 0 0 0 0 0 0 0 + 10.8450 -0.8100 22.8050 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.1030 0.5220 23.1740 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.9960 1.2540 23.5110 O 0 0 0 0 0 0 0 0 0 0 0 0 + 10.1950 2.5310 24.1160 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.8960 -1.6480 22.4570 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.1940 -1.1590 22.4790 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.4480 0.1470 22.8520 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.4090 0.9960 23.1930 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 2 0 + 3 2 1 0 + 4 2 1 0 + 5 4 1 0 + 6 5 2 0 + 7 6 1 0 + 8 7 1 0 + 9 7 2 0 + 10 9 1 0 + 11 10 2 0 + 11 5 1 0 + 12 6 1 0 + 12 3 2 0 + 13 12 1 0 + 14 13 2 0 + 15 13 1 0 + 16 15 1 0 + 17 16 1 0 + 18 17 1 0 + 19 18 1 0 + 20 19 2 0 + 21 20 1 0 + 22 21 1 0 + 23 19 1 0 + 24 23 2 0 + 25 24 1 0 + 26 25 2 0 + 26 20 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x11317.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x11317.mol new file mode 100644 index 0000000..a48b2d3 --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x11317.mol @@ -0,0 +1,44 @@ + + RDKit 3D + + 19 20 0 0 0 0 0 0 0 0999 V2000 + 13.7350 -1.8750 21.1970 Cl 0 0 0 0 0 0 0 0 0 0 0 0 + 12.5670 -1.0860 22.2180 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.9990 -0.1670 23.1510 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.0570 0.4390 23.9700 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.7090 0.1460 23.8170 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.2320 -1.3870 22.0560 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.2810 -0.7480 22.8410 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.8100 -0.9830 22.5820 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.3300 -0.1760 21.3920 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.8570 0.8920 21.0720 O 0 0 0 0 0 0 0 0 0 0 0 0 + 7.2400 -0.6750 20.7780 N 0 0 0 0 0 0 0 0 0 0 0 0 + 6.5600 0.0120 19.7390 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.4800 0.8640 20.0240 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.0200 1.0990 21.4430 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.0000 -0.1440 18.4320 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.4300 0.4810 17.4030 N 0 0 0 0 0 0 0 0 0 0 0 0 + 5.3950 1.2880 17.6660 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.8850 1.5050 18.9650 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.8060 2.3670 19.1070 N 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 1 0 + 3 2 2 0 + 4 3 1 0 + 5 4 2 0 + 6 2 1 0 + 7 5 1 0 + 7 6 2 0 + 8 7 1 0 + 9 8 1 0 + 10 9 2 0 + 11 9 1 0 + 12 11 1 0 + 13 12 2 0 + 14 13 1 0 + 15 12 1 0 + 16 15 2 0 + 17 16 1 0 + 18 17 2 0 + 18 13 1 0 + 19 18 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x11318.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x11318.mol new file mode 100644 index 0000000..9ad5088 --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x11318.mol @@ -0,0 +1,46 @@ + + RDKit 3D + + 20 21 0 0 0 0 0 0 0 0999 V2000 + 14.2440 -1.9630 20.4970 N 0 0 0 0 0 0 0 0 0 0 0 0 + 13.5400 -1.5050 21.2700 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.6130 -0.9350 22.2180 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.0710 -0.1190 23.2490 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.1660 0.4200 24.1480 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.8090 0.1810 23.9950 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.2500 -1.1890 22.0800 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.3370 -0.6060 22.9520 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.8570 -0.8000 22.7320 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.3980 -0.0310 21.5120 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.0120 0.9480 21.0980 O 0 0 0 0 0 0 0 0 0 0 0 0 + 7.2500 -0.4880 20.9670 N 0 0 0 0 0 0 0 0 0 0 0 0 + 6.5610 0.1310 19.8970 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.4160 0.9090 20.1460 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.9200 1.1490 21.5540 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.0390 -0.0300 18.6020 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.4440 0.5090 17.5380 N 0 0 0 0 0 0 0 0 0 0 0 0 + 5.3420 1.2380 17.7490 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.7820 1.4820 19.0420 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.6580 2.3120 19.1480 N 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 3 0 + 3 2 1 0 + 4 3 2 0 + 5 4 1 0 + 6 5 2 0 + 7 3 1 0 + 8 6 1 0 + 8 7 2 0 + 9 8 1 0 + 10 9 1 0 + 11 10 2 0 + 12 10 1 0 + 13 12 1 0 + 14 13 2 0 + 15 14 1 0 + 16 13 1 0 + 17 16 2 0 + 18 17 1 0 + 19 18 2 0 + 19 14 1 0 + 20 19 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x11339.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x11339.mol new file mode 100644 index 0000000..b713c23 --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x11339.mol @@ -0,0 +1,36 @@ + + RDKit 3D + + 15 16 0 0 0 0 0 0 0 0999 V2000 + 13.5090 -0.5230 21.3410 F 0 0 0 0 0 0 0 0 0 0 0 0 + 12.6350 -1.3060 22.1030 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.4360 -0.4690 22.4630 C 0 0 2 0 0 0 0 0 0 0 0 0 + 10.5010 -0.8360 23.5670 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.0870 -1.0740 22.1350 C 0 0 1 0 0 0 0 0 0 0 0 0 + 9.1570 -0.0920 21.4490 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.5160 1.0500 21.1810 O 0 0 0 0 0 0 0 0 0 0 0 0 + 7.9550 -0.6070 21.1050 N 0 0 0 0 0 0 0 0 0 0 0 0 + 7.0470 -0.0450 20.1770 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.8990 0.6270 20.6340 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.5860 0.7660 22.1020 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.2660 -0.1310 18.8000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.4420 0.3940 17.8880 N 0 0 0 0 0 0 0 0 0 0 0 0 + 5.3560 1.0310 18.3370 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.0510 1.1690 19.6760 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 1 0 + 3 2 1 1 + 4 3 1 0 + 5 4 1 0 + 5 3 1 0 + 5 6 1 6 + 7 6 2 0 + 8 6 1 0 + 9 8 1 0 + 10 9 2 0 + 11 10 1 0 + 12 9 1 0 + 13 12 2 0 + 14 13 1 0 + 15 14 2 0 + 15 10 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x11346.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x11346.mol new file mode 100644 index 0000000..23131ec --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x11346.mol @@ -0,0 +1,42 @@ + + RDKit 3D + + 18 19 0 0 0 0 0 0 0 0999 V2000 + 8.5870 0.8890 21.3780 O 0 0 0 0 0 0 0 0 0 0 0 0 + 8.2350 -0.2700 21.1730 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.8690 -1.4380 21.9040 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.8630 -0.9400 22.9260 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.1810 -0.6990 22.5620 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.0550 -0.0310 23.4050 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.4470 0.3220 22.9490 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.5950 0.3510 24.6590 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.4440 -0.5620 24.1960 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.2970 0.0880 25.0770 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.8170 0.5220 26.4410 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.4030 -0.6210 20.1470 N 0 0 0 0 0 0 0 0 0 0 0 0 + 6.5480 0.0260 19.2880 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.7650 1.1420 19.5790 N 0 0 0 0 0 0 0 0 0 0 0 0 + 5.4510 1.7080 20.8890 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.2640 1.5710 18.4130 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.6650 0.8090 17.4390 N 0 0 0 0 0 0 0 0 0 0 0 0 + 6.4720 -0.1800 17.9840 N 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 2 0 + 3 2 1 0 + 4 3 1 0 + 5 4 2 0 + 6 5 1 0 + 7 6 1 0 + 8 6 2 0 + 9 4 1 0 + 10 9 2 0 + 10 8 1 0 + 11 10 1 0 + 12 2 1 0 + 13 12 1 0 + 14 13 1 0 + 15 14 1 0 + 16 14 1 0 + 17 16 2 0 + 18 17 1 0 + 18 13 2 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x11354.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x11354.mol new file mode 100644 index 0000000..b28ccfc --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x11354.mol @@ -0,0 +1,49 @@ + + RDKit 3D + + 21 23 0 0 0 0 0 0 0 0999 V2000 + 9.2620 0.7430 21.0970 O 0 0 0 0 0 0 0 0 0 0 0 0 + 8.7880 -0.3310 21.4630 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.3480 -0.7060 21.1660 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.6930 0.0160 20.0070 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.1670 -0.1320 18.7150 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.6020 0.4170 17.6350 N 0 0 0 0 0 0 0 0 0 0 0 0 + 5.4990 1.1470 17.8290 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.9520 1.3720 19.0750 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.5520 0.8130 20.1970 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.9980 1.1100 21.5670 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.4720 -1.2620 22.1790 N 0 0 0 0 0 0 0 0 0 0 0 0 + 10.8230 -1.2920 22.6320 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.1320 -1.9510 23.8460 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.0360 -2.5500 24.6920 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.4870 -2.9350 26.0330 N 0 0 0 0 0 0 0 0 0 0 0 0 + 11.7770 -3.6530 25.9900 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.8810 -2.7410 25.5120 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.4780 -2.0320 24.2410 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.4660 -1.4540 23.4480 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.1440 -0.8060 22.2710 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.8280 -0.7260 21.8550 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 2 0 + 3 2 1 0 + 4 3 1 0 + 5 4 2 0 + 6 5 1 0 + 7 6 2 0 + 8 7 1 0 + 9 8 2 0 + 9 4 1 0 + 10 9 1 0 + 11 2 1 0 + 12 11 1 0 + 13 12 1 0 + 14 13 1 0 + 15 14 1 0 + 16 15 1 0 + 17 16 1 0 + 18 17 1 0 + 18 13 2 0 + 19 18 1 0 + 20 19 2 0 + 21 12 2 0 + 21 20 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x11366.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x11366.mol new file mode 100644 index 0000000..e36c5da --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x11366.mol @@ -0,0 +1,60 @@ + + RDKit 3D + + 26 29 0 0 0 0 0 0 0 0999 V2000 + 6.5590 1.0590 16.9220 O 0 0 0 0 0 0 0 0 0 0 0 0 + 5.9650 0.8300 17.9730 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.2890 -0.2450 18.8450 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.9710 1.6710 18.4020 N 0 0 0 0 0 0 0 0 0 0 0 0 + 4.3080 1.5480 19.6160 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.6520 0.4950 20.4890 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.9820 0.3780 21.7080 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2.9700 1.2680 22.0340 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2.6200 2.2790 21.1650 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.2910 2.4390 19.9630 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.6920 -0.4360 20.0490 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.0800 -1.6390 20.8380 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.5630 -2.7120 20.5620 O 0 0 0 0 0 0 0 0 0 0 0 0 + 6.9900 -1.5190 21.8210 N 0 0 0 0 0 0 0 0 0 0 0 0 + 7.2690 -2.6200 22.7540 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.7550 -2.9580 22.7280 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.8020 -0.3180 22.0630 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.2850 -0.6720 22.0500 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.5600 -1.7580 22.9980 N 0 0 0 0 0 0 0 0 0 0 0 0 + 10.8990 -1.9390 23.4590 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.1610 -2.7360 24.5960 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.1310 -3.4040 25.1700 F 0 0 0 0 0 0 0 0 0 0 0 0 + 11.9900 -1.3300 22.8410 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.2690 -1.4990 23.3560 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.4820 -2.2680 24.4900 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.4220 -2.8960 25.1200 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 2 0 + 3 2 1 0 + 4 2 1 0 + 5 4 1 0 + 6 5 2 0 + 7 6 1 0 + 8 7 2 0 + 9 8 1 0 + 10 9 2 0 + 10 5 1 0 + 11 6 1 0 + 11 3 2 0 + 12 11 1 0 + 13 12 2 0 + 14 12 1 0 + 15 14 1 0 + 16 15 1 0 + 17 14 1 0 + 18 17 1 0 + 19 18 1 0 + 19 16 1 0 + 20 19 1 0 + 21 20 2 0 + 22 21 1 0 + 23 20 1 0 + 24 23 2 0 + 25 24 1 0 + 26 25 2 0 + 26 21 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x11368.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x11368.mol new file mode 100644 index 0000000..73148fa --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x11368.mol @@ -0,0 +1,42 @@ + + RDKit 3D + + 18 19 0 0 0 0 0 0 0 0999 V2000 + 13.7300 -1.9080 21.3300 Br 0 0 0 0 0 0 0 0 0 0 0 0 + 12.4340 -0.9800 22.3590 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.8520 -0.0310 23.2720 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.8940 0.5870 24.0610 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.5520 0.2830 23.8940 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.1060 -1.3040 22.1910 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.1450 -0.6440 22.9450 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.6810 -0.8690 22.6530 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.2440 -0.1030 21.4220 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.8610 0.8770 21.0120 O 0 0 0 0 0 0 0 0 0 0 0 0 + 7.0990 -0.5470 20.8720 N 0 0 0 0 0 0 0 0 0 0 0 0 + 6.4550 0.0670 19.7750 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.3110 0.8510 19.9910 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.7370 1.0700 21.3680 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.9660 -0.0380 18.4850 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.4280 0.5810 17.4300 N 0 0 0 0 0 0 0 0 0 0 0 0 + 5.3390 1.3270 17.6460 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.7530 1.4810 18.8850 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 1 0 + 3 2 2 0 + 4 3 1 0 + 5 4 2 0 + 6 2 1 0 + 7 5 1 0 + 7 6 2 0 + 8 7 1 0 + 9 8 1 0 + 10 9 2 0 + 11 9 1 0 + 12 11 1 0 + 13 12 2 0 + 14 13 1 0 + 15 12 1 0 + 16 15 2 0 + 17 16 1 0 + 18 17 2 0 + 18 13 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x11372.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x11372.mol new file mode 100644 index 0000000..c0c7259 --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x11372.mol @@ -0,0 +1,50 @@ + + RDKit 3D + + 22 23 0 0 0 0 0 0 0 0999 V2000 + 13.8980 -1.6030 21.0620 Cl 0 0 0 0 0 0 0 0 0 0 0 0 + 12.8400 -0.6570 22.0730 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.3860 0.2720 22.9340 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.5410 0.9660 23.7850 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.1750 0.7360 23.7520 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.4790 -0.8850 22.0160 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.6290 -0.1760 22.8600 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.1220 -0.3960 22.7890 C 0 0 2 0 0 0 0 0 0 0 0 0 + 8.7510 -1.7860 23.3460 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.5920 0.1550 21.4540 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.0460 1.1820 20.9640 O 0 0 0 0 0 0 0 0 0 0 0 0 + 7.5390 -0.5130 20.9050 N 0 0 0 0 0 0 0 0 0 0 0 0 + 6.7750 -0.0460 19.8130 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.5670 0.6260 20.0490 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.0980 0.7410 21.3780 N 0 0 0 0 0 0 0 0 0 0 0 0 + 3.9000 1.1840 21.8330 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.7420 1.1520 23.3240 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2.9980 1.5710 21.0900 O 0 0 0 0 0 0 0 0 0 0 0 0 + 4.8850 1.1870 18.9720 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.4430 1.0540 17.7160 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.5930 0.4140 17.4670 N 0 0 0 0 0 0 0 0 0 0 0 0 + 7.2350 -0.1310 18.5030 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 1 0 + 3 2 2 0 + 4 3 1 0 + 5 4 2 0 + 6 2 1 0 + 7 6 2 0 + 7 5 1 0 + 8 7 1 0 + 8 9 1 6 + 10 8 1 0 + 11 10 2 0 + 12 10 1 0 + 13 12 1 0 + 14 13 2 0 + 15 14 1 0 + 16 15 1 0 + 17 16 1 0 + 18 16 2 0 + 19 14 1 0 + 20 19 2 0 + 21 20 1 0 + 22 21 2 0 + 22 13 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x11417.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x11417.mol new file mode 100644 index 0000000..b6d3585 --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x11417.mol @@ -0,0 +1,46 @@ + + RDKit 3D + + 20 21 0 0 0 0 0 0 0 0999 V2000 + 9.2440 0.5290 20.9690 O 0 0 0 0 0 0 0 0 0 0 0 0 + 8.5070 -0.3180 21.4670 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.2740 -0.6280 21.0000 N 0 0 0 0 0 0 0 0 0 0 0 0 + 6.5880 -0.0130 19.9210 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.4200 0.7380 20.1650 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.8320 0.8800 21.5440 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.8210 1.3570 19.0770 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.3800 1.2210 17.8230 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.4820 0.5080 17.5760 N 0 0 0 0 0 0 0 0 0 0 0 0 + 7.0650 -0.0990 18.6130 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.9240 -1.0920 22.7080 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.3230 -0.8750 23.0680 N 0 0 0 0 0 0 0 0 0 0 0 0 + 11.1280 -2.0480 22.7010 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.5970 -1.8310 23.0410 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.4660 -0.5970 24.5100 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.9340 -0.3720 24.8750 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.7360 -1.5340 24.4680 N 0 0 0 0 0 0 0 0 0 0 0 0 + 13.4560 -2.3220 25.3010 C 0 0 0 0 0 0 0 0 0 0 0 0 + 14.5480 -1.9740 25.7020 O 0 0 0 0 0 0 0 0 0 0 0 0 + 12.8720 -3.6350 25.7080 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 2 0 + 3 2 1 0 + 4 3 1 0 + 5 4 2 0 + 6 5 1 0 + 7 5 1 0 + 8 7 2 0 + 9 8 1 0 + 10 9 2 0 + 10 4 1 0 + 11 2 1 0 + 12 11 1 0 + 13 12 1 0 + 14 13 1 0 + 15 12 1 0 + 16 15 1 0 + 17 16 1 0 + 17 14 1 0 + 18 17 1 0 + 19 18 2 0 + 20 18 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x11424.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x11424.mol new file mode 100644 index 0000000..8ef7a79 --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x11424.mol @@ -0,0 +1,47 @@ + + RDKit 3D + + 20 22 0 0 0 0 0 0 0 0999 V2000 + 8.7230 0.6180 20.8910 O 0 0 0 0 0 0 0 0 0 0 0 0 + 8.1440 -0.2500 21.5450 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.8870 -1.2190 22.4420 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.3050 -0.7850 22.7350 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.5760 0.3030 23.5570 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.8790 0.7480 23.7390 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.9270 0.1160 23.0880 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.3610 -1.4380 22.1180 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.6430 -0.9660 22.2780 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.9250 -1.7150 21.3630 Cl 0 0 0 0 0 0 0 0 0 0 0 0 + 6.8000 -0.3920 21.5910 N 0 0 0 0 0 0 0 0 0 0 0 0 + 5.8230 0.3910 20.9290 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.8870 0.5350 19.5320 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.7150 0.0930 18.4710 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.3100 0.5680 17.3100 N 0 0 0 0 0 0 0 0 0 0 0 0 + 5.2080 1.3320 17.5780 N 0 0 0 0 0 0 0 0 0 0 0 0 + 4.9120 1.3350 18.9040 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.8990 1.9620 19.6200 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.8480 1.7910 20.9950 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.7990 1.0200 21.6460 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 2 0 + 3 2 1 0 + 4 3 1 0 + 5 4 2 0 + 6 5 1 0 + 7 6 2 0 + 8 4 1 0 + 9 8 2 0 + 9 7 1 0 + 10 9 1 0 + 11 2 1 0 + 12 11 1 0 + 13 12 2 0 + 14 13 1 0 + 15 14 2 0 + 16 15 1 0 + 17 16 1 0 + 17 13 1 0 + 18 17 2 0 + 19 18 1 0 + 20 19 2 0 + 20 12 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x11426.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x11426.mol new file mode 100644 index 0000000..a1f6b8c --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x11426.mol @@ -0,0 +1,38 @@ + + RDKit 3D + + 16 17 0 0 0 0 0 0 0 0999 V2000 + 13.7660 -1.8420 21.3540 Cl 0 0 0 0 0 0 0 0 0 0 0 0 + 12.5750 -0.9540 22.2700 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.9780 0.1040 23.0570 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.0200 0.7940 23.7840 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.6820 0.4400 23.6900 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.2490 -1.3270 22.1800 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.2800 -0.6000 22.8640 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.8200 -0.8270 22.5530 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.4270 -0.3190 21.1600 C 0 0 2 0 0 0 0 0 0 0 0 0 + 8.7990 1.0620 21.0360 O 0 0 0 0 0 0 0 0 0 0 0 0 + 6.9300 -0.4970 20.9320 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.5050 -0.0130 19.6210 N 0 0 0 0 0 0 0 0 0 0 0 0 + 5.4530 0.8350 19.5050 N 0 0 0 0 0 0 0 0 0 0 0 0 + 5.4280 1.0630 18.2110 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.3800 0.4310 17.4930 N 0 0 0 0 0 0 0 0 0 0 0 0 + 7.0260 -0.2400 18.4200 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 1 0 + 3 2 2 0 + 4 3 1 0 + 5 4 2 0 + 6 2 1 0 + 7 5 1 0 + 7 6 2 0 + 8 7 1 0 + 9 8 1 0 + 9 10 1 1 + 11 9 1 0 + 12 11 1 0 + 13 12 1 0 + 14 13 2 0 + 15 14 1 0 + 16 15 2 0 + 16 12 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x11427.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x11427.mol new file mode 100644 index 0000000..518e089 --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x11427.mol @@ -0,0 +1,44 @@ + + RDKit 3D + + 19 20 0 0 0 0 0 0 0 0999 V2000 + 11.5320 -4.2200 26.0040 F 0 0 0 0 0 0 0 0 0 0 0 0 + 12.0450 -3.1780 25.2790 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.3830 -2.9110 25.3830 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.8950 -1.8830 24.6070 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.0650 -1.1430 23.7730 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.1890 -2.4600 24.4610 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.7030 -1.4080 23.7030 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.7880 -0.5070 22.9080 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.5590 -1.1610 22.2340 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.7960 -0.1860 21.3610 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.2670 0.9080 21.0470 O 0 0 0 0 0 0 0 0 0 0 0 0 + 7.5800 -0.6230 20.9430 N 0 0 0 0 0 0 0 0 0 0 0 0 + 6.7990 -0.0030 19.9230 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.6070 0.6900 20.2460 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.1200 0.8270 21.6660 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.2060 -0.0250 18.5860 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.5360 0.5700 17.5930 N 0 0 0 0 0 0 0 0 0 0 0 0 + 5.4020 1.2050 17.9160 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.9130 1.2920 19.2040 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 1 0 + 3 2 2 0 + 4 3 1 0 + 5 4 2 0 + 6 2 1 0 + 7 6 2 0 + 7 5 1 0 + 8 7 1 0 + 9 8 1 0 + 10 9 1 0 + 11 10 2 0 + 12 10 1 0 + 13 12 1 0 + 14 13 2 0 + 15 14 1 0 + 16 13 1 0 + 17 16 2 0 + 18 17 1 0 + 19 18 2 0 + 19 14 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x11428.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x11428.mol new file mode 100644 index 0000000..2df34b9 --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x11428.mol @@ -0,0 +1,40 @@ + + RDKit 3D + + 17 18 0 0 0 0 0 0 0 0999 V2000 + 9.2810 0.5870 20.8940 O 0 0 0 0 0 0 0 0 0 0 0 0 + 8.5470 -0.1660 21.5290 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.2660 -0.4350 21.1960 N 0 0 0 0 0 0 0 0 0 0 0 0 + 6.5960 0.1020 20.0680 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.1480 -0.0060 18.7870 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.5730 0.5090 17.6940 N 0 0 0 0 0 0 0 0 0 0 0 0 + 5.4040 1.1460 17.8600 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.7800 1.3030 19.0850 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.3750 0.7860 20.2290 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.7430 0.9940 21.5840 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.0160 -0.8040 22.8240 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.4420 -0.5650 23.0260 N 0 0 0 0 0 0 0 0 0 0 0 0 + 10.8140 -0.7050 24.4470 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.2850 -0.4060 24.6690 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.1600 -1.2780 23.7930 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.7140 -1.2110 22.3370 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.2370 -1.4990 22.2110 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 2 0 + 3 2 1 0 + 4 3 1 0 + 5 4 2 0 + 6 5 1 0 + 7 6 2 0 + 8 7 1 0 + 9 8 2 0 + 9 4 1 0 + 10 9 1 0 + 11 2 1 0 + 12 11 1 0 + 13 12 1 0 + 14 13 1 0 + 15 14 1 0 + 16 15 1 0 + 17 12 1 0 + 17 16 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x11431.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x11431.mol new file mode 100644 index 0000000..102e3c5 --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x11431.mol @@ -0,0 +1,49 @@ + + RDKit 3D + + 21 23 0 0 0 0 0 0 0 0999 V2000 + 8.8830 0.7640 21.0330 O 0 0 0 0 0 0 0 0 0 0 0 0 + 8.3880 -0.3130 21.3470 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.8790 -1.1010 22.5470 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.3330 -0.8240 22.8590 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.6910 0.0680 23.8610 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.0140 0.4430 24.0360 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.0030 -0.0780 23.2170 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.3320 -1.3820 22.0700 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.6440 -0.9970 22.2530 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.8700 -1.6620 21.2090 Cl 0 0 0 0 0 0 0 0 0 0 0 0 + 7.3390 -0.8610 20.6960 N 0 0 0 0 0 0 0 0 0 0 0 0 + 6.5630 -0.1890 19.7270 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.4850 0.6400 20.0830 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.0150 0.7110 21.5200 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.0640 1.8690 21.8070 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.0580 2.0630 20.6890 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.7690 2.3750 19.3920 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.8490 1.3700 19.0710 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.2960 1.2020 17.7780 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.3100 0.4060 17.4240 N 0 0 0 0 0 0 0 0 0 0 0 0 + 6.9300 -0.2760 18.3900 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 2 0 + 3 2 1 0 + 4 3 1 0 + 5 4 2 0 + 6 5 1 0 + 7 6 2 0 + 8 4 1 0 + 9 8 2 0 + 9 7 1 0 + 10 9 1 0 + 11 2 1 0 + 12 11 1 0 + 13 12 1 0 + 14 13 1 0 + 15 14 1 0 + 16 15 1 0 + 17 16 1 0 + 18 17 1 0 + 18 13 2 0 + 19 18 1 0 + 20 19 2 0 + 21 20 1 0 + 21 12 2 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x11432.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x11432.mol new file mode 100644 index 0000000..af3e0b8 --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x11432.mol @@ -0,0 +1,51 @@ + + RDKit 3D + + 22 24 0 0 0 0 0 0 0 0999 V2000 + 9.0080 1.1740 21.2020 O 0 0 0 0 0 0 0 0 0 0 0 0 + 8.7960 0.0560 21.6540 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.8750 -0.9140 20.9200 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.1600 -0.2550 19.8490 N 0 0 0 0 0 0 0 0 0 0 0 0 + 5.9910 0.4460 19.8920 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.1750 0.8890 20.9270 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.1030 1.7070 20.5950 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.8490 2.0520 19.2680 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.6610 1.5930 18.2410 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.7500 0.7870 18.5660 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.7700 0.2860 17.7910 N 0 0 0 0 0 0 0 0 0 0 0 0 + 7.6100 -0.3300 18.5710 N 0 0 0 0 0 0 0 0 0 0 0 0 + 9.3400 -0.3570 22.8200 N 0 0 0 0 0 0 0 0 0 0 0 0 + 8.8860 -1.5130 23.5920 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.5040 0.3340 23.3630 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.7180 -0.5620 23.3770 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.1870 -1.0940 24.5780 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.2210 -2.0120 24.5620 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.7440 -2.7230 26.0730 Cl 0 0 0 0 0 0 0 0 0 0 0 0 + 13.8290 -2.3990 23.3830 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.3770 -1.8530 22.1870 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.3290 -0.9440 22.1880 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 2 0 + 3 2 1 0 + 4 3 1 0 + 5 4 1 0 + 6 5 2 0 + 7 6 1 0 + 8 7 2 0 + 9 8 1 0 + 10 9 2 0 + 10 5 1 0 + 11 10 1 0 + 12 11 2 0 + 12 4 1 0 + 13 2 1 0 + 14 13 1 0 + 15 13 1 0 + 16 15 1 0 + 17 16 2 0 + 18 17 1 0 + 19 18 1 0 + 20 18 2 0 + 21 20 1 0 + 22 21 2 0 + 22 16 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x11454.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x11454.mol new file mode 100644 index 0000000..60acab1 --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x11454.mol @@ -0,0 +1,47 @@ + + RDKit 3D + + 20 22 0 0 0 0 0 0 0 0999 V2000 + 8.8420 0.9750 21.2870 O 0 0 0 0 0 0 0 0 0 0 0 0 + 8.4780 -0.1570 21.5940 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.9900 -0.8660 22.8330 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.4680 -0.6140 23.0290 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.9110 0.3810 23.8900 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.2440 0.7630 23.9060 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.1610 0.1330 23.0800 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.3970 -1.2750 22.2320 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.7250 -0.8950 22.2710 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.8720 -1.7380 21.2680 Cl 0 0 0 0 0 0 0 0 0 0 0 0 + 7.6080 -0.8840 20.8330 N 0 0 0 0 0 0 0 0 0 0 0 0 + 7.0200 -0.3840 19.6750 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.9590 0.4910 19.7370 N 0 0 0 0 0 0 0 0 0 0 0 0 + 5.6710 0.8360 18.4210 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.4950 0.2180 17.5740 N 0 0 0 0 0 0 0 0 0 0 0 0 + 7.3160 -0.5360 18.3620 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.2440 1.0000 20.8070 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.2300 1.8620 20.5760 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.9070 2.2390 19.2470 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.6070 1.7390 18.1880 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 2 0 + 3 2 1 0 + 4 3 1 0 + 5 4 2 0 + 6 5 1 0 + 7 6 2 0 + 8 4 1 0 + 9 8 2 0 + 9 7 1 0 + 10 9 1 0 + 11 2 1 0 + 12 11 1 0 + 13 12 1 0 + 14 13 1 0 + 15 14 2 0 + 16 15 1 0 + 16 12 2 0 + 17 13 1 0 + 18 17 2 0 + 19 18 1 0 + 20 19 2 0 + 20 14 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x11458.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x11458.mol new file mode 100644 index 0000000..658ab15 --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x11458.mol @@ -0,0 +1,51 @@ + + RDKit 3D + + 22 24 0 0 0 0 0 0 0 0999 V2000 + 8.8390 0.5980 21.2610 O 0 0 0 0 0 0 0 0 0 0 0 0 + 8.2800 -0.4850 21.4150 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.2640 -0.9210 20.6420 N 0 0 0 0 0 0 0 0 0 0 0 0 + 6.5640 -0.2130 19.6480 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.4280 0.5600 20.0350 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.9670 0.6700 21.3700 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.8910 1.4540 21.6780 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.2240 2.1600 20.6890 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.6260 2.0840 19.3880 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.7360 1.2820 19.0250 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.2160 1.1810 17.6980 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.2710 0.4670 17.3420 N 0 0 0 0 0 0 0 0 0 0 0 0 + 6.9190 -0.2030 18.3030 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.6760 -1.4180 22.5380 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.1040 -1.1450 22.9310 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.1360 -1.4010 22.0910 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.4360 -0.8840 22.3250 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.4330 -1.1280 21.4300 C 0 0 0 0 0 0 0 0 0 0 0 0 + 14.2870 -1.3480 20.6380 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.6230 -0.0980 23.5150 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.5880 0.0960 24.3900 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.3270 -0.4270 24.1150 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 2 0 + 3 2 1 0 + 4 3 1 0 + 5 4 1 0 + 6 5 2 0 + 7 6 1 0 + 8 7 2 0 + 9 8 1 0 + 10 9 2 0 + 10 5 1 0 + 11 10 1 0 + 12 11 2 0 + 13 12 1 0 + 13 4 2 0 + 14 2 1 0 + 15 14 1 0 + 16 15 2 0 + 17 16 1 0 + 18 17 1 0 + 19 18 3 0 + 20 17 2 0 + 21 20 1 0 + 22 15 1 0 + 22 21 2 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x11473.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x11473.mol new file mode 100644 index 0000000..6afe59a --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x11473.mol @@ -0,0 +1,40 @@ + + RDKit 3D + + 17 18 0 0 0 0 0 0 0 0999 V2000 + 13.5630 -1.8070 21.3990 Cl 0 0 0 0 0 0 0 0 0 0 0 0 + 12.3640 -0.9320 22.3100 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.7720 0.0400 23.1960 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.8120 0.6980 23.9450 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.4690 0.3970 23.7820 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.0270 -1.2450 22.1350 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.0600 -0.5630 22.8670 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.5900 -0.7810 22.5830 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.1870 -0.0020 21.3460 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.7740 1.0220 21.0010 O 0 0 0 0 0 0 0 0 0 0 0 0 + 7.1120 -0.5070 20.6680 N 0 0 0 0 0 0 0 0 0 0 0 0 + 6.6450 0.0350 19.4700 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.6520 0.9890 19.3570 N 0 0 0 0 0 0 0 0 0 0 0 0 + 4.9700 1.7090 20.4320 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.0680 -0.2510 18.2130 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.3510 0.4920 17.3040 N 0 0 0 0 0 0 0 0 0 0 0 0 + 5.5150 1.2070 18.0280 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 1 0 + 3 2 2 0 + 4 3 1 0 + 5 4 2 0 + 6 2 1 0 + 7 5 1 0 + 7 6 2 0 + 8 7 1 0 + 9 8 1 0 + 10 9 2 0 + 11 9 1 0 + 12 11 1 0 + 13 12 1 0 + 14 13 1 0 + 15 12 2 0 + 16 15 1 0 + 17 16 2 0 + 17 13 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x11475.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x11475.mol new file mode 100644 index 0000000..32f4e36 --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x11475.mol @@ -0,0 +1,47 @@ + + RDKit 3D + + 20 22 0 0 0 0 0 0 0 0999 V2000 + 13.8980 -2.6560 23.6140 Cl 0 0 0 0 0 0 0 0 0 0 0 0 + 12.7950 -1.3520 23.3030 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.2330 -0.0560 23.4590 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.3160 0.9740 23.3580 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.9890 0.7040 23.0770 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.4950 -1.6480 22.9510 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.5870 -0.6050 22.8300 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.3130 -0.8220 22.2470 N 0 0 0 0 0 0 0 0 0 0 0 0 + 8.4710 -1.9800 22.5760 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.2110 -1.7480 21.7740 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.7220 0.0250 21.3400 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.1860 1.0640 20.9200 O 0 0 0 0 0 0 0 0 0 0 0 0 + 7.4950 -0.5160 21.0230 N 0 0 0 0 0 0 0 0 0 0 0 0 + 6.6310 0.0040 20.0060 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.4780 0.7360 20.2850 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.9630 0.9260 21.6890 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.0690 -0.0980 18.6920 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.4470 0.4830 17.6610 N 0 0 0 0 0 0 0 0 0 0 0 0 + 5.3370 1.1760 17.9350 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.8250 1.3260 19.2090 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 1 0 + 3 2 2 0 + 4 3 1 0 + 5 4 2 0 + 6 2 1 0 + 7 6 2 0 + 7 5 1 0 + 8 7 1 0 + 9 8 1 0 + 10 9 1 0 + 11 8 1 0 + 12 11 2 0 + 13 11 1 0 + 13 10 1 0 + 14 13 1 0 + 15 14 2 0 + 16 15 1 0 + 17 14 1 0 + 18 17 2 0 + 19 18 1 0 + 20 19 2 0 + 20 15 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x11485.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x11485.mol new file mode 100644 index 0000000..a653c3f --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x11485.mol @@ -0,0 +1,42 @@ + + RDKit 3D + + 18 19 0 0 0 0 0 0 0 0999 V2000 + 13.8100 -1.8340 21.4510 Cl 0 0 0 0 0 0 0 0 0 0 0 0 + 12.6090 -1.0000 22.4000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.0160 -0.1120 23.3780 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.0530 0.4430 24.2100 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.7110 0.1640 24.0070 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.2750 -1.2950 22.1950 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.3060 -0.6820 22.9810 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.8420 -0.8750 22.6640 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.3890 -0.0380 21.4840 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.9860 0.9810 21.1220 O 0 0 0 0 0 0 0 0 0 0 0 0 + 7.2470 -0.4690 20.9150 N 0 0 0 0 0 0 0 0 0 0 0 0 + 6.5680 0.1440 19.8640 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.3590 0.8440 20.1050 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.7590 0.9850 21.4820 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.1510 0.1430 18.6650 N 0 0 0 0 0 0 0 0 0 0 0 0 + 6.5990 0.8030 17.6280 N 0 0 0 0 0 0 0 0 0 0 0 0 + 5.4590 1.4680 17.8000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.8100 1.5050 19.0180 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 1 0 + 3 2 2 0 + 4 3 1 0 + 5 4 2 0 + 6 2 1 0 + 7 5 1 0 + 7 6 2 0 + 8 7 1 0 + 9 8 1 0 + 10 9 2 0 + 11 9 1 0 + 12 11 1 0 + 13 12 2 0 + 14 13 1 0 + 15 12 1 0 + 16 15 2 0 + 17 16 1 0 + 18 13 1 0 + 18 17 2 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x11488.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x11488.mol new file mode 100644 index 0000000..b232b1e --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x11488.mol @@ -0,0 +1,50 @@ + + RDKit 3D + + 22 23 0 0 0 0 0 0 0 0999 V2000 + 13.7880 -1.8590 21.3950 Cl 0 0 0 0 0 0 0 0 0 0 0 0 + 12.6500 -0.8620 22.2620 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.0940 0.2920 22.8760 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.1630 1.1200 23.4890 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.8190 0.7790 23.4870 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.3180 -1.2200 22.2650 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.3830 -0.3870 22.8700 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.8930 -0.7000 22.7530 C 0 0 1 0 0 0 0 0 0 0 0 0 + 8.1600 -0.2620 24.0150 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.4650 0.7130 24.0990 O 0 0 0 0 0 0 0 0 0 0 0 0 + 8.4310 -1.0880 25.0280 O 0 0 0 0 0 0 0 0 0 0 0 0 + 8.0090 -0.6650 26.3470 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.3220 0.0500 21.5260 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.8340 1.0780 21.0990 O 0 0 0 0 0 0 0 0 0 0 0 0 + 7.2280 -0.5140 20.9810 N 0 0 0 0 0 0 0 0 0 0 0 0 + 6.5280 0.0810 19.8980 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.3750 0.8460 20.1480 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.8220 1.0250 21.5400 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.7790 1.4780 19.0620 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.3240 1.3330 17.8010 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.4190 0.6020 17.5490 N 0 0 0 0 0 0 0 0 0 0 0 0 + 7.0010 -0.0080 18.5870 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 1 0 + 3 2 2 0 + 4 3 1 0 + 5 4 2 0 + 6 2 1 0 + 7 5 1 0 + 7 6 2 0 + 8 7 1 0 + 8 9 1 1 + 10 9 2 0 + 11 9 1 0 + 12 11 1 0 + 13 8 1 0 + 14 13 2 0 + 15 13 1 0 + 16 15 1 0 + 17 16 2 0 + 18 17 1 0 + 19 17 1 0 + 20 19 2 0 + 21 20 1 0 + 22 21 2 0 + 22 16 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x11493.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x11493.mol new file mode 100644 index 0000000..4a10b92 --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x11493.mol @@ -0,0 +1,47 @@ + + RDKit 3D + + 20 22 0 0 0 0 0 0 0 0999 V2000 + 8.5970 0.7890 20.7700 O 0 0 0 0 0 0 0 0 0 0 0 0 + 8.1710 -0.3630 20.8120 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.8110 -1.4380 21.6690 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.0660 -0.9810 22.3700 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.0130 -0.1790 23.5030 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.1750 0.3140 24.0770 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.4100 -0.0010 23.5300 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.3060 -1.3260 21.8500 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.4520 -0.8490 22.4410 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.9880 -1.4320 21.8660 Cl 0 0 0 0 0 0 0 0 0 0 0 0 + 7.1340 -0.7940 20.0400 N 0 0 0 0 0 0 0 0 0 0 0 0 + 6.3500 0.0690 19.3100 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.3400 0.7450 19.9310 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.7120 1.4460 18.9050 N 0 0 0 0 0 0 0 0 0 0 0 0 + 5.3920 1.1600 17.7510 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.3990 0.3290 17.9470 N 0 0 0 0 0 0 0 0 0 0 0 0 + 4.8090 0.8450 21.2420 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.6950 1.6010 21.4600 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.0730 2.2960 20.3960 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.5740 2.2230 19.1450 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 2 0 + 3 2 1 0 + 4 3 1 0 + 5 4 2 0 + 6 5 1 0 + 7 6 2 0 + 8 4 1 0 + 9 8 2 0 + 9 7 1 0 + 10 9 1 0 + 11 2 1 0 + 12 11 1 0 + 13 12 2 0 + 14 13 1 0 + 15 14 1 0 + 16 15 2 0 + 16 12 1 0 + 17 13 1 0 + 18 17 2 0 + 19 18 1 0 + 20 19 2 0 + 20 14 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x11498.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x11498.mol new file mode 100644 index 0000000..04e2611 --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x11498.mol @@ -0,0 +1,56 @@ + + RDKit 3D + + 24 27 0 0 0 0 0 0 0 0999 V2000 + 9.0750 0.9330 21.0680 O 0 0 0 0 0 0 0 0 0 0 0 0 + 8.5980 -0.1580 21.3640 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.0830 -0.9600 22.5730 C 0 0 2 0 0 0 0 0 0 0 0 0 + 8.2800 -0.5370 23.8130 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.7940 0.7810 24.3340 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.1940 0.7090 24.6880 O 0 0 0 0 0 0 0 0 0 0 0 0 + 10.5680 -0.7060 22.7430 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.0250 0.1500 23.7490 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.3720 0.4550 23.8820 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.2900 -0.1090 23.0150 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.5100 -1.2860 21.8960 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.8480 -0.9830 22.0470 C 0 0 0 0 0 0 0 0 0 0 0 0 + 14.0100 -1.7520 21.0040 Cl 0 0 0 0 0 0 0 0 0 0 0 0 + 7.6260 -0.7540 20.6530 N 0 0 0 0 0 0 0 0 0 0 0 0 + 6.7050 -0.2150 19.7470 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.5850 0.5400 20.2190 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.1680 0.5750 21.5770 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.0580 1.2770 21.9550 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.3100 1.9760 21.0190 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.6720 1.9820 19.7040 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.8180 1.2690 19.2670 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.2390 1.2340 17.9160 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.3020 0.5650 17.4850 N 0 0 0 0 0 0 0 0 0 0 0 0 + 6.9920 -0.1470 18.3840 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 2 0 + 3 2 1 6 + 4 3 1 0 + 5 4 1 0 + 6 5 1 0 + 7 3 1 0 + 8 7 2 0 + 8 6 1 0 + 9 8 1 0 + 10 9 2 0 + 11 7 1 0 + 12 11 2 0 + 12 10 1 0 + 13 12 1 0 + 14 2 1 0 + 15 14 1 0 + 16 15 1 0 + 17 16 2 0 + 18 17 1 0 + 19 18 2 0 + 20 19 1 0 + 21 20 2 0 + 21 16 1 0 + 22 21 1 0 + 23 22 2 0 + 24 23 1 0 + 24 15 2 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x11499.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x11499.mol new file mode 100644 index 0000000..69f0beb --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x11499.mol @@ -0,0 +1,49 @@ + + RDKit 3D + + 21 23 0 0 0 0 0 0 0 0999 V2000 + 8.7220 1.1160 21.3520 O 0 0 0 0 0 0 0 0 0 0 0 0 + 8.4320 -0.0740 21.3610 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.9750 -1.0160 22.4200 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.4370 -0.7590 22.7110 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.8210 0.1740 23.6680 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.1570 0.5090 23.8370 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.1310 -0.0980 23.0590 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.4200 -1.3850 21.9550 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.7450 -1.0440 22.1350 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.9550 -1.8190 21.1510 Cl 0 0 0 0 0 0 0 0 0 0 0 0 + 7.7190 -0.6680 20.3880 N 0 0 0 0 0 0 0 0 0 0 0 0 + 6.6740 -0.1960 19.5760 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.6040 0.6110 20.0910 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.1520 0.6780 21.4350 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.0420 1.2910 21.8460 N 0 0 0 0 0 0 0 0 0 0 0 0 + 3.3000 1.9180 20.9270 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.6200 1.9750 19.6110 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.7870 1.3110 19.1520 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.1100 1.1970 17.7780 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.0910 0.4460 17.3050 N 0 0 0 0 0 0 0 0 0 0 0 0 + 6.8230 -0.2420 18.1890 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 2 0 + 3 2 1 0 + 4 3 1 0 + 5 4 2 0 + 6 5 1 0 + 7 6 2 0 + 8 4 1 0 + 9 8 2 0 + 9 7 1 0 + 10 9 1 0 + 11 2 1 0 + 12 11 1 0 + 13 12 1 0 + 14 13 2 0 + 15 14 1 0 + 16 15 2 0 + 17 16 1 0 + 18 17 2 0 + 18 13 1 0 + 19 18 1 0 + 20 19 2 0 + 21 20 1 0 + 21 12 2 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x11541.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x11541.mol new file mode 100644 index 0000000..64368dd --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x11541.mol @@ -0,0 +1,53 @@ + + RDKit 3D + + 23 25 0 0 0 0 0 0 0 0999 V2000 + 9.4820 0.9530 21.0490 O 0 0 0 0 0 0 0 0 0 0 0 0 + 9.1380 -0.1910 21.3290 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.9880 -0.7520 20.8960 N 0 0 0 0 0 0 0 0 0 0 0 0 + 7.1120 -0.2230 19.9230 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.8860 0.3840 20.3330 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.4400 0.4320 21.6770 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.2760 1.0620 22.0080 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.5010 1.6700 21.0360 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.8830 1.6470 19.7250 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.0830 1.0080 19.3380 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.5500 0.9830 18.0060 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.6960 0.4410 17.6320 N 0 0 0 0 0 0 0 0 0 0 0 0 + 7.4400 -0.1460 18.5770 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.0240 -1.0990 22.1670 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.2780 -1.9200 23.1120 N 0 0 0 0 0 0 0 0 0 0 0 0 + 8.6610 -1.1020 24.1540 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.7450 -1.9610 25.0120 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.1360 -2.9180 23.7530 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.2870 -3.8610 24.6050 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.4880 -3.1000 25.5800 N 0 0 0 0 0 0 0 0 0 0 0 0 + 8.3430 -3.4260 26.8920 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.6520 -2.7400 27.6370 O 0 0 0 0 0 0 0 0 0 0 0 0 + 9.0200 -4.6640 27.3960 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 2 0 + 3 2 1 0 + 4 3 1 0 + 5 4 1 0 + 6 5 2 0 + 7 6 1 0 + 8 7 2 0 + 9 8 1 0 + 10 9 2 0 + 10 5 1 0 + 11 10 1 0 + 12 11 2 0 + 13 12 1 0 + 13 4 2 0 + 14 2 1 0 + 15 14 1 0 + 16 15 1 0 + 17 16 1 0 + 18 15 1 0 + 19 18 1 0 + 20 19 1 0 + 20 17 1 0 + 21 20 1 0 + 22 21 2 0 + 23 21 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x11562.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x11562.mol new file mode 100644 index 0000000..5350280 --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x11562.mol @@ -0,0 +1,52 @@ + + RDKit 3D + + 23 24 0 0 0 0 0 0 0 0999 V2000 + 8.9020 0.6480 20.8970 O 0 0 0 0 0 0 0 0 0 0 0 0 + 8.2700 -0.3610 21.2130 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.0520 -0.6630 20.7300 N 0 0 0 0 0 0 0 0 0 0 0 0 + 6.4090 0.0370 19.6840 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.2950 0.8410 19.9630 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.7800 1.0300 21.3680 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.7250 1.5300 18.8990 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.2760 1.4170 17.6390 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.3470 0.6610 17.3630 N 0 0 0 0 0 0 0 0 0 0 0 0 + 6.8950 -0.0150 18.3780 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.8030 -1.3740 22.2060 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.1200 -0.8970 22.7690 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.3160 -1.3800 22.2530 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.5110 -0.8700 22.7070 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.9970 -1.5480 22.1030 Cl 0 0 0 0 0 0 0 0 0 0 0 0 + 12.5590 0.1080 23.6780 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.3760 0.5710 24.2320 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.1640 0.0870 23.7590 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.9490 0.6260 24.1060 O 0 0 0 0 0 0 0 0 0 0 0 0 + 8.4930 0.5100 25.4700 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.0050 0.7880 25.5140 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.1190 -0.3050 24.9180 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.6440 0.0200 25.0410 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 2 0 + 3 2 1 0 + 4 3 1 0 + 5 4 2 0 + 6 5 1 0 + 7 5 1 0 + 8 7 2 0 + 9 8 1 0 + 10 9 2 0 + 10 4 1 0 + 11 2 1 0 + 12 11 1 0 + 13 12 2 0 + 14 13 1 0 + 15 14 1 0 + 16 14 2 0 + 17 16 1 0 + 18 12 1 0 + 18 17 2 0 + 19 18 1 0 + 20 19 1 0 + 21 20 1 0 + 22 21 1 0 + 23 22 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x11564.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x11564.mol new file mode 100644 index 0000000..05ea822 --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x11564.mol @@ -0,0 +1,61 @@ + + RDKit 3D + + 27 29 0 0 0 0 0 0 0 0999 V2000 + 8.6870 1.0200 20.8300 O 0 0 0 0 0 0 0 0 0 0 0 0 + 8.1900 -0.0030 21.2820 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.0450 -0.5390 20.8080 N 0 0 0 0 0 0 0 0 0 0 0 0 + 6.3080 0.0350 19.7340 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.1890 0.8420 20.0080 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.6910 1.0640 21.4140 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.5900 1.4890 18.9340 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.1100 1.3330 17.6640 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.1760 0.5680 17.3900 N 0 0 0 0 0 0 0 0 0 0 0 0 + 6.7500 -0.0730 18.4150 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.8210 -0.7390 22.4480 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.2120 -0.2310 22.7660 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.3080 -1.0750 22.6400 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.5750 -0.5780 22.8610 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.9280 -1.6720 22.8070 Cl 0 0 0 0 0 0 0 0 0 0 0 0 + 12.7970 0.7450 23.1870 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.4230 1.0970 23.1280 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.7080 1.6080 23.3320 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.9170 3.0370 23.7110 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.0840 3.6860 23.2950 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.3750 4.9800 23.7070 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.0550 3.7710 24.5220 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.9430 3.1900 25.0040 F 0 0 0 0 0 0 0 0 0 0 0 0 + 11.3300 5.0650 24.9070 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.4330 5.7320 25.6610 F 0 0 0 0 0 0 0 0 0 0 0 0 + 12.5150 5.7040 24.5410 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.9040 7.0660 25.0590 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 2 0 + 3 2 1 0 + 4 3 1 0 + 5 4 2 0 + 6 5 1 0 + 7 5 1 0 + 8 7 2 0 + 9 8 1 0 + 10 9 2 0 + 10 4 1 0 + 11 2 1 0 + 12 11 1 0 + 13 12 2 0 + 14 13 1 0 + 15 14 1 0 + 16 14 2 0 + 17 12 1 0 + 18 17 2 0 + 18 16 1 0 + 19 18 1 0 + 20 19 2 0 + 21 20 1 0 + 22 19 1 0 + 23 22 1 0 + 24 22 2 0 + 25 24 1 0 + 26 24 1 0 + 26 21 2 0 + 27 26 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x11579.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x11579.mol new file mode 100644 index 0000000..33a66e6 --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x11579.mol @@ -0,0 +1,50 @@ + + RDKit 3D + + 22 23 0 0 0 0 0 0 0 0999 V2000 + 5.5120 -5.1660 20.2160 N 0 0 0 0 0 0 0 0 0 0 0 0 + 5.7780 -5.0660 21.3260 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.1800 -4.9140 22.6800 C 0 0 2 0 0 0 0 0 0 0 0 0 + 7.4340 -4.4600 22.8970 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.2120 -3.8080 21.9530 N 0 0 0 0 0 0 0 0 0 0 0 0 + 7.7850 -3.0040 20.9390 C 0 0 2 0 0 0 0 0 0 0 0 0 + 8.8680 -2.5050 20.0100 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.6400 -2.5560 20.8820 O 0 0 0 0 0 0 0 0 0 0 0 0 + 8.0050 -4.5960 24.1230 N 0 0 0 0 0 0 0 0 0 0 0 0 + 7.3850 -5.1810 25.1910 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.2750 -5.2380 26.7010 S 0 0 0 0 0 0 0 0 0 0 0 0 + 9.9740 -5.4180 26.1480 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.3000 -5.4560 23.8010 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.1220 -5.6630 25.0730 C 0 0 1 0 0 0 0 0 0 0 0 0 + 5.5610 -6.4440 26.1160 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.0780 -7.0900 26.9300 N 0 0 0 0 0 0 0 0 0 0 0 0 + 4.6110 -6.7080 23.1970 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.1980 -6.9800 23.6990 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2.3240 -5.7510 23.5690 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2.9160 -4.6020 24.3530 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.3140 -4.2620 23.8510 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.1340 -3.0660 18.4540 S 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 1 0 + 3 2 1 6 + 4 3 1 0 + 5 4 1 0 + 6 5 1 0 + 6 7 1 0 + 6 8 1 1 + 9 4 1 0 + 10 9 1 0 + 11 10 1 0 + 12 11 1 0 + 13 3 1 0 + 14 13 1 0 + 14 10 1 0 + 14 15 1 6 + 16 15 1 0 + 13 17 1 0 + 18 17 1 0 + 19 18 1 0 + 20 19 1 0 + 21 13 1 0 + 21 20 1 0 + 7 22 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x11587.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x11587.mol new file mode 100644 index 0000000..d3c153d --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x11587.mol @@ -0,0 +1,57 @@ + + RDKit 3D + + 25 27 0 0 0 0 0 0 0 0999 V2000 + 7.0470 -7.3650 30.1900 O 0 0 0 0 0 0 0 0 0 0 0 0 + 6.7280 -6.7600 29.1750 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.6090 -6.5890 28.1750 N 0 0 0 0 0 0 0 0 0 0 0 0 + 7.4020 -5.9040 26.9840 N 0 0 0 0 0 0 0 0 0 0 0 0 + 5.4140 -6.1450 28.9740 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.1530 -5.4370 27.7890 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.8920 -4.8650 27.5960 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2.9090 -5.0120 28.5640 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.1680 -5.7140 29.7250 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.4170 -6.2750 29.9420 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.2270 -5.3400 26.7820 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.1790 -4.6060 25.4600 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.2550 -3.8410 25.1870 O 0 0 0 0 0 0 0 0 0 0 0 0 + 7.1910 -4.8710 24.6110 N 0 0 0 0 0 0 0 0 0 0 0 0 + 7.2060 -4.1990 23.4020 N 0 0 0 0 0 0 0 0 0 0 0 0 + 7.7760 -2.9830 23.1810 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.4720 -2.1940 24.2380 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.6480 -4.7200 22.2690 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.9370 -6.0280 22.2210 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.8790 -3.7800 21.2670 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.5910 -2.6980 21.8500 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.4870 -3.8580 19.8550 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.7400 -4.7540 19.4890 O 0 0 0 0 0 0 0 0 0 0 0 0 + 7.0550 -2.8430 18.8870 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.6450 -3.4550 18.4130 S 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 1 0 + 3 2 1 0 + 4 3 1 0 + 5 2 1 0 + 6 5 1 0 + 7 6 1 0 + 8 7 1 0 + 9 8 1 0 + 10 9 1 0 + 10 5 1 0 + 11 6 1 0 + 11 4 1 0 + 12 11 1 0 + 13 12 1 0 + 14 12 1 0 + 15 14 1 0 + 16 15 1 0 + 17 16 1 0 + 18 15 1 0 + 19 18 1 0 + 20 18 1 0 + 21 20 1 0 + 21 16 1 0 + 22 20 1 0 + 23 22 1 0 + 24 22 1 0 + 24 25 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x11612.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x11612.mol new file mode 100644 index 0000000..9c0a1ec --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x11612.mol @@ -0,0 +1,56 @@ + + RDKit 3D + + 24 27 0 0 0 0 0 0 0 0999 V2000 + 10.1830 0.5300 24.8720 O 0 0 0 0 0 0 0 0 0 0 0 0 + 3.9090 1.5170 21.6460 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.2760 2.1570 20.6000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.7320 2.0200 19.3210 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.8760 1.2340 19.0450 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.0720 0.8170 21.1090 O 0 0 0 0 0 0 0 0 0 0 0 0 + 11.4230 -1.3060 21.9520 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.4220 1.0840 17.7490 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.1290 -0.2210 18.5010 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.7110 -0.1630 19.8250 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.5030 -0.7720 22.8490 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.5180 -0.2110 21.4910 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.8950 -1.7240 20.9750 Cl 0 0 0 0 0 0 0 0 0 0 0 0 + 7.4250 -0.7170 20.9010 N 0 0 0 0 0 0 0 0 0 0 0 0 + 5.0070 0.7400 21.4210 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.7520 -0.9550 22.0370 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.2020 -0.0540 22.9750 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.3090 0.4620 23.8970 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.9780 0.0800 23.8470 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.7820 0.6560 24.5480 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.2260 -0.6160 23.9610 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.0150 -1.0110 22.6970 C 0 0 2 0 0 0 0 0 0 0 0 0 + 6.5140 0.3850 17.4790 N 0 0 0 0 0 0 0 0 0 0 0 0 + 5.5340 0.5830 20.1170 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3 2 2 0 + 4 3 1 0 + 5 4 2 0 + 8 5 1 0 + 10 9 2 0 + 11 7 2 0 + 12 6 2 0 + 14 12 1 0 + 14 10 1 0 + 15 2 1 0 + 16 13 1 0 + 16 7 1 0 + 17 16 2 0 + 18 17 1 0 + 19 11 1 0 + 19 1 1 0 + 19 18 2 0 + 20 1 1 0 + 21 20 1 0 + 22 12 1 6 + 22 21 1 0 + 22 11 1 0 + 23 8 2 0 + 23 9 1 0 + 24 15 2 0 + 24 5 1 0 + 24 10 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x11642.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x11642.mol new file mode 100644 index 0000000..296a71d --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x11642.mol @@ -0,0 +1,68 @@ + + RDKit 3D + + 30 33 0 0 0 0 0 0 0 0999 V2000 + 8.5830 1.0330 21.0140 O 0 0 0 0 0 0 0 0 0 0 0 0 + 8.4980 -0.1720 21.2430 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.3170 -0.9950 20.7690 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.5420 -0.2330 19.7130 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.4520 0.6030 20.0760 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.0200 0.7820 21.4170 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.9780 1.6110 21.7130 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.3140 2.2930 20.7100 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.6920 2.1600 19.4070 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.7710 1.3150 19.0550 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.2310 1.1470 17.7290 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.2540 0.3730 17.3940 N 0 0 0 0 0 0 0 0 0 0 0 0 + 6.8740 -0.2940 18.3760 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.4200 -0.8730 21.9320 N 0 0 0 0 0 0 0 0 0 0 0 0 + 10.5920 -0.3790 22.5470 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.7110 -1.1970 22.6570 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.8450 -0.6960 23.2660 C 0 0 0 0 0 0 0 0 0 0 0 0 + 14.1930 -1.7590 23.5330 Cl 0 0 0 0 0 0 0 0 0 0 0 0 + 12.9130 0.5980 23.7400 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.6300 0.9240 23.0340 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.7890 1.3970 23.6210 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.7600 2.6760 24.1730 O 0 0 0 0 0 0 0 0 0 0 0 0 + 12.3990 3.7300 23.5870 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.9870 3.5210 22.3380 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.6470 4.5950 21.7660 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.6970 5.8110 22.4230 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.4260 4.8780 24.2530 N 0 0 0 0 0 0 0 0 0 0 0 0 + 13.0590 5.8940 23.6650 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.1120 7.1020 24.2690 O 0 0 0 0 0 0 0 0 0 0 0 0 + 12.4830 7.2470 25.5530 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 2 0 + 3 2 1 0 + 4 3 1 0 + 5 4 1 0 + 6 5 2 0 + 7 6 1 0 + 8 7 2 0 + 9 8 1 0 + 10 9 2 0 + 10 5 1 0 + 11 10 1 0 + 12 11 2 0 + 13 12 1 0 + 13 4 2 0 + 14 2 1 0 + 15 14 1 0 + 16 15 2 0 + 17 16 1 0 + 18 17 1 0 + 19 17 2 0 + 20 15 1 0 + 21 20 2 0 + 21 19 1 0 + 22 21 1 0 + 23 22 1 0 + 24 23 2 0 + 25 24 1 0 + 26 25 2 0 + 27 23 1 0 + 28 27 2 0 + 28 26 1 0 + 29 28 1 0 + 30 29 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x11723.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x11723.mol new file mode 100644 index 0000000..4ab9d9b --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x11723.mol @@ -0,0 +1,59 @@ + + RDKit 3D + + 26 28 0 0 0 0 0 0 0 0999 V2000 + 8.6550 0.6220 20.8640 O 0 0 0 0 0 0 0 0 0 0 0 0 + 8.1020 -0.4640 21.0060 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.9750 -0.8200 20.3670 N 0 0 0 0 0 0 0 0 0 0 0 0 + 6.2960 -0.0290 19.4240 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.1630 0.7030 19.8140 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.6800 0.7300 21.2400 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.5410 1.4780 18.8420 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.0610 1.5150 17.5640 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.1550 0.8350 17.1890 N 0 0 0 0 0 0 0 0 0 0 0 0 + 6.7520 0.0690 18.1110 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.6380 -1.5250 21.9440 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.9290 -1.0780 22.5810 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.1470 -1.5340 22.0910 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.3170 -1.1310 22.6980 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.8250 -1.8040 22.1510 Cl 0 0 0 0 0 0 0 0 0 0 0 0 + 12.3200 -0.2640 23.7720 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.9090 -0.2190 23.6720 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.0990 0.1700 24.2650 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.1810 1.0120 25.3460 O 0 0 0 0 0 0 0 0 0 0 0 0 + 9.9830 1.6090 25.8600 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.2290 0.6560 26.7230 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.8000 -0.4810 27.1440 O 0 0 0 0 0 0 0 0 0 0 0 0 + 8.8350 -1.1190 27.9660 N 0 0 0 0 0 0 0 0 0 0 0 0 + 8.0300 0.8250 27.1630 N 0 0 0 0 0 0 0 0 0 0 0 0 + 7.8290 -0.2970 27.9300 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.5450 -0.5210 28.6440 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 2 0 + 3 2 1 0 + 4 3 1 0 + 5 4 2 0 + 6 5 1 0 + 7 5 1 0 + 8 7 2 0 + 9 8 1 0 + 10 9 2 0 + 10 4 1 0 + 11 2 1 0 + 12 11 1 0 + 13 12 2 0 + 14 13 1 0 + 15 14 1 0 + 16 14 2 0 + 17 12 1 0 + 18 17 2 0 + 18 16 1 0 + 19 18 1 0 + 20 19 1 0 + 21 20 1 0 + 22 21 1 0 + 23 22 1 0 + 24 21 2 0 + 25 24 1 0 + 25 23 2 0 + 26 25 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x11743.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x11743.mol new file mode 100644 index 0000000..8a0af3b --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x11743.mol @@ -0,0 +1,52 @@ + + RDKit 3D + + 23 24 0 0 0 0 0 0 0 0999 V2000 + 11.2790 5.5760 24.0740 O 0 0 0 0 0 0 0 0 0 0 0 0 + 10.6560 4.2940 24.0870 S 0 0 1 0 0 0 0 0 0 0 0 0 + 9.8600 3.9230 25.2110 O 0 0 0 0 0 0 0 0 0 0 0 0 + 9.6990 4.2410 22.7890 N 0 0 0 0 0 0 0 0 0 0 0 0 + 11.7600 3.0940 23.8910 N 0 0 0 0 0 0 0 0 0 0 0 0 + 11.5880 1.6990 23.5570 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.7090 0.9490 23.1980 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.5240 -0.3360 22.7170 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.9060 -1.2440 22.1690 Cl 0 0 0 0 0 0 0 0 0 0 0 0 + 11.2720 -0.9020 22.6060 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.3220 1.1190 23.4790 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.1540 -0.1700 22.9790 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.7700 -0.7170 22.7020 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.2000 -0.0770 21.4500 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.7690 0.8530 20.9000 O 0 0 0 0 0 0 0 0 0 0 0 0 + 7.0190 -0.5720 21.0210 N 0 0 0 0 0 0 0 0 0 0 0 0 + 6.3550 -0.0140 19.8980 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.2120 0.7870 20.0850 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.5910 0.9920 21.4430 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.8610 -0.1550 18.6050 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.3450 0.4560 17.5330 N 0 0 0 0 0 0 0 0 0 0 0 0 + 5.2590 1.2140 17.7250 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.6690 1.4010 18.9600 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 2 0 + 3 2 2 0 + 2 4 1 6 + 5 2 1 0 + 6 5 1 0 + 7 6 2 0 + 8 7 1 0 + 9 8 1 0 + 10 8 2 0 + 11 6 1 0 + 12 11 2 0 + 12 10 1 0 + 13 12 1 0 + 14 13 1 0 + 15 14 2 0 + 16 14 1 0 + 17 16 1 0 + 18 17 2 0 + 19 18 1 0 + 20 17 1 0 + 21 20 2 0 + 22 21 1 0 + 23 22 2 0 + 23 18 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x11764.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x11764.mol new file mode 100644 index 0000000..4c58a61 --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x11764.mol @@ -0,0 +1,57 @@ + + RDKit 3D + + 25 27 0 0 0 0 0 0 0 0999 V2000 + 13.4090 0.6560 23.7000 Cl 0 0 0 0 0 0 0 0 0 0 0 0 + 11.7460 0.2020 23.9200 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.1000 -0.4680 22.9030 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.1260 0.4830 25.1220 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.8160 0.0530 25.3140 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.1770 0.3240 26.5220 N 0 0 0 0 0 0 0 0 0 0 0 0 + 7.8200 -0.0560 26.8870 C 0 0 2 0 0 0 0 0 0 0 0 0 + 6.7760 1.0060 26.4930 C 0 0 1 0 0 0 0 0 0 0 0 0 + 6.4280 0.9400 25.1090 O 0 0 0 0 0 0 0 0 0 0 0 0 + 5.5850 0.6470 27.3700 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.1820 0.1760 28.6890 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.6380 -0.2000 28.4050 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.1580 -0.6330 24.2970 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.7870 -0.8820 23.0840 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.0350 -1.5360 21.9520 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.3820 -0.4830 21.0790 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.9220 0.5990 20.8480 O 0 0 0 0 0 0 0 0 0 0 0 0 + 7.1840 -0.8420 20.5790 N 0 0 0 0 0 0 0 0 0 0 0 0 + 6.5090 -0.1020 19.5860 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.4170 0.7050 19.9390 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.9570 0.8440 21.3660 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.9270 -0.1220 18.2540 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.3370 0.5850 17.2870 N 0 0 0 0 0 0 0 0 0 0 0 0 + 5.2820 1.3340 17.6330 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.7970 1.4210 18.9220 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 1 0 + 3 2 2 0 + 4 2 1 0 + 5 4 2 0 + 6 5 1 0 + 7 6 1 1 + 8 7 1 0 + 8 9 1 6 + 10 8 1 0 + 11 10 1 0 + 12 7 1 0 + 12 11 1 0 + 13 5 1 0 + 14 13 2 0 + 14 3 1 0 + 15 14 1 0 + 16 15 1 0 + 17 16 2 0 + 18 16 1 0 + 19 18 1 0 + 20 19 2 0 + 21 20 1 0 + 22 19 1 0 + 23 22 2 0 + 24 23 1 0 + 25 24 2 0 + 25 20 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x11790.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x11790.mol new file mode 100644 index 0000000..b181bd8 --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x11790.mol @@ -0,0 +1,66 @@ + + RDKit 3D + + 29 32 0 0 0 0 0 0 0 0999 V2000 + 9.1500 0.9950 21.1240 O 0 0 0 0 0 0 0 0 0 0 0 0 + 8.7900 -0.0410 21.6650 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.7860 -0.9510 20.9810 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.9310 -0.2210 19.9640 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.7910 0.5260 20.3700 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.3810 0.6490 21.7230 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.2950 1.4050 22.0620 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.5700 2.0780 21.0920 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.9150 1.9820 19.7750 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.0300 1.2020 19.3770 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.4490 1.0680 18.0340 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.5150 0.3720 17.6570 N 0 0 0 0 0 0 0 0 0 0 0 0 + 7.2240 -0.2420 18.6140 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.2790 -0.4250 22.8830 N 0 0 0 0 0 0 0 0 0 0 0 0 + 10.3020 0.4140 23.5010 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.7040 0.0050 23.1320 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.9630 -0.9120 22.1530 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.6260 -1.2470 21.9950 S 0 0 0 0 0 0 0 0 0 0 0 0 + 14.0190 -0.1310 23.2530 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.8990 0.4560 23.7590 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.8580 -1.6020 23.5890 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.9790 -1.4900 24.6640 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.7040 -2.5860 25.4640 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.4250 -2.8420 23.3020 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.1440 -3.9440 24.0940 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.2890 -3.8350 25.2040 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.0660 -4.9190 26.0400 N 0 0 0 0 0 0 0 0 0 0 0 0 + 9.1030 -5.9230 26.2280 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.2010 -4.8000 27.2070 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 2 0 + 3 2 1 0 + 4 3 1 0 + 5 4 1 0 + 6 5 2 0 + 7 6 1 0 + 8 7 2 0 + 9 8 1 0 + 10 9 2 0 + 10 5 1 0 + 11 10 1 0 + 12 11 2 0 + 13 12 1 0 + 13 4 2 0 + 14 2 1 0 + 15 14 1 0 + 16 15 1 0 + 17 16 2 0 + 18 17 1 0 + 19 18 1 0 + 20 19 2 0 + 20 16 1 0 + 21 14 1 0 + 22 21 2 0 + 23 22 1 0 + 24 21 1 0 + 25 24 2 0 + 26 25 1 0 + 26 23 2 0 + 27 26 1 0 + 28 27 1 0 + 29 27 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x11797.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x11797.mol new file mode 100644 index 0000000..5a6852b --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x11797.mol @@ -0,0 +1,64 @@ + + RDKit 3D + + 28 31 0 0 0 0 0 0 0 0999 V2000 + 8.9180 1.5350 21.1340 O 0 0 0 0 0 0 0 0 0 0 0 0 + 8.8170 0.4600 21.7010 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.1540 -0.7340 21.0100 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.2300 -0.3130 19.9780 N 0 0 0 0 0 0 0 0 0 0 0 0 + 6.1010 0.4430 20.0720 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.2810 0.8180 21.1280 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.1580 1.5800 20.8320 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.8740 1.9600 19.5180 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.7130 1.5940 18.4720 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.8350 0.8220 18.7590 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.8110 0.2940 17.9430 N 0 0 0 0 0 0 0 0 0 0 0 0 + 7.6430 -0.3790 18.6860 N 0 0 0 0 0 0 0 0 0 0 0 0 + 9.2880 0.2530 22.9640 N 0 0 0 0 0 0 0 0 0 0 0 0 + 9.8500 1.3880 23.6910 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.2850 1.6060 23.3640 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.7550 2.8060 22.9770 N 0 0 0 0 0 0 0 0 0 0 0 0 + 13.1000 2.7590 22.7470 N 0 0 0 0 0 0 0 0 0 0 0 0 + 13.4490 1.5020 22.9860 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.3510 0.7420 23.3800 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.2160 -1.0050 23.6310 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.0790 -2.0410 23.2910 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.9910 -3.2610 23.9380 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.2650 -1.2050 24.6210 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.1900 -2.4150 25.2860 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.0550 -3.4660 24.9660 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.0080 -4.6580 25.6580 N 0 0 0 0 0 0 0 0 0 0 0 0 + 7.9060 -4.9740 26.5570 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.9070 -5.7500 25.3310 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 2 0 + 3 2 1 0 + 4 3 1 0 + 5 4 1 0 + 6 5 2 0 + 7 6 1 0 + 8 7 2 0 + 9 8 1 0 + 10 9 2 0 + 10 5 1 0 + 11 10 1 0 + 12 11 2 0 + 12 4 1 0 + 13 2 1 0 + 14 13 1 0 + 15 14 1 0 + 16 15 1 0 + 17 16 1 0 + 18 17 2 0 + 19 18 1 0 + 19 15 2 0 + 20 13 1 0 + 21 20 2 0 + 22 21 1 0 + 23 20 1 0 + 24 23 2 0 + 25 24 1 0 + 25 22 2 0 + 26 25 1 0 + 27 26 1 0 + 28 26 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x11798.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x11798.mol new file mode 100644 index 0000000..dab4108 --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x11798.mol @@ -0,0 +1,68 @@ + + RDKit 3D + + 30 33 0 0 0 0 0 0 0 0999 V2000 + 9.4320 0.9750 21.1840 O 0 0 0 0 0 0 0 0 0 0 0 0 + 9.0430 -0.0390 21.7560 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.0370 -0.9790 21.0940 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.3040 -0.3120 20.0430 N 0 0 0 0 0 0 0 0 0 0 0 0 + 6.1460 0.4010 20.1100 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.3360 0.8190 21.1570 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.2390 1.6130 20.8460 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.9580 1.9610 19.5270 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.7720 1.5320 18.4840 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.8780 0.7410 18.7880 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.8740 0.2250 17.9910 N 0 0 0 0 0 0 0 0 0 0 0 0 + 7.7270 -0.3940 18.7560 N 0 0 0 0 0 0 0 0 0 0 0 0 + 9.4690 -0.3870 23.0050 N 0 0 0 0 0 0 0 0 0 0 0 0 + 10.5190 0.4140 23.6230 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.7850 -0.3720 23.8350 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.5170 -0.8250 22.7780 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.7850 -1.8400 23.2710 S 0 0 0 0 0 0 0 0 0 0 0 0 + 13.3820 -1.6830 24.9410 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.2900 -0.8570 25.0780 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.9660 -1.5140 23.7270 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.6160 -2.7450 23.6520 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.2110 -3.7970 24.4530 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.8740 -1.3680 24.5850 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.4650 -2.4260 25.3790 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.1450 -3.6410 25.3350 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.8840 -4.6730 26.2680 N 0 0 0 0 0 0 0 0 0 0 0 0 + 6.7560 -4.8650 27.0230 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.6650 -4.3510 26.7780 O 0 0 0 0 0 0 0 0 0 0 0 0 + 6.9400 -5.6820 28.0720 N 0 0 0 0 0 0 0 0 0 0 0 0 + 5.8740 -5.9990 29.0050 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 2 0 + 3 2 1 0 + 4 3 1 0 + 5 4 1 0 + 6 5 2 0 + 7 6 1 0 + 8 7 2 0 + 9 8 1 0 + 10 9 2 0 + 10 5 1 0 + 11 10 1 0 + 12 11 2 0 + 12 4 1 0 + 13 2 1 0 + 14 13 1 0 + 15 14 1 0 + 16 15 2 0 + 17 16 1 0 + 18 17 1 0 + 19 18 2 0 + 19 15 1 0 + 20 13 1 0 + 21 20 2 0 + 22 21 1 0 + 23 20 1 0 + 24 23 2 0 + 25 24 1 0 + 25 22 2 0 + 26 25 1 0 + 27 26 1 0 + 28 27 2 0 + 29 27 1 0 + 30 29 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x11801.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x11801.mol new file mode 100644 index 0000000..2720664 --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x11801.mol @@ -0,0 +1,52 @@ + + RDKit 3D + + 23 24 0 0 0 0 0 0 0 0999 V2000 + 8.8070 0.9260 21.0500 O 0 0 0 0 0 0 0 0 0 0 0 0 + 8.3050 -0.1500 21.3540 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.2510 -0.6810 20.7070 N 0 0 0 0 0 0 0 0 0 0 0 0 + 6.5090 -0.0260 19.7000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.3690 0.7210 20.0500 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.9130 0.8640 21.4790 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.7030 1.3860 19.0270 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.1830 1.3070 17.7360 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.2710 0.6060 17.3920 N 0 0 0 0 0 0 0 0 0 0 0 0 + 6.9100 -0.0530 18.3640 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.8230 -0.9820 22.5110 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.2690 -0.6570 22.8100 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.2880 -1.3680 22.1900 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.5880 -0.9180 22.2990 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.8660 -1.8460 21.5760 Cl 0 0 0 0 0 0 0 0 0 0 0 0 + 12.9030 0.2380 22.9850 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.5920 0.4620 23.5700 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.8950 0.9400 23.6360 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.2220 2.1820 24.4310 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.8870 3.4680 23.8300 N 0 0 0 0 0 0 0 0 0 0 0 0 + 10.7190 3.9620 23.4050 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.8710 3.2560 22.8560 O 0 0 0 0 0 0 0 0 0 0 0 0 + 10.4970 5.4280 23.6340 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 2 0 + 3 2 1 0 + 4 3 1 0 + 5 4 2 0 + 6 5 1 0 + 7 5 1 0 + 8 7 2 0 + 9 8 1 0 + 10 9 2 0 + 10 4 1 0 + 11 2 1 0 + 12 11 1 0 + 13 12 2 0 + 14 13 1 0 + 15 14 1 0 + 16 14 2 0 + 17 12 1 0 + 18 17 2 0 + 18 16 1 0 + 19 18 1 0 + 20 19 1 0 + 21 20 1 0 + 22 21 2 0 + 23 21 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x11809.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x11809.mol new file mode 100644 index 0000000..b867596 --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x11809.mol @@ -0,0 +1,49 @@ + + RDKit 3D + + 21 23 0 0 0 0 0 0 0 0999 V2000 + 13.7950 -1.7250 21.1590 Cl 0 0 0 0 0 0 0 0 0 0 0 0 + 12.6740 -0.8990 22.2020 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.1520 0.0240 23.1080 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.2720 0.6140 23.9980 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.3350 -1.2280 22.1370 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.4280 -0.6100 22.9960 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.9220 0.2980 23.9380 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.1200 0.9140 24.8710 O 0 0 0 0 0 0 0 0 0 0 0 0 + 8.7220 1.0250 24.5230 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.1490 -0.2870 24.0510 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.9340 -0.8000 22.8300 C 0 0 1 0 0 0 0 0 0 0 0 0 + 8.4970 -0.0390 21.5780 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.1300 0.9180 21.1470 O 0 0 0 0 0 0 0 0 0 0 0 0 + 7.3630 -0.4960 21.0080 N 0 0 0 0 0 0 0 0 0 0 0 0 + 6.6950 0.0990 19.9110 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.5410 0.8680 20.1450 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.0340 1.1420 21.5390 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.1540 -0.0380 18.5990 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.5430 0.5110 17.5460 N 0 0 0 0 0 0 0 0 0 0 0 0 + 5.4360 1.2260 17.7810 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.9100 1.4280 19.0400 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 1 0 + 3 2 2 0 + 4 3 1 0 + 5 2 1 0 + 6 5 2 0 + 7 6 1 0 + 7 4 2 0 + 8 7 1 0 + 9 8 1 0 + 10 9 1 0 + 11 10 1 0 + 11 6 1 0 + 11 12 1 6 + 13 12 2 0 + 14 12 1 0 + 15 14 1 0 + 16 15 2 0 + 17 16 1 0 + 18 15 1 0 + 19 18 2 0 + 20 19 1 0 + 21 20 2 0 + 21 16 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x11831.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x11831.mol new file mode 100644 index 0000000..c198e01 --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x11831.mol @@ -0,0 +1,56 @@ + + RDKit 3D + + 24 27 0 0 0 0 0 0 0 0999 V2000 + 8.7860 0.7240 21.1730 O 0 0 0 0 0 0 0 0 0 0 0 0 + 8.3450 -0.4180 21.2680 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.8500 -1.3820 22.3210 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.2700 -0.9890 22.6580 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.5440 -0.0390 23.6450 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.6150 0.5670 24.4590 O 0 0 0 0 0 0 0 0 0 0 0 0 + 10.3520 1.4480 25.3560 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.8080 1.4860 24.8930 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.8390 0.3970 23.8570 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.8900 -0.1280 23.1140 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.3300 -1.5190 21.9260 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.6180 -1.0900 22.1680 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.9310 -1.8000 21.2720 Cl 0 0 0 0 0 0 0 0 0 0 0 0 + 7.4950 -0.9410 20.3830 N 0 0 0 0 0 0 0 0 0 0 0 0 + 6.5560 -0.3350 19.5380 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.5270 0.5390 20.0170 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.0650 0.5550 21.3590 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.9500 1.2620 21.7120 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.2460 1.9890 20.7690 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.6640 2.0360 19.4720 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.8110 1.3150 19.0590 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.2140 1.2260 17.7080 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.1960 0.4590 17.2760 N 0 0 0 0 0 0 0 0 0 0 0 0 + 6.8140 -0.3130 18.1740 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 2 0 + 3 2 1 0 + 4 3 1 0 + 5 4 2 0 + 6 5 1 0 + 7 6 1 0 + 8 7 1 0 + 9 5 1 0 + 9 8 1 0 + 10 9 2 0 + 11 4 1 0 + 12 11 2 0 + 12 10 1 0 + 13 12 1 0 + 14 2 1 0 + 15 14 1 0 + 16 15 1 0 + 17 16 2 0 + 18 17 1 0 + 19 18 2 0 + 20 19 1 0 + 21 20 2 0 + 21 16 1 0 + 22 21 1 0 + 23 22 2 0 + 24 23 1 0 + 24 15 2 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x11894.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x11894.mol new file mode 100644 index 0000000..b541600 --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x11894.mol @@ -0,0 +1,55 @@ + + RDKit 3D + + 24 26 0 0 0 0 0 0 0 0999 V2000 + 7.0980 -0.3790 18.1610 O 0 0 0 0 0 0 0 0 0 0 0 0 + 6.4680 -0.2950 19.2120 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.4110 0.7130 19.3800 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.8770 1.5130 17.9710 S 0 0 0 0 0 0 0 0 0 0 0 0 + 3.7660 2.4430 18.8630 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.7900 2.1480 20.1780 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.7270 1.1490 20.4990 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.7350 -1.0650 20.3100 N 0 0 0 0 0 0 0 0 0 0 0 0 + 7.7590 -2.0240 20.3750 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.4740 -3.2990 19.7940 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.4220 -3.6270 19.2860 O 0 0 0 0 0 0 0 0 0 0 0 0 + 8.9790 -1.7490 20.9940 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.4080 -0.5350 21.6150 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.4970 0.9430 21.6280 S 0 0 0 0 0 0 0 0 0 0 0 0 + 9.6990 1.7340 22.6090 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.7510 0.8850 22.8980 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.5810 -0.3920 22.3290 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.5460 3.0360 22.9980 N 0 0 0 0 0 0 0 0 0 0 0 0 + 10.3790 3.4900 24.1210 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.5370 4.9940 24.0660 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.2660 5.6540 24.0180 O 0 0 0 0 0 0 0 0 0 0 0 0 + 8.5160 5.2470 22.8600 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.2680 3.7550 22.8580 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.6960 -3.6850 18.6780 S 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 2 0 + 3 2 1 0 + 4 3 1 0 + 5 4 1 0 + 6 5 2 0 + 7 6 1 0 + 7 3 2 0 + 8 2 1 0 + 9 8 1 0 + 10 9 1 0 + 11 10 2 0 + 12 9 2 3 + 13 12 1 0 + 14 13 1 0 + 15 14 1 0 + 16 15 2 0 + 17 13 2 0 + 17 16 1 0 + 18 15 1 0 + 19 18 1 0 + 20 19 1 0 + 21 20 1 0 + 22 21 1 0 + 23 22 1 0 + 23 18 1 0 + 10 24 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x12025.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x12025.mol new file mode 100644 index 0000000..1eb2f9b --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x12025.mol @@ -0,0 +1,60 @@ + + RDKit 3D + + 26 29 0 0 0 0 0 0 0 0999 V2000 + 6.0650 0.6960 25.2700 O 0 0 0 0 0 0 0 0 0 0 0 0 + 6.2770 1.5570 24.3970 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.4590 1.6030 23.5930 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.3600 2.5520 24.1680 N 0 0 0 0 0 0 0 0 0 0 0 0 + 5.5230 3.5820 23.2340 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.6940 3.6240 22.4440 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.8550 4.6530 21.5130 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.8640 5.6110 21.3640 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.7270 5.5770 22.1540 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.5460 4.5710 23.0890 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.6870 2.5700 22.6500 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.9340 2.4870 21.8360 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.9020 1.9790 20.7250 O 0 0 0 0 0 0 0 0 0 0 0 0 + 10.0650 2.9780 22.3560 N 0 0 0 0 0 0 0 0 0 0 0 0 + 10.4160 3.7950 23.5220 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.3380 3.2340 21.6730 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.7430 4.1670 22.8280 C 0 0 1 0 0 0 0 0 0 0 0 0 + 11.9140 5.5710 22.5030 N 0 0 0 0 0 0 0 0 0 0 0 0 + 11.7070 6.5680 23.4190 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.7760 7.5620 23.1080 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.0970 7.3530 21.9400 O 0 0 0 0 0 0 0 0 0 0 0 0 + 8.7540 7.8150 21.8590 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.4230 6.6420 24.6150 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.2220 7.7140 25.4680 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.3230 8.7110 25.1380 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.5810 8.6370 23.9670 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 2 0 + 3 2 1 0 + 4 2 1 0 + 5 4 1 0 + 6 5 2 0 + 7 6 1 0 + 8 7 2 0 + 9 8 1 0 + 10 9 2 0 + 10 5 1 0 + 11 6 1 0 + 11 3 2 0 + 12 11 1 0 + 13 12 2 0 + 14 12 1 0 + 15 14 1 0 + 16 14 1 0 + 17 15 1 0 + 17 16 1 0 + 17 18 1 6 + 19 18 1 0 + 20 19 2 0 + 21 20 1 0 + 22 21 1 0 + 23 19 1 0 + 24 23 2 0 + 25 24 1 0 + 26 20 1 0 + 26 25 2 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x12073.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x12073.mol new file mode 100644 index 0000000..6680c90 --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x12073.mol @@ -0,0 +1,58 @@ + + RDKit 3D + + 25 28 0 0 0 0 0 0 0 0999 V2000 + 9.1340 1.5280 21.2860 O 0 0 0 0 0 0 0 0 0 0 0 0 + 8.8020 0.4400 21.7490 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.4540 -0.1220 23.0110 C 0 0 1 0 0 0 0 0 0 0 0 0 + 10.9630 -0.0900 22.8810 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.6400 -0.9600 22.0230 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.0090 -0.8540 21.8790 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.8160 -1.8580 20.7060 Cl 0 0 0 0 0 0 0 0 0 0 0 0 + 13.7380 0.0750 22.5840 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.0860 0.9290 23.4520 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.7120 0.8460 23.5950 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.1470 1.7340 24.4810 O 0 0 0 0 0 0 0 0 0 0 0 0 + 9.7270 1.9230 24.4150 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.9950 0.6030 24.3000 C 0 0 1 0 0 0 0 0 0 0 0 0 + 7.4850 0.8230 24.3270 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.8590 -0.3490 21.1970 N 0 0 0 0 0 0 0 0 0 0 0 0 + 7.0010 -0.0360 20.1300 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.7350 0.5610 20.4280 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.2110 0.6900 21.7400 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.0210 1.3250 21.9630 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.3000 1.8670 20.9070 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.7580 1.7600 19.6250 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.9770 1.0920 19.3480 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.5060 0.9530 18.0420 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.6700 0.3740 17.7640 N 0 0 0 0 0 0 0 0 0 0 0 0 + 7.3840 -0.1010 18.7910 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 2 0 + 3 2 1 6 + 4 3 1 0 + 5 4 2 0 + 6 5 1 0 + 7 6 1 0 + 8 6 2 0 + 9 8 1 0 + 10 9 2 0 + 10 4 1 0 + 11 10 1 0 + 12 11 1 0 + 13 12 1 0 + 13 3 1 0 + 13 14 1 6 + 15 2 1 0 + 16 15 1 0 + 17 16 1 0 + 18 17 2 0 + 19 18 1 0 + 20 19 2 0 + 21 20 1 0 + 22 21 2 0 + 22 17 1 0 + 23 22 1 0 + 24 23 2 0 + 25 24 1 0 + 25 16 2 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x12080.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x12080.mol new file mode 100644 index 0000000..be3b2b1 --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x12080.mol @@ -0,0 +1,31 @@ + + RDKit 3D + + 13 13 0 0 0 0 0 0 0 0999 V2000 + 6.1160 -5.0930 19.6930 N 0 0 0 0 0 0 0 0 0 0 0 0 + 7.0140 -4.1840 19.8630 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.9230 -3.3880 21.1420 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.0250 -2.6900 21.4700 N 0 0 0 0 0 0 0 0 0 0 0 0 + 7.9600 -1.9990 22.6000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.0670 -1.3770 23.0640 O 0 0 0 0 0 0 0 0 0 0 0 0 + 10.2580 -1.4300 22.2660 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.8270 -1.9570 23.4040 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.7820 -3.4600 21.8570 N 0 0 0 0 0 0 0 0 0 0 0 0 + 5.7770 -2.7710 22.9940 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.7950 -2.9140 23.9130 O 0 0 0 0 0 0 0 0 0 0 0 0 + 3.7170 -3.8110 23.6210 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.4080 -3.6990 18.7530 S 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 2 0 + 3 2 1 0 + 4 3 2 0 + 5 4 1 0 + 6 5 1 0 + 7 6 1 0 + 8 5 2 0 + 9 3 1 0 + 10 9 2 0 + 10 8 1 0 + 11 10 1 0 + 12 11 1 0 + 2 13 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x2971.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x2971.mol new file mode 100644 index 0000000..e6c60cd --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x2971.mol @@ -0,0 +1,52 @@ + + RDKit 3D + + 23 24 0 0 0 0 0 0 0 0999 V2000 + 9.1320 0.9360 20.9810 O 0 0 0 0 0 0 0 0 0 0 0 0 + 8.5060 0.0060 21.4830 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.3180 -0.4430 21.0270 N 0 0 0 0 0 0 0 0 0 0 0 0 + 6.6120 0.0650 19.9170 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.1700 -0.0230 18.6420 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.6630 0.5920 17.5710 N 0 0 0 0 0 0 0 0 0 0 0 0 + 5.5440 1.3010 17.7430 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.8900 1.4180 18.9580 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.4360 0.7890 20.0610 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.0520 -0.7460 22.6830 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.5020 -0.5860 22.7740 N 0 0 0 0 0 0 0 0 0 0 0 0 + 11.1690 -1.8930 22.7110 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.6690 -1.7380 22.5730 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.2350 -0.8790 23.6950 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.4640 0.4310 23.8620 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.9580 0.1870 23.9510 C 0 0 1 0 0 0 0 0 0 0 0 0 + 10.1540 1.4520 24.2690 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.6230 2.7530 23.6390 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.6890 3.7970 24.6670 N 0 0 0 0 0 0 0 0 0 0 0 0 + 10.5530 5.3640 24.2860 S 0 0 1 0 0 0 0 0 0 0 0 0 + 10.1690 6.0470 25.4820 O 0 0 0 0 0 0 0 0 0 0 0 0 + 11.7710 5.7420 23.6400 O 0 0 0 0 0 0 0 0 0 0 0 0 + 9.2490 5.5190 23.1260 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 2 0 + 3 2 1 0 + 4 3 1 0 + 5 4 2 0 + 6 5 1 0 + 7 6 2 0 + 8 7 1 0 + 9 8 2 0 + 9 4 1 0 + 10 2 1 0 + 11 10 1 0 + 12 11 1 0 + 13 12 1 0 + 14 13 1 0 + 15 14 1 0 + 16 11 1 0 + 16 15 1 0 + 16 17 1 6 + 18 17 1 0 + 19 18 1 0 + 20 19 1 0 + 21 20 2 0 + 22 20 2 0 + 20 23 1 6 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x3325.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x3325.mol new file mode 100644 index 0000000..b75db00 --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x3325.mol @@ -0,0 +1,31 @@ + + RDKit 3D + + 13 13 0 0 0 0 0 0 0 0999 V2000 + 6.1820 -3.8500 19.8540 O 0 0 0 0 0 0 0 0 0 0 0 0 + 7.0420 -3.4020 20.5980 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.4510 -3.1400 20.1050 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.8000 -3.1080 21.8910 N 0 0 0 0 0 0 0 0 0 0 0 0 + 5.8050 -3.8190 22.7040 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.4610 -4.3690 23.9690 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.1190 -3.2860 24.7250 N 0 0 0 0 0 0 0 0 0 0 0 0 + 8.1510 -2.6510 23.8850 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.5230 -2.0630 22.6280 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.6690 -3.7640 25.9890 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.6970 -4.8030 25.8550 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.5170 -5.6330 25.7010 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.5400 -3.1290 18.3040 S 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 2 0 + 3 2 1 0 + 4 2 1 0 + 5 4 1 0 + 6 5 1 0 + 7 6 1 0 + 8 7 1 0 + 9 8 1 0 + 9 4 1 0 + 10 7 1 0 + 11 10 1 0 + 12 11 3 0 + 3 13 1 0 +M END diff --git a/fragmenstein/mpro/data/hit_mols/Mpro-x3348.mol b/fragmenstein/mpro/data/hit_mols/Mpro-x3348.mol new file mode 100644 index 0000000..19933ab --- /dev/null +++ b/fragmenstein/mpro/data/hit_mols/Mpro-x3348.mol @@ -0,0 +1,53 @@ + + RDKit 3D + + 23 25 0 0 0 0 0 0 0 0999 V2000 + 5.9260 -4.2510 19.5750 O 0 0 0 0 0 0 0 0 0 0 0 0 + 6.5260 -3.1900 19.6410 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.0770 -2.5170 18.3960 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.7680 -2.5780 20.8170 N 0 0 0 0 0 0 0 0 0 0 0 0 + 7.5860 -1.3760 20.9840 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.8620 -1.7560 21.6930 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.5610 -2.3740 23.0020 N 0 0 0 0 0 0 0 0 0 0 0 0 + 7.6560 -3.5350 22.8670 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.3970 -3.1710 22.1030 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.8170 -2.7610 23.6900 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.8500 -1.6380 23.6860 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.8160 -0.6260 24.6380 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.7650 0.3860 24.6310 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.7590 0.4030 23.6640 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.7940 -0.5890 22.6990 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.8500 -1.6070 22.7150 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.5590 -3.4880 25.0090 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.0990 -4.7530 25.2180 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.7850 -5.4780 26.3570 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.9360 -4.9450 27.3090 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.4090 -3.6810 27.1270 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.7240 -2.9520 25.9860 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.7050 -3.2750 18.2520 S 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 2 0 + 3 2 1 0 + 4 2 1 0 + 5 4 1 0 + 6 5 1 0 + 7 6 1 0 + 8 7 1 0 + 9 4 1 0 + 9 8 1 0 + 10 7 1 0 + 10 11 1 0 + 12 11 2 0 + 13 12 1 0 + 14 13 2 0 + 15 14 1 0 + 16 11 1 0 + 16 15 2 0 + 17 10 1 0 + 18 17 2 0 + 19 18 1 0 + 20 19 2 0 + 21 20 1 0 + 22 21 2 0 + 22 17 1 0 + 3 23 1 0 +M END diff --git a/test.py b/test.py index 2cf965c..0b85009 100644 --- a/test.py +++ b/test.py @@ -16,21 +16,42 @@ class MProTargetTester(unittest.TestCase): def test_easy(self): + """ + To a **human** this looks easy. x0692 is a red herring and the other two make the molecule. + As currently written this will fail. + + :return: + """ + # PAU-UNI-52c0427f-1 MProVictor.quick_renanimation = True victor = MProVictor.from_hit_codes(smiles='CCNc1ncc(C#N)cc1CN1CCN(C(=O)C*)CC1', hit_codes=['x0692', 'x0305', 'x1249'], long_name='2_ACL') self.assertEqual(victor.error, '',victor.error) self.assertIsNotNone(victor.minimised_mol, 'Failed minimisation') + msg = f'x1249 is the red herring, prediction: {victor.monster.unmatched}, '+\ + f'while x0305 and x0692 the true inspirations {victor.monster.matched}' + self.assertIn('x1249', victor.monster.unmatched, msg) + self.assertIn('x0305', victor.monster.matched, msg) + + victor.make_pse() def test_nasty(self): + """ + The human suggested a lot of novel groups. + 'x0540' is a really odd inspiration. Three atoms are conserved. the rest aren't. + + :return: + """ MProVictor.quick_renanimation = True victor = MProVictor.from_hit_codes(smiles='*CCC(=O)N1CC(CCN(C(=O)Nc2c(C)ncc(C)c2CCN2CCOCC2)c2cc(C)ccn2)C1', hit_codes=['x0434', 'x0540'], long_name='AGN-NEW-5f0-1_ACR1') self.assertEqual(victor.error, '', victor.error) self.assertIsNotNone(victor.minimised_mol, 'Failed minimisation') + self.assertEqual(len(victor.monster.unmatched), 0, + f'Both were correct but {victor.monster.unmatched} was discarded') victor.make_pse() def test_incorrect(self): @@ -178,7 +199,7 @@ def test_peridimethylnaphthalene(self): def test_spirodituluene(self): name = 'spirodituluene' - after = 'C[C@@H]1C=CC[C@]2(C=C[C@H](C)C=C2)C1' + after = ('C[C@@H]1C=CC[C@]2(C=C[C@H](C)C=C2)C1', 'C[C@@H]1C=CC[C@]2(C=C[C@@H](C)C=C2)C1') template = os.path.join(MProVictor.get_mpro_path(), 'template.pdb') toluene = Chem.MolFromMolFile('test_mols/toluene.mol') toluene.SetProp('_Name', 'toluene') @@ -190,4 +211,86 @@ def test_spirodituluene(self): covalent_resi='3A', # a random residue is still required for the constaint ref atom. covalent_resn='VAL') gotten = Chem.MolToSmiles(Chem.RemoveHs(v.minimised_mol)) - self.assertEqual(gotten, after, f'{name} failed {gotten} (expected {after})') + self.assertIn(gotten, after, f'{name} failed {gotten} (expected {after})') + +class UnresolvedProblems(unittest.TestCase): + def test_recto_fail_A(self): + """Not too sure why this fails. I think it is the alphatic - ring merger""" + MProVictor.monster_throw_on_discard = True + victor = MProVictor.combine_codes(hit_codes=['x11612','x11475']) + self.assertEqual(victor.error, '', victor.error) + + def test_supplementary1_to_recto_fail_A(self): + """ + This was ment to test the above, but it works fine. + :return: + """ + # make hits + chlorotoluene = Chem.MolFromSmiles('c1c(Cl)c(C)ccc1') + AllChem.EmbedMolecule(chlorotoluene) + chlorotoluene.SetProp('_Name', 'orthochlorotoluene') + toluene = Chem.RWMol(chlorotoluene) + toluene.RemoveAtom(2) + Chem.SanitizeMol(toluene) + toluene.SetProp('_Name', 'toluene') + chlorobutane = Chem.RWMol(chlorotoluene) + for n in range(chlorobutane.GetNumAtoms() - 1, 4, -1): + chlorobutane.RemoveAtom(n) + for atom in chlorobutane.GetAtoms(): + atom.SetIsAromatic(False) + for bond in chlorobutane.GetBonds(): + bond.SetBondType(Chem.BondType.SINGLE) + Chem.SanitizeMol(chlorobutane) + chlorobutane.SetProp('_Name', '2-chlorobutane') + # merge + monster = Monster(mol=Chem.Mol(), + hits=[], + attachment=None, + merging_mode='off') + monster.throw_on_discard = False + # # merge! + col_hits = monster.collapse_mols([toluene, chlorobutane]) + monster.scaffold = monster.merge_hits(col_hits) + monster.positioned_mol = monster.expand_ring(monster.scaffold) + recto = Rectifier(monster.positioned_mol) + # ====== + self.assertEqual(Chem.MolToSmiles(recto.mol), Chem.MolToSmiles(chlorotoluene)) #CC(Cl)CCc1ccccc1 + + + def test_supplementary2_to_recto_fail_A(self): + """ + This was meant to test as above. It also works fine. + :return: + """ + # + methylchlorotoluene = Chem.MolFromSmiles('Cc1c(Cl)c(C)ccc1') + AllChem.EmbedMolecule(methylchlorotoluene) + methylchlorotoluene.SetProp('_Name', 'methylchlorotoluene') + # + methyltoluene = Chem.RWMol(methylchlorotoluene) + methyltoluene.RemoveAtom(3) + Chem.SanitizeMol(methyltoluene) + methyltoluene.SetProp('_Name', 'methyltoluene') + # + chloropentane = Chem.RWMol(methylchlorotoluene) + for n in range(chloropentane.GetNumAtoms() - 1, 5, -1): + chloropentane.RemoveAtom(n) + for atom in chloropentane.GetAtoms(): + atom.SetIsAromatic(False) + for bond in chloropentane.GetBonds(): + bond.SetBondType(Chem.BondType.SINGLE) + Chem.SanitizeMol(chloropentane) + chloropentane.SetProp('_Name', '2-chloropentane') + # + monster = Monster(mol=Chem.Mol(), + hits=[], + attachment=None, + merging_mode='off') + monster.throw_on_discard = False + # # merge! + col_hits = monster.collapse_mols([methyltoluene, chloropentane]) + monster.scaffold = monster.merge_hits(col_hits) + monster.positioned_mol = monster.expand_ring(monster.scaffold) + recto = Rectifier(monster.positioned_mol) + # ====== + self.assertEqual(Chem.MolToSmiles(recto.mol), Chem.MolToSmiles(methylchlorotoluene)) \ No newline at end of file From eb08d3a90ae3a959f21d7a1e987eb549d109b1b3 Mon Sep 17 00:00:00 2001 From: matteoferla Date: Fri, 29 Jan 2021 12:32:04 +0000 Subject: [PATCH 02/32] :hammer: started writing CLI --- cli/fragmenstein.py | 116 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 116 insertions(+) create mode 100644 cli/fragmenstein.py diff --git a/cli/fragmenstein.py b/cli/fragmenstein.py new file mode 100644 index 0000000..feee5fd --- /dev/null +++ b/cli/fragmenstein.py @@ -0,0 +1,116 @@ +#!/usr/bin/env python3 +# Do not split file up + +__version__ = '0.1' +__doc__ = """ +Command line interface to Fragmenstein. +The the first argument to the command is one of the three option: + +## extract +Given a target folder (`-i `) +extract the mol files (with covalent atom if present) in an output folder (`-o `) + +## merge + + +## position + +NB. Please no spaces in the filenames. If spaces are present quote/double-quote the fle path. +""".strip() + +from typing import * +import argparse + + +# from fragmenstein import Victor + +class FragmensteinParser: + ___doc__ = __doc__ # this works (in a function it doesn't as the global cmd is called for) + + # ===================== Actions ==================================================================================== + + def extract(self, input_folder: str, output_folder: str): + pass + + def merge(self, target_filenames: List): + pass + + def place(self, target_filenames: List, smiles: str): + pass + + def set_verbosity(verbose:int): + # set logging stdout + # logging.ERROR, logging.CRITICAL --> 0 ? + # logging.WARNING --> 1 ? + # logging.INFO --> 2 + # logging.DEBUG --> 3 + pass + + # ===================== Arguments ================================================================================== + + def __init__(self, cli_override: Optional[List[str]] = None): + self.parser = self.define_parser() + # ---- parse --------------------------------------------------------------------------------------------------- + if cli_override: # testing basically + self.args = self.parser.parse_args(cli_override) + else: # normal way + self.args = self.parser.parse_args() + # ---- verify -------------------------------------------------------------------------------------------------- + self.verify() + # ---- route -------------------------------------------------------------------------------------------------- + self.route() + + @classmethod + def mock(cls): + self = cls.__new__(cls) + self.parser = self.define_parser() + self.args = property(lambda: exec("raise NotImplementedError")) + + def define_parser(self): + parser = argparse.ArgumentParser(description=self.__doc__) + parser.add_argument('mode', type=str, help='Three modes are accepted: extract, merge, position', + choices=['extract', 'merge', 'position']) + parser.add_argument('-v', '--verbose', action="count", help='verbose') + # ------- mode: extract ---------------------------------------------------------------------------------------- + parser.add_argument('-i', '--input', + type=str, nargs='+', help='mode: extract. input folder') + parser.add_argument('-o', '--output', + type=str, nargs='+', + help='mode: extract. output folder') + # ------- mode: merge and place -------------------------------------------------------------------------------- + parser.add_argument('-t', '--targets', + type=str, nargs='+', + help='mode: merge and place. input target filenames') + parser.add_argument('-n', '--name', + type=str, nargs=1, + help='mode: merge and place. output compound name') + # ------- mode: place ------------------------------------------------------------------------------------------ + parser.add_argument('-s', '--smiles', type=str, nargs='+', help='mode: place. SMILE-String to be placed') + return parser + + def verify(self): + if self.args.mode == 'extract' and not (self.args.input and self.args.output): + self.parser.error('mode extract requires --input and --output ') + elif self.args.mode == 'extract' and not self.args.targets: + self.parser.error('mode extract requires --targets ') + elif self.args.mode == 'place' and not (self.args.targets and self.args.smiles): + self.parser.error('mode place requires --targets and --smiles ') + else: + pass # no issues. + + def route(self): + self.set_verbosity(self.args.verbose) + if self.args.mode == 'extract': + self.extract(self.args.input, self.args.output) + elif self.args.mode == 'merge': + self.merge(self.args.targets) + elif self.args.mode == 'place': + self.place(self.args.targets, self.args.smiles) + else: + raise SyntaxError('Mode choice impossible. Check declaration') + + +# ====================================================================================================================== + +if __name__ == '__main__': + FragmensteinParser() From 93c7077e5366de17e4d2e0a5ebb6c43eed51e985 Mon Sep 17 00:00:00 2001 From: matteoferla Date: Fri, 29 Jan 2021 13:15:50 +0000 Subject: [PATCH 03/32] :beetle: overzealous search and replace! --- setup.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/setup.py b/setup.py index 543bb07..1e4ad01 100644 --- a/setup.py +++ b/setup.py @@ -9,10 +9,11 @@ install_requires=['numpy', 'rdkit'], extras_require={'minimization': ['pyrosetta','rdkit_to_params'], 'pse-export': ['pymol'], - 'jupyter': ['jupyter']}, + 'jupyter': ['jupyter']}, url='https://github.com/matteoferla/Fragmenstein', license='MIT', author='Matteo Ferla', author_email='matteo.ferla@gmail.com', - description='Scaffold hopping between bound compounds by stitching them together like a reanimated corpse' + description='Scaffold hopping between bound compounds by stitching them together like a reanimated corpse', + scripts=['fragmenstein=cli/fragmenstein.py'], ) From 102cdf65206e040207164577ad703b3065129a0d Mon Sep 17 00:00:00 2001 From: matteoferla Date: Fri, 29 Jan 2021 15:19:58 +0000 Subject: [PATCH 04/32] :hammer: I read that `scripts` does not work it windows... --- cli/fragmenstein.py | 3 +++ setup.py | 4 +++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/cli/fragmenstein.py b/cli/fragmenstein.py index feee5fd..c0b8778 100644 --- a/cli/fragmenstein.py +++ b/cli/fragmenstein.py @@ -112,5 +112,8 @@ def route(self): # ====================================================================================================================== +def main(): + FragmensteinParser() + if __name__ == '__main__': FragmensteinParser() diff --git a/setup.py b/setup.py index 1e4ad01..b17a217 100644 --- a/setup.py +++ b/setup.py @@ -15,5 +15,7 @@ author='Matteo Ferla', author_email='matteo.ferla@gmail.com', description='Scaffold hopping between bound compounds by stitching them together like a reanimated corpse', - scripts=['fragmenstein=cli/fragmenstein.py'], + entry_points={ + 'console_scripts': ['fragmenstein=cli/fragmenstein.py:main'], + } ) From 25e3b171128887b3c064c10bbb804dbf5d636234 Mon Sep 17 00:00:00 2001 From: matteoferla Date: Fri, 29 Jan 2021 16:08:42 +0000 Subject: [PATCH 05/32] :pencil: note to self: TODO tests for missing modules --- test.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test.py b/test.py index 0b85009..8c2ea40 100644 --- a/test.py +++ b/test.py @@ -293,4 +293,6 @@ def test_supplementary2_to_recto_fail_A(self): monster.positioned_mol = monster.expand_ring(monster.scaffold) recto = Rectifier(monster.positioned_mol) # ====== - self.assertEqual(Chem.MolToSmiles(recto.mol), Chem.MolToSmiles(methylchlorotoluene)) \ No newline at end of file + self.assertEqual(Chem.MolToSmiles(recto.mol), Chem.MolToSmiles(methylchlorotoluene)) + +# Todo: add a class to test missing modules. \ No newline at end of file From 6940228a72114d961d1377777041723e3fce48cc Mon Sep 17 00:00:00 2001 From: matteoferla Date: Fri, 29 Jan 2021 16:09:49 +0000 Subject: [PATCH 06/32] :hammer: fixed scripts. Works on Mac on Linux. No clue on Windows... --- .../cli/__init__.py | 11 ++++---- fragmenstein/cli/fragmenstein.py | 0 setup.py | 26 ++++++++++++++----- 3 files changed, 26 insertions(+), 11 deletions(-) rename cli/fragmenstein.py => fragmenstein/cli/__init__.py (95%) create mode 100644 fragmenstein/cli/fragmenstein.py diff --git a/cli/fragmenstein.py b/fragmenstein/cli/__init__.py similarity index 95% rename from cli/fragmenstein.py rename to fragmenstein/cli/__init__.py index c0b8778..174875c 100644 --- a/cli/fragmenstein.py +++ b/fragmenstein/cli/__init__.py @@ -14,7 +14,7 @@ ## position - + NB. Please no spaces in the filenames. If spaces are present quote/double-quote the fle path. """.strip() @@ -25,7 +25,7 @@ # from fragmenstein import Victor class FragmensteinParser: - ___doc__ = __doc__ # this works (in a function it doesn't as the global cmd is called for) + ___doc__ = __doc__ # this works (it is in a function it doesn't as the global cmd is called for) # ===================== Actions ==================================================================================== @@ -38,7 +38,7 @@ def merge(self, target_filenames: List): def place(self, target_filenames: List, smiles: str): pass - def set_verbosity(verbose:int): + def set_verbosity(verbose: int): # set logging stdout # logging.ERROR, logging.CRITICAL --> 0 ? # logging.WARNING --> 1 ? @@ -57,7 +57,7 @@ def __init__(self, cli_override: Optional[List[str]] = None): self.args = self.parser.parse_args() # ---- verify -------------------------------------------------------------------------------------------------- self.verify() - # ---- route -------------------------------------------------------------------------------------------------- + # ---- route --------------------------------------------------------------------------------------------------- self.route() @classmethod @@ -115,5 +115,6 @@ def route(self): def main(): FragmensteinParser() + if __name__ == '__main__': - FragmensteinParser() + main() diff --git a/fragmenstein/cli/fragmenstein.py b/fragmenstein/cli/fragmenstein.py new file mode 100644 index 0000000..e69de29 diff --git a/setup.py b/setup.py index b17a217..b73eaf0 100644 --- a/setup.py +++ b/setup.py @@ -1,21 +1,35 @@ from setuptools import setup +from warnings import warn +from importlib import util -print('This 3.6+ script requires rdkit, numpy and optionally pymol and jupyter, which are best installed with conda.') +# ---------- Non pip modules ------------------------------------------------------------------------------------------ + +if not util.find_spec('rdkit'): + raise ModuleNotFoundError('This 3.6+ script **requires** rdkit which cannot be pip installed.' + + ' To install try either ' + + 'conda install -c conda-forge rdkit or ' + + 'sudo apt-get/brew install python3-rdkit or visit rdkit documentation.') + +if not util.find_spec('pyrosetta'): + warn('The minimisation part of this code uses pyrosetta, which has to be downloaded from ' + + 'the Rosetta software site due to licencing. Without it only the classes Monster and Rectifier will work') + +if not util.find_spec('pymol2'): + warn('The module pymol2 is optionally required (conda or apt-get installable).') setup( name='Fragmenstein', version='0.5', packages=['fragmenstein'], - install_requires=['numpy', 'rdkit'], - extras_require={'minimization': ['pyrosetta','rdkit_to_params'], - 'pse-export': ['pymol'], - 'jupyter': ['jupyter']}, + install_requires=['numpy'], + extras_require={'minimization': ['rdkit_to_params'], + 'jupyter': ['jupyter']}, url='https://github.com/matteoferla/Fragmenstein', license='MIT', author='Matteo Ferla', author_email='matteo.ferla@gmail.com', description='Scaffold hopping between bound compounds by stitching them together like a reanimated corpse', entry_points={ - 'console_scripts': ['fragmenstein=cli/fragmenstein.py:main'], + 'console_scripts': ['fragmenstein=fragmenstein.cli:main'], } ) From 4c194e12d6c6d45e2c60927e4d0da7d04ce39496 Mon Sep 17 00:00:00 2001 From: matteoferla Date: Mon, 1 Feb 2021 18:20:54 +0000 Subject: [PATCH 07/32] :black_nib: comment is no longfer valid --- fragmenstein/cli/__init__.py | 1 - fragmenstein/cli/fragmenstein.py | 0 2 files changed, 1 deletion(-) delete mode 100644 fragmenstein/cli/fragmenstein.py diff --git a/fragmenstein/cli/__init__.py b/fragmenstein/cli/__init__.py index 174875c..d267229 100644 --- a/fragmenstein/cli/__init__.py +++ b/fragmenstein/cli/__init__.py @@ -1,5 +1,4 @@ #!/usr/bin/env python3 -# Do not split file up __version__ = '0.1' __doc__ = """ diff --git a/fragmenstein/cli/fragmenstein.py b/fragmenstein/cli/fragmenstein.py deleted file mode 100644 index e69de29..0000000 From 569ddc4fc790cebb94c9c070a2ce58de56a42a88 Mon Sep 17 00:00:00 2001 From: matteoferla Date: Mon, 1 Feb 2021 18:21:21 +0000 Subject: [PATCH 08/32] :hammer: various fixes --- fragmenstein/monster/__init__.py | 205 ++++++++++++++++++------- fragmenstein/monster/_base.py | 171 +++++++++++++-------- fragmenstein/monster/_utility_mixin.py | 8 +- fragmenstein/monster/unmerge_mapper.py | 2 + test.py | 18 +++ 5 files changed, 282 insertions(+), 122 deletions(-) diff --git a/fragmenstein/monster/__init__.py b/fragmenstein/monster/__init__.py index 7970c06..cdf9a78 100644 --- a/fragmenstein/monster/__init__.py +++ b/fragmenstein/monster/__init__.py @@ -30,8 +30,10 @@ from .positional_mapping import GPM from .unmerge_mapper import Unmerge from .bond_provenance import BondProvenance +from ..rectifier import Rectifier import itertools + ################################################################## class Monster(_MonsterUtil, _MonsterRing, GPM, _MonsterJoinNeighMixin): # Unmerge is called. Not inherited. @@ -59,60 +61,140 @@ class Monster(_MonsterUtil, _MonsterRing, GPM, _MonsterJoinNeighMixin): # Unmer defined in the ``dummy`` class variable. Namely element R in mol file or * in string is the default. """ - def __init__(self, mol: Chem.Mol, hits: List[Chem.Mol], attachment: Optional[Chem.Mol] = None, - debug_draw: bool = False, merging_mode='partial', average_position=False): + def __init__(self, + hits: List[Chem.Mol], + attachment: Optional[Chem.Mol] = None, + debug_draw: bool = False, + average_position=False): """ - Merging mode controls what algorithm to use. - - * 'full': a single scaffold is made - * 'partial': multiple possible scaffolds and best is chosen - * 'none': no merging is done. The hits are mapped individually. Not great for small fragments. - * 'off': do nothing. + Initialisation starts Monster, but it does not do any mergers or placements. + This is changed in revision 0.6. - :param mol: - :param hits: + :param hits: hits are a list of rdkit molecules :param attachment: :param debug_draw: - :param merging_mode: full | partial | none | off + :param average_position: """ # starting attributes - super().__init__() - self.initial_mol = mol # untouched. - if self.initial_mol.HasSubstructMatch(self.dummy) and attachment: - self.attachement = attachment - elif self.initial_mol.HasSubstructMatch(self.dummy): - warn('No attachment atom provided but dummy atom present --- ignoring.') - self.attachement = None - elif attachment: - warn('Attachment atom provided but dummy atom not present --- ignoring.') - self.attachement = None - else: - self.attachement = None - # Chem.RemoveHs(self.initial_mol) + # formerly this was present... but it does nothing. + # super().__init__() + # bar for self._debug_draw = _debug_draw from _MonsterRing + # ==== hits =========================================== self.hits = self.fix_hits(hits) # list of hits + # fix_hits: assert Chem.Mol, fix name if needed and store positions (see ``store_positions``) + # ==== other ========================================== self._debug_draw = debug_draw # Jupyter notebook only. - self.unmatched = [] self.average_position = average_position - # derived attributes - self.scaffold = None #: template which may have wrong elements - self.scaffold_options = [] #: partial combined templates (merging_mode: partial) + # ==== To do be filled ================================ + # List[str] + self.unmatched = [] #: rejected hits + # self.matched is dynamic. #: accepted hits + # Chem.Mol or List[Chem.Mol] + self.modifications = [] + self.initial_mol = None + # self.scaffold = None #: template which may have wrong elements + # self.scaffold_options = [] #: partial combined templates (merging_mode: partial) + self.scaffolds = [] #: templates which may have wrong elements self.chimera = None #: merger of hits but with atoms made to match the to-be-aligned mol self.positioned_mol = None #: final molecule - # do calculations - if merging_mode == 'off': - pass - elif merging_mode == 'full': - self.full_merging() - elif merging_mode == 'partial': - self.partial_merging() - elif merging_mode == 'none_permissive' or merging_mode == 'permissive_none': - self.no_merging(broad=True) - elif merging_mode == 'none': - self.no_merging() - else: - raise ValueError( - f"Merging mode can only be 'full' | 'partial' | 'none' | 'none_permissive' | 'off', not '{merging_mode}'") + def place(self, mol: Chem.Mol): + pass + + def place_smiles(self, smiles: str): + mol = Chem.MolFromSmiles(smiles) + self.place(mol) + + def merge(self, keep_all=False, collapse_rings=True): + """ + :return: + """ + # merge! + col_hits = self.collapse_mols(self.hits) + self.modifications.extend(col_hits) + self.monster.scaffold = self.merge_hits(col_hits) + self.modifications.append(Chem.Mol(self.monster.scaffold)) # backup for debug + self._log_warnings() + ## Discard can happen for other reasons than disconnect + if self.monster_throw_on_discard and len(self.monster.unmatched): + raise ConnectionError(f'{self.long_name} - Could not combine with {self.monster.unmatched} ' + \ + f'(>{self.monster.joining_cutoff}') + # expand and fix + self._log_warnings() + self.journal.debug(f'{self.long_name} - Merged') + self.monster.positioned_mol = self.monster.expand_ring(self.monster.scaffold) + # bonded_as_original=False no longer needed. + self.modifications.append(Chem.Mol(self.monster.positioned_mol)) # backup for debug + self._log_warnings() + self.journal.debug(f'{self.long_name} - Expanded') + recto = Rectifier(self.monster.positioned_mol) + try: + recto.fix() + except ConnectionError: + self.journal.critical(f'This really odd cornercase: Rectifier broke the mol.') + mol = self.monster._emergency_joining(recto.mol) + recto = Rectifier(self.monster.positioned_mol) + recto.fix() + self.monster.positioned_mol = recto.mol + self.modifications.extend(recto.modifications) # backup for debug + + # + # def __init__(self, mol: Chem.Mol, hits: List[Chem.Mol], attachment: Optional[Chem.Mol] = None, + # debug_draw: bool = False, merging_mode='partial', average_position=False): + # """ + # Merging mode controls what algorithm to use. + # + # * 'full': a single scaffold is made + # * 'partial': multiple possible scaffolds and best is chosen + # * 'none': no merging is done. The hits are mapped individually. Not great for small fragments. + # * 'off': do nothing. + # + # :param mol: + # :param hits: + # :param attachment: + # :param debug_draw: + # :param merging_mode: full | partial | none | off + # """ + # # starting attributes + # # self._debug_draw = _debug_draw from _MonsterRing + # super().__init__() + # self.initial_mol = mol # untouched. + # if self.initial_mol.HasSubstructMatch(self.dummy) and attachment: + # self.attachement = attachment + # elif self.initial_mol.HasSubstructMatch(self.dummy): + # warn('No attachment atom provided but dummy atom present --- ignoring.') + # self.attachement = None + # elif attachment: + # warn('Attachment atom provided but dummy atom not present --- ignoring.') + # self.attachement = None + # else: + # self.attachement = None + # # Chem.RemoveHs(self.initial_mol) + # self.hits = self.fix_hits(hits) # list of hits + # self._debug_draw = debug_draw # Jupyter notebook only. + # self.unmatched = [] + # self.average_position = average_position + # # derived attributes + # self.scaffold = None #: template which may have wrong elements + # self.scaffold_options = [] #: partial combined templates (merging_mode: partial) + # self.chimera = None #: merger of hits but with atoms made to match the to-be-aligned mol + # self.positioned_mol = None #: final molecule + # # do calculations + # if merging_mode == 'off': + # pass + # elif merging_mode == 'full': + # self.full_merging() + # elif merging_mode == 'partial': + # self.partial_merging() + # elif merging_mode == 'none_permissive' or merging_mode == 'permissive_none': + # self.no_merging(broad=True) + # elif merging_mode == 'none': + # self.no_merging() + # else: + # raise ValueError( + # f"Merging mode can only be 'full' | 'partial' | 'none' | 'none_permissive' | 'off', not '{merging_mode}'") + + @classmethod def full_merging(self) -> None: """ a single scaffold is made (except for ``.unmatched``) @@ -152,8 +234,6 @@ def no_merging(self, broad=False) -> None: matchChiralTag=True) pair_atom_maps = [dict(p) for p in pair_atom_maps_t] maps[template.GetProp('_Name')] = pair_atom_maps - if self.throw_on_discard: - Unmerge.max_strikes = 20 um = Unmerge(followup=self.initial_mol, mols=self.hits, maps=maps, @@ -437,18 +517,27 @@ def merge_hits(self, hits: Optional[List[Chem.Mol]] = None) -> Chem.Mol: return scaffold def _prevent_two_bonds_on_dummy(self, mol: Chem.RWMol): + """ + The case '*(C)C' is seen legitimately in some warheads... but in most cases these are not. + :param mol: + :return: + """ for atom in mol.GetAtoms(): if atom.GetSymbol() != '*': pass elif len(atom.GetNeighbors()) <= 1: pass elif len(atom.GetNeighbors()) >= 2: + self.journal.info(f'Dummy atom (idx={atom.GetIdx()}) has {len(atom.GetNeighbors())} bonds!') neighs = atom.GetNeighbors() + first = neighs[0] for second in neighs[1:]: - self._absorb(mol, atom.GetIdx(), second.GetIdx()) - mol.RemoveAtom(second.GetIdx()) - self._prevent_two_bonds_on_dummy(mol) - break + rejected = second.GetIdx() # that will be absorbed (deleted) + keeper = first.GetIdx() # that absorbs (kept) + self._copy_bonding(mol, keeper, rejected) + self._mark_for_deletion(mol, rejected) + self._delete_marked(mol) + return self._prevent_two_bonds_on_dummy(mol) # ================= Chimera ======================================================================================== @@ -462,7 +551,8 @@ def make_chimera(self, min_mode_index=0) -> Chem.Mol: """ # get the matches atom_map, mode = self.get_mcs_mapping(self.scaffold, self.initial_mol, min_mode_index=min_mode_index) - self.journal.debug(f"scaffold-followup: {{**{k: str(v) for k, v in mode.items()}, 'N_atoms': len(atom_map)}}") + follow = {**{k: str(v) for k, v in mode.items()}, 'N_atoms': len(atom_map)} + self.journal.debug(f"scaffold-followup: {follow}") if self._debug_draw: self.draw_nicely(self.initial_mol, highlightAtoms=atom_map.values()) ## make the scaffold more like the followup to avoid weird matches. @@ -517,7 +607,8 @@ def place_followup(self, mol: Chem.Mol = None, atom_map: Optional[Dict] = None) # variables: atom_map sextant -> uniques if atom_map is None: atom_map, mode = self.get_mcs_mapping(mol, self.chimera) - self.journal.debug(f"followup-chimera' = {{**{k: str(v) for k, v in mode.items()}, 'N_atoms': len(atom_map)}}") + msg = {**{k: str(v) for k, v in mode.items()}, 'N_atoms': len(atom_map)} + self.journal.debug(f"followup-chimera' = {msg}") rdMolAlign.AlignMol(sextant, self.chimera, atomMap=list(atom_map.items()), maxIters=500) # debug print if self._debug_draw: @@ -670,7 +761,7 @@ def _merge_part(self, scaffold: Chem.Mol, fragmentanda: Chem.Mol, anchor_index: bond_type = detail['type'] combo.AddBond(scaffold_anchor_index, scaffold_attachment_index, bond_type) new_bond = combo.GetBondBetweenAtoms(scaffold_anchor_index, scaffold_attachment_index) - #BondProvenance.set_bond(new_bond, '???') + # BondProvenance.set_bond(new_bond, '???') # self.transfer_ring_data(fragmentanda.GetAtomWithIdx(attachment_index), # combo.GetAtomWithIdx(scaffold_anchor_index)) for oi, oad in zip(other_attachments, other_attachment_details): @@ -679,7 +770,7 @@ def _merge_part(self, scaffold: Chem.Mol, fragmentanda: Chem.Mol, anchor_index: scaffold_anchor_index = indices.index(oi) + scaffold.GetNumAtoms() combo.AddBond(scaffold_anchor_index, scaffold_attachment_index, bond_type) new_bond = combo.GetBondBetweenAtoms(scaffold_anchor_index, scaffold_attachment_index) - #BondProvenance.set_bond(new_bond, '???') + # BondProvenance.set_bond(new_bond, '???') if self._debug_draw: print( f"Added additional {bond_type.name} bond between {scaffold_attachment_index} and {scaffold_anchor_index} " + \ @@ -815,6 +906,13 @@ def _categorise(self, mol: Chem.Mol, uniques: set) -> Dict[str, Union[set, Dict] # ========= Other ================================================================================================== def fix_hits(self, hits: List[Chem.Mol]) -> List[Chem.Mol]: + """ + Adds the ``_Name`` Prop if needed + asserts everything is a Chem.Mol + calls ``store_positions`` + :param hits: + :return: + """ for hi, hit in enumerate(hits): if isinstance(hit, str): warn(f'Hit {hi} is a string ({hit}). This route is not the intended way. Trying to read it.') @@ -831,6 +929,7 @@ def fix_hits(self, hits: List[Chem.Mol]) -> List[Chem.Mol]: # fallback naming. if not hit.HasProp('_Name') or hit.GetProp('_Name').strip() == '': hit.SetProp('_Name', f'hit{hi}') + # ====== IMPORTANT ========== self.store_positions(hit) return hits @@ -910,7 +1009,7 @@ def get_mcs_mappings(self, molA, molB, min_mode_index: int = 0) -> Tuple[List[Di return [dict(n) for n in neolax], mode else: # Then the strict will have to do. - return [dict(n) for n in strict], strict_settings # tuple to dict + return [dict(n) for n in strict], strict_settings # tuple to dict # raise ValueError('This is chemically impossible: nothing matches in the MCS step ' +\ # f'({len(self.matching_modes)} modes tried') diff --git a/fragmenstein/monster/_base.py b/fragmenstein/monster/_base.py index b9b6e05..32c6d38 100644 --- a/fragmenstein/monster/_base.py +++ b/fragmenstein/monster/_base.py @@ -6,8 +6,8 @@ from .bond_provenance import BondProvenance import logging -class _MonsterBaseMixin: +class _MonsterBaseMixin: journal = logging.getLogger('Fragmenstein') dummy_symbol = '*' @@ -71,12 +71,12 @@ def _closest__is_warhead_marked(atom): return atom.HasProp('_Warhead') and atom.GetBoolProp('_Warhead') is True # func: https://stackoverflow.com/questions/41921255/staticmethod-object-is-not-callable - closeness_weights =[ - (_closest__is_warhead_marked.__func__, np.nan), - (_closest__is_fullbonded.__func__, 1.0), - (_closest__is_ring_atom.__func__, 0.5) - # is_triangle, 2.0 - ] + closeness_weights = [ + (_closest__is_warhead_marked.__func__, np.nan), + (_closest__is_fullbonded.__func__, 1.0), + (_closest__is_ring_atom.__func__, 0.5) + # is_triangle, 2.0 + ] def _find_closest(self, mol_A: Chem.Mol, mol_B: Chem.Mol) -> Tuple[Chem.RWMol, int, int, float]: """ @@ -133,8 +133,8 @@ def get_closest(pendistance): candidates.append((anchor_A, anchor_B, distance)) return combo, candidates - - def _get_distance_matrix(self, combo: Chem.Mol, A: Union[Chem.Mol, np.ndarray], B: Union[Chem.Mol, np.ndarray]) -> np.ndarray: + def _get_distance_matrix(self, combo: Chem.Mol, A: Union[Chem.Mol, np.ndarray], + B: Union[Chem.Mol, np.ndarray]) -> np.ndarray: """ Called by ``_find_closest`` and ``_determine_mergers_novel_ringcore_pair`` in collapse ring (for expansion). @@ -205,45 +205,89 @@ def _delete_marked(self, mol: Chem.RWMol): # ============= Other ============================================================================================== - def _copy_bonding(self, mol, i: int, j: int, force: Optional[bool] = None): + def _copy_bonding(self, mol, keeper_idx: int, reject_idx: int, force: Optional[bool] = None): """ formerly called `absorb`. Preps for absorbing. remove J separately. + So copy bonding from i to j. :param mol: :param i: :param j: :return: """ - self.journal.debug(f'Absorbing atom {i} with {j}') - absorbenda = mol.GetAtomWithIdx(i) - absorbiturum = mol.GetAtomWithIdx(j) - for neighbor in absorbiturum.GetNeighbors(): - neigh_i = neighbor.GetIdx() - old_bond = mol.GetBondBetweenAtoms(j, neigh_i) + self.journal.debug(f'Absorbing atom {keeper_idx} with {reject_idx}, force={force}') + keeper = mol.GetAtomWithIdx(keeper_idx) + reject = mol.GetAtomWithIdx(reject_idx) + # prevent confusion when it comes to triangles + vertex = self._get_triangle(reject, keeper) + if vertex: + mol.RemoveBond(reject_idx, vertex) + # deal with neighbours of reject atom + for neighbor in reject.GetNeighbors(): + # collect bonding details between neighbour of reject and reject itself + neigh_idx = neighbor.GetIdx() + old_bond = mol.GetBondBetweenAtoms(reject_idx, neigh_idx) bt = old_bond.GetBondType() + # forcing? if force is not None: - pass - if old_bond.HasProp('_IsRingBond'): + force_bond = bool(force) + elif old_bond.HasProp('_IsRingBond'): # the ring needs to be force! - force = True + force_bond = True else: - force = False + force_bond = False # mol.RemoveBond(j, n) - if i == neigh_i: + if keeper_idx == neigh_idx: # the neighbour is the keeper continue else: - atom_i, atom_j = mol.GetAtomWithIdx(i), mol.GetAtomWithIdx(j) - if force and mol.GetBondBetweenAtoms(i, neigh_i) is None: - self.journal.debug(f'Forcing bond between {i} and {neigh_i}') - mol.AddBond(i, neigh_i, bt) - new_bond = mol.GetBondBetweenAtoms(i, neigh_i) - BondProvenance.copy_bond(old_bond, new_bond) + # copy bond. The provenance should be 'other_novel' not the original vai + # provenance = BondProvenance.get_bond(old_bond) + if force_bond and mol.GetBondBetweenAtoms(keeper_idx, neigh_idx) is None: + self.journal.debug(f'Forcing bond between {keeper_idx} and {neigh_idx}') + self._add_bond_regardlessly(mol=mol, + first=keeper, + second=neighbor, + bond_type=bt, + provenance='other_novel' + ) else: - self._add_bond_if_possible(mol, atom_i, atom_j) + self._add_bond_if_possible(mol=mol, + first=keeper, + second=neighbor, + provenance='other_novel') - def _add_bond_if_possible(self, mol, atom_i, atom_j, provenance='other_novel'): - i = atom_i.GetIdx() - j = atom_j.GetIdx() + def _add_bond_regardlessly(self, mol, first: Chem.Atom, second: Chem.Atom, bond_type, provenance='other_novel'): + """ + This methods does no checking and operates dangerously! + + :param mol: + :param first: + :param second: + :param bond_type: + :param provenance: + :return: + """ + first_idx = first.GetIdx() + second_idx = second.GetIdx() + # add if absent... (error prevention) + present_bond = mol.GetBondBetweenAtoms(first_idx, second_idx) + if present_bond is None: + mol.AddBond(first_idx, second_idx, bond_type) + new_bond = mol.GetBondBetweenAtoms(first_idx, second_idx) + BondProvenance.set_bond(new_bond, provenance) + + def _add_bond_if_possible(self, mol, first: Chem.Atom, second: Chem.Atom, provenance='other_novel'): + """ + This method is used by _copy_bonding, but triggered when force=False + + :param mol: + :param first: + :param second: + :param provenance: + :return: + """ + first_idx = first.GetIdx() + second_idx = second.GetIdx() def assess_atom(atom: Chem.Atom, bt: Chem.BondType) -> Tuple[bool, Chem.BondType]: """ @@ -265,23 +309,23 @@ def assess_atom(atom: Chem.Atom, bt: Chem.BondType) -> Tuple[bool, Chem.BondType else: return False, bt # too bonded already! - if self._is_triangle(atom_i, atom_j): - self.journal.debug(f'Bond between {i} and {j} would make a triangle, skipping') + if self._is_would_be_triangle(first, second): + self.journal.debug(f'Bond between {first_idx} and {second_idx} would make a triangle, skipping') return False - elif self._is_square(atom_i, atom_j): - self.journal.debug(f'Bond between {i} and {j} would make a square, skipping') + elif self._is_would_be_square(first, second): + self.journal.debug(f'Bond between {first_idx} and {second_idx} would make a square, skipping') return False - elif self._is_connected_warhead(atom_j, atom_i): - self.journal.debug(f'Bond between {i} and {j} would break a warhead, skipping') + elif self._is_connected_warhead(second, first): + self.journal.debug(f'Bond between {first_idx} and {second_idx} would break a warhead, skipping') return False else: - present_bond = mol.GetBondBetweenAtoms(i, j) - if atom_j.HasProp('_ring_bond'): - bt = getattr(Chem.BondType, atom_j.GetProp('_ring_bond')) + present_bond = mol.GetBondBetweenAtoms(first_idx, second_idx) + if second.HasProp('_ring_bond'): + bt = getattr(Chem.BondType, second.GetProp('_ring_bond')) else: bt = None if present_bond is not None and bt is None: - self.journal.debug(f'Bond between {i} and {j} already exists') + self.journal.debug(f'Bond between {first_idx} and {second_idx} already exists') pass # exists elif present_bond is not None and present_bond.GetBondType() is None: present_bond.SetBondType(Chem.BondType.SINGLE) @@ -291,16 +335,16 @@ def assess_atom(atom: Chem.Atom, bt: Chem.BondType) -> Tuple[bool, Chem.BondType present_bond.SetBondType(bt) return True else: - v, bt = assess_atom(atom_i, bt) - w, bt = assess_atom(atom_j, bt) + v, bt = assess_atom(first, bt) + w, bt = assess_atom(second, bt) if v and w and bt is not None: - mol.AddBond(i, j, bt) - new_bond = mol.GetBondBetweenAtoms(i, j) + mol.AddBond(first_idx, j, bt) + new_bond = mol.GetBondBetweenAtoms(first_idx, second_idx) BondProvenance.set_bond(new_bond, provenance) return True elif v and w: - mol.AddBond(i, j, Chem.BondType.SINGLE) - new_bond = mol.GetBondBetweenAtoms(i, j) + mol.AddBond(first_idx, second_idx, Chem.BondType.SINGLE) + new_bond = mol.GetBondBetweenAtoms(first_idx, second_idx) BondProvenance.set_bond(new_bond, provenance) return True else: @@ -310,7 +354,7 @@ def assess_atom(atom: Chem.Atom, bt: Chem.BondType) -> Tuple[bool, Chem.BondType # === conditional selectors ======================================================================================== - def _is_triangle(self, first: Chem.Atom, second: Chem.Atom) -> bool: + def _is_would_be_triangle(self, first: Chem.Atom, second: Chem.Atom) -> bool: """ Get bool of whether two atoms share a common neighbor. Ie. joining them would make a triangle. Direct bond does not count. @@ -324,6 +368,22 @@ def _is_triangle(self, first: Chem.Atom, second: Chem.Atom) -> bool: else: return False + + def _is_would_be_square(self, first: Chem.Atom, second: Chem.Atom) -> bool: + """ + Get bool of whether two atoms share a common neighbor+over-neighbor. Ie. joining them would make a square. + Direct bond does not count. + + :param first: + :param second: + :return: + """ + for third in [neigh for neigh in second.GetNeighbors() if neigh.GetIdx() != first.GetIdx()]: + if self._is_would_be_triangle(first, third) is True: + return True + else: + return False + def _get_triangle(self, first: Chem.Atom, second: Chem.Atom) -> Union[int, None]: """ Get the third atom... @@ -372,20 +432,6 @@ def _is_count_valid(self, atom: Chem.Atom) -> bool: else: return True - def _is_square(self, first: Chem.Atom, second: Chem.Atom) -> bool: - """ - Get bool of whether two atoms share a common over-neighbor. Ie. joining them would make a square. - Direct bond does not count. - - :param first: - :param second: - :return: - """ - for third in [neigh for neigh in second.GetNeighbors() if neigh.GetIdx() != first.GetIdx()]: - if self._is_triangle(first, third) is True: - return True - else: - return False def _get_square(self, first: Chem.Atom, second: Chem.Atom) -> Union[Tuple[int, int], None]: for third in [neigh for neigh in second.GetNeighbors() if neigh.GetIdx() != first.GetIdx()]: @@ -396,7 +442,6 @@ def _get_square(self, first: Chem.Atom, second: Chem.Atom) -> Union[Tuple[int, i else: return None - def _is_connected_warhead(self, atom, anchor_atom): if not atom.HasProp('_Warhead'): return False diff --git a/fragmenstein/monster/_utility_mixin.py b/fragmenstein/monster/_utility_mixin.py index e7be785..674b499 100644 --- a/fragmenstein/monster/_utility_mixin.py +++ b/fragmenstein/monster/_utility_mixin.py @@ -29,11 +29,6 @@ SVG = lambda *args, **kwargs: print('Install IPython...') display = lambda *args, **kwargs: print('Install IPython...') -try: - import pymol2 -except ImportError: - warn('No Pymol module installed. `.make_pse` will not work.') - pymol2 = None ######################################################################################################################## @@ -182,7 +177,7 @@ def save_temp(self, mol): def save_commonality(self, filename:Optional[str]=None): """ - Saves an SVG of the followup fragmenstein with the common atoms with the chimeric scaffold highlighted. + Saves an SVG of the followup fragmenstein monster with the common atoms with the chimeric scaffold highlighted. :param filename: optinal filename to save it as. Otherwise returns a Draw.MolDraw2DSVG object. :return: @@ -210,6 +205,7 @@ def make_pse(self, filename='test.pse', extra_mols:Optional[Chem.Mol]=None): :return: """ assert '.pse' in filename, 'Must be a pymol pse extension!' + import pymol2 with pymol2.PyMOL() as pymol: tints = iter(['wheat', 'palegreen', 'lightblue', 'paleyellow', 'lightpink', 'palecyan', 'lightorange', 'bluewhite']) #pymol.cmd.bg_color('white') diff --git a/fragmenstein/monster/unmerge_mapper.py b/fragmenstein/monster/unmerge_mapper.py index e3b795b..9a1369f 100644 --- a/fragmenstein/monster/unmerge_mapper.py +++ b/fragmenstein/monster/unmerge_mapper.py @@ -66,6 +66,8 @@ def __init__(self, followup: Chem.Mol, mols: List[Chem.Mol], maps: Dict[str, Lis self.mols = mols self.maps = maps self.no_discard = no_discard + if self.no_discard: + self.max_strikes = 100 self._debug_draw = _debug_draw accounted_for = set() self.c_map_options = [] diff --git a/test.py b/test.py index 8c2ea40..4c82093 100644 --- a/test.py +++ b/test.py @@ -213,6 +213,24 @@ def test_spirodituluene(self): gotten = Chem.MolToSmiles(Chem.RemoveHs(v.minimised_mol)) self.assertIn(gotten, after, f'{name} failed {gotten} (expected {after})') +# ---------------------------------------------------------------------------------------------------------------------- + + +class Internals(unittest.TestCase): + def test_triangle(self): + """ + Test triangle prevention. + """ + probanda = Chem.MolFromSmiles('CCC') + AllChem.EmbedMolecule(probanda) + monster = Monster([probanda]) + zeroth = probanda.GetAtomWithIdx(0) + second = probanda.GetAtomWithIdx(2) + # 0 - 2 would make a triangle + self.assertTrue(monster._is_would_be_triangle(zeroth, second)) # connecting zeroth and second would make a triangle + self.assertEqual(monster._get_triangle(zeroth, second),1) # connecting 0+2, would make 1 the vertex. + +# ---------------------------------------------------------------------------------------------------------------------- class UnresolvedProblems(unittest.TestCase): def test_recto_fail_A(self): """Not too sure why this fails. I think it is the alphatic - ring merger""" From da3551e1c4e7c552d7291113ef0e68ed3f2277c6 Mon Sep 17 00:00:00 2001 From: matteoferla Date: Mon, 1 Feb 2021 18:22:03 +0000 Subject: [PATCH 09/32] :construction: getting (not done) rid of non-method imports of pymol --- fragmenstein/victor/__init__.py | 3 ++- fragmenstein/victor/_victor_utils_mixin.py | 8 +++----- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/fragmenstein/victor/__init__.py b/fragmenstein/victor/__init__.py index fd59773..4a45578 100644 --- a/fragmenstein/victor/__init__.py +++ b/fragmenstein/victor/__init__.py @@ -20,7 +20,6 @@ import json import os -import pymol2 import re import warnings import pyrosetta @@ -474,6 +473,8 @@ def _get_attachment_from_pdbblock(self) -> Union[None, Chem.Mol]: Hence why `find_attachment` will replace it. todo `_get_attachment_from_pdbblock` --> `find_attachment` """ + import pymol2 + self.journal.debug(f'{self.long_name} - getting attachemnt atom') if not self.covalent_resn: return None diff --git a/fragmenstein/victor/_victor_utils_mixin.py b/fragmenstein/victor/_victor_utils_mixin.py index c1604db..96ce667 100644 --- a/fragmenstein/victor/_victor_utils_mixin.py +++ b/fragmenstein/victor/_victor_utils_mixin.py @@ -33,11 +33,6 @@ from ..igor import Igor from ._loggerwriter import LoggerWriter -try: - import pymol2 -except ImportError: - pymol2 = None - class _VictorUtilsMixin(_VictorBaseMixin): @@ -231,6 +226,7 @@ def distance_hits(cls, pdb_filenames: List[str], :return: """ distances = [] + import pymol2 with pymol2.PyMOL() as pymol: for hit in pdb_filenames: pymol.cmd.load(hit) @@ -348,6 +344,7 @@ def make_pse(self, filename: str = 'combo.pse', extra_mols:Optional[Chem.Mol]=No :return: """ assert '.pse' in filename, f'{filename} not .pse file' + import pymol2 with pymol2.PyMOL() as pymol: for hit in self.hits: hit_name = hit.GetProp('_Name') @@ -383,6 +380,7 @@ def make_pse(self, filename: str = 'combo.pse', extra_mols:Optional[Chem.Mol]=No pymol.cmd.save(os.path.join(self.work_path, self.long_name, filename)) def make_steps_pse(self, filename: str='step.pse'): + import pymol2 assert '.pse' in filename, f'{filename} not .pse file' with pymol2.PyMOL() as pymol: for hit in self.hits: From 90d5221a9ffaaa6f4e34d46bd3987d76158ebbf5 Mon Sep 17 00:00:00 2001 From: matteoferla Date: Mon, 1 Feb 2021 19:09:14 +0000 Subject: [PATCH 10/32] :tada: copies snippet to tests --- fragmenstein/monster/__init__.py | 6 +-- test.py | 80 +++++++++++++++++++++++--------- 2 files changed, 62 insertions(+), 24 deletions(-) diff --git a/fragmenstein/monster/__init__.py b/fragmenstein/monster/__init__.py index cdf9a78..6264b9e 100644 --- a/fragmenstein/monster/__init__.py +++ b/fragmenstein/monster/__init__.py @@ -532,8 +532,8 @@ def _prevent_two_bonds_on_dummy(self, mol: Chem.RWMol): neighs = atom.GetNeighbors() first = neighs[0] for second in neighs[1:]: - rejected = second.GetIdx() # that will be absorbed (deleted) - keeper = first.GetIdx() # that absorbs (kept) + rejected = second.GetIdx() # that will be absorbed (deleted) + keeper = first.GetIdx() # that absorbs (kept) self._copy_bonding(mol, keeper, rejected) self._mark_for_deletion(mol, rejected) self._delete_marked(mol) @@ -555,7 +555,7 @@ def make_chimera(self, min_mode_index=0) -> Chem.Mol: self.journal.debug(f"scaffold-followup: {follow}") if self._debug_draw: self.draw_nicely(self.initial_mol, highlightAtoms=atom_map.values()) - ## make the scaffold more like the followup to avoid weird matches. + # make the scaffold more like the followup to avoid weird matches. chimera = Chem.RWMol(self.scaffold) for scaff_ai, follow_ai in atom_map.items(): if self.scaffold.GetAtomWithIdx(scaff_ai).GetSymbol() != self.initial_mol.GetAtomWithIdx( diff --git a/test.py b/test.py index 4c82093..9951166 100644 --- a/test.py +++ b/test.py @@ -1,6 +1,7 @@ import unittest, os # ====================================================================================================================== import pyrosetta + pyrosetta.init( extra_options='-no_optH false -mute all -ex1 -ex2 -ignore_unrecognized_res false -load_PDB_components false -ignore_waters false') # ====================================================================================================================== @@ -9,6 +10,8 @@ from fragmenstein import Monster, Victor, Igor, Rectifier from fragmenstein.mpro import MProVictor +from typing import * + # ====================================================================================================================== @@ -25,16 +28,15 @@ def test_easy(self): # PAU-UNI-52c0427f-1 MProVictor.quick_renanimation = True victor = MProVictor.from_hit_codes(smiles='CCNc1ncc(C#N)cc1CN1CCN(C(=O)C*)CC1', - hit_codes=['x0692', 'x0305', 'x1249'], - long_name='2_ACL') - self.assertEqual(victor.error, '',victor.error) + hit_codes=['x0692', 'x0305', 'x1249'], + long_name='2_ACL') + self.assertEqual(victor.error, '', victor.error) self.assertIsNotNone(victor.minimised_mol, 'Failed minimisation') - msg = f'x1249 is the red herring, prediction: {victor.monster.unmatched}, '+\ + msg = f'x1249 is the red herring, prediction: {victor.monster.unmatched}, ' + \ f'while x0305 and x0692 the true inspirations {victor.monster.matched}' self.assertIn('x1249', victor.monster.unmatched, msg) self.assertIn('x0305', victor.monster.matched, msg) - victor.make_pse() def test_nasty(self): @@ -88,8 +90,8 @@ def test_pentachromatic(self): # ,'x2646' Victor.monster_throw_on_discard = True victor = MProVictor.from_hit_codes(smiles='Cc1ccncc1NC(=O)Cc1cccc(Cl)c1', - #hit_codes=['x0107','x0434','x0678','x0995','x1382'], - hit_codes=['x0107' ,'x0434', 'x1382'], + # hit_codes=['x0107','x0434','x0678','x0995','x1382'], + hit_codes=['x0107', 'x0434', 'x1382'], long_name='TRY-UNI-714a760b-6') self.assertEqual(victor.error, '', victor.error) self.assertIsNotNone(victor.minimised_mol, 'Failed minimisation') @@ -97,8 +99,9 @@ def test_pentachromatic(self): victor.make_pse(extra_mols=[actual]) rmsd = victor.validate(reference_mol=actual) self.assertLess(rmsd, 1, f'The RMSD is large...') - #self.assertIn('x1382', victor.monster.matched) - #self.assertIn('x0995', victor.monster.unmatched) # red herring + # self.assertIn('x1382', victor.monster.matched) + # self.assertIn('x0995', victor.monster.unmatched) # red herring + # ====================================================================================================================== @@ -108,10 +111,10 @@ def test_rectifier(self): # name: [before, after] chemdex = {'phenylnaphthalene': ('c1ccc2ccccc2c1(c3ccccc3)', 'c1ccc(-c2cccc3ccccc23)cc1'), 'benzo-azetine': ('C12CCCCC1CC2', 'C1CCC2CCCC2C1'), - #'conjoined': ('C1C2CCC2C1', 'C1CCCCC1'), # bridged hexane + # 'conjoined': ('C1C2CCC2C1', 'C1CCCCC1'), # bridged hexane 'allene': ('C=C=C', 'C=CC'), 'benzo-cyclopronane': ('C12CCCCC1C2', 'C1CCC2CCCC2C1'), - #'norbornane': ('C1CC2CCC1C2', 'C1CC2CCC1C2'), + # 'norbornane': ('C1CC2CCC1C2', 'C1CC2CCC1C2'), 'mixed ring': ('c1cccc2c1CCCC2', 'c1ccc2c(c1)CCCC2'), 'mixed ring': ('C1CCCc2c1cccc2', 'c1ccc2c(c1)CCCC2'), } @@ -125,7 +128,6 @@ def test_rectifier(self): gotten = Chem.MolToSmiles(recto.mol) self.assertEqual(gotten, after, f'{name} failed {gotten} (expected {after}) from {before}') - def test_cyclopentine(self): # aromatic cyclopent-ine -> cyclopentadiene name = 'cyclopentine' @@ -145,7 +147,7 @@ def test_bad_ring(self): after = 'c1ccc2c(c1)CCCC2' mol = Chem.MolFromSmiles(after) mol.SetProp('_Name', name) - mol.GetBondBetweenAtoms(0,1).SetBondType(Chem.BondType.SINGLE) + mol.GetBondBetweenAtoms(0, 1).SetBondType(Chem.BondType.SINGLE) before = Chem.MolToSmiles(mol) recto = Rectifier(mol).fix() gotten = Chem.MolToSmiles(recto.mol) @@ -157,8 +159,8 @@ def test_bad_ring2(self): after = 'c1ccc2ccccc2c1' mol = Chem.MolFromSmiles(before) mol.SetProp('_Name', name) - mol.GetBondBetweenAtoms(0,1).SetBondType(Chem.BondType.SINGLE) - mol.GetBondBetweenAtoms(6,7).SetBondType(Chem.BondType.AROMATIC) + mol.GetBondBetweenAtoms(0, 1).SetBondType(Chem.BondType.SINGLE) + mol.GetBondBetweenAtoms(6, 7).SetBondType(Chem.BondType.AROMATIC) before = Chem.MolToSmiles(mol) recto = Rectifier(mol).fix() gotten = Chem.MolToSmiles(recto.mol) @@ -213,6 +215,7 @@ def test_spirodituluene(self): gotten = Chem.MolToSmiles(Chem.RemoveHs(v.minimised_mol)) self.assertIn(gotten, after, f'{name} failed {gotten} (expected {after})') + # ---------------------------------------------------------------------------------------------------------------------- @@ -227,15 +230,51 @@ def test_triangle(self): zeroth = probanda.GetAtomWithIdx(0) second = probanda.GetAtomWithIdx(2) # 0 - 2 would make a triangle - self.assertTrue(monster._is_would_be_triangle(zeroth, second)) # connecting zeroth and second would make a triangle - self.assertEqual(monster._get_triangle(zeroth, second),1) # connecting 0+2, would make 1 the vertex. + self.assertTrue( + monster._is_would_be_triangle(zeroth, second)) # connecting zeroth and second would make a triangle + self.assertEqual(monster._get_triangle(zeroth, second), 1) # connecting 0+2, would make 1 the vertex. + + def make_mol(self, smiles: str) -> Chem.Mol: + mol = Chem.MolFromSmiles(smiles) + dummies = mol.GetAtomsMatchingQuery(Chem.rdqueries.AtomNumEqualsQueryAtom(0)) + for dummy in dummies: + dummy.SetAtomicNum(6) # carbon is 6 not 12! + AllChem.EmbedMolecule(mol) + for dummy in dummies: + dummy.SetAtomicNum(0) + return mol + + def make_pair_by_split(self, conjoined: Chem.Mol, atom_idx: int) -> Tuple[Chem.Mol]: + # make overlapping mols by getting a single molecule, and split it + # this gives more control over Chem.rdMolAlign.AlignMol as this may overlap other atoms. + # negative weights does not work... + # fore + bond = conjoined.GetBondBetweenAtoms(atom_idx, atom_idx + 1) + fragged = Chem.FragmentOnBonds(conjoined, [bond.GetIdx()], addDummies=False) + fore = Chem.GetMolFrags(fragged, asMols=True)[0] + bond = conjoined.GetBondBetweenAtoms(atom_idx - 1, atom_idx) + fragged = Chem.FragmentOnBonds(conjoined, [bond.GetIdx()], addDummies=False) + aft = Chem.GetMolFrags(fragged, asMols=True)[1] + return fore, aft + + def test_merge_on_same_dummy(self): + conjoined = self.make_mol('O=C(O)CSCC#N') + acetyl, nitrile = self.make_pair_by_split(conjoined, 4) + # merge + monster = Monster([acetyl, nitrile]) + merger = monster.merge_hits() + dummies = merger.GetAtomsMatchingQuery(Chem.rdqueries.AtomNumEqualsQueryAtom(0)) + for dummy in dummies: + self.assertEqual(len(dummy.GetNeighbors()), 1) + self.assertEqual(len(Chem.GetMolFrags(merger)), 1) + # ---------------------------------------------------------------------------------------------------------------------- class UnresolvedProblems(unittest.TestCase): def test_recto_fail_A(self): """Not too sure why this fails. I think it is the alphatic - ring merger""" MProVictor.monster_throw_on_discard = True - victor = MProVictor.combine_codes(hit_codes=['x11612','x11475']) + victor = MProVictor.combine_codes(hit_codes=['x11612', 'x11475']) self.assertEqual(victor.error, '', victor.error) def test_supplementary1_to_recto_fail_A(self): @@ -272,8 +311,7 @@ def test_supplementary1_to_recto_fail_A(self): monster.positioned_mol = monster.expand_ring(monster.scaffold) recto = Rectifier(monster.positioned_mol) # ====== - self.assertEqual(Chem.MolToSmiles(recto.mol), Chem.MolToSmiles(chlorotoluene)) #CC(Cl)CCc1ccccc1 - + self.assertEqual(Chem.MolToSmiles(recto.mol), Chem.MolToSmiles(chlorotoluene)) # CC(Cl)CCc1ccccc1 def test_supplementary2_to_recto_fail_A(self): """ @@ -313,4 +351,4 @@ def test_supplementary2_to_recto_fail_A(self): # ====== self.assertEqual(Chem.MolToSmiles(recto.mol), Chem.MolToSmiles(methylchlorotoluene)) -# Todo: add a class to test missing modules. \ No newline at end of file +# Todo: add a class to test missing modules. From 7a33efbc0127f8ad6dcd5b845433927945b253cd Mon Sep 17 00:00:00 2001 From: matteoferla Date: Wed, 3 Feb 2021 16:40:41 +0000 Subject: [PATCH 11/32] :truck: git added the laboratory folder... :warning: Incomplete :warning: --- fragmenstein/laboratory/__init__.py | 4 + fragmenstein/laboratory/_process.py | 53 +++++++++ fragmenstein/laboratory/laboratory.py | 111 ++++++++++++++++++ .../laboratory/make_pyrosetta_options.py | 35 ++++++ fragmenstein/laboratory/pyrosetta_log.py | 44 +++++++ 5 files changed, 247 insertions(+) create mode 100644 fragmenstein/laboratory/__init__.py create mode 100644 fragmenstein/laboratory/_process.py create mode 100644 fragmenstein/laboratory/laboratory.py create mode 100644 fragmenstein/laboratory/make_pyrosetta_options.py create mode 100644 fragmenstein/laboratory/pyrosetta_log.py diff --git a/fragmenstein/laboratory/__init__.py b/fragmenstein/laboratory/__init__.py new file mode 100644 index 0000000..f914f4f --- /dev/null +++ b/fragmenstein/laboratory/__init__.py @@ -0,0 +1,4 @@ +from ._process import process # config for a run +from .laboratory import Laboratory # prepping data and analysis +from .make_pyrosetta_options import make_option_string # make the pyrosetta init str a dict +from .pyrosetta_log import get_log_entries, configure_logger # capture log properly diff --git a/fragmenstein/laboratory/_process.py b/fragmenstein/laboratory/_process.py new file mode 100644 index 0000000..cdd0271 --- /dev/null +++ b/fragmenstein/laboratory/_process.py @@ -0,0 +1,53 @@ +from typing import Dict, List, Union + + +def process(data: Dict[str, Union[str, dict]]): + # read data + project = data['project'] + db_name = f'{project}.sqlite' + hit_blocks = data['hit_blocks'] + name = '-'.join(hit_blocks.keys()) + print('**********', name) + # imports ------------------------------------------------------ + import pyrosetta, logging + from .make_pyrosetta_options import make_option_string + pyrosetta.distributed.maybe_init(extra_options=make_option_string(no_optH=False, + mute='all', + ignore_unrecognized_res=True, + load_PDB_components=False)) + from fragmenstein.mpro import MProVictor + from sqlitedict import SqliteDict + import json, logging + # fix hits ------------------------------------------------------ + from rdkit import Chem + hits = [] + for hit_name in hit_blocks: + hit = Chem.MolFromMolBlock(hit_blocks[hit_name]) + hit.SetProp('_Name', hit_name) + hits.append(hit) + # settings for Fragmenstein ------------------------------------ + MProVictor.work_path = f'{project}' # db_name + MProVictor.monster_throw_on_discard = True + MProVictor.monster_joining_cutoff = 5 # 10 + MProVictor.quick_renanimation = False + MProVictor.error_to_catch = Exception + MProVictor.enable_stdout(logging.ERROR) + MProVictor.enable_logfile(f'{project}.log', logging.INFO) + MProVictor.log_errors() + # analyse ------------------------------------------------------ + try: + v = MProVictor.combine(hits=hits) + results = SqliteDict(db_name, encode=json.dumps, decode=json.loads, autocommit=True) + results[v.long_name] = v.summarise() + if not v.error: + v.make_pse() + print('DONE', [hit.GetProp('_Name') for hit in hits]) + return v.minimised_mol + except Exception as error: + error_msg = f'{error.__class__.__name__} {error}' + results = SqliteDict(db_name, encode=json.dumps, decode=json.loads, autocommit=True) + results[name] = {'error': error_msg} + MProVictor.journal.critical(f'*** {error_msg}, data: {data}') + except ConnectionError: + pass + return None diff --git a/fragmenstein/laboratory/laboratory.py b/fragmenstein/laboratory/laboratory.py new file mode 100644 index 0000000..626c196 --- /dev/null +++ b/fragmenstein/laboratory/laboratory.py @@ -0,0 +1,111 @@ +## INCOMPLETE + +raise NotImplementedError + + +from sqlitedict import SqliteDict +from rdkit.Chem import PandasTools +import json +import pandas as pd +from fragmenstein.victor import Victor + +import numpy as np +import os +from rdkit import Chem +from rdkit.Chem import AllChem +from scipy.stats import skewnorm, gennorm +from typing import Dict, List, Union + +from ._process import process + +class Laboratory: + + def __init__(self, project, hits: list[Chem.Mol]): + self.project = project + self.hits = {hit.GetProp('_Name'): hit for hit in hits} + if None in self.hits: + raise ValueError('Molecule without a name given.') + + def merge(self, cores = 25): + ## Process + pass + + + + + + + def old_ranker(self, row): + try: + return float(row['∆∆G']) / 5 + float( + row.comRMSD) + row.N_unconstrained_atoms / 5 - row.N_constrained_atoms / 10 + # return float(row['∆∆G'])/(row.N_unconstrained_atoms + row.N_constrained_atoms * 0.5)*10 + float(row.comRMSD) + except: + return float('nan') + + rank_weights = {'LE': 1., 'comRMSD': 2., 'atom_bonus': 2., 'novelty_penalty': 5.} + + def ranker(self, row): + try: + # atom_bonus = row.N_constrained_atoms / (20 + row.N_constrained_atoms) + # atom_bonus = skewnorm.pdf((row.N_constrained_atoms - 20)/8, 3) + ζ = (row.N_constrained_atoms ** 2 - 25 ** 2) / 500 + atom_bonus = gennorm.pdf(ζ, 5) / 0.5445622105291682 + novelty_penalty = row.N_unconstrained_atoms / row.N_constrained_atoms + return rank_weights['LE'] * float(row.LE) + \ + rank_weights['comRMSD'] * float(row.comRMSD) + \ + - rank_weights['atom_bonus'] * atom_bonus + \ + rank_weights['novelty_penalty'] * novelty_penalty + except: + return float('nan') + + def LE(self, row): + try: + return float(row['∆∆G']) / (row.N_unconstrained_atoms + row.N_constrained_atoms) + except: + return float('nan') + + def get_mol3D(self, name): + path = os.path.join(Victor.work_path, name, name + '.minimised.mol') + if os.path.exists(path): + try: + mol = Chem.MolFromMolFile(path, sanitize=True) + if mol is None: + return None + Chem.SanitizeMol(mol, sanitizeOps=Chem.SanitizeFlags.SANITIZE_ALL) + return mol + except Exception as error: + print(f'{type(error)}: {error}') + return None + else: + return None + + def get_table(self, db_name, mols=True, mol_only=True): + results = SqliteDict(db_name, encode=json.dumps, decode=json.loads, autocommit=True) + result_table = pd.DataFrame(results.values()) + print(len(result_table), sum(~result_table['∆∆G'].isna())) + result_table['LE'] = result_table.apply(LE, 1) + rank = result_table.apply(ranker, axis=1).rank() + m = np.nanmax(rank.values) + result_table['%Rank'] = rank / m * 100 + result_table['N_hits'] = result_table.regarded.apply(lambda x: len(x) if str(x) != 'nan' else float('nan')) + result_table = result_table.loc[~result_table.smiles.isna()].sort_values(['%Rank'], axis=0) + if mols: + result_table['mol3D'] = result_table['name'].apply(get_mol3D) + # result_table['mol2D'] = result_table['name'].apply(get_mol2D) + PandasTools.AddMoleculeColumnToFrame(result_table, 'smiles', 'mol2D') + if mol_only: + result_table = result_table.loc[~result_table.mol3D.isna()] + return result_table + + atom_Ns = {} + + for folder in ('newinputs',): # 'input', 'UCSF2-hits', 'frags'): + for file in os.listdir(folder): + if '.mol' in file: + mol = Chem.MolFromMolFile(os.path.join(folder, file), sanitize=False) + if mol is None: + atom_Ns[file.replace('.mol', '')] = 0 # float nan? + else: + mol = Chem.GetMolFrags(mol, asMols=True)[0] # just in case + atom_Ns[file.replace('.mol', '')] = mol.GetNumAtoms() \ No newline at end of file diff --git a/fragmenstein/laboratory/make_pyrosetta_options.py b/fragmenstein/laboratory/make_pyrosetta_options.py new file mode 100644 index 0000000..d71cd93 --- /dev/null +++ b/fragmenstein/laboratory/make_pyrosetta_options.py @@ -0,0 +1,35 @@ +## Copied from https://github.com/matteoferla/pyrosetta_scripts/tree/main/init_helper + +def make_option_string(**options): + """ + This just converts the key:value pairs to a command line string for the pyrosetta init. + + >> make_option_string(no_optH=False, ex1=None, remodel=dict(blueprint='mod.blue')) + + Bools are converted, + None results in a value argument, + Tuples are converted to xx:xx type arguments + Dictionaries are converted to xx:xx type arguments (multiple, if multiple keys in the nested dictionary) + + Also... Full option list: https://www.rosettacommons.org/docs/latest/full-options-list + """ + + def format_inner(v): + if v is None: + return '' + elif v in (False, True): + return ' ' + str(v).lower() + else: + return ' ' + str(v) + + def format_outer(k): + if isinstance(options[k], tuple): + return '-' + ':'.join(k) + format_inner(options[k]) + elif isinstance(options[k], dict): + return ' '.join([f'-{k}:{k2}' + format_inner(v2) for k2, v2 in options[k].items()]) + else: + return '-' + k + format_inner(options[k]) + + args = [format_outer(k) for k in options] + return ' '.join(args) + diff --git a/fragmenstein/laboratory/pyrosetta_log.py b/fragmenstein/laboratory/pyrosetta_log.py new file mode 100644 index 0000000..f1d75c9 --- /dev/null +++ b/fragmenstein/laboratory/pyrosetta_log.py @@ -0,0 +1,44 @@ +## Copied from https://github.com/matteoferla/pyrosetta_scripts/tree/main/init_helper + +import io +import logging +import pyrosetta +import re +from typing import Union, List + + +def configure_logger() -> logging.Logger: + """ + The function `get_logger`, simply adds a stringIO handler to the log and captures the log, + thus making it easier to use. + The function `get_log_entries`, spits out entries of a given level. + + :return: logger + """ + pyrosetta.logging_support.set_logging_sink() + logger = logging.getLogger("rosetta") + logger.setLevel(logging.INFO) # default = logging.WARNING + stringio = io.StringIO() + handler = logging.StreamHandler(stringio) + handler.setLevel(logging.INFO) + # handler.set_name('stringio') + handler.setFormatter(logging.Formatter('[%(asctime)s] %(levelname)s - %(message)s')) + logger.addHandler(handler) + return logger + + +def get_log_entries(levelname: Union[str, int] = logging.INFO) -> List[str]: + """ + Get a list of all entries in log at a given level. + levelname can be either an int (``logging.INFO`` etc. are numbers multiples of 10 in increasing severity) + or a string of the level. + Note that it is very crude: if INFO is requested, ERROR is not shown! + + :param levelname: int for the level number or str of the name + :return: List of str + """ + if isinstance(levelname, int): + # logging.INFO is actually an int, not an enum + levelname = logging.getLevelName(levelname) + stringio = logging.getLogger("rosetta").handlers[0].stream + return re.findall(f'(\[.*\] {levelname} - [\w\W]*)', stringio.getvalue()) From 18d4ac56ec5a60504c947fa830d70513613bd3e9 Mon Sep 17 00:00:00 2001 From: matteoferla Date: Wed, 3 Feb 2021 16:42:41 +0000 Subject: [PATCH 12/32] :mouse: minor changes --- fragmenstein/victor/__init__.py | 7 ++++--- fragmenstein/victor/_loggerwriter.py | 2 +- fragmenstein/victor/_victor_automerge_mixin.py | 4 ++-- fragmenstein/victor/junk.py | 4 ++-- 4 files changed, 9 insertions(+), 8 deletions(-) diff --git a/fragmenstein/victor/__init__.py b/fragmenstein/victor/__init__.py index 4a45578..1b1d058 100644 --- a/fragmenstein/victor/__init__.py +++ b/fragmenstein/victor/__init__.py @@ -100,7 +100,8 @@ def __init__(self, # entry attributes self.long_name = self.slugify(long_name) self.smiles = smiles - self.apo_pdbblock = open(pdb_filename).read() + with open(pdb_filename) as fh: + self.apo_pdbblock = fh.read() self.hits = hits self.ligand_resn = ligand_resn.upper() self.ligand_resi = ligand_resi @@ -203,8 +204,8 @@ def _analyse(self) -> None: # make params self.journal.debug(f'{self.long_name} - Starting parameterisation') self.params = Params.from_smiles(self.smiles, name=self.ligand_resn, generic=False, atomnames=self.atomnames) - self.journal.warning(f'{self.long_name} - CHI HAS BEEN DISABLED') - self.params.CHI.data = [] # TODO fix chi + #self.journal.warning(f'{self.long_name} - CHI HAS BEEN DISABLED') + #self.params.CHI.data = [] # Chi is fixed, but older version. should probably check version self.mol = self.params.mol self._log_warnings() # get constraint diff --git a/fragmenstein/victor/_loggerwriter.py b/fragmenstein/victor/_loggerwriter.py index d1353e1..4dd15b1 100644 --- a/fragmenstein/victor/_loggerwriter.py +++ b/fragmenstein/victor/_loggerwriter.py @@ -18,4 +18,4 @@ def write(self, message): def flush(self): if self._msg != '': self._writer(self._msg) - self._msg = '' \ No newline at end of file + self._msg = '' diff --git a/fragmenstein/victor/_victor_automerge_mixin.py b/fragmenstein/victor/_victor_automerge_mixin.py index ebdbaae..eddc90c 100644 --- a/fragmenstein/victor/_victor_automerge_mixin.py +++ b/fragmenstein/victor/_victor_automerge_mixin.py @@ -174,8 +174,8 @@ def _combine_main(self): # those Hs lack correct names and charge!! self.params.add_Hs() self.params.convert_mol() - self.journal.warning(f'{self.long_name} - CHI HAS BEEN DISABLED') - self.params.CHI.data = [] # TODO check if chi fix is okay + # self.journal.warning(f'{self.long_name} - CHI HAS BEEN DISABLED') + # self.params.CHI.data = [] # TODO check if chi fix is okay self._log_warnings() self.post_params_step() self.monster_merging_mode = 'full' diff --git a/fragmenstein/victor/junk.py b/fragmenstein/victor/junk.py index 5576ca2..37ad50a 100644 --- a/fragmenstein/victor/junk.py +++ b/fragmenstein/victor/junk.py @@ -96,8 +96,8 @@ def _vanalyse(self): smiles=self.smiles, generic= False, name=self.ligand_resn, proximityBonding=False) - self.journal.warning(f'{self.long_name} - CHI HAS BEEN DISABLED') - self.params.CHI.data = [] # TODO fix chi + # self.journal.warning(f'{self.long_name} - CHI HAS BEEN DISABLED') + # self.params.CHI.data = [] # TODO fix chi self.mol = self.params.mol self._log_warnings() # get constraint From 9f34579f0277742825eba3cb42e394559552a8ba Mon Sep 17 00:00:00 2001 From: matteoferla Date: Wed, 3 Feb 2021 19:09:54 +0000 Subject: [PATCH 13/32] :hammer: minor refactoring & completion of Monster().place vs. Monster().merge() split --- documentation/_snippets.md | 12 ++ documentation/covalents.md | 2 +- documentation/monster/monster.md | 4 +- documentation/monster/monster_full.md | 4 +- documentation/sphinx-docs.md | 2 +- fragmenstein/monster/__init__.py | 196 ++++++++++-------- fragmenstein/mpro/__init__.py | 62 ++++-- fragmenstein/victor/__init__.py | 110 ++++++---- .../victor/_victor_automerge_mixin.py | 19 +- fragmenstein/victor/junk.py | 2 +- 10 files changed, 244 insertions(+), 169 deletions(-) create mode 100644 documentation/_snippets.md diff --git a/documentation/_snippets.md b/documentation/_snippets.md new file mode 100644 index 0000000..688a511 --- /dev/null +++ b/documentation/_snippets.md @@ -0,0 +1,12 @@ +These are snippets that need to go somewhere +# 1 + +To make Victor carp at any exception, do + + Victor.error_to_catch = () + +This is because `try`/`except` can accept multiple error classes as a tuple. + +# 2 + +`ConnectionError` is meant for comms connection errors, but here it is raised as bad bonding. \ No newline at end of file diff --git a/documentation/covalents.md b/documentation/covalents.md index 2240b93..0d1ca82 100644 --- a/documentation/covalents.md +++ b/documentation/covalents.md @@ -10,7 +10,7 @@ Fragalysis does not do this, so the hits from there will be treated as regular c ## Monster -A molecule with a single atom is passed to `attachement` argument of `Monster`, +A molecule with a single atom is passed to `attachment` argument of `Monster`, then the covalent linker if absent in the hits is anchored to that atom. If you know a ligand that is covalent `Victor.find_attachment` can be used to extract the attachment atom. diff --git a/documentation/monster/monster.md b/documentation/monster/monster.md index 6191821..6c9f90f 100644 --- a/documentation/monster/monster.md +++ b/documentation/monster/monster.md @@ -90,7 +90,7 @@ For a comparison see [three modes compared](three_modes_compared.md). ## Covalent If the `Chem.Mol` has a dummy atom (element symbol: `*` within RDKit and smiles, but `R` in a mol file and PDB file) and -a molecule with a single atom is passed to `attachement` argument, then the covalent linker if absent in the hits is anchored +a molecule with a single atom is passed to `attachment` argument, then the covalent linker if absent in the hits is anchored to that atom. The default dummy atom can be overridden with `Fragmenstein.dummy:Chem.Mol` and `Fragmenstein.dummy_symbol:str`. @@ -110,7 +110,7 @@ Many atoms may be novel and added to the followup. ## Placing -The method called by the class `place_followup`, placed the followup using those atoms. +The method called by the class `place_from_map`, placed the followup using those atoms. To do a contrained embed in RDKit the reference atoms need to have a good geometry. Consequently, this is not possible. diff --git a/documentation/monster/monster_full.md b/documentation/monster/monster_full.md index 75e2de9..6910645 100644 --- a/documentation/monster/monster_full.md +++ b/documentation/monster/monster_full.md @@ -28,7 +28,7 @@ The following steps are done: * `.merge_hits()`: merges the hits, the output `rdkit.Chem.Mol` object added as `.scaffold`. * `.make_chimera()`: makes the atomic elements in `.scaffold` match those in the followup, the output `rdkit.Chem.Mol` object added as `.chimera`. -* `.place_followup()` followup is places like the scaffold. +* `.place_from_map()` followup is places like the scaffold. ## Merger The merger of the hits does not use MCS. @@ -79,7 +79,7 @@ This step is needed to avoid weird matches with the followup. # further alignments... not correct way of tho monster.initial_mol = new_mol - aligned = monster.place_followup(new_mol) + aligned = monster.place_from_map(new_mol) ## Issues to be aware of diff --git a/documentation/sphinx-docs.md b/documentation/sphinx-docs.md index f85ff6d..893a250 100644 --- a/documentation/sphinx-docs.md +++ b/documentation/sphinx-docs.md @@ -139,7 +139,7 @@ Recursively stick the hits together and average the positions. -#### place_followup(mol=None) +#### place_from_map(mol=None) * **Return type** diff --git a/fragmenstein/monster/__init__.py b/fragmenstein/monster/__init__.py index 6264b9e..0fff1df 100644 --- a/fragmenstein/monster/__init__.py +++ b/fragmenstein/monster/__init__.py @@ -1,5 +1,5 @@ ######################################################################################################################## - +# TODO this file is over 1,000 lines long! __doc__ = \ """ This is Monster proper. and contains the class ``Monster``. @@ -38,6 +38,13 @@ class Monster(_MonsterUtil, _MonsterRing, GPM, _MonsterJoinNeighMixin): # Unmerge is called. Not inherited. """ + This creates a stitched together monster. + For initilialisation for either placing or merging, it needs a list of hits (rdkit.Chem.Mol). + + The calculation are done either by place or merge. + + ## Place + monster.place(mol) Given a RDKit molecule and a series of hits it makes a spatially stitched together version of the initial molecule based on the hits. The reason is to do place the followup compound to the hits as faithfully as possible regardless of the screaming forcefields. @@ -61,14 +68,14 @@ class Monster(_MonsterUtil, _MonsterRing, GPM, _MonsterJoinNeighMixin): # Unmer defined in the ``dummy`` class variable. Namely element R in mol file or * in string is the default. """ + # TODO move to base and move out all the methods. def __init__(self, hits: List[Chem.Mol], - attachment: Optional[Chem.Mol] = None, debug_draw: bool = False, average_position=False): """ Initialisation starts Monster, but it does not do any mergers or placements. - This is changed in revision 0.6. + This is changed in revision 0.6 (previously `mol` was specified for the latter) :param hits: hits are a list of rdkit molecules :param attachment: @@ -78,121 +85,130 @@ def __init__(self, # starting attributes # formerly this was present... but it does nothing. # super().__init__() - # bar for self._debug_draw = _debug_draw from _MonsterRing + # bar for self._debug_draw = _debug_draw from _MonsterRing it is empty. # ==== hits =========================================== - self.hits = self.fix_hits(hits) # list of hits # fix_hits: assert Chem.Mol, fix name if needed and store positions (see ``store_positions``) + self.hits = self.fix_hits(hits) # list of hits # ==== other ========================================== self._debug_draw = debug_draw # Jupyter notebook only. self.average_position = average_position # ==== To do be filled ================================ # List[str] - self.unmatched = [] #: rejected hits + self.unmatched = [] #: rejected hit names # self.matched is dynamic. #: accepted hits # Chem.Mol or List[Chem.Mol] self.modifications = [] - self.initial_mol = None + self.initial_mol = None #: to be filled + self.attachment = None # self.scaffold = None #: template which may have wrong elements # self.scaffold_options = [] #: partial combined templates (merging_mode: partial) self.scaffolds = [] #: templates which may have wrong elements self.chimera = None #: merger of hits but with atoms made to match the to-be-aligned mol self.positioned_mol = None #: final molecule - def place(self, mol: Chem.Mol): - pass + # TODO move these to own file + # ================================================================================================================== - def place_smiles(self, smiles: str): + def place(self, + mol: Chem.Mol, + attachment: Optional[Chem.Mol] = None, + merging_mode: str = 'none_permissive'): + self.initial_mol, self.attachment = self._parse_mol_for_place(mol, attachment) + # Reset + self.unmatched = [] + self.scaffold_options = [] + # do calculations + if merging_mode == 'off': + pass + elif merging_mode == 'full': + self.full_merging() + elif merging_mode == 'partial': + self.partial_merging() + elif merging_mode == 'none_permissive' or merging_mode == 'permissive_none': + self.no_merging(broad=True) + elif merging_mode == 'none': + self.no_merging() + else: + valid_modes = ('full','partial','none','none_permissive', 'off') + raise ValueError( + f"Merging mode can only be {'| '.join(valid_modes)}, not '{merging_mode}'") + return self + + def place_smiles(self, + smiles: str, + attachment: Optional[Chem.Mol] = None): mol = Chem.MolFromSmiles(smiles) - self.place(mol) + self.place(mol=mol, attachment=attachment) + return self + + def _parse_mol_for_place(self, + mol: Chem.Mol, + attachment: Optional[Chem.Mol] = None): + # ------------- store mol --------------------------------------- + if mol.HasSubstructMatch(self.dummy) and attachment: + pass + elif mol.HasSubstructMatch(self.dummy): + warn('No attachment atom provided but dummy atom present --- ignoring.') + attachment = None + elif attachment: + warn('Attachment atom provided but dummy atom not present --- ignoring.') + attachment = None + else: + attachment = None + return mol, attachment + + # TODO move these to own file + # ================================================================================================================== - def merge(self, keep_all=False, collapse_rings=True): + def merge(self, keep_all=True, collapse_rings=True, joining_cutoff: int = 5): """ + Merge the hits. + + :param keep_all: + :param collapse_rings: + :param joining_cutoff: :return: """ + # The following override class declared attributes. TODO declare them in __init__ + self.joining_cutoff = joining_cutoff + self.throw_on_discard = keep_all # merge! - col_hits = self.collapse_mols(self.hits) - self.modifications.extend(col_hits) - self.monster.scaffold = self.merge_hits(col_hits) - self.modifications.append(Chem.Mol(self.monster.scaffold)) # backup for debug - self._log_warnings() + if collapse_rings: + col_hits = self.collapse_mols(self.hits) + self.modifications.extend(col_hits) + else: + col_hits = self.hits + self.scaffold = self.merge_hits(col_hits) + self.modifications.append(Chem.Mol(self.scaffold)) # backup for debug ## Discard can happen for other reasons than disconnect - if self.monster_throw_on_discard and len(self.monster.unmatched): - raise ConnectionError(f'{self.long_name} - Could not combine with {self.monster.unmatched} ' + \ - f'(>{self.monster.joining_cutoff}') + if keep_all and len(self.unmatched): + raise ConnectionError(f'Could not combine with {self.unmatched} (>{self.joining_cutoff}') # expand and fix - self._log_warnings() - self.journal.debug(f'{self.long_name} - Merged') - self.monster.positioned_mol = self.monster.expand_ring(self.monster.scaffold) + self.journal.debug(f'Merged') + if collapse_rings: + self.positioned_mol = self.expand_ring(self.scaffold) # bonded_as_original=False no longer needed. - self.modifications.append(Chem.Mol(self.monster.positioned_mol)) # backup for debug - self._log_warnings() - self.journal.debug(f'{self.long_name} - Expanded') - recto = Rectifier(self.monster.positioned_mol) + self.modifications.append(Chem.Mol(self.positioned_mol)) # backup for debug + self.journal.debug(f'Expanded') + self.rectify() + self.journal.debug(f'Rectified') + return self + + def rectify(self): + recto = Rectifier(self.positioned_mol) try: recto.fix() except ConnectionError: self.journal.critical(f'This really odd cornercase: Rectifier broke the mol.') - mol = self.monster._emergency_joining(recto.mol) + mol = self._emergency_joining(recto.mol) recto = Rectifier(self.monster.positioned_mol) recto.fix() - self.monster.positioned_mol = recto.mol + self.positioned_mol = recto.mol self.modifications.extend(recto.modifications) # backup for debug - # - # def __init__(self, mol: Chem.Mol, hits: List[Chem.Mol], attachment: Optional[Chem.Mol] = None, - # debug_draw: bool = False, merging_mode='partial', average_position=False): - # """ - # Merging mode controls what algorithm to use. - # - # * 'full': a single scaffold is made - # * 'partial': multiple possible scaffolds and best is chosen - # * 'none': no merging is done. The hits are mapped individually. Not great for small fragments. - # * 'off': do nothing. - # - # :param mol: - # :param hits: - # :param attachment: - # :param debug_draw: - # :param merging_mode: full | partial | none | off - # """ - # # starting attributes - # # self._debug_draw = _debug_draw from _MonsterRing - # super().__init__() - # self.initial_mol = mol # untouched. - # if self.initial_mol.HasSubstructMatch(self.dummy) and attachment: - # self.attachement = attachment - # elif self.initial_mol.HasSubstructMatch(self.dummy): - # warn('No attachment atom provided but dummy atom present --- ignoring.') - # self.attachement = None - # elif attachment: - # warn('Attachment atom provided but dummy atom not present --- ignoring.') - # self.attachement = None - # else: - # self.attachement = None - # # Chem.RemoveHs(self.initial_mol) - # self.hits = self.fix_hits(hits) # list of hits - # self._debug_draw = debug_draw # Jupyter notebook only. - # self.unmatched = [] - # self.average_position = average_position - # # derived attributes - # self.scaffold = None #: template which may have wrong elements - # self.scaffold_options = [] #: partial combined templates (merging_mode: partial) - # self.chimera = None #: merger of hits but with atoms made to match the to-be-aligned mol - # self.positioned_mol = None #: final molecule - # # do calculations - # if merging_mode == 'off': - # pass - # elif merging_mode == 'full': - # self.full_merging() - # elif merging_mode == 'partial': - # self.partial_merging() - # elif merging_mode == 'none_permissive' or merging_mode == 'permissive_none': - # self.no_merging(broad=True) - # elif merging_mode == 'none': - # self.no_merging() - # else: - # raise ValueError( - # f"Merging mode can only be 'full' | 'partial' | 'none' | 'none_permissive' | 'off', not '{merging_mode}'") + + # TODO move these to own file + # ================================================================================================================== @classmethod def full_merging(self) -> None: @@ -202,7 +218,7 @@ def full_merging(self) -> None: self.scaffold_options = [self.merge_hits()] self.scaffold = self.posthoc_refine(self.scaffold_options[0]) self.chimera = self.make_chimera() - self.positioned_mol = self.place_followup() + self.positioned_mol = self.place_from_map() def partial_merging(self) -> None: """ @@ -214,7 +230,7 @@ def partial_merging(self) -> None: self.unmatched = [h.GetProp('_Name') for h in self.hits if h.GetProp('_Name') not in used] self.scaffold = self.posthoc_refine(unrefined_scaffold) self.chimera = self.make_chimera(mode_index) - self.positioned_mol = self.place_followup() + self.positioned_mol = self.place_from_map() def no_merging(self, broad=False) -> None: """ @@ -251,7 +267,7 @@ def no_merging(self, broad=False) -> None: self.draw_nicely(self.initial_mol) print('scaffold') self.draw_nicely(self.scaffold) - placed = self.place_followup(atom_map=full_atom_map) + placed = self.place_from_map(atom_map=full_atom_map) self.positioned_mol = self.posthoc_refine(placed) # ========== Merging =============================================================================================== @@ -585,7 +601,7 @@ def make_chimera(self, min_mode_index=0) -> Chem.Mol: warn('Valance issue' + str(err)) return chimera - def place_followup(self, mol: Chem.Mol = None, atom_map: Optional[Dict] = None) -> Chem.Mol: + def place_from_map(self, mol: Chem.Mol = None, atom_map: Optional[Dict] = None) -> Chem.Mol: """ This method places the atoms with known mapping and places the 'uniques' (novel) via an aligned mol (the 'sextant') @@ -658,9 +674,9 @@ def place_followup(self, mol: Chem.Mol = None, atom_map: Optional[Dict] = None) i.GetIdx() not in uniques] for n in neighs: sights.add((n, n)) - if self.attachement and list(categories['dummies']) and list(categories['dummies'])[0] in team: + if self.attachment and list(categories['dummies']) and list(categories['dummies'])[0] in team: r = list(categories['dummies'])[0] - pconf.SetAtomPosition(r, self.attachement.GetConformer().GetAtomPosition(0)) + pconf.SetAtomPosition(r, self.attachment.GetConformer().GetAtomPosition(0)) sights.add((r, r)) rdMolAlign.AlignMol(sextant, putty, atomMap=list(sights), maxIters=500) sconf = sextant.GetConformer() diff --git a/fragmenstein/mpro/__init__.py b/fragmenstein/mpro/__init__.py index 4fb7438..50b4be5 100644 --- a/fragmenstein/mpro/__init__.py +++ b/fragmenstein/mpro/__init__.py @@ -26,7 +26,7 @@ import requests -def pose_fx(pose): +def pose_fx(pose: pyrosetta.Pose): """ Histidine in delta. """ @@ -36,7 +36,7 @@ def pose_fx(pose): MutateResidue(target=r, new_res='HIS').apply(pose) -def poised_pose_fx(pose): +def poised_pose_fx(pose: pyrosetta.Pose): """ Histidine in delta and cysteine in thiolate. """ @@ -130,28 +130,50 @@ def __init__(self, smiles: str, hits:List[Chem.Mol], long_name:str, category:Opt pose_fx=fx, atomnames=atomnames) + def __init__(self, category:Optional[str]=None, **options): + # this category flag is solely for Mpro. # TODO check. + if category == 'noncolavent': + fx = poised_pose_fx + else: + fx = pose_fx + extra_constraint = 'AtomPair SG 145A NE2 41A HARMONIC 3.5 0.2\n' + if category not in (None, 'noncovalent') and '_' in category: + cname, rxd = category.split('_') + if rxd == 'noncovalent': + wd = [wd for wd in self.warhead_definitions if wd['name'] == cname][0] + mol = Chem.MolFromSmiles(options['smiles']) + nc = Chem.MolFromSmiles(wd['noncovalent']) + atomnames = dict(zip(mol.GetSubstructMatch(nc), wd['noncovalent_atomnames'])) + fx = poised_pose_fx + extra_constraint += 'AtomPair SG 145A CX 1B HARMONIC 3.2 0.5\n' + extra_constraint += wd['constraint'] + # -------------------- + defaults = dict( + pdb_filename=os.path.join(self.get_mpro_path(), 'template.pdb'), + ligand_resn='LIG', + ligand_resi='1B', + covalent_resn='CYS', covalent_resi='145A', + extra_constraint='AtomPair SG 145A NE2 41A HARMONIC 3.5 0.2\n', + pose_fx=fx # from the above. + ) + super().__init__(**{**defaults, **options}) + @classmethod - def combine_codes(cls, hit_codes: List[str], warhead_harmonisation='first'): + def combine_codes(cls, hit_codes: List[str], **options): hits = [cls.get_mol(xnumber) for xnumber in hit_codes] - return cls.combine(hits=hits, warhead_harmonisation=warhead_harmonisation) - + return cls.combine(hits=hits, **options) @classmethod - def combine(cls, hits:List[Chem.Mol], warhead_harmonisation='first'): - mpro_folder = cls.get_mpro_path() - apo = os.path.join(mpro_folder, 'template.pdb') - atomnames = {} - fx = pose_fx - extra_constraint = 'AtomPair SG 145A NE2 41A HARMONIC 3.5 0.2\n' - return super().combine(hits=hits, - pdb_filename=apo, - ligand_resn='LIG', - ligand_resi='1B', - covalent_resn='CYS', covalent_resi='145A', - extra_constraint=extra_constraint, - pose_fx=fx, - atomnames=atomnames, - warhead_harmonisation=warhead_harmonisation) + def combine(cls, **options): + defaults = dict( + pdb_filename=os.path.join(cls.get_mpro_path(), 'template.pdb'), + ligand_resn='LIG', + ligand_resi='1B', + covalent_resn='CYS', covalent_resi='145A', + extra_constraint='AtomPair SG 145A NE2 41A HARMONIC 3.5 0.2\n', + pose_fx=pose_fx # from the module namespace. + ) + return super().combine(**{**defaults, **options}) # ======= postera csv file ops ===================================================================================== diff --git a/fragmenstein/victor/__init__.py b/fragmenstein/victor/__init__.py index 1b1d058..8c3df1c 100644 --- a/fragmenstein/victor/__init__.py +++ b/fragmenstein/victor/__init__.py @@ -1,4 +1,5 @@ from __future__ import annotations + ######################################################################################################################## __doc__ = \ @@ -116,16 +117,16 @@ def __init__(self, self.mol = None self.constraint = None self.monster = None - self.modifications = [] # used by automerger only + self.modifications = [] # used by automerger only self.unminimised_pdbblock = None self.igor = None self.minimised_pdbblock = None self.minimised_mol = None - self.reference_mol = None # filled only for validate + self.reference_mol = None # filled only for validate # buffers etc. self._warned = [] self.energy_score = {'ligand_ref2015': {'total_score': float('nan')}, - 'unbound_ref2015': {'total_score': float('nan')}} + 'unbound_ref2015': {'total_score': float('nan')}} self.mrmsd = mRSMD.mock() self.tick = time.time() self.tock = float('inf') @@ -133,7 +134,6 @@ def __init__(self, # analyse self._safely_do(execute=self._analyse, resolve=self._resolve, reject=self._reject) - # =================== Init monster methods ============================================================================ def _safely_do(self, @@ -204,8 +204,8 @@ def _analyse(self) -> None: # make params self.journal.debug(f'{self.long_name} - Starting parameterisation') self.params = Params.from_smiles(self.smiles, name=self.ligand_resn, generic=False, atomnames=self.atomnames) - #self.journal.warning(f'{self.long_name} - CHI HAS BEEN DISABLED') - #self.params.CHI.data = [] # Chi is fixed, but older version. should probably check version + # self.journal.warning(f'{self.long_name} - CHI HAS BEEN DISABLED') + # self.params.CHI.data = [] # Chi is fixed, but older version. should probably check version self.mol = self.params.mol self._log_warnings() # get constraint @@ -218,14 +218,14 @@ def _analyse(self) -> None: self.journal.debug(f'{self.long_name} - Starting fragmenstein') # monster_throw_on_discard controls if disconnected. Monster.throw_on_discard = self.monster_throw_on_discard - self.monster = Monster(mol=self.mol, - hits=self.hits, - attachment=attachment, - merging_mode=self.monster_merging_mode, - debug_draw=self.monster_debug_draw, - average_position=self.monster_average_position) + self.monster = Monster(hits=self.hits, + debug_draw=self.monster_debug_draw, + average_position=self.monster_average_position) + self.monster.place(mol=self.mol, + attachment=attachment, + merging_mode=self.monster_merging_mode) self.journal.debug(f'{self.long_name} - Tried {len(self.monster.scaffold_options)} combinations') - self.unminimised_pdbblock = self._place_monster() + self.unminimised_pdbblock = self._place_monster_in_structure() self.constraint.custom_constraint += self._make_coordinate_constraints() self._checkpoint_bravo() # save stuff @@ -320,40 +320,65 @@ def _make_coordinate_constraints(self): f'{pos.x} {pos.y} {pos.z} {fxn}\n') return ''.join(lines) - def _place_monster(self): - l_resi, l_chain = re.match('(\d+)(\D?)', str(self.ligand_resi)).groups() - if self.covalent_resi: - p_resi, p_chain = re.match('(\d+)(\D?)', str(self.covalent_resi)).groups() - else: - p_resi, p_chain = None, None - if not p_chain: - p_chain = 'A' - if not l_chain: - l_chain = 'B' + def _get_LINK_record(self): + if self.is_covalent: + # get correct chain names. + l_resi, l_chain = re.match('(\d+)(\D?)', str(self.ligand_resi)).groups() + if self.covalent_resi: + p_resi, p_chain = re.match('(\d+)(\D?)', str(self.covalent_resi)).groups() + else: + p_resi, p_chain = None, None + if not p_chain: + p_chain = 'A' + if not l_chain: + l_chain = 'B' + # get the cx atom name + cx = self.params.pad_name(self.params.CONNECT[0].atom_name) + # TODO the SG connection is hardcoded. + return f'LINK SG {self.covalent_resn} {p_chain} {p_resi: >3} ' + \ + f'{cx} {self.ligand_resn} {l_chain} {l_resi: >3} 1555 1555 1.8\n' + + def _correct_ligand_info(self, mol: Optional[Chem.Mol]=None) -> Chem.Mol: + """ + Corrects in place the given mol based on self.ligand_resi. + If none provided it assumed self.monster.positioned_mol + """ + if mol is None: + mol = self.monster.positioned_mol + l_resi, l_chain = re.match('(\d+)(\D?)', str(self.ligand_resi)).groups() #TODO improve ligand_resi + for atom in mol.GetAtoms(): + info = atom.GetPDBResidueInfo() + info.SetResidueNumber(int(l_resi)) + info.SetChainId(l_chain) + info.SetIsHeteroAtom(True) + info.SetOccupancy(1.) + info.SetResidueName(self.ligand_resn) + return mol + + + def _place_monster_in_structure(self): # TODO make a new method that does not use Pymol + """ + Places the molecule in the structure using pymol. + :return: + """ + import pymol2 + self._correct_ligand_info() mol = AllChem.DeleteSubstructs(self.monster.positioned_mol, Chem.MolFromSmiles('*')) if self.monster_mmff_minisation: self.journal.debug(f'{self.long_name} - pre-minimising monster (MMFF)') self.monster.mmff_minimise(mol) - self.journal.debug(f'{self.long_name} - placing monster') + self.journal.debug(f'{self.long_name} - placing monster in structure') with pymol2.PyMOL() as pymol: pymol.cmd.read_pdbstr(self.apo_pdbblock, 'apo') - # distort positions pos_mol = Chem.MolToPDBBlock(mol) pymol.cmd.read_pdbstr(pos_mol, 'scaffold') - pymol.cmd.alter('scaffold', f'resi="{l_resi}"') - pymol.cmd.alter('scaffold', f'chain="{l_chain}"') pymol.cmd.remove('name R') # no dummy atoms! for c in self._connected_names: pymol.cmd.remove(f'name {c}') # no conns pymol.cmd.remove('resn UNL') # no unmatched stuff. pdbblock = pymol.cmd.get_pdbstr('*') pymol.cmd.delete('*') - if self.is_covalent: - cx = self.params.pad_name(self.params.CONNECT[0].atom_name) - return f'LINK SG {self.covalent_resn} {p_chain} {p_resi: >3} '+\ - f'{cx} {self.ligand_resn} {l_chain} {l_resi: >3} 1555 1555 1.8\n' + pdbblock - else: - return pdbblock + return self._get_LINK_record() + pdbblock def _fix_minimised(self) -> Chem.Mol: """ @@ -380,7 +405,6 @@ def quick_reanimate(self) -> float: ddG = dG_bound - dG_unbound return ddG - def reanimate(self) -> float: """ Calls Igor recursively until the ddG is negative or zero. @@ -390,7 +414,7 @@ def reanimate(self) -> float: """ ddG = 999 self.igor.coordinate_constraint = 0. - #self.igor.fa_intra_rep = 0.02 # 4x + # self.igor.fa_intra_rep = 0.02 # 4x # quick unconstrained minimisation to wiggle it out of nasty local minima self.igor.minimise(cycles=15, default_coord_constraint=False) self.igor.coordinate_constraint = 2 @@ -445,7 +469,7 @@ def _get_war_def(self): return {'name': 'unknown', 'covalent': 'C~C*', 'covalent_atomnames': ['CY', 'CX', 'CONN1'], - 'noncovalent': 'C~[C+]', # clearly not + 'noncovalent': 'C~[C+]', # clearly not 'noncovalent_atomnames': ['CY', 'CX'] } else: @@ -565,7 +589,7 @@ def _save_prerequisites(self): self.journal.debug(f'{self.long_name} - saving constraint') constraint_file = os.path.join(self.work_path, self.long_name, self.long_name + '.con') self.constraint.dump(constraint_file) - else: # basically impossible. + else: # basically impossible. constraint_file = '' return params_file, holo_file, constraint_file @@ -598,7 +622,7 @@ def _checkpoint_alpha(self): def _checkpoint_bravo(self): self._log_warnings() self.journal.debug(f'{self.long_name} - saving mols from monster') - if self.monster.scaffold is not None: + if self.monster.scaffold is not None: scaffold_file = os.path.join(self.work_path, self.long_name, self.long_name + '.scaffold.mol') Chem.MolToMolFile(self.monster.scaffold, scaffold_file, kekulize=False) if self.monster.scaffold.HasProp('parts'): @@ -622,12 +646,12 @@ def _checkpoint_bravo(self): frag_file = os.path.join(self.work_path, self.long_name, self.long_name + '.monster.json') data = {'smiles': self.smiles, - 'origin': self.monster.origin_from_mol(self.monster.positioned_mol), - 'stdev': self.monster.stdev_from_mol(self.monster.positioned_mol)} + 'origin': self.monster.origin_from_mol(self.monster.positioned_mol), + 'stdev': self.monster.stdev_from_mol(self.monster.positioned_mol)} if disregard: data['disregard'] = disregard with open(frag_file, 'w') as w: - json.dump(data, w) + json.dump(data, w) self._log_warnings() # unminimised_pdbblock will be saved by igor (round trip via pose) @@ -664,12 +688,14 @@ def constrained_atoms(self) -> int: def unconstrained_heavy_atoms(self) -> int: try: origins = self.monster.origin_from_mol(self.monster.positioned_mol) - unconn = sum([o == [] and atom.GetSymbol() != 'H' for o, atom in zip(origins, self.monster.positioned_mol.GetAtoms())]) + unconn = sum([o == [] and atom.GetSymbol() != 'H' for o, atom in + zip(origins, self.monster.positioned_mol.GetAtoms())]) except Exception as err: self.journal.warning(f'{self.long_name} - {err.__class__.__name__}: {err}') unconn = float('nan') return unconn + ######### Make params use the same log. Params.log = Victor.journal diff --git a/fragmenstein/victor/_victor_automerge_mixin.py b/fragmenstein/victor/_victor_automerge_mixin.py index eddc90c..972dfc4 100644 --- a/fragmenstein/victor/_victor_automerge_mixin.py +++ b/fragmenstein/victor/_victor_automerge_mixin.py @@ -110,17 +110,16 @@ def combine(cls, def _combine_main(self): attachment = self._get_attachment_from_pdbblock() if self.is_covalent else None - self.monster = Monster(mol=Chem.MolFromSmiles('*') if self.is_covalent else Chem.Mol(), - hits=[], - attachment=attachment, - merging_mode='off') + self.monster = Monster(hits=self.hits, + debug_draw=self.monster_debug_draw, + average_position=self.monster_average_position + ) + self.monster.merge(keep_all=self.monster_throw_on_discard, + collapse_rings=True, + joining_cutoff=self.monster_joining_cutoff # Å + ) # collapse hits # monster_throw_on_discard controls if disconnected. - self.monster.throw_on_discard = self.monster_throw_on_discard - self.monster.joining_cutoff = self.monster_joining_cutoff # Å - # merge! - col_hits = self.monster.collapse_mols(self.hits) - self.modifications.extend(col_hits) self.monster.scaffold = self.monster.merge_hits(col_hits) self.modifications.append(Chem.Mol(self.monster.scaffold)) # backup for debug self._log_warnings() @@ -179,7 +178,7 @@ def _combine_main(self): self._log_warnings() self.post_params_step() self.monster_merging_mode = 'full' - self.unminimised_pdbblock = self._place_monster() + self.unminimised_pdbblock = self._place_monster_in_structure() params_file, holo_file, constraint_file = self._save_prerequisites() self.unbound_pose = self.params.test() self._checkpoint_alpha() diff --git a/fragmenstein/victor/junk.py b/fragmenstein/victor/junk.py index 37ad50a..8b2647f 100644 --- a/fragmenstein/victor/junk.py +++ b/fragmenstein/victor/junk.py @@ -115,7 +115,7 @@ def _vanalyse(self): merging_mode=self.monster_merging_mode, debug_draw=self.monster_debug_draw, average_position=self.monster_average_position) - self.unminimised_pdbblock = self._place_monster() + self.unminimised_pdbblock = self._place_monster_in_structure() if self.monster_mmff_minisation: self.journal.debug(f'{self.long_name} - pre-minimising monster (MMFF)') self.monster.mmff_minimise(self.monster.positioned_mol) From 735866cfb75ab155cac409e41459de0615d3ac4e Mon Sep 17 00:00:00 2001 From: matteoferla Date: Wed, 3 Feb 2021 19:21:44 +0000 Subject: [PATCH 14/32] :beetle: should have been deleted --- .../victor/_victor_automerge_mixin.py | 34 +------------------ 1 file changed, 1 insertion(+), 33 deletions(-) diff --git a/fragmenstein/victor/_victor_automerge_mixin.py b/fragmenstein/victor/_victor_automerge_mixin.py index 972dfc4..8c21959 100644 --- a/fragmenstein/victor/_victor_automerge_mixin.py +++ b/fragmenstein/victor/_victor_automerge_mixin.py @@ -114,43 +114,11 @@ def _combine_main(self): debug_draw=self.monster_debug_draw, average_position=self.monster_average_position ) + self.monster.modifications = self.modifications self.monster.merge(keep_all=self.monster_throw_on_discard, collapse_rings=True, joining_cutoff=self.monster_joining_cutoff # Å ) - # collapse hits - # monster_throw_on_discard controls if disconnected. - self.monster.scaffold = self.monster.merge_hits(col_hits) - self.modifications.append(Chem.Mol(self.monster.scaffold)) # backup for debug - self._log_warnings() - ## Discard can happen for other reasons than disconnect - if self.monster_throw_on_discard and len(self.monster.unmatched): - raise ConnectionError(f'{self.long_name} - Could not combine with {self.monster.unmatched} '+\ - f'(>{self.monster.joining_cutoff}') - # expand and fix - self._log_warnings() - self.journal.debug(f'{self.long_name} - Merged') - self.monster.positioned_mol = self.monster.expand_ring(self.monster.scaffold) - # bonded_as_original=False no longer needed. - self.modifications.append(Chem.Mol(self.monster.positioned_mol)) # backup for debug - self._log_warnings() - self.journal.debug(f'{self.long_name} - Expanded') - recto = Rectifier(self.monster.positioned_mol) - try: - recto.fix() - except ConnectionError: - self.journal.critical(f'This really odd cornercase: Rectifier broke the mol.') - mol = self.monster._emergency_joining(recto.mol) - recto = Rectifier(self.monster.positioned_mol) - recto.fix() - self.monster.positioned_mol = recto.mol - self.modifications.extend(recto.modifications) # backup for debug - self._log_warnings() - # the origins are obscured because of the collapsing and rectification... - self.monster.guess_origins(self.monster.positioned_mol, self.hits) - self.monster.positioned_mol.SetProp('_Name', self.long_name) - self.mol = self.monster.positioned_mol - self.journal.debug(f'{self.long_name} - Rectified') self.smiles = Chem.MolToSmiles(self.mol) if self.monster_debug_draw: picture = Chem.CombineMols(Chem.CombineMols(self.hits[0], self.hits[1]), self.monster.positioned_mol) From 105ffe315d11d1bb29fa38d3154ebcca8f17c243 Mon Sep 17 00:00:00 2001 From: matteoferla Date: Thu, 4 Feb 2021 09:45:43 +0000 Subject: [PATCH 15/32] :beetle: bugs from split... fixed --- fragmenstein/victor/__init__.py | 2 ++ test.py | 43 +++++++++++---------------------- 2 files changed, 16 insertions(+), 29 deletions(-) diff --git a/fragmenstein/victor/__init__.py b/fragmenstein/victor/__init__.py index 8c3df1c..71b1c2f 100644 --- a/fragmenstein/victor/__init__.py +++ b/fragmenstein/victor/__init__.py @@ -337,6 +337,8 @@ def _get_LINK_record(self): # TODO the SG connection is hardcoded. return f'LINK SG {self.covalent_resn} {p_chain} {p_resi: >3} ' + \ f'{cx} {self.ligand_resn} {l_chain} {l_resi: >3} 1555 1555 1.8\n' + else: + return '' def _correct_ligand_info(self, mol: Optional[Chem.Mol]=None) -> Chem.Mol: """ diff --git a/test.py b/test.py index 9951166..1be17ba 100644 --- a/test.py +++ b/test.py @@ -50,7 +50,7 @@ def test_nasty(self): victor = MProVictor.from_hit_codes(smiles='*CCC(=O)N1CC(CCN(C(=O)Nc2c(C)ncc(C)c2CCN2CCOCC2)c2cc(C)ccn2)C1', hit_codes=['x0434', 'x0540'], long_name='AGN-NEW-5f0-1_ACR1') - self.assertEqual(victor.error, '', victor.error) + self.assertEqual(str(victor.error), '', str(victor.error)) self.assertIsNotNone(victor.minimised_mol, 'Failed minimisation') self.assertEqual(len(victor.monster.unmatched), 0, f'Both were correct but {victor.monster.unmatched} was discarded') @@ -177,11 +177,12 @@ def test_orthomethyltoluene(self): toluene.SetProp('_Name', 'toluene') rototoluene = Chem.MolFromMolFile('test_mols/rototoluene.mol') rototoluene.SetProp('_Name', 'rototoluene') - v = Victor.combine(hits=[toluene, rototoluene], + victor = Victor.combine(hits=[toluene, rototoluene], pdb_filename=template, covalent_resi='3A', # a random residue is still required for the constaint ref atom. covalent_resn='VAL') - gotten = Chem.MolToSmiles(Chem.RemoveHs(v.minimised_mol)) + self.assertEqual(victor.error, '', victor.error) + gotten = Chem.MolToSmiles(Chem.RemoveHs(victor.minimised_mol)) self.assertEqual(gotten, after, f'{name} failed {gotten} (expected {after})') def test_peridimethylnaphthalene(self): @@ -192,11 +193,12 @@ def test_peridimethylnaphthalene(self): toluene.SetProp('_Name', 'toluene') transtolueneF = Chem.MolFromMolFile('test_mols/transtoluene.mol') transtolueneF.SetProp('_Name', 'transtoluene-fuse') - v = Victor.combine(hits=[toluene, transtolueneF], + victor = Victor.combine(hits=[toluene, transtolueneF], pdb_filename=template, covalent_resi='3A', # a random residue is still required for the constaint ref atom. covalent_resn='VAL') - gotten = Chem.MolToSmiles(Chem.RemoveHs(v.minimised_mol)) + self.assertEqual(victor.error, '', victor.error) + gotten = Chem.MolToSmiles(Chem.RemoveHs(victor.minimised_mol)) self.assertEqual(gotten, after, f'{name} failed {gotten} (expected {after})') def test_spirodituluene(self): @@ -208,11 +210,12 @@ def test_spirodituluene(self): transtolueneS = Chem.MolFromMolFile('test_mols/transtoluene2.mol') transtolueneS.SetProp('_Name', 'transtoluene-spiro') # cmd.rotate('z', -90, 'rototoluene', camera=0) - v = Victor.combine(hits=[toluene, transtolueneS], + victor = Victor.combine(hits=[toluene, transtolueneS], pdb_filename=template, covalent_resi='3A', # a random residue is still required for the constaint ref atom. covalent_resn='VAL') - gotten = Chem.MolToSmiles(Chem.RemoveHs(v.minimised_mol)) + self.assertEqual(victor.error, '', victor.error) + gotten = Chem.MolToSmiles(Chem.RemoveHs(victor.minimised_mol)) self.assertIn(gotten, after, f'{name} failed {gotten} (expected {after})') @@ -300,18 +303,9 @@ def test_supplementary1_to_recto_fail_A(self): Chem.SanitizeMol(chlorobutane) chlorobutane.SetProp('_Name', '2-chlorobutane') # merge - monster = Monster(mol=Chem.Mol(), - hits=[], - attachment=None, - merging_mode='off') - monster.throw_on_discard = False - # # merge! - col_hits = monster.collapse_mols([toluene, chlorobutane]) - monster.scaffold = monster.merge_hits(col_hits) - monster.positioned_mol = monster.expand_ring(monster.scaffold) - recto = Rectifier(monster.positioned_mol) + monster = Monster(hits=[toluene, chlorobutane]).merge(keep_all=False) # ====== - self.assertEqual(Chem.MolToSmiles(recto.mol), Chem.MolToSmiles(chlorotoluene)) # CC(Cl)CCc1ccccc1 + self.assertEqual(Chem.MolToSmiles(monster.positioned_mol), Chem.MolToSmiles(chlorotoluene)) # CC(Cl)CCc1ccccc1 def test_supplementary2_to_recto_fail_A(self): """ @@ -338,17 +332,8 @@ def test_supplementary2_to_recto_fail_A(self): Chem.SanitizeMol(chloropentane) chloropentane.SetProp('_Name', '2-chloropentane') # - monster = Monster(mol=Chem.Mol(), - hits=[], - attachment=None, - merging_mode='off') - monster.throw_on_discard = False - # # merge! - col_hits = monster.collapse_mols([methyltoluene, chloropentane]) - monster.scaffold = monster.merge_hits(col_hits) - monster.positioned_mol = monster.expand_ring(monster.scaffold) - recto = Rectifier(monster.positioned_mol) + monster = Monster(hits=[methyltoluene, chloropentane]).merge(keep_all=False) # ====== - self.assertEqual(Chem.MolToSmiles(recto.mol), Chem.MolToSmiles(methylchlorotoluene)) + self.assertEqual(Chem.MolToSmiles(monster.positioned_mol), Chem.MolToSmiles(methylchlorotoluene)) # Todo: add a class to test missing modules. From 51091ccda092ee6784194a4d5a6dc978f14cff95 Mon Sep 17 00:00:00 2001 From: matteoferla Date: Thu, 4 Feb 2021 19:51:04 +0000 Subject: [PATCH 16/32] :tada: the phenylene formation works! --- documentation/_snippets.md | 12 +- fragmenstein/monster/_base.py | 24 ++- fragmenstein/monster/_collapse_ring.py | 205 +++++++++++++++++-------- test.py | 22 +++ 4 files changed, 194 insertions(+), 69 deletions(-) diff --git a/documentation/_snippets.md b/documentation/_snippets.md index 688a511..bebec07 100644 --- a/documentation/_snippets.md +++ b/documentation/_snippets.md @@ -9,4 +9,14 @@ This is because `try`/`except` can accept multiple error classes as a tuple. # 2 -`ConnectionError` is meant for comms connection errors, but here it is raised as bad bonding. \ No newline at end of file +`ConnectionError` is meant for comms connection errors, but here it is raised as bad bonding. + +# 3 + +Show the steps + + from IPython.display import display + + monster = Monster([fore, aft]).merge() + for m in monster.modifications: + display(m) \ No newline at end of file diff --git a/fragmenstein/monster/_base.py b/fragmenstein/monster/_base.py index 32c6d38..080ae22 100644 --- a/fragmenstein/monster/_base.py +++ b/fragmenstein/monster/_base.py @@ -101,7 +101,7 @@ def _find_all_closest(self, mol_A: Chem.Mol, mol_B: Chem.Mol) -> Tuple[Chem.RWMo combo = Chem.RWMol(Chem.CombineMols(mol_A, mol_B)) # ========= distance matrix pre-tweaks. distance_matrix = self._get_distance_matrix(combo, mol_A, mol_B) - penalties = self._get_penalties(combo, distance_matrix.shape) + penalties = self._get_joining_penalties(combo, distance_matrix.shape) # ========= get closest pendist_matrix = penalties + distance_matrix pendistance = np.nanmin(pendist_matrix) @@ -157,13 +157,26 @@ def _get_distance_matrix(self, combo: Chem.Mol, A: Union[Chem.Mol, np.ndarray], distance_matrix = Chem.Get3DDistanceMatrix(combo) length = combo.GetNumAtoms() # nan fill the self values - self._nan_submatrix(distance_matrix, A_idxs) - self._nan_submatrix(distance_matrix, B_idxs) + self._nan_fill_submatrix(distance_matrix, A_idxs) + self._nan_fill_submatrix(distance_matrix, B_idxs) return distance_matrix - def _get_penalties(self, combo: Chem.Mol, shape: Tuple[int, int]) -> np.ndarray: + def _nan_fill_others(self, mol: Chem.Mol, distance_matrix: np.array, good_indices: List[int]): + """ + Nan fill the inidices that are not the good_indices. + :param mol: + :param distance_matrix: + :param good_indices: + :return: + """ + others = np.array(list(set(range(mol.GetNumAtoms())).difference(good_indices))) + distance_matrix[others, :] = np.nan + distance_matrix[:, others] = np.nan + + def _get_joining_penalties(self, combo: Chem.Mol, shape: Tuple[int, int]) -> np.ndarray: """ Called by ``_find_closest``. + THis is different from _get_merging_penalties :param combo: :param shape: @@ -177,10 +190,11 @@ def _get_penalties(self, combo: Chem.Mol, shape: Tuple[int, int]) -> np.ndarray: penalties[:, weigh_bool] += weight return penalties - def _nan_submatrix(self, matrix, indices): + def _nan_fill_submatrix(self, matrix, indices): """ Given a square matrix, blank the self-submatrix of the group of indices There is probably a better way to do this. + changed from _nan_submatrix as to nan is not a verb. :param matrix: :param indices: diff --git a/fragmenstein/monster/_collapse_ring.py b/fragmenstein/monster/_collapse_ring.py index e743908..2b172de 100644 --- a/fragmenstein/monster/_collapse_ring.py +++ b/fragmenstein/monster/_collapse_ring.py @@ -57,7 +57,6 @@ def store_positions(self, mol: Chem.Mol) -> Chem.Mol: atom.SetDoubleProp('_z', pos.z) return mol - # =========== Collapse & Expand ==================================================================================== def collapse_ring(self, mol: Chem.Mol) -> Chem.Mol: @@ -155,10 +154,10 @@ def expand_ring(self, mol: Chem.Mol) -> Chem.Mol: self._place_ring_atoms(mol, rings) # bonded_as_original. Rectifier will fix. self._restore_original_bonding(mol, rings) - self._add_novel_bonding(mol, rings) # formerly `_ring_overlap_scenario` and `_infer_bonding_by_proximity`. + self._add_novel_bonding(mol, rings) # formerly `_ring_overlap_scenario` and `_infer_bonding_by_proximity`. self._delete_collapsed(mol) self._detriangulate(mol) - mol = self._emergency_joining(mol) # does not modify in place! + mol = self._emergency_joining(mol) # does not modify in place! if mol is None: raise ValueError('(Impossible) Failed at some point...') elif isinstance(mol, Chem.RWMol): @@ -189,7 +188,7 @@ def offset(self, mol: Chem.Mol): atom.SetIntProp('_ori_i', n) old2new[o] = n else: - pass # ringcores have -1 ori_i + pass # ringcores have -1 ori_i # sort the ringcore for atom in self._get_collapsed_atoms(mol): old = json.loads(atom.GetProp('_ori_is')) @@ -198,7 +197,7 @@ def offset(self, mol: Chem.Mol): old2new = {**old2new, **dict(zip(old, new))} # this has to be done afterwards in case of a bonded mol for atom in self._get_collapsed_atoms(mol): - old_neighss = json.loads(atom.GetProp('_neighbors')) #if i in old2new else i + old_neighss = json.loads(atom.GetProp('_neighbors')) # if i in old2new else i new_neighss = [[old2new[i] for i in old_neighs if i in old2new] for old_neighs in old_neighss] atom.SetProp('_neighbors', json.dumps(new_neighss)) @@ -285,14 +284,15 @@ def _place_ring_atoms(self, mol, rings: List[Dict[str, Union[Chem.Atom, List[Any """ conf = mol.GetConformer() for ring in rings: # atoms in ring addition - indices = [] # will store current indices + ringcore = ring['atom'] + indices = [] # will store current indices for i in range(len(ring['elements'])): # atom addition collapsed_atom_data = self._get_expansion_for_atom(ring, i) # atom will be added if it is not already present! if self._is_present(mol, collapsed_atom_data['ori_i']): natom = self._get_new_index(mol, collapsed_atom_data['ori_i'], search_collapsed=False) self.journal.debug(f"{natom} (formerly {collapsed_atom_data['ori_i']} existed already." + - "Fused ring or similar.") + "Fused ring or similar.") else: n = mol.AddAtom(Chem.Atom(collapsed_atom_data['element'])) natom = mol.GetAtomWithIdx(n) @@ -304,9 +304,11 @@ def _place_ring_atoms(self, mol, rings: List[Dict[str, Union[Chem.Atom, List[Any natom.SetDoubleProp('_y', collapsed_atom_data['y']) natom.SetDoubleProp('_z', collapsed_atom_data['z']) natom.SetProp('_ori_name', collapsed_atom_data['ori_name']) + natom.SetIntProp('_ring_i', ringcore.GetIdx()) indices.append(n) - ringcore = ring['atom'] + ringcore.SetIntProp('_ring_i', ringcore.GetIdx()) # it really really should have not changed. ringcore.SetProp('_current_is', json.dumps(indices)) + ring['current_is'] = indices def _restore_original_bonding(self, mol: Chem.RWMol, rings: List[Dict[str, List[Any]]]) -> None: self.journal.debug('Restoring original bonding if any.') @@ -332,13 +334,13 @@ def _restore_original_bonding(self, mol: Chem.RWMol, rings: List[Dict[str, List[ assert distance < 4, f'Bond length too long ({distance}. {info}' elif present_bond.GetBondType().name != bond: self.journal.warning(f'bond between {new_i} {new_neigh} exists already ' + - f'(has {present_bond.GetBondType().name} expected {bt})') + f'(has {present_bond.GetBondType().name} expected {bt})') present_bond.SetBondType(bt) present_bond.SetBoolProp('_IsRingBond', True) BondProvenance.set_bond(present_bond, 'original') else: self.journal.debug(f'bond between {new_i} {new_neigh} exists already ' + - f'(has {present_bond.GetBondType().name} expected {bt})') + f'(has {present_bond.GetBondType().name} expected {bt})') pass # try: # @@ -381,9 +383,10 @@ def _add_novel_bonding(self, mol: Chem.RWMol, rings: List[Dict[str, List[Any]]]) :type rings: List[Dict[str, List[Any]]] :return: """ - # ===== Deal with Ring on ring bonding self.journal.debug('Adding novel bonding (if any)...') - novel_ringcore_pairs = self._get_novel_ringcore_pairs(rings) + # ===== Deal with Ring on ring bonding + novel_ringcore_pairs = self._get_novel_ringcore_pairs(mol, rings, cutoff = 2.8 + 1.5) + # these is a list of Chem.Atom pairs. for ringcore_A, ringcore_B in novel_ringcore_pairs: self.journal.debug(f'determining novel bond between {ringcore_A} and {ringcore_B}') # _determine_mergers_novel_ringcore_pair finds mergers @@ -447,26 +450,94 @@ def _get_collapsed_atoms(self, mol: Chem.Mol) -> List[Chem.Atom]: # ==== Novel Ring to Ring bonding ================================================================================== - def _get_novel_ringcore_pairs(self, rings) -> List[Tuple[Chem.Atom, Chem.Atom]]: - pairs = [] + def _get_novel_ringcore_pairs(self, + mol: Chem.Mol, + rings: List[Dict[str, List[Any]]], cutoff)\ + -> List[Tuple[Chem.Atom, Chem.Atom]]: + """ + Get the ring atoms that are bonded or closer than a cutoff + + + + :param mol: + :param rings: output of `_get_expansion_data`. See that for details. + :type rings: List[Dict[str, List[Any]]] + :param cutoff: + :return: + """ + # ---------------------------------------------------------- + # scenario where they are closer than the cutoff + close_pairs = self._get_close_nonorigin_ringcores(mol, rings, cutoff) # 2.7889 ring diameter + 1.45 C-C bond + # ---------------------------------------------------------- + # scenario where they are bonded... + bonded_pairs = [] for ring in rings: # ring: Dict[str, List[Any]] - ringcore = ring['atom'] # Chem.Atom + ringcore = ring['atom'] # Chem.Atom the ring core marker, not a real atom. for neigh in ringcore.GetNeighbors(): # find those ringcore atoms that are connected. via these conditions: - has_ringcore_neighbor = neigh.HasProp('_ori_name') and neigh.GetIntProp('_ori_i') == -1 + has_ringcore_neighbor = neigh.HasProp('_ori_name') and neigh.GetIntProp('_ori_i') == -1 # -1 is ring. is_new_pair = ringcore.GetIdx() < neigh.GetIdx() # to avoid doing it twice each direction is_novel_connection = neigh.HasProp('_ori_name') and ring['ori_name'] != neigh.GetProp('_ori_name') + # checking: if has_ringcore_neighbor and is_new_pair and is_novel_connection: # This ringcore atom shares a novel border with another ringcore atom - pairs.append((ringcore, neigh)) + bonded_pairs.append((ringcore, neigh)) # i.e. List[Tuple[Chem.Atom, Chem.Atom]} + # ------------ merge lists ----------- + # todo this extra step should not exist + # complicate because mol.GetAtomWithIdx(2) == mol.GetAtomWithIdx(2) is False + seen = [] + pairs = [] + for atom_a, atom_b in close_pairs+bonded_pairs: + ai = atom_a.GetIdx() + bi = atom_b.GetIdx() + low_i, high_i = sorted([ai, bi]) + pairing = f'{low_i}-{high_i}' + if pairing in seen: + pass + else: + seen.append(pairing) + pairs.append((atom_a, atom_b)) return pairs + def _get_ring_atom_indices_per_origin(self, rings: List[Dict[str, List[Any]]]) -> Dict[str, List[int]]: + atomdex = defaultdict(set) + for ring in rings: + origin_name = ring['ori_name'] # ring['ori_name'] is same as ringcore.GetProp('_ori_name') + atomdex[origin_name].update(ring['current_is']) # ring['current_is'] = json ringcore.GetProp('_current_is') + return atomdex + + def _get_close_nonorigin_ringcores(self, mol: Chem.Mol, rings: List[Dict[str, List[Any]]], cutoff: int): + """ + Unfortunately, internally this compares ring atoms, not ring cores. Yet the return are ring cores. + """ + cnrai = self._get_close_nonorigin_ring_atoms_indices(mol, rings, cutoff) + # these are indices of ring atoms, not ring cores + get_atom = lambda i: mol.GetAtomWithIdx(int(i)) + get_ringcore = lambda atom: get_atom(atom.GetIntProp('_ring_i')) + idx2ringcore = lambda i: get_ringcore(get_atom(i)) + return [(idx2ringcore(ai), idx2ringcore(bi)) for ai, bi in cnrai] + + def _get_close_nonorigin_ring_atoms_indices(self, + mol: Chem.Mol, + rings: List[Dict[str, List[Any]]], + cutoff: int): + atomdex = self._get_ring_atom_indices_per_origin(rings) + # not calling get_distance matrxi because tehre may be more than 2 origins. + distance_matrix = Chem.Get3DDistanceMatrix(mol) + for origin_name, indices in atomdex.items(): + self._nan_fill_submatrix(distance_matrix, list(indices)) + self._nan_fill_others(mol, distance_matrix, [idx for idcs in atomdex.values() for idx in idcs]) + # get the pair of atom indices that are less thna cutoff. + # where returns a tuple of np.arrays of dtype=np.int64 + return list(zip(*[w.astype(int) for w in np.where(distance_matrix < cutoff)])) + def _determine_mergers_novel_ringcore_pair(self, mol: Chem.RWMol, ringcore_A: Chem.Atom, ringcore_B: Chem.Atom) -> List[Tuple[int, int]]: """ + Preps to resolve ringcore pairs. Formerly part of ``_ring_overlap_scenario``. Preps without deleting. ``_delete_marked(mol)`` does that. bonded, spiro, fused @@ -476,22 +547,22 @@ def _determine_mergers_novel_ringcore_pair(self, :param ringcore_B: :return: list of atoms to be merged """ - absorption_distance = 1. # Å + absorption_distance = 1. # Å + print('A', ringcore_A, ringcore_A.GetIdx(), ringcore_A.GetIntProp('_ori_i')) + print('B', ringcore_B, ringcore_B.GetIdx(), ringcore_B.GetIntProp('_ori_i')) indices_A = json.loads(ringcore_A.GetProp('_current_is')) indices_B = json.loads(ringcore_B.GetProp('_current_is')) - distance_matrix = self._get_distance_matrix(mol, indices_A, indices_B) # currently in `_join_neighboring`. + distance_matrix = self._get_distance_matrix(mol, indices_A, indices_B) # currently in `_join_neighboring`. # distance matrix is for the whole thing # TODO merge into _get_distance_matrix - # getting the other atom indices: - others = np.array(list(set(range(mol.GetNumAtoms())).difference(indices_A + indices_B))) - distance_matrix[others, :] = np.nan - distance_matrix[:, others] = np.nan + # blanking the other atom indices: + self._nan_fill_others(mol, distance_matrix, indices_A + indices_B) # get closest pair. distance = np.nanmin(distance_matrix) if np.isnan(distance): self.journal.critical('This is impossible. Two neighbouring rings cannot be connected.') return [] - elif distance > absorption_distance: # bonded + elif distance > absorption_distance: # bonded p = np.where(distance_matrix == distance) a = int(p[0][0]) b = int(p[1][0]) @@ -505,8 +576,8 @@ def _determine_mergers_novel_ringcore_pair(self, self.journal.info('A novel bond-connected ring pair was found') self._mark_for_deletion(mol, b) self._copy_bonding(mol, a, b, force=True) - return [] #bonded - else: + return [] # bonded + else: # Spiro or fused. p = np.where(distance_matrix == distance) a = int(p[0][0]) b = int(p[1][0]) @@ -522,10 +593,10 @@ def _determine_mergers_novel_ringcore_pair(self, self._mark_for_deletion(mol, d) self._copy_bonding(mol, c, d, force=True) self.journal.info('A novel fused ring pair was found') - return [(a, b), (c, d)] #fused + return [(a, b), (c, d)] # fused else: self.journal.info('A novel spiro ring pair was found') - return [(a,b)] # spiro + return [(a, b)] # spiro # ==== Novel Ring to Ring bonding ================================================================================== @@ -549,7 +620,6 @@ def _determine_mergers_novel_ringcore_pair(self, # self.join_rings(mol) # self._triangle_warn(mol) - def _get_novel_other_pairs(self, rings) -> List[Tuple[Chem.Atom, Chem.Atom]]: ## similar to novel ringcore..but opposite pairs = [] @@ -565,34 +635,28 @@ def _get_novel_other_pairs(self, rings) -> List[Tuple[Chem.Atom, Chem.Atom]]: pairs.append((ringcore, neigh)) return pairs - def _determine_mergers_novel_other_pair(self, - mol: Chem.RWMol, - ringcore: Chem.Atom, - other: Chem.Atom) -> List[Tuple[int, int]]: - absorption_distance = 1. # Å - indices_ring = json.loads(ringcore.GetProp('_current_is')) - indices_other = [other.GetIdx()] - distance_matrix = self._get_distance_matrix(mol, indices_ring, indices_other) # currently in `_join_neighboring`. - # distance matrix is for the whole thing - # TODO merge into _get_distance_matrix - # getting the other atom indices: - others = np.array(list(set(range(mol.GetNumAtoms())).difference(indices_ring + indices_other))) - distance_matrix[others, :] = np.nan - distance_matrix[:, others] = np.nan - # penalties - penalties = np.zeros(distance_matrix.shape) + + def _get_merging_penalties(self, mol, shape: Tuple[int, int], indices_ring): + """ + confusingly this is a different set of penalties to `_get_joining_penalties` which is for joining + :param mol: + :param shape: + :param indices_ring: The indices inside the ring atom, aka. prop _current_is + :return: + """ + penalties = np.zeros(shape) for i in indices_ring: atom = mol.GetAtomWithIdx(i) neighs = [neigh for neigh in atom.GetNeighbors() if self._is_count_valid(neigh)] n_neighs = len(neighs) if atom.GetAtomicNum() > 8: # next row. # weird chemistry... likely wrong! - penalties[i,:] = 2. - penalties[:,i] = 2. + penalties[i, :] = 2. + penalties[:, i] = 2. elif n_neighs == 2: - pass # no penalty! + pass # no penalty! elif atom.GetIsAromatic(): - penalties[i, :] = 2 # this would result in a ring downgrade... + penalties[i, :] = 2 # this would result in a ring downgrade... penalties[:, i] = 2 elif n_neighs == 3: penalties[i, :] = 1. # 4 bonded carbon is not nice... @@ -600,6 +664,29 @@ def _determine_mergers_novel_other_pair(self, else: penalties[i, :] = np.nan # this will likely crash things. penalties[:, i] = np.nan + return penalties + + def _determine_mergers_novel_other_pair(self, + mol: Chem.RWMol, + ringcore: Chem.Atom, + other: Chem.Atom) -> List[Tuple[int, int]]: + """ + Like _determine_mergers_novel_ringcore_pair finds, bonds and marks for deletion. + It however finds atoms to absorb between a ring and non-ring atom. + + :param mol: + :param ringcore: + :param other: + :return: + """ + absorption_distance = 1. # Å + indices_ring = json.loads(ringcore.GetProp('_current_is')) + indices_other = [other.GetIdx()] + distance_matrix = self._get_distance_matrix(mol, indices_ring, + indices_other) # currently in `_join_neighboring`. + self._nan_fill_others(mol, distance_matrix, indices_ring + indices_other) + # merging penalties + penalties = self._get_merging_penalties(mol, distance_matrix.shape, indices_ring) # get closest pair. pendist_matrix = penalties + distance_matrix pendistance = np.nanmin(pendist_matrix) @@ -613,7 +700,7 @@ def _determine_mergers_novel_other_pair(self, distance = distance_matrix[a, b] penalty = penalties[a, b] if distance > 4: - raise ValueError(f'The bond between {a} and {b} too long {distance} '+\ + raise ValueError(f'The bond between {a} and {b} too long {distance} ' + \ f'from {indices_ring} and {indices_other}') elif distance > absorption_distance: # get bond type @@ -628,7 +715,7 @@ def _determine_mergers_novel_other_pair(self, # This is no longer required: # atom_a = mol.GetAtomWithIdx(a) # atom_b = mol.GetAtomWithIdx(b) - #self._add_bond_if_possible(mol, atom_a, atom_b) + # self._add_bond_if_possible(mol, atom_a, atom_b) self.journal.info(f'A novel bonding to ring was added {distance} {penalty}') else: # absorb the non-ring atom! @@ -659,7 +746,7 @@ def _emergency_joining(self, mol): for i, frag in enumerate(frags): frag.SetProp('_Name', f'name.{i}') # find which fragments are closest. - #TODO use the distance_matrix = self._get_distance_matrix(..) code + # TODO use the distance_matrix = self._get_distance_matrix(..) code closeness = np.ones([n, n]) closeness.fill(float('nan')) for a, b in itertools.combinations(list(range(n)), 2): @@ -678,7 +765,6 @@ def _emergency_joining(self, mol): n = len(frags) return Chem.RWMol(mol) - # # # distance = distance_matrix[anchor_A, anchor_B] @@ -716,7 +802,7 @@ def _detriangulate(self, mol: Chem.RWMol) -> None: atom_i = atom.GetIdx() for neigh in atom.GetNeighbors(): neigh_i = neigh.GetIdx() - if neigh_i < atom_i: # dont check twice... + if neigh_i < atom_i: # dont check twice... continue # de triangulate third_i = self._get_triangle(atom, neigh) @@ -734,7 +820,7 @@ def _detriangulate(self, mol: Chem.RWMol) -> None: if sq is not None: far_i, close_i = sq far = mol.GetAtomWithIdx(far_i) - close = mol.GetAtomWithIdx(close_i) # second neighbour of atom + close = mol.GetAtomWithIdx(close_i) # second neighbour of atom # bonding is: # atom - neigh - far - close - atom self.journal.debug(f'Square present {(atom_i, neigh_i, far_i, close_i)}.') @@ -781,16 +867,9 @@ def _detriangulate_inner(self, scores += np.sum(list(combinator(funscore)), axis=1) d = np.nanmax(scores) if np.isnan(d): - return None # impossible but okay. + return None # impossible but okay. doomed_i = int(np.where(scores == d)[0]) doomed_bond = bonds[doomed_i] a, b = doomed_bond.GetBeginAtomIdx(), doomed_bond.GetEndAtomIdx() self.journal.debug(f'Removing triangle/square forming bond between {a} and {b}') mol.RemoveBond(a, b) - - - - - - - diff --git a/test.py b/test.py index 1be17ba..d434091 100644 --- a/test.py +++ b/test.py @@ -218,6 +218,28 @@ def test_spirodituluene(self): gotten = Chem.MolToSmiles(Chem.RemoveHs(victor.minimised_mol)) self.assertIn(gotten, after, f'{name} failed {gotten} (expected {after})') + def test_phenylene(self): + # make carboxy and amide benzenes that overlap so that the end result is a phenylene where one ring is oxazine + before = 'c3c1cccc2\C(=O)O/C(-N)c(c12)cc3' + conjoined = Chem.MolFromSmiles(before) + AllChem.EmbedMolecule(conjoined) + bonds = [conjoined.GetBondBetweenAtoms(0, 1).GetIdx(), + conjoined.GetBondBetweenAtoms(12, 11).GetIdx(), + conjoined.GetBondBetweenAtoms(8, 9).GetIdx()] + fragged = Chem.FragmentOnBonds(conjoined, bonds, addDummies=False) + fore = Chem.GetMolFrags(fragged, asMols=True, sanitizeFrags=False)[1] + Chem.SanitizeMol(fore) + bonds = [conjoined.GetBondBetweenAtoms(2, 1).GetIdx(), + conjoined.GetBondBetweenAtoms(12, 5).GetIdx(), + conjoined.GetBondBetweenAtoms(8, 6).GetIdx()] + fragged = Chem.FragmentOnBonds(conjoined, bonds, addDummies=False) + aft = Chem.GetMolFrags(fragged, asMols=True, sanitizeFrags=False)[0] + Chem.SanitizeMol(aft) + # merge them + mol = Monster([fore, aft]).merge().positioned_mol + after = Chem.MolToSmiles(mol) + self.assertEqual(before, after) + # ---------------------------------------------------------------------------------------------------------------------- From 3a553e7610234796f43cd5b792543e007174c2a1 Mon Sep 17 00:00:00 2001 From: matteoferla Date: Thu, 4 Feb 2021 19:54:43 +0000 Subject: [PATCH 17/32] :beetle: smiles from wiki was not canonical --- test.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test.py b/test.py index d434091..449864d 100644 --- a/test.py +++ b/test.py @@ -220,8 +220,8 @@ def test_spirodituluene(self): def test_phenylene(self): # make carboxy and amide benzenes that overlap so that the end result is a phenylene where one ring is oxazine - before = 'c3c1cccc2\C(=O)O/C(-N)c(c12)cc3' - conjoined = Chem.MolFromSmiles(before) + conjoined = Chem.MolFromSmiles('c3c1cccc2\C(=O)O/C(-N)c(c12)cc3') + before = Chem.MolToSmiles(conjoined) # structure from wiki is not canonical AllChem.EmbedMolecule(conjoined) bonds = [conjoined.GetBondBetweenAtoms(0, 1).GetIdx(), conjoined.GetBondBetweenAtoms(12, 11).GetIdx(), From 56ed803719210ad5eaec48aa4a59a1bb99819691 Mon Sep 17 00:00:00 2001 From: matteoferla Date: Fri, 5 Feb 2021 11:15:35 +0000 Subject: [PATCH 18/32] :pencil: documenting changes --- documentation/changelog_0.5.md | 59 ++++++++++++++++++++++++++ fragmenstein/monster/__init__.py | 2 + fragmenstein/monster/_collapse_ring.py | 2 +- 3 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 documentation/changelog_0.5.md diff --git a/documentation/changelog_0.5.md b/documentation/changelog_0.5.md new file mode 100644 index 0000000..21baafb --- /dev/null +++ b/documentation/changelog_0.5.md @@ -0,0 +1,59 @@ +## Monster entrypoints + +Previously merging in `Monster` was overly complicated and an add-on, now it is cleaner as the initialisation of +the object does not do a placement. To do that one has to do: + + monster = Monster(hits) + monster.place(mol) + monster.positioned_mol + +or `place_smiles` for a SMILES. + +While to do a merger + + monster = Monster(hits) + monster.merge() + monster.positioned_mol + +Additionally, the attribute `modifications` was added/expanded, so that intermediate steps are stored +for potential inspection. + +`merge` still calls `merge_hits`. +If one wanted to merge two or more hits, independently of those in `.hits` attribute and without ring collapsing +and rectification etc. +`merge_hits` is still the one: + + monster = Monster([]) + monster.merge_hits([molA, molB]) + +The `place` method accepts the argument `merging_mode`, by default it is "permissive_none", +which calls `.no_merging(broad=True)`, +but "off" (nothing), +"full" (`.full_merging()`), +"partial" (`.partial_merging()`) +and "none" (`.no_merging()`) +are accepted. + +## Future +Victor however still has the merger as a side route. + +The names "merge" and "place" are ambiguous when it comes to the other methods, especially those of "place". +"position" is also used for the (distored) 3D final compound. + +## Overlapping rings + +There was a bug in the code for `Monster` that meant that if two rings from different origins that were not bonded +—i.e. without side atoms that were absorbed they were not assessed for merging. This has been corrected. + +Namely, what happens to rings is controlled in `expand_ring` method, which calls `_add_novel_bonding`, where "novel" +means that does not share the same "origin" (original molecule). +The latter method calls in turn `_get_novel_ringcore_pairs`, which now get ring marking atoms that are close or bonded. +Closeness is determined by ring atoms (not ring core markers) within 1.5 Å cutoff (viz. `_get_close_nonorigin_ringcores`) + +The test case was the merger of a phenylacetic acid and phenylacetamide which overlap in two ring carbons and a terminal oxygen, resulting +in a phenylene-like ring (where one ring is an oxazine). See tests. + +![phenylene](../images/phenylene.png) + + + \ No newline at end of file diff --git a/fragmenstein/monster/__init__.py b/fragmenstein/monster/__init__.py index 0fff1df..4e1fdbe 100644 --- a/fragmenstein/monster/__init__.py +++ b/fragmenstein/monster/__init__.py @@ -605,6 +605,8 @@ def place_from_map(self, mol: Chem.Mol = None, atom_map: Optional[Dict] = None) """ This method places the atoms with known mapping and places the 'uniques' (novel) via an aligned mol (the 'sextant') + This sextant business is a workaround for the fact that only minimised molecules can use the partial + embedding function of RDKit. :param mol: :param atom_map: something that get_mcs_mapping would return. diff --git a/fragmenstein/monster/_collapse_ring.py b/fragmenstein/monster/_collapse_ring.py index 2b172de..da7f42a 100644 --- a/fragmenstein/monster/_collapse_ring.py +++ b/fragmenstein/monster/_collapse_ring.py @@ -385,7 +385,7 @@ def _add_novel_bonding(self, mol: Chem.RWMol, rings: List[Dict[str, List[Any]]]) """ self.journal.debug('Adding novel bonding (if any)...') # ===== Deal with Ring on ring bonding - novel_ringcore_pairs = self._get_novel_ringcore_pairs(mol, rings, cutoff = 2.8 + 1.5) + novel_ringcore_pairs = self._get_novel_ringcore_pairs(mol, rings, cutoff = 1.5) # these is a list of Chem.Atom pairs. for ringcore_A, ringcore_B in novel_ringcore_pairs: self.journal.debug(f'determining novel bond between {ringcore_A} and {ringcore_B}') From 38eb90a34812f1e9b4931848bfe62be66ffb48bd Mon Sep 17 00:00:00 2001 From: matteoferla Date: Fri, 5 Feb 2021 15:19:00 +0000 Subject: [PATCH 19/32] :tada: Victor now places ("plonks") the monster mol w/o using pymol --- fragmenstein/victor/__init__.py | 73 +++++++- .../victor/_victor_automerge_mixin.py | 2 +- fragmenstein/victor/junk.py | 158 ------------------ fragmenstein/victor/minimalPDB.py | 98 +++++++++++ 4 files changed, 164 insertions(+), 167 deletions(-) delete mode 100644 fragmenstein/victor/junk.py create mode 100644 fragmenstein/victor/minimalPDB.py diff --git a/fragmenstein/victor/__init__.py b/fragmenstein/victor/__init__.py index 71b1c2f..305dfbe 100644 --- a/fragmenstein/victor/__init__.py +++ b/fragmenstein/victor/__init__.py @@ -39,6 +39,8 @@ from ..igor import Igor from ..m_rmsd import mRSMD +from .minimalPDB import MinimalPDBParser + class Victor(_VictorUtilsMixin, _VictorValidateMixin, _VictorAutomergeMixin): """ @@ -225,7 +227,7 @@ def _analyse(self) -> None: attachment=attachment, merging_mode=self.monster_merging_mode) self.journal.debug(f'{self.long_name} - Tried {len(self.monster.scaffold_options)} combinations') - self.unminimised_pdbblock = self._place_monster_in_structure() + self.unminimised_pdbblock = self._plonk_monster_in_structure() self.constraint.custom_constraint += self._make_coordinate_constraints() self._checkpoint_bravo() # save stuff @@ -320,6 +322,10 @@ def _make_coordinate_constraints(self): f'{pos.x} {pos.y} {pos.z} {fxn}\n') return ''.join(lines) + # ------------- Plonk in structure ------------------------------------------------------------------------------ + # the following is here as opposed to Monster, because it requires the template, ligand connections etc. + # the stupid name "plonk" is to distinguish it from place and placement, which have a different meaning in Monster. + def _get_LINK_record(self): if self.is_covalent: # get correct chain names. @@ -344,6 +350,7 @@ def _correct_ligand_info(self, mol: Optional[Chem.Mol]=None) -> Chem.Mol: """ Corrects in place the given mol based on self.ligand_resi. If none provided it assumed self.monster.positioned_mol + Correcting the serial unfortunately does not do anything. """ if mol is None: mol = self.monster.positioned_mol @@ -357,23 +364,71 @@ def _correct_ligand_info(self, mol: Optional[Chem.Mol]=None) -> Chem.Mol: info.SetResidueName(self.ligand_resn) return mol + def _plonk_monster_in_structure(self, use_pymol=False): + self._correct_ligand_info() + self.journal.debug(f'{self.long_name} - placing monster in structure') + if use_pymol: + return self._plonk_monster_in_structure_pymol() + else: + # _plonk_monster_in_structure_raw does no corrections. + return self._plonk_monster_in_structure_minimal() - def _place_monster_in_structure(self): # TODO make a new method that does not use Pymol + def _get_preminimised_undummied_monster(self): """ - Places the molecule in the structure using pymol. - :return: + This method is called by the plonking into structure methods. + Not "positioning" as intended by ``monster`` is done. + Opening a PDB in RDKit is doable but gets exponentially slow with chain length """ - import pymol2 - self._correct_ligand_info() mol = AllChem.DeleteSubstructs(self.monster.positioned_mol, Chem.MolFromSmiles('*')) if self.monster_mmff_minisation: self.journal.debug(f'{self.long_name} - pre-minimising monster (MMFF)') self.monster.mmff_minimise(mol) - self.journal.debug(f'{self.long_name} - placing monster in structure') + return mol + + + def _plonk_monster_in_structure_minimal(self): + """ + Plonks the molecule in the structure without using pymol. + Uses a custom miniparser. see minimalPDB + + :return: + """ + mol = self._get_preminimised_undummied_monster() + pdbdata = MinimalPDBParser(self.apo_pdbblock) + moldata = MinimalPDBParser(Chem.MolToPDBBlock(mol)) + if self.is_covalent: + pdbdata.headers.append(self._get_LINK_record()) + pdbdata.append(moldata) # fixes offsets in ATOM/HETATM and CONECT lines. + return str(pdbdata) + + def _plonk_monster_in_structure_raw(self): + """ + Plonks the molecule in the structure without using pymol. + Not "positioning" as intended by ``monster`` is done. + Opening a PDB in RDKit is doable but gets exponentially slow with chain length + + :return: + """ + mol = self._get_preminimised_undummied_monster() + mol_block = Chem.MolToPDBBlock(mol) + return '\n'.join([self._get_LINK_record().strip(), + self.apo_pdbblock.strip(), + mol_block + ]).strip() + + def _plonk_monster_in_structure_pymol(self): + """ + Plonks the molecule in the structure using pymol. + Not "positioning" as intended by ``monster`` is done. + + :return: + """ + import pymol2 + mol = self._get_preminimised_undummied_monster() with pymol2.PyMOL() as pymol: pymol.cmd.read_pdbstr(self.apo_pdbblock, 'apo') pos_mol = Chem.MolToPDBBlock(mol) - pymol.cmd.read_pdbstr(pos_mol, 'scaffold') + #pymol.cmd.read_pdbstr(pos_mol, 'scaffold') pymol.cmd.remove('name R') # no dummy atoms! for c in self._connected_names: pymol.cmd.remove(f'name {c}') # no conns @@ -382,6 +437,8 @@ def _place_monster_in_structure(self): # TODO make a new method that does not us pymol.cmd.delete('*') return self._get_LINK_record() + pdbblock + # ------------- Igor ------------------------------------------------------------------------------ + def _fix_minimised(self) -> Chem.Mol: """ PDBs are terrible for bond order etc. and Rosetta addes these based on atom types diff --git a/fragmenstein/victor/_victor_automerge_mixin.py b/fragmenstein/victor/_victor_automerge_mixin.py index 8c21959..c03c008 100644 --- a/fragmenstein/victor/_victor_automerge_mixin.py +++ b/fragmenstein/victor/_victor_automerge_mixin.py @@ -146,7 +146,7 @@ def _combine_main(self): self._log_warnings() self.post_params_step() self.monster_merging_mode = 'full' - self.unminimised_pdbblock = self._place_monster_in_structure() + self.unminimised_pdbblock = self._plonk_monster_in_structure() params_file, holo_file, constraint_file = self._save_prerequisites() self.unbound_pose = self.params.test() self._checkpoint_alpha() diff --git a/fragmenstein/victor/junk.py b/fragmenstein/victor/junk.py deleted file mode 100644 index 8b2647f..0000000 --- a/fragmenstein/victor/junk.py +++ /dev/null @@ -1,158 +0,0 @@ -# this method is kept here as it has high salvage potential... -# namely it predicts what the covalent points are etc. - -class DeleteMe: - @classmethod - def validate(cls, - hits: List[Chem.Mol], - smiles: str, - followup_pdb_filename: str, - template_pdb_filename: str, - ligand_resn: str = 'LIG'): - - """ - Given a pdb file with the protein with ligand and a smiles string, score it against hits. - Without changing the position of the ligand —bar for protonations. - The purpose of this is to get a DDG and a RMSD of a given followup for validation purposes. - It is a bit convoluted solely to have consistent atom names with the followup, - as opposed to changing them afterwards —safer for any arbitrary test. - The followup pdb is not used for monster placement as that would bias the test! - - :param hits: - :param smiles: - :param followup_pdb_filename: pdb file with followup - :param template_pdb_filename: pdb file of apo structure to use for placement - - :param ligand_resn: - :return: - """ - raise ValueError('THIS MAY BE BIASED!') - # ***** STORE ******* - # entry attributes - self = cls.__new__(cls) - self.monster_merging_mode = 'none_permissive' - fname = long_name = os.path.split(followup_pdb_filename)[-1] - long_name = os.path.splitext(fname)[0] + '_validation' - self.long_name = self.slugify(long_name) - self.pdb_filename = followup_pdb_filename # non standard! - self.unminimised_pdbblock = None - self.apo_pdbblock = open(template_pdb_filename).read() - self.hits = hits - self.ligand_resn = ligand_resn - pdb = Chem.MolFromPDBFile(followup_pdb_filename) - attachment, attachee = self.find_attachment(pdb, ligand_resn) - if attachment is not None: - self.is_covalent = True - if '*' in smiles: - self.smiles = smiles - else: - self.smiles = self.make_covalent(smiles) - else: - self.smiles = smiles - self.is_covalent = False - attachment, attachee = self.find_closest_to_ligand(pdb, ligand_resn) - info = attachment.GetPDBResidueInfo() - self.covalent_resn = info.GetResidueName() - self.covalent_resi = str(info.GetResidueNumber() ) +info.GetChainId() - info = attachee.GetPDBResidueInfo() - self.ligand_resi = str(info.GetResidueNumber() ) +info.GetChainId() - self.pose_fx = None - # these are calculated - self.params = None - self.mol = None - self.constraint = None - self.extra_constraint = None - self.monster = None - self.igor = None - self.minimised_pdbblock = None - self.minimised_mol = None - # this is unique to validate - self.reference_mol = self.extract_mol(name='crystal', - filepath=followup_pdb_filename, - smiles=smiles, - ligand_resn=ligand_resn) - # buffers etc. - self._warned = [] - self.energy_score = {'ligand_ref2015': {'total_score': float('nan')}, - 'unbound_ref2015': {'total_score': float('nan')}} - self.mrmsd = mRSMD.mock() - self.tick = time.time() - self.tock = float('inf') - # analyse - self._safely_do(execute=self._vanalyse, resolve=self._resolve, reject=self._reject) - return self - - def _vanalyse(self): - # THIS IS A COPY PASTE EXCEPT FOR REANIMATE and Params!! - # self._assert_inputs() - # ***** PARAMS & CONSTRAINT ******* - self.journal.info(f'{self.long_name} - Starting work') - self._log_warnings() - # making folder. - self._make_output_folder() - # make params - self.journal.debug(f'{self.long_name} - Starting parameterisation') - self.params = Params.from_smiles_w_pdbfile(pdb_file=self.pdb_filename, - smiles=self.smiles, generic= False, - name=self.ligand_resn, - proximityBonding=False) - # self.journal.warning(f'{self.long_name} - CHI HAS BEEN DISABLED') - # self.params.CHI.data = [] # TODO fix chi - self.mol = self.params.mol - self._log_warnings() - # get constraint - self.constraint = self._get_constraint(self.extra_constraint) - attachment = self._get_attachment_from_pdbblock() if self.is_covalent else None - self._log_warnings() - self.post_params_step() - # ***** FRAGMENSTEIN ******* - # make monster - attachment = self._get_attachment_from_pdbblock() if self.is_covalent else None - self.journal.debug(f'{self.long_name} - Starting monster') - self.monster = Monster(mol=self.params.mol, # Chem.MolFromSmiles(self.smiles) - hits=self.hits, - attachment=attachment, - merging_mode=self.monster_merging_mode, - debug_draw=self.monster_debug_draw, - average_position=self.monster_average_position) - self.unminimised_pdbblock = self._place_monster_in_structure() - if self.monster_mmff_minisation: - self.journal.debug(f'{self.long_name} - pre-minimising monster (MMFF)') - self.monster.mmff_minimise(self.monster.positioned_mol) - self.constraint.custom_constraint += self._make_coordinate_constraints() - self._checkpoint_bravo() - # save stuff - params_file, holo_file, constraint_file = self._save_prerequisites() - self.post_monster_step() - self.unbound_pose = self.params.test() - self._checkpoint_alpha() - # ***** EGOR ******* - self.journal.debug(f'{self.long_name} - setting up Igor') - self.igor = Igor.from_pdbblock(pdbblock=self.unminimised_pdbblock, - params_file=params_file, - constraint_file=constraint_file, - ligand_residue=self.ligand_resi, - key_residues=[self.covalent_resi]) - # user custom code. - if self.pose_fx is not None: - self.journal.debug(f'{self.long_name} - running custom pose mod.') - self.pose_fx(self.igor.pose) - else: - self.pose_mod_step() - # storing a roundtrip - self.unminimised_pdbblock = self.igor.pose2str() - # DO NOT DO ddG = self.reanimate() - # ddG = self.quick_renamiate() # put igor to work! - ddG = self.reanimate() - self.minimised_pdbblock = self.igor.pose2str() - self.post_igor_step() - self.minimised_mol = self._fix_minimised() - self.mrmsd = self._calculate_rmsd() - self.journal.info(f'{self.long_name} - final score: {ddG} kcal/mol {self.mrmsd.mrmsd}.') - self._checkpoint_charlie() - # RMSD against self.reference_mol and docked_mol - m = mRSMD.from_other_annotated_mols(self.minimised_mol, self.hits, self.monster.positioned_mol) - - docked_mol = self.dock() - # RMSD again - self.journal.debug(f'{self.long_name} - Completed') diff --git a/fragmenstein/victor/minimalPDB.py b/fragmenstein/victor/minimalPDB.py new file mode 100644 index 0000000..eb8ca09 --- /dev/null +++ b/fragmenstein/victor/minimalPDB.py @@ -0,0 +1,98 @@ +from __future__ import annotations +# # original smaller function +# from collections import namedtuple +# +# Parts = namedtuple('Parts', +# ['step', 'headers', 'coordinates', 'connections', 'tails'], +# defaults=(0, [], [], [], []) +# ) + +# # The following does not work +# +# block = Chem.MolToPDBBlock(mol) +# mol = Chem.MolFromPDBBlock(block) +# for atom in mol.GetAtoms(): +# sn = atom.GetPDBResidueInfo().GetSerialNumber() +# atom.GetPDBResidueInfo().SetSerialNumber(sn+10) +# block = Chem.MolToPDBBlock(mol) + +from textwrap import wrap + +class MinimalPDBParser: + """ + This purpose build PDB parser simply fixes the serial numbers. + The reason is that writing a custom 50 line class is easier that + having biopython or other non-builtin requirement as a requirement + Importing the PDB into RDKit is inadvisable. + """ + + def __init__(self, block: str): + self.step = 0 + # step = 0 header unfinished, 1 coordinates finished, 2 connections finished. + self.headers = [] + self.coordinates = [] + self.connections = [] + self.tails = [] + self.parse(block) + + def parse(self, block:str) -> None: + # ---- parse ----------------------------------------- + def starts_with(xrow, name): return xrow.find(name) == 0 + + for row in block.split('\n'): + row = row.strip() + if row == '': + continue + elif starts_with(row, 'ATOM') or starts_with(row, 'HETATM'): + self.step = 1 + self.coordinates.append(row) + elif starts_with(row, 'CONECT'): + self.step = 2 + self.connections.append(row) + elif starts_with(row, 'TER') or starts_with(row, 'END'): + continue + elif self.step == 0: + self.headers.append(row) + elif starts_with(row, 'ANISOU'): + continue + elif self.step == 1: + print(f'What is {row}?') + elif self.step > 1: + self.tails.append(row) + else: + raise SyntaxError('Impossible') + + def __str__(self): + return '\n'.join(self.headers + self.coordinates + self.connections + ['END'] + self.tails) + + def get_serial(self, entry: str): + # ATOM 588 11 - 14 + return int(entry[6:12].strip()) + + def get_max_serial(self) -> int: + # assuming ordered + return self.get_serial(self.coordinates[-1]) + + def set_serial(self, entry: str, value: int) -> None: + new = f'{entry[:6]}{value: >5}{entry[11:]}' + i = self.coordinates.index(entry) + self.coordinates[i] = new + + def offset_serials(self, offset: int) -> None: + for entry in self.coordinates: + original_serial = self.get_serial(entry) + self.set_serial(entry, original_serial + offset) + + def offset_connections(self, offset:int) -> None: + for i, entry in enumerate(self.connections): + self.connections[i] = 'CONECT' + ''.join([f'{int(x)+offset: >5}' for x in wrap(entry[7:], 5)]) + + def append(self, other: MinimalPDBParser): + """ + Add a second parser data to it. But only its coordinates and connections. + """ + offset = self.get_max_serial() + other.offset_serials(offset) + other.offset_connections(offset) + self.coordinates += other.coordinates + self.connections += other.connections \ No newline at end of file From e295f0b8586d9a7ac1c465540f861346554d184e Mon Sep 17 00:00:00 2001 From: matteoferla Date: Fri, 5 Feb 2021 16:41:39 +0000 Subject: [PATCH 20/32] :name_badge: I had to change the darn names as they were ambiguous: now all "merging" for **placement** is "blending" --- documentation/_snippets.md | 38 ++++++++++- documentation/changelog_0.5.md | 27 +++++--- documentation/monster/monster_full.md | 2 +- .../monster/note_about_merging_operations.md | 2 +- documentation/sphinx-docs.md | 2 +- fragmenstein/monster/__init__.py | 65 +++++++++++++------ fragmenstein/monster/_collapse_ring.py | 3 +- test.py | 2 +- 8 files changed, 105 insertions(+), 36 deletions(-) diff --git a/documentation/_snippets.md b/documentation/_snippets.md index bebec07..c6a735b 100644 --- a/documentation/_snippets.md +++ b/documentation/_snippets.md @@ -19,4 +19,40 @@ Show the steps monster = Monster([fore, aft]).merge() for m in monster.modifications: - display(m) \ No newline at end of file + display(m) + +Show multiple RDKit mols in nglview + + import nglview as nv + from io import StringIO + + def show_mols(*mols: Chem.Mol) -> nv.NGLWidget: + view = nv.NGLWidget() + for mol in mols: + fh = StringIO(Chem.MolToPDBBlock(mol)) + view.add_component(fh, ext='pdb') + return view + +# X + +One issue is that the ring mergers are not transitive. +Hit order results in different cases: + + ortho = Chem.MolFromSmiles('Cc1cc(O)ccc1') + meta = Chem.MolFromSmiles('Cc1ccc(O)cc1') + AllChem.EmbedMolecule(ortho) + AllChem.EmbedMolecule(meta) + Chem.rdMolAlign.AlignMol(prbMol=ortho, + refMol=meta, + atomMap=[(0,0), (1,1)], + weights=[1,1], + ) + show_mols(ortho, meta) + +These two cresol rings are perpendicular. The merger produces the same compound, methylcatecol +but one has a more distorted conformation. + + Monster([ortho, meta]).merge().positioned_mol # decent + Monster([meta, ortho]).merge().positioned_mol # indecent + +What are the implications for this? \ No newline at end of file diff --git a/documentation/changelog_0.5.md b/documentation/changelog_0.5.md index 21baafb..0c3ce94 100644 --- a/documentation/changelog_0.5.md +++ b/documentation/changelog_0.5.md @@ -18,28 +18,35 @@ While to do a merger Additionally, the attribute `modifications` was added/expanded, so that intermediate steps are stored for potential inspection. -`merge` still calls `merge_hits`. +`merge` still calls `simply_merge_hits`. If one wanted to merge two or more hits, independently of those in `.hits` attribute and without ring collapsing and rectification etc. -`merge_hits` is still the one: +`simply_merge_hits` is still the one: monster = Monster([]) - monster.merge_hits([molA, molB]) + monster.simply_merge_hits([molA, molB]) The `place` method accepts the argument `merging_mode`, by default it is "permissive_none", -which calls `.no_merging(broad=True)`, +which calls `.no_blending(broad=True)`, but "off" (nothing), -"full" (`.full_merging()`), -"partial" (`.partial_merging()`) -and "none" (`.no_merging()`) +"full" (`.full_blending()`), +"partial" (`.partial_blending()`) +and "none" (`.no_blending()`) are accepted. +## Names +The names "merge" and "place" were ultra-confusingly ambiguous when it comes to the other methods, especially those of "place". + +* Now all the cases where hits are partially combined for placement purposes are called "blending" +The placement of the (distored) 3D final monster compound Victor is called "plonk". + +* place and position are used synonymously +* combine and merge are used synonymously + + ## Future Victor however still has the merger as a side route. -The names "merge" and "place" are ambiguous when it comes to the other methods, especially those of "place". -"position" is also used for the (distored) 3D final compound. - ## Overlapping rings There was a bug in the code for `Monster` that meant that if two rings from different origins that were not bonded diff --git a/documentation/monster/monster_full.md b/documentation/monster/monster_full.md index 6910645..43b264e 100644 --- a/documentation/monster/monster_full.md +++ b/documentation/monster/monster_full.md @@ -26,7 +26,7 @@ Note that `.initial_mol` is not touched. `.positioned_mol` may have lost some cu The following steps are done: -* `.merge_hits()`: merges the hits, the output `rdkit.Chem.Mol` object added as `.scaffold`. +* `.simply_merge_hits()`: merges the hits, the output `rdkit.Chem.Mol` object added as `.scaffold`. * `.make_chimera()`: makes the atomic elements in `.scaffold` match those in the followup, the output `rdkit.Chem.Mol` object added as `.chimera`. * `.place_from_map()` followup is places like the scaffold. diff --git a/documentation/monster/note_about_merging_operations.md b/documentation/monster/note_about_merging_operations.md index 7552403..f564fb5 100644 --- a/documentation/monster/note_about_merging_operations.md +++ b/documentation/monster/note_about_merging_operations.md @@ -6,7 +6,7 @@ The automerging route was therefore built on top of it. The `_VictorAutomergeMixin` contains the automerging code, most notably the classmethod `combine`. -This uses `merge_hits` from the main class, written first. +This uses `simply_merge_hits` from the main class, written first. Then to address the problem of rings merging oddly, the ring collapse functionality was added and can be found in `_collapse_ring`. diff --git a/documentation/sphinx-docs.md b/documentation/sphinx-docs.md index 893a250..dffdefa 100644 --- a/documentation/sphinx-docs.md +++ b/documentation/sphinx-docs.md @@ -123,7 +123,7 @@ while for the positioning this is not the case. -#### merge_hits() +#### simply_merge_hits() Recursively stick the hits together and average the positions. diff --git a/fragmenstein/monster/__init__.py b/fragmenstein/monster/__init__.py index 4e1fdbe..cf17ebe 100644 --- a/fragmenstein/monster/__init__.py +++ b/fragmenstein/monster/__init__.py @@ -113,6 +113,21 @@ def place(self, mol: Chem.Mol, attachment: Optional[Chem.Mol] = None, merging_mode: str = 'none_permissive'): + """ + Positioned a given mol based on the hits. (Main entrypoint) + accepts the argument `merging_mode`, by default it is "permissive_none", + which calls `.no_blending(broad=True)`, + but "off" (does nothing except fill the attribute ``initial_mol``), + "full" (`.full_blending()`), + "partial" (`.partial_blending()`) + and "none" (`.no_blending()`) + are accepted. + + :param mol: + :param attachment: + :param merging_mode: + :return: + """ self.initial_mol, self.attachment = self._parse_mol_for_place(mol, attachment) # Reset self.unmatched = [] @@ -121,15 +136,15 @@ def place(self, if merging_mode == 'off': pass elif merging_mode == 'full': - self.full_merging() + self.full_blending() elif merging_mode == 'partial': - self.partial_merging() + self.partial_blending() elif merging_mode == 'none_permissive' or merging_mode == 'permissive_none': - self.no_merging(broad=True) + self.no_blending(broad=True) elif merging_mode == 'none': - self.no_merging() + self.no_blending() else: - valid_modes = ('full','partial','none','none_permissive', 'off') + valid_modes = ('full', 'partial', 'none', 'none_permissive', 'off') raise ValueError( f"Merging mode can only be {'| '.join(valid_modes)}, not '{merging_mode}'") return self @@ -162,7 +177,7 @@ def _parse_mol_for_place(self, def merge(self, keep_all=True, collapse_rings=True, joining_cutoff: int = 5): """ - Merge the hits. + Merge/links the hits. (Main entrypoint) :param keep_all: :param collapse_rings: @@ -178,7 +193,7 @@ def merge(self, keep_all=True, collapse_rings=True, joining_cutoff: int = 5): self.modifications.extend(col_hits) else: col_hits = self.hits - self.scaffold = self.merge_hits(col_hits) + self.scaffold = self.simply_merge_hits(col_hits) self.modifications.append(Chem.Mol(self.scaffold)) # backup for debug ## Discard can happen for other reasons than disconnect if keep_all and len(self.unmatched): @@ -206,25 +221,30 @@ def rectify(self): self.positioned_mol = recto.mol self.modifications.extend(recto.modifications) # backup for debug - # TODO move these to own file # ================================================================================================================== + # common to move - @classmethod - def full_merging(self) -> None: + #simply_merge_hits, merge_pair, _pre_fragment_pairs, _recruit_team, _categorise, get_positional_mapping + + # ================================================================================================================== + # placement dependent methdos + + # @classmethod #why was this a classmethod + def full_blending(self) -> None: """ a single scaffold is made (except for ``.unmatched``) """ - self.scaffold_options = [self.merge_hits()] + self.scaffold_options = [self.simply_merge_hits()] self.scaffold = self.posthoc_refine(self.scaffold_options[0]) self.chimera = self.make_chimera() self.positioned_mol = self.place_from_map() - def partial_merging(self) -> None: + def partial_blending(self) -> None: """ multiple possible scaffolds and best is chosen """ - self.scaffold_options = self.combine_hits() # merger of hits + self.scaffold_options = self.partially_blend_hits() # merger of hits unrefined_scaffold, mode_index = self.pick_best() used = self.scaffold.GetProp('_Name').split('-') self.unmatched = [h.GetProp('_Name') for h in self.hits if h.GetProp('_Name') not in used] @@ -232,7 +252,7 @@ def partial_merging(self) -> None: self.chimera = self.make_chimera(mode_index) self.positioned_mol = self.place_from_map() - def no_merging(self, broad=False) -> None: + def no_blending(self, broad=False) -> None: """ no merging is done. The hits are mapped individually. Not great for small fragments. """ @@ -316,9 +336,9 @@ def merge_pair(self, scaffold: Chem.Mol, fragmentanda: Chem.Mol, mapping: Option self.draw_nicely(scaffold) return scaffold - # ================= Combine hits =================================================================================== + # ================= Blend hits =================================================================================== - def combine_hits(self, hits: Optional[List[Chem.Mol]] = None) -> List[Chem.Mol]: + def partially_blend_hits(self, hits: Optional[List[Chem.Mol]] = None) -> List[Chem.Mol]: """ This is the partial merge algorithm, wherein the hits are attempted to be combined. If the combination is bad. It will not be combined. @@ -372,7 +392,7 @@ def get_dodgies(skippers): print(dodgy_names) dodgies = [hit for hit in hits if hit.GetProp('_Name') in dodgy_names] mergituri = [hit for hit in hits if hit.GetProp('_Name') not in dodgy_names] - merged = self.merge_hits(mergituri) + merged = self.simply_merge_hits(mergituri) dodgies += [hit for hit in hits if hit.GetProp('_Name') in self.unmatched] self.unmatched = [] combined_dodgies = [] @@ -405,7 +425,12 @@ def propagate_alternatives(self, fewer): new += 1 return new - def pick_best(self): + def pick_best(self) -> Tuple[Chem.Mol, int]: + """ + Method for partial merging for placement + + :return: unrefined_scaffold, mode_index + """ if len(self.scaffold_options) == 1: return self.scaffold_options[0], 0 elif len(self.scaffold_options) == 0: @@ -488,11 +513,11 @@ def template_sorter(t: List[Chem.Mol]) -> float: # else: # return {n: path} - def merge_hits(self, hits: Optional[List[Chem.Mol]] = None) -> Chem.Mol: + def simply_merge_hits(self, hits: Optional[List[Chem.Mol]] = None) -> Chem.Mol: """ Recursively stick the hits together and average the positions. This is the monster of automerging, full-merging mapping and partial merging mapping. - The latter however uses `combine_hits` first. + The latter however uses `partially_blend_hits` first. The hits are not ring-collapsed and -expanded herein. :param hits: optionally give a hit list, else uses the attribute ``.hits``. diff --git a/fragmenstein/monster/_collapse_ring.py b/fragmenstein/monster/_collapse_ring.py index da7f42a..842e691 100644 --- a/fragmenstein/monster/_collapse_ring.py +++ b/fragmenstein/monster/_collapse_ring.py @@ -530,7 +530,8 @@ def _get_close_nonorigin_ring_atoms_indices(self, self._nan_fill_others(mol, distance_matrix, [idx for idcs in atomdex.values() for idx in idcs]) # get the pair of atom indices that are less thna cutoff. # where returns a tuple of np.arrays of dtype=np.int64 - return list(zip(*[w.astype(int) for w in np.where(distance_matrix < cutoff)])) + with np.errstate(invalid='ignore'): + return list(zip(*[w.astype(int) for w in np.where(distance_matrix < cutoff)])) def _determine_mergers_novel_ringcore_pair(self, mol: Chem.RWMol, diff --git a/test.py b/test.py index 449864d..26f2164 100644 --- a/test.py +++ b/test.py @@ -287,7 +287,7 @@ def test_merge_on_same_dummy(self): acetyl, nitrile = self.make_pair_by_split(conjoined, 4) # merge monster = Monster([acetyl, nitrile]) - merger = monster.merge_hits() + merger = monster.simply_merge_hits() dummies = merger.GetAtomsMatchingQuery(Chem.rdqueries.AtomNumEqualsQueryAtom(0)) for dummy in dummies: self.assertEqual(len(dummy.GetNeighbors()), 1) From b55e3ef3470c98cf1d890c9c8d9c8f0594934a52 Mon Sep 17 00:00:00 2001 From: matteoferla Date: Mon, 8 Feb 2021 17:45:43 +0000 Subject: [PATCH 21/32] :hammer: Misc. including changed `scaffold_options` to `mol_options` --- fragmenstein/monster/__init__.py | 39 ++++++++++--------- fragmenstein/monster/_collapse_ring.py | 31 +++++++++++++-- fragmenstein/monster/_utility_mixin.py | 4 +- fragmenstein/monster/unmerge_mapper.py | 1 + fragmenstein/victor/__init__.py | 8 ++-- .../victor/_victor_automerge_mixin.py | 4 +- test.py | 34 +++++++++------- 7 files changed, 76 insertions(+), 45 deletions(-) diff --git a/fragmenstein/monster/__init__.py b/fragmenstein/monster/__init__.py index cf17ebe..90da25e 100644 --- a/fragmenstein/monster/__init__.py +++ b/fragmenstein/monster/__init__.py @@ -49,7 +49,7 @@ class Monster(_MonsterUtil, _MonsterRing, GPM, _MonsterJoinNeighMixin): # Unmer The reason is to do place the followup compound to the hits as faithfully as possible regardless of the screaming forcefields. * ``.scaffold`` is the combined version of the hits (rdkit.Chem.Mol object). - * ``.scaffold_options`` are the possible scaffolds to use. + * ``.mol_options`` are the possible mol_options to use. * ``.chimera`` is the combined version of the hits, but with differing atoms made to match the followup (rdkit.Chem.Mol object). * ``.positioned_mol`` is the desired output (rdkit.Chem.Mol object) @@ -98,11 +98,11 @@ def __init__(self, # self.matched is dynamic. #: accepted hits # Chem.Mol or List[Chem.Mol] self.modifications = [] - self.initial_mol = None #: to be filled + self.initial_mol = None #: to be filled by place. The starting molecule (Chem.Mol). self.attachment = None - # self.scaffold = None #: template which may have wrong elements - # self.scaffold_options = [] #: partial combined templates (merging_mode: partial) - self.scaffolds = [] #: templates which may have wrong elements + # self.scaffold = None #: template which may have wrong elements in place, or + # self.mol_options = [] #: partial combined templates (merging_mode: partial) + self.mol_options = [] #: templates which may have wrong elements self.chimera = None #: merger of hits but with atoms made to match the to-be-aligned mol self.positioned_mol = None #: final molecule @@ -131,7 +131,7 @@ def place(self, self.initial_mol, self.attachment = self._parse_mol_for_place(mol, attachment) # Reset self.unmatched = [] - self.scaffold_options = [] + self.mol_options = [] # do calculations if merging_mode == 'off': pass @@ -235,16 +235,16 @@ def full_blending(self) -> None: """ a single scaffold is made (except for ``.unmatched``) """ - self.scaffold_options = [self.simply_merge_hits()] - self.scaffold = self.posthoc_refine(self.scaffold_options[0]) + self.mol_options = [self.simply_merge_hits()] + self.scaffold = self.posthoc_refine(self.mol_options[0]) self.chimera = self.make_chimera() self.positioned_mol = self.place_from_map() def partial_blending(self) -> None: """ - multiple possible scaffolds and best is chosen + multiple possible scaffolds for placement and best is chosen """ - self.scaffold_options = self.partially_blend_hits() # merger of hits + self.mol_options = self.partially_blend_hits() # merger of hits unrefined_scaffold, mode_index = self.pick_best() used = self.scaffold.GetProp('_Name').split('-') self.unmatched = [h.GetProp('_Name') for h in self.hits if h.GetProp('_Name') not in used] @@ -276,6 +276,7 @@ def no_blending(self, broad=False) -> None: no_discard=self.throw_on_discard, _debug_draw=self._debug_draw) self.scaffold = um.combined + self.mol_options = um.combined_alternatives full_atom_map = um.combined_map self.unmatched = [m.GetProp('_Name') for m in um.disregarded] if self.throw_on_discard and len(self.unmatched): @@ -431,9 +432,9 @@ def pick_best(self) -> Tuple[Chem.Mol, int]: :return: unrefined_scaffold, mode_index """ - if len(self.scaffold_options) == 1: - return self.scaffold_options[0], 0 - elif len(self.scaffold_options) == 0: + if len(self.mol_options) == 1: + return self.mol_options[0], 0 + elif len(self.mol_options) == 0: raise ValueError('No scaffolds made?!') else: mapx = {} #: dictionary of key mol name and value tuple of maps and mode @@ -447,7 +448,7 @@ def template_sorter(t: List[Chem.Mol]) -> float: ## get data # presort as this is expensive. - for template in self.scaffold_options: + for template in self.mol_options: # _get_atom_maps returns a list of alternative mappings which are lists of template to initail mol atom_maps = self._get_atom_maps(template, self.initial_mol, atomCompare=rdFMCS.AtomCompare.CompareElements, @@ -457,8 +458,8 @@ def template_sorter(t: List[Chem.Mol]) -> float: matchChiralTag=False) mapx[template.GetProp('_Name')] = (atom_maps, self.matching_modes[-1]) # search properly only top 3. - self.scaffold_options = sorted(self.scaffold_options, key=template_sorter) - for template in self.scaffold_options[:3]: + self.mol_options = sorted(self.mol_options, key=template_sorter) + for template in self.mol_options[:3]: atom_map, mode = self.get_mcs_mapping(template, self.initial_mol) # get_mcs_mapping returns a dict going from template index to initial. mapx[template.GetProp('_Name')] = (atom_map, mode) @@ -466,15 +467,15 @@ def template_sorter(t: List[Chem.Mol]) -> float: print( f"With {template.GetProp('_Name')}, {len(atom_map)} atoms map using mode {self.matching_modes.index(mode)}") ## pick best template - self.scaffold_options = sorted(self.scaffold_options, key=template_sorter) + self.mol_options = sorted(self.mol_options, key=template_sorter) ## Check if missing atoms can be explained by a different one with no overlap - best = self.scaffold_options[0] + best = self.mol_options[0] ## Fuse overlaps # best_map = maps[best.GetProp('_Name')][0] # full = set(range(self.initial_mol.GetNumAtoms())) # present = set(best_map.values()) # missing = full - present - # for other in self.scaffold_options: + # for other in self.mol_options: # other_map = maps[other.GetProp('_Name')][0] # found = set(other_map.values()) # if len(found) > 6 and len(present & found) == 0: # more than just a ring and no overlap diff --git a/fragmenstein/monster/_collapse_ring.py b/fragmenstein/monster/_collapse_ring.py index 842e691..16e1d67 100644 --- a/fragmenstein/monster/_collapse_ring.py +++ b/fragmenstein/monster/_collapse_ring.py @@ -269,8 +269,31 @@ def _get_expansion_data(self, mol: Chem.Mol) -> List[Dict[str, List[Any]]]: bonds=json.loads(atom.GetProp('_bonds'))) for atom in self._get_collapsed_atoms(mol)] - def _get_expansion_for_atom(self, data: Dict[str, List[Any]], i: int) -> Dict[str, Any]: - return {k.replace('s', ''): data[k][i] if isinstance(data[k], list) else data[k] for k in data} + def _get_expansion_for_atom(self, ring: Dict[str, List[Any]], i: int) -> Dict[str, Any]: + """ + ``_get_expansion_data`` returns from a mol the "expansion data for the rings" + ``_get_expansion_for_atom`` given one of the list of the data from the latter (representing a ring core) + and an index of which of the internal atoms that were collapsed return a dictionary of details + of that atom. + + :param ring: see ``_get_expansion_data`` + :param i: the internal index. Say 'elements': ['C', 'C', 'C', 'O', 'C', 'C']. i = 3 would will be Oxygen. + :return: + """ + try: + return {k.replace('s', ''): ring[k][i] if isinstance(ring[k], list) else ring[k] for k in ring} + except IndexError: + troublesome = [k for k in ring if isinstance(ring[k], list) and len(ring[k]) <= i] + if len(troublesome) == 0: + raise IndexError(f'There is a major issue with ring data for index {i}: {ring}') + elif troublesome[0] == 'current_is': + self.journal.warning(f'One atom lacks a current index!'+ \ + 'This is a fallback that should not happen') + mol = ring['atom'].GetOwningMol() + ring['current_is'] = [self._get_new_index(mol, old_i, search_collapsed=False) for old_i in ring['ori_is']] + return self._get_expansion_for_atom(ring, i) + else: + raise IndexError(f'The indices of the collapsed atom do not extend to {i} for {troublesome}') # === Key steps ==================================================================================================== @@ -549,8 +572,8 @@ def _determine_mergers_novel_ringcore_pair(self, :return: list of atoms to be merged """ absorption_distance = 1. # Å - print('A', ringcore_A, ringcore_A.GetIdx(), ringcore_A.GetIntProp('_ori_i')) - print('B', ringcore_B, ringcore_B.GetIdx(), ringcore_B.GetIntProp('_ori_i')) + # print('A', ringcore_A, ringcore_A.GetIdx(), ringcore_A.GetIntProp('_ori_i')) + # print('B', ringcore_B, ringcore_B.GetIdx(), ringcore_B.GetIntProp('_ori_i')) indices_A = json.loads(ringcore_A.GetProp('_current_is')) indices_B = json.loads(ringcore_B.GetProp('_current_is')) distance_matrix = self._get_distance_matrix(mol, indices_A, indices_B) # currently in `_join_neighboring`. diff --git a/fragmenstein/monster/_utility_mixin.py b/fragmenstein/monster/_utility_mixin.py index 674b499..2cf9540 100644 --- a/fragmenstein/monster/_utility_mixin.py +++ b/fragmenstein/monster/_utility_mixin.py @@ -221,8 +221,8 @@ def make_pse(self, filename='test.pse', extra_mols:Optional[Chem.Mol]=None): if self.positioned_mol: pymol.cmd.read_molstr(Chem.MolToMolBlock(self.positioned_mol, kekulize=False), f'followup') pymol.cmd.color('tv_green', f'followup and name C*') - if self.scaffold_options: - for i, mol in enumerate(self.scaffold_options): + if self.mol_options: + for i, mol in enumerate(self.mol_options): pymol.cmd.read_molstr(Chem.MolToMolBlock(mol, kekulize=False), f'opt{i}') pymol.cmd.color('grey50', f'opt{i} and name C*') pymol.cmd.hide('sticks') diff --git a/fragmenstein/monster/unmerge_mapper.py b/fragmenstein/monster/unmerge_mapper.py index 9a1369f..d8e1901 100644 --- a/fragmenstein/monster/unmerge_mapper.py +++ b/fragmenstein/monster/unmerge_mapper.py @@ -121,6 +121,7 @@ def __init__(self, followup: Chem.Mol, mols: List[Chem.Mol], maps: Dict[str, Lis dv = self.measure_map(mol, m) print(j, [dd.GetProp('_Name') for dd in d], len(m), np.mean(dv), np.max(dv), self.offness(mol, m)) self.combined = self.c_options[i] + self.combined_alternatives = [self.c_options[j] for j in equals if j != i] self.combined_map = self.c_map_options[i] self.disregarded = self.c_disregarded_options[i] self.combined_bonded = self.bond() diff --git a/fragmenstein/victor/__init__.py b/fragmenstein/victor/__init__.py index 305dfbe..810e0e2 100644 --- a/fragmenstein/victor/__init__.py +++ b/fragmenstein/victor/__init__.py @@ -226,7 +226,7 @@ def _analyse(self) -> None: self.monster.place(mol=self.mol, attachment=attachment, merging_mode=self.monster_merging_mode) - self.journal.debug(f'{self.long_name} - Tried {len(self.monster.scaffold_options)} combinations') + self.journal.debug(f'{self.long_name} - Tried {len(self.monster.mol_options)} combinations') self.unminimised_pdbblock = self._plonk_monster_in_structure() self.constraint.custom_constraint += self._make_coordinate_constraints() self._checkpoint_bravo() @@ -695,11 +695,11 @@ def _checkpoint_bravo(self): if self.monster.positioned_mol is not None: pos_file = os.path.join(self.work_path, self.long_name, self.long_name + '.positioned.mol') Chem.MolToMolFile(self.monster.positioned_mol, pos_file, kekulize=False) - if self.monster.scaffold_options: - opt_file = os.path.join(self.work_path, self.long_name, self.long_name + '.scaffold_options.sdf') + if self.monster.mol_options: + opt_file = os.path.join(self.work_path, self.long_name, self.long_name + '.mol_options.sdf') writer = Chem.SDWriter(opt_file) writer.SetKekulize(False) - for t in self.monster.scaffold_options: + for t in self.monster.mol_options: writer.write(t) writer.close() diff --git a/fragmenstein/victor/_victor_automerge_mixin.py b/fragmenstein/victor/_victor_automerge_mixin.py index c03c008..e5eb8c8 100644 --- a/fragmenstein/victor/_victor_automerge_mixin.py +++ b/fragmenstein/victor/_victor_automerge_mixin.py @@ -58,7 +58,8 @@ def combine(cls, self = cls.__new__(cls) self.monster_merging_mode = 'full' # needed solely for logkeeping self.long_name = '-'.join([h.GetProp('_Name') for h in hits]) - self.apo_pdbblock = open(pdb_filename).read() + with open(pdb_filename) as fh: + self.apo_pdbblock = fh.read() self.journal.debug(f'{self.long_name} - harmonising warheads on hits in "{warhead_harmonisation}" mode') with warnings.catch_warnings(record=True) as self._warned: self.hits = self.harmonise_warheads(hits, warhead_harmonisation, covalent_form=True) @@ -119,6 +120,7 @@ def _combine_main(self): collapse_rings=True, joining_cutoff=self.monster_joining_cutoff # Å ) + self.mol = self.monster.positioned_mol self.smiles = Chem.MolToSmiles(self.mol) if self.monster_debug_draw: picture = Chem.CombineMols(Chem.CombineMols(self.hits[0], self.hits[1]), self.monster.positioned_mol) diff --git a/test.py b/test.py index 26f2164..6c55c1b 100644 --- a/test.py +++ b/test.py @@ -203,7 +203,10 @@ def test_peridimethylnaphthalene(self): def test_spirodituluene(self): name = 'spirodituluene' - after = ('C[C@@H]1C=CC[C@]2(C=C[C@H](C)C=C2)C1', 'C[C@@H]1C=CC[C@]2(C=C[C@@H](C)C=C2)C1') + after = ('C[C@@H]1C=CC[C@]2(C=C[C@H](C)C=C2)C1', + 'C[C@@H]1C=CC[C@]2(C=C[C@@H](C)C=C2)C1', + 'C[C@H]1C=CC[C@]2(C=C[C@H](C)C=C2)C1', + 'C[C@H]1C=CC[C@]2(C=C[C@@H](C)C=C2)C1') template = os.path.join(MProVictor.get_mpro_path(), 'template.pdb') toluene = Chem.MolFromMolFile('test_mols/toluene.mol') toluene.SetProp('_Name', 'toluene') @@ -297,14 +300,14 @@ def test_merge_on_same_dummy(self): # ---------------------------------------------------------------------------------------------------------------------- class UnresolvedProblems(unittest.TestCase): def test_recto_fail_A(self): - """Not too sure why this fails. I think it is the alphatic - ring merger""" + """This used to fail.""" MProVictor.monster_throw_on_discard = True victor = MProVictor.combine_codes(hit_codes=['x11612', 'x11475']) self.assertEqual(victor.error, '', victor.error) def test_supplementary1_to_recto_fail_A(self): """ - This was ment to test the above, but it works fine. + This was meant to test the above, but it works fine. :return: """ # make hits @@ -327,24 +330,25 @@ def test_supplementary1_to_recto_fail_A(self): # merge monster = Monster(hits=[toluene, chlorobutane]).merge(keep_all=False) # ====== - self.assertEqual(Chem.MolToSmiles(monster.positioned_mol), Chem.MolToSmiles(chlorotoluene)) # CC(Cl)CCc1ccccc1 + self.assertEqual(Chem.MolToSmiles(chlorotoluene), Chem.MolToSmiles(monster.positioned_mol)) # CC(Cl)CCc1ccccc1 def test_supplementary2_to_recto_fail_A(self): """ - This was meant to test as above. It also works fine. + This was meant to test as above. + It mergers xylene with chloropentane :return: """ # - methylchlorotoluene = Chem.MolFromSmiles('Cc1c(Cl)c(C)ccc1') - AllChem.EmbedMolecule(methylchlorotoluene) - methylchlorotoluene.SetProp('_Name', 'methylchlorotoluene') + chloroxylene = Chem.MolFromSmiles('Cc1c(Cl)c(C)ccc1') + AllChem.EmbedMolecule(chloroxylene) + chloroxylene.SetProp('_Name', 'chloroxylene') # - methyltoluene = Chem.RWMol(methylchlorotoluene) - methyltoluene.RemoveAtom(3) - Chem.SanitizeMol(methyltoluene) - methyltoluene.SetProp('_Name', 'methyltoluene') + xylene = Chem.RWMol(chloroxylene) + xylene.RemoveAtom(3) + Chem.SanitizeMol(xylene) + xylene.SetProp('_Name', 'xylene') # - chloropentane = Chem.RWMol(methylchlorotoluene) + chloropentane = Chem.RWMol(chloroxylene) for n in range(chloropentane.GetNumAtoms() - 1, 5, -1): chloropentane.RemoveAtom(n) for atom in chloropentane.GetAtoms(): @@ -354,8 +358,8 @@ def test_supplementary2_to_recto_fail_A(self): Chem.SanitizeMol(chloropentane) chloropentane.SetProp('_Name', '2-chloropentane') # - monster = Monster(hits=[methyltoluene, chloropentane]).merge(keep_all=False) + monster = Monster(hits=[xylene, chloropentane]).merge(keep_all=False) # ====== - self.assertEqual(Chem.MolToSmiles(monster.positioned_mol), Chem.MolToSmiles(methylchlorotoluene)) + self.assertEqual(Chem.MolToSmiles(chloroxylene), Chem.MolToSmiles(monster.positioned_mol)) # Todo: add a class to test missing modules. From fa20f8df4454058eb2f0b3606d3477f797325381 Mon Sep 17 00:00:00 2001 From: matteoferla Date: Mon, 8 Feb 2021 17:45:54 +0000 Subject: [PATCH 22/32] :art: figure --- images/phenylene.png | Bin 0 -> 7968 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 images/phenylene.png diff --git a/images/phenylene.png b/images/phenylene.png new file mode 100644 index 0000000000000000000000000000000000000000..7c2b12446b9b18e3e2016929c88e1285f28975d4 GIT binary patch literal 7968 zcmZ9R1yog0n}#o?&1J0%i*?S~`|SP2`@B0sQ(XZchYAOQK;SDW%4s7IXkGAkGS(IN?jojFfL|Eq zDhhIl%fCNw+X@m82)YR+IcZ(5^sQ-cgT(u%m^<5eSdDL`gBzEK`3PULhd0@qN4|Me zm~={<`mX;~P9au!OZ&^@H_2r03X7zE3#bi^I;k*_T+<~XmU|SJ@$Av?b}WC$BMfq@ zOhLZit3H=IlGf!Le*Uv1E&GE%MsD5gp}=AcY31VIMuZS*w`ftagv3#03n*hT3d>j~ z63Waxn{s^wSl8RSV#m?m?zPF~8UySp%5UZ-npqV6vSBf%TnTVd(NKs}TiOdbn zm&NqExP?M_tuo|Y=U<@>vQcvrQdY@2I~k@u%=%V|w%rzXxG}%MX}}}BytE`IFYn{y zgHyjS)8^}Yur^j}tMguu`A;ayW_o@VlPQ-ikO$dSQc--Ox-n@`eRY4;;v*JgF1Gbp z&b>#E9^t%@sU!^}pub~@N{pr!#i_qJCVHT0>Y0A)d3rkArD2WyVz1R;P{NJ&GwsgD zGEMFqlcD(3h_k~lrUKF*dwO1WFK|DsKieOXYP~!Pp`MDSqN$>o^~V$y9dD~?Yi(<@ z6!@0Nq0{WX!8-VoR^08i$djo*ha3KWe(G6wxCe9OW=Ega{%Y}~q!xu2C}5%$pDU?w zI_B$86?fWO>NgEI$#-7tVPs^KDW|5P`B7{8S{lujlLU*_tYg3BS2dEGu)J^08!MDamDqH5fq|8OF}eRXZgE z%X`;p#SsS0ZbdsKH-5>L{_>ZVFK%?j{1D2>e3d?+P(0}kj)DRS>HMbQ!Fo57QM6LN zwy&>mk**JHjr4Pj`{#FUY}T4wS8J=2TUt&Rx+6 zZ*tDKH)7cTTsT4T>oasJDME@q#L7Afg}NG*FPRm1aVzNJ{M7zWXXT?0wTB}Er`sK- z=g1qZs-yj;uh#gdq9>i_=f75=V-n;%l8w&dKnCYBX=_(Lp=MPh=1Uhb>Ii7F=#4>` zo13R+WK0CG!iR}TmUF<+(6Fhwxj3WQbv34@rbd-D^5sjPjk1Q?YMLTiuP@Fy51Hio z?Cq_rdp9?~*4k1@)mvbq8`M~Fu_<&qO^r4A)e%!&K7XC+pCno zTIcX>Z)GSgno4+qHVo_8AGo=^oI;9@g=OdWD(&(~sY#poty|yVGcXY8nOwlC`g$~9 zCFS(@c7;JzuqW9~!l~$21p)#L@eHEmy|IgJzr6~ICeKfQ)6&xJ@9%4*i|r0eZ12SA z^uNF*Z}!}NYG+49Pd{63EHUF8K0Nj`@%BV1<&`Ul&JhBaTiZetZzMdQ1_WG$6EPi> zg({PbvmQ>@IwFn}kMhXPBffEiz2h@3o}3=pw$M6XkDs3(g#`rlrx7Zg zx0VCRt}BCRbBl{Q@+tV^?z-|3#g9JB%|F|8;4;jKB{+hW@9^5qiH?rWloA-plx%tO zy}qidYBumva+^!8p)iVAxT_1cb5KL-ma%>lMQp>_*_rqL3YtNai{)ZZw0Cb&Ols;k zR1zoJV4A1~GHEYH)-4>xu9fTWD<%<`m6|H#x}rK`h%{_=vwiU3!IyGl`+KgZeeq1E zM_Zgp$`hGZGV6GMA|eV?GBTbxI%Xv$xv!08Gs=eU#GoVk`}@_^)$2C$55Imj5ET`T zSJWNiyv(c5oo3e>>FP3{?|OlN`8*b&+!pH$T)i1fEm~ebu8H8`;mHd4V|!BcDNj9T znte=>C#9vixu?6k47T=k`xdO<&o33GPi~LykL4;5M=b3w_V&imQj0k;K%kvMj0y>e zh?ul^a0hiqk{1*dxT8&g-qBAfsy!DvSMCj@1J$v@-c)LducKZlA#Ki8-4u!yD zMH7>m;A^;IJ(@FSKOh#Qq@-f_O{P*z1AflUIc-dGHxIX~=Y;v};WaqUdU$y7aC5gg z%?G!%wCtc&*VM2OD_L2sz&=Y#O1>a?OWJX^H}F>aIhE+s^td>NoqS)pFEF{x_mh(z zD}$*xFS@>ePaEiPla-MX5EPsZINh3hD2s+iBj(f@gx1v5^#1+()*3=?ST67S*4EpY zm|+J82jSu2e=AJW0hDp`%W(ToM0RL|B+=is^>SdggwoJTT;kr6} z_-p$6$B&N(U-Pf5tTdabXKQYLt681@5N7|S{Jw|81b&*RW2U&f-S_$@jx(*cc6KO< z>tk1txl7k-?Z3qEdu-20K1#NSz6SZ$=KI^kdzti+9?4y(`vb|`u(Ayf-^?8x2LIml zCoukYg>2aM={DalKYsY_E_CCUG##0!P*_llK2=pwc?g-5b1zcYDwgI}_0#EQD3(80 zL)Cdw2&jZ?j(6rwOiaw3^GzALy1HCkTzHI|KXOu!-FaW(##;AEl{G<;88KO5%KJ4Z z@cb}Ekr_5gMP0pIj3;Ga)^A@8F_6Mb&NYaOjf;zJW^exxcEkC$q@=NT`)tGwHZM!2 z2MVwv$CZkhaI%o8;jd|&~bTDa&~1tR_a1Cl}g-=JqW5L zHqFn}cWP-EogY5PTAo2Vn^%4P_>q}|BSM8Q2gFT(jauey%FZ}O*~U^jV&W@rVIf?a zS{II?cB`qWb(`-(qBLFA*_f)c@A>y}c6KK1CB?ZHODBnd(h#dJ^6xoWvYc@M*UKpkTZr2_gW^bqmtSboS*NXW1>PwA-&Zs?I7k5J<-&?EEGhD zB&{41JG!>sMjqL=mt)F+w68Ul0GDzoE5EmJM$l2E-r87Kdg5k z5*Rt!`aU5NVr6X&tB&@y!7(e&JACKwz3rzlXr=c#ds<#7CZM5XAYO~R7o(2hjgqzu zkz4uAI+~iJ&F=OHsf*)WRN`LLI7G?%ND11%R6x178t$*)nYDQA#^j7a1zevfVIzyI zFlx#X$amm9UoWW$Q4$Ee@TT{y0xvHwg5GcES-BuPuMQ}g zQdHwRM@J>&dvGvaT_d6M>m~uErV~fn+%Kb|NFwC!Q_Gb6WMOb8P14%S znhmr@2#Q+&@g%H%FyUrd{-93ziEmMTVp0+Z?;8Sq{QIe&#=j}A^8t$R_ZZl6*w1F7 zIV>yBXqg1P^9*?`km{mBK}Pm2(!JyS=pmw_?dZWobmhC>rHZujmWg~l6b~C>&;}=y z@3%`RUfTLtoI`;@aB*?bN&4hXle)UNI5;>UHm6(kEtNk%yv%!=i<^wikR)?cT952H zZC4y)>*v`84jIySgqpoF(~#TTnY;)F5-a~ zXRY4*i3Ov$w$MbNZO}@1w7M+6g#79Rv0oTPl}E~1>B_dSI9AK?W15Hz})4@*}INb`LkcY;A5{efax-C0pRxZrI+2mbuNxR&>JmYH6W!W>Iv}h3pQ~FT)7N zngkaXy?cu}L`56;EqW3Y69+RS^!wab2U8)M`COJ1i?cBzJ#sNvd9L&DU=j2-I%~+k zjGSK!|20iS^j-eEi_EhEzV4T_3#c>qL^; zr}*)OpWY^s3J8c@`&11rJ2^2C%4_?d^^z-GY)Q&B)z#YC+E)!C*SL|n7(G)|*x2ms zcRz$`V2)%dl<1ua*sAI3jsux)e5nXLT%Q2?!>Tlwmk*V@dCO&~58B;~|8HY7J!YTq z0CNGp^76QTz`oB!Jx=Q+S5H{A3P^BXG&G1>49?D)z6N1ySYw5ThKBI-_g{8t;)^8q zmzCnDr0ALZ71J9_L>I$j9G4mq1lmy0+?*kP=ej-%6YP}!!8wLOy zAVL#fy=p&MN&ES^0JolJj2?n#Bv;|J5O!~jmZy7M+NhDm!K&At6c0Hke43 z-(JK{2?4dp=CtSR(D3keY;2+c_b%Ekd3+NO5oY4YR_3#J@aTsnh6Wn_PwQ)HTy1TC z0%iP|o^E;^9vkcF?EEO|o`OOL%-cwS(8Na6ZikDj(uN2zm>IobK4WVVnw6EM%9p#jusU~NQQwJNM_`Y_IyLmkTQ_e(s2!!Y^N+6!Ntu@ z&SMmQ>Cx-=fsheIF(Rm8Hnf0kZ=Z;;Qv!txpr~VHlwMX=23xt!h1lsPH*JM?04Z$J z5%3o{#11qyE)vr5*x33WhrjH4=(wxC?*NE)baeFRh_Fn`RDke3=+UzRV~OLFXZ)&J z*IxvCzOlx|!y81Q*1uF_U4Z(hqoaF{NiaMxfLl7$fE`CJ)1sv<9dL(+CN4R2>w8va zUO~!1(|bjFs><*PLqwsQsEatF3CGAX?&1H@6J$}D3*A$POX zB>G{4SAkY;Uf##qS$aVJ!hlIl1gvs)b~eIlB-2<^vlDbEBuyS@W_~NY#{%A(gwPd1 z^{{eqD4k3aZgWkf3faB_lK_NUi`@hgF#743tfbcJ#X0p2wg9ig^_BBeh~xo@Asv*( zD_2+7SbC|88Q<;Qn0-7Dp8CLbLxY1)e>5_FB`TEjs-DmZr%3G9tp+!()Xsx3I7eIt2@h zB~-)&R<#Av#e9$`_F%tEPEJNdM5w(Hnx_r3p#<`F2j$(`+PdV@6dOy>O92v4MM=ro z-93Zv(Uo2b-Y4UQTEGzjpuJwPsCZd3PC;AR!_zJrpP4a1CecZFILviE>%vr2Q*(E7 z<3b|EeUBU}Oxi+#;Ks(rK#_vq1f4End{4z70tb8r>&n_%qe?S0grlP)PXW=$8{v}5 zN+%emt^vG(@uJTkBW|cDD?@+`N#KqN{JkS#VEJzw3ON6BdGQJFjT{nfuo$;klkwV^0>@6b=5KK+%5-QD;Ud?WZ=t zF+3K8nT0Vg+iRFJ0j>D>)YKp73n0`X%eeW#=3J}Wn>htE0E6wXNrOb%{r)xGRXPJH z0rR@!|EDm6n}dU&pPz`eUuBe}!g?eVpGv53LMnxbR2MdLWh4u1go%#8OHgNMuWz}o zbUs68)5uIuPM(A*%STiFbUPd!9R)Gc+1a_>epU=(o-rT|h>bcvS`Q@eM zWw0XV6EyBXMbzSW2Rh)zix*IgYDvo^C>W`XT0DlpmiV@A;B1tw*?Ktn5KIB6f1|cR zP~)NRf+Y%oSEAasKP-VrY;ar4hN&RdCd<-fvJ1uN=;=)>Oe6st0xwR&fR6r}Gx8|y z{Ijyw9QwdBqM+z#HFfovazVet3H`q*S*{%`l;q{_bb9pUA40h8F5FAvSUw5(T%fT^ z9JL01bj}Q94C4QA4^Z&6AYe3HLMBnsFFidNov;D--zE0`KHQ!)4Wi&(`amFcmCt!W zE@>C4*%erJuY)zB|9~U0F!)oTV-OBM8nrByzn!eDtiU^hQwCNq!e*lQen3D#_ikw^ z*RrvyLJSS;$G({RI!O>L@pMOE$3mkjt4=$5bHKTe$+z$rz&AVgzzltpdK2ff;S32> z?|tJy&IejROAsw+S1~b5R5?s>D(mXF!I0(B5Qco*>skd5t4NjGw4J7t+ObtjTf2+p zAH>N`z3N;<_E$$D<#K?XX4`xl7QAe2ZJ{=zK_oqxQ?&En z9}-2FKvB%e$$7a*NlA&?-;JS{`fo6loA|$^^k8eTnD5S?H6{cY7sm(&@jbb()v?3y#_+?wrsobbO1Jq#<>E@$m5>{tw&q_zK5uxp)xU}i^k@_%K(!x3JZv7lxt@F)9GS?{Gv8p zzBg1dp1*!zcS2f%D`pf-ga-R|$-!<`(bj_?qbnB>1Vazu*l{kBVnk|NtPH^Bd$dV( zXChlRY+NKnPv^IiF`SZ|Szq{J@QI4*ox~e{UPO{FkMw~PsgylqSm<;|>-qZIyvS_>I&rr`)G^rY z<3OkC-m+^@C*g%}Gr2?2?P6x6fo+S*xHE*9e2doNS@Ee+wTGD)qq34uy?@+yXYSd% zrygos`QkZ6jJlssuYjv4V7Ig6va-;HsQ0Q`A1}U-XXe=Y{$Tt3p4zsa-e;3ycUZ>~ zZ{MVGB~X+zJ<)h(We)|DOsxb23=&xJ%uUZ zL;FWAN_cD{z-AGo6>dur4GFkB{|z9oqI#u!jG<#^C^e>ie=O2yf*-$Sz{6J)2BWN#XfvZk&?^&`^nnPSIH`67p+i2x0YP$nL{w zq@dNHrY}PunCu_TtBQ)iw=4G0AMEQJJ>Zz`0|);r86Zgwl?YcEqCV-nEmraq`Nlb(<+6Z6ig^%Tm)06K?~7UcsFKf;f{V7nTaV5ON}m%@aop zR`(z0r%q0HrO_^q(f$AIsPDJJL5nz4G;;C=zY~|`p`I=%?HRGLv1Mgjzgp3@99)puy=OId6`m>F}-z3WNq=t+I+rZca|K+s~U{n|F72!3#&^Tq~0X3(EQdt3Z#JAXDR;E)Q62R%JKqbMfu zf=km`ByT&6UkT%zEiB9}1n)RSQU89N*GLf)vo=FZL}Zj;D{W$u`TV)8k56+&MMd?w z$rm1@#!8oEn99J%k8+l?r2Kaw4F=aI;NVf4LoTP_`TO_B^O!$cdU=y49lqCdi;0N| z3*WCK1y4;7%E><(gA>Sq#G0S?)_p@6w95bBC(vU1>8}=4OU#QZkF6=avIp4pG-I+b zLR6hFF|np*P$+)Z^-QVQW^JsG=FTO0Wr<-@L^t7>p}(`SS%&pPe}aYr#fKuDwXx@> ztTJ|@f1Zwa@?m&--VTV`adP_^Jg9p0>fCA;(GB#75Kl1~I~F+3q=?7rxPT+QgH7xk zH)?I36|$#GX$U9ArO3Bv$tEQ{PZJ$`hwtFvrNEfy0R{K(Suw%ke@=$68S~`9Gn7$` ghDiC}qvX9y76T@^xngvCIPyj)-BXt Date: Tue, 9 Feb 2021 11:45:45 +0000 Subject: [PATCH 23/32] :tada: per atom scores might be handy! --- fragmenstein/igor/_igor_utils_mixin.py | 55 ++++++++++++++++++++++---- 1 file changed, 48 insertions(+), 7 deletions(-) diff --git a/fragmenstein/igor/_igor_utils_mixin.py b/fragmenstein/igor/_igor_utils_mixin.py index dc0ae87..8962f6c 100644 --- a/fragmenstein/igor/_igor_utils_mixin.py +++ b/fragmenstein/igor/_igor_utils_mixin.py @@ -4,17 +4,11 @@ """ These are extra functionality for Igor """ -__author__ = "Matteo Ferla. [Github](https://github.com/matteoferla)" -__email__ = "matteo.ferla@gmail.com" -__date__ = "2020 A.D." -__license__ = "MIT" -__version__ = "0.4" -__citation__ = "" ######################################################################################################################## import requests, shutil, pyrosetta -from typing import Optional +from typing import Optional, Dict import pyrosetta @@ -37,6 +31,53 @@ def dock(self) -> pyrosetta.Pose: docking.apply(docked) return docked + def per_atom_scores(self, + pose: Optional[pyrosetta.Pose]=None, + target_res: Optional[int]=None, + scorefxn: Optional[pyrosetta.ScoreFunction]=None) -> Dict[str, Dict[str, float]]: + """ + Per atom scores are generally a bad idea as a score relative to something else is better. + So do treat with the appropriate caution. + NB. these scores will not sum to the that of the residue. + + Given a pose, a target_res and a scorefxn return a dict of per atom scores: + + * Lenard-Jones attraction 6-term + * Lenard-Jones repulsion 12-term + * Solvatation (zero) + * Electrostatic interactions + + :param pose: + :param target_res: + :param scorefxn: + :return: a dict of atom names to dict of 'lj_atr', 'lj_rep', 'fa_solv', 'fa_elec' to value + """ + # Defaults + if target_res is None: + target_res = self.ligand_residue[0] + if pose is None: + pose = self.pose + if scorefxn is None: + scorefxn = pyrosetta.get_fa_scorefxn() # unconstrained! + # Prep + score_types = ['lj_atr', 'lj_rep', 'fa_solv', 'fa_elec'] + residue = pose.residue(target_res) + scores = {residue.atom_name(i): {st: 0 for st in score_types} for i in range(1, residue.natoms() + 1)} + # Iterate per target residue's atom per all other residues' atoms + for i in range(1, residue.natoms() + 1): + iname = residue.atom_name(i) + for r in range(1, pose.total_residue() + 1): + other = pose.residue(r) + for o in range(1, other.natoms() + 1): + score = pyrosetta.toolbox.atom_pair_energy.etable_atom_pair_energies(residue, + i, + other, + o, + scorefxn) + for st, s in zip(score_types, score): + scores[iname][st] += s + return scores + @classmethod def download_map(cls, pdbcode: str, filename: str): """ From 2de3f1e334bb2833657a27d7c5bc4f38035e00e3 Mon Sep 17 00:00:00 2001 From: matteoferla Date: Wed, 10 Feb 2021 15:40:40 +0000 Subject: [PATCH 24/32] :fire: Spring clean! --- documentation/changelog_0.5.md | 2 +- documentation/mol_properties.md | 81 ++ fragmenstein/monster/__init__.py | 1116 +---------------- fragmenstein/monster/_base.py | 525 ++------ fragmenstein/monster/_blend_place.py | 690 ++++++++++ fragmenstein/monster/_collapse_ring.py | 295 +++-- fragmenstein/monster/_combine.py | 67 + fragmenstein/monster/_communal.py | 454 +++++++ fragmenstein/monster/_join_neighboring.py | 4 +- fragmenstein/monster/_merge.py | 248 ++++ fragmenstein/monster/_modification_logging.py | 28 + fragmenstein/monster/_place.py | 106 ++ .../{_utility_mixin.py => _utility.py} | 47 +- fragmenstein/monster/positional_mapping.py | 20 +- 14 files changed, 2035 insertions(+), 1648 deletions(-) create mode 100644 documentation/mol_properties.md create mode 100644 fragmenstein/monster/_blend_place.py create mode 100644 fragmenstein/monster/_combine.py create mode 100644 fragmenstein/monster/_communal.py create mode 100644 fragmenstein/monster/_merge.py create mode 100644 fragmenstein/monster/_modification_logging.py create mode 100644 fragmenstein/monster/_place.py rename fragmenstein/monster/{_utility_mixin.py => _utility.py} (92%) diff --git a/documentation/changelog_0.5.md b/documentation/changelog_0.5.md index 0c3ce94..cb6ab5b 100644 --- a/documentation/changelog_0.5.md +++ b/documentation/changelog_0.5.md @@ -38,7 +38,7 @@ are accepted. The names "merge" and "place" were ultra-confusingly ambiguous when it comes to the other methods, especially those of "place". * Now all the cases where hits are partially combined for placement purposes are called "blending" -The placement of the (distored) 3D final monster compound Victor is called "plonk". +The placement of the (distorted) 3D final monster compound Victor is called "plonk". * place and position are used synonymously * combine and merge are used synonymously diff --git a/documentation/mol_properties.md b/documentation/mol_properties.md new file mode 100644 index 0000000..055ae37 --- /dev/null +++ b/documentation/mol_properties.md @@ -0,0 +1,81 @@ +## Molecule properties + +> This file is for discussion of standards + +### SDFile +As of February 2021, Monster stores information in the Properties fields of the molecule. +These are not saved as MOL files, but are in SDF files. + + import tempfile + def _MolToSDBlock(mol:Chem.Mol): + with tempfile.NamedTemporaryFile(suffix='.sdf') as fh: + w = Chem.SDWriter(fh.name) + return w.GetText(mol) + Chem.MolToSDBlock = _MolToSDBlock + + mol = Chem.MolFromSmiles('*CCC') + mol.SetProp('_Name','Something') + mol.SetProp('_Hide','Nothing') + mol.SetProp('Show','Everything') + print('Mol file has no properties') + print(Chem.MolToMolBlock(mol)) + print('SD file has non-private properties') + print(Chem.MolToSDBlock(mol)) + +### Binary +A pickled Chem.Mol does not require sanitation, so for +A further issue is that pickled `Chem.Mol` objects lack properties, +hence the presence of `PropertyMol` workaround ([link](https://www.rdkit.org/docs/source/rdkit.Chem.PropertyMol.html)). +However, the properties assigned to a `Mol` before conversion to a `PropertyMol` are lost. +So a better solution is to use the `ToBinary` method of a mol instance. + + bstr = mol.ToBinary(propertyFlags=0b00010111) + with open('out.b', 'b') as fh: + fh.write(bstr) + +The binary string can be passed to a Chem.Mol: + + Chem.Mol(bstr) + +I could not find any documentation for the exact definitions of property flags argument, but empirical I have figure out: + + 0b00000001 -> mol + 0b00000010 -> atom + 0b00000100 -> bond + 0b00010001 -> inc. private + +I am guessing that it's not a full octet of bits, but simply 5 bits. `0b1000` is probably include calculated. +I'd say this is probably the best way to store them, albeit non-standard. + +### Custom +Alternative, one could have a custom extractor to save as JSON. + + + def get_properties(mol: Chem.Mol) -> Dict[str, Union[dict, List[dict]]]: + data = dict(mol= mol.GetPropsAsDict(includePrivate=True, includeComputed=False), + atoms=[atom.GetPropsAsDict(includePrivate=True, includeComputed=False) for atom in mol.GetAtoms()], + bonds=[bond.GetPropsAsDict(includePrivate=True, includeComputed=False) for bond in mol.GetBonds()]) + return data + + def set_properties(mol: Chem.Mol, data: Dict[str, dict]): + def _assign(obj, k, v): + if isinstance(v, str): + obj.SetProp(k, v) + elif isinstance(v, int): + obj.SetIntProp(k, v) + elif isinstance(v, bool): + obj.SetBoolProp(k, v) + elif isinstance(v, float): + obj.SetDoubleProp(k, v) + elif v is None: + pass + else: + obj.SetProp(k, str(v)) + for k,v in data['mol'].items(): + _assign(mol, k, v) + for atom, atomdata in zip(mol.GetAtoms(), data['atoms']): + for k,v in atomdata.items(): + _assign(atom, k, v) + for bond, bonddata in zip(mol.GetBonds(), data['bonds']): + for k, v in bonddata.items(): + _assign(bond, k, v) \ No newline at end of file diff --git a/fragmenstein/monster/__init__.py b/fragmenstein/monster/__init__.py index 90da25e..f53637a 100644 --- a/fragmenstein/monster/__init__.py +++ b/fragmenstein/monster/__init__.py @@ -1,42 +1,48 @@ ######################################################################################################################## -# TODO this file is over 1,000 lines long! __doc__ = \ """ This is Monster proper. and contains the class ``Monster``. - """ -__author__ = "Matteo Ferla. [Github](https://github.com/matteoferla)" -__email__ = "matteo.ferla@gmail.com" -__date__ = "2019 A.D." -__license__ = "MIT" -__version__ = "0.5" -__citation__ = "" +The inheritance is as follows: -######################################################################################################################## -from typing import Dict, Union, List, Optional, Tuple -from warnings import warn -import json +**_MonsterCombine** inherits: + +* ``_MonsterMerge`` (``_MonsterCommunal`` <- ``_MonsterTracker`` <- ``_MonsterBase``) +* ``_MonsterRing`` + +**_MonsterPlace** inherits: + +* ``_MonsterMerge`` (``_MonsterBlend`` < - ``_MonsterCommunal`` <- ``_MonsterTracker`` <- ``_MonsterBase``) + +**_MonsterUtils** inherits + +* ``_MonsterCommunal`` ( <- ``_MonsterTracker`` <- ``_MonsterBase``) +* ``GPM`` + +Where: + +**_MonsterBase** adds the cvars and the ``__init__`` and its dependent methods + +**_MonsterTracker** inherits ``_MonsterBase`` and adds just a method to better store modifications + +**_MonsterCommunal** inherits ``_MonsterTracker`` ( <- ``_MonsterBase``) -import numpy as np -from collections import defaultdict, Counter -from rdkit import Chem -from rdkit.Chem import AllChem, rdFMCS, rdMolAlign, rdmolops -from rdkit.Geometry.rdGeometry import Point3D +It adds methods for misc purposes beyond place/combine. +It is inherited by ``Monster`` only. + """ + +######################################################################################################################## -from ._utility_mixin import _MonsterUtil -from ._join_neighboring import _MonsterJoinNeighMixin -from ._collapse_ring import _MonsterRing -from .positional_mapping import GPM -from .unmerge_mapper import Unmerge -from .bond_provenance import BondProvenance -from ..rectifier import Rectifier -import itertools +from ._communal import _MonsterCommunal +from ._utility import _MonsterUtil # Adds extras, not called by place/combine +from ._combine import _MonsterCombine # inherits _MonsterCommunal adds the combine method +from ._place import _MonsterPlace # inherits _MonsterCommunal adds the combine method ################################################################## -class Monster(_MonsterUtil, _MonsterRing, GPM, _MonsterJoinNeighMixin): # Unmerge is called. Not inherited. +class Monster(_MonsterUtil, _MonsterPlace, _MonsterCombine): """ This creates a stitched together monster. For initilialisation for either placing or merging, it needs a list of hits (rdkit.Chem.Mol). @@ -67,1060 +73,4 @@ class Monster(_MonsterUtil, _MonsterRing, GPM, _MonsterJoinNeighMixin): # Unmer If an atom in a Chem.Mol object is provided via ``attachment`` argument and the molecule contains a dummy atom as defined in the ``dummy`` class variable. Namely element R in mol file or * in string is the default. """ - - # TODO move to base and move out all the methods. - def __init__(self, - hits: List[Chem.Mol], - debug_draw: bool = False, - average_position=False): - """ - Initialisation starts Monster, but it does not do any mergers or placements. - This is changed in revision 0.6 (previously `mol` was specified for the latter) - - :param hits: hits are a list of rdkit molecules - :param attachment: - :param debug_draw: - :param average_position: - """ - # starting attributes - # formerly this was present... but it does nothing. - # super().__init__() - # bar for self._debug_draw = _debug_draw from _MonsterRing it is empty. - # ==== hits =========================================== - # fix_hits: assert Chem.Mol, fix name if needed and store positions (see ``store_positions``) - self.hits = self.fix_hits(hits) # list of hits - # ==== other ========================================== - self._debug_draw = debug_draw # Jupyter notebook only. - self.average_position = average_position - # ==== To do be filled ================================ - # List[str] - self.unmatched = [] #: rejected hit names - # self.matched is dynamic. #: accepted hits - # Chem.Mol or List[Chem.Mol] - self.modifications = [] - self.initial_mol = None #: to be filled by place. The starting molecule (Chem.Mol). - self.attachment = None - # self.scaffold = None #: template which may have wrong elements in place, or - # self.mol_options = [] #: partial combined templates (merging_mode: partial) - self.mol_options = [] #: templates which may have wrong elements - self.chimera = None #: merger of hits but with atoms made to match the to-be-aligned mol - self.positioned_mol = None #: final molecule - - # TODO move these to own file - # ================================================================================================================== - - def place(self, - mol: Chem.Mol, - attachment: Optional[Chem.Mol] = None, - merging_mode: str = 'none_permissive'): - """ - Positioned a given mol based on the hits. (Main entrypoint) - accepts the argument `merging_mode`, by default it is "permissive_none", - which calls `.no_blending(broad=True)`, - but "off" (does nothing except fill the attribute ``initial_mol``), - "full" (`.full_blending()`), - "partial" (`.partial_blending()`) - and "none" (`.no_blending()`) - are accepted. - - :param mol: - :param attachment: - :param merging_mode: - :return: - """ - self.initial_mol, self.attachment = self._parse_mol_for_place(mol, attachment) - # Reset - self.unmatched = [] - self.mol_options = [] - # do calculations - if merging_mode == 'off': - pass - elif merging_mode == 'full': - self.full_blending() - elif merging_mode == 'partial': - self.partial_blending() - elif merging_mode == 'none_permissive' or merging_mode == 'permissive_none': - self.no_blending(broad=True) - elif merging_mode == 'none': - self.no_blending() - else: - valid_modes = ('full', 'partial', 'none', 'none_permissive', 'off') - raise ValueError( - f"Merging mode can only be {'| '.join(valid_modes)}, not '{merging_mode}'") - return self - - def place_smiles(self, - smiles: str, - attachment: Optional[Chem.Mol] = None): - mol = Chem.MolFromSmiles(smiles) - self.place(mol=mol, attachment=attachment) - return self - - def _parse_mol_for_place(self, - mol: Chem.Mol, - attachment: Optional[Chem.Mol] = None): - # ------------- store mol --------------------------------------- - if mol.HasSubstructMatch(self.dummy) and attachment: - pass - elif mol.HasSubstructMatch(self.dummy): - warn('No attachment atom provided but dummy atom present --- ignoring.') - attachment = None - elif attachment: - warn('Attachment atom provided but dummy atom not present --- ignoring.') - attachment = None - else: - attachment = None - return mol, attachment - - # TODO move these to own file - # ================================================================================================================== - - def merge(self, keep_all=True, collapse_rings=True, joining_cutoff: int = 5): - """ - Merge/links the hits. (Main entrypoint) - - :param keep_all: - :param collapse_rings: - :param joining_cutoff: - :return: - """ - # The following override class declared attributes. TODO declare them in __init__ - self.joining_cutoff = joining_cutoff - self.throw_on_discard = keep_all - # merge! - if collapse_rings: - col_hits = self.collapse_mols(self.hits) - self.modifications.extend(col_hits) - else: - col_hits = self.hits - self.scaffold = self.simply_merge_hits(col_hits) - self.modifications.append(Chem.Mol(self.scaffold)) # backup for debug - ## Discard can happen for other reasons than disconnect - if keep_all and len(self.unmatched): - raise ConnectionError(f'Could not combine with {self.unmatched} (>{self.joining_cutoff}') - # expand and fix - self.journal.debug(f'Merged') - if collapse_rings: - self.positioned_mol = self.expand_ring(self.scaffold) - # bonded_as_original=False no longer needed. - self.modifications.append(Chem.Mol(self.positioned_mol)) # backup for debug - self.journal.debug(f'Expanded') - self.rectify() - self.journal.debug(f'Rectified') - return self - - def rectify(self): - recto = Rectifier(self.positioned_mol) - try: - recto.fix() - except ConnectionError: - self.journal.critical(f'This really odd cornercase: Rectifier broke the mol.') - mol = self._emergency_joining(recto.mol) - recto = Rectifier(self.monster.positioned_mol) - recto.fix() - self.positioned_mol = recto.mol - self.modifications.extend(recto.modifications) # backup for debug - - # TODO move these to own file - # ================================================================================================================== - # common to move - - #simply_merge_hits, merge_pair, _pre_fragment_pairs, _recruit_team, _categorise, get_positional_mapping - - # ================================================================================================================== - # placement dependent methdos - - # @classmethod #why was this a classmethod - def full_blending(self) -> None: - """ - a single scaffold is made (except for ``.unmatched``) - """ - self.mol_options = [self.simply_merge_hits()] - self.scaffold = self.posthoc_refine(self.mol_options[0]) - self.chimera = self.make_chimera() - self.positioned_mol = self.place_from_map() - - def partial_blending(self) -> None: - """ - multiple possible scaffolds for placement and best is chosen - """ - self.mol_options = self.partially_blend_hits() # merger of hits - unrefined_scaffold, mode_index = self.pick_best() - used = self.scaffold.GetProp('_Name').split('-') - self.unmatched = [h.GetProp('_Name') for h in self.hits if h.GetProp('_Name') not in used] - self.scaffold = self.posthoc_refine(unrefined_scaffold) - self.chimera = self.make_chimera(mode_index) - self.positioned_mol = self.place_from_map() - - def no_blending(self, broad=False) -> None: - """ - no merging is done. The hits are mapped individually. Not great for small fragments. - """ - maps = {} - for template in self.hits: - if broad: - pair_atom_maps, _ = self.get_mcs_mappings(self.initial_mol, template) - maps[template.GetProp('_Name')] = pair_atom_maps - else: - pair_atom_maps_t = self._get_atom_maps(self.initial_mol, template, - atomCompare=rdFMCS.AtomCompare.CompareElements, - bondCompare=rdFMCS.BondCompare.CompareOrder, - ringMatchesRingOnly=True, - ringCompare=rdFMCS.RingCompare.PermissiveRingFusion, - matchChiralTag=True) - pair_atom_maps = [dict(p) for p in pair_atom_maps_t] - maps[template.GetProp('_Name')] = pair_atom_maps - um = Unmerge(followup=self.initial_mol, - mols=self.hits, - maps=maps, - no_discard=self.throw_on_discard, - _debug_draw=self._debug_draw) - self.scaffold = um.combined - self.mol_options = um.combined_alternatives - full_atom_map = um.combined_map - self.unmatched = [m.GetProp('_Name') for m in um.disregarded] - if self.throw_on_discard and len(self.unmatched): - raise ConnectionError(f'{self.unmatched} was rejected.') - self.chimera = um.combined_bonded - if self._debug_draw: - print('followup to scaffold', full_atom_map) - print('followup') - self.draw_nicely(self.initial_mol) - print('scaffold') - self.draw_nicely(self.scaffold) - placed = self.place_from_map(atom_map=full_atom_map) - self.positioned_mol = self.posthoc_refine(placed) - - # ========== Merging =============================================================================================== - - def merge_pair(self, scaffold: Chem.Mol, fragmentanda: Chem.Mol, mapping: Optional = None) -> Chem.Mol: - """ - To specify attachments use ``.merge``. - To understand what is going on see ``.categorise`` - - :param scaffold: mol to be added to. - :param fragmentanda: mol to be fragmented - :param mapping: see ``get_positional_mapping``. Optional in _pre_fragment_pairs - :return: - """ - done_already = [] - if self._debug_draw: - print('Scaffold') - self.draw_nicely(scaffold) - print('To be added') - self.draw_nicely(fragmentanda) - fp = self._pre_fragment_pairs(scaffold, fragmentanda, mapping) - # confusingly these are hit indexed. - for anchor_index, attachment_details in fp.items(): - # anchor index is the fragment-to-added's internal atom that attaches - if anchor_index in done_already: - continue - # fix rings. - uniques = {atom.GetIdx() for atom in fragmentanda.GetAtoms() if - 'overlapping' not in atom.GetProp('_Category')} - team = self._recruit_team(fragmentanda, anchor_index, uniques) - other_attachments = list((team & set(fp.keys())) - {anchor_index}) - other_attachment_details = [] - for other in other_attachments: - other_attachment_details.append(fp[other]) - done_already.append(other) - scaffold = self._merge_part(scaffold, fragmentanda, - anchor_index=anchor_index, - attachment_details=attachment_details, - other_attachments=other_attachments, - other_attachment_details=other_attachment_details) - name_A = scaffold.GetProp('_Name') - name_B = fragmentanda.GetProp('_Name') - scaffold.SetProp('_Name', f'{name_A}-{name_B}') - if self._debug_draw: - print('Merged', scaffold.GetProp('_Name')) - self.draw_nicely(scaffold) - return scaffold - - # ================= Blend hits =================================================================================== - - def partially_blend_hits(self, hits: Optional[List[Chem.Mol]] = None) -> List[Chem.Mol]: - """ - This is the partial merge algorithm, wherein the hits are attempted to be combined. - If the combination is bad. It will not be combined. - Returning a list of possible options. - These will have the atoms changed too. - - :param hits: - :param distance: - :return: - """ - - if hits is None: - hits = sorted(self.hits, key=lambda h: h.GetNumAtoms(), reverse=True) - for hi, hit in enumerate(hits): - # fallback naming. - if not hit.HasProp('_Name') or hit.GetProp('_Name').strip() == '': - hit.SetProp('_Name', f'hit{hi}') - - ## a dodgy hit is a hit with inconsistent mapping bwteen three. - def get_dodgies(skippers): - dodgy = [] - for hit0, hit1, hit2 in itertools.combinations(hits, 3): - hn0 = hit0.GetProp('_Name') - hn1 = hit1.GetProp('_Name') - hn2 = hit2.GetProp('_Name') - if any([hit in skippers for hit in (hn0, hn1, hn2)]): - continue - for a, b in inter_mapping[(hn0, hn1)].items(): - if a in inter_mapping[(hn0, hn2)] and b in inter_mapping[(hn1, hn2)]: - if inter_mapping[(hn0, hn2)][a] != inter_mapping[(hn1, hn2)][b]: - # TODO: THIS IS A BAD OPTION: - # if all([m.GetAtomWithIdx(i).IsInRing() for m, i in ((hit0, a), - # (hit1, b), - # (hit2, inter_mapping[(hn0, hn2)][a]), - # (hit2, inter_mapping[(hn1, hn2)][b]))]): - # pass - # else: - dodgy.extend((hn0, hn1, hn2)) - d = Counter(dodgy).most_common() - if dodgy: - return get_dodgies(skippers=skippers + [d[0][0]]) - else: - return skippers - - inter_mapping = {} - for h1, h2 in itertools.combinations(hits, 2): - inter_mapping[(h1.GetProp('_Name'), h2.GetProp('_Name'))] = self.get_positional_mapping(h1, h2) - dodgy_names = get_dodgies([]) - if self._debug_draw: - print('******** These combine badly') - print(dodgy_names) - dodgies = [hit for hit in hits if hit.GetProp('_Name') in dodgy_names] - mergituri = [hit for hit in hits if hit.GetProp('_Name') not in dodgy_names] - merged = self.simply_merge_hits(mergituri) - dodgies += [hit for hit in hits if hit.GetProp('_Name') in self.unmatched] - self.unmatched = [] - combined_dodgies = [] - for h1, h2 in itertools.combinations(dodgies, 2): - h_alt = Chem.Mol(h1) - try: - combined_dodgies.append(self.merge_pair(h_alt, h2)) - except ConnectionError: - pass - combinations = [merged] + dodgies + combined_dodgies - # propagate alternatives - while self.propagate_alternatives(combinations) != 0: - pass - if self._debug_draw: - print('alternatives propagated') - return combinations - - def propagate_alternatives(self, fewer): - pt = Chem.GetPeriodicTable() - new = 0 - for template in list(fewer): - for i, atom in enumerate(template.GetAtoms()): - if atom.HasProp('_AltSymbol'): - alt = Chem.Mol(template) - aa = alt.GetAtomWithIdx(i) - aa.SetAtomicNum(pt.GetAtomicNumber(atom.GetProp('_AltSymbol'))) - aa.ClearProp('_AltSymbol') - atom.ClearProp('_AltSymbol') - fewer.append(alt) - new += 1 - return new - - def pick_best(self) -> Tuple[Chem.Mol, int]: - """ - Method for partial merging for placement - - :return: unrefined_scaffold, mode_index - """ - if len(self.mol_options) == 1: - return self.mol_options[0], 0 - elif len(self.mol_options) == 0: - raise ValueError('No scaffolds made?!') - else: - mapx = {} #: dictionary of key mol name and value tuple of maps and mode - - def template_sorter(t: List[Chem.Mol]) -> float: - # key for sorting. requires outer scope ``maps``. - n_atoms = len(mapx[t.GetProp('_Name')][0]) - mode = mapx[t.GetProp('_Name')][1] - mode_i = self.matching_modes.index(mode) - return - n_atoms - mode_i / 10 - - ## get data - # presort as this is expensive. - for template in self.mol_options: - # _get_atom_maps returns a list of alternative mappings which are lists of template to initail mol - atom_maps = self._get_atom_maps(template, self.initial_mol, - atomCompare=rdFMCS.AtomCompare.CompareElements, - bondCompare=rdFMCS.BondCompare.CompareOrder, - ringMatchesRingOnly=True, - ringCompare=rdFMCS.RingCompare.PermissiveRingFusion, - matchChiralTag=False) - mapx[template.GetProp('_Name')] = (atom_maps, self.matching_modes[-1]) - # search properly only top 3. - self.mol_options = sorted(self.mol_options, key=template_sorter) - for template in self.mol_options[:3]: - atom_map, mode = self.get_mcs_mapping(template, self.initial_mol) - # get_mcs_mapping returns a dict going from template index to initial. - mapx[template.GetProp('_Name')] = (atom_map, mode) - if self._debug_draw: - print( - f"With {template.GetProp('_Name')}, {len(atom_map)} atoms map using mode {self.matching_modes.index(mode)}") - ## pick best template - self.mol_options = sorted(self.mol_options, key=template_sorter) - ## Check if missing atoms can be explained by a different one with no overlap - best = self.mol_options[0] - ## Fuse overlaps - # best_map = maps[best.GetProp('_Name')][0] - # full = set(range(self.initial_mol.GetNumAtoms())) - # present = set(best_map.values()) - # missing = full - present - # for other in self.mol_options: - # other_map = maps[other.GetProp('_Name')][0] - # found = set(other_map.values()) - # if len(found) > 6 and len(present & found) == 0: # more than just a ring and no overlap - # fusion = self._fuse(best, other, best_map, other_map) - return best, self.matching_modes.index(mapx[best.GetProp('_Name')][1]) - - # def _fuse(self, mol_A: Chem.Mol, mol_B: Chem.Mol, map_A: Dict[int, int], map_B: Dict[int, int]) -> Chem.Mol: - # """ - # Merge two compounds... but that are unlinked, using the followup as a guide. - # Conceptually different but overlapping is join_neighboring_mols - # - # :param mol_A: - # :param mol_B: - # :param map_A: - # :param map_B: - # :return: - # """ - # # No longer needed. - # fusion = Chem.RwMol(Chem.CombineMols(mol_A, mol_B)) - # t = mol_A.GetNumAtoms() - # new_map_B = {k+t: v for k, v in map_B.items()} - # full = set(range(self.initial_mol.GetNumAtoms())) - # present_A = set(map_A.values()) - # present_B = set(map_B.values()) - # - # def find_route(n): - # if n in present_A: - # return None - # elif n in present_B: - # return n - # else: - # path_raw = {m: find_route(m) for m in self.initial_mol.GetAtomWithIdx(n).GetNeighbors()} - # path = {i: path_raw[i] for i in path_raw if path_raw[i] is not None} - # if len(path) == 0: - # return None - # else: - # return {n: path} - - def simply_merge_hits(self, hits: Optional[List[Chem.Mol]] = None) -> Chem.Mol: - """ - Recursively stick the hits together and average the positions. - This is the monster of automerging, full-merging mapping and partial merging mapping. - The latter however uses `partially_blend_hits` first. - The hits are not ring-collapsed and -expanded herein. - - :param hits: optionally give a hit list, else uses the attribute ``.hits``. - :return: the rdkit.Chem.Mol object that will fill ``.scaffold`` - """ - if hits is None: - hits = sorted(self.hits, key=lambda h: h.GetNumAtoms(), reverse=True) - for hit in hits: - BondProvenance.set_all_bonds(hit, 'original') - if self._debug_draw: - print('Merging: ', [hit.GetProp('_Name') for hit in hits]) - scaffold = Chem.Mol(hits[0]) - # first try - save_for_later = [] - for fragmentanda in hits[1:]: - try: - scaffold = self.merge_pair(scaffold, fragmentanda) - except ConnectionError: - save_for_later.append(fragmentanda) - # second try - join_later = [] - for fragmentanda in save_for_later: - try: - scaffold = self.merge_pair(scaffold, fragmentanda) - except ConnectionError: - join_later.append(fragmentanda) - # join (last ditch) - for fragmentanda in join_later: - try: - scaffold = self.join_neighboring_mols(scaffold, fragmentanda) - except ConnectionError: - self.unmatched.append(fragmentanda.GetProp("_Name")) - msg = f'Hit {fragmentanda.GetProp("_Name")} has no connections! Skipping!' - if self.throw_on_discard: - raise ConnectionError(msg) - else: - warn(msg) - return scaffold - - def _prevent_two_bonds_on_dummy(self, mol: Chem.RWMol): - """ - The case '*(C)C' is seen legitimately in some warheads... but in most cases these are not. - :param mol: - :return: - """ - for atom in mol.GetAtoms(): - if atom.GetSymbol() != '*': - pass - elif len(atom.GetNeighbors()) <= 1: - pass - elif len(atom.GetNeighbors()) >= 2: - self.journal.info(f'Dummy atom (idx={atom.GetIdx()}) has {len(atom.GetNeighbors())} bonds!') - neighs = atom.GetNeighbors() - first = neighs[0] - for second in neighs[1:]: - rejected = second.GetIdx() # that will be absorbed (deleted) - keeper = first.GetIdx() # that absorbs (kept) - self._copy_bonding(mol, keeper, rejected) - self._mark_for_deletion(mol, rejected) - self._delete_marked(mol) - return self._prevent_two_bonds_on_dummy(mol) - - # ================= Chimera ======================================================================================== - - def make_chimera(self, min_mode_index=0) -> Chem.Mol: - """ - This is to avoid extreme corner corner cases. - E.g. here the MCS is ringMatchesRingOnly=True and AtomCompare.CompareAny, - while for the positioning this is not the case. - - :return: - """ - # get the matches - atom_map, mode = self.get_mcs_mapping(self.scaffold, self.initial_mol, min_mode_index=min_mode_index) - follow = {**{k: str(v) for k, v in mode.items()}, 'N_atoms': len(atom_map)} - self.journal.debug(f"scaffold-followup: {follow}") - if self._debug_draw: - self.draw_nicely(self.initial_mol, highlightAtoms=atom_map.values()) - # make the scaffold more like the followup to avoid weird matches. - chimera = Chem.RWMol(self.scaffold) - for scaff_ai, follow_ai in atom_map.items(): - if self.scaffold.GetAtomWithIdx(scaff_ai).GetSymbol() != self.initial_mol.GetAtomWithIdx( - follow_ai).GetSymbol(): - v = {'F': 1, 'Br': 1, 'Cl': 1, 'H': 1, 'B': 3, 'C': 4, 'N': 3, 'O': 2, 'S': 2, 'Se': 2, 'P': 6} - wanted = self.initial_mol.GetAtomWithIdx(follow_ai) - if wanted.GetSymbol() == '*': # all good then! - continue - owned = self.scaffold.GetAtomWithIdx(scaff_ai) - diff_valance = owned.GetExplicitValence() - v[wanted.GetSymbol()] - if wanted.GetSymbol() in ('F', 'Br', 'Cl', 'C', 'H') and diff_valance > 0: - continue # cannot change this. - elif owned.GetExplicitValence() > 4 and wanted.GetSymbol() not in ('P',): - continue - else: - newatom = Chem.Atom(wanted) - stdev = chimera.GetAtomWithIdx(scaff_ai).GetDoubleProp('_Stdev') - newatom.SetDoubleProp('_Stdev', stdev) - origin = chimera.GetAtomWithIdx(scaff_ai).GetProp('_Origin') - newatom.SetProp('_Origin', origin) - chimera.ReplaceAtom(scaff_ai, newatom) - if diff_valance > 0: - chimera.GetAtomWithIdx(scaff_ai).SetFormalCharge(diff_valance) - try: - chimera.UpdatePropertyCache() - except Chem.AtomValenceException as err: - warn('Valance issue' + str(err)) - return chimera - - def place_from_map(self, mol: Chem.Mol = None, atom_map: Optional[Dict] = None) -> Chem.Mol: - """ - This method places the atoms with known mapping - and places the 'uniques' (novel) via an aligned mol (the 'sextant') - This sextant business is a workaround for the fact that only minimised molecules can use the partial - embedding function of RDKit. - - :param mol: - :param atom_map: something that get_mcs_mapping would return. - :return: - """ - # Note none of this malarkey: AllChem.MMFFOptimizeMolecule(ref) - # prealignment - if mol is None: - mol = self.initial_mol - sextant = Chem.Mol(mol) - Chem.SanitizeMol(sextant) - AllChem.EmbedMolecule(sextant) - AllChem.MMFFOptimizeMolecule(sextant) - ###################################################### - # mapping retrieval and sextant alignment - # variables: atom_map sextant -> uniques - if atom_map is None: - atom_map, mode = self.get_mcs_mapping(mol, self.chimera) - msg = {**{k: str(v) for k, v in mode.items()}, 'N_atoms': len(atom_map)} - self.journal.debug(f"followup-chimera' = {msg}") - rdMolAlign.AlignMol(sextant, self.chimera, atomMap=list(atom_map.items()), maxIters=500) - # debug print - if self._debug_draw: - self.draw_nicely(mol, highlightAtoms=dict(atom_map).keys()) - self.draw_nicely(self.chimera, highlightAtoms=dict(atom_map).values()) - # place atoms that have a known location - putty = Chem.Mol(sextant) - pconf = putty.GetConformer() - chimera_conf = self.chimera.GetConformer() - uniques = set() # unique atoms in followup - for i in range(putty.GetNumAtoms()): - p_atom = putty.GetAtomWithIdx(i) - p_atom.SetDoubleProp('_Stdev', 0.) - p_atom.SetProp('_Origin', 'none') - if i in atom_map: - ci = atom_map[i] - c_atom = self.chimera.GetAtomWithIdx(ci) - if c_atom.HasProp('_Stdev'): - stdev = c_atom.GetDoubleProp('_Stdev') - origin = c_atom.GetAtomWithIdx(ci).GetProp('_Origin') - p_atom.SetDoubleProp('_Stdev', stdev) - p_atom.SetProp('_Origin', origin) - pconf.SetAtomPosition(i, chimera_conf.GetAtomPosition(ci)) - else: - uniques.add(i) - ###################################################### - # I be using a sextant for dead reckoning! - # variables: sextant unique team - categories = self._categorise(sextant, uniques) - # debug print - if self._debug_draw: - print('internal', categories['internals']) - done_already = [] # multi-attachment issue. - for unique_idx in categories['pairs']: # attachment unique indices - # check the index was not done already (by virtue of a second attachment) - if unique_idx in done_already: - continue - # get other attachments if any. - team = self._recruit_team(mol, unique_idx, categories['uniques']) - other_attachments = (team & set(categories['pairs'].keys())) - {unique_idx} - sights = set() # atoms to align against - for att_idx in [unique_idx] + list(other_attachments): - for pd in categories['pairs'][att_idx]: - first_sight = pd['idx'] - sights.add((first_sight, first_sight)) - neighs = [i.GetIdx() for i in sextant.GetAtomWithIdx(first_sight).GetNeighbors() if - i.GetIdx() not in uniques] - for n in neighs: - sights.add((n, n)) - if self.attachment and list(categories['dummies']) and list(categories['dummies'])[0] in team: - r = list(categories['dummies'])[0] - pconf.SetAtomPosition(r, self.attachment.GetConformer().GetAtomPosition(0)) - sights.add((r, r)) - rdMolAlign.AlignMol(sextant, putty, atomMap=list(sights), maxIters=500) - sconf = sextant.GetConformer() - # debug print - if self._debug_draw: - print(f'alignment atoms for {unique_idx} ({team}): {sights}') - self.draw_nicely(sextant, highlightAtoms=[a for a, b in sights]) - # copy position over - for atom_idx in team: - pconf.SetAtomPosition(atom_idx, sconf.GetAtomPosition(atom_idx)) - # the ring problem does not apply here but would result in rejiggling atoms. - - for other in other_attachments: - done_already.append(other) - # complete - AllChem.SanitizeMol(putty) - return putty # positioned_mol - - def _merge_part(self, scaffold: Chem.Mol, fragmentanda: Chem.Mol, anchor_index: int, - attachment_details: List[Dict], - other_attachments: List[int], - other_attachment_details: List[List[Dict]]) -> Chem.Mol: - """ - This does the messy work for merge_pair. - - :param scaffold: the Chem.Mol molecule onto whose copy the fragmentanda Chem.Mol gets added - :param fragmentanda: The other Chem.Mol molecule - :param anchor_index: the fragment-to-added's internal atom that attaches (hit indexed) - :param attachment_details: see `_pre_fragment_pairs` or example below fo an entry - :type attachment_details: List[Dict] - :param other_attachments: - :param other_attachment_details: - :return: a new Chem.Mol molecule - - Details object example: - - [{'idx': 5, - 'type': rdkit.Chem.rdchem.BondType.SINGLE, - 'idx_F': 5, # fragmentanda index - 'idx_S': 1 # scaffold index - }], ...} - """ - # get bit to add. - bonds_to_frag = [] - for detail in attachment_details: - attachment_index = detail['idx_F'] # fragmentanda attachment_index - bonds_to_frag += [fragmentanda.GetBondBetweenAtoms(anchor_index, attachment_index).GetIdx()] - bonds_to_frag += [fragmentanda.GetBondBetweenAtoms(oi, oad[0]['idx_F']).GetIdx() for oi, oad in - zip(other_attachments, other_attachment_details)] - if self._debug_draw and other_attachments: - print('ring!', other_attachments) - print('ring!', other_attachment_details) - f = Chem.FragmentOnBonds(fragmentanda, - bonds_to_frag, - addDummies=False) - frag_split = [] - fragmols = Chem.GetMolFrags(f, asMols=True, fragsMolAtomMapping=frag_split, sanitizeFrags=False) - if self._debug_draw: - print('Fragment splits') - print(frag_split) - # Get the fragment of interest. - ii = 0 - for mol_N, indices in enumerate(frag_split): - if anchor_index in indices: - break - ii += len(indices) - else: - raise Exception - frag = fragmols[mol_N] - frag_anchor_index = indices.index(anchor_index) - # pre-emptively fix atom ori_i - # offset collapsed to avoid clashes. - self.offset(frag) - # Experimental code. - # TODO: finish! - # frag_atom = frag.GetAtomWithIdx(frag_anchor_index) - # old2future = {atom.GetIntProp('_ori_i'): atom.GetIdx() + scaffold.GetNumAtoms() for atom in frag.GetAtoms()} - # del old2future[-1] # does nothing but nice to double tap - # if frag_atom.GetIntProp('_ori_i') == -1: #damn. - # for absent in self._get_mystery_ori_i(frag): - # old2future[absent] = scaffold_attachment_index - # self._renumber_original_indices(frag, old2future) - if self._debug_draw: - print('Fragment to add') - self.draw_nicely(frag) - combo = Chem.RWMol(rdmolops.CombineMols(scaffold, frag)) - scaffold_anchor_index = frag_anchor_index + scaffold.GetNumAtoms() - if self._debug_draw: - print('Pre-merger') - print(scaffold_anchor_index, attachment_details, anchor_index, scaffold.GetNumAtoms()) - self.draw_nicely(combo) - for detail in attachment_details: - # scaffold_anchor_index : atom index in scaffold that needs to be added to scaffold_attachment_index - # but was originally attached to attachment_index in fragmentanda. - # the latter is not kept. - attachment_index = detail['idx_F'] # fragmentanda attachment_index - scaffold_attachment_index = detail['idx_S'] # scaffold attachment index - bond_type = detail['type'] - combo.AddBond(scaffold_anchor_index, scaffold_attachment_index, bond_type) - new_bond = combo.GetBondBetweenAtoms(scaffold_anchor_index, scaffold_attachment_index) - # BondProvenance.set_bond(new_bond, '???') - # self.transfer_ring_data(fragmentanda.GetAtomWithIdx(attachment_index), - # combo.GetAtomWithIdx(scaffold_anchor_index)) - for oi, oad in zip(other_attachments, other_attachment_details): - bond_type = oad[0]['type'] - scaffold_attachment_index = oad[0]['idx_S'] - scaffold_anchor_index = indices.index(oi) + scaffold.GetNumAtoms() - combo.AddBond(scaffold_anchor_index, scaffold_attachment_index, bond_type) - new_bond = combo.GetBondBetweenAtoms(scaffold_anchor_index, scaffold_attachment_index) - # BondProvenance.set_bond(new_bond, '???') - if self._debug_draw: - print( - f"Added additional {bond_type.name} bond between {scaffold_attachment_index} and {scaffold_anchor_index} " + \ - f"(formerly {indices.index(oi)})") - Chem.SanitizeMol(combo, - sanitizeOps=Chem.rdmolops.SanitizeFlags.SANITIZE_ADJUSTHS + - Chem.rdmolops.SanitizeFlags.SANITIZE_SETAROMATICITY, - catchErrors=True) - if self._debug_draw: - print('Merged') - self.draw_nicely(combo) - self._prevent_two_bonds_on_dummy(combo) - scaffold = combo.GetMol() - return scaffold - - def transfer_ring_data(self, donor: Chem.Atom, acceptor: Chem.Atom): - """ - Transfer the info if a ringcore atom. - - :param donor: - :param acceptor: - :return: - """ - # if donor.GetIntProp('_ori_i') == -1: - # data = donor - pass - - def _pre_fragment_pairs(self, scaffold: Chem.Mol, fragmentanda: Chem.Mol, A2B_mapping: Optional = None) \ - -> Dict[int, List[Dict]]: - """ - Returns - - {4: [{'idx': 5, - 'type': rdkit.Chem.rdchem.BondType.SINGLE, - 'idx_F': 5, - 'idx_S': 1}], ...} - - which is slight more than {5: [{'idx': 4, 'type': rdkit.Chem.rdchem.BondType.SINGLE}], ... from categories - - idx_F: fragmentanda index - idx_S: scaffold index - - required for self.merge, the key is the index of anchoring atom. - - Calls get_positional_mapping and _categorise. - - :param scaffold: mol to be added to. - :param fragmentanda: mol to be fragmented - :param A2B_mapping: see ``get_positional_mapping`` - :return: - """ - # get A2B mapping - if A2B_mapping is None: - A2B_mapping = self.get_positional_mapping(scaffold, fragmentanda) - get_key = lambda d, v: list(d.keys())[list(d.values()).index(v)] - if len(A2B_mapping) == 0: - raise ConnectionError('No overlap!') - # store alternative atom symbols. - for si, fi in A2B_mapping.items(): - sa = scaffold.GetAtomWithIdx(si) - sn = sa.GetSymbol() - fn = fragmentanda.GetAtomWithIdx(fi).GetSymbol() - if sn != fn: - sa.SetProp('_AltSymbol', fn) - # prepare. - uniques = set(range(fragmentanda.GetNumAtoms())) - set(A2B_mapping.values()) - categories = self._categorise(fragmentanda, uniques) - pairs = categories['pairs'] - for p in pairs: # pairs:Dict[List[Dict]] - for pp in pairs[p]: - pp['idx_F'] = pp['idx'] # less ambiguous: fragmentanda index - pp['idx_S'] = get_key(A2B_mapping, pp['idx']) # scaffold index - return pairs - - def _categorise(self, mol: Chem.Mol, uniques: set) -> Dict[str, Union[set, Dict]]: - """ - What do the novel atoms do in terms of connectivity. - Complicated dict output (called ``categories`` in the methods). Really ought to be SetProp of the atoms. - - * ``uniques`` are set of atoms to classify on - * ``internals`` are unique atoms that are connected solely to unique atoms - * ``attachments`` are non-unique atoms to which a unique atom connects - * ``pairs`` is a dict of unique atom idx --> dict of ``idx`` --> attachment idx and ``type`` bond type. - - :param mol: molecule to describe - :param uniques: set of indices that are new to this molecule - :return: - """ - # - pairs = {} - internals = set() - attachments = set() - dummies = set() - for i in uniques: # novel atoms - unique_atom = mol.GetAtomWithIdx(i) - if unique_atom.GetSymbol() == self.dummy_symbol: - dummies.add(i) - neighbours = {n.GetIdx() for n in unique_atom.GetNeighbors()} - if len(neighbours - uniques) == 0: # unlessone of the connections is not unique. - internals.add(i) - else: - i_attached = neighbours - uniques - attachments |= i_attached - pairs[i] = [{'idx': j, - 'type': mol.GetBondBetweenAtoms(i, j).GetBondType()} for j in i_attached] - anchors = uniques - internals - # store for safekeeping - for atom in mol.GetAtoms(): - i = atom.GetIdx() - if i in internals: # novel and not connected - atom.SetProp('_Category', 'internal') - elif i in attachments: # not-novel but connected - atom.SetProp('_Category', 'overlapping-attachment') - elif i in pairs: # dict not set tho - atom.SetProp('_Category', 'internal-attachment') - else: # overlapping - atom.SetProp('_Category', 'overlapping') - if self._debug_draw: - high = list(internals) + list(attachments) + list(anchors) - color = {**{i: (0, 0.8, 0) for i in internals}, - **{i: (0, 0, 0.8) for i in attachments}, - **{i: (0.8, 0, 0.8) for i in anchors}} - print('Purple: anchor atoms, Blue: attachments, Green: internals') - self.draw_nicely(mol, highlightAtoms=high, highlightAtomColors=color) - print({atom.GetIdx(): atom.GetProp('_Category') for atom in mol.GetAtoms()}) - return dict(uniques=uniques, - internals=internals, - attachments=attachments, - pairs=pairs, - dummies=dummies - ) - - # ========= Other ================================================================================================== - - def fix_hits(self, hits: List[Chem.Mol]) -> List[Chem.Mol]: - """ - Adds the ``_Name`` Prop if needed - asserts everything is a Chem.Mol - calls ``store_positions`` - :param hits: - :return: - """ - for hi, hit in enumerate(hits): - if isinstance(hit, str): - warn(f'Hit {hi} is a string ({hit}). This route is not the intended way. Trying to read it.') - if '.mol' in hit or '.mdf' in hit: - hits[hi] = Chem.MolFromMolFile(hit) - elif '.pdb' in hit: - hits[hi] = Chem.MolFromPDBFile(hit) - else: - raise ValueError(f'Hit {hit} is not a Mol file.') - elif isinstance(hit, Chem.Mol): - pass - else: - raise ValueError(f'Hit has to be a Chem.Mol! not {type(hit)}') - # fallback naming. - if not hit.HasProp('_Name') or hit.GetProp('_Name').strip() == '': - hit.SetProp('_Name', f'hit{hi}') - # ====== IMPORTANT ========== - self.store_positions(hit) - return hits - - def posthoc_refine(self, scaffold, indices: Optional[List[int]] = None) -> Chem.Mol: - """ - Averages the overlapping atoms. - - :param scaffold: - :return: - """ - if indices is None: - indices = list(range(scaffold.GetNumAtoms())) - refined = Chem.RWMol(scaffold) - refconf = refined.GetConformer() - positions = defaultdict(list) # coordinates - equivalence = defaultdict(list) # atom indices of hits. - for h in self.hits: - if h.GetProp('_Name') in self.unmatched: - continue - hc = h.GetConformer() - for k, v in self.get_positional_mapping(scaffold, h).items(): - positions[k].append([hc.GetAtomPosition(v).x, hc.GetAtomPosition(v).y, hc.GetAtomPosition(v).z]) - equivalence[k].append(f'{h.GetProp("_Name")}.{v}') - for i in range(scaffold.GetNumAtoms()): - if i not in indices: - continue - elif len(positions[i]) == 0: - refined.GetAtomWithIdx(i).SetDoubleProp('_Stdev', 0.) - refined.GetAtomWithIdx(i).SetDoubleProp('_Max', 0.) - refined.GetAtomWithIdx(i).SetProp('_Origin', 'none') - # warn(f'Atom {i} {scaffold.GetAtomWithIdx(i).GetSymbol}/{refined.GetAtomWithIdx(i).GetSymbol} '+ \ - # 'in scaffold that has no positions.') - else: - p = np.mean(np.array(positions[i]), axis=0).astype(float) - # sd = np.mean(np.std(np.array(positions[i]), axis=0)).astype(float) - ds = [np.linalg.norm(p - pi) for pi in positions[i]] - sd = np.std(ds) - md = np.max(ds) - refined.GetAtomWithIdx(i).SetProp('_Origin', json.dumps(equivalence[i])) - refined.GetAtomWithIdx(i).SetDoubleProp('_Stdev', sd) - refined.GetAtomWithIdx(i).SetDoubleProp('_Max', md) - if self.average_position: - refconf.SetAtomPosition(i, Point3D(p[0], p[1], p[2])) - Chem.SanitizeMol(refined, - sanitizeOps=Chem.rdmolops.SanitizeFlags.SANITIZE_ADJUSTHS + - Chem.rdmolops.SanitizeFlags.SANITIZE_SETAROMATICITY, - catchErrors=True) - return refined - - def get_mcs_mappings(self, molA, molB, min_mode_index: int = 0) -> Tuple[List[Dict[int, int]], dict]: - """ - This is a weird method. It does a strict MCS match. - And then it uses laxer searches and finds the case where a lax search includes the strict search. - - :param molA: query molecule - :param molB: target/ref molecule - :param min_mode_index: the lowest index to try (opt. speed reasons) - :return: mappings and mode - """ - strict_settings = dict(atomCompare=rdFMCS.AtomCompare.CompareElements, - bondCompare=rdFMCS.BondCompare.CompareOrder, - ringMatchesRingOnly=True, - ringCompare=rdFMCS.RingCompare.PermissiveRingFusion, - matchChiralTag=True) - strict = self._get_atom_maps(molA, molB, **strict_settings) - for i, mode in enumerate(self.matching_modes): - if i < min_mode_index: - continue - if self._debug_draw: - print(f'Trying mode {mode}') - lax = self._get_atom_maps(molA, molB, **mode) - # remove the lax matches that disobey - neolax = [l for l in lax if any([len(set(s) - set(l)) == 0 for s in strict])] - if len(neolax) == 0: - continue - else: - return [dict(n) for n in neolax], mode - else: - # Then the strict will have to do. - return [dict(n) for n in strict], strict_settings # tuple to dict - # raise ValueError('This is chemically impossible: nothing matches in the MCS step ' +\ - # f'({len(self.matching_modes)} modes tried') - - def get_mcs_mapping(self, molA, molB, min_mode_index: int = 0) -> Tuple[Dict[int, int], dict]: - """ - This is a weird method. It does a strict MCS match. - And then it uses laxer searches and finds the case where a lax search includes the strict search. - - :param molA: query molecule - :param molB: target/ref molecule - :param min_mode_index: the lowest index to try (opt. speed reasons) - :return: mapping and mode - """ - ms, mode = self.get_mcs_mappings(molA, molB, min_mode_index) - return ms[0], mode - - def _get_atom_maps(self, molA, molB, **mode) -> List[List[Tuple[int, int]]]: - mcs = rdFMCS.FindMCS([molA, molB], **mode) - common = Chem.MolFromSmarts(mcs.smartsString) - matches = [] - # prevent a dummy to match a non-dummy, which can happen when the mode is super lax. - is_dummy = lambda mol, at: mol.GetAtomWithIdx(at).GetSymbol() == '*' - all_bar_dummy = lambda Aat, Bat: (is_dummy(molA, Aat) and is_dummy(molB, Bat)) or not ( - is_dummy(molA, Aat) or is_dummy(molB, Bat)) - for molA_match in molA.GetSubstructMatches(common, uniquify=False): - for molB_match in molB.GetSubstructMatches(common, uniquify=False): - matches.append([(molA_at, molB_at) for molA_at, molB_at in zip(molA_match, molB_match) if - all_bar_dummy(molA_at, molB_at)]) - # you can map two toluenes 4 ways, but two are repeats. - matches = set([tuple(sorted(m, key=lambda i: i[0])) for m in matches]) - return matches - - def _get_atom_map(self, molA, molB, **mode) -> List[Tuple[int, int]]: - return self._get_atom_maps(molA, molB, **mode)[0] - - def _recruit_team(self, mol: Chem.Mol, starting: int, uniques: set, team: Optional[set] = None) -> set: - if team is None: - team = set() - team.add(starting) - for atom in mol.GetAtomWithIdx(starting).GetNeighbors(): - i = atom.GetIdx() - if i in uniques and i not in team: - team = self._recruit_team(mol, i, uniques, team) - return team - - def pretweak(self) -> None: - """ - What if the fragments were prealigned slightly? Really bad things. - - :return: - """ - warn('This method is unreliable. Do not use it') - ref = self.hits[0] - for target in self.hits[1:]: - A2B = list(self.get_positional_mapping(target, ref, 0.5).items()) - if A2B: - rdMolAlign.AlignMol(target, ref, atomMap=A2B, maxIters=500) - else: - warn(f'No overlap? {A2B}') - - @property - def matched(self): - """ - This is the counter to unmatched. - It's dynamic as you never know... - - :return: - """ - return [h.GetProp('_Name') for h in self.hits if - h.GetProp('_Name') not in self.unmatched] + pass diff --git a/fragmenstein/monster/_base.py b/fragmenstein/monster/_base.py index 080ae22..6aa10e4 100644 --- a/fragmenstein/monster/_base.py +++ b/fragmenstein/monster/_base.py @@ -1,20 +1,34 @@ -import numpy as np -from rdkit import Chem -from rdkit.Chem import AllChem, rdFMCS, rdMolAlign, rdmolops -from rdkit.Geometry.rdGeometry import Point3D -from typing import Optional, Dict, List, Any, Tuple, Union -from .bond_provenance import BondProvenance +######################################################################################################################## +__doc__ = \ + """ +This is contains the class _MonsterBase to be inherited by _MonsterCommunal, then Monster + """ + +######################################################################################################################## + import logging +from typing import List +from rdkit import Chem +from rdkit.Chem import rdFMCS + +class _MonsterBase: + """ + _MonsterBase -> _MonsterTracker -> _MonsterCommunal + """ -class _MonsterBaseMixin: journal = logging.getLogger('Fragmenstein') + # overriding these seems insane. dummy_symbol = '*' dummy = Chem.MolFromSmiles(dummy_symbol) #: The virtual atom where the targets attaches + + # settings... cutoff = 2. joining_cutoff = 5. # how distant (in Å) is too much? - atoms_in_bridge_cutoff = 2 # how many bridge atoms can be deleted? (0 = preserves norbornane, 1 = preserves monsterantane) + atoms_in_bridge_cutoff = 2 + # atoms_in_bridge_cutoff: how many bridge atoms can be deleted? + # (0 = preserves norbornane, 1 = preserves adamantane) throw_on_discard = False matching_modes = [ dict(atomCompare=rdFMCS.AtomCompare.CompareAny, @@ -42,437 +56,84 @@ class _MonsterBaseMixin: ringCompare=rdFMCS.RingCompare.PermissiveRingFusion, ringMatchesRingOnly=True)] - # === Find closest ================================================================================================= - # dep methods: - - @staticmethod - def _closest__is_fullbonded(atom): - if atom.GetIsAromatic() and len(atom.GetNeighbors()) > 2: - return True - elif len(atom.GetNeighbors()) > 3: - return True - else: - return False - - @staticmethod - def _closest__is_ring_atom(atom): - if atom.GetIsAromatic(): - return True - elif atom.HasProp('_ori_i') and atom.GetIntProp('_ori_i') == -1: - if atom.HasProp('_bonds') and 'AROMATIC' in atom.GetProp('_bonds'): - return True # technically it could be non-aromatic (ring fusion). - else: - return False - else: - return False - - @staticmethod - def _closest__is_warhead_marked(atom): - return atom.HasProp('_Warhead') and atom.GetBoolProp('_Warhead') is True - - # func: https://stackoverflow.com/questions/41921255/staticmethod-object-is-not-callable - closeness_weights = [ - (_closest__is_warhead_marked.__func__, np.nan), - (_closest__is_fullbonded.__func__, 1.0), - (_closest__is_ring_atom.__func__, 0.5) - # is_triangle, 2.0 - ] - - def _find_closest(self, mol_A: Chem.Mol, mol_B: Chem.Mol) -> Tuple[Chem.RWMol, int, int, float]: - """ - first step in join_neighboring_mols - This is not to be confused with cls.find_closest_to_ligand - - :param mol_A: - :param mol_B: - :return: - """ - combo, candidates = self._find_all_closest(mol_A, mol_B) - return (combo, *candidates[0]) - - def _find_all_closest(self, mol_A: Chem.Mol, mol_B: Chem.Mol) -> Tuple[Chem.RWMol, List[Tuple[int, int, float]]]: - """ - See _find_closest - - :param mol_A: - :param mol_B: + # ------------------------------------------------------------------------------------------------------------------ + + def __init__(self, + hits: List[Chem.Mol], + debug_draw: bool = False, + average_position=False): + """ + Initialisation starts Monster, but it does not do any mergers or placements. + This is changed in revision 0.6 (previously `mol` was specified for the latter) + + :param hits: + :param debug_draw: + :param average_position: + """ + # ==== hits =========================================== + # fix_hits: assert Chem.Mol, fix name if needed and store positions (see ``store_positions``) + self.hits = self.fix_hits(hits) # list of hits + # ==== other ========================================== + self._debug_draw = debug_draw # Jupyter notebook only. + self.average_position = average_position + # ==== To do be filled ================================ + # List[str] + self.unmatched = [] #: rejected hit names + # self.matched is dynamic. #: accepted hits + # Chem.Mol or List[Chem.Mol] + self.modifications = {} + self.initial_mol = None #: to be filled by place. The starting molecule (Chem.Mol). + self.attachment = None + # self.scaffold = None #: template which may have wrong elements in place, or + # self.mol_options = [] #: partial combined templates (merging_mode: partial) + self.mol_options = [] #: templates which may have wrong elements + self.chimera = None #: merger of hits but with atoms made to match the to-be-aligned mol + self.positioned_mol = None #: final molecule + + def fix_hits(self, hits: List[Chem.Mol]) -> List[Chem.Mol]: + """ + Adds the ``_Name`` Prop if needed + asserts everything is a Chem.Mol + calls ``store_positions`` + :param hits: :return: """ - combo = Chem.RWMol(Chem.CombineMols(mol_A, mol_B)) - # ========= distance matrix pre-tweaks. - distance_matrix = self._get_distance_matrix(combo, mol_A, mol_B) - penalties = self._get_joining_penalties(combo, distance_matrix.shape) - # ========= get closest - pendist_matrix = penalties + distance_matrix - pendistance = np.nanmin(pendist_matrix) - if np.isnan(pendistance): - raise ConnectionError('This is impossible. Previous is absent??') - else: - candidates = [] - - def get_closest(pendistance): - p = np.where(pendist_matrix == pendistance) - anchor_A = int(p[0][0]) - anchor_B = int(p[1][0]) - distance = distance_matrix[anchor_A, anchor_B] - penalty = penalties[anchor_A, anchor_B] - self.journal.debug(f'Connecting {anchor_A} with {anchor_B}, {penalty} penalised distance of {distance}') - return anchor_A, anchor_B, distance - - anchor_A, anchor_B, distance = get_closest(pendistance) - candidates.append((anchor_A, anchor_B, distance)) - pendist_matrix[pendist_matrix > 1.] = np.nan - while pendistance < 1.: - pendist_matrix[[anchor_A, anchor_B], :] = np.nan - pendist_matrix[:, [anchor_A, anchor_B]] = np.nan - pendistance = np.nanmin(pendist_matrix) - if np.isnan(pendistance): - break + for hi, hit in enumerate(hits): + if isinstance(hit, str): + self.journal.warning(f'Hit {hi} is a string ({hit}).' + + 'This route is not the intended way. Trying to read it.') + if '.mol' in hit or '.mdf' in hit: + hits[hi] = Chem.MolFromMolFile(hit) + elif '.pdb' in hit: + hits[hi] = Chem.MolFromPDBFile(hit) else: - anchor_A, anchor_B, distance = get_closest(pendistance) - candidates.append((anchor_A, anchor_B, distance)) - return combo, candidates - - def _get_distance_matrix(self, combo: Chem.Mol, A: Union[Chem.Mol, np.ndarray], - B: Union[Chem.Mol, np.ndarray]) -> np.ndarray: - """ - Called by ``_find_closest`` and ``_determine_mergers_novel_ringcore_pair`` in collapse ring (for expansion). - - """ - # TODO move to base once made. - # input type - if isinstance(A, Chem.Mol): - mol_A = A - A_idxs = np.arange(mol_A.GetNumAtoms()) - else: - mol_A = None - A_idxs = np.array(A) - if isinstance(B, Chem.Mol): - mol_B = B - B_idxs = np.arange(mol_B.GetNumAtoms()) + mol_A.GetNumAtoms() - else: - mol_B = None - B_idxs = np.array(B) - # make matrix - distance_matrix = Chem.Get3DDistanceMatrix(combo) - length = combo.GetNumAtoms() - # nan fill the self values - self._nan_fill_submatrix(distance_matrix, A_idxs) - self._nan_fill_submatrix(distance_matrix, B_idxs) - return distance_matrix - - def _nan_fill_others(self, mol: Chem.Mol, distance_matrix: np.array, good_indices: List[int]): - """ - Nan fill the inidices that are not the good_indices. - :param mol: - :param distance_matrix: - :param good_indices: - :return: - """ - others = np.array(list(set(range(mol.GetNumAtoms())).difference(good_indices))) - distance_matrix[others, :] = np.nan - distance_matrix[:, others] = np.nan - - def _get_joining_penalties(self, combo: Chem.Mol, shape: Tuple[int, int]) -> np.ndarray: - """ - Called by ``_find_closest``. - THis is different from _get_merging_penalties - - :param combo: - :param shape: - :return: - """ - # penalise - penalties = np.zeros(shape) - for fun, weight in self.closeness_weights: - weigh_bool = np.array([fun(atom) for atom in combo.GetAtoms()]) - penalties[weigh_bool, :] += weight - penalties[:, weigh_bool] += weight - return penalties - - def _nan_fill_submatrix(self, matrix, indices): - """ - Given a square matrix, blank the self-submatrix of the group of indices - There is probably a better way to do this. - changed from _nan_submatrix as to nan is not a verb. - - :param matrix: - :param indices: - :return: - """ - dimension = matrix.shape[0] - bool_vector = np.zeros((dimension, 1)).astype(bool) - bool_vector[indices] = True - bool_matrix = np.tile(bool_vector, (1, dimension)) - logic = np.logical_and(bool_matrix, bool_matrix.transpose()) - matrix[logic] = np.nan - - # ============= Deletion =========================================================================================== - - def _mark_for_deletion(self, mol: Chem.Mol, i: int): - mol.GetAtomWithIdx(i).SetBoolProp('DELETE', True) - - def _delete_marked(self, mol: Chem.RWMol): - morituri = list(reversed(mol.GetAtomsMatchingQuery(Chem.rdqueries.HasPropQueryAtom('DELETE')))) - for atom in morituri: - mol.RemoveAtom(atom.GetIdx()) - - # ============= Other ============================================================================================== - - def _copy_bonding(self, mol, keeper_idx: int, reject_idx: int, force: Optional[bool] = None): - """ - formerly called `absorb`. Preps for absorbing. remove J separately. - So copy bonding from i to j. - - :param mol: - :param i: - :param j: - :return: - """ - self.journal.debug(f'Absorbing atom {keeper_idx} with {reject_idx}, force={force}') - keeper = mol.GetAtomWithIdx(keeper_idx) - reject = mol.GetAtomWithIdx(reject_idx) - # prevent confusion when it comes to triangles - vertex = self._get_triangle(reject, keeper) - if vertex: - mol.RemoveBond(reject_idx, vertex) - # deal with neighbours of reject atom - for neighbor in reject.GetNeighbors(): - # collect bonding details between neighbour of reject and reject itself - neigh_idx = neighbor.GetIdx() - old_bond = mol.GetBondBetweenAtoms(reject_idx, neigh_idx) - bt = old_bond.GetBondType() - # forcing? - if force is not None: - force_bond = bool(force) - elif old_bond.HasProp('_IsRingBond'): - # the ring needs to be force! - force_bond = True - else: - force_bond = False - # mol.RemoveBond(j, n) - if keeper_idx == neigh_idx: # the neighbour is the keeper - continue + raise ValueError(f'Hit {hit} is not a Mol file.') + elif isinstance(hit, Chem.Mol): + pass else: - # copy bond. The provenance should be 'other_novel' not the original vai - # provenance = BondProvenance.get_bond(old_bond) - if force_bond and mol.GetBondBetweenAtoms(keeper_idx, neigh_idx) is None: - self.journal.debug(f'Forcing bond between {keeper_idx} and {neigh_idx}') - self._add_bond_regardlessly(mol=mol, - first=keeper, - second=neighbor, - bond_type=bt, - provenance='other_novel' - ) - else: - self._add_bond_if_possible(mol=mol, - first=keeper, - second=neighbor, - provenance='other_novel') - - def _add_bond_regardlessly(self, mol, first: Chem.Atom, second: Chem.Atom, bond_type, provenance='other_novel'): - """ - This methods does no checking and operates dangerously! + raise ValueError(f'Hit has to be a Chem.Mol! not {type(hit)}') + # fallback naming. + if not hit.HasProp('_Name') or hit.GetProp('_Name').strip() == '': + hit.SetProp('_Name', f'hit{hi}') + # ====== IMPORTANT ========== + self.store_positions(hit) + return hits - :param mol: - :param first: - :param second: - :param bond_type: - :param provenance: - :return: - """ - first_idx = first.GetIdx() - second_idx = second.GetIdx() - # add if absent... (error prevention) - present_bond = mol.GetBondBetweenAtoms(first_idx, second_idx) - if present_bond is None: - mol.AddBond(first_idx, second_idx, bond_type) - new_bond = mol.GetBondBetweenAtoms(first_idx, second_idx) - BondProvenance.set_bond(new_bond, provenance) - - def _add_bond_if_possible(self, mol, first: Chem.Atom, second: Chem.Atom, provenance='other_novel'): + def store_positions(self, mol: Chem.Mol) -> Chem.Mol: """ - This method is used by _copy_bonding, but triggered when force=False + Saves positional data as _x, _y, _z and majorly ``_ori_i``, the original index. + The latter gets used by ``_get_new_index``. :param mol: - :param first: - :param second: - :param provenance: - :return: - """ - first_idx = first.GetIdx() - second_idx = second.GetIdx() - - def assess_atom(atom: Chem.Atom, bt: Chem.BondType) -> Tuple[bool, Chem.BondType]: - """ - True means add, False means delete - - :param atom: - :param bt: - :return: - """ - n_neigh = sum([self._is_count_valid(neigh) for neigh in atom.GetNeighbors()]) - if atom.GetAtomicNum() > 8: - return True, bt - elif atom.HasProp('DELETE'): # if it is to be deleted it should be fine. - return True, bt - elif n_neigh <= 2 and atom.GetIsAromatic(): - return True, Chem.BondType.SINGLE - elif n_neigh <= 3 and not atom.GetIsAromatic(): - return True, bt - else: - return False, bt # too bonded already! - - if self._is_would_be_triangle(first, second): - self.journal.debug(f'Bond between {first_idx} and {second_idx} would make a triangle, skipping') - return False - elif self._is_would_be_square(first, second): - self.journal.debug(f'Bond between {first_idx} and {second_idx} would make a square, skipping') - return False - elif self._is_connected_warhead(second, first): - self.journal.debug(f'Bond between {first_idx} and {second_idx} would break a warhead, skipping') - return False - else: - present_bond = mol.GetBondBetweenAtoms(first_idx, second_idx) - if second.HasProp('_ring_bond'): - bt = getattr(Chem.BondType, second.GetProp('_ring_bond')) - else: - bt = None - if present_bond is not None and bt is None: - self.journal.debug(f'Bond between {first_idx} and {second_idx} already exists') - pass # exists - elif present_bond is not None and present_bond.GetBondType() is None: - present_bond.SetBondType(Chem.BondType.SINGLE) - elif present_bond is not None and present_bond.GetBondType() is not None and bt.name == present_bond.GetBondType().name: - pass # exists and has correct bond - elif present_bond is not None: - present_bond.SetBondType(bt) - return True - else: - v, bt = assess_atom(first, bt) - w, bt = assess_atom(second, bt) - if v and w and bt is not None: - mol.AddBond(first_idx, j, bt) - new_bond = mol.GetBondBetweenAtoms(first_idx, second_idx) - BondProvenance.set_bond(new_bond, provenance) - return True - elif v and w: - mol.AddBond(first_idx, second_idx, Chem.BondType.SINGLE) - new_bond = mol.GetBondBetweenAtoms(first_idx, second_idx) - BondProvenance.set_bond(new_bond, provenance) - return True - else: - # len(Chem.GetMolFrags(mol, sanitizeFrags=False)) ought to be checked. - # however, join_neighboring gets called by emergency bonding so should be fine. - return False # too bonded etc. - - # === conditional selectors ======================================================================================== - - def _is_would_be_triangle(self, first: Chem.Atom, second: Chem.Atom) -> bool: - """ - Get bool of whether two atoms share a common neighbor. Ie. joining them would make a triangle. - Direct bond does not count. - - :param first: - :param second: :return: """ - if self._get_triangle(first, second) is not None: - return True - else: - return False - - - def _is_would_be_square(self, first: Chem.Atom, second: Chem.Atom) -> bool: - """ - Get bool of whether two atoms share a common neighbor+over-neighbor. Ie. joining them would make a square. - Direct bond does not count. - - :param first: - :param second: - :return: - """ - for third in [neigh for neigh in second.GetNeighbors() if neigh.GetIdx() != first.GetIdx()]: - if self._is_would_be_triangle(first, third) is True: - return True - else: - return False - - def _get_triangle(self, first: Chem.Atom, second: Chem.Atom) -> Union[int, None]: - """ - Get the third atom... - - :param first: atom - :param second: atom - :return: atom index of third - """ - triang = self._get_triangles(first, second) - if triang: - return triang[0] - else: - return None - - def _get_triangles(self, first: Chem.Atom, second: Chem.Atom) -> Union[List[int], None]: - """ - Get the third atoms... (Square situation) - - :param first: atom - :param second: atom - :return: atom index of third - """ - get_neigh_idxs = lambda atom: [neigh.GetIdx() for neigh in atom.GetNeighbors() if - self._is_count_valid(neigh)] - f_neighs = get_neigh_idxs(first) - s_neighs = get_neigh_idxs(second) - a = set(f_neighs) - {first.GetIdx(), second.GetIdx()} - b = set(s_neighs) - {first.GetIdx(), second.GetIdx()} - others = list(a.intersection(b)) - if len(others) == 0: # is disjoined - return None - else: - return list(others) - - def _is_count_valid(self, atom: Chem.Atom) -> bool: - """ - Some atoms are not to be counted as they will be deleted. - - :param atom: - :return: - """ - if atom.HasProp('DELETE'): - return False - elif atom.HasProp('_ori_i') and atom.GetIntProp('_ori_i') == -1: - return False - else: - return True - - - def _get_square(self, first: Chem.Atom, second: Chem.Atom) -> Union[Tuple[int, int], None]: - for third in [neigh for neigh in second.GetNeighbors() if neigh.GetIdx() != first.GetIdx()]: - fourths = self._get_triangles(first, third) - if fourths and len(fourths) > 1: - fourth = [f for f in fourths if f != second.GetIdx()][0] - return third.GetIdx(), fourth - else: - return None - - def _is_connected_warhead(self, atom, anchor_atom): - if not atom.HasProp('_Warhead'): - return False - elif atom.GetBoolProp('_Warhead') == False: - return False - else: - # is it a single compound? - frags = Chem.GetMolFrags(atom.GetOwningMol(), sanitizeFrags=False) - if len(frags) == 1: - return True - else: - for frag in frags: - if atom.GetIdx() in frag and anchor_atom.GetIdx() in frag: - return True - elif atom.GetIdx() in frag: - return False # if the warhead is not connected pretend it is not a warhead. - else: - pass - else: - raise ValueError('I do not think this is possible.') + conf = mol.GetConformer() + name = mol.GetProp('_Name') + for i, atom in enumerate(mol.GetAtoms()): + pos = conf.GetAtomPosition(i) + atom.SetIntProp('_ori_i', i) + atom.SetProp('_ori_name', name) + atom.SetDoubleProp('_x', pos.x) + atom.SetDoubleProp('_y', pos.y) + atom.SetDoubleProp('_z', pos.z) + return mol diff --git a/fragmenstein/monster/_blend_place.py b/fragmenstein/monster/_blend_place.py new file mode 100644 index 0000000..c6141e9 --- /dev/null +++ b/fragmenstein/monster/_blend_place.py @@ -0,0 +1,690 @@ +from rdkit.Chem import rdmolops + +import itertools +import json +from collections import Counter +from collections import defaultdict +from typing import Optional, Dict, List, Tuple +from warnings import warn + +import numpy as np +from rdkit import Chem +from rdkit.Chem import AllChem +from rdkit.Chem import rdFMCS, rdMolAlign, rdmolops +from rdkit.Chem import rdmolops +from rdkit.Geometry.rdGeometry import Point3D + +from ._communal import _MonsterCommunal +from ._merge import _MonsterMerge +from .unmerge_mapper import Unmerge + + +class _MonsterBlend(_MonsterMerge): + # placement dependent methdos + + # @classmethod #why was this a classmethod + def full_blending(self) -> None: + """ + a single scaffold is made (except for ``.unmatched``) + """ + self.mol_options = [self.simply_merge_hits()] + self.scaffold = self.posthoc_refine(self.mol_options[0]) + self.chimera = self.make_chimera() + self.positioned_mol = self.place_from_map() + + def partial_blending(self) -> None: + """ + multiple possible scaffolds for placement and best is chosen + """ + self.mol_options = self.partially_blend_hits() # merger of hits + unrefined_scaffold, mode_index = self.pick_best() + used = self.scaffold.GetProp('_Name').split('-') + self.unmatched = [h.GetProp('_Name') for h in self.hits if h.GetProp('_Name') not in used] + self.scaffold = self.posthoc_refine(unrefined_scaffold) + self.chimera = self.make_chimera(mode_index) + self.positioned_mol = self.place_from_map() + + def no_blending(self, broad=False) -> None: + """ + no merging is done. The hits are mapped individually. Not great for small fragments. + """ + maps = {} + for template in self.hits: + if broad: + pair_atom_maps, _ = self.get_mcs_mappings(self.initial_mol, template) + maps[template.GetProp('_Name')] = pair_atom_maps + else: + pair_atom_maps_t = self._get_atom_maps(self.initial_mol, template, + atomCompare=rdFMCS.AtomCompare.CompareElements, + bondCompare=rdFMCS.BondCompare.CompareOrder, + ringMatchesRingOnly=True, + ringCompare=rdFMCS.RingCompare.PermissiveRingFusion, + matchChiralTag=True) + pair_atom_maps = [dict(p) for p in pair_atom_maps_t] + maps[template.GetProp('_Name')] = pair_atom_maps + um = Unmerge(followup=self.initial_mol, + mols=self.hits, + maps=maps, + no_discard=self.throw_on_discard, + _debug_draw=self._debug_draw) + self.scaffold = um.combined + self.mol_options = um.combined_alternatives + full_atom_map = um.combined_map + self.unmatched = [m.GetProp('_Name') for m in um.disregarded] + if self.throw_on_discard and len(self.unmatched): + raise ConnectionError(f'{self.unmatched} was rejected.') + self.chimera = um.combined_bonded + if self._debug_draw: + print('followup to scaffold', full_atom_map) + print('followup') + self.draw_nicely(self.initial_mol) + print('scaffold') + self.draw_nicely(self.scaffold) + placed = self.place_from_map(atom_map=full_atom_map) + self.positioned_mol = self.posthoc_refine(placed) + + + # ================= Blend hits =================================================================================== + + def partially_blend_hits(self, hits: Optional[List[Chem.Mol]] = None) -> List[Chem.Mol]: + """ + This is the partial merge algorithm, wherein the hits are attempted to be combined. + If the combination is bad. It will not be combined. + Returning a list of possible options. + These will have the atoms changed too. + + :param hits: + :param distance: + :return: + """ + + if hits is None: + hits = sorted(self.hits, key=lambda h: h.GetNumAtoms(), reverse=True) + for hi, hit in enumerate(hits): + # fallback naming. + if not hit.HasProp('_Name') or hit.GetProp('_Name').strip() == '': + hit.SetProp('_Name', f'hit{hi}') + + ## a dodgy hit is a hit with inconsistent mapping bwteen three. + def get_dodgies(skippers): + dodgy = [] + for hit0, hit1, hit2 in itertools.combinations(hits, 3): + hn0 = hit0.GetProp('_Name') + hn1 = hit1.GetProp('_Name') + hn2 = hit2.GetProp('_Name') + if any([hit in skippers for hit in (hn0, hn1, hn2)]): + continue + for a, b in inter_mapping[(hn0, hn1)].items(): + if a in inter_mapping[(hn0, hn2)] and b in inter_mapping[(hn1, hn2)]: + if inter_mapping[(hn0, hn2)][a] != inter_mapping[(hn1, hn2)][b]: + # TODO: THIS IS A BAD OPTION: + # if all([m.GetAtomWithIdx(i).IsInRing() for m, i in ((hit0, a), + # (hit1, b), + # (hit2, inter_mapping[(hn0, hn2)][a]), + # (hit2, inter_mapping[(hn1, hn2)][b]))]): + # pass + # else: + dodgy.extend((hn0, hn1, hn2)) + d = Counter(dodgy).most_common() + if dodgy: + return get_dodgies(skippers=skippers + [d[0][0]]) + else: + return skippers + + inter_mapping = {} + for h1, h2 in itertools.combinations(hits, 2): + inter_mapping[(h1.GetProp('_Name'), h2.GetProp('_Name'))] = self.get_positional_mapping(h1, h2) + dodgy_names = get_dodgies([]) + if self._debug_draw: + print('******** These combine badly') + print(dodgy_names) + dodgies = [hit for hit in hits if hit.GetProp('_Name') in dodgy_names] + mergituri = [hit for hit in hits if hit.GetProp('_Name') not in dodgy_names] + merged = self.simply_merge_hits(mergituri) + dodgies += [hit for hit in hits if hit.GetProp('_Name') in self.unmatched] + self.unmatched = [] + combined_dodgies = [] + for h1, h2 in itertools.combinations(dodgies, 2): + h_alt = Chem.Mol(h1) + try: + combined_dodgies.append(self.merge_pair(h_alt, h2)) + except ConnectionError: + pass + combinations = [merged] + dodgies + combined_dodgies + # propagate alternatives + while self.propagate_alternatives(combinations) != 0: + pass + if self._debug_draw: + print('alternatives propagated') + return combinations + + def propagate_alternatives(self, fewer): + pt = Chem.GetPeriodicTable() + new = 0 + for template in list(fewer): + for i, atom in enumerate(template.GetAtoms()): + if atom.HasProp('_AltSymbol'): + alt = Chem.Mol(template) + aa = alt.GetAtomWithIdx(i) + aa.SetAtomicNum(pt.GetAtomicNumber(atom.GetProp('_AltSymbol'))) + aa.ClearProp('_AltSymbol') + atom.ClearProp('_AltSymbol') + fewer.append(alt) + new += 1 + return new + + def pick_best(self) -> Tuple[Chem.Mol, int]: + """ + Method for partial merging for placement + + :return: unrefined_scaffold, mode_index + """ + if len(self.mol_options) == 1: + return self.mol_options[0], 0 + elif len(self.mol_options) == 0: + raise ValueError('No scaffolds made?!') + else: + mapx = {} #: dictionary of key mol name and value tuple of maps and mode + + def template_sorter(t: List[Chem.Mol]) -> float: + # key for sorting. requires outer scope ``maps``. + n_atoms = len(mapx[t.GetProp('_Name')][0]) + mode = mapx[t.GetProp('_Name')][1] + mode_i = self.matching_modes.index(mode) + return - n_atoms - mode_i / 10 + + ## get data + # presort as this is expensive. + for template in self.mol_options: + # _get_atom_maps returns a list of alternative mappings which are lists of template to initail mol + atom_maps = self._get_atom_maps(template, self.initial_mol, + atomCompare=rdFMCS.AtomCompare.CompareElements, + bondCompare=rdFMCS.BondCompare.CompareOrder, + ringMatchesRingOnly=True, + ringCompare=rdFMCS.RingCompare.PermissiveRingFusion, + matchChiralTag=False) + mapx[template.GetProp('_Name')] = (atom_maps, self.matching_modes[-1]) + # search properly only top 3. + self.mol_options = sorted(self.mol_options, key=template_sorter) + for template in self.mol_options[:3]: + atom_map, mode = self.get_mcs_mapping(template, self.initial_mol) + # get_mcs_mapping returns a dict going from template index to initial. + mapx[template.GetProp('_Name')] = (atom_map, mode) + if self._debug_draw: + print( + f"With {template.GetProp('_Name')}, {len(atom_map)} atoms map using mode {self.matching_modes.index(mode)}") + ## pick best template + self.mol_options = sorted(self.mol_options, key=template_sorter) + ## Check if missing atoms can be explained by a different one with no overlap + best = self.mol_options[0] + ## Fuse overlaps + # best_map = maps[best.GetProp('_Name')][0] + # full = set(range(self.initial_mol.GetNumAtoms())) + # present = set(best_map.values()) + # missing = full - present + # for other in self.mol_options: + # other_map = maps[other.GetProp('_Name')][0] + # found = set(other_map.values()) + # if len(found) > 6 and len(present & found) == 0: # more than just a ring and no overlap + # fusion = self._fuse(best, other, best_map, other_map) + return best, self.matching_modes.index(mapx[best.GetProp('_Name')][1]) + + # def _fuse(self, mol_A: Chem.Mol, mol_B: Chem.Mol, map_A: Dict[int, int], map_B: Dict[int, int]) -> Chem.Mol: + # """ + # Merge two compounds... but that are unlinked, using the followup as a guide. + # Conceptually different but overlapping is join_neighboring_mols + # + # :param mol_A: + # :param mol_B: + # :param map_A: + # :param map_B: + # :return: + # """ + # # No longer needed. + # fusion = Chem.RwMol(Chem.CombineMols(mol_A, mol_B)) + # t = mol_A.GetNumAtoms() + # new_map_B = {k+t: v for k, v in map_B.items()} + # full = set(range(self.initial_mol.GetNumAtoms())) + # present_A = set(map_A.values()) + # present_B = set(map_B.values()) + # + # def find_route(n): + # if n in present_A: + # return None + # elif n in present_B: + # return n + # else: + # path_raw = {m: find_route(m) for m in self.initial_mol.GetAtomWithIdx(n).GetNeighbors()} + # path = {i: path_raw[i] for i in path_raw if path_raw[i] is not None} + # if len(path) == 0: + # return None + # else: + # return {n: path} + + + def _prevent_two_bonds_on_dummy(self, mol: Chem.RWMol): + """ + The case '*(C)C' is seen legitimately in some warheads... but in most cases these are not. + :param mol: + :return: + """ + for atom in mol.GetAtoms(): + if atom.GetSymbol() != '*': + pass + elif len(atom.GetNeighbors()) <= 1: + pass + elif len(atom.GetNeighbors()) >= 2: + self.journal.info(f'Dummy atom (idx={atom.GetIdx()}) has {len(atom.GetNeighbors())} bonds!') + neighs = atom.GetNeighbors() + first = neighs[0] + for second in neighs[1:]: + rejected = second.GetIdx() # that will be absorbed (deleted) + keeper = first.GetIdx() # that absorbs (kept) + self._copy_bonding(mol, keeper, rejected) + self._mark_for_deletion(mol, rejected) + self._delete_marked(mol) + return self._prevent_two_bonds_on_dummy(mol) + + # ================= Chimera ======================================================================================== + + def make_chimera(self, min_mode_index=0) -> Chem.Mol: + """ + This is to avoid extreme corner corner cases. + E.g. here the MCS is ringMatchesRingOnly=True and AtomCompare.CompareAny, + while for the positioning this is not the case. + + :return: + """ + # get the matches + atom_map, mode = self.get_mcs_mapping(self.scaffold, self.initial_mol, min_mode_index=min_mode_index) + follow = {**{k: str(v) for k, v in mode.items()}, 'N_atoms': len(atom_map)} + self.journal.debug(f"scaffold-followup: {follow}") + if self._debug_draw: + self.draw_nicely(self.initial_mol, highlightAtoms=atom_map.values()) + # make the scaffold more like the followup to avoid weird matches. + chimera = Chem.RWMol(self.scaffold) + for scaff_ai, follow_ai in atom_map.items(): + if self.scaffold.GetAtomWithIdx(scaff_ai).GetSymbol() != self.initial_mol.GetAtomWithIdx( + follow_ai).GetSymbol(): + v = {'F': 1, 'Br': 1, 'Cl': 1, 'H': 1, 'B': 3, 'C': 4, 'N': 3, 'O': 2, 'S': 2, 'Se': 2, 'P': 6} + wanted = self.initial_mol.GetAtomWithIdx(follow_ai) + if wanted.GetSymbol() == '*': # all good then! + continue + owned = self.scaffold.GetAtomWithIdx(scaff_ai) + diff_valance = owned.GetExplicitValence() - v[wanted.GetSymbol()] + if wanted.GetSymbol() in ('F', 'Br', 'Cl', 'C', 'H') and diff_valance > 0: + continue # cannot change this. + elif owned.GetExplicitValence() > 4 and wanted.GetSymbol() not in ('P',): + continue + else: + newatom = Chem.Atom(wanted) + stdev = chimera.GetAtomWithIdx(scaff_ai).GetDoubleProp('_Stdev') + newatom.SetDoubleProp('_Stdev', stdev) + origin = chimera.GetAtomWithIdx(scaff_ai).GetProp('_Origin') + newatom.SetProp('_Origin', origin) + chimera.ReplaceAtom(scaff_ai, newatom) + if diff_valance > 0: + chimera.GetAtomWithIdx(scaff_ai).SetFormalCharge(diff_valance) + try: + chimera.UpdatePropertyCache() + except Chem.AtomValenceException as err: + warn('Valance issue' + str(err)) + return chimera + + def place_from_map(self, mol: Chem.Mol = None, atom_map: Optional[Dict] = None) -> Chem.Mol: + """ + This method places the atoms with known mapping + and places the 'uniques' (novel) via an aligned mol (the 'sextant') + This sextant business is a workaround for the fact that only minimised molecules can use the partial + embedding function of RDKit. + + :param mol: + :param atom_map: something that get_mcs_mapping would return. + :return: + """ + # Note none of this malarkey: AllChem.MMFFOptimizeMolecule(ref) + # prealignment + if mol is None: + mol = self.initial_mol + sextant = Chem.Mol(mol) + Chem.SanitizeMol(sextant) + AllChem.EmbedMolecule(sextant) + AllChem.MMFFOptimizeMolecule(sextant) + ###################################################### + # mapping retrieval and sextant alignment + # variables: atom_map sextant -> uniques + if atom_map is None: + atom_map, mode = self.get_mcs_mapping(mol, self.chimera) + msg = {**{k: str(v) for k, v in mode.items()}, 'N_atoms': len(atom_map)} + self.journal.debug(f"followup-chimera' = {msg}") + rdMolAlign.AlignMol(sextant, self.chimera, atomMap=list(atom_map.items()), maxIters=500) + # debug print + if self._debug_draw: + self.draw_nicely(mol, highlightAtoms=dict(atom_map).keys()) + self.draw_nicely(self.chimera, highlightAtoms=dict(atom_map).values()) + # place atoms that have a known location + putty = Chem.Mol(sextant) + pconf = putty.GetConformer() + chimera_conf = self.chimera.GetConformer() + uniques = set() # unique atoms in followup + for i in range(putty.GetNumAtoms()): + p_atom = putty.GetAtomWithIdx(i) + p_atom.SetDoubleProp('_Stdev', 0.) + p_atom.SetProp('_Origin', 'none') + if i in atom_map: + ci = atom_map[i] + c_atom = self.chimera.GetAtomWithIdx(ci) + if c_atom.HasProp('_Stdev'): + stdev = c_atom.GetDoubleProp('_Stdev') + origin = c_atom.GetAtomWithIdx(ci).GetProp('_Origin') + p_atom.SetDoubleProp('_Stdev', stdev) + p_atom.SetProp('_Origin', origin) + pconf.SetAtomPosition(i, chimera_conf.GetAtomPosition(ci)) + else: + uniques.add(i) + ###################################################### + # I be using a sextant for dead reckoning! + # variables: sextant unique team + categories = self._categorise(sextant, uniques) + # debug print + if self._debug_draw: + print('internal', categories['internals']) + done_already = [] # multi-attachment issue. + for unique_idx in categories['pairs']: # attachment unique indices + # check the index was not done already (by virtue of a second attachment) + if unique_idx in done_already: + continue + # get other attachments if any. + team = self._recruit_team(mol, unique_idx, categories['uniques']) + other_attachments = (team & set(categories['pairs'].keys())) - {unique_idx} + sights = set() # atoms to align against + for att_idx in [unique_idx] + list(other_attachments): + for pd in categories['pairs'][att_idx]: + first_sight = pd['idx'] + sights.add((first_sight, first_sight)) + neighs = [i.GetIdx() for i in sextant.GetAtomWithIdx(first_sight).GetNeighbors() if + i.GetIdx() not in uniques] + for n in neighs: + sights.add((n, n)) + if self.attachment and list(categories['dummies']) and list(categories['dummies'])[0] in team: + r = list(categories['dummies'])[0] + pconf.SetAtomPosition(r, self.attachment.GetConformer().GetAtomPosition(0)) + sights.add((r, r)) + rdMolAlign.AlignMol(sextant, putty, atomMap=list(sights), maxIters=500) + sconf = sextant.GetConformer() + # debug print + if self._debug_draw: + print(f'alignment atoms for {unique_idx} ({team}): {sights}') + self.draw_nicely(sextant, highlightAtoms=[a for a, b in sights]) + # copy position over + for atom_idx in team: + pconf.SetAtomPosition(atom_idx, sconf.GetAtomPosition(atom_idx)) + # the ring problem does not apply here but would result in rejiggling atoms. + + for other in other_attachments: + done_already.append(other) + # complete + AllChem.SanitizeMol(putty) + return putty # positioned_mol + + def _merge_part(self, scaffold: Chem.Mol, fragmentanda: Chem.Mol, anchor_index: int, + attachment_details: List[Dict], + other_attachments: List[int], + other_attachment_details: List[List[Dict]]) -> Chem.Mol: + """ + This does the messy work for merge_pair. + + :param scaffold: the Chem.Mol molecule onto whose copy the fragmentanda Chem.Mol gets added + :param fragmentanda: The other Chem.Mol molecule + :param anchor_index: the fragment-to-added's internal atom that attaches (hit indexed) + :param attachment_details: see `_pre_fragment_pairs` or example below fo an entry + :type attachment_details: List[Dict] + :param other_attachments: + :param other_attachment_details: + :return: a new Chem.Mol molecule + + Details object example: + + [{'idx': 5, + 'type': rdkit.Chem.rdchem.BondType.SINGLE, + 'idx_F': 5, # fragmentanda index + 'idx_S': 1 # scaffold index + }], ...} + """ + # get bit to add. + bonds_to_frag = [] + for detail in attachment_details: + attachment_index = detail['idx_F'] # fragmentanda attachment_index + bonds_to_frag += [fragmentanda.GetBondBetweenAtoms(anchor_index, attachment_index).GetIdx()] + bonds_to_frag += [fragmentanda.GetBondBetweenAtoms(oi, oad[0]['idx_F']).GetIdx() for oi, oad in + zip(other_attachments, other_attachment_details)] + if self._debug_draw and other_attachments: + print('ring!', other_attachments) + print('ring!', other_attachment_details) + f = Chem.FragmentOnBonds(fragmentanda, + bonds_to_frag, + addDummies=False) + frag_split = [] + fragmols = Chem.GetMolFrags(f, asMols=True, fragsMolAtomMapping=frag_split, sanitizeFrags=False) + if self._debug_draw: + print('Fragment splits') + print(frag_split) + # Get the fragment of interest. + ii = 0 + for mol_N, indices in enumerate(frag_split): + if anchor_index in indices: + break + ii += len(indices) + else: + raise Exception + frag = fragmols[mol_N] + frag_anchor_index = indices.index(anchor_index) + # pre-emptively fix atom ori_i + # offset collapsed to avoid clashes. + self.offset(frag) + # Experimental code. + # TODO: finish! + # frag_atom = frag.GetAtomWithIdx(frag_anchor_index) + # old2future = {atom.GetIntProp('_ori_i'): atom.GetIdx() + scaffold.GetNumAtoms() for atom in frag.GetAtoms()} + # del old2future[-1] # does nothing but nice to double tap + # if frag_atom.GetIntProp('_ori_i') == -1: #damn. + # for absent in self._get_mystery_ori_i(frag): + # old2future[absent] = scaffold_attachment_index + # self._renumber_original_indices(frag, old2future) + if self._debug_draw: + print('Fragment to add') + self.draw_nicely(frag) + combo = Chem.RWMol(rdmolops.CombineMols(scaffold, frag)) + scaffold_anchor_index = frag_anchor_index + scaffold.GetNumAtoms() + if self._debug_draw: + print('Pre-merger') + print(scaffold_anchor_index, attachment_details, anchor_index, scaffold.GetNumAtoms()) + self.draw_nicely(combo) + for detail in attachment_details: + # scaffold_anchor_index : atom index in scaffold that needs to be added to scaffold_attachment_index + # but was originally attached to attachment_index in fragmentanda. + # the latter is not kept. + attachment_index = detail['idx_F'] # fragmentanda attachment_index + scaffold_attachment_index = detail['idx_S'] # scaffold attachment index + bond_type = detail['type'] + combo.AddBond(scaffold_anchor_index, scaffold_attachment_index, bond_type) + new_bond = combo.GetBondBetweenAtoms(scaffold_anchor_index, scaffold_attachment_index) + # BondProvenance.set_bond(new_bond, '???') + # self.transfer_ring_data(fragmentanda.GetAtomWithIdx(attachment_index), + # combo.GetAtomWithIdx(scaffold_anchor_index)) + for oi, oad in zip(other_attachments, other_attachment_details): + bond_type = oad[0]['type'] + scaffold_attachment_index = oad[0]['idx_S'] + scaffold_anchor_index = indices.index(oi) + scaffold.GetNumAtoms() + combo.AddBond(scaffold_anchor_index, scaffold_attachment_index, bond_type) + new_bond = combo.GetBondBetweenAtoms(scaffold_anchor_index, scaffold_attachment_index) + # BondProvenance.set_bond(new_bond, '???') + if self._debug_draw: + print( + f"Added additional {bond_type.name} bond between {scaffold_attachment_index} and {scaffold_anchor_index} " + \ + f"(formerly {indices.index(oi)})") + Chem.SanitizeMol(combo, + sanitizeOps=Chem.rdmolops.SanitizeFlags.SANITIZE_ADJUSTHS + + Chem.rdmolops.SanitizeFlags.SANITIZE_SETAROMATICITY, + catchErrors=True) + if self._debug_draw: + print('Merged') + self.draw_nicely(combo) + self._prevent_two_bonds_on_dummy(combo) + scaffold = combo.GetMol() + return scaffold + + def transfer_ring_data(self, donor: Chem.Atom, acceptor: Chem.Atom): + """ + Transfer the info if a ringcore atom. + + :param donor: + :param acceptor: + :return: + """ + # if donor.GetIntProp('_ori_i') == -1: + # data = donor + pass + + + # ========= Other ================================================================================================== + + + def posthoc_refine(self, scaffold, indices: Optional[List[int]] = None) -> Chem.Mol: + """ + Averages the overlapping atoms. + + :param scaffold: + :return: + """ + if indices is None: + indices = list(range(scaffold.GetNumAtoms())) + refined = Chem.RWMol(scaffold) + refconf = refined.GetConformer() + positions = defaultdict(list) # coordinates + equivalence = defaultdict(list) # atom indices of hits. + for h in self.hits: + if h.GetProp('_Name') in self.unmatched: + continue + hc = h.GetConformer() + for k, v in self.get_positional_mapping(scaffold, h).items(): + positions[k].append([hc.GetAtomPosition(v).x, hc.GetAtomPosition(v).y, hc.GetAtomPosition(v).z]) + equivalence[k].append(f'{h.GetProp("_Name")}.{v}') + for i in range(scaffold.GetNumAtoms()): + if i not in indices: + continue + elif len(positions[i]) == 0: + refined.GetAtomWithIdx(i).SetDoubleProp('_Stdev', 0.) + refined.GetAtomWithIdx(i).SetDoubleProp('_Max', 0.) + refined.GetAtomWithIdx(i).SetProp('_Origin', 'none') + # warn(f'Atom {i} {scaffold.GetAtomWithIdx(i).GetSymbol}/{refined.GetAtomWithIdx(i).GetSymbol} '+ \ + # 'in scaffold that has no positions.') + else: + p = np.mean(np.array(positions[i]), axis=0).astype(float) + # sd = np.mean(np.std(np.array(positions[i]), axis=0)).astype(float) + ds = [np.linalg.norm(p - pi) for pi in positions[i]] + sd = np.std(ds) + md = np.max(ds) + refined.GetAtomWithIdx(i).SetProp('_Origin', json.dumps(equivalence[i])) + refined.GetAtomWithIdx(i).SetDoubleProp('_Stdev', sd) + refined.GetAtomWithIdx(i).SetDoubleProp('_Max', md) + if self.average_position: + refconf.SetAtomPosition(i, Point3D(p[0], p[1], p[2])) + Chem.SanitizeMol(refined, + sanitizeOps=Chem.rdmolops.SanitizeFlags.SANITIZE_ADJUSTHS + + Chem.rdmolops.SanitizeFlags.SANITIZE_SETAROMATICITY, + catchErrors=True) + return refined + + def get_mcs_mappings(self, molA, molB, min_mode_index: int = 0) -> Tuple[List[Dict[int, int]], dict]: + """ + This is a weird method. It does a strict MCS match. + And then it uses laxer searches and finds the case where a lax search includes the strict search. + + :param molA: query molecule + :param molB: target/ref molecule + :param min_mode_index: the lowest index to try (opt. speed reasons) + :return: mappings and mode + """ + strict_settings = dict(atomCompare=rdFMCS.AtomCompare.CompareElements, + bondCompare=rdFMCS.BondCompare.CompareOrder, + ringMatchesRingOnly=True, + ringCompare=rdFMCS.RingCompare.PermissiveRingFusion, + matchChiralTag=True) + strict = self._get_atom_maps(molA, molB, **strict_settings) + for i, mode in enumerate(self.matching_modes): + if i < min_mode_index: + continue + if self._debug_draw: + print(f'Trying mode {mode}') + lax = self._get_atom_maps(molA, molB, **mode) + # remove the lax matches that disobey + neolax = [l for l in lax if any([len(set(s) - set(l)) == 0 for s in strict])] + if len(neolax) == 0: + continue + else: + return [dict(n) for n in neolax], mode + else: + # Then the strict will have to do. + return [dict(n) for n in strict], strict_settings # tuple to dict + # raise ValueError('This is chemically impossible: nothing matches in the MCS step ' +\ + # f'({len(self.matching_modes)} modes tried') + + def get_mcs_mapping(self, molA, molB, min_mode_index: int = 0) -> Tuple[Dict[int, int], dict]: + """ + This is a weird method. It does a strict MCS match. + And then it uses laxer searches and finds the case where a lax search includes the strict search. + + :param molA: query molecule + :param molB: target/ref molecule + :param min_mode_index: the lowest index to try (opt. speed reasons) + :return: mapping and mode + """ + ms, mode = self.get_mcs_mappings(molA, molB, min_mode_index) + return ms[0], mode + + def _get_atom_maps(self, molA, molB, **mode) -> List[List[Tuple[int, int]]]: + mcs = rdFMCS.FindMCS([molA, molB], **mode) + common = Chem.MolFromSmarts(mcs.smartsString) + matches = [] + # prevent a dummy to match a non-dummy, which can happen when the mode is super lax. + is_dummy = lambda mol, at: mol.GetAtomWithIdx(at).GetSymbol() == '*' + all_bar_dummy = lambda Aat, Bat: (is_dummy(molA, Aat) and is_dummy(molB, Bat)) or not ( + is_dummy(molA, Aat) or is_dummy(molB, Bat)) + for molA_match in molA.GetSubstructMatches(common, uniquify=False): + for molB_match in molB.GetSubstructMatches(common, uniquify=False): + matches.append([(molA_at, molB_at) for molA_at, molB_at in zip(molA_match, molB_match) if + all_bar_dummy(molA_at, molB_at)]) + # you can map two toluenes 4 ways, but two are repeats. + matches = set([tuple(sorted(m, key=lambda i: i[0])) for m in matches]) + return matches + + def _get_atom_map(self, molA, molB, **mode) -> List[Tuple[int, int]]: + return self._get_atom_maps(molA, molB, **mode)[0] + + + def pretweak(self) -> None: + """ + What if the fragments were prealigned slightly? Really bad things. + + :return: + """ + warn('This method is unreliable. Do not use it') + ref = self.hits[0] + for target in self.hits[1:]: + A2B = list(self.get_positional_mapping(target, ref, 0.5).items()) + if A2B: + rdMolAlign.AlignMol(target, ref, atomMap=A2B, maxIters=500) + else: + warn(f'No overlap? {A2B}') + + @property + def matched(self): + """ + This is the counter to unmatched. + It's dynamic as you never know... + + :return: + """ + return [h.GetProp('_Name') for h in self.hits if + h.GetProp('_Name') not in self.unmatched] \ No newline at end of file diff --git a/fragmenstein/monster/_collapse_ring.py b/fragmenstein/monster/_collapse_ring.py index 16e1d67..650537a 100644 --- a/fragmenstein/monster/_collapse_ring.py +++ b/fragmenstein/monster/_collapse_ring.py @@ -3,60 +3,39 @@ __doc__ = \ """ This is the ring collapsing code. - """ -__author__ = "Matteo Ferla. [Github](https://github.com/matteoferla)" -__email__ = "matteo.ferla@gmail.com" -__date__ = "2020 A.D." -__license__ = "MIT" -__version__ = "0.4" -__citation__ = "" +In Pymol, a ring diameter is 2.7894375324249268 Å. + + fab F + print cmd.distance('/obj01///PHE`1/CE1','/obj01///PHE`1/CD2') + """ ######################################################################################################################## -import json, itertools -from warnings import warn -from rdkit.Geometry.rdGeometry import Point3D +import itertools +import json from collections import defaultdict -from rdkit import Chem -from rdkit.Chem import AllChem +from functools import partial from typing import Optional, Dict, List, Any, Tuple, Union, Callable + import numpy as np -from collections import Counter -from functools import partial +from rdkit import Chem +from rdkit.Geometry.rdGeometry import Point3D + +from ._communal import _MonsterCommunal +from ._join_neighboring import _MonsterJoinNeigh from .bond_provenance import BondProvenance -from ._base import _MonsterBaseMixin -class _MonsterRing(_MonsterBaseMixin): - def __init__(self, _debug_draw=False): - # abstracted... - self._debug_draw = _debug_draw +######################################################################################################################## + +class _MonsterRing(_MonsterCommunal, _MonsterJoinNeigh): def collapse_mols(self, mols: List[Chem.Mol]): mols = [self.collapse_ring(mol) for mol in mols] [self.offset(mol) for mol in mols] return mols - def store_positions(self, mol: Chem.Mol) -> Chem.Mol: - """ - Saves positional data as _x, _y, _z and majorly ``_ori_i``, the original index. - The latter gets used by ``_get_new_index``. - - :param mol: - :return: - """ - conf = mol.GetConformer() - name = mol.GetProp('_Name') - for i, atom in enumerate(mol.GetAtoms()): - pos = conf.GetAtomPosition(i) - atom.SetIntProp('_ori_i', i) - atom.SetProp('_ori_name', name) - atom.SetDoubleProp('_x', pos.x) - atom.SetDoubleProp('_y', pos.y) - atom.SetDoubleProp('_z', pos.z) - return mol - # =========== Collapse & Expand ==================================================================================== def collapse_ring(self, mol: Chem.Mol) -> Chem.Mol: @@ -154,6 +133,7 @@ def expand_ring(self, mol: Chem.Mol) -> Chem.Mol: self._place_ring_atoms(mol, rings) # bonded_as_original. Rectifier will fix. self._restore_original_bonding(mol, rings) + self.keep_copy(mol, 'Rings expanded and original bonding restored.') self._add_novel_bonding(mol, rings) # formerly `_ring_overlap_scenario` and `_infer_bonding_by_proximity`. self._delete_collapsed(mol) self._detriangulate(mol) @@ -200,6 +180,8 @@ def offset(self, mol: Chem.Mol): old_neighss = json.loads(atom.GetProp('_neighbors')) # if i in old2new else i new_neighss = [[old2new[i] for i in old_neighs if i in old2new] for old_neighs in old_neighss] atom.SetProp('_neighbors', json.dumps(new_neighss)) + # determine if the new atoms have close neighbours. + pass def _renumber_original_indices(self, mol: Chem.Mol, mapping: Dict[int, int], @@ -287,10 +269,11 @@ def _get_expansion_for_atom(self, ring: Dict[str, List[Any]], i: int) -> Dict[st if len(troublesome) == 0: raise IndexError(f'There is a major issue with ring data for index {i}: {ring}') elif troublesome[0] == 'current_is': - self.journal.warning(f'One atom lacks a current index!'+ \ + self.journal.warning(f'One atom lacks a current index!' + \ 'This is a fallback that should not happen') mol = ring['atom'].GetOwningMol() - ring['current_is'] = [self._get_new_index(mol, old_i, search_collapsed=False) for old_i in ring['ori_is']] + ring['current_is'] = [self._get_new_index(mol, old_i, search_collapsed=False) for old_i in + ring['ori_is']] return self._get_expansion_for_atom(ring, i) else: raise IndexError(f'The indices of the collapsed atom do not extend to {i} for {troublesome}') @@ -408,17 +391,19 @@ def _add_novel_bonding(self, mol: Chem.RWMol, rings: List[Dict[str, List[Any]]]) """ self.journal.debug('Adding novel bonding (if any)...') # ===== Deal with Ring on ring bonding - novel_ringcore_pairs = self._get_novel_ringcore_pairs(mol, rings, cutoff = 1.5) + novel_ringcore_pairs = self._get_novel_ringcore_pairs(mol, rings, cutoff=1.5) # these is a list of Chem.Atom pairs. for ringcore_A, ringcore_B in novel_ringcore_pairs: - self.journal.debug(f'determining novel bond between {ringcore_A} and {ringcore_B}') + self.journal.debug('determining novel bond between ring markers ' + \ + f'{ringcore_A.GetIdx()} and {ringcore_B.GetIdx()}') # _determine_mergers_novel_ringcore_pair finds mergers self._determine_mergers_novel_ringcore_pair(mol, ringcore_A, ringcore_B) # ===== Deal with Ring on other bonding # formerly: _infer_bonding_by_proximity - novel_other_pairs = self._get_novel_other_pairs(rings) + novel_other_pairs = self._get_novel_other_pairs(mol, rings, 1.0) for ringcore, other in novel_other_pairs: - self.journal.debug(f'determining novel bond between {ringcore} and {other}') + self.journal.debug(f'determining novel bond between ' + \ + f'ring marker {ringcore.GetIdx()} and non-ring {other.GetIdx()}') # _determine_mergers_novel_ringcore_pair finds, bonds and marks for deletion. self._determine_mergers_novel_other_pair(mol, ringcore, other) # ===== Clean up @@ -475,12 +460,12 @@ def _get_collapsed_atoms(self, mol: Chem.Mol) -> List[Chem.Atom]: def _get_novel_ringcore_pairs(self, mol: Chem.Mol, - rings: List[Dict[str, List[Any]]], cutoff)\ - -> List[Tuple[Chem.Atom, Chem.Atom]]: + rings: List[Dict[str, List[Any]]], + cutoff: float) \ + -> List[Tuple[Chem.Atom, Chem.Atom]]: """ - Get the ring atoms that are bonded or closer than a cutoff - - + Get the ring atoms that are bonded or closer than a cutoff. + It is the countepart to _get_novel_ringcore_pairs :param mol: :param rings: output of `_get_expansion_data`. See that for details. @@ -490,9 +475,21 @@ def _get_novel_ringcore_pairs(self, """ # ---------------------------------------------------------- # scenario where they are closer than the cutoff - close_pairs = self._get_close_nonorigin_ringcores(mol, rings, cutoff) # 2.7889 ring diameter + 1.45 C-C bond + close_pairs = self._get_close_novel_ringcores(mol, rings, cutoff) # 2.7889 ring diameter + 1.45 C-C bond # ---------------------------------------------------------- # scenario where they are bonded... + bonded_pairs = self._get_novel_ringcore_bonded_pairs(rings) + # ------------ merge lists ----------- + return self.merge_pairing_lists(close_pairs + bonded_pairs) + + def _get_novel_ringcore_bonded_pairs(self, rings): + """ + called by _get_novel_ringcore_pairs alongside _get_close_novel_ringcores + Opposite of _get_novel_other_bonded_pairs + + :param rings: + :return: + """ bonded_pairs = [] for ring in rings: # ring: Dict[str, List[Any]] @@ -506,16 +503,39 @@ def _get_novel_ringcore_pairs(self, if has_ringcore_neighbor and is_new_pair and is_novel_connection: # This ringcore atom shares a novel border with another ringcore atom bonded_pairs.append((ringcore, neigh)) # i.e. List[Tuple[Chem.Atom, Chem.Atom]} - # ------------ merge lists ----------- - # todo this extra step should not exist + return bonded_pairs + + def merge_pairing_lists(self, + nonunique_pairs: List[Tuple[Chem.Atom, Chem.Atom]], + ringcore_first=True) \ + -> List[Tuple[Chem.Atom, Chem.Atom]]: # complicate because mol.GetAtomWithIdx(2) == mol.GetAtomWithIdx(2) is False seen = [] pairs = [] - for atom_a, atom_b in close_pairs+bonded_pairs: + for atom_a, atom_b in nonunique_pairs: + # sort out ai = atom_a.GetIdx() bi = atom_b.GetIdx() - low_i, high_i = sorted([ai, bi]) - pairing = f'{low_i}-{high_i}' + if ai == bi: + self.journal.debug(f'Bond to self incident with {ai} (ring? {atom_a.HasProp("_current_is")})') + continue + if ringcore_first and atom_a.HasProp('_current_is') and not atom_b.HasProp('_current_is'): + ringcore = ai + other = bi + pairing = f'{ringcore}-{other}' + elif ringcore_first and atom_b.HasProp('_current_is') and not atom_a.HasProp('_current_is'): + ringcore = bi + other = ai + pairing = f'{ringcore}-{other}' + atom_a, atom_b = atom_b, atom_a + elif atom_a.HasProp('_current_is') and atom_b.HasProp('_current_is'): + low_i, high_i = sorted([ai, bi]) + pairing = f'{low_i}-{high_i}' + else: + # these should not have been let thorugh but other novel does not filter them. + # self.journal.debug(f'Non-ring to non-ring closeness flagged!') + continue + # verify unseen if pairing in seen: pass else: @@ -530,31 +550,85 @@ def _get_ring_atom_indices_per_origin(self, rings: List[Dict[str, List[Any]]]) - atomdex[origin_name].update(ring['current_is']) # ring['current_is'] = json ringcore.GetProp('_current_is') return atomdex - def _get_close_nonorigin_ringcores(self, mol: Chem.Mol, rings: List[Dict[str, List[Any]]], cutoff: int): + def _get_atom_indices_per_origin(self, mol: Chem.Mol) -> Dict[str, List[int]]: + atomdex = defaultdict(list) + for atom in mol.GetAtoms(): + if not atom.HasProp('ori_name'): + atomdex['unknown'].append(atom.GetIdx()) + else: + name = atom.GetProp('ori_name') + atomdex[name].append(atom.GetIdx()) + return atomdex + + def _get_close_novel_ringcores(self, mol: Chem.Mol, rings: List[Dict[str, List[Any]]], cutoff: float): + cnrai = self._get_close_novel_ring_atoms_indices(mol, rings, cutoff) + return self._indices_to_atoms_n_cores(mol, cnrai) + + def _indices_to_atoms_n_cores(self, mol: Chem.Mol, index_pairs: List[Tuple[int, int]]): """ - Unfortunately, internally this compares ring atoms, not ring cores. Yet the return are ring cores. + Give a list of index pairs convert them to a list of pairs of atoms/cores """ - cnrai = self._get_close_nonorigin_ring_atoms_indices(mol, rings, cutoff) # these are indices of ring atoms, not ring cores get_atom = lambda i: mol.GetAtomWithIdx(int(i)) - get_ringcore = lambda atom: get_atom(atom.GetIntProp('_ring_i')) + get_ringcore = lambda atom: get_atom(atom.GetIntProp('_ring_i')) if atom.HasProp('_ring_i') else atom idx2ringcore = lambda i: get_ringcore(get_atom(i)) - return [(idx2ringcore(ai), idx2ringcore(bi)) for ai, bi in cnrai] + return [(idx2ringcore(ai), idx2ringcore(bi)) for ai, bi in index_pairs] + + def _get_close_novel_ring_atoms_indices(self, + mol: Chem.Mol, + rings: List[Dict[str, List[Any]]], + cutoff: int) -> List[Tuple[int, int]]: + """ + Get the list of pairs of indices derived from a ring that are closer that ``cutoff`` to another ring atom. + Note, the operations are between real ring atoms not ring core markers. + Hence why ``_get_close_novel_ringcores`` does a conversion. + - def _get_close_nonorigin_ring_atoms_indices(self, - mol: Chem.Mol, - rings: List[Dict[str, List[Any]]], - cutoff: int): + :param mol: + :param rings: output of `_get_expansion_data`. See that for details. + :param cutoff: + :return: + """ atomdex = self._get_ring_atom_indices_per_origin(rings) # not calling get_distance matrxi because tehre may be more than 2 origins. distance_matrix = Chem.Get3DDistanceMatrix(mol) for origin_name, indices in atomdex.items(): + # this blanks subsquares of same origin but not interesections of different indices from atomdex... self._nan_fill_submatrix(distance_matrix, list(indices)) self._nan_fill_others(mol, distance_matrix, [idx for idcs in atomdex.values() for idx in idcs]) + return self._get_closest_from_matrix(distance_matrix, cutoff) + + def _get_closest_from_matrix(self, matrix: np.ndarray, cutoff: int) -> List[Tuple[int, int]]: # get the pair of atom indices that are less thna cutoff. # where returns a tuple of np.arrays of dtype=np.int64 with np.errstate(invalid='ignore'): - return list(zip(*[w.astype(int) for w in np.where(distance_matrix < cutoff)])) + return list(zip(*[w.astype(int) for w in np.where(matrix < cutoff)])) + + def _get_close_novel_ring_other_indices(self, + mol: Chem.Mol, + rings: List[Dict[str, List[Any]]], + cutoff: int) -> List[Tuple[int, int]]: + """ + Get the list of pairs of indices between an ring atom and a non-ring atom from a different origin that is too close. + + :param mol: + :param rings: output of `_get_expansion_data`. See that for details. + :param cutoff: + :return: + """ + atomdex = self._get_ring_atom_indices_per_origin(rings) + oridex = self._get_atom_indices_per_origin(mol) + distance_matrix = Chem.Get3DDistanceMatrix(mol) + # blank all rings to rings + self._nan_fill_submatrix(distance_matrix, [i for l in atomdex.values() for i in l]) + closeness = [] + for origin_name, indices in atomdex.items(): + sub = distance_matrix.copy() + self._nan_fill_submatrix(sub, oridex[origin_name]) + # get the pair of atom indices that are less thna cutoff. + # where returns a tuple of np.arrays of dtype=np.int64 + closeness.extend(self._get_closest_from_matrix(distance_matrix, cutoff)) + return closeness def _determine_mergers_novel_ringcore_pair(self, mol: Chem.RWMol, @@ -591,12 +665,7 @@ def _determine_mergers_novel_ringcore_pair(self, a = int(p[0][0]) b = int(p[1][0]) present_bond = mol.GetBondBetweenAtoms(ringcore_A.GetIdx(), ringcore_B.GetIdx()) - bt = present_bond.GetBondType() - if bt is None or bt == Chem.BondType.UNSPECIFIED: - bt = Chem.BondType.SINGLE - n = mol.AddBond(a, b, bt) - new_bond = mol.GetBondBetweenAtoms(a, b) - BondProvenance.copy_bond(present_bond, new_bond) + self._add_bond_by_reference(mol, a, b, present_bond) self.journal.info('A novel bond-connected ring pair was found') self._mark_for_deletion(mol, b) self._copy_bonding(mol, a, b, force=True) @@ -644,12 +713,12 @@ def _determine_mergers_novel_ringcore_pair(self, # self.join_rings(mol) # self._triangle_warn(mol) - def _get_novel_other_pairs(self, rings) -> List[Tuple[Chem.Atom, Chem.Atom]]: - ## similar to novel ringcore..but opposite + def _get_novel_other_bonded_pairs(self, rings) -> List[Tuple[Chem.Atom, Chem.Atom]]: pairs = [] for ring in rings: # ring: Dict[str, List[Any]] ringcore = ring['atom'] # Chem.Atom + # --------- find ring atom - non-origin other pairs that are bonded for neigh in ringcore.GetNeighbors(): # find those ringcore-other atoms that are connected. via these conditions: has_notringcore_neighbor = (not neigh.HasProp('_ori_name')) or neigh.GetIntProp('_ori_i') != -1 @@ -659,6 +728,33 @@ def _get_novel_other_pairs(self, rings) -> List[Tuple[Chem.Atom, Chem.Atom]]: pairs.append((ringcore, neigh)) return pairs + def _get_novel_other_pairs(self, mol, rings, cutoff: float) -> List[Tuple[Chem.Atom, Chem.Atom]]: + """ + similar to self._get_novel_ringcore_pairs... but opposite + It deals with bonded and close pairs. + + :param mol: + :param rings: output of `_get_expansion_data`. See that for details. + :type rings: List[Dict[str, List[Any]]] + :param cutoff: + :return: + """ + # ---------------------------------------------------------- + # scenario where they are closer than the cutoff + close_pairs = self._get_close_novel_others(mol, rings, cutoff) # 2.7889 ring diameter + 1.45 C-C bond + # ---------------------------------------------------------- + # scenario where they are bonded... + bonded_pairs = self._get_novel_other_bonded_pairs(rings) + # ------------ merge lists ----------- + return self.merge_pairing_lists(close_pairs + bonded_pairs) + + def _get_close_novel_others(self, + mol, + rings, + cutoff): + idx_pairs = self._get_close_novel_ring_other_indices(mol, rings, cutoff) + # filter out those that are bonded already to core atom. + return self._indices_to_atoms_n_cores(mol, idx_pairs) def _get_merging_penalties(self, mol, shape: Tuple[int, int], indices_ring): """ @@ -696,7 +792,7 @@ def _determine_mergers_novel_other_pair(self, other: Chem.Atom) -> List[Tuple[int, int]]: """ Like _determine_mergers_novel_ringcore_pair finds, bonds and marks for deletion. - It however finds atoms to absorb between a ring and non-ring atom. + It however finds atoms to absorb between a ring and a given non-ring atom. :param mol: :param ringcore: @@ -715,35 +811,30 @@ def _determine_mergers_novel_other_pair(self, pendist_matrix = penalties + distance_matrix pendistance = np.nanmin(pendist_matrix) if np.isnan(pendistance): - raise ValueError('This is impossible...') + self.journal.warning('(DetMergeNovOther). This is impossible...') + return [] else: # bonded p = np.where(pendist_matrix == pendistance) a = int(p[0][0]) b = int(p[1][0]) # absorb or bond distance = distance_matrix[a, b] - penalty = penalties[a, b] + penalty = penalties[a, b] # penalties were already applied. this is for msgs only if distance > 4: - raise ValueError(f'The bond between {a} and {b} too long {distance} ' + \ - f'from {indices_ring} and {indices_other}') + self.journal.warning(f'(DetMergeNovOther: {a}, {b}). ' + \ + f'The bond between {a} and {b} too long {distance} ' + \ + f'from {indices_ring} and {indices_other}') + return [] elif distance > absorption_distance: + self.journal.info(f'(DetMergeNovOther: {a}, {b}). A novel bonding to ring may be added. ' + \ + f'd: {distance} p: {penalty}') # get bond type present_bond = mol.GetBondBetweenAtoms(ringcore.GetIdx(), other.GetIdx()) - bt = present_bond.GetBondType() - if bt is None or bt == Chem.BondType.UNSPECIFIED: - bt = Chem.BondType.SINGLE - mol.AddBond(a, b, bt) - new_bond = mol.GetBondBetweenAtoms(a, b) - BondProvenance.set_bond(new_bond, 'original') - BondProvenance.copy_bond(present_bond, new_bond) - # This is no longer required: - # atom_a = mol.GetAtomWithIdx(a) - # atom_b = mol.GetAtomWithIdx(b) - # self._add_bond_if_possible(mol, atom_a, atom_b) - self.journal.info(f'A novel bonding to ring was added {distance} {penalty}') + self._add_bond_by_reference(mol, a, b, present_bond) else: # absorb the non-ring atom! - self.journal.info(f'An atom was absorbed to ring was added {distance} {penalty}') + self.journal.info(f'(DetMergeNovOther: {a}, {b}). An atom was absorbed to ring. ' + \ + f'd: {distance} p: {penalty}') if mol.GetAtomWithIdx(a).GetIntProp('_ori_i') == -1: self._copy_bonding(mol, a, b) self._mark_for_deletion(mol, b) @@ -753,6 +844,28 @@ def _determine_mergers_novel_other_pair(self, self._mark_for_deletion(mol, a) return [(b, a)] + def _add_bond_by_reference(self, mol, a, b, reference_bond): + """ + _copy_bonding copies all the bonds. THis just adds one like the reference bond. + It calls ``_add_bond_if_possible`` if its a closeness bond, i.e. reference_bond is None + It calls ``_add_bond_regardlessly`` if its an orginal one. + + :param mol: + :param a: + :param b: + :param reference_bond: + :return: + """ + atom_a = mol.GetAtomWithIdx(a) + atom_b = mol.GetAtomWithIdx(b) + if reference_bond is None: + self._add_bond_if_possible(mol, atom_a, atom_b, 'other_novel') + else: + bt = reference_bond.GetBondType() + if bt is None or bt == Chem.BondType.UNSPECIFIED: + bt = Chem.BondType.SINGLE + self._add_bond_regardlessly(mol, atom_a, atom_b, bt, BondProvenance.get_bond(reference_bond).name) + # ======== Emergency =============================================================================================== def _emergency_joining(self, mol): diff --git a/fragmenstein/monster/_combine.py b/fragmenstein/monster/_combine.py new file mode 100644 index 0000000..60962f6 --- /dev/null +++ b/fragmenstein/monster/_combine.py @@ -0,0 +1,67 @@ +######################################################################################################################## + +__doc__ = \ + """ +Combine = merge/join + """ + +######################################################################################################################## + +from rdkit import Chem + +from ._collapse_ring import _MonsterRing +from ._base import _MonsterBase +from ._communal import _MonsterCommunal +from ._merge import _MonsterMerge +from ..rectifier import Rectifier + + +######################################################################################################################## + +class _MonsterCombine(_MonsterRing, _MonsterMerge): + + def merge(self, keep_all=True, collapse_rings=True, joining_cutoff: int = 5): + """ + Merge/links the hits. (Main entrypoint) + + :param keep_all: + :param collapse_rings: + :param joining_cutoff: + :return: + """ + # The following override class declared attributes. + self.joining_cutoff = joining_cutoff + self.throw_on_discard = keep_all + # merge! + if collapse_rings: + col_hits = self.collapse_mols(self.hits) + self.keep_copies(col_hits, 'Collapsed hits') + else: + col_hits = self.hits + self.scaffold = self.simply_merge_hits(col_hits) + self.keep_copy(self.scaffold, 'merged template') + ## Discard can happen for other reasons than disconnect + if keep_all and len(self.unmatched): + raise ConnectionError(f'Could not combine with {self.unmatched} (>{self.joining_cutoff}') + # expand and fix + self.journal.debug(f'Merged') + if collapse_rings: + self.positioned_mol = self.expand_ring(self.scaffold) + # bonded_as_original=False no longer needed. + self.keep_copy(self.positioned_mol, 'expanded') + self.journal.debug(f'Expanded') + self.rectify() + self.journal.debug(f'Rectified') + return self + + def rectify(self): + recto = Rectifier(self.positioned_mol) + try: + recto.fix() + except ConnectionError: + self.journal.critical(f'This really odd cornercase: Rectifier broke the mol.') + mol = self._emergency_joining(recto.mol) + recto = Rectifier(mol) + recto.fix() + self.positioned_mol = recto.mol + self.keep_copies(recto.modifications, 'fixed') diff --git a/fragmenstein/monster/_communal.py b/fragmenstein/monster/_communal.py new file mode 100644 index 0000000..d1b234f --- /dev/null +++ b/fragmenstein/monster/_communal.py @@ -0,0 +1,454 @@ +from typing import Optional, List, Tuple, Union + +import numpy as np +from rdkit import Chem + +from ._modification_logging import _MonsterTracker +from .bond_provenance import BondProvenance + + +# _MonsterBase -> _MonsterTracker -> _MonsterCommunal + +class _MonsterCommunal(_MonsterTracker): + + # === Find closest ================================================================================================= + # dep methods: + + @staticmethod + def _closest__is_fullbonded(atom): + if atom.GetIsAromatic() and len(atom.GetNeighbors()) > 2: + return True + elif len(atom.GetNeighbors()) > 3: + return True + else: + return False + + @staticmethod + def _closest__is_ring_atom(atom): + if atom.GetIsAromatic(): + return True + elif atom.HasProp('_ori_i') and atom.GetIntProp('_ori_i') == -1: + if atom.HasProp('_bonds') and 'AROMATIC' in atom.GetProp('_bonds'): + return True # technically it could be non-aromatic (ring fusion). + else: + return False + else: + return False + + @staticmethod + def _closest__is_warhead_marked(atom): + return atom.HasProp('_Warhead') and atom.GetBoolProp('_Warhead') is True + + # func: https://stackoverflow.com/questions/41921255/staticmethod-object-is-not-callable + closeness_weights = [ + (_closest__is_warhead_marked.__func__, np.nan), + (_closest__is_fullbonded.__func__, 1.0), + (_closest__is_ring_atom.__func__, 0.5) + # is_triangle, 2.0 + ] + + def _find_closest(self, mol_A: Chem.Mol, mol_B: Chem.Mol) -> Tuple[Chem.RWMol, int, int, float]: + """ + first step in join_neighboring_mols + This is not to be confused with cls.find_closest_to_ligand + + :param mol_A: + :param mol_B: + :return: + """ + combo, candidates = self._find_all_closest(mol_A, mol_B) + return (combo, *candidates[0]) + + def _find_all_closest(self, mol_A: Chem.Mol, mol_B: Chem.Mol) -> Tuple[Chem.RWMol, List[Tuple[int, int, float]]]: + """ + See _find_closest + + :param mol_A: + :param mol_B: + :return: + """ + combo = Chem.RWMol(Chem.CombineMols(mol_A, mol_B)) + # ========= distance matrix pre-tweaks. + distance_matrix = self._get_distance_matrix(combo, mol_A, mol_B) + penalties = self._get_joining_penalties(combo, distance_matrix.shape) + # ========= get closest + pendist_matrix = penalties + distance_matrix + pendistance = np.nanmin(pendist_matrix) + if np.isnan(pendistance): + raise ConnectionError('This is impossible. Previous is absent??') + else: + candidates = [] + + def get_closest(pendistance): + p = np.where(pendist_matrix == pendistance) + anchor_A = int(p[0][0]) + anchor_B = int(p[1][0]) + distance = distance_matrix[anchor_A, anchor_B] + penalty = penalties[anchor_A, anchor_B] + self.journal.debug(f'Connecting {anchor_A} with {anchor_B}, {penalty} penalised distance of {distance}') + return anchor_A, anchor_B, distance + + anchor_A, anchor_B, distance = get_closest(pendistance) + candidates.append((anchor_A, anchor_B, distance)) + pendist_matrix[pendist_matrix > 1.] = np.nan + while pendistance < 1.: + pendist_matrix[[anchor_A, anchor_B], :] = np.nan + pendist_matrix[:, [anchor_A, anchor_B]] = np.nan + pendistance = np.nanmin(pendist_matrix) + if np.isnan(pendistance): + break + else: + anchor_A, anchor_B, distance = get_closest(pendistance) + candidates.append((anchor_A, anchor_B, distance)) + return combo, candidates + + def _get_distance_matrix(self, combo: Chem.Mol, A: Union[Chem.Mol, np.ndarray], + B: Union[Chem.Mol, np.ndarray]) -> np.ndarray: + """ + Called by ``_find_closest`` and ``_determine_mergers_novel_ringcore_pair`` in collapse ring (for expansion). + + """ + # TODO move to base once made. + # input type + if isinstance(A, Chem.Mol): + mol_A = A + A_idxs = np.arange(mol_A.GetNumAtoms()) + else: + mol_A = None + A_idxs = np.array(A) + if isinstance(B, Chem.Mol): + mol_B = B + B_idxs = np.arange(mol_B.GetNumAtoms()) + mol_A.GetNumAtoms() + else: + mol_B = None + B_idxs = np.array(B) + # make matrix + distance_matrix = Chem.Get3DDistanceMatrix(combo) + length = combo.GetNumAtoms() + # nan fill the self values + self._nan_fill_submatrix(distance_matrix, A_idxs) + self._nan_fill_submatrix(distance_matrix, B_idxs) + return distance_matrix + + def _nan_fill_others(self, mol: Chem.Mol, distance_matrix: np.array, good_indices: List[int]): + """ + Nan fill the inidices that are not the good_indices. + + :param mol: + :param distance_matrix: + :param good_indices: + :return: + """ + others = np.array(list(set(range(mol.GetNumAtoms())).difference(good_indices))) + distance_matrix[others, :] = np.nan + distance_matrix[:, others] = np.nan + + def _get_joining_penalties(self, combo: Chem.Mol, shape: Tuple[int, int]) -> np.ndarray: + """ + Called by ``_find_closest``. + THis is different from _get_merging_penalties + + :param combo: + :param shape: + :return: + """ + # penalise + penalties = np.zeros(shape) + for fun, weight in self.closeness_weights: + weigh_bool = np.array([fun(atom) for atom in combo.GetAtoms()]) + penalties[weigh_bool, :] += weight + penalties[:, weigh_bool] += weight + return penalties + + def _nan_fill_submatrix(self, matrix, indices): + """ + Given a square matrix, blank the self-submatrix of the group of indices + There is probably a better way to do this. + changed from _nan_submatrix as to nan is not a verb. + + :param matrix: + :param indices: + :return: + """ + dimension = matrix.shape[0] + bool_vector = np.zeros((dimension, 1)).astype(bool) + bool_vector[indices] = True + bool_matrix = np.tile(bool_vector, (1, dimension)) + logic = np.logical_and(bool_matrix, bool_matrix.transpose()) + matrix[logic] = np.nan + + # ============= Deletion =========================================================================================== + + def _mark_for_deletion(self, mol: Chem.Mol, i: int): + mol.GetAtomWithIdx(i).SetBoolProp('DELETE', True) + + def _delete_marked(self, mol: Chem.RWMol): + morituri = list(reversed(mol.GetAtomsMatchingQuery(Chem.rdqueries.HasPropQueryAtom('DELETE')))) + for atom in morituri: + mol.RemoveAtom(atom.GetIdx()) + + # ============= Other ============================================================================================== + + def _copy_bonding(self, mol, keeper_idx: int, reject_idx: int, force: Optional[bool] = None): + """ + formerly called `absorb`. Preps for absorbing. remove reject_idx separately. + So copy bonding from reject_idx to keeper_idx. + + :param mol: + :param keeper_idx: + :param reject_idx: + :param force: + :return: + """ + self.journal.debug(f'Copying atom bonding from {reject_idx} to {keeper_idx}, force={force}') + keeper = mol.GetAtomWithIdx(keeper_idx) + reject = mol.GetAtomWithIdx(reject_idx) + # prevent confusion when it comes to triangles + vertex = self._get_triangle(reject, keeper) + if vertex: + mol.RemoveBond(reject_idx, vertex) + # deal with neighbours of reject atom + for neighbor in reject.GetNeighbors(): + # collect bonding details between neighbour of reject and reject itself + neigh_idx = neighbor.GetIdx() + old_bond = mol.GetBondBetweenAtoms(reject_idx, neigh_idx) + bt = old_bond.GetBondType() + # forcing? + if force is not None: + force_bond = bool(force) + elif old_bond.HasProp('_IsRingBond'): + # the ring needs to be force! + force_bond = True + else: + force_bond = False + # mol.RemoveBond(j, n) + if keeper_idx == neigh_idx: # the neighbour is the keeper + continue + else: + # copy bond. The provenance should be 'other_novel' not the original vai + # provenance = BondProvenance.get_bond(old_bond) + if force_bond and mol.GetBondBetweenAtoms(keeper_idx, neigh_idx) is None: + self.journal.debug(f'... Forcing bond between {keeper_idx} and {neigh_idx} during bond copying') + self._add_bond_regardlessly(mol=mol, + first=keeper, + second=neighbor, + bond_type=bt, + provenance='other_novel' + ) + else: + self.journal.debug(f'... Potentially adding bond between {keeper_idx} and {neigh_idx} during bond copying') + self._add_bond_if_possible(mol=mol, + first=keeper, + second=neighbor, + provenance='other_novel') + + def _add_bond_regardlessly(self, mol, first: Chem.Atom, second: Chem.Atom, bond_type, provenance='other_novel'): + """ + This methods does no checking and operates dangerously! + + :param mol: + :param first: + :param second: + :param bond_type: + :param provenance: + :return: + """ + first_idx = first.GetIdx() + second_idx = second.GetIdx() + # add if absent... (error prevention) + present_bond = mol.GetBondBetweenAtoms(first_idx, second_idx) + if present_bond is None: + mol.AddBond(first_idx, second_idx, bond_type) + new_bond = mol.GetBondBetweenAtoms(first_idx, second_idx) + BondProvenance.set_bond(new_bond, provenance) + + def _assess_atom_for_possible_bonding(self, atom: Chem.Atom, bt: Chem.BondType) -> bool: + """ + Method for add_bond_if_possible + True means add, False means delete + + :param atom: + :param bt: + :return: + """ + n_neigh = sum([self._is_count_valid(neigh) for neigh in atom.GetNeighbors()]) + if atom.GetAtomicNum() > 8: + return True + elif atom.HasProp('DELETE'): # if it is to be deleted it should be fine. + return True + elif n_neigh <= 2 and atom.GetIsAromatic(): + return True, Chem.BondType.SINGLE + elif n_neigh <= 3 and not atom.GetIsAromatic(): + return True + else: + return False # too bonded already! + + def _add_bond_if_possible(self, mol, first: Chem.Atom, second: Chem.Atom, provenance='other_novel'): + """ + This method is used by _copy_bonding, but triggered when force=False + + :param mol: + :param first: + :param second: + :param provenance: + :return: + """ + # --- Prep + first_idx = first.GetIdx() + second_idx = second.GetIdx() + present_bond = mol.GetBondBetweenAtoms(first_idx, second_idx) + if second.HasProp('_ring_bond'): + bt = getattr(Chem.BondType, second.GetProp('_ring_bond')) + else: + bt = None + # === Bond already exists series ============================================ + # --- Bond already exists and not bond type is specified + if present_bond is not None and bt is None: + self.journal.debug(f'Bond between {first_idx} and {second_idx} already exists') + return True # exists + # --- Bond already exists but has an error + elif present_bond is not None and present_bond.GetBondType() is None: + present_bond.SetBondType(Chem.BondType.SINGLE) + return True + # --- Bond already exists and matches the expected bond type + elif present_bond is not None and bt.name == present_bond.GetBondType().name: + return True + # --- Bond already exists but does not match the expected bond type + elif present_bond is not None: + present_bond.SetBondType(bt) + return True + # === Assess if new bond should be added ============================================ + # --- Don't add if it would make a triangle + elif self._is_would_be_triangle(first, second): + self.journal.debug(f'Bond between {first_idx} and {second_idx} would make a triangle, skipping') + return False + # --- Don't add if it would make a square + elif self._is_would_be_square(first, second): + self.journal.debug(f'Bond between {first_idx} and {second_idx} would make a square, skipping') + return False + # --- Don't add if it would ruin the warhead + elif self._is_connected_warhead(second, first): + self.journal.debug(f'Bond between {first_idx} and {second_idx} would break a warhead, skipping') + return False + # --- New bond is green lit + elif self._assess_atom_for_possible_bonding(first, bt) and self._assess_atom_for_possible_bonding(second, bt): + mol.AddBond(first_idx, second_idx, bt if bt is not None else Chem.BondType.SINGLE) + new_bond = mol.GetBondBetweenAtoms(first_idx, second_idx) + BondProvenance.set_bond(new_bond, provenance) + return True + # --- New bond is no go + else: + # len(Chem.GetMolFrags(mol, sanitizeFrags=False)) ought to be checked. + # however, join_neighboring gets called by emergency bonding so should be fine. + return False # too bonded etc. + + # === conditional selectors ======================================================================================== + + def _is_would_be_triangle(self, first: Chem.Atom, second: Chem.Atom) -> bool: + """ + Get bool of whether two atoms share a common neighbor. Ie. joining them would make a triangle. + Direct bond does not count. + + :param first: + :param second: + :return: + """ + if self._get_triangle(first, second) is not None: + return True + else: + return False + + + def _is_would_be_square(self, first: Chem.Atom, second: Chem.Atom) -> bool: + """ + Get bool of whether two atoms share a common neighbor+over-neighbor. Ie. joining them would make a square. + Direct bond does not count. + + :param first: + :param second: + :return: + """ + for third in [neigh for neigh in second.GetNeighbors() if neigh.GetIdx() != first.GetIdx()]: + if self._is_would_be_triangle(first, third) is True: + return True + else: + return False + + def _get_triangle(self, first: Chem.Atom, second: Chem.Atom) -> Union[int, None]: + """ + Get the third atom... + + :param first: atom + :param second: atom + :return: atom index of third + """ + triang = self._get_triangles(first, second) + if triang: + return triang[0] + else: + return None + + def _get_triangles(self, first: Chem.Atom, second: Chem.Atom) -> Union[List[int], None]: + """ + Get the third atoms... (Square situation) + + :param first: atom + :param second: atom + :return: atom index of third + """ + get_neigh_idxs = lambda atom: [neigh.GetIdx() for neigh in atom.GetNeighbors() if + self._is_count_valid(neigh)] + f_neighs = get_neigh_idxs(first) + s_neighs = get_neigh_idxs(second) + a = set(f_neighs) - {first.GetIdx(), second.GetIdx()} + b = set(s_neighs) - {first.GetIdx(), second.GetIdx()} + others = list(a.intersection(b)) + if len(others) == 0: # is disjoined + return None + else: + return list(others) + + def _is_count_valid(self, atom: Chem.Atom) -> bool: + """ + Some atoms are not to be counted as they will be deleted. + + :param atom: + :return: + """ + if atom.HasProp('DELETE'): + return False + elif atom.HasProp('_ori_i') and atom.GetIntProp('_ori_i') == -1: + return False + else: + return True + + + def _get_square(self, first: Chem.Atom, second: Chem.Atom) -> Union[Tuple[int, int], None]: + for third in [neigh for neigh in second.GetNeighbors() if neigh.GetIdx() != first.GetIdx()]: + fourths = self._get_triangles(first, third) + if fourths and len(fourths) > 1: + fourth = [f for f in fourths if f != second.GetIdx()][0] + return third.GetIdx(), fourth + else: + return None + + def _is_connected_warhead(self, atom, anchor_atom): + if not atom.HasProp('_Warhead'): + return False + elif atom.GetBoolProp('_Warhead') == False: + return False + else: + # is it a single compound? + frags = Chem.GetMolFrags(atom.GetOwningMol(), sanitizeFrags=False) + if len(frags) == 1: + return True + else: + for frag in frags: + if atom.GetIdx() in frag and anchor_atom.GetIdx() in frag: + return True + elif atom.GetIdx() in frag: + return False # if the warhead is not connected pretend it is not a warhead. + else: + pass + else: + raise ValueError('I do not think this is possible.') \ No newline at end of file diff --git a/fragmenstein/monster/_join_neighboring.py b/fragmenstein/monster/_join_neighboring.py index e0d1e7f..8c1d6f3 100644 --- a/fragmenstein/monster/_join_neighboring.py +++ b/fragmenstein/monster/_join_neighboring.py @@ -4,9 +4,9 @@ import numpy as np from warnings import warn from .bond_provenance import BondProvenance -from ._base import _MonsterBaseMixin +from ._base import _MonsterBase -class _MonsterJoinNeighMixin(_MonsterBaseMixin): +class _MonsterJoinNeigh(_MonsterBase): def join_neighboring_mols(self, mol_A: Chem.Mol, mol_B: Chem.Mol): """ Joins two molecules by first calling _find_closest to find closest. diff --git a/fragmenstein/monster/_merge.py b/fragmenstein/monster/_merge.py new file mode 100644 index 0000000..039430d --- /dev/null +++ b/fragmenstein/monster/_merge.py @@ -0,0 +1,248 @@ +######################################################################################################################## + +__doc__ = \ + """ +Combine = merge/join + """ + +######################################################################################################################## + +from typing import Dict, Union, List, Optional, Tuple +from warnings import warn +import json + +import numpy as np +from collections import defaultdict, Counter + +from rdkit import Chem +from rdkit.Chem import AllChem, rdFMCS, rdMolAlign, rdmolops +from rdkit.Geometry.rdGeometry import Point3D +import numpy as np +from rdkit import Chem +from rdkit.Chem import AllChem, rdFMCS, rdMolAlign, rdmolops +from rdkit.Geometry.rdGeometry import Point3D +from typing import Optional, Dict, List, Any, Tuple, Union +from .bond_provenance import BondProvenance +import logging +from ..rectifier import Rectifier +import itertools +from .unmerge_mapper import Unmerge +from .bond_provenance import BondProvenance + +import json, itertools +from warnings import warn +from rdkit.Geometry.rdGeometry import Point3D +from collections import defaultdict +from rdkit import Chem +from rdkit.Chem import AllChem +from typing import Optional, Dict, List, Any, Tuple, Union, Callable +import numpy as np +from collections import Counter +from functools import partial +from .bond_provenance import BondProvenance +from ._communal import _MonsterCommunal +from .positional_mapping import GPM + +class _MonsterMerge(_MonsterCommunal, GPM): + def merge_pair(self, scaffold: Chem.Mol, fragmentanda: Chem.Mol, mapping: Optional = None) -> Chem.Mol: + """ + To specify attachments use ``.merge``. + To understand what is going on see ``.categorise`` + + :param scaffold: mol to be added to. + :param fragmentanda: mol to be fragmented + :param mapping: see ``get_positional_mapping``. Optional in _pre_fragment_pairs + :return: + """ + done_already = [] + if self._debug_draw: + print('Scaffold') + self.draw_nicely(scaffold) + print('To be added') + self.draw_nicely(fragmentanda) + fp = self._pre_fragment_pairs(scaffold, fragmentanda, mapping) + # confusingly these are hit indexed. + for anchor_index, attachment_details in fp.items(): + # anchor index is the fragment-to-added's internal atom that attaches + if anchor_index in done_already: + continue + # fix rings. + uniques = {atom.GetIdx() for atom in fragmentanda.GetAtoms() if + 'overlapping' not in atom.GetProp('_Category')} + team = self._recruit_team(fragmentanda, anchor_index, uniques) + other_attachments = list((team & set(fp.keys())) - {anchor_index}) + other_attachment_details = [] + for other in other_attachments: + other_attachment_details.append(fp[other]) + done_already.append(other) + scaffold = self._merge_part(scaffold, fragmentanda, + anchor_index=anchor_index, + attachment_details=attachment_details, + other_attachments=other_attachments, + other_attachment_details=other_attachment_details) + name_A = scaffold.GetProp('_Name') + name_B = fragmentanda.GetProp('_Name') + scaffold.SetProp('_Name', f'{name_A}-{name_B}') + if self._debug_draw: + print('Merged', scaffold.GetProp('_Name')) + self.draw_nicely(scaffold) + return scaffold + + def simply_merge_hits(self, hits: Optional[List[Chem.Mol]] = None) -> Chem.Mol: + """ + Recursively stick the hits together and average the positions. + This is the monster of automerging, full-merging mapping and partial merging mapping. + The latter however uses `partially_blend_hits` first. + The hits are not ring-collapsed and -expanded herein. + + :param hits: optionally give a hit list, else uses the attribute ``.hits``. + :return: the rdkit.Chem.Mol object that will fill ``.scaffold`` + """ + if hits is None: + hits = sorted(self.hits, key=lambda h: h.GetNumAtoms(), reverse=True) + for hit in hits: + BondProvenance.set_all_bonds(hit, 'original') + if self._debug_draw: + print('Merging: ', [hit.GetProp('_Name') for hit in hits]) + scaffold = Chem.Mol(hits[0]) + # first try + save_for_later = [] + for fragmentanda in hits[1:]: + try: + scaffold = self.merge_pair(scaffold, fragmentanda) + except ConnectionError: + save_for_later.append(fragmentanda) + # second try + join_later = [] + for fragmentanda in save_for_later: + try: + scaffold = self.merge_pair(scaffold, fragmentanda) + except ConnectionError: + join_later.append(fragmentanda) + # join (last ditch) + for fragmentanda in join_later: + try: + scaffold = self.join_neighboring_mols(scaffold, fragmentanda) + except ConnectionError: + self.unmatched.append(fragmentanda.GetProp("_Name")) + msg = f'Hit {fragmentanda.GetProp("_Name")} has no connections! Skipping!' + if self.throw_on_discard: + raise ConnectionError(msg) + else: + warn(msg) + return scaffold + + def _pre_fragment_pairs(self, scaffold: Chem.Mol, fragmentanda: Chem.Mol, A2B_mapping: Optional = None) \ + -> Dict[int, List[Dict]]: + """ + Returns + + {4: [{'idx': 5, + 'type': rdkit.Chem.rdchem.BondType.SINGLE, + 'idx_F': 5, + 'idx_S': 1}], ...} + + which is slight more than {5: [{'idx': 4, 'type': rdkit.Chem.rdchem.BondType.SINGLE}], ... from categories + + idx_F: fragmentanda index + idx_S: scaffold index + + required for self.merge, the key is the index of anchoring atom. + + Calls get_positional_mapping and _categorise. + + :param scaffold: mol to be added to. + :param fragmentanda: mol to be fragmented + :param A2B_mapping: see ``get_positional_mapping`` + :return: + """ + # get A2B mapping + if A2B_mapping is None: + A2B_mapping = self.get_positional_mapping(scaffold, fragmentanda) + get_key = lambda d, v: list(d.keys())[list(d.values()).index(v)] + if len(A2B_mapping) == 0: + raise ConnectionError('No overlap!') + # store alternative atom symbols. + for si, fi in A2B_mapping.items(): + sa = scaffold.GetAtomWithIdx(si) + sn = sa.GetSymbol() + fn = fragmentanda.GetAtomWithIdx(fi).GetSymbol() + if sn != fn: + sa.SetProp('_AltSymbol', fn) + # prepare. + uniques = set(range(fragmentanda.GetNumAtoms())) - set(A2B_mapping.values()) + categories = self._categorise(fragmentanda, uniques) + pairs = categories['pairs'] + for p in pairs: # pairs:Dict[List[Dict]] + for pp in pairs[p]: + pp['idx_F'] = pp['idx'] # less ambiguous: fragmentanda index + pp['idx_S'] = get_key(A2B_mapping, pp['idx']) # scaffold index + return pairs + + def _recruit_team(self, mol: Chem.Mol, starting: int, uniques: set, team: Optional[set] = None) -> set: + if team is None: + team = set() + team.add(starting) + for atom in mol.GetAtomWithIdx(starting).GetNeighbors(): + i = atom.GetIdx() + if i in uniques and i not in team: + team = self._recruit_team(mol, i, uniques, team) + return team + + def _categorise(self, mol: Chem.Mol, uniques: set) -> Dict[str, Union[set, Dict]]: + """ + What do the novel atoms do in terms of connectivity. + Complicated dict output (called ``categories`` in the methods). Really ought to be SetProp of the atoms. + + * ``uniques`` are set of atoms to classify on + * ``internals`` are unique atoms that are connected solely to unique atoms + * ``attachments`` are non-unique atoms to which a unique atom connects + * ``pairs`` is a dict of unique atom idx --> dict of ``idx`` --> attachment idx and ``type`` bond type. + + :param mol: molecule to describe + :param uniques: set of indices that are new to this molecule + :return: + """ + # + pairs = {} + internals = set() + attachments = set() + dummies = set() + for i in uniques: # novel atoms + unique_atom = mol.GetAtomWithIdx(i) + if unique_atom.GetSymbol() == self.dummy_symbol: + dummies.add(i) + neighbours = {n.GetIdx() for n in unique_atom.GetNeighbors()} + if len(neighbours - uniques) == 0: # unlessone of the connections is not unique. + internals.add(i) + else: + i_attached = neighbours - uniques + attachments |= i_attached + pairs[i] = [{'idx': j, + 'type': mol.GetBondBetweenAtoms(i, j).GetBondType()} for j in i_attached] + anchors = uniques - internals + # store for safekeeping + for atom in mol.GetAtoms(): + i = atom.GetIdx() + if i in internals: # novel and not connected + atom.SetProp('_Category', 'internal') + elif i in attachments: # not-novel but connected + atom.SetProp('_Category', 'overlapping-attachment') + elif i in pairs: # dict not set tho + atom.SetProp('_Category', 'internal-attachment') + else: # overlapping + atom.SetProp('_Category', 'overlapping') + if self._debug_draw: + high = list(internals) + list(attachments) + list(anchors) + color = {**{i: (0, 0.8, 0) for i in internals}, + **{i: (0, 0, 0.8) for i in attachments}, + **{i: (0.8, 0, 0.8) for i in anchors}} + print('Purple: anchor atoms, Blue: attachments, Green: internals') + self.draw_nicely(mol, highlightAtoms=high, highlightAtomColors=color) + print({atom.GetIdx(): atom.GetProp('_Category') for atom in mol.GetAtoms()}) + return dict(uniques=uniques, + internals=internals, + attachments=attachments, + pairs=pairs, + dummies=dummies + ) \ No newline at end of file diff --git a/fragmenstein/monster/_modification_logging.py b/fragmenstein/monster/_modification_logging.py new file mode 100644 index 0000000..9c2748a --- /dev/null +++ b/fragmenstein/monster/_modification_logging.py @@ -0,0 +1,28 @@ +""" +Keep a copy of the mol. +""" +from rdkit import Chem +from ._base import _MonsterBase +from typing import List + +class _MonsterTracker(_MonsterBase): + """ + _MonsterBase -> _MonsterTracker -> _MonsterCommunal + """ + + def keep_copy(self, mol: Chem.Mol, label=None): + copy = Chem.Mol(mol) + if label is None: + label = f'Mol#{len(self.modifications)}' + copy.SetProp('_Name', label) + self.modifications[label] = copy + + def keep_copies(self, mols: List[Chem.Mol], label=None): + for i, mol in enumerate(mols): + copy = Chem.Mol(mol) + if label is None: + this_label = f'Mol#{len(self.modifications)}' + else: + this_label = f'{label}#{i}' + copy.SetProp('_Name', this_label) + self.modifications[this_label] = copy diff --git a/fragmenstein/monster/_place.py b/fragmenstein/monster/_place.py new file mode 100644 index 0000000..e77b2cd --- /dev/null +++ b/fragmenstein/monster/_place.py @@ -0,0 +1,106 @@ +from ._blend_place import _MonsterBlend # inherits _MonsterCommunal <- _MonsterBase +from typing import * +from rdkit import Chem +from typing import Dict, Union, List, Optional, Tuple +from warnings import warn +import json + +import numpy as np +from collections import defaultdict, Counter + +from rdkit import Chem +from rdkit.Chem import AllChem, rdFMCS, rdMolAlign, rdmolops +from rdkit.Geometry.rdGeometry import Point3D +import numpy as np +from rdkit import Chem +from rdkit.Chem import AllChem, rdFMCS, rdMolAlign, rdmolops +from rdkit.Geometry.rdGeometry import Point3D +from typing import Optional, Dict, List, Any, Tuple, Union +from .bond_provenance import BondProvenance +import logging +from ..rectifier import Rectifier +import itertools +from .unmerge_mapper import Unmerge +from .bond_provenance import BondProvenance + +import json, itertools +from warnings import warn +from rdkit.Geometry.rdGeometry import Point3D +from collections import defaultdict +from rdkit import Chem +from rdkit.Chem import AllChem +from typing import Optional, Dict, List, Any, Tuple, Union, Callable +import numpy as np +from collections import Counter +from functools import partial +from .bond_provenance import BondProvenance +from ._base import _MonsterBase +from ._communal import _MonsterCommunal +from ._merge import _MonsterMerge +from ._collapse_ring import _MonsterRing + + +class _MonsterPlace(_MonsterBlend): + + def place(self, + mol: Chem.Mol, + attachment: Optional[Chem.Mol] = None, + merging_mode: str = 'none_permissive'): + """ + Positioned a given mol based on the hits. (Main entrypoint) + accepts the argument `merging_mode`, by default it is "permissive_none", + which calls `.no_blending(broad=True)`, + but "off" (does nothing except fill the attribute ``initial_mol``), + "full" (`.full_blending()`), + "partial" (`.partial_blending()`) + and "none" (`.no_blending()`) + are accepted. + + :param mol: + :param attachment: + :param merging_mode: + :return: + """ + self.initial_mol, self.attachment = self._parse_mol_for_place(mol, attachment) + # Reset + self.unmatched = [] + self.mol_options = [] + # do calculations + if merging_mode == 'off': + pass + elif merging_mode == 'full': + self.full_blending() + elif merging_mode == 'partial': + self.partial_blending() + elif merging_mode == 'none_permissive' or merging_mode == 'permissive_none': + self.no_blending(broad=True) + elif merging_mode == 'none': + self.no_blending() + else: + valid_modes = ('full', 'partial', 'none', 'none_permissive', 'off') + raise ValueError( + f"Merging mode can only be {'| '.join(valid_modes)}, not '{merging_mode}'") + return self + + def place_smiles(self, + smiles: str, + attachment: Optional[Chem.Mol] = None): + mol = Chem.MolFromSmiles(smiles) + self.place(mol=mol, attachment=attachment) + return self + + def _parse_mol_for_place(self, + mol: Chem.Mol, + attachment: Optional[Chem.Mol] = None): + # ------------- store mol --------------------------------------- + if mol.HasSubstructMatch(self.dummy) and attachment: + pass + elif mol.HasSubstructMatch(self.dummy): + warn('No attachment atom provided but dummy atom present --- ignoring.') + attachment = None + elif attachment: + warn('Attachment atom provided but dummy atom not present --- ignoring.') + attachment = None + else: + attachment = None + return mol, attachment diff --git a/fragmenstein/monster/_utility_mixin.py b/fragmenstein/monster/_utility.py similarity index 92% rename from fragmenstein/monster/_utility_mixin.py rename to fragmenstein/monster/_utility.py index 2cf9540..014bb67 100644 --- a/fragmenstein/monster/_utility_mixin.py +++ b/fragmenstein/monster/_utility.py @@ -1,20 +1,12 @@ ######################################################################################################################## - __doc__ = \ """ These are extras for the Monster step """ -__author__ = "Matteo Ferla. [Github](https://github.com/matteoferla)" -__email__ = "matteo.ferla@gmail.com" -__date__ = "2020 A.D." -__license__ = "MIT" -__version__ = "0.4" -__citation__ = "" - ######################################################################################################################## -from typing import List, Optional, Tuple +from typing import List, Optional, Tuple, Dict from warnings import warn from rdkit import Chem @@ -29,11 +21,14 @@ SVG = lambda *args, **kwargs: print('Install IPython...') display = lambda *args, **kwargs: print('Install IPython...') +from ._communal import _MonsterCommunal +from .positional_mapping import GPM + ######################################################################################################################## -class _MonsterUtil: +class _MonsterUtil(_MonsterCommunal, GPM): @classmethod def get_combined_rmsd(cls, followup_moved: Chem.Mol, followup_placed: Optional[Chem.Mol] = None, @@ -100,7 +95,7 @@ def num_common(self) -> int: def percent_common(self) -> int: return round(self.num_common / self.initial_mol.GetNumAtoms() * 100) - def stdev_from_mol(self, mol: Chem.Mol=None): + def stdev_from_mol(self, mol: Chem.Mol = None): """ these values are stored from Monster for scaffold, chimera and positioned_mol @@ -109,14 +104,13 @@ def stdev_from_mol(self, mol: Chem.Mol=None): """ if mol is None: mol = self.positioned_mol - return [atom.GetDoubleProp('_Stdev') if atom.HasProp('_Stdev') else 0 for atom in mol.GetAtoms()] + return [atom.GetDoubleProp('_Stdev') if atom.HasProp('_Stdev') else 0 for atom in mol.GetAtoms()] - def max_from_mol(self, mol: Chem.Mol=None): + def max_from_mol(self, mol: Chem.Mol = None): if mol is None: mol = self.positioned_mol return [atom.GetDoubleProp('_Max') if atom.HasProp('_Max') else 0 for atom in mol.GetAtoms()] - def origin_from_mol(self, mol: Chem.Mol = None): """ these values are stored from Monster for scaffold, chimera and positioned_mol @@ -140,7 +134,7 @@ def origin_from_mol(self, mol: Chem.Mol = None): origin.append([]) return origin - def guess_origins(self, mol: Chem.Mol = None, hits: Optional[List[Chem.Mol]]=None): + def guess_origins(self, mol: Chem.Mol = None, hits: Optional[List[Chem.Mol]] = None): """ Given a positioned mol guess its origins... @@ -156,7 +150,7 @@ def guess_origins(self, mol: Chem.Mol = None, hits: Optional[List[Chem.Mol]]=Non for hi, mi in self.get_positional_mapping(hit, mol).items(): atom = mol.GetAtomWithIdx(mi) if atom.HasProp('_Novel') and atom.GetBoolProp('_Novel') == True: - continue # flagged to avoid. + continue # flagged to avoid. elif atom.HasProp('_Origin') and atom.GetProp('_Origin') != 'none': origin = json.loads(atom.GetProp('_Origin')) else: @@ -164,7 +158,6 @@ def guess_origins(self, mol: Chem.Mol = None, hits: Optional[List[Chem.Mol]]=Non origin.append(f'{hname}.{hi}') atom.SetProp('_Origin', json.dumps(origin)) - # class attribute for next method _i = 0 @@ -175,7 +168,7 @@ def save_temp(self, mol): Chem.MolToMolFile(mol, f'debug_temp{self.i}.mol', kekulize=False) self._i += 1 - def save_commonality(self, filename:Optional[str]=None): + def save_commonality(self, filename: Optional[str] = None): """ Saves an SVG of the followup fragmenstein monster with the common atoms with the chimeric scaffold highlighted. @@ -196,7 +189,7 @@ def save_commonality(self, filename:Optional[str]=None): with open(filename, 'w') as w: w.write(d.GetDrawingText()) - def make_pse(self, filename='test.pse', extra_mols:Optional[Chem.Mol]=None): + def make_pse(self, filename='test.pse', extra_mols: Optional[Chem.Mol] = None): """ This is specifically for debugging the full fragment merging mode. For general use. Please use the Victor method ``make_pse``. @@ -207,8 +200,9 @@ def make_pse(self, filename='test.pse', extra_mols:Optional[Chem.Mol]=None): assert '.pse' in filename, 'Must be a pymol pse extension!' import pymol2 with pymol2.PyMOL() as pymol: - tints = iter(['wheat', 'palegreen', 'lightblue', 'paleyellow', 'lightpink', 'palecyan', 'lightorange', 'bluewhite']) - #pymol.cmd.bg_color('white') + tints = iter( + ['wheat', 'palegreen', 'lightblue', 'paleyellow', 'lightpink', 'palecyan', 'lightorange', 'bluewhite']) + # pymol.cmd.bg_color('white') for h, hit in enumerate(self.hits): pymol.cmd.read_molstr(Chem.MolToMolBlock(hit, kekulize=False), f'hit{h}') pymol.cmd.color(next(tints), f'hit{h} and name C*') @@ -226,7 +220,7 @@ def make_pse(self, filename='test.pse', extra_mols:Optional[Chem.Mol]=None): pymol.cmd.read_molstr(Chem.MolToMolBlock(mol, kekulize=False), f'opt{i}') pymol.cmd.color('grey50', f'opt{i} and name C*') pymol.cmd.hide('sticks') - pymol.cmd.hide('cartoon') # there should not be.... + pymol.cmd.hide('cartoon') # there should not be.... pymol.cmd.show('lines', 'not polymer') if self.chimera: pymol.cmd.show('sticks', 'chimera') @@ -259,7 +253,7 @@ def draw_nicely(self, mol, show=True, **kwargs) -> Draw.MolDraw2DSVG: AllChem.Compute2DCoords(x) Chem.SanitizeMol(x, catchErrors=True) try: - #x = Chem.MolFromSmiles(Chem.MolToSmiles(x, kekuleSmiles=False), sanitize=False) + # x = Chem.MolFromSmiles(Chem.MolToSmiles(x, kekuleSmiles=False), sanitize=False) Draw.PrepareAndDrawMolecule(d, x, **kwargs) d.FinishDrawing() if show: @@ -269,8 +263,7 @@ def draw_nicely(self, mol, show=True, **kwargs) -> Draw.MolDraw2DSVG: warn(f'*{err.__class__.__name__}* : {err}') display(x) - - def mmff_minimise(self, mol: Optional[Chem.Mol]=None) -> None: + def mmff_minimise(self, mol: Optional[Chem.Mol] = None) -> None: """ Minimises a mol, or self.positioned_mol if not provided, with MMFF constrained to 2 Å. Gets called by Victor if the flag .monster_mmff_minimisation is true during PDB template construction. @@ -283,7 +276,7 @@ def mmff_minimise(self, mol: Optional[Chem.Mol]=None) -> None: elif mol is None: mol = self.positioned_mol else: - pass # mol is fine + pass # mol is fine # protect for atom in mol.GetAtomsMatchingQuery(Chem.rdqueries.AtomNumEqualsQueryAtom(0)): atom.SetBoolProp('_IsDummy', True) @@ -321,5 +314,3 @@ def mmff_minimise(self, mol: Optional[Chem.Mol]=None) -> None: # deprotect for atom in mol.GetAtomsMatchingQuery(Chem.rdqueries.HasPropQueryAtom('_IsDummy')): atom.SetAtomicNum(0) - - diff --git a/fragmenstein/monster/positional_mapping.py b/fragmenstein/monster/positional_mapping.py index 637c16a..d315f6b 100644 --- a/fragmenstein/monster/positional_mapping.py +++ b/fragmenstein/monster/positional_mapping.py @@ -5,31 +5,29 @@ Positional mapping """ -__author__ = "Matteo Ferla. [Github](https://github.com/matteoferla)" -__email__ = "matteo.ferla@gmail.com" -__date__ = "2020 A.D." -__license__ = "MIT" -__version__ = "0.4" -__citation__ = "" - ######################################################################################################################## - from rdkit import Chem from typing import Dict, List, Tuple import numpy as np + # ========= Get positional mapping ================================================================================= class GPM: + """ + This class simply contains ``get_positional_mapping`` and is inherited both by Monster and Unmerge. + ``get_positional_mapping`` teturns a map to convert overlapping atom of A onto B + """ + cutoff = 2 @classmethod def get_positional_mapping(cls, mol_A: Chem.Mol, mol_B: Chem.Mol, dummy_w_dummy=True) -> Dict[int, int]: """ Returns a map to convert overlapping atom of A onto B - Cutoff 2 Å. + Cutoff 2 Å (see class attr.) :param mol_A: first molecule (Chem.Mol) will form keys :param mol_B: second molecule (Chem.Mol) will form values @@ -114,7 +112,7 @@ def _gpm_covert(cls, array: np.array, cutoff: float) -> Dict[int, int]: :param cutoff: :return: """ - ## find the closest + # find the closest mapping = {} while 1 == 1: d = np.nanmin(array) @@ -125,4 +123,4 @@ def _gpm_covert(cls, array: np.array, cutoff: float) -> Dict[int, int]: mapping[int(f)] = int(s) # np.int64 --> int array[f, :] = np.ones(array.shape[1]) * 999 array[:, s] = np.ones(array.shape[0]) * 999 - return mapping \ No newline at end of file + return mapping From 7ccfc501c72173b3530c1ed3365b011fac0f6013 Mon Sep 17 00:00:00 2001 From: matteoferla Date: Wed, 10 Feb 2021 15:40:58 +0000 Subject: [PATCH 25/32] :pencil: typo --- fragmenstein/igor/_igor_min_mixin.py | 7 ------- fragmenstein/rectifier/_ring.py | 4 ++-- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/fragmenstein/igor/_igor_min_mixin.py b/fragmenstein/igor/_igor_min_mixin.py index 314d565..9c2b183 100644 --- a/fragmenstein/igor/_igor_min_mixin.py +++ b/fragmenstein/igor/_igor_min_mixin.py @@ -5,13 +5,6 @@ Minimisers """ -__author__ = "Matteo Ferla. [Github](https://github.com/matteoferla)" -__email__ = "matteo.ferla@gmail.com" -__date__ = "2020 A.D." -__license__ = "MIT" -__version__ = "0.4" -__citation__ = "" - ######################################################################################################################## from typing import Dict, List, Optional, Tuple, Union, Sequence diff --git a/fragmenstein/rectifier/_ring.py b/fragmenstein/rectifier/_ring.py index 24a2256..79b6413 100644 --- a/fragmenstein/rectifier/_ring.py +++ b/fragmenstein/rectifier/_ring.py @@ -64,7 +64,7 @@ def _prevent_weird_rings(self): elif len(shared) < self.atoms_in_bridge_cutoff and \ self.atoms_in_bridge_cutoff >= 2 \ and len(ring_A) == len(ring_B): - # monsterantene/norbornane/tropinone kind of thing + # adamantene/norbornane/tropinone kind of thing self.journal.warning(f'This molecule ({self.rwmol.GetProp("_Name")}) has a bridge: leaving') pass # ideally check if planar... elif len(shared) == 1: @@ -96,7 +96,7 @@ def _prevent_weird_rings(self): self.journal.warning(f'mysterious ring system {len(ring_A)} + {len(ring_B)}') pass # ???? elif len(shared) < self.atoms_in_bridge_cutoff: - # monsterantene/norbornane/tropinone kind of thing + # adamantene/norbornane/tropinone kind of thing self.journal.warning(f'This molecule ({self.rwmol.GetProp("_Name")}) has a bridge: leaving') pass # ideally check if planar... else: From 8607f1e68cac46ea9165386789984fa0e43d0590 Mon Sep 17 00:00:00 2001 From: matteoferla Date: Wed, 10 Feb 2021 18:46:11 +0000 Subject: [PATCH 26/32] :fire: finished spring clean --- fragmenstein/monster/__init__.py | 10 ++- fragmenstein/monster/_base.py | 6 +- fragmenstein/monster/_blend_place.py | 74 +++++-------------- fragmenstein/monster/_collapse_ring.py | 45 ++++++++--- fragmenstein/monster/_combine.py | 8 +- fragmenstein/monster/_communal.py | 13 +++- fragmenstein/monster/_join_neighboring.py | 14 +++- fragmenstein/monster/_merge.py | 62 ++++------------ fragmenstein/monster/_modification_logging.py | 20 +++-- fragmenstein/monster/_place.py | 45 +++-------- fragmenstein/monster/unmerge_mapper.py | 60 ++++----------- fragmenstein/victor/__init__.py | 31 ++++---- .../victor/_victor_automerge_mixin.py | 15 ++-- fragmenstein/victor/_victor_base_mixin.py | 3 +- fragmenstein/victor/_victor_utils_mixin.py | 4 +- test.py | 33 ++++++++- 16 files changed, 192 insertions(+), 251 deletions(-) diff --git a/fragmenstein/monster/__init__.py b/fragmenstein/monster/__init__.py index f53637a..d87b72f 100644 --- a/fragmenstein/monster/__init__.py +++ b/fragmenstein/monster/__init__.py @@ -34,14 +34,20 @@ ######################################################################################################################## +# --- independent of Monster ------------------------------------------------------------------------------------------- +from .positional_mapping import GPM +from .bond_provenance import BondProvenance +from .unmerge_mapper import Unmerge + + +# --- Monster --------------------------------------------------------------------------------------------------------- + from ._communal import _MonsterCommunal from ._utility import _MonsterUtil # Adds extras, not called by place/combine from ._combine import _MonsterCombine # inherits _MonsterCommunal adds the combine method from ._place import _MonsterPlace # inherits _MonsterCommunal adds the combine method -################################################################## - class Monster(_MonsterUtil, _MonsterPlace, _MonsterCombine): """ This creates a stitched together monster. diff --git a/fragmenstein/monster/_base.py b/fragmenstein/monster/_base.py index 6aa10e4..b048761 100644 --- a/fragmenstein/monster/_base.py +++ b/fragmenstein/monster/_base.py @@ -60,21 +60,19 @@ class _MonsterBase: def __init__(self, hits: List[Chem.Mol], - debug_draw: bool = False, - average_position=False): + average_position: bool=False): """ Initialisation starts Monster, but it does not do any mergers or placements. This is changed in revision 0.6 (previously `mol` was specified for the latter) :param hits: - :param debug_draw: :param average_position: """ # ==== hits =========================================== # fix_hits: assert Chem.Mol, fix name if needed and store positions (see ``store_positions``) self.hits = self.fix_hits(hits) # list of hits # ==== other ========================================== - self._debug_draw = debug_draw # Jupyter notebook only. + #self._debug_draw has been taken over by ``modifications`` and ``journal`` self.average_position = average_position # ==== To do be filled ================================ # List[str] diff --git a/fragmenstein/monster/_blend_place.py b/fragmenstein/monster/_blend_place.py index c6141e9..19dc168 100644 --- a/fragmenstein/monster/_blend_place.py +++ b/fragmenstein/monster/_blend_place.py @@ -1,3 +1,11 @@ +######################################################################################################################## +__doc__ = \ + """ +This is inherited by MonsterPlace + """ + +######################################################################################################################## + from rdkit.Chem import rdmolops import itertools @@ -65,25 +73,19 @@ def no_blending(self, broad=False) -> None: um = Unmerge(followup=self.initial_mol, mols=self.hits, maps=maps, - no_discard=self.throw_on_discard, - _debug_draw=self._debug_draw) + no_discard=self.throw_on_discard) self.scaffold = um.combined - self.mol_options = um.combined_alternatives + # self.mol_options\ + combined_alternative = um.combined_alternatives full_atom_map = um.combined_map self.unmatched = [m.GetProp('_Name') for m in um.disregarded] if self.throw_on_discard and len(self.unmatched): raise ConnectionError(f'{self.unmatched} was rejected.') self.chimera = um.combined_bonded - if self._debug_draw: - print('followup to scaffold', full_atom_map) - print('followup') - self.draw_nicely(self.initial_mol) - print('scaffold') - self.draw_nicely(self.scaffold) + self.journal.debug(f'followup to scaffold {full_atom_map}') placed = self.place_from_map(atom_map=full_atom_map) self.positioned_mol = self.posthoc_refine(placed) - # ================= Blend hits =================================================================================== def partially_blend_hits(self, hits: Optional[List[Chem.Mol]] = None) -> List[Chem.Mol]: @@ -135,9 +137,7 @@ def get_dodgies(skippers): for h1, h2 in itertools.combinations(hits, 2): inter_mapping[(h1.GetProp('_Name'), h2.GetProp('_Name'))] = self.get_positional_mapping(h1, h2) dodgy_names = get_dodgies([]) - if self._debug_draw: - print('******** These combine badly') - print(dodgy_names) + self.warning(f'These combiend badly: {dodgy_names}') dodgies = [hit for hit in hits if hit.GetProp('_Name') in dodgy_names] mergituri = [hit for hit in hits if hit.GetProp('_Name') not in dodgy_names] merged = self.simply_merge_hits(mergituri) @@ -154,8 +154,6 @@ def get_dodgies(skippers): # propagate alternatives while self.propagate_alternatives(combinations) != 0: pass - if self._debug_draw: - print('alternatives propagated') return combinations def propagate_alternatives(self, fewer): @@ -210,9 +208,8 @@ def template_sorter(t: List[Chem.Mol]) -> float: atom_map, mode = self.get_mcs_mapping(template, self.initial_mol) # get_mcs_mapping returns a dict going from template index to initial. mapx[template.GetProp('_Name')] = (atom_map, mode) - if self._debug_draw: - print( - f"With {template.GetProp('_Name')}, {len(atom_map)} atoms map using mode {self.matching_modes.index(mode)}") + self.journal.debug(f"With {template.GetProp('_Name')}, "+\ + "{len(atom_map)} atoms map using mode {self.matching_modes.index(mode)}") ## pick best template self.mol_options = sorted(self.mol_options, key=template_sorter) ## Check if missing atoms can be explained by a different one with no overlap @@ -261,7 +258,6 @@ def template_sorter(t: List[Chem.Mol]) -> float: # else: # return {n: path} - def _prevent_two_bonds_on_dummy(self, mol: Chem.RWMol): """ The case '*(C)C' is seen legitimately in some warheads... but in most cases these are not. @@ -299,8 +295,6 @@ def make_chimera(self, min_mode_index=0) -> Chem.Mol: atom_map, mode = self.get_mcs_mapping(self.scaffold, self.initial_mol, min_mode_index=min_mode_index) follow = {**{k: str(v) for k, v in mode.items()}, 'N_atoms': len(atom_map)} self.journal.debug(f"scaffold-followup: {follow}") - if self._debug_draw: - self.draw_nicely(self.initial_mol, highlightAtoms=atom_map.values()) # make the scaffold more like the followup to avoid weird matches. chimera = Chem.RWMol(self.scaffold) for scaff_ai, follow_ai in atom_map.items(): @@ -358,10 +352,6 @@ def place_from_map(self, mol: Chem.Mol = None, atom_map: Optional[Dict] = None) msg = {**{k: str(v) for k, v in mode.items()}, 'N_atoms': len(atom_map)} self.journal.debug(f"followup-chimera' = {msg}") rdMolAlign.AlignMol(sextant, self.chimera, atomMap=list(atom_map.items()), maxIters=500) - # debug print - if self._debug_draw: - self.draw_nicely(mol, highlightAtoms=dict(atom_map).keys()) - self.draw_nicely(self.chimera, highlightAtoms=dict(atom_map).values()) # place atoms that have a known location putty = Chem.Mol(sextant) pconf = putty.GetConformer() @@ -386,9 +376,6 @@ def place_from_map(self, mol: Chem.Mol = None, atom_map: Optional[Dict] = None) # I be using a sextant for dead reckoning! # variables: sextant unique team categories = self._categorise(sextant, uniques) - # debug print - if self._debug_draw: - print('internal', categories['internals']) done_already = [] # multi-attachment issue. for unique_idx in categories['pairs']: # attachment unique indices # check the index was not done already (by virtue of a second attachment) @@ -412,10 +399,8 @@ def place_from_map(self, mol: Chem.Mol = None, atom_map: Optional[Dict] = None) sights.add((r, r)) rdMolAlign.AlignMol(sextant, putty, atomMap=list(sights), maxIters=500) sconf = sextant.GetConformer() - # debug print - if self._debug_draw: - print(f'alignment atoms for {unique_idx} ({team}): {sights}') - self.draw_nicely(sextant, highlightAtoms=[a for a, b in sights]) + self.journal.debug(f'alignment atoms for {unique_idx} ({team}): {sights}') + # self.draw_nicely(sextant, highlightAtoms=[a for a, b in sights]) # copy position over for atom_idx in team: pconf.SetAtomPosition(atom_idx, sconf.GetAtomPosition(atom_idx)) @@ -458,17 +443,11 @@ def _merge_part(self, scaffold: Chem.Mol, fragmentanda: Chem.Mol, anchor_index: bonds_to_frag += [fragmentanda.GetBondBetweenAtoms(anchor_index, attachment_index).GetIdx()] bonds_to_frag += [fragmentanda.GetBondBetweenAtoms(oi, oad[0]['idx_F']).GetIdx() for oi, oad in zip(other_attachments, other_attachment_details)] - if self._debug_draw and other_attachments: - print('ring!', other_attachments) - print('ring!', other_attachment_details) f = Chem.FragmentOnBonds(fragmentanda, bonds_to_frag, addDummies=False) frag_split = [] fragmols = Chem.GetMolFrags(f, asMols=True, fragsMolAtomMapping=frag_split, sanitizeFrags=False) - if self._debug_draw: - print('Fragment splits') - print(frag_split) # Get the fragment of interest. ii = 0 for mol_N, indices in enumerate(frag_split): @@ -491,15 +470,8 @@ def _merge_part(self, scaffold: Chem.Mol, fragmentanda: Chem.Mol, anchor_index: # for absent in self._get_mystery_ori_i(frag): # old2future[absent] = scaffold_attachment_index # self._renumber_original_indices(frag, old2future) - if self._debug_draw: - print('Fragment to add') - self.draw_nicely(frag) combo = Chem.RWMol(rdmolops.CombineMols(scaffold, frag)) scaffold_anchor_index = frag_anchor_index + scaffold.GetNumAtoms() - if self._debug_draw: - print('Pre-merger') - print(scaffold_anchor_index, attachment_details, anchor_index, scaffold.GetNumAtoms()) - self.draw_nicely(combo) for detail in attachment_details: # scaffold_anchor_index : atom index in scaffold that needs to be added to scaffold_attachment_index # but was originally attached to attachment_index in fragmentanda. @@ -519,17 +491,10 @@ def _merge_part(self, scaffold: Chem.Mol, fragmentanda: Chem.Mol, anchor_index: combo.AddBond(scaffold_anchor_index, scaffold_attachment_index, bond_type) new_bond = combo.GetBondBetweenAtoms(scaffold_anchor_index, scaffold_attachment_index) # BondProvenance.set_bond(new_bond, '???') - if self._debug_draw: - print( - f"Added additional {bond_type.name} bond between {scaffold_attachment_index} and {scaffold_anchor_index} " + \ - f"(formerly {indices.index(oi)})") Chem.SanitizeMol(combo, sanitizeOps=Chem.rdmolops.SanitizeFlags.SANITIZE_ADJUSTHS + Chem.rdmolops.SanitizeFlags.SANITIZE_SETAROMATICITY, catchErrors=True) - if self._debug_draw: - print('Merged') - self.draw_nicely(combo) self._prevent_two_bonds_on_dummy(combo) scaffold = combo.GetMol() return scaffold @@ -546,10 +511,8 @@ def transfer_ring_data(self, donor: Chem.Atom, acceptor: Chem.Atom): # data = donor pass - # ========= Other ================================================================================================== - def posthoc_refine(self, scaffold, indices: Optional[List[int]] = None) -> Chem.Mol: """ Averages the overlapping atoms. @@ -615,8 +578,6 @@ def get_mcs_mappings(self, molA, molB, min_mode_index: int = 0) -> Tuple[List[Di for i, mode in enumerate(self.matching_modes): if i < min_mode_index: continue - if self._debug_draw: - print(f'Trying mode {mode}') lax = self._get_atom_maps(molA, molB, **mode) # remove the lax matches that disobey neolax = [l for l in lax if any([len(set(s) - set(l)) == 0 for s in strict])] @@ -662,7 +623,6 @@ def _get_atom_maps(self, molA, molB, **mode) -> List[List[Tuple[int, int]]]: def _get_atom_map(self, molA, molB, **mode) -> List[Tuple[int, int]]: return self._get_atom_maps(molA, molB, **mode)[0] - def pretweak(self) -> None: """ What if the fragments were prealigned slightly? Really bad things. diff --git a/fragmenstein/monster/_collapse_ring.py b/fragmenstein/monster/_collapse_ring.py index 650537a..fe7736d 100644 --- a/fragmenstein/monster/_collapse_ring.py +++ b/fragmenstein/monster/_collapse_ring.py @@ -22,14 +22,13 @@ from rdkit import Chem from rdkit.Geometry.rdGeometry import Point3D -from ._communal import _MonsterCommunal from ._join_neighboring import _MonsterJoinNeigh from .bond_provenance import BondProvenance ######################################################################################################################## -class _MonsterRing(_MonsterCommunal, _MonsterJoinNeigh): +class _MonsterRing( _MonsterJoinNeigh): def collapse_mols(self, mols: List[Chem.Mol]): mols = [self.collapse_ring(mol) for mol in mols] @@ -390,7 +389,7 @@ def _add_novel_bonding(self, mol: Chem.RWMol, rings: List[Dict[str, List[Any]]]) :return: """ self.journal.debug('Adding novel bonding (if any)...') - # ===== Deal with Ring on ring bonding + # ===== Deal with Ring on ring bonding ------------------------------------------ novel_ringcore_pairs = self._get_novel_ringcore_pairs(mol, rings, cutoff=1.5) # these is a list of Chem.Atom pairs. for ringcore_A, ringcore_B in novel_ringcore_pairs: @@ -398,7 +397,7 @@ def _add_novel_bonding(self, mol: Chem.RWMol, rings: List[Dict[str, List[Any]]]) f'{ringcore_A.GetIdx()} and {ringcore_B.GetIdx()}') # _determine_mergers_novel_ringcore_pair finds mergers self._determine_mergers_novel_ringcore_pair(mol, ringcore_A, ringcore_B) - # ===== Deal with Ring on other bonding + # ===== Deal with Ring on other bonding ------------------------------------------ # formerly: _infer_bonding_by_proximity novel_other_pairs = self._get_novel_other_pairs(mol, rings, 1.0) for ringcore, other in novel_other_pairs: @@ -406,7 +405,7 @@ def _add_novel_bonding(self, mol: Chem.RWMol, rings: List[Dict[str, List[Any]]]) f'ring marker {ringcore.GetIdx()} and non-ring {other.GetIdx()}') # _determine_mergers_novel_ringcore_pair finds, bonds and marks for deletion. self._determine_mergers_novel_other_pair(mol, ringcore, other) - # ===== Clean up + # ===== Clean up ------------------------------------------------------------------ self._delete_marked(mol) # =========== dependant methods ================================================================================= @@ -517,7 +516,7 @@ def merge_pairing_lists(self, ai = atom_a.GetIdx() bi = atom_b.GetIdx() if ai == bi: - self.journal.debug(f'Bond to self incident with {ai} (ring? {atom_a.HasProp("_current_is")})') + self.journal.debug(f'Bond to self incident with {ai} (ring? {atom_a.HasProp("_current_is") == 1})') continue if ringcore_first and atom_a.HasProp('_current_is') and not atom_b.HasProp('_current_is'): ringcore = ai @@ -786,6 +785,19 @@ def _get_merging_penalties(self, mol, shape: Tuple[int, int], indices_ring): penalties[:, i] = np.nan return penalties + def _get_distance(self, atom_a: Chem.Atom, atom_b: Chem.Atom) -> np.float: + """ + Not sure where doing it manually is quicker than getting the whole 3D distance table. + + :param atom_a: + :param atom_b: + :return: + """ + conf = atom_a.GetOwningMol().GetConformer() + get_pos = lambda atom: np.array(conf.GetAtomPosition(atom.GetIdx())) + return np.linalg.norm(get_pos(atom_a) - get_pos(atom_b)) + + def _determine_mergers_novel_other_pair(self, mol: Chem.RWMol, ringcore: Chem.Atom, @@ -799,24 +811,37 @@ def _determine_mergers_novel_other_pair(self, :param other: :return: """ - absorption_distance = 1. # Å + # ---- Prep data. indices_ring = json.loads(ringcore.GetProp('_current_is')) - indices_other = [other.GetIdx()] + index_other = other.GetIdx() + indices_other = [index_other] + index_core = ringcore.GetIdx() distance_matrix = self._get_distance_matrix(mol, indices_ring, indices_other) # currently in `_join_neighboring`. self._nan_fill_others(mol, distance_matrix, indices_ring + indices_other) # merging penalties penalties = self._get_merging_penalties(mol, distance_matrix.shape, indices_ring) + core_absorption_distance = 1.5 # Å between ring core and other. 2.8 Å is diameter. + core_other_distance = self._get_distance(ringcore, other) + if core_other_distance < core_absorption_distance: + # ------ Within ring must go. No penalties. + self.journal.debug(f'(DetMergeNovOther *{index_core}, {index_other}). Other is within ring. Forcing absoption') + absorption_distance = 9999 + pendist_matrix = distance_matrix + else: + # ------ Assess cases normally. + absorption_distance = 1. # Å between ring atom and other. + pendist_matrix = penalties + distance_matrix # get closest pair. - pendist_matrix = penalties + distance_matrix pendistance = np.nanmin(pendist_matrix) if np.isnan(pendistance): - self.journal.warning('(DetMergeNovOther). This is impossible...') + self.journal.warning(f'(DetMergeNovOther*{index_core}, {index_other}). This is impossible...') return [] else: # bonded p = np.where(pendist_matrix == pendistance) a = int(p[0][0]) b = int(p[1][0]) + assert index_other in (a, b), 'CRITICIAL: Matrix error!' # absorb or bond distance = distance_matrix[a, b] penalty = penalties[a, b] # penalties were already applied. this is for msgs only diff --git a/fragmenstein/monster/_combine.py b/fragmenstein/monster/_combine.py index 60962f6..b70eb3d 100644 --- a/fragmenstein/monster/_combine.py +++ b/fragmenstein/monster/_combine.py @@ -20,7 +20,7 @@ class _MonsterCombine(_MonsterRing, _MonsterMerge): - def merge(self, keep_all=True, collapse_rings=True, joining_cutoff: int = 5): + def combine(self, keep_all=True, collapse_rings=True, joining_cutoff: int = 5): """ Merge/links the hits. (Main entrypoint) @@ -38,15 +38,15 @@ def merge(self, keep_all=True, collapse_rings=True, joining_cutoff: int = 5): self.keep_copies(col_hits, 'Collapsed hits') else: col_hits = self.hits - self.scaffold = self.simply_merge_hits(col_hits) - self.keep_copy(self.scaffold, 'merged template') + self.positioned_mol = self.simply_merge_hits(col_hits) + self.keep_copy(self.positioned_mol, 'merged template') ## Discard can happen for other reasons than disconnect if keep_all and len(self.unmatched): raise ConnectionError(f'Could not combine with {self.unmatched} (>{self.joining_cutoff}') # expand and fix self.journal.debug(f'Merged') if collapse_rings: - self.positioned_mol = self.expand_ring(self.scaffold) + self.positioned_mol = self.expand_ring(self.positioned_mol) # bonded_as_original=False no longer needed. self.keep_copy(self.positioned_mol, 'expanded') self.journal.debug(f'Expanded') diff --git a/fragmenstein/monster/_communal.py b/fragmenstein/monster/_communal.py index d1b234f..c80ea5b 100644 --- a/fragmenstein/monster/_communal.py +++ b/fragmenstein/monster/_communal.py @@ -1,3 +1,11 @@ +######################################################################################################################## +__doc__ = \ + """ +This is inherited by all three parents of the place/combine/other group + """ + +######################################################################################################################## + from typing import Optional, List, Tuple, Union import numpy as np @@ -37,7 +45,7 @@ def _closest__is_ring_atom(atom): @staticmethod def _closest__is_warhead_marked(atom): - return atom.HasProp('_Warhead') and atom.GetBoolProp('_Warhead') is True + return atom.HasProp('_Warhead') == 1 and atom.GetBoolProp('_Warhead') is True # func: https://stackoverflow.com/questions/41921255/staticmethod-object-is-not-callable closeness_weights = [ @@ -90,7 +98,8 @@ def get_closest(pendistance): anchor_A, anchor_B, distance = get_closest(pendistance) candidates.append((anchor_A, anchor_B, distance)) - pendist_matrix[pendist_matrix > 1.] = np.nan + with np.errstate(invalid='ignore'): + pendist_matrix[pendist_matrix > 1.] = np.nan while pendistance < 1.: pendist_matrix[[anchor_A, anchor_B], :] = np.nan pendist_matrix[:, [anchor_A, anchor_B]] = np.nan diff --git a/fragmenstein/monster/_join_neighboring.py b/fragmenstein/monster/_join_neighboring.py index 8c1d6f3..30e2ef7 100644 --- a/fragmenstein/monster/_join_neighboring.py +++ b/fragmenstein/monster/_join_neighboring.py @@ -1,12 +1,20 @@ +######################################################################################################################## +__doc__ = \ + """ +This is inherited by both place and combine via _MonsterMerge + """ + +######################################################################################################################## + from rdkit import Chem from rdkit.Geometry.rdGeometry import Point3D from typing import Tuple, List, Dict, Optional, Union import numpy as np from warnings import warn from .bond_provenance import BondProvenance -from ._base import _MonsterBase +from ._communal import _MonsterCommunal -class _MonsterJoinNeigh(_MonsterBase): +class _MonsterJoinNeigh(_MonsterCommunal): def join_neighboring_mols(self, mol_A: Chem.Mol, mol_B: Chem.Mol): """ Joins two molecules by first calling _find_closest to find closest. @@ -23,8 +31,6 @@ def join_neighboring_mols(self, mol_A: Chem.Mol, mol_B: Chem.Mol): mol = self._join_atoms(combo, anchor_A, anchor_B, distance, linking=True) for anchor_A, anchor_B, distance in candidates[1:]: mol = self._join_atoms(combo, anchor_A, anchor_B, distance, linking=False) - - mol.SetProp('_Name', mol_A.GetProp('_Name') + '~' + mol_B.GetProp('_Name')) return mol diff --git a/fragmenstein/monster/_merge.py b/fragmenstein/monster/_merge.py index 039430d..9f1a971 100644 --- a/fragmenstein/monster/_merge.py +++ b/fragmenstein/monster/_merge.py @@ -7,43 +7,17 @@ ######################################################################################################################## -from typing import Dict, Union, List, Optional, Tuple +from typing import Optional, Dict, List, Union from warnings import warn -import json -import numpy as np -from collections import defaultdict, Counter - -from rdkit import Chem -from rdkit.Chem import AllChem, rdFMCS, rdMolAlign, rdmolops -from rdkit.Geometry.rdGeometry import Point3D -import numpy as np from rdkit import Chem -from rdkit.Chem import AllChem, rdFMCS, rdMolAlign, rdmolops -from rdkit.Geometry.rdGeometry import Point3D -from typing import Optional, Dict, List, Any, Tuple, Union -from .bond_provenance import BondProvenance -import logging -from ..rectifier import Rectifier -import itertools -from .unmerge_mapper import Unmerge -from .bond_provenance import BondProvenance -import json, itertools -from warnings import warn -from rdkit.Geometry.rdGeometry import Point3D -from collections import defaultdict -from rdkit import Chem -from rdkit.Chem import AllChem -from typing import Optional, Dict, List, Any, Tuple, Union, Callable -import numpy as np -from collections import Counter -from functools import partial +from ._join_neighboring import _MonsterJoinNeigh from .bond_provenance import BondProvenance -from ._communal import _MonsterCommunal from .positional_mapping import GPM -class _MonsterMerge(_MonsterCommunal, GPM): + +class _MonsterMerge(_MonsterJoinNeigh, GPM): def merge_pair(self, scaffold: Chem.Mol, fragmentanda: Chem.Mol, mapping: Optional = None) -> Chem.Mol: """ To specify attachments use ``.merge``. @@ -55,11 +29,6 @@ def merge_pair(self, scaffold: Chem.Mol, fragmentanda: Chem.Mol, mapping: Option :return: """ done_already = [] - if self._debug_draw: - print('Scaffold') - self.draw_nicely(scaffold) - print('To be added') - self.draw_nicely(fragmentanda) fp = self._pre_fragment_pairs(scaffold, fragmentanda, mapping) # confusingly these are hit indexed. for anchor_index, attachment_details in fp.items(): @@ -83,9 +52,7 @@ def merge_pair(self, scaffold: Chem.Mol, fragmentanda: Chem.Mol, mapping: Option name_A = scaffold.GetProp('_Name') name_B = fragmentanda.GetProp('_Name') scaffold.SetProp('_Name', f'{name_A}-{name_B}') - if self._debug_draw: - print('Merged', scaffold.GetProp('_Name')) - self.draw_nicely(scaffold) + self.keep_copy(scaffold, 'pair_merged') return scaffold def simply_merge_hits(self, hits: Optional[List[Chem.Mol]] = None) -> Chem.Mol: @@ -102,8 +69,7 @@ def simply_merge_hits(self, hits: Optional[List[Chem.Mol]] = None) -> Chem.Mol: hits = sorted(self.hits, key=lambda h: h.GetNumAtoms(), reverse=True) for hit in hits: BondProvenance.set_all_bonds(hit, 'original') - if self._debug_draw: - print('Merging: ', [hit.GetProp('_Name') for hit in hits]) + self.journal.debug(f"Merging: {[hit.GetProp('_Name') for hit in hits]}") scaffold = Chem.Mol(hits[0]) # first try save_for_later = [] @@ -232,14 +198,14 @@ def _categorise(self, mol: Chem.Mol, uniques: set) -> Dict[str, Union[set, Dict] atom.SetProp('_Category', 'internal-attachment') else: # overlapping atom.SetProp('_Category', 'overlapping') - if self._debug_draw: - high = list(internals) + list(attachments) + list(anchors) - color = {**{i: (0, 0.8, 0) for i in internals}, - **{i: (0, 0, 0.8) for i in attachments}, - **{i: (0.8, 0, 0.8) for i in anchors}} - print('Purple: anchor atoms, Blue: attachments, Green: internals') - self.draw_nicely(mol, highlightAtoms=high, highlightAtomColors=color) - print({atom.GetIdx(): atom.GetProp('_Category') for atom in mol.GetAtoms()}) + # if self._debug_draw: # depracated... but this could be useful... + # high = list(internals) + list(attachments) + list(anchors) + # color = {**{i: (0, 0.8, 0) for i in internals}, + # **{i: (0, 0, 0.8) for i in attachments}, + # **{i: (0.8, 0, 0.8) for i in anchors}} + # print('Purple: anchor atoms, Blue: attachments, Green: internals') + # self.draw_nicely(mol, highlightAtoms=high, highlightAtomColors=color) + # print({atom.GetIdx(): atom.GetProp('_Category') for atom in mol.GetAtoms()}) return dict(uniques=uniques, internals=internals, attachments=attachments, diff --git a/fragmenstein/monster/_modification_logging.py b/fragmenstein/monster/_modification_logging.py index 9c2748a..189df2e 100644 --- a/fragmenstein/monster/_modification_logging.py +++ b/fragmenstein/monster/_modification_logging.py @@ -1,6 +1,12 @@ -""" +######################################################################################################################## + +__doc__ = \ + """ Keep a copy of the mol. -""" + """ + +######################################################################################################################## + from rdkit import Chem from ._base import _MonsterBase from typing import List @@ -15,7 +21,12 @@ def keep_copy(self, mol: Chem.Mol, label=None): if label is None: label = f'Mol#{len(self.modifications)}' copy.SetProp('_Name', label) - self.modifications[label] = copy + if label not in self.modifications: + self.modifications[label] = copy + else: + label += '_' + self.keep_copy(mol, label) + def keep_copies(self, mols: List[Chem.Mol], label=None): for i, mol in enumerate(mols): @@ -24,5 +35,4 @@ def keep_copies(self, mols: List[Chem.Mol], label=None): this_label = f'Mol#{len(self.modifications)}' else: this_label = f'{label}#{i}' - copy.SetProp('_Name', this_label) - self.modifications[this_label] = copy + self.keep_copy(mol, this_label) diff --git a/fragmenstein/monster/_place.py b/fragmenstein/monster/_place.py index e77b2cd..63972a4 100644 --- a/fragmenstein/monster/_place.py +++ b/fragmenstein/monster/_place.py @@ -1,43 +1,18 @@ -from ._blend_place import _MonsterBlend # inherits _MonsterCommunal <- _MonsterBase -from typing import * -from rdkit import Chem -from typing import Dict, Union, List, Optional, Tuple -from warnings import warn -import json +######################################################################################################################## -import numpy as np -from collections import defaultdict, Counter +__doc__ = \ + """ +Place followup + """ -from rdkit import Chem -from rdkit.Chem import AllChem, rdFMCS, rdMolAlign, rdmolops -from rdkit.Geometry.rdGeometry import Point3D -import numpy as np -from rdkit import Chem -from rdkit.Chem import AllChem, rdFMCS, rdMolAlign, rdmolops -from rdkit.Geometry.rdGeometry import Point3D -from typing import Optional, Dict, List, Any, Tuple, Union -from .bond_provenance import BondProvenance -import logging -from ..rectifier import Rectifier -import itertools -from .unmerge_mapper import Unmerge -from .bond_provenance import BondProvenance +######################################################################################################################## -import json, itertools +from typing import Optional from warnings import warn -from rdkit.Geometry.rdGeometry import Point3D -from collections import defaultdict + from rdkit import Chem -from rdkit.Chem import AllChem -from typing import Optional, Dict, List, Any, Tuple, Union, Callable -import numpy as np -from collections import Counter -from functools import partial -from .bond_provenance import BondProvenance -from ._base import _MonsterBase -from ._communal import _MonsterCommunal -from ._merge import _MonsterMerge -from ._collapse_ring import _MonsterRing + +from ._blend_place import _MonsterBlend # inherits _MonsterCommunal <- _MonsterBase class _MonsterPlace(_MonsterBlend): diff --git a/fragmenstein/monster/unmerge_mapper.py b/fragmenstein/monster/unmerge_mapper.py index d8e1901..51e11c4 100644 --- a/fragmenstein/monster/unmerge_mapper.py +++ b/fragmenstein/monster/unmerge_mapper.py @@ -47,9 +47,11 @@ class Unmerge(GPM): pick = 0 # override to pick not the first(0) best match. distance_cutoff = 3 #: how distance is too distant in Å - def __init__(self, followup: Chem.Mol, mols: List[Chem.Mol], maps: Dict[str, List[Dict[int, int]]], - no_discard:bool=False, - _debug_draw: bool = False): + def __init__(self, + followup: Chem.Mol, + mols: List[Chem.Mol], + maps: Dict[str, List[Dict[int, int]]], + no_discard:bool=False): """ @@ -60,7 +62,6 @@ def __init__(self, followup: Chem.Mol, mols: List[Chem.Mol], maps: Dict[str, Lis :param maps: can be generated outseide of Monster by ``.make_maps``. :type maps: Dict[List[Dict[int, int]]] :param no_discard: do not allow any to be discarded - :param _debug_draw: """ self.followup = followup self.mols = mols @@ -68,7 +69,6 @@ def __init__(self, followup: Chem.Mol, mols: List[Chem.Mol], maps: Dict[str, Lis self.no_discard = no_discard if self.no_discard: self.max_strikes = 100 - self._debug_draw = _debug_draw accounted_for = set() self.c_map_options = [] self.c_options = [] @@ -81,8 +81,6 @@ def __init__(self, followup: Chem.Mol, mols: List[Chem.Mol], maps: Dict[str, Lis others = deque(self.mols) for s in range(len(self.mols)): others.rotate(1) - if self._debug_draw: - print(f"Rotated, new first : {others[0].GetProp('_Name')}") self.unmerge_inner(Chem.Mol(), {}, list(others), []) else: # pre sort others = sorted(self.mols, key=accounted_sorter, reverse=True) @@ -112,14 +110,14 @@ def __init__(self, followup: Chem.Mol, mols: List[Chem.Mol], maps: Dict[str, Lis equals = [j for j in indices if goodness_sorter(j) == ref] if len(equals) > 1: log.warning(f'There are {len(equals)} equally good mappings.') - if self._debug_draw: - print(f'## Option #{i} for combinations:') - for j in range(len(self.c_options)): - mol = self.c_options[j] - m = self.c_map_options[j] - d = self.c_disregarded_options[j] - dv = self.measure_map(mol, m) - print(j, [dd.GetProp('_Name') for dd in d], len(m), np.mean(dv), np.max(dv), self.offness(mol, m)) + # if self._debug_draw: + # print(f'## Option #{i} for combinations:') + # for j in range(len(self.c_options)): + # mol = self.c_options[j] + # m = self.c_map_options[j] + # d = self.c_disregarded_options[j] + # dv = self.measure_map(mol, m) + # print(j, [dd.GetProp('_Name') for dd in d], len(m), np.mean(dv), np.max(dv), self.offness(mol, m)) self.combined = self.c_options[i] self.combined_alternatives = [self.c_options[j] for j in equals if j != i] self.combined_map = self.c_map_options[i] @@ -208,8 +206,6 @@ def unmerge_inner(self, """ # stop if len(others) == 0: - if self._debug_draw: - print('************************ (stored)') self.store(combined=combined, combined_map=combined_map, disregarded=disregarded) return None # prevent issues. @@ -227,21 +223,12 @@ def unmerge_inner(self, o_present = set(o_map.keys()) label = f'{oname} ({oi + 1}/{ot})' if len(o_map) == 0: - if self._debug_draw: - print(f'{label} unmapped') possible_map = {} elif len(o_present - accounted_for) == 0: - if self._debug_draw: - print(o_present, accounted_for) - print(f'{label} unnovel') possible_map = {} elif combined.GetNumAtoms() == 0: - if self._debug_draw: - print(f'{label} first one') possible_map = o_map else: - if self._debug_draw: - print(f'{label} assessment') possible_map = self.get_possible_map(other=other, label=label, o_map=o_map, @@ -266,14 +253,10 @@ def judge_n_move_on(self, combined, combined_map, other, possible_map, others, d """ if len(possible_map) == 0: # reject - if self._debug_draw: - print('>> reject') combined = Chem.Mol(combined) disregarded = [*disregarded, other] # new obj else: # accept - if self._debug_draw: - print(f'>> accept: {possible_map}') combined_map = {**combined_map, **possible_map} # new obj combined = Chem.CombineMols(combined, other) # new obj name = '-'.join([m.GetProp('_Name') for m in (combined, other) if m.HasProp('_Name')]) @@ -315,18 +298,12 @@ def get_possible_map(self, c = inter_map[o] # equivalent index of combined if c not in combined_map.values(): # the other atom does not contribute - if self._debug_draw: - print(f'{label} - {i} accounted, but no contrib') strikes += 1 elif self.get_key(combined_map, c) == i: pass # that is fine. else: # no it's a different atom - if self._debug_draw: - print(f'{label} - {i} accounted, diff atom') strikes += 1 else: # this position does not overlaps. Yet atom is accounted for. - if self._debug_draw: - print(f'{label} - {i} accounted, no overlap') strikes += 1 elif o not in inter_map: # new atom that does not overlap @@ -335,16 +312,11 @@ def get_possible_map(self, # overlaps but the overlap was not counted possible_map[i] = combined.GetNumAtoms() + o else: # mismatch! - if self._debug_draw: - print(f'{label} - {i} mismatch') + log.debug(f'{label} - {i} mismatch') strikes += 1 if strikes >= self.max_strikes: - if self._debug_draw: - print(f'{label} got {strikes} strikes') return {} elif not self.check_possible_distances(other, possible_map, combined, combined_map, cutoff=self.distance_cutoff): - if self._debug_draw: - print(f'{label} gives too long bonds') return {} else: return possible_map @@ -377,12 +349,8 @@ def bond(self): nci = self.combined_map[ni] bond_type = self.followup.GetBondBetweenAtoms(fi, ni).GetBondType() if not putty.GetBondBetweenAtoms(ci, nci): - if self._debug_draw: - print(fi, ni, 'bond new') putty.AddBond(ci, nci, bond_type) else: - if self._debug_draw: - print(fi, ni, 'bond added') putty.GetBondBetweenAtoms(ci, nci).SetBondType(bond_type) return putty.GetMol() diff --git a/fragmenstein/victor/__init__.py b/fragmenstein/victor/__init__.py index 810e0e2..9b992a6 100644 --- a/fragmenstein/victor/__init__.py +++ b/fragmenstein/victor/__init__.py @@ -69,7 +69,7 @@ class Victor(_VictorUtilsMixin, _VictorValidateMixin, _VictorAutomergeMixin): The need for atomnames is actually not for the code but to allow lazy tweaks and analysis downstream (say typing in pymol: `show sphere, name CX`). Adding a 'constraint' to an entry will apply that constraint. - ``monster_debug_draw:bool`` and ``monster_merging_mode:str`` are class attributes that control Monster. + ``monster_merging_mode:str`` is class attributes that control Monster. """ @@ -119,7 +119,7 @@ def __init__(self, self.mol = None self.constraint = None self.monster = None - self.modifications = [] # used by automerger only + self.modifications = {} # used by automerger only self.unminimised_pdbblock = None self.igor = None self.minimised_pdbblock = None @@ -221,7 +221,6 @@ def _analyse(self) -> None: # monster_throw_on_discard controls if disconnected. Monster.throw_on_discard = self.monster_throw_on_discard self.monster = Monster(hits=self.hits, - debug_draw=self.monster_debug_draw, average_position=self.monster_average_position) self.monster.place(mol=self.mol, attachment=attachment, @@ -681,17 +680,17 @@ def _checkpoint_alpha(self): def _checkpoint_bravo(self): self._log_warnings() self.journal.debug(f'{self.long_name} - saving mols from monster') - if self.monster.scaffold is not None: - scaffold_file = os.path.join(self.work_path, self.long_name, self.long_name + '.scaffold.mol') - Chem.MolToMolFile(self.monster.scaffold, scaffold_file, kekulize=False) - if self.monster.scaffold.HasProp('parts'): - disregard = json.loads(self.monster.scaffold.GetProp('parts')) - self.journal.info(f'{self.long_name} - disregarded {disregard}') - else: - disregard = [] - if self.monster.chimera is not None: - chimera_file = os.path.join(self.work_path, self.long_name, self.long_name + '.chimera.mol') - Chem.MolToMolFile(self.monster.chimera, chimera_file, kekulize=False) + # if self.monster.scaffold is not None: + # scaffold_file = os.path.join(self.work_path, self.long_name, self.long_name + '.scaffold.mol') + # Chem.MolToMolFile(self.monster.scaffold, scaffold_file, kekulize=False) + # if self.monster.scaffold.HasProp('parts'): + # disregard = json.loads(self.monster.scaffold.GetProp('parts')) + # self.journal.info(f'{self.long_name} - disregarded {disregard}') + # else: + # disregard = [] + # if self.monster.chimera is not None: + # chimera_file = os.path.join(self.work_path, self.long_name, self.long_name + '.chimera.mol') + # Chem.MolToMolFile(self.monster.chimera, chimera_file, kekulize=False) if self.monster.positioned_mol is not None: pos_file = os.path.join(self.work_path, self.long_name, self.long_name + '.positioned.mol') Chem.MolToMolFile(self.monster.positioned_mol, pos_file, kekulize=False) @@ -707,8 +706,8 @@ def _checkpoint_bravo(self): data = {'smiles': self.smiles, 'origin': self.monster.origin_from_mol(self.monster.positioned_mol), 'stdev': self.monster.stdev_from_mol(self.monster.positioned_mol)} - if disregard: - data['disregard'] = disregard + # if disregard: + # data['disregard'] = disregard with open(frag_file, 'w') as w: json.dump(data, w) self._log_warnings() diff --git a/fragmenstein/victor/_victor_automerge_mixin.py b/fragmenstein/victor/_victor_automerge_mixin.py index e5eb8c8..9396c96 100644 --- a/fragmenstein/victor/_victor_automerge_mixin.py +++ b/fragmenstein/victor/_victor_automerge_mixin.py @@ -87,7 +87,7 @@ def combine(cls, self.constraint = None self.monster = None # ====== debug: absent in main mode. - self.modifications = [] # list of the various steps during fragment merging mode. + self.modifications = {} # list of the various steps during fragment merging mode. # ====== self.unminimised_pdbblock = None self.igor = None @@ -112,20 +112,15 @@ def combine(cls, def _combine_main(self): attachment = self._get_attachment_from_pdbblock() if self.is_covalent else None self.monster = Monster(hits=self.hits, - debug_draw=self.monster_debug_draw, average_position=self.monster_average_position ) self.monster.modifications = self.modifications - self.monster.merge(keep_all=self.monster_throw_on_discard, - collapse_rings=True, - joining_cutoff=self.monster_joining_cutoff # Å - ) + self.monster.combine(keep_all=self.monster_throw_on_discard, + collapse_rings=True, + joining_cutoff=self.monster_joining_cutoff # Å + ) self.mol = self.monster.positioned_mol self.smiles = Chem.MolToSmiles(self.mol) - if self.monster_debug_draw: - picture = Chem.CombineMols(Chem.CombineMols(self.hits[0], self.hits[1]), self.monster.positioned_mol) - AllChem.Compute2DCoords(picture) - self.monster.draw_nicely(picture) # making folder. self._make_output_folder() # paramterise diff --git a/fragmenstein/victor/_victor_base_mixin.py b/fragmenstein/victor/_victor_base_mixin.py index ff08abf..c7c5ee2 100644 --- a/fragmenstein/victor/_victor_base_mixin.py +++ b/fragmenstein/victor/_victor_base_mixin.py @@ -21,7 +21,6 @@ class _VictorBaseMixin: quick_renanimation = False # thorugh reanimation? monster_merging_mode = 'none_permissive' - monster_debug_draw = False monster_average_position = False monster_joining_cutoff = 5. # Å monster_throw_on_discard = False @@ -105,7 +104,7 @@ def __init__(self): self.mol = 'Chem.Mol' self.constraint = 'Constraint' self.monster = 'Monster' - self.modifications = [] + self.modifications = {} self.unminimised_pdbblock = str() self.igor = 'Igor' self.minimised_pdbblock = str() diff --git a/fragmenstein/victor/_victor_utils_mixin.py b/fragmenstein/victor/_victor_utils_mixin.py index 96ce667..903df5b 100644 --- a/fragmenstein/victor/_victor_utils_mixin.py +++ b/fragmenstein/victor/_victor_utils_mixin.py @@ -385,8 +385,8 @@ def make_steps_pse(self, filename: str='step.pse'): with pymol2.PyMOL() as pymol: for hit in self.hits: pymol.cmd.read_molstr(Chem.MolToMolBlock(hit, kekulize=False), hit.GetProp('_Name')) - for i, mod in enumerate(self.modifications): - pymol.cmd.read_molstr(Chem.MolToMolBlock(mod, kekulize=False), f'step{i}') + for label, mod in self.modifications: + pymol.cmd.read_molstr(Chem.MolToMolBlock(mod, kekulize=False), re.sub('[^\w_]', '_', label)) pymol.cmd.save(os.path.join(self.work_path, self.long_name, filename)) # =================== extract_mols ================================================================================= diff --git a/test.py b/test.py index 6c55c1b..89f90db 100644 --- a/test.py +++ b/test.py @@ -11,6 +11,7 @@ from fragmenstein import Monster, Victor, Igor, Rectifier from fragmenstein.mpro import MProVictor from typing import * +import numpy as np # ====================================================================================================================== @@ -239,7 +240,7 @@ def test_phenylene(self): aft = Chem.GetMolFrags(fragged, asMols=True, sanitizeFrags=False)[0] Chem.SanitizeMol(aft) # merge them - mol = Monster([fore, aft]).merge().positioned_mol + mol = Monster([fore, aft]).combine().positioned_mol after = Chem.MolToSmiles(mol) self.assertEqual(before, after) @@ -272,7 +273,7 @@ def make_mol(self, smiles: str) -> Chem.Mol: dummy.SetAtomicNum(0) return mol - def make_pair_by_split(self, conjoined: Chem.Mol, atom_idx: int) -> Tuple[Chem.Mol]: + def make_pair_by_split(self, conjoined: Chem.Mol, atom_idx: int) -> Tuple[Chem.Mol,Chem.Mol]: # make overlapping mols by getting a single molecule, and split it # this gives more control over Chem.rdMolAlign.AlignMol as this may overlap other atoms. # negative weights does not work... @@ -296,6 +297,30 @@ def test_merge_on_same_dummy(self): self.assertEqual(len(dummy.GetNeighbors()), 1) self.assertEqual(len(Chem.GetMolFrags(merger)), 1) + def translate(self, mol, x=0, y=0, z=0): + """ + Translates the molecule in place + + :param mol: + :param x: + :param y: + :param z: + :return: + """ + translation = np.array([[1, 0, 0, x], + [0, 1, 0, y], + [0, 0, 1, z], + [0, 0, 0, 1]], dtype=np.double) + AllChem.TransformConformer(mol.GetConformer(0), translation) + + def test_join(self): + wanted = 'c1ccc(Oc2ccccc2)cc1' + benzene = Chem.MolFromSmiles('c1ccccc1') + AllChem.EmbedMolecule(benzene) + moved = Chem.Mol(benzene) + self.translate(moved, x=5) + found = Chem.MolToSmiles(Monster([benzene, moved]).combine().positioned_mol) + self.assertEqual(wanted, found, 'The joining differs') # ---------------------------------------------------------------------------------------------------------------------- class UnresolvedProblems(unittest.TestCase): @@ -328,7 +353,7 @@ def test_supplementary1_to_recto_fail_A(self): Chem.SanitizeMol(chlorobutane) chlorobutane.SetProp('_Name', '2-chlorobutane') # merge - monster = Monster(hits=[toluene, chlorobutane]).merge(keep_all=False) + monster = Monster(hits=[toluene, chlorobutane]).combine(keep_all=False) # ====== self.assertEqual(Chem.MolToSmiles(chlorotoluene), Chem.MolToSmiles(monster.positioned_mol)) # CC(Cl)CCc1ccccc1 @@ -358,7 +383,7 @@ def test_supplementary2_to_recto_fail_A(self): Chem.SanitizeMol(chloropentane) chloropentane.SetProp('_Name', '2-chloropentane') # - monster = Monster(hits=[xylene, chloropentane]).merge(keep_all=False) + monster = Monster(hits=[xylene, chloropentane]).combine(keep_all=False) # ====== self.assertEqual(Chem.MolToSmiles(chloroxylene), Chem.MolToSmiles(monster.positioned_mol)) From b70b543712dbf86930de376399985d2dad0af819 Mon Sep 17 00:00:00 2001 From: matteoferla Date: Thu, 11 Feb 2021 16:12:49 +0000 Subject: [PATCH 27/32] :name_badge: Next version is 0.6 --- documentation/{changelog_0.5.md => changelog_0.6.md} | 0 setup.py | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename documentation/{changelog_0.5.md => changelog_0.6.md} (100%) diff --git a/documentation/changelog_0.5.md b/documentation/changelog_0.6.md similarity index 100% rename from documentation/changelog_0.5.md rename to documentation/changelog_0.6.md diff --git a/setup.py b/setup.py index b73eaf0..70b8383 100644 --- a/setup.py +++ b/setup.py @@ -19,7 +19,7 @@ setup( name='Fragmenstein', - version='0.5', + version='0.6', packages=['fragmenstein'], install_requires=['numpy'], extras_require={'minimization': ['rdkit_to_params'], From cb2dfd03bf0b1b3572a3c9debef9410a88a61d47 Mon Sep 17 00:00:00 2001 From: matteoferla Date: Thu, 11 Feb 2021 17:24:39 +0000 Subject: [PATCH 28/32] :fire: further cleanups --- documentation/changelog_0.6.md | 15 +- fragmenstein/monster/__init__.py | 108 ++++++++-- fragmenstein/monster/_base.py | 29 +-- fragmenstein/monster/_blend_place.py | 187 +++++------------- fragmenstein/monster/_collapse_ring.py | 26 ++- fragmenstein/monster/_combine.py | 5 +- fragmenstein/monster/_communal.py | 57 +++--- fragmenstein/monster/_join_neighboring.py | 7 +- fragmenstein/monster/_merge.py | 229 +++++++++++++++++----- fragmenstein/monster/_utility.py | 24 ++- fragmenstein/monster/unmerge_mapper.py | 48 ++++- 11 files changed, 461 insertions(+), 274 deletions(-) diff --git a/documentation/changelog_0.6.md b/documentation/changelog_0.6.md index cb6ab5b..8fd8d84 100644 --- a/documentation/changelog_0.6.md +++ b/documentation/changelog_0.6.md @@ -12,16 +12,25 @@ or `place_smiles` for a SMILES. While to do a merger monster = Monster(hits) - monster.merge() + monster.combine() monster.positioned_mol Additionally, the attribute `modifications` was added/expanded, so that intermediate steps are stored for potential inspection. +It is a dictionary, but since 3.6 dict is ordered and `.keep_copy(mol, label)` prevents over-writes. +This includes `scaffold` (the template) and `chimera` (the template with the atom symbols adapted), +which are no longer attributes. + +Equally viable alternatives are stored in a list + + monster.mol_options + +`combine` still calls `simply_merge_hits`, which is used by placement too and merges by fragmentation +—unlike atom-ring absorption events. The fact that two different approaches are present is just historical. -`merge` still calls `simply_merge_hits`. If one wanted to merge two or more hits, independently of those in `.hits` attribute and without ring collapsing and rectification etc. -`simply_merge_hits` is still the one: +`simply_merge_hits` is still the method to use: monster = Monster([]) monster.simply_merge_hits([molA, molB]) diff --git a/fragmenstein/monster/__init__.py b/fragmenstein/monster/__init__.py index d87b72f..b131512 100644 --- a/fragmenstein/monster/__init__.py +++ b/fragmenstein/monster/__init__.py @@ -51,32 +51,108 @@ class Monster(_MonsterUtil, _MonsterPlace, _MonsterCombine): """ This creates a stitched together monster. - For initilialisation for either placing or merging, it needs a list of hits (rdkit.Chem.Mol). + For initilialisation for either placing or combining, it needs a list of hits (rdkit.Chem.Mol). + + Note, the hits have to be 3D embedded as present in the protein —it would defeat the point otherwise! + For a helper method to extract them from crystal structures see `Victor.extract_mol`. The calculation are done either by place or merge. ## Place - monster.place(mol) - Given a RDKit molecule and a series of hits it makes a spatially stitched together version of the initial molecule based on the hits. - The reason is to do place the followup compound to the hits as faithfully as possible regardless of the screaming forcefields. - * ``.scaffold`` is the combined version of the hits (rdkit.Chem.Mol object). - * ``.mol_options`` are the possible mol_options to use. - * ``.chimera`` is the combined version of the hits, but with differing atoms made to match the followup (rdkit.Chem.Mol object). - * ``.positioned_mol`` is the desired output (rdkit.Chem.Mol object) + >>> monster.place(mol) - Note, the hits have to be spatially aligned —i.e. extracted from crystal structures in bond form (see. `extract_mol`). + Given a RDKit molecule and a series of hits it makes a spatially stitched together version + of the initial molecule based on the hits. + The reason is to do place the followup compound to the hits as faithfully as possible + regardless of the screaming forcefields. - ``.get_positional_mapping``, which works also as a class method, creates a dictionary of mol_A atom index to mol_B atom index + * ``.mol_options`` are the possible equiprobable alternatives. + * ``.positioned_mol`` is the desired output (rdkit.Chem.Mol object) + * ``.initial_mol`` is the input (rdkit.Chem.Mol object), this is `None` in a `.combine` call. + * ``.modifications['scaffold']`` is the combined version of the hits (rdkit.Chem.Mol object). + * ``.modifications['chimera']`` is the combined version of the hits, but with differing atoms made + to match the followup (rdkit.Chem.Mol object). + + ``.get_positional_mapping``, which works also as a class method, + creates a dictionary of mol_A atom index to mol_B atom index based on distance (cutoff 2Å) and not MCS. The code works in two broad steps, first a scaffold is made, which is the combination of the hits (by position). - Then the followup is placed. It is not embedded with constraint embed, which requires the reference molecule to have a valid geometry. - ``.scaffold`` and ``.chimera`` and ``.positioned_mol`` absolutely do not have this. + Then the followup is placed. It is not embedded with constrained embedding functionality of RDKit as this + requires the reference molecule to have a valid geometry, which these absolutely do not have this. Novel side chains are added by aligning an optimised conformer against the closest 3-4 reference atoms. - Note that ``.initial_mol`` is not touched. ``.positioned_mol`` may have lost some custom properties, but the atom idices are the same. - - If an atom in a Chem.Mol object is provided via ``attachment`` argument and the molecule contains a dummy atom as - defined in the ``dummy`` class variable. Namely element R in mol file or * in string is the default. + Note that ``.initial_mol`` is not touched. ``.positioned_mol`` may have lost some custom properties, + but the atom indices are the same. + + If an atom in a Chem.Mol object is provided via ``attachment`` argument and the molecule contains a dummy atom. + Namely element R in mol file or * in string. + + ## Combine + + >>> monster.combine(keep_all=True, collapse_rings=True, joining_cutoff= 5)) + + Combines the hits by merging and linking. ``collapse_rings`` argument results in rings being collapsed + before merging to avoid oddities. + The last step within the call is fixing any oddities of impossible chemistry via the call ``rectify``. + This uses the separate class ``Rectifier`` to fix it. + + ## Attributes + + Common input derived + + :ivar hits: + :vartype hits: list + :cvar throw_on_discard: filled by keep_all + :vartype throw_on_discard: bool + + Common derived + + :var matched: (dynamic) accepted hit names + :vartype matched: List[str] + :ivar unmatched: discarded hit names + :vartype unmatched: List[str] + + :cvar journal: The "journal" is the log of Dr Victor Frankenstein (see Victor for more) + :vartype journal: Logger + :ivar modifications: copies of the mols along the way + :vartype modifications: dict + :ivar mol_options: equally valid alternatives to self.positioned_mol + :vartype mol_options: list + + + ``place`` specific: + + :ivar positioned_mol: + :vartype positioned_mol: Mol + :ivar attachment: + :vartype attachment: NoneType + :ivar initial_mol: + :vartype initial_mol: NoneType + :ivar average_position: + :vartype average_position: bool + :var num_common: (dynamic) number of atoms in common between follow-up and hits + :vartype num_common: int + :var percent_common: (dynamic) percentage of atoms of follow-up that are present in the hits + :vartype percent_common: float + + ``combine`` specific: + + :cvar joining_cutoff: how distant (in Å) is too much? + :vartype joining_cutoff: int + :cvar atoms_in_bridge_cutoff: how many bridge atoms can be deleted? + (0 = preserves norbornane, 1 = preserves adamantane) + :vartype atoms_in_bridge_cutoff: int + + Class attributes best ignored: + + :cvar closeness_weights: list of functions to penalise closeness (ignore for most applications) + :vartype closeness_weights: list + :cvar dummy: The virtual atom where the targets attaches. by default `*`. Best not override. + :vartype dummy: Mol + :cvar dummy_symbol: The virtual atom where the targets attaches. by default `*`. Best not override. + :vartype dummy_symbol: str + :cvar matching_modes: + :vartype matching_modes: list """ pass diff --git a/fragmenstein/monster/_base.py b/fragmenstein/monster/_base.py index b048761..a29e879 100644 --- a/fragmenstein/monster/_base.py +++ b/fragmenstein/monster/_base.py @@ -24,10 +24,9 @@ class _MonsterBase: dummy = Chem.MolFromSmiles(dummy_symbol) #: The virtual atom where the targets attaches # settings... - cutoff = 2. joining_cutoff = 5. # how distant (in Å) is too much? atoms_in_bridge_cutoff = 2 - # atoms_in_bridge_cutoff: how many bridge atoms can be deleted? + # atoms_in_bridge_cutoff is how many bridge atoms can be deleted? # (0 = preserves norbornane, 1 = preserves adamantane) throw_on_discard = False matching_modes = [ @@ -75,18 +74,22 @@ def __init__(self, #self._debug_draw has been taken over by ``modifications`` and ``journal`` self.average_position = average_position # ==== To do be filled ================================ - # List[str] - self.unmatched = [] #: rejected hit names - # self.matched is dynamic. #: accepted hits - # Chem.Mol or List[Chem.Mol] + # -------- placement ---------------------------------- + self.initial_mol = None # to be filled by place. The starting molecule (Chem.Mol). + # Manually assignmnt of self.initial_mol is futile + self.attachment = None # place only. + # -------- common ------------------------------------ + # # ivars of type List[str] + self.unmatched = [] # rejected hit names List[str] + # self.matched is dynamic. # accepted hits names List[str] + # # ivars of type Chem.Mol or List[Chem.Mol] or Dict[Chem.Mol] self.modifications = {} - self.initial_mol = None #: to be filled by place. The starting molecule (Chem.Mol). - self.attachment = None - # self.scaffold = None #: template which may have wrong elements in place, or - # self.mol_options = [] #: partial combined templates (merging_mode: partial) - self.mol_options = [] #: templates which may have wrong elements - self.chimera = None #: merger of hits but with atoms made to match the to-be-aligned mol - self.positioned_mol = None #: final molecule + self.positioned_mol = None # final molecule + self.mol_options = [] # equally valid alternatives to self.positioned_mol + self._collapsed_ring_offset = 0 # variable to keep track of how much to offset in ring collapse. + # formerly: + # self.scaffold = None # template which may have wrong elements in place, or + # self.chimera = None # merger of hits but with atoms made to match the to-be-aligned mol def fix_hits(self, hits: List[Chem.Mol]) -> List[Chem.Mol]: """ diff --git a/fragmenstein/monster/_blend_place.py b/fragmenstein/monster/_blend_place.py index 19dc168..71e6bb8 100644 --- a/fragmenstein/monster/_blend_place.py +++ b/fragmenstein/monster/_blend_place.py @@ -36,9 +36,13 @@ def full_blending(self) -> None: a single scaffold is made (except for ``.unmatched``) """ self.mol_options = [self.simply_merge_hits()] - self.scaffold = self.posthoc_refine(self.mol_options[0]) - self.chimera = self.make_chimera() - self.positioned_mol = self.place_from_map() + scaffold = self.posthoc_refine(self.mol_options[0]) + chimera = self.make_chimera(scaffold) + self.keep_copy(scaffold, 'scaffold') + self.keep_copy(chimera, 'chimera') + self.positioned_mol = self.place_from_map(target_mol=self.initial_mol, + template_mol=chimera, + atom_map=None) def partial_blending(self) -> None: """ @@ -46,11 +50,15 @@ def partial_blending(self) -> None: """ self.mol_options = self.partially_blend_hits() # merger of hits unrefined_scaffold, mode_index = self.pick_best() - used = self.scaffold.GetProp('_Name').split('-') + used = unrefined_scaffold.GetProp('_Name').split('-') self.unmatched = [h.GetProp('_Name') for h in self.hits if h.GetProp('_Name') not in used] - self.scaffold = self.posthoc_refine(unrefined_scaffold) - self.chimera = self.make_chimera(mode_index) - self.positioned_mol = self.place_from_map() + scaffold = self.posthoc_refine(unrefined_scaffold) + chimera = self.make_chimera(scaffold, mode_index) + self.keep_copy(scaffold, 'scaffold') + self.keep_copy(chimera, 'chimera') + self.positioned_mol = self.place_from_map(target_mol=self.positioned_mol, + template_mol=chimera, + atom_map=None) def no_blending(self, broad=False) -> None: """ @@ -74,17 +82,23 @@ def no_blending(self, broad=False) -> None: mols=self.hits, maps=maps, no_discard=self.throw_on_discard) - self.scaffold = um.combined - # self.mol_options\ - combined_alternative = um.combined_alternatives - full_atom_map = um.combined_map + self.keep_copy(um.combined, 'scaffold') + self.keep_copy(um.combined_bonded, 'chimera') self.unmatched = [m.GetProp('_Name') for m in um.disregarded] if self.throw_on_discard and len(self.unmatched): raise ConnectionError(f'{self.unmatched} was rejected.') - self.chimera = um.combined_bonded - self.journal.debug(f'followup to scaffold {full_atom_map}') - placed = self.place_from_map(atom_map=full_atom_map) + self.journal.debug(f'followup to scaffold {um.combined_map}') + # ------------------ places the atoms with known mapping ------------------ + placed = self.place_from_map(target_mol=self.initial_mol, + template_mol=um.combined_bonded, + atom_map=um.combined_map) + alts = zip(um.combined_bonded_alternatives, um.combined_map_alternatives) + placed_options = [self.place_from_map(target_mol=self.initial_mol, + template_mol=mol, + atom_map=mappa) for mol, mappa in alts] + # ------------------ Averages the overlapping atoms ------------------ self.positioned_mol = self.posthoc_refine(placed) + self.mol_options = [self.posthoc_refine(mol) for mol in placed_options] # ================= Blend hits =================================================================================== @@ -258,32 +272,9 @@ def template_sorter(t: List[Chem.Mol]) -> float: # else: # return {n: path} - def _prevent_two_bonds_on_dummy(self, mol: Chem.RWMol): - """ - The case '*(C)C' is seen legitimately in some warheads... but in most cases these are not. - :param mol: - :return: - """ - for atom in mol.GetAtoms(): - if atom.GetSymbol() != '*': - pass - elif len(atom.GetNeighbors()) <= 1: - pass - elif len(atom.GetNeighbors()) >= 2: - self.journal.info(f'Dummy atom (idx={atom.GetIdx()}) has {len(atom.GetNeighbors())} bonds!') - neighs = atom.GetNeighbors() - first = neighs[0] - for second in neighs[1:]: - rejected = second.GetIdx() # that will be absorbed (deleted) - keeper = first.GetIdx() # that absorbs (kept) - self._copy_bonding(mol, keeper, rejected) - self._mark_for_deletion(mol, rejected) - self._delete_marked(mol) - return self._prevent_two_bonds_on_dummy(mol) - # ================= Chimera ======================================================================================== - def make_chimera(self, min_mode_index=0) -> Chem.Mol: + def make_chimera(self, template: Chem.Mol, min_mode_index=0) -> Chem.Mol: """ This is to avoid extreme corner corner cases. E.g. here the MCS is ringMatchesRingOnly=True and AtomCompare.CompareAny, @@ -292,19 +283,19 @@ def make_chimera(self, min_mode_index=0) -> Chem.Mol: :return: """ # get the matches - atom_map, mode = self.get_mcs_mapping(self.scaffold, self.initial_mol, min_mode_index=min_mode_index) + atom_map, mode = self.get_mcs_mapping(template, self.initial_mol, min_mode_index=min_mode_index) follow = {**{k: str(v) for k, v in mode.items()}, 'N_atoms': len(atom_map)} self.journal.debug(f"scaffold-followup: {follow}") # make the scaffold more like the followup to avoid weird matches. - chimera = Chem.RWMol(self.scaffold) + chimera = Chem.RWMol(template) for scaff_ai, follow_ai in atom_map.items(): - if self.scaffold.GetAtomWithIdx(scaff_ai).GetSymbol() != self.initial_mol.GetAtomWithIdx( + if template.GetAtomWithIdx(scaff_ai).GetSymbol() != self.initial_mol.GetAtomWithIdx( follow_ai).GetSymbol(): v = {'F': 1, 'Br': 1, 'Cl': 1, 'H': 1, 'B': 3, 'C': 4, 'N': 3, 'O': 2, 'S': 2, 'Se': 2, 'P': 6} wanted = self.initial_mol.GetAtomWithIdx(follow_ai) if wanted.GetSymbol() == '*': # all good then! continue - owned = self.scaffold.GetAtomWithIdx(scaff_ai) + owned = template.GetAtomWithIdx(scaff_ai) diff_valance = owned.GetExplicitValence() - v[wanted.GetSymbol()] if wanted.GetSymbol() in ('F', 'Br', 'Cl', 'C', 'H') and diff_valance > 0: continue # cannot change this. @@ -325,22 +316,23 @@ def make_chimera(self, min_mode_index=0) -> Chem.Mol: warn('Valance issue' + str(err)) return chimera - def place_from_map(self, mol: Chem.Mol = None, atom_map: Optional[Dict] = None) -> Chem.Mol: + def place_from_map(self, target_mol: Chem.Mol, template_mol: Chem.Mol, atom_map: Optional[Dict] = None) -> Chem.Mol: """ This method places the atoms with known mapping and places the 'uniques' (novel) via an aligned mol (the 'sextant') This sextant business is a workaround for the fact that only minimised molecules can use the partial embedding function of RDKit. - :param mol: + :param target_mol: target mol + :param template_mol: the template/scaffold to place the mol :param atom_map: something that get_mcs_mapping would return. :return: """ # Note none of this malarkey: AllChem.MMFFOptimizeMolecule(ref) # prealignment - if mol is None: - mol = self.initial_mol - sextant = Chem.Mol(mol) + if target_mol is None: + target_mol = self.initial_mol + sextant = Chem.Mol(target_mol) Chem.SanitizeMol(sextant) AllChem.EmbedMolecule(sextant) AllChem.MMFFOptimizeMolecule(sextant) @@ -348,14 +340,14 @@ def place_from_map(self, mol: Chem.Mol = None, atom_map: Optional[Dict] = None) # mapping retrieval and sextant alignment # variables: atom_map sextant -> uniques if atom_map is None: - atom_map, mode = self.get_mcs_mapping(mol, self.chimera) + atom_map, mode = self.get_mcs_mapping(target_mol, template_mol) msg = {**{k: str(v) for k, v in mode.items()}, 'N_atoms': len(atom_map)} self.journal.debug(f"followup-chimera' = {msg}") - rdMolAlign.AlignMol(sextant, self.chimera, atomMap=list(atom_map.items()), maxIters=500) + rdMolAlign.AlignMol(sextant, template_mol, atomMap=list(atom_map.items()), maxIters=500) # place atoms that have a known location putty = Chem.Mol(sextant) pconf = putty.GetConformer() - chimera_conf = self.chimera.GetConformer() + chimera_conf = template_mol.GetConformer() uniques = set() # unique atoms in followup for i in range(putty.GetNumAtoms()): p_atom = putty.GetAtomWithIdx(i) @@ -363,7 +355,7 @@ def place_from_map(self, mol: Chem.Mol = None, atom_map: Optional[Dict] = None) p_atom.SetProp('_Origin', 'none') if i in atom_map: ci = atom_map[i] - c_atom = self.chimera.GetAtomWithIdx(ci) + c_atom = template_mol.GetAtomWithIdx(ci) if c_atom.HasProp('_Stdev'): stdev = c_atom.GetDoubleProp('_Stdev') origin = c_atom.GetAtomWithIdx(ci).GetProp('_Origin') @@ -382,7 +374,7 @@ def place_from_map(self, mol: Chem.Mol = None, atom_map: Optional[Dict] = None) if unique_idx in done_already: continue # get other attachments if any. - team = self._recruit_team(mol, unique_idx, categories['uniques']) + team = self._recruit_team(target_mol, unique_idx, categories['uniques']) other_attachments = (team & set(categories['pairs'].keys())) - {unique_idx} sights = set() # atoms to align against for att_idx in [unique_idx] + list(other_attachments): @@ -412,92 +404,7 @@ def place_from_map(self, mol: Chem.Mol = None, atom_map: Optional[Dict] = None) AllChem.SanitizeMol(putty) return putty # positioned_mol - def _merge_part(self, scaffold: Chem.Mol, fragmentanda: Chem.Mol, anchor_index: int, - attachment_details: List[Dict], - other_attachments: List[int], - other_attachment_details: List[List[Dict]]) -> Chem.Mol: - """ - This does the messy work for merge_pair. - - :param scaffold: the Chem.Mol molecule onto whose copy the fragmentanda Chem.Mol gets added - :param fragmentanda: The other Chem.Mol molecule - :param anchor_index: the fragment-to-added's internal atom that attaches (hit indexed) - :param attachment_details: see `_pre_fragment_pairs` or example below fo an entry - :type attachment_details: List[Dict] - :param other_attachments: - :param other_attachment_details: - :return: a new Chem.Mol molecule - - Details object example: - - [{'idx': 5, - 'type': rdkit.Chem.rdchem.BondType.SINGLE, - 'idx_F': 5, # fragmentanda index - 'idx_S': 1 # scaffold index - }], ...} - """ - # get bit to add. - bonds_to_frag = [] - for detail in attachment_details: - attachment_index = detail['idx_F'] # fragmentanda attachment_index - bonds_to_frag += [fragmentanda.GetBondBetweenAtoms(anchor_index, attachment_index).GetIdx()] - bonds_to_frag += [fragmentanda.GetBondBetweenAtoms(oi, oad[0]['idx_F']).GetIdx() for oi, oad in - zip(other_attachments, other_attachment_details)] - f = Chem.FragmentOnBonds(fragmentanda, - bonds_to_frag, - addDummies=False) - frag_split = [] - fragmols = Chem.GetMolFrags(f, asMols=True, fragsMolAtomMapping=frag_split, sanitizeFrags=False) - # Get the fragment of interest. - ii = 0 - for mol_N, indices in enumerate(frag_split): - if anchor_index in indices: - break - ii += len(indices) - else: - raise Exception - frag = fragmols[mol_N] - frag_anchor_index = indices.index(anchor_index) - # pre-emptively fix atom ori_i - # offset collapsed to avoid clashes. - self.offset(frag) - # Experimental code. - # TODO: finish! - # frag_atom = frag.GetAtomWithIdx(frag_anchor_index) - # old2future = {atom.GetIntProp('_ori_i'): atom.GetIdx() + scaffold.GetNumAtoms() for atom in frag.GetAtoms()} - # del old2future[-1] # does nothing but nice to double tap - # if frag_atom.GetIntProp('_ori_i') == -1: #damn. - # for absent in self._get_mystery_ori_i(frag): - # old2future[absent] = scaffold_attachment_index - # self._renumber_original_indices(frag, old2future) - combo = Chem.RWMol(rdmolops.CombineMols(scaffold, frag)) - scaffold_anchor_index = frag_anchor_index + scaffold.GetNumAtoms() - for detail in attachment_details: - # scaffold_anchor_index : atom index in scaffold that needs to be added to scaffold_attachment_index - # but was originally attached to attachment_index in fragmentanda. - # the latter is not kept. - attachment_index = detail['idx_F'] # fragmentanda attachment_index - scaffold_attachment_index = detail['idx_S'] # scaffold attachment index - bond_type = detail['type'] - combo.AddBond(scaffold_anchor_index, scaffold_attachment_index, bond_type) - new_bond = combo.GetBondBetweenAtoms(scaffold_anchor_index, scaffold_attachment_index) - # BondProvenance.set_bond(new_bond, '???') - # self.transfer_ring_data(fragmentanda.GetAtomWithIdx(attachment_index), - # combo.GetAtomWithIdx(scaffold_anchor_index)) - for oi, oad in zip(other_attachments, other_attachment_details): - bond_type = oad[0]['type'] - scaffold_attachment_index = oad[0]['idx_S'] - scaffold_anchor_index = indices.index(oi) + scaffold.GetNumAtoms() - combo.AddBond(scaffold_anchor_index, scaffold_attachment_index, bond_type) - new_bond = combo.GetBondBetweenAtoms(scaffold_anchor_index, scaffold_attachment_index) - # BondProvenance.set_bond(new_bond, '???') - Chem.SanitizeMol(combo, - sanitizeOps=Chem.rdmolops.SanitizeFlags.SANITIZE_ADJUSTHS + - Chem.rdmolops.SanitizeFlags.SANITIZE_SETAROMATICITY, - catchErrors=True) - self._prevent_two_bonds_on_dummy(combo) - scaffold = combo.GetMol() - return scaffold + def transfer_ring_data(self, donor: Chem.Atom, acceptor: Chem.Atom): """ @@ -639,7 +546,7 @@ def pretweak(self) -> None: warn(f'No overlap? {A2B}') @property - def matched(self): + def matched(self) -> List[str]: """ This is the counter to unmatched. It's dynamic as you never know... @@ -647,4 +554,4 @@ def matched(self): :return: """ return [h.GetProp('_Name') for h in self.hits if - h.GetProp('_Name') not in self.unmatched] \ No newline at end of file + h.GetProp('_Name') not in self.unmatched] diff --git a/fragmenstein/monster/_collapse_ring.py b/fragmenstein/monster/_collapse_ring.py index fe7736d..01bde2b 100644 --- a/fragmenstein/monster/_collapse_ring.py +++ b/fragmenstein/monster/_collapse_ring.py @@ -146,7 +146,7 @@ def expand_ring(self, mol: Chem.Mol) -> Chem.Mol: # =========== Offset =============================================================================================== - _collapsed_ring_offset = 0 + def offset(self, mol: Chem.Mol): """ @@ -893,21 +893,31 @@ def _add_bond_by_reference(self, mol, a, b, reference_bond): # ======== Emergency =============================================================================================== - def _emergency_joining(self, mol): + def _emergency_joining(self, mol: Chem.Mol) -> Chem.Mol: + return self._join_internally(mol, severe=True) + + def _join_internally(self, mol: Chem.Mol, severe: bool=False) -> Chem.Mol: """ - The last check to see if the mol is connected, before being rectified (valence fixes). + The last check to see if the mol is connected. + This differs (and calls) ``join_neighboring_mols`` + """ + is_rw = isinstance(mol, Chem.RWMol) frags = Chem.GetMolFrags(mol, asMols=True, sanitizeFrags=False) n = len(frags) if n == 1: return mol else: while n > 1: - self.journal.warning(f'Molecule disconnected in {n} parts. Please inspect final product!') + if severe: + self.journal.warning(f'Molecule disconnected in {n} parts. Please inspect final product!') + else: + self.journal.debug('Linking two disconnected fragments') + # ----- get names --------------- name = mol.GetProp('_Name') for i, frag in enumerate(frags): frag.SetProp('_Name', f'name.{i}') - # find which fragments are closest. + # find which fragments are closest ------------------------------ # TODO use the distance_matrix = self._get_distance_matrix(..) code closeness = np.ones([n, n]) closeness.fill(float('nan')) @@ -920,12 +930,16 @@ def _emergency_joining(self, mol): mol = self.join_neighboring_mols(first, second) frags.remove(first) frags.remove(second) + # ---- reset variables --------- for part in frags: mol = Chem.CombineMols(mol, part) mol.SetProp('_Name', name) frags = Chem.GetMolFrags(mol, asMols=True, sanitizeFrags=False) n = len(frags) - return Chem.RWMol(mol) + if is_rw: + return Chem.RWMol(mol) + else: + return mol # # diff --git a/fragmenstein/monster/_combine.py b/fragmenstein/monster/_combine.py index b70eb3d..81b3c7b 100644 --- a/fragmenstein/monster/_combine.py +++ b/fragmenstein/monster/_combine.py @@ -20,7 +20,7 @@ class _MonsterCombine(_MonsterRing, _MonsterMerge): - def combine(self, keep_all=True, collapse_rings=True, joining_cutoff: int = 5): + def combine(self, keep_all: bool=True, collapse_rings: bool=True, joining_cutoff: int = 5): """ Merge/links the hits. (Main entrypoint) @@ -38,7 +38,7 @@ def combine(self, keep_all=True, collapse_rings=True, joining_cutoff: int = 5): self.keep_copies(col_hits, 'Collapsed hits') else: col_hits = self.hits - self.positioned_mol = self.simply_merge_hits(col_hits) + self.positioned_mol = self.simply_merge_hits(col_hits, linked=False) self.keep_copy(self.positioned_mol, 'merged template') ## Discard can happen for other reasons than disconnect if keep_all and len(self.unmatched): @@ -49,6 +49,7 @@ def combine(self, keep_all=True, collapse_rings=True, joining_cutoff: int = 5): self.positioned_mol = self.expand_ring(self.positioned_mol) # bonded_as_original=False no longer needed. self.keep_copy(self.positioned_mol, 'expanded') + self._join_internally(self.positioned_mol) self.journal.debug(f'Expanded') self.rectify() self.journal.debug(f'Rectified') diff --git a/fragmenstein/monster/_communal.py b/fragmenstein/monster/_communal.py index c80ea5b..547abe0 100644 --- a/fragmenstein/monster/_communal.py +++ b/fragmenstein/monster/_communal.py @@ -84,37 +84,40 @@ def _find_all_closest(self, mol_A: Chem.Mol, mol_B: Chem.Mol) -> Tuple[Chem.RWMo pendistance = np.nanmin(pendist_matrix) if np.isnan(pendistance): raise ConnectionError('This is impossible. Previous is absent??') - else: - candidates = [] - - def get_closest(pendistance): - p = np.where(pendist_matrix == pendistance) - anchor_A = int(p[0][0]) - anchor_B = int(p[1][0]) - distance = distance_matrix[anchor_A, anchor_B] - penalty = penalties[anchor_A, anchor_B] - self.journal.debug(f'Connecting {anchor_A} with {anchor_B}, {penalty} penalised distance of {distance}') - return anchor_A, anchor_B, distance - - anchor_A, anchor_B, distance = get_closest(pendistance) - candidates.append((anchor_A, anchor_B, distance)) - with np.errstate(invalid='ignore'): - pendist_matrix[pendist_matrix > 1.] = np.nan - while pendistance < 1.: - pendist_matrix[[anchor_A, anchor_B], :] = np.nan - pendist_matrix[:, [anchor_A, anchor_B]] = np.nan - pendistance = np.nanmin(pendist_matrix) - if np.isnan(pendistance): - break - else: - anchor_A, anchor_B, distance = get_closest(pendistance) - candidates.append((anchor_A, anchor_B, distance)) - return combo, candidates + candidates = [] + + def get_closest(pendistance): + p = np.where(pendist_matrix == pendistance) + anchor_A = int(p[0][0]) + anchor_B = int(p[1][0]) + distance = distance_matrix[anchor_A, anchor_B] + penalty = penalties[anchor_A, anchor_B] + self.journal.debug(f'Connecting {anchor_A} with {anchor_B} would have a ' + + f'{penalty} penalised distance of {distance}') + return anchor_A, anchor_B, distance + + anchor_A, anchor_B, distance = get_closest(pendistance) + candidates.append((anchor_A, anchor_B, distance)) + with np.errstate(invalid='ignore'): + pendist_matrix[pendist_matrix > 1.] = np.nan + while pendistance < 1.: + pendist_matrix[[anchor_A, anchor_B], :] = np.nan + pendist_matrix[:, [anchor_A, anchor_B]] = np.nan + pendistance = np.nanmin(pendist_matrix) + if np.isnan(pendistance): + break + else: + anchor_A, anchor_B, distance = get_closest(pendistance) + candidates.append((anchor_A, anchor_B, distance)) + return combo, candidates - def _get_distance_matrix(self, combo: Chem.Mol, A: Union[Chem.Mol, np.ndarray], + def _get_distance_matrix(self, + combo: Chem.Mol, + A: Union[Chem.Mol, np.ndarray], B: Union[Chem.Mol, np.ndarray]) -> np.ndarray: """ Called by ``_find_closest`` and ``_determine_mergers_novel_ringcore_pair`` in collapse ring (for expansion). + This is a distance matrix blanked so it is only distances to other fragment """ # TODO move to base once made. diff --git a/fragmenstein/monster/_join_neighboring.py b/fragmenstein/monster/_join_neighboring.py index 30e2ef7..0f1ef04 100644 --- a/fragmenstein/monster/_join_neighboring.py +++ b/fragmenstein/monster/_join_neighboring.py @@ -26,7 +26,7 @@ def join_neighboring_mols(self, mol_A: Chem.Mol, mol_B: Chem.Mol): :return: """ # get closets atoms - combo, candidates = self._find_all_closest(mol_A, mol_B) + combo, candidates = self._find_all_closest(mol_A, mol_B) # _find_all_closest is in communal anchor_A, anchor_B, distance = candidates[0] mol = self._join_atoms(combo, anchor_A, anchor_B, distance, linking=True) for anchor_A, anchor_B, distance in candidates[1:]: @@ -52,7 +52,7 @@ def _join_atoms(self, ys = np.linspace(pos_A.y, pos_B.y, n_new + 2)[1:-1] zs = np.linspace(pos_A.z, pos_B.z, n_new + 2)[1:-1] - # correct for ring marker atoms + # correcting for ring marker atoms def is_ring_atom(anchor: int) -> bool: atom = combo.GetAtomWithIdx(anchor) if atom.HasProp('_ori_i') and atom.GetIntProp('_ori_i') == -1: @@ -76,7 +76,8 @@ def is_ring_atom(anchor: int) -> bool: # notify that things could be leary. if distance < 0: - self.journal.debug(f'Two ring atoms detected to be close. Joining for now. They will be bonded/fused/spiro afterwards') + self.journal.debug(f'Two ring atoms detected to be close. Joining for now.'+ + ' They will be bonded/fused/spiro afterwards') # check if valid. if distance > self.joining_cutoff: msg = f'Atoms {anchor_A}+{anchor_B} are {distance} Å away. Cutoff is {self.joining_cutoff}.' diff --git a/fragmenstein/monster/_merge.py b/fragmenstein/monster/_merge.py index 9f1a971..0d561d3 100644 --- a/fragmenstein/monster/_merge.py +++ b/fragmenstein/monster/_merge.py @@ -2,7 +2,12 @@ __doc__ = \ """ -Combine = merge/join +Combine => merge/join +This merge is used by all. + +Peculiarly/for historical reasons the merging is done by fragmentation and joining the fragments +as opposed to absorption, which is what happens in the ring expansion. + """ ######################################################################################################################## @@ -11,13 +16,68 @@ from warnings import warn from rdkit import Chem - +from rdkit.Chem import rdmolops from ._join_neighboring import _MonsterJoinNeigh from .bond_provenance import BondProvenance from .positional_mapping import GPM class _MonsterMerge(_MonsterJoinNeigh, GPM): + + def simply_merge_hits(self, + hits: Optional[List[Chem.Mol]] = None, + linked: bool = True, + ) -> Chem.Mol: + """ + Recursively stick the hits together and average the positions. + This is the monster of automerging, full-merging mapping and partial merging mapping. + The latter however uses `partially_blend_hits` first. + The hits are not ring-collapsed and -expanded herein. + + :param hits: optionally give a hit list, else uses the attribute ``.hits``. + :param linked: if true the molecules are joined, else they are placed + in the same molecule as disconnected fragments. + :return: the rdkit.Chem.Mol object that will fill ``.scaffold`` + """ + if hits is None: + hits = sorted(self.hits, key=lambda h: h.GetNumAtoms(), reverse=True) + for hit in hits: + BondProvenance.set_all_bonds(hit, 'original') + self.journal.debug(f"Merging: {[hit.GetProp('_Name') for hit in hits]}") + scaffold = Chem.Mol(hits[0]) + # first try + save_for_later = [] + for fragmentanda in hits[1:]: + try: + scaffold = self.merge_pair(scaffold, fragmentanda) + except ConnectionError: + save_for_later.append(fragmentanda) + # second try + join_later = [] + for fragmentanda in save_for_later: + try: + scaffold = self.merge_pair(scaffold, fragmentanda) + except ConnectionError: + join_later.append(fragmentanda) + # join (last ditch) + for fragmentanda in join_later: + if linked: + try: + scaffold = self.join_neighboring_mols(scaffold, fragmentanda) + except ConnectionError: + self.unmatched.append(fragmentanda.GetProp("_Name")) + msg = f'Hit {fragmentanda.GetProp("_Name")} has no connections! Skipping!' + if self.throw_on_discard: + raise ConnectionError(msg) + else: + warn(msg) + else: + new_name = self._get_combined_name(scaffold, fragmentanda) + scaffold = rdmolops.CombineMols(scaffold, fragmentanda) + scaffold.SetProp('_Name', new_name) + return scaffold + + def merge_pair(self, scaffold: Chem.Mol, fragmentanda: Chem.Mol, mapping: Optional = None) -> Chem.Mol: """ To specify attachments use ``.merge``. @@ -49,54 +109,18 @@ def merge_pair(self, scaffold: Chem.Mol, fragmentanda: Chem.Mol, mapping: Option attachment_details=attachment_details, other_attachments=other_attachments, other_attachment_details=other_attachment_details) - name_A = scaffold.GetProp('_Name') - name_B = fragmentanda.GetProp('_Name') - scaffold.SetProp('_Name', f'{name_A}-{name_B}') + new_name = self._get_combined_name(scaffold, fragmentanda) + scaffold.SetProp('_Name', new_name) self.keep_copy(scaffold, 'pair_merged') return scaffold - def simply_merge_hits(self, hits: Optional[List[Chem.Mol]] = None) -> Chem.Mol: - """ - Recursively stick the hits together and average the positions. - This is the monster of automerging, full-merging mapping and partial merging mapping. - The latter however uses `partially_blend_hits` first. - The hits are not ring-collapsed and -expanded herein. + def _get_combined_name(self, first_mol: Chem.Mol, second_mol: Chem.Mol): + get_name = lambda mol: mol.GetProp('_Name') if mol.HasProp('_Name') else 'molecule' + name_1 = get_name(first_mol) + name_2 = get_name(second_mol) + return f'{name_1}-{name_2}' - :param hits: optionally give a hit list, else uses the attribute ``.hits``. - :return: the rdkit.Chem.Mol object that will fill ``.scaffold`` - """ - if hits is None: - hits = sorted(self.hits, key=lambda h: h.GetNumAtoms(), reverse=True) - for hit in hits: - BondProvenance.set_all_bonds(hit, 'original') - self.journal.debug(f"Merging: {[hit.GetProp('_Name') for hit in hits]}") - scaffold = Chem.Mol(hits[0]) - # first try - save_for_later = [] - for fragmentanda in hits[1:]: - try: - scaffold = self.merge_pair(scaffold, fragmentanda) - except ConnectionError: - save_for_later.append(fragmentanda) - # second try - join_later = [] - for fragmentanda in save_for_later: - try: - scaffold = self.merge_pair(scaffold, fragmentanda) - except ConnectionError: - join_later.append(fragmentanda) - # join (last ditch) - for fragmentanda in join_later: - try: - scaffold = self.join_neighboring_mols(scaffold, fragmentanda) - except ConnectionError: - self.unmatched.append(fragmentanda.GetProp("_Name")) - msg = f'Hit {fragmentanda.GetProp("_Name")} has no connections! Skipping!' - if self.throw_on_discard: - raise ConnectionError(msg) - else: - warn(msg) - return scaffold + # ------ merging by fragmentation ------------------------ def _pre_fragment_pairs(self, scaffold: Chem.Mol, fragmentanda: Chem.Mol, A2B_mapping: Optional = None) \ -> Dict[int, List[Dict]]: @@ -211,4 +235,115 @@ def _categorise(self, mol: Chem.Mol, uniques: set) -> Dict[str, Union[set, Dict] attachments=attachments, pairs=pairs, dummies=dummies - ) \ No newline at end of file + ) + + def _merge_part(self, scaffold: Chem.Mol, fragmentanda: Chem.Mol, anchor_index: int, + attachment_details: List[Dict], + other_attachments: List[int], + other_attachment_details: List[List[Dict]]) -> Chem.Mol: + """ + This does the messy work for merge_pair. + + :param scaffold: the Chem.Mol molecule onto whose copy the fragmentanda Chem.Mol gets added + :param fragmentanda: The other Chem.Mol molecule + :param anchor_index: the fragment-to-added's internal atom that attaches (hit indexed) + :param attachment_details: see `_pre_fragment_pairs` or example below fo an entry + :type attachment_details: List[Dict] + :param other_attachments: + :param other_attachment_details: + :return: a new Chem.Mol molecule + + Details object example: + + [{'idx': 5, + 'type': rdkit.Chem.rdchem.BondType.SINGLE, + 'idx_F': 5, # fragmentanda index + 'idx_S': 1 # scaffold index + }], ...} + """ + # get bit to add. + bonds_to_frag = [] + for detail in attachment_details: + attachment_index = detail['idx_F'] # fragmentanda attachment_index + bonds_to_frag += [fragmentanda.GetBondBetweenAtoms(anchor_index, attachment_index).GetIdx()] + bonds_to_frag += [fragmentanda.GetBondBetweenAtoms(oi, oad[0]['idx_F']).GetIdx() for oi, oad in + zip(other_attachments, other_attachment_details)] + f = Chem.FragmentOnBonds(fragmentanda, + bonds_to_frag, + addDummies=False) + frag_split = [] + fragmols = Chem.GetMolFrags(f, asMols=True, fragsMolAtomMapping=frag_split, sanitizeFrags=False) + # Get the fragment of interest. + ii = 0 + for mol_N, indices in enumerate(frag_split): + if anchor_index in indices: + break + ii += len(indices) + else: + raise Exception + frag = fragmols[mol_N] + frag_anchor_index = indices.index(anchor_index) + # pre-emptively fix atom ori_i + # offset collapsed to avoid clashes. + self.offset(frag) + # Experimental code. + # TODO: finish! + # frag_atom = frag.GetAtomWithIdx(frag_anchor_index) + # old2future = {atom.GetIntProp('_ori_i'): atom.GetIdx() + scaffold.GetNumAtoms() for atom in frag.GetAtoms()} + # del old2future[-1] # does nothing but nice to double tap + # if frag_atom.GetIntProp('_ori_i') == -1: #damn. + # for absent in self._get_mystery_ori_i(frag): + # old2future[absent] = scaffold_attachment_index + # self._renumber_original_indices(frag, old2future) + combo = Chem.RWMol(rdmolops.CombineMols(scaffold, frag)) + scaffold_anchor_index = frag_anchor_index + scaffold.GetNumAtoms() + for detail in attachment_details: + # scaffold_anchor_index : atom index in scaffold that needs to be added to scaffold_attachment_index + # but was originally attached to attachment_index in fragmentanda. + # the latter is not kept. + attachment_index = detail['idx_F'] # fragmentanda attachment_index + scaffold_attachment_index = detail['idx_S'] # scaffold attachment index + bond_type = detail['type'] + combo.AddBond(scaffold_anchor_index, scaffold_attachment_index, bond_type) + new_bond = combo.GetBondBetweenAtoms(scaffold_anchor_index, scaffold_attachment_index) + # BondProvenance.set_bond(new_bond, '???') + # self.transfer_ring_data(fragmentanda.GetAtomWithIdx(attachment_index), + # combo.GetAtomWithIdx(scaffold_anchor_index)) + for oi, oad in zip(other_attachments, other_attachment_details): + bond_type = oad[0]['type'] + scaffold_attachment_index = oad[0]['idx_S'] + scaffold_anchor_index = indices.index(oi) + scaffold.GetNumAtoms() + combo.AddBond(scaffold_anchor_index, scaffold_attachment_index, bond_type) + new_bond = combo.GetBondBetweenAtoms(scaffold_anchor_index, scaffold_attachment_index) + # BondProvenance.set_bond(new_bond, '???') + Chem.SanitizeMol(combo, + sanitizeOps=Chem.rdmolops.SanitizeFlags.SANITIZE_ADJUSTHS + + Chem.rdmolops.SanitizeFlags.SANITIZE_SETAROMATICITY, + catchErrors=True) + self._prevent_two_bonds_on_dummy(combo) + scaffold = combo.GetMol() + return scaffold + + def _prevent_two_bonds_on_dummy(self, mol: Chem.RWMol): + """ + The case '*(C)C' is seen legitimately in some warheads... but in most cases these are not. + + :param mol: + :return: + """ + for atom in mol.GetAtoms(): + if atom.GetSymbol() != '*': + pass + elif len(atom.GetNeighbors()) <= 1: + pass + elif len(atom.GetNeighbors()) >= 2: + self.journal.info(f'Dummy atom (idx={atom.GetIdx()}) has {len(atom.GetNeighbors())} bonds!') + neighs = atom.GetNeighbors() + first = neighs[0] + for second in neighs[1:]: + rejected = second.GetIdx() # that will be absorbed (deleted) + keeper = first.GetIdx() # that absorbs (kept) + self._copy_bonding(mol, keeper, rejected) + self._mark_for_deletion(mol, rejected) + self._delete_marked(mol) + return self._prevent_two_bonds_on_dummy(mol) diff --git a/fragmenstein/monster/_utility.py b/fragmenstein/monster/_utility.py index 014bb67..a7bec55 100644 --- a/fragmenstein/monster/_utility.py +++ b/fragmenstein/monster/_utility.py @@ -86,11 +86,20 @@ def _get_square_deviation(self, molA, molB, mapping): @property def num_common(self) -> int: - mcs = rdFMCS.FindMCS([self.scaffold, self.initial_mol], + template = self._get_last_template() + mcs = rdFMCS.FindMCS([template, self.initial_mol], atomCompare=rdFMCS.AtomCompare.CompareElements, bondCompare=rdFMCS.BondCompare.CompareOrder) return Chem.MolFromSmarts(mcs.smartsString).GetNumAtoms() + def _get_last_template(self): + if 'chimera' in self.modifications: + template = self.modifications['chimera'] + elif 'scaffold' in self.modifications: + template = self.modifications['scaffold'] + else: + raise KeyError('There is no chimeric or reg scaffold/template to compare to.') + @property def percent_common(self) -> int: return round(self.num_common / self.initial_mol.GetNumAtoms() * 100) @@ -175,7 +184,8 @@ def save_commonality(self, filename: Optional[str] = None): :param filename: optinal filename to save it as. Otherwise returns a Draw.MolDraw2DSVG object. :return: """ - mcs = rdFMCS.FindMCS([self.chimera, self.positioned_mol], + template = self._get_last_template() + mcs = rdFMCS.FindMCS([template, self.positioned_mol], atomCompare=rdFMCS.AtomCompare.CompareElements, bondCompare=rdFMCS.BondCompare.CompareOrder, ringMatchesRingOnly=True) @@ -206,11 +216,11 @@ def make_pse(self, filename='test.pse', extra_mols: Optional[Chem.Mol] = None): for h, hit in enumerate(self.hits): pymol.cmd.read_molstr(Chem.MolToMolBlock(hit, kekulize=False), f'hit{h}') pymol.cmd.color(next(tints), f'hit{h} and name C*') - if self.scaffold: - pymol.cmd.read_molstr(Chem.MolToMolBlock(self.scaffold, kekulize=False), f'scaffold') + if 'scaffold' in self.modifications: + pymol.cmd.read_molstr(Chem.MolToMolBlock(self.modifications['scaffold'], kekulize=False), f'scaffold') pymol.cmd.color('tv_blue', f'scaffold and name C*') - if self.chimera: - pymol.cmd.read_molstr(Chem.MolToMolBlock(self.chimera, kekulize=False), f'chimera') + if 'chimera' in self.modifications: + pymol.cmd.read_molstr(Chem.MolToMolBlock(self.modifications['chimera'], kekulize=False), f'chimera') pymol.cmd.color('cyan', f'chimera and name C*') if self.positioned_mol: pymol.cmd.read_molstr(Chem.MolToMolBlock(self.positioned_mol, kekulize=False), f'followup') @@ -222,7 +232,7 @@ def make_pse(self, filename='test.pse', extra_mols: Optional[Chem.Mol] = None): pymol.cmd.hide('sticks') pymol.cmd.hide('cartoon') # there should not be.... pymol.cmd.show('lines', 'not polymer') - if self.chimera: + if 'chimera' in self.modifications: pymol.cmd.show('sticks', 'chimera') if self.positioned_mol: pymol.cmd.show('sticks', 'followup') diff --git a/fragmenstein/monster/unmerge_mapper.py b/fragmenstein/monster/unmerge_mapper.py index 51e11c4..0e7d8a5 100644 --- a/fragmenstein/monster/unmerge_mapper.py +++ b/fragmenstein/monster/unmerge_mapper.py @@ -63,20 +63,29 @@ def __init__(self, :type maps: Dict[List[Dict[int, int]]] :param no_discard: do not allow any to be discarded """ + # ---- inputs ------------ self.followup = followup self.mols = mols self.maps = maps self.no_discard = no_discard if self.no_discard: self.max_strikes = 100 + # ---- to be filled ------------ accounted_for = set() self.c_map_options = [] self.c_options = [] self.c_disregarded_options = [] - # sorters + self.combined = None + self.combined_alternatives = [] + self.combined_map = {} + self.disregarded = [] + self.combined_bonded = None + self.combined_bonded_alternatives = [] + self.combined_map_alternatives = [] + # ---- sorters -------------------- goodness_sorter = lambda i: len(self.c_map_options[i]) - self.offness(self.c_options[i], self.c_map_options[i]) accounted_sorter = self.template_sorter_factory(accounted_for) - # rotate + # ---- rotate ---------------------------- if self.rotational_approach: others = deque(self.mols) for s in range(len(self.mols)): @@ -92,7 +101,7 @@ def __init__(self, aname = alt.GetProp('_Name') not_alt = set([o for o in others if o.GetProp('_Name') != aname]) self.unmerge_inner(Chem.Mol(), {}, [alt] + list(not_alt), []) - # find best + # ---- find best ------------------------------------ if self.no_discard: valids = [i for i, v in enumerate(self.c_disregarded_options) if len(v) == 0] if len(valids) == 0: @@ -118,13 +127,24 @@ def __init__(self, # d = self.c_disregarded_options[j] # dv = self.measure_map(mol, m) # print(j, [dd.GetProp('_Name') for dd in d], len(m), np.mean(dv), np.max(dv), self.offness(mol, m)) + # ----- fill ---------------------------------------------------------------- self.combined = self.c_options[i] - self.combined_alternatives = [self.c_options[j] for j in equals if j != i] self.combined_map = self.c_map_options[i] self.disregarded = self.c_disregarded_options[i] self.combined_bonded = self.bond() + alternative_indices = [j for j in equals if j != i] + self.combined_alternatives = [self.c_options[j] for j in alternative_indices] + self.combined_map_alternatives = [self.c_map_options[j] for j in alternative_indices] + self.combined_bonded_alternatives = [self.bond(n) for n in range(len(self.combined_alternatives))] - get_key = lambda self, d, v: list(d.keys())[list(d.values()).index(v)] + def get_key(self, d: dict, v: Any): + """ + Given a value and a dict and a value get the key. + :param d: + :param v: + :return: + """ + return list(d.keys())[list(d.values()).index(v)] @classmethod def make_maps(cls, target: Chem.Mol, mols: List[Chem.Mol], mode: Optional[Dict[str, Any]] = None) \ @@ -338,15 +358,23 @@ def check_possible_distances(self, other, possible_map, combined, combined_map, return True - def bond(self): - putty = Chem.RWMol(self.combined) - for fi, ci in self.combined_map.items(): + def bond(self, idx: Optional[int]=None): + if idx is None: + # calculating self.combined_bonded + mol = self.combined + mapping = self.combined_map + else: + # calculating one of self.combined_bonded_alternatives + mol = self.combined_alternatives[idx] + mapping = self.combined_map_alternatives[idx] + putty = Chem.RWMol(mol) + for fi, ci in mapping.items(): fatom = self.followup.GetAtomWithIdx(fi) for neigh in fatom.GetNeighbors(): ni = neigh.GetIdx() - if ni not in self.combined_map: + if ni not in mapping: continue - nci = self.combined_map[ni] + nci = mapping[ni] bond_type = self.followup.GetBondBetweenAtoms(fi, ni).GetBondType() if not putty.GetBondBetweenAtoms(ci, nci): putty.AddBond(ci, nci, bond_type) From a5e489dc72f209b428fe827b5b8816517ad65646 Mon Sep 17 00:00:00 2001 From: matteoferla Date: Fri, 12 Feb 2021 13:22:22 +0000 Subject: [PATCH 29/32] :beetle: `ModuleNotFoundError` for conda/apt modules is a bad option as it prevents the github action --- setup.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/setup.py b/setup.py index 70b8383..c9dc282 100644 --- a/setup.py +++ b/setup.py @@ -1,11 +1,16 @@ from setuptools import setup from warnings import warn from importlib import util +import sys + +if sys.version_info.major != 3 or sys.version_info.minor < 6: + print(sys.version_info) + raise SystemError('Module written for Python 3.6+.') # ---------- Non pip modules ------------------------------------------------------------------------------------------ if not util.find_spec('rdkit'): - raise ModuleNotFoundError('This 3.6+ script **requires** rdkit which cannot be pip installed.' + + warn('This 3.6+ script **requires** rdkit which cannot be pip installed.' + ' To install try either ' + 'conda install -c conda-forge rdkit or ' + 'sudo apt-get/brew install python3-rdkit or visit rdkit documentation.') @@ -21,9 +26,8 @@ name='Fragmenstein', version='0.6', packages=['fragmenstein'], - install_requires=['numpy'], - extras_require={'minimization': ['rdkit_to_params'], - 'jupyter': ['jupyter']}, + install_requires=['numpy', 'rdkit-to-params', 'molecular-rectifier'], + extras_require={'jupyter': ['jupyter']}, url='https://github.com/matteoferla/Fragmenstein', license='MIT', author='Matteo Ferla', From 4df3d8f767da50b18b8ca6ca10aa134251a21419 Mon Sep 17 00:00:00 2001 From: matteoferla Date: Fri, 12 Feb 2021 13:22:52 +0000 Subject: [PATCH 30/32] :truck: rectifier moved to own repo as discussed --- documentation/monster/no_template.md | 2 +- fragmenstein/__init__.py | 2 +- fragmenstein/monster/_combine.py | 2 +- fragmenstein/rectifier/__init__.py | 51 --- fragmenstein/rectifier/_base.py | 79 ---- fragmenstein/rectifier/_odd.py | 64 --- fragmenstein/rectifier/_ring.py | 205 --------- fragmenstein/rectifier/_valence.py | 389 ------------------ .../victor/_victor_automerge_mixin.py | 2 +- fragmenstein/victor/_victor_validate_mixin.py | 2 +- test.py | 64 +-- 11 files changed, 6 insertions(+), 856 deletions(-) delete mode 100644 fragmenstein/rectifier/__init__.py delete mode 100644 fragmenstein/rectifier/_base.py delete mode 100644 fragmenstein/rectifier/_odd.py delete mode 100644 fragmenstein/rectifier/_ring.py delete mode 100644 fragmenstein/rectifier/_valence.py diff --git a/documentation/monster/no_template.md b/documentation/monster/no_template.md index 47720b8..27db7d7 100644 --- a/documentation/monster/no_template.md +++ b/documentation/monster/no_template.md @@ -90,7 +90,7 @@ and for rings of size 3/4 will become 5. ## Allenes -Additionally, are forbidden. +Additionally, allene are forbidden. ## Code caveat diff --git a/fragmenstein/__init__.py b/fragmenstein/__init__.py index 53b2757..f52eec3 100644 --- a/fragmenstein/__init__.py +++ b/fragmenstein/__init__.py @@ -27,5 +27,5 @@ warn(f'Victor (pipeline) unavailable — {err}.', category=ImportWarning) from .monster import Monster -from .rectifier import Rectifier +from molecular_rectifier import Rectifier from .m_rmsd import mRSMD diff --git a/fragmenstein/monster/_combine.py b/fragmenstein/monster/_combine.py index 81b3c7b..1d8020f 100644 --- a/fragmenstein/monster/_combine.py +++ b/fragmenstein/monster/_combine.py @@ -13,7 +13,7 @@ from ._base import _MonsterBase from ._communal import _MonsterCommunal from ._merge import _MonsterMerge -from ..rectifier import Rectifier +from molecular_rectifier import Rectifier ######################################################################################################################## diff --git a/fragmenstein/rectifier/__init__.py b/fragmenstein/rectifier/__init__.py deleted file mode 100644 index 0ab07c5..0000000 --- a/fragmenstein/rectifier/__init__.py +++ /dev/null @@ -1,51 +0,0 @@ -from __future__ import annotations -######################################################################################################################## - -__doc__ = \ - """ -Fix issue in auto-merging. - """ - -__author__ = "Matteo Ferla. [Github](https://github.com/matteoferla)" -__email__ = "matteo.ferla@gmail.com" -__date__ = "2020 A.D." -__license__ = "MIT" -__version__ = "0.4" -__citation__ = "" - -######################################################################################################################## - -from ._base import _RectifierBaseMixin # provides the __init__ and shared methods -from ._ring import _RectifierRingMixin # fixes rings -from ._odd import _RectifierOddMixin # fixes specific oddities -from ._valence import _RectifierValenceMixin # fixes valence -from rdkit import Chem - - -class Rectifier(_RectifierRingMixin, _RectifierOddMixin, _RectifierValenceMixin): - """ - Fixes the nastiness. - - Do note that that the Chem.Mol does not get modified in place. - ``.rwmol`` does and is a Chem.RWMol. The ``.mol`` is a Chem.Mol. - - The steps can be found in ``.modifications``. - - The .journal log is not given a handler. - - New atoms with have the bool prop ``_Novel``. - - Does not link distant atoms. For that see joining methods in Monster. - - >>> Rectifier(mol).fix().mol - """ - - def fix(self) -> Rectifier: - self.fix_rings() # from _RectifierRingMixin - self.prevent_oddities() # from _RectifierOddMixin - self.ununspecified_bonds() # from _RectifierValenceMixin - self.triage_rings() # from _RectifierValenceMixin - Chem.Cleanup(self.rwmol) - self.fix_issues() # from _RectifierValenceMixin - Chem.SanitizeMol(self.rwmol, sanitizeOps=Chem.SanitizeFlags.SANITIZE_ALL) - return self diff --git a/fragmenstein/rectifier/_base.py b/fragmenstein/rectifier/_base.py deleted file mode 100644 index c71914b..0000000 --- a/fragmenstein/rectifier/_base.py +++ /dev/null @@ -1,79 +0,0 @@ -######################################################################################################################## - -__doc__ = \ - """ - This has the methods common to ring and odd. - Formerly part of collapse_ring.py - """ - -__author__ = "Matteo Ferla. [Github](https://github.com/matteoferla)" -__email__ = "matteo.ferla@gmail.com" -__date__ = "2020 A.D." -__license__ = "MIT" -__version__ = "0.4" -__citation__ = "" - -######################################################################################################################## - -import json, itertools -from warnings import warn -from rdkit.Geometry.rdGeometry import Point3D -from collections import defaultdict -from rdkit import Chem -from rdkit.Chem import AllChem -from typing import Optional, Dict, List, Any, Tuple, Union -import numpy as np -from collections import Counter -import logging - -class _RectifierBaseMixin: - - journal = logging.getLogger('Fragmenstein') - - def __init__(self, mol: Chem.Mol, - atoms_in_bridge_cutoff:int = 2, - valence_correction: str = 'element', - debug: bool = False): - """ - Instantiates but does not call ``fix`` (or its specific methods). - - :param mol: Does not get edited. ``.mol`` does (but is a``Chem.RWMol``, so use ``mol.GetMol()``) - # how many bridge atoms can be deleted? (0 = preserves norbornane, 1 = preserves monsterantane) - - :param valence_correction: - :param debug: - """ - self.debug = bool(debug) - assert valence_correction in ('charge', 'element'), f'valence_correction "{valence_correction} id not charge/element' - self.valence_correction = str(valence_correction) - self.atoms_in_bridge_cutoff = int(atoms_in_bridge_cutoff) - self.rwmol = Chem.RWMol(mol) - self.modifications = [] # keeping track of steps - self._valence_mode = 'max' - self._iterations_done = 0 - self._subiterations_done = 0 - - @property - def mol(self) -> Chem.Mol: - return self.rwmol.GetMol() - - def _get_ring_info(self, mode='atom') -> Tuple[Tuple[int]]: - """ - you cannot get ring info on an unsanitized mol. Ironically I need ring info for sanitization - - :param mode: bond|atom - :return: same as mol.GetRingInfo().AtomRings() or .BondRings() - """ - mol2 = Chem.Mol(self.mol) - for bond in mol2.GetBonds(): - bond.SetBondType(Chem.BondType.UNSPECIFIED) - for atom in mol2.GetAtoms(): - atom.SetIsAromatic(False) - atom.SetAtomicNum(0) - Chem.SanitizeMol(mol2) - if mode == 'atom': - return mol2.GetRingInfo().AtomRings() - elif mode == 'bond': - return mol2.GetRingInfo().BondRings() - else: - raise ValueError(f'Unknown mode {mode}') diff --git a/fragmenstein/rectifier/_odd.py b/fragmenstein/rectifier/_odd.py deleted file mode 100644 index 0bb2fa1..0000000 --- a/fragmenstein/rectifier/_odd.py +++ /dev/null @@ -1,64 +0,0 @@ -######################################################################################################################## - -__doc__ = \ - """ - This add the oddity fixing functionality. Generally odd corner cases. - Formerly part of collapse_ring.py - """ - -__author__ = "Matteo Ferla. [Github](https://github.com/matteoferla)" -__email__ = "matteo.ferla@gmail.com" -__date__ = "2020 A.D." -__license__ = "MIT" -__version__ = "0.4" -__citation__ = "" - -######################################################################################################################## - -import json, itertools -from warnings import warn -from rdkit.Geometry.rdGeometry import Point3D -from collections import defaultdict -from rdkit import Chem -from rdkit.Chem import AllChem -from typing import Optional, Dict, List, Any, Tuple, Union -import numpy as np -from collections import Counter - -from ._base import _RectifierBaseMixin - - -class _RectifierOddMixin(_RectifierBaseMixin): - - def prevent_oddities(self): - self._prevent_allene() - - # ====== Private methods =========================================================================================== - - def _prevent_allene(self): - for atom in self.rwmol.GetAtoms(): - if atom.GetAtomicNum() < 14: - n = [] - for bond in atom.GetBonds(): - if bond.GetBondType().name in ('DOUBLE', 'TRIPLE'): - n.append(bond) - else: - pass - if len(n) > 2: - # this is a mess! - self.journal.info(f'Allene issue: {n} double bonds on {atom.GetSymbol()} atom {atom.GetIdx()}!') - for bond in n: - bond.SetBondType(Chem.BondType().SINGLE) - elif len(n) == 2: - # downgrade the higher bonded one! - others = [a for bond in n for a in (bond.GetBeginAtom(), bond.GetEndAtom()) if - a.GetIdx() != atom.GetIdx()] - others = sorted(others, key=lambda atom: sum([b.GetBondTypeAsDouble() for b in atom.GetBonds()])) - self.journal.info(f'Allene removed between {atom.GetIdx()} and {[a.GetIdx() for a in others]}') - self.rwmol.GetBondBetweenAtoms(atom.GetIdx(), others[-1].GetIdx()).SetBondType(Chem.BondType.SINGLE) - else: - pass - else: - continue - self.modifications.append(self.mol) - diff --git a/fragmenstein/rectifier/_ring.py b/fragmenstein/rectifier/_ring.py deleted file mode 100644 index 79b6413..0000000 --- a/fragmenstein/rectifier/_ring.py +++ /dev/null @@ -1,205 +0,0 @@ -######################################################################################################################## - -__doc__ = \ - """ - This add the ring fixing functionality. Fusing etc. - Formerly part of collapse_ring.py - """ - -__author__ = "Matteo Ferla. [Github](https://github.com/matteoferla)" -__email__ = "matteo.ferla@gmail.com" -__date__ = "2020 A.D." -__license__ = "MIT" -__version__ = "0.4" -__citation__ = "" - -######################################################################################################################## - -import json, itertools -from warnings import warn -from rdkit.Geometry.rdGeometry import Point3D -from rdkit import Chem -from rdkit.Chem import AllChem -from typing import Optional, Dict, List, Any, Tuple, Union -import numpy as np -from collections import Counter, defaultdict - -from ._base import _RectifierBaseMixin - -# ====================================================================================================================== - - -class _RectifierRingMixin(_RectifierBaseMixin): - - def fix_rings(self): - self._prevent_conjoined_ring() - self._prevent_weird_rings() - - def _prevent_conjoined_ring(self) -> None: - """ - This kills bridging bonds with not atoms in the bridge within rings. - So it is bridged, fused and spiro safe. - It removes only one bond, so andamantane/norbornane are safe. - """ - c = Counter([i for ring in self._get_ring_info() for i in ring]) - nested = [k for k in c if c[k] >= 3] - pairs = [(idx_a, idx_b) for idx_a, idx_b in itertools.combinations(nested, r=2) if - self.rwmol.GetBondBetweenAtoms(idx_a, idx_b) is not None] - rank = sorted(pairs, key=lambda x: c[x[0]] + c[x[1]], reverse=True) - if len(rank) > 0: - idx_a, idx_b = rank[0] - self.rwmol.RemoveBond(idx_a, idx_b) # SetBoolProp('_IsRingBond') is not important - self.journal.info(f'Zero-atom bridged ring issue: bond between {idx_a}-{idx_b} removed') - # re-run: - self._prevent_conjoined_ring() - self.modifications.append(self.mol) - - def _prevent_weird_rings(self): - ringatoms = self._get_ring_info() # GetRingInfo().AtomRings() - for ring_A, ring_B in itertools.combinations(ringatoms, r=2): - shared = set(ring_A).intersection(set(ring_B)) - if len(shared) == 0: - self.journal.debug(f'This molecule ({self.rwmol.GetProp("_Name")}) has some separate rings') - pass # separate rings - elif len(shared) < self.atoms_in_bridge_cutoff and \ - self.atoms_in_bridge_cutoff >= 2 \ - and len(ring_A) == len(ring_B): - # adamantene/norbornane/tropinone kind of thing - self.journal.warning(f'This molecule ({self.rwmol.GetProp("_Name")}) has a bridge: leaving') - pass # ideally check if planar... - elif len(shared) == 1: - self.journal.debug(f'This molecule ({self.rwmol.GetProp("_Name")}) has a spiro bicycle') - pass # spiro ring. - elif len(shared) == 2: - self.journal.debug(f'This molecule ({self.rwmol.GetProp("_Name")}) has a fused ring') - if self.rwmol.GetBondBetweenAtoms(*shared) is not None: - pass # indole/naphtalene - small, big = sorted([ring_A, ring_B], key=lambda ring: len(ring)) - if len(small) == 4: - self.journal.warning(f'This molecule ({self.rwmol.GetProp("_Name")}) has a benzo-azetine–kind-of-thing: expanding to indole') - # Chem.MolFromSmiles('C12CCCCC1CC2') - # benzo-azetine is likely an error: add and extra atom - a, b = set(small).difference(big) - self._place_between(a, b) - elif len(small) == 3: - self.journal.warning(f'This molecule ({self.rwmol.GetProp("_Name")}) has a benzo-cyclopropane–kind-of-thing: expanding to indole') - # Chem.MolFromSmiles('C12CCCCC1C2') - # benzo-cyclopronane is actually impossible at this stage. - a = list(set(small).difference(big))[0] - for b in shared: - self._place_between(a, b) - else: - pass # indole and nathalene - elif (len(ring_A), len(ring_B)) == (6, 6): - raise Exception('This is utterly impossible') - else: - self.journal.warning(f'mysterious ring system {len(ring_A)} + {len(ring_B)}') - pass # ???? - elif len(shared) < self.atoms_in_bridge_cutoff: - # adamantene/norbornane/tropinone kind of thing - self.journal.warning(f'This molecule ({self.rwmol.GetProp("_Name")}) has a bridge: leaving') - pass # ideally check if planar... - else: - self.journal.warning(f'This molecule ({self.rwmol.GetProp("_Name")}) has a bridge that will be removed') - self._prevent_bridge_ring(ring_A) - # start from scratch. - self._prevent_weird_rings() - self.modifications.append(self.mol) - - # ===== Dep of prevent weird rings ================================================================================= - - def _place_between(self, a: int, b: int, aromatic: Optional[bool] = None, atomic_number: int = 6) -> None: - """ - Places an C atom, possibly of type aromatic, between atom of index a, and of b. - - :param a: index of atom A - :param b: index of atom B - :param aromatic: bool of aromaticity (False = Single, None = copy, True = aromatic) - :param atomic_number: Carbon is 6. - :return: - """ - oribond = self.rwmol.GetBondBetweenAtoms(a, b) - if oribond is None: - self.journal.critical(f'FAIL. There should be a bond btween {a} and {b}') - return None # fail - elif aromatic is True: - bt = Chem.BondType.AROMATIC - elif aromatic is False: - bt = Chem.BondType.SINGLE - else: - bt = oribond.GetBondType() - idx = self.rwmol.AddAtom(Chem.Atom(atomic_number)) - neoatom = self.rwmol.GetAtomWithIdx(idx) - atom_a = self.rwmol.GetAtomWithIdx(a) - atom_b = self.rwmol.GetAtomWithIdx(b) - if aromatic: - neoatom.SetIsAromatic(True) - atom_a.SetIsAromatic(True) - atom_b.SetIsAromatic(True) - # prevent constraints - neoatom.SetBoolProp('_Novel', True) - atom_a.SetBoolProp('_Novel', True) - atom_b.SetBoolProp('_Novel', True) - # fix position - conf = self.rwmol.GetConformer() - pos_A = conf.GetAtomPosition(a) - pos_B = conf.GetAtomPosition(b) - x = pos_A.x / 2 + pos_B.x / 2 - y = pos_A.y / 2 + pos_B.y / 2 - z = pos_A.z / 2 + pos_B.z / 2 - conf.SetAtomPosition(idx, Point3D(x, y, z)) - # fix bonds - self.rwmol.RemoveBond(a, b) - self.rwmol.AddBond(a, idx, bt) - self.rwmol.AddBond(b, idx, bt) - - def _prevent_bridge_ring(self, examplar: Tuple[int]) -> None: - # examplar is ring - ringatoms = self._get_ring_info() # GetRingInfo().AtomRings() - ringatoms = [ring for ring in ringatoms if set(ring).intersection(examplar)] - ring_idx = list(range(len(ringatoms))) - shared_count = {} - for ra, rb in itertools.combinations(ring_idx, r=2): - shared_count[(ra, rb)] = len(set(ringatoms[ra]).intersection(set(ringatoms[rb]))) - if len(shared_count) == 0: - return None - ra, rb = list(shared_count.keys())[0] - shared = list(set(ringatoms[ra]).intersection(ringatoms[rb])) - has_bond = lambda a, b: self.rwmol.GetBondBetweenAtoms(a, b) is not None - pairs = [(a, b) for a, b in itertools.combinations(shared, r=2) if has_bond(a, b)] - c = Counter([i for pair in pairs for i in pair]) - ring_A, ring_B = ringatoms[ra], ringatoms[rb] - small, big = sorted([ring_A, ring_B], key=lambda ring: len(ring)) - inners = [i for i in c if c[i] > 1] - x = list(set(shared).difference(inners)) - if len(x) != 2: - self.journal.critical( - f'This is impossible. {ringatoms} share {shared} with {inners} in the inside and {x} on the edge?') - return None - a, b = x - if len(big) > 6: - self.journal.warning(f'Removing {len(inners)} bridging atoms and replacing with fused ring') - # bond the vertices - bt = Chem.BondType.SINGLE # ??? - if self.rwmol.GetBondBetweenAtoms(a, b) is None: - self.rwmol.AddBond(a, b, bt) - else: - self.journal.warning('This is really odd! Why is there a bond already??') - # remove the middle atoms. - for i in sorted(inners, reverse=True): - self.rwmol.RemoveAtom(i) - else: - self.journal.warning(f'Shriking the smaller ring to change from bridged to fused.') - # get the neighbour in the small atom to a vertex. - neighs = [neigh for neigh in self.rwmol.GetAtomWithIdx(a).GetNeighbors() if - neigh.GetIdx() not in shared and neigh.GetIdx() in small] - neigh = sorted(neighs, key=lambda atom: atom.GetSymbol() != 'C')[0] - bt = self.rwmol.GetBondBetweenAtoms(a, neigh.GetIdx()).GetBondType() - self.rwmol.RemoveBond(a, neigh.GetIdx()) - new_neigh = [neigh for neigh in self.rwmol.GetAtomWithIdx(a).GetNeighbors() if neigh.GetIdx() in shared][0] - self.rwmol.AddBond(neigh.GetIdx(), new_neigh.GetIdx(), bt) - neigh.SetBoolProp('_Novel', True) - new_neigh.SetBoolProp('_Novel', True) - self.rwmol.GetAtomWithIdx(a).SetBoolProp('_Novel', True) - - diff --git a/fragmenstein/rectifier/_valence.py b/fragmenstein/rectifier/_valence.py deleted file mode 100644 index 5ef1d04..0000000 --- a/fragmenstein/rectifier/_valence.py +++ /dev/null @@ -1,389 +0,0 @@ -######################################################################################################################## - -__doc__ = \ - """ - This add the oddity fixing functionality. Generally odd corner cases. - Formerly part of collapse_ring.py - """ - -__author__ = "Matteo Ferla. [Github](https://github.com/matteoferla)" -__email__ = "matteo.ferla@gmail.com" -__date__ = "2020 A.D." -__license__ = "MIT" -__version__ = "0.4" -__citation__ = "" - -######################################################################################################################## -from rdkit import Chem -from typing import Optional, List, Tuple, Union -import warnings, random -import itertools - - -# when hits are combined they can result in odd valence and other issues. - -from ._base import _RectifierBaseMixin - -class _RectifierValenceMixin(_RectifierBaseMixin): - """ - Checks whether the valence is right and corrects by either shifting the element or adding a charge. - With the following exceptions: - - * Texas carbon -> Sulfur - * Hydrogen -> Fluoride shifted downwards - * Carbon in aromatic ring -> single bond ring - """ - # ========= Three main steps ======================================================================================= - - def ununspecified_bonds(self) -> None: - """ - This get run during instantiation. It is the first one run. - BondType.UNSPECIFIED ==> BondType.SINGLE - - :return: None - """ - for bond in self.rwmol.GetBonds(): - if bond.GetBondType().name == 'UNSPECIFIED': - self.journal.debug(f'Fixing unspecified bond {bond.GetIdx()}') - bond.SetBondType(Chem.BondType.SINGLE) - # debug: - self.modifications.append(self.mol) - - def triage_rings(self) -> None: - """ - This get run during instantiation. It is the second one run. - It is also run again by `fix_issues` the third step after a weird valence change. - Deals with rings. - - :return: None - """ - # upgrade to aromatic if aromatic. - rings = self._get_ring_info() - for ring in rings: - if self._is_aromatic_ring(ring, rings): - for i, ni in self._get_ring_neighbors(ring): - self.rwmol.GetBondBetweenAtoms(i, ni).SetBondType(Chem.BondType.AROMATIC) - # downgrade to single if non-ring aromatic - for i, atom in enumerate(self.rwmol.GetAtoms()): - if any([i in r for r in rings]): - continue # ring - else: # non-ring - for bond in atom.GetBonds(): - if bond.GetBondType().name == 'AROMATIC': - self.journal.debug(f'donwgrading bond {i}') - bond.SetBondType(Chem.BondType.SINGLE) - # aromatics - for ring in sorted(rings, key=self._is_aromatic_ring): - if self._is_aromatic_ring(ring, rings): # the nonaromatic rings will be done first. - for i in ring: - self.rwmol.GetAtomWithIdx(i).SetIsAromatic(True) - else: - for i in ring: - self.rwmol.GetAtomWithIdx(i).SetIsAromatic(False) - self.modifications.append(self.mol) # may not have changed. - - def fix_issues(self, _previous=None) -> None: - """ - This get run during instantiation. It is the third and final one run before sanitization. - Deals with a variety of problems. - It calls itself until no problems according to `Chem.DetectChemistryProblems` exits. - It is a bit shoddy and any oddity likely steps from here. TODO - - :return: None - """ - self.modifications.append(self.mol) # may not have changed. - problems = Chem.DetectChemistryProblems(self.rwmol) - if self._iterations_done > 100: - self.journal.error(f'Iterations maxed out!') - return None - elif self._subiterations_done > 5: - self.journal.error(f'Unfixable') - return None - elif len(problems) == 0: - return None - else: - self.journal.debug(f'(Iteration: {self._iterations_done}) N problems {len(problems)}') - p = problems[0] - self.journal.debug(f'(Iteration: {self._iterations_done}) Issue {p.GetType()}: {p.Message()}') - if p.Message() == _previous: - self.triage_rings() - ############################################################ - if p.GetType() == 'KekulizeException': - if p.Message() != _previous: - N = self._get_nitrogens(p.GetAtomIndices()) - if len(N) > 0 and self._nitrogen_protonate(N, p.Message()): - pass # been fixed. - else: - # triage rings should have altered any not ring atoms that are aromatic. - # self._get_ring_info() - # so it is likely a hetatom thing. - self.journal.info(f'Ring triages seems to have failed. Is it a valence thing?') - valence_issues = [self._has_correct_valence(i) for i in p.GetAtomIndices()] - if not all(valence_issues): - for i in p.GetAtomIndices(): - self.fix_valence(i) - else: - self.journal.warning(f'Attempting default valency (not max)') - self._valence_mode = 'default' - for i in p.GetAtomIndices(): - self.fix_valence(i) - self._valence_mode = 'max' - else: - for i in p.GetAtomIndices(): - self.downgrade_ring(self.rwmol.GetAtomWithIdx(i)) - self.triage_rings() - ############################################################ - elif p.GetType() == 'AtomKekulizeException' and 'non-ring atom' in p.Message(): - atom = self.rwmol.GetAtomWithIdx(p.GetAtomIdx()) - atom.SetIsAromatic(False) - self.journal.debug(f'Atom {p.GetAtomIdx()} set to non-aromatic.') - for bond in atom.GetBonds(): - bond.SetBondType(Chem.BondType.SINGLE) - elif p.GetType() == 'AtomKekulizeException' and 'Aromatic bonds on non aromatic atom' in p.Message(): - atom = self.rwmol.GetAtomWithIdx(p.GetAtomIdx()) - self.journal.debug(f'Atom {p.GetAtomIdx()} set to aromatic.') - atom.SetIsAromatic(True) - ############################################################ - elif p.GetType() == 'AtomValenceException': - i = p.GetAtomIdx() - self.fix_valence(i) - else: - self.journal.error('???', p.GetType(), p.Message()) - self._iterations_done += 1 - if _previous != p.Message(): - self.journal.debug(f'{self._iterations_done} appears successful.') - self._subiterations_done = 0 - else: - self._subiterations_done += 1 - self.journal.debug(f'{self._iterations_done} appears unsuccessful.') - return self.fix_issues(_previous=p.Message()) - - # ========= Methods that circumvent the nonsanitization ============================================================ - - def _get_valence_difference(self, atom: Chem.Atom) -> int: - pt = Chem.GetPeriodicTable() - valence = self._get_atom_valence(atom) - if self._valence_mode == 'max': - maxv = max(pt.GetValenceList(atom.GetAtomicNum())) - return valence - maxv - else: - d = pt.GetDefaultValence(atom.GetAtomicNum()) - return valence - d - - def _get_atom_valence(self, atom: Chem.Atom): - """ - Cannot get the normal way as it cannot be sanitised. - - :param atom: - :return: - """ - valence = 0 - for bond in atom.GetBonds(): - valence += bond.GetBondTypeAsDouble() - return valence - atom.GetFormalCharge() - - def _has_correct_valence(self, atom: Union[Chem.Atom, int]): - if isinstance(atom, Chem.Atom): - return self._get_valence_difference(atom) <= 0 - elif isinstance(atom, int): - atom = self.rwmol.GetAtomWithIdx(atom) - return self._get_valence_difference(atom) <= 0 - - # ========= rings ================================================================================================== - - def _get_atoms_at_fusion(self, ring, rings): - fused = [] - if rings is not None: - for other in rings: - if other == ring: - pass - elif not set(ring).isdisjoint(other): - fused.extend(set(ring).intersection(other)) - return fused - - def _is_aromatic_ring(self, ring: Tuple[int], rings=None) -> bool: - """ - :param ring: GetRingInfo().AtomRings() entry - :return: - """ - fused = self._get_atoms_at_fusion(ring, rings) - for i in list(set(ring).difference(fused)): - atom_i = self.rwmol.GetAtomWithIdx(i) - for n in atom_i.GetNeighbors(): - ni = n.GetIdx() - if ni in ring: - if self.rwmol.GetBondBetweenAtoms(i, ni).GetBondType().name == 'AROMATIC': - return True - else: - return False - - def _get_ring_neighbors(self, ring: Tuple[int]) -> List[Tuple[int, int]]: - """ - :param ring: GetRingInfo().AtomRings() entry - :return: list of pairs of indices that are neighbors in the ring - """ - rns = [] - for i in ring: - atom = self.rwmol.GetAtomWithIdx(i) - for n in atom.GetNeighbors(): - ni = n.GetIdx() - if ni in ring: - rns.append((i, ni)) - return rns - - def _get_aroma(self, atom, this_bond): - # determine if the bond of the atom is aromatic - return [b for b in atom.GetBonds() if b.GetIdx() != this_bond and b.GetBondType().name == 'AROMATIC'] - - def _get_other(self, bond, these_atoms): - others = [a for a in (bond.GetBeginAtom(), bond.GetEndAtom()) if a.GetIdx() not in these_atoms] - if others: - other = others[0] - other.SetIsAromatic(False) - return other - - def downgrade_ring(self, atom: Chem.Atom): - ## very crappy way of doing this - self.journal.debug(f'downgrading whole ring!') - atom.SetIsAromatic(False) - ringinfo = self._get_ring_info(mode='atom') - get_atomrings = lambda ai: [ring for ring in ringinfo if ai in ring] - atomrings = get_atomrings(atom.GetIdx()) - for atomring in atomrings: - rnieghs = self._get_ring_neighbors(atomring) - for n1, n2 in rnieghs: - self.rwmol.GetAtomWithIdx(n1).SetIsAromatic(False) - self.rwmol.GetAtomWithIdx(n2).SetIsAromatic(False) - self.rwmol.GetBondBetweenAtoms(n1, n2).SetBondType(Chem.BondType.SINGLE) - for atomring in atomrings: - rnieghs = self._get_ring_neighbors(atomring) - for n1, n2 in rnieghs: - if self._get_valence_difference(self.rwmol.GetAtomWithIdx(n1)) <= -2 and \ - self._get_valence_difference(self.rwmol.GetAtomWithIdx(n2)) <= -2: - self.rwmol.GetBondBetweenAtoms(n1, n2).SetBondType(Chem.BondType.DOUBLE) - - # if len(self._get_rings(atom.GetIdx())) == 1: - # for bond in atom.GetBonds(): - # bond.SetBondType(Chem.BondType.SINGLE) - # other = self._get_other(bond, [atom.GetIdx()]) - # aro = self._get_aroma(other, bond.GetIdx()) - # if aro: - # aro[0].SetBondType(Chem.BondType.DOUBLE) - # doubleother = self._get_other(aro[0], [atom.GetIdx(), other.GetIdx()]) - # for b in doubleother.GetBonds(): - # if b.GetBondType() == Chem.BondType.AROMATIC: - # b.SetBondType(Chem.BondType.SINGLE) - # neigh = self._get_other(b, [doubleother.GetIdx()]) - # if neigh: - # neigh.SetIsAromatic(False) - - # ========= Sanitization based fixes =============================================================================== - - def _nitrogen_protonate(self, nitrogens, previous): - """ - - :param nitrogens: list of Nitrogens - :param previous: - :return: - """ - def reset(): - for n in nitrogens: - self.rwmol.GetAtomWithIdx(n).SetNumExplicitHs(0) - - reset() - p = Chem.DetectChemistryProblems(self.rwmol) - if len(p) == 0 or p[0].Message() != previous: - return True - for i in range(1, len(nitrogens)): - for c in itertools.combinations(nitrogens, i): - reset() - for n in c: - self.rwmol.GetAtomWithIdx(n).SetNumExplicitHs(1) - p = Chem.DetectChemistryProblems(self.rwmol) - if len(p) == 0 or p[0].Message() != previous: - return True - return False - - self.journal.debug(f'KekulizeException likely caused by nitrogen') - - # ========= other helpers ========================================================================================== - - def _get_nitrogens(self, indices): - """ - Called when ``KekulizeException`` happends during ``.fix_issues`` - - :param indices: - :return: - """ - return [i for i in indices if self.rwmol.GetAtomWithIdx(i).GetSymbol() == 'N'] - - # ========= shift/charge =========================================================================================== - - def _adjust_for_fix_valence(self, atom): - df = self._get_valence_difference(atom) - ori = atom.GetSymbol() - if self.valence_correction == 'charge': - atom.SetFormalCharge(df) - elif self.valence_correction == 'element': - # ## correct row - n = atom.GetAtomicNum() - if n == 1: - atom.SetAtomicNum(8) - elif n > 10: - n = (n % 8) - 2 + 8 - atom.SetAtomicNum(n) - # ## correct column - if len(atom.GetNeighbors()) > 4: - self._break_bonds(atom) - # elif len(atom.GetNeighbors()) > 4 and n <= 16: # S... - # atom.SetAtomicNum(16) - elif n - df < 6: # C -> B no! - for bond in atom.GetBonds(): - bond.SetBondType(Chem.BondType.SINGLE) - else: # N, O, F etc. - atom.SetAtomicNum(int(n - df)) - self.journal.info(f'Shifting atom from {ori} to {atom.GetSymbol()}') - else: - raise ValueError(f'self.valence_correction can only be "element"/"charge" not {self.valence_correction}.') - - def _break_bonds(self, atom): - """ - Extreme last ditch. Breaks off all non-ring bonds to atom. - Will likely trigger emergency_joining. - - :param atom: - :return: - """ - self.journal.warning(f'In molecule ({self.rwmol.GetProp("_Name")}) reaking bond to atom {atom.GetIdx()}') - ring_indices = [a for ring in self._get_ring_info() for a in ring] - for neigh in atom.GetNeighbors(): - if neigh.GetIdx() in ring_indices or neigh.GetSymbol() == '*': - continue - else: - self.rwmol.RemoveBond(atom.GetIdx(), neigh.GetIdx()) - - - def fix_valence(self, i): - atom = self.rwmol.GetAtomWithIdx(i) - atom.SetFormalCharge(0) - atom.SetNumExplicitHs(0) - self.journal.debug(f'{i} {atom.GetSymbol()}: {len(atom.GetNeighbors())} bonds {self._get_atom_valence(atom)}') - if self._has_correct_valence(atom): - self.journal.debug('\tValence seems correct') - return None - elif atom.GetSymbol() == 'C' and len(atom.GetNeighbors()) > 4: - self.journal.debug('\ttexas carbon --> S') - atom.SetAtomicNum(16) - elif atom.GetSymbol() == 'C' and atom.GetIsAromatic() and len(atom.GetNeighbors()) == 4: - self.journal.debug('\tDowngrading ring') - self.downgrade_ring(atom) - elif atom.GetSymbol() == 'C': - for bond in atom.GetBonds(): - bond.SetBondType(Chem.BondType.SINGLE) - else: - self._adjust_for_fix_valence(atom) - # did it work? - if self._has_correct_valence(atom): - return self.rwmol - else: - return self.fix_valence(i) diff --git a/fragmenstein/victor/_victor_automerge_mixin.py b/fragmenstein/victor/_victor_automerge_mixin.py index 9396c96..38596f0 100644 --- a/fragmenstein/victor/_victor_automerge_mixin.py +++ b/fragmenstein/victor/_victor_automerge_mixin.py @@ -2,7 +2,7 @@ from ..monster import Monster from ..igor import Igor from ..m_rmsd import mRSMD -from ..rectifier import Rectifier +from molecular_rectifier import Rectifier from typing import List, Optional, Dict, Union, Callable from rdkit import Chem from rdkit.Chem import AllChem diff --git a/fragmenstein/victor/_victor_validate_mixin.py b/fragmenstein/victor/_victor_validate_mixin.py index ca7e033..a4804c9 100644 --- a/fragmenstein/victor/_victor_validate_mixin.py +++ b/fragmenstein/victor/_victor_validate_mixin.py @@ -2,7 +2,7 @@ from ..monster import Monster from ..igor import Igor from ..m_rmsd import mRSMD -from ..rectifier import Rectifier +from molecular_rectifier import Rectifier from typing import List, Optional, Dict, Union, Callable from rdkit import Chem from rdkit.Chem import AllChem diff --git a/test.py b/test.py index 89f90db..6f18096 100644 --- a/test.py +++ b/test.py @@ -8,7 +8,7 @@ from rdkit import Chem from rdkit.Chem import AllChem -from fragmenstein import Monster, Victor, Igor, Rectifier +from fragmenstein import Monster, Victor, Igor from fragmenstein.mpro import MProVictor from typing import * import numpy as np @@ -106,68 +106,6 @@ def test_pentachromatic(self): # ====================================================================================================================== - -class RectifierTester(unittest.TestCase): - def test_rectifier(self): - # name: [before, after] - chemdex = {'phenylnaphthalene': ('c1ccc2ccccc2c1(c3ccccc3)', 'c1ccc(-c2cccc3ccccc23)cc1'), - 'benzo-azetine': ('C12CCCCC1CC2', 'C1CCC2CCCC2C1'), - # 'conjoined': ('C1C2CCC2C1', 'C1CCCCC1'), # bridged hexane - 'allene': ('C=C=C', 'C=CC'), - 'benzo-cyclopronane': ('C12CCCCC1C2', 'C1CCC2CCCC2C1'), - # 'norbornane': ('C1CC2CCC1C2', 'C1CC2CCC1C2'), - 'mixed ring': ('c1cccc2c1CCCC2', 'c1ccc2c(c1)CCCC2'), - 'mixed ring': ('C1CCCc2c1cccc2', 'c1ccc2c(c1)CCCC2'), - } - - for name in chemdex: - before, after = chemdex[name] - mol = Chem.MolFromSmiles(before) - mol.SetProp('_Name', name) - AllChem.EmbedMolecule(mol) - recto = Rectifier(mol).fix() - gotten = Chem.MolToSmiles(recto.mol) - self.assertEqual(gotten, after, f'{name} failed {gotten} (expected {after}) from {before}') - - def test_cyclopentine(self): - # aromatic cyclopent-ine -> cyclopentadiene - name = 'cyclopentine' - mol = Chem.MolFromSmiles('[nH]1cccc1') - mol.SetProp('_Name', name) - AllChem.EmbedMolecule(mol) - mod = Chem.RWMol(mol) - mod.GetAtomWithIdx(0).SetAtomicNum(6) - mol = mod.GetMol() - recto = Rectifier(mol, atoms_in_bridge_cutoff=3).fix() - gotten = Chem.MolToSmiles(recto.mol) - after = 'C1=CCC=C1' - self.assertEqual(gotten, after, f'{name} failed {gotten} (expected {after})') - - def test_bad_ring(self): - name = 'bad ring' - after = 'c1ccc2c(c1)CCCC2' - mol = Chem.MolFromSmiles(after) - mol.SetProp('_Name', name) - mol.GetBondBetweenAtoms(0, 1).SetBondType(Chem.BondType.SINGLE) - before = Chem.MolToSmiles(mol) - recto = Rectifier(mol).fix() - gotten = Chem.MolToSmiles(recto.mol) - self.assertEqual(gotten, after, f'{name} failed {gotten} (expected {after})') - - def test_bad_ring2(self): - name = 'bad ring2' - before = 'c1ccc2c(c1)CCCC2' - after = 'c1ccc2ccccc2c1' - mol = Chem.MolFromSmiles(before) - mol.SetProp('_Name', name) - mol.GetBondBetweenAtoms(0, 1).SetBondType(Chem.BondType.SINGLE) - mol.GetBondBetweenAtoms(6, 7).SetBondType(Chem.BondType.AROMATIC) - before = Chem.MolToSmiles(mol) - recto = Rectifier(mol).fix() - gotten = Chem.MolToSmiles(recto.mol) - self.assertEqual(gotten, after, f'{name} failed {gotten} (expected {after})') - - class RingTestsVictor(unittest.TestCase): def test_orthomethyltoluene(self): From 9bf9d49a458461ca2aa722b6281546629b406d3a Mon Sep 17 00:00:00 2001 From: matteoferla Date: Fri, 12 Feb 2021 19:10:48 +0000 Subject: [PATCH 31/32] :fire: cleaned up victor --- fragmenstein/igor/__init__.py | 8 +- .../{_igor_init_mixin.py => _igor_init.py} | 9 +- .../igor/{_igor_min_mixin.py => _igor_min.py} | 2 +- fragmenstein/igor/_igor_utils_mixin.py | 2 +- fragmenstein/laboratory/__init__.py | 1 - fragmenstein/laboratory/_process.py | 4 +- fragmenstein/laboratory/pyrosetta_log.py | 44 -- fragmenstein/monster/_base.py | 1 - fragmenstein/monster/_communal.py | 3 +- fragmenstein/mpro/__init__.py | 1 - fragmenstein/victor/__init__.py | 733 +----------------- fragmenstein/victor/_loggerwriter.py | 2 +- .../victor/_victor_automerge_mixin.py | 301 ------- fragmenstein/victor/_victor_base.py | 164 ++++ fragmenstein/victor/_victor_base_mixin.py | 110 --- fragmenstein/victor/_victor_combine.py | 149 ++++ fragmenstein/victor/_victor_common.py | 350 +++++++++ fragmenstein/victor/_victor_igor.py | 109 +++ fragmenstein/victor/_victor_journal.py | 122 +++ fragmenstein/victor/_victor_overridables.py | 31 + fragmenstein/victor/_victor_place.py | 111 +++ fragmenstein/victor/_victor_plonk.py | 125 +++ fragmenstein/victor/_victor_safety.py | 53 ++ fragmenstein/victor/_victor_store.py | 93 +++ ...victor_utils_mixin.py => _victor_utils.py} | 169 +--- ..._validate_mixin.py => _victor_validate.py} | 4 +- 26 files changed, 1368 insertions(+), 1333 deletions(-) rename fragmenstein/igor/{_igor_init_mixin.py => _igor_init.py} (96%) rename fragmenstein/igor/{_igor_min_mixin.py => _igor_min.py} (99%) delete mode 100644 fragmenstein/laboratory/pyrosetta_log.py delete mode 100644 fragmenstein/victor/_victor_automerge_mixin.py create mode 100644 fragmenstein/victor/_victor_base.py delete mode 100644 fragmenstein/victor/_victor_base_mixin.py create mode 100644 fragmenstein/victor/_victor_combine.py create mode 100644 fragmenstein/victor/_victor_common.py create mode 100644 fragmenstein/victor/_victor_igor.py create mode 100644 fragmenstein/victor/_victor_journal.py create mode 100644 fragmenstein/victor/_victor_overridables.py create mode 100644 fragmenstein/victor/_victor_place.py create mode 100644 fragmenstein/victor/_victor_plonk.py create mode 100644 fragmenstein/victor/_victor_safety.py create mode 100644 fragmenstein/victor/_victor_store.py rename fragmenstein/victor/{_victor_utils_mixin.py => _victor_utils.py} (79%) rename fragmenstein/victor/{_victor_validate_mixin.py => _victor_validate.py} (91%) diff --git a/fragmenstein/igor/__init__.py b/fragmenstein/igor/__init__.py index ce29ae1..ea26c31 100644 --- a/fragmenstein/igor/__init__.py +++ b/fragmenstein/igor/__init__.py @@ -15,14 +15,14 @@ from typing import Dict, List, Optional, Tuple, Union, Sequence -from ._igor_init_mixin import _IgorInitMixin, pyrosetta -from ._igor_min_mixin import _IgorMinMixin -from ._igor_utils_mixin import _IgorUtilsMixin +from ._igor_init import _IgorInit, pyrosetta +from ._igor_min import _IgorMin +from ._igor_utils_mixin import _IgorUtils # this contains the init and the two classmethods. -class Igor(_IgorInitMixin, _IgorMinMixin, _IgorUtilsMixin): +class Igor(_IgorInit, _IgorMin, _IgorUtils): """ Regular Igor(..) accepts pyrosetta pose. ``Igor.from_pdbblock(..)`` accepts pdb block as str, diff --git a/fragmenstein/igor/_igor_init_mixin.py b/fragmenstein/igor/_igor_init.py similarity index 96% rename from fragmenstein/igor/_igor_init_mixin.py rename to fragmenstein/igor/_igor_init.py index 311e32b..7f52e62 100644 --- a/fragmenstein/igor/_igor_init_mixin.py +++ b/fragmenstein/igor/_igor_init.py @@ -5,13 +5,6 @@ base methods """ -__author__ = "Matteo Ferla. [Github](https://github.com/matteoferla)" -__email__ = "matteo.ferla@gmail.com" -__date__ = "2020 A.D." -__license__ = "MIT" -__version__ = "0.4" -__citation__ = "" - ######################################################################################################################## import pyrosetta @@ -21,7 +14,7 @@ from warnings import warn -class _IgorInitMixin: +class _IgorInit: atom_pair_constraint = 10 angle_constraint = 10 coordinate_constraint = 1 diff --git a/fragmenstein/igor/_igor_min_mixin.py b/fragmenstein/igor/_igor_min.py similarity index 99% rename from fragmenstein/igor/_igor_min_mixin.py rename to fragmenstein/igor/_igor_min.py index 9c2b183..7d28386 100644 --- a/fragmenstein/igor/_igor_min_mixin.py +++ b/fragmenstein/igor/_igor_min.py @@ -17,7 +17,7 @@ from rdkit.Chem import AllChem -class _IgorMinMixin: +class _IgorMin: def __init__(self): warn('THIS METHOD SHOULD NOT BE RUN. INHERIT _init_') diff --git a/fragmenstein/igor/_igor_utils_mixin.py b/fragmenstein/igor/_igor_utils_mixin.py index 8962f6c..14265cb 100644 --- a/fragmenstein/igor/_igor_utils_mixin.py +++ b/fragmenstein/igor/_igor_utils_mixin.py @@ -13,7 +13,7 @@ import pyrosetta -class _IgorUtilsMixin: +class _IgorUtils: def dock(self) -> pyrosetta.Pose: """ diff --git a/fragmenstein/laboratory/__init__.py b/fragmenstein/laboratory/__init__.py index f914f4f..bc613f1 100644 --- a/fragmenstein/laboratory/__init__.py +++ b/fragmenstein/laboratory/__init__.py @@ -1,4 +1,3 @@ from ._process import process # config for a run from .laboratory import Laboratory # prepping data and analysis from .make_pyrosetta_options import make_option_string # make the pyrosetta init str a dict -from .pyrosetta_log import get_log_entries, configure_logger # capture log properly diff --git a/fragmenstein/laboratory/_process.py b/fragmenstein/laboratory/_process.py index cdd0271..7c69bf7 100644 --- a/fragmenstein/laboratory/_process.py +++ b/fragmenstein/laboratory/_process.py @@ -28,12 +28,12 @@ def process(data: Dict[str, Union[str, dict]]): # settings for Fragmenstein ------------------------------------ MProVictor.work_path = f'{project}' # db_name MProVictor.monster_throw_on_discard = True - MProVictor.monster_joining_cutoff = 5 # 10 + MProVictor.joining_cutoff = 5 # 10 MProVictor.quick_renanimation = False MProVictor.error_to_catch = Exception MProVictor.enable_stdout(logging.ERROR) MProVictor.enable_logfile(f'{project}.log', logging.INFO) - MProVictor.log_errors() + MProVictor.capture_rdkit_log() # analyse ------------------------------------------------------ try: v = MProVictor.combine(hits=hits) diff --git a/fragmenstein/laboratory/pyrosetta_log.py b/fragmenstein/laboratory/pyrosetta_log.py deleted file mode 100644 index f1d75c9..0000000 --- a/fragmenstein/laboratory/pyrosetta_log.py +++ /dev/null @@ -1,44 +0,0 @@ -## Copied from https://github.com/matteoferla/pyrosetta_scripts/tree/main/init_helper - -import io -import logging -import pyrosetta -import re -from typing import Union, List - - -def configure_logger() -> logging.Logger: - """ - The function `get_logger`, simply adds a stringIO handler to the log and captures the log, - thus making it easier to use. - The function `get_log_entries`, spits out entries of a given level. - - :return: logger - """ - pyrosetta.logging_support.set_logging_sink() - logger = logging.getLogger("rosetta") - logger.setLevel(logging.INFO) # default = logging.WARNING - stringio = io.StringIO() - handler = logging.StreamHandler(stringio) - handler.setLevel(logging.INFO) - # handler.set_name('stringio') - handler.setFormatter(logging.Formatter('[%(asctime)s] %(levelname)s - %(message)s')) - logger.addHandler(handler) - return logger - - -def get_log_entries(levelname: Union[str, int] = logging.INFO) -> List[str]: - """ - Get a list of all entries in log at a given level. - levelname can be either an int (``logging.INFO`` etc. are numbers multiples of 10 in increasing severity) - or a string of the level. - Note that it is very crude: if INFO is requested, ERROR is not shown! - - :param levelname: int for the level number or str of the name - :return: List of str - """ - if isinstance(levelname, int): - # logging.INFO is actually an int, not an enum - levelname = logging.getLevelName(levelname) - stringio = logging.getLogger("rosetta").handlers[0].stream - return re.findall(f'(\[.*\] {levelname} - [\w\W]*)', stringio.getvalue()) diff --git a/fragmenstein/monster/_base.py b/fragmenstein/monster/_base.py index a29e879..f1aca0b 100644 --- a/fragmenstein/monster/_base.py +++ b/fragmenstein/monster/_base.py @@ -24,7 +24,6 @@ class _MonsterBase: dummy = Chem.MolFromSmiles(dummy_symbol) #: The virtual atom where the targets attaches # settings... - joining_cutoff = 5. # how distant (in Å) is too much? atoms_in_bridge_cutoff = 2 # atoms_in_bridge_cutoff is how many bridge atoms can be deleted? # (0 = preserves norbornane, 1 = preserves adamantane) diff --git a/fragmenstein/monster/_communal.py b/fragmenstein/monster/_communal.py index 547abe0..e0a7e24 100644 --- a/fragmenstein/monster/_communal.py +++ b/fragmenstein/monster/_communal.py @@ -463,4 +463,5 @@ def _is_connected_warhead(self, atom, anchor_atom): else: pass else: - raise ValueError('I do not think this is possible.') \ No newline at end of file + raise ValueError('I do not think this is possible.') + diff --git a/fragmenstein/mpro/__init__.py b/fragmenstein/mpro/__init__.py index 50b4be5..37a9831 100644 --- a/fragmenstein/mpro/__init__.py +++ b/fragmenstein/mpro/__init__.py @@ -48,7 +48,6 @@ def poised_pose_fx(pose: pyrosetta.Pose): MutateResidue(target=r, new_res='CYZ').apply(pose) class MProVictor(Victor): - monster_merging_mode = 'none_permissive' constraint_function_type = 'FLAT_HARMONIC' @classmethod diff --git a/fragmenstein/victor/__init__.py b/fragmenstein/victor/__init__.py index 9b992a6..ded7109 100644 --- a/fragmenstein/victor/__init__.py +++ b/fragmenstein/victor/__init__.py @@ -8,41 +8,36 @@ This master reanimator keeps a ``.journal`` (logging, class attribute). And can be called via the class method ``.laboratory`` where he can process multiple compounds at once. +The class Victor is assembled via a various class that inherit VictorCommon +This is made by series of classes, whose dependency is not really linear, +but for simplicity is have been written that way. + +1. VictorBase => constructor +2. VictorSafety => error catching +3. VictorJournal => logging +4. VictorPlonk => place +5. VictorOverridables => empty methods +5. VictorStore => save +6. VictorIgor => call igor +7. VictorCommon => common + +* VctorPlace => placement +* VictorCombine => merging/linking +* VictorUtils => Bits and bobs +* """ - -__author__ = "Matteo Ferla. [Github](https://github.com/matteoferla)" -__email__ = "matteo.ferla@gmail.com" -__date__ = "2020 A.D." -__license__ = "MIT" -__version__ = "0.5" -__citation__ = "" - ######################################################################################################################## -import json -import os -import re -import warnings -import pyrosetta -import time -from typing import List, Union, Optional, Callable, Dict +from ._victor_utils import _VictorUtils +from ._victor_validate import _VictorValidate +from ._victor_combine import _VictorCombine +from ._victor_place import _VictorPlace -from rdkit import Chem -from rdkit.Chem import AllChem -# noinspection PyUnresolvedReferences -from rdkit_to_params import Params, Constraints - -from ._victor_utils_mixin import _VictorUtilsMixin # <--- _VictorBaseMixin -from ._victor_validate_mixin import _VictorValidateMixin -from ._victor_automerge_mixin import _VictorAutomergeMixin -from ..monster import Monster -from ..igor import Igor -from ..m_rmsd import mRSMD from .minimalPDB import MinimalPDBParser -class Victor(_VictorUtilsMixin, _VictorValidateMixin, _VictorAutomergeMixin): +class Victor(_VictorUtils, _VictorValidate, _VictorCombine, _VictorPlace): """ * ``smiles`` SMILES string (inputted) * ``long_name`` name for files @@ -69,691 +64,11 @@ class Victor(_VictorUtilsMixin, _VictorValidateMixin, _VictorAutomergeMixin): The need for atomnames is actually not for the code but to allow lazy tweaks and analysis downstream (say typing in pymol: `show sphere, name CX`). Adding a 'constraint' to an entry will apply that constraint. - ``monster_merging_mode:str`` is class attributes that control Monster. + ``merging_mode:str`` is class attributes that control Monster. """ + pass - def __init__(self, - smiles: str, - hits: List[Chem.Mol], - pdb_filename: str, - long_name: str = 'ligand', - ligand_resn: str = 'LIG', - ligand_resi: Union[int, str] = '1B', - covalent_resn: str = 'CYS', # no other option is accepted. - covalent_resi: Optional[Union[int, str]] = None, - extra_constraint: Union[str] = None, - pose_fx: Optional[Callable] = None, - atomnames: Optional[Dict[int, str]] = None - ): - """ - :param smiles: smiles of followup, optionally covalent (_e.g._ ``*CC(=O)CCC``) - :param hits: list of rdkit molecules - :param pdb_filename: file of apo structure - :param long_name: gets used for filenames so will get slugified - :param ligand_resn: 3 letter code or your choice - :param ligand_resi: Rosetta-style pose(int) or pdb(str) - :param covalent_resn: only CYS accepted. if smiles has no * it is ignored - :param covalent_resi: Rosetta-style pose(int) or pdb(str) - :param extra_constraint: multiline string of constraints.. - :param pose_fx: a function to call with pose to tweak or change something before minimising. - :param atomnames: an optional dictionary that gets used by ``Params.from_smiles`` - """ - # ***** STORE ******* - # entry attributes - self.long_name = self.slugify(long_name) - self.smiles = smiles - with open(pdb_filename) as fh: - self.apo_pdbblock = fh.read() - self.hits = hits - self.ligand_resn = ligand_resn.upper() - self.ligand_resi = ligand_resi - self.covalent_resn = covalent_resn.upper() - self.covalent_resi = covalent_resi - self.atomnames = atomnames - self.extra_constraint = extra_constraint - self.pose_fx = pose_fx - # these are calculated - self.is_covalent = None - self.params = None - self.mol = None - self.constraint = None - self.monster = None - self.modifications = {} # used by automerger only - self.unminimised_pdbblock = None - self.igor = None - self.minimised_pdbblock = None - self.minimised_mol = None - self.reference_mol = None # filled only for validate - # buffers etc. - self._warned = [] - self.energy_score = {'ligand_ref2015': {'total_score': float('nan')}, - 'unbound_ref2015': {'total_score': float('nan')}} - self.mrmsd = mRSMD.mock() - self.tick = time.time() - self.tock = float('inf') - self.error = '' - # analyse - self._safely_do(execute=self._analyse, resolve=self._resolve, reject=self._reject) - - # =================== Init monster methods ============================================================================ - - def _safely_do(self, - execute: Optional[Callable] = None, - resolve: Optional[Callable] = None, - reject: Optional[Callable] = None): - """ - A safety net around the analysis. - Ought to be a decorator and ought to not use the same names as a JS Promise. - The class attribute ``error_to_catch`` is by default Exception - - :param execute: what to run (main) - :param resolve: what to run at the end (regardless of failure) - :param reject: what to run if ``exceute`` fails - :return: - """ - # warnings - with warnings.catch_warnings(record=True) as self._warned: - try: - if execute is not None: - execute() - except self.error_to_catch as err: - self.error = f'{err.__class__.__name__}: {err}' - if reject is not None: - reject(err) - finally: - if resolve is not None: - resolve() - - def _resolve(self) -> None: - """ - This gets called at the end of ``_safely_do``, regardless of the whether it worked or not. - So the name is a bit misleading. - :return: - """ - self.tock = time.time() - self.journal.info(f'{self.long_name} - Time taken: {self.tock - self.tick}') - - def _reject(self, err) -> None: - """ - This gets called by ``_safely_do`` on error. - - :param err: the error raised. - :return: - """ - self.journal.error(f'{self.long_name} — {err.__class__.__name__}: {err}') - - def _analyse(self) -> None: - """ - This is the actual monster of the class. - - :return: - """ - # check they are okay - if '*' in self.smiles and (self.covalent_resi is None or self.covalent_resn is None): - raise ValueError(f'{self.long_name} - is covalent but without known covalent residues') - # TODO '*' in self.smiles is bad. user might start with a mol file. - elif '*' in self.smiles: - self.is_covalent = True - else: - self.is_covalent = False - self._assert_inputs() - # ***** PARAMS & CONSTRAINT ******* - self.journal.info(f'{self.long_name} - Starting work') - self._log_warnings() - # making folder. - self._make_output_folder() - # make params - self.journal.debug(f'{self.long_name} - Starting parameterisation') - self.params = Params.from_smiles(self.smiles, name=self.ligand_resn, generic=False, atomnames=self.atomnames) - # self.journal.warning(f'{self.long_name} - CHI HAS BEEN DISABLED') - # self.params.CHI.data = [] # Chi is fixed, but older version. should probably check version - self.mol = self.params.mol - self._log_warnings() - # get constraint - self.constraint = self._get_constraint(self.extra_constraint) - attachment = self._get_attachment_from_pdbblock() if self.is_covalent else None - self._log_warnings() - self.post_params_step() - # ***** FRAGMENSTEIN ******* - # make monster - self.journal.debug(f'{self.long_name} - Starting fragmenstein') - # monster_throw_on_discard controls if disconnected. - Monster.throw_on_discard = self.monster_throw_on_discard - self.monster = Monster(hits=self.hits, - average_position=self.monster_average_position) - self.monster.place(mol=self.mol, - attachment=attachment, - merging_mode=self.monster_merging_mode) - self.journal.debug(f'{self.long_name} - Tried {len(self.monster.mol_options)} combinations') - self.unminimised_pdbblock = self._plonk_monster_in_structure() - self.constraint.custom_constraint += self._make_coordinate_constraints() - self._checkpoint_bravo() - # save stuff - params_file, holo_file, constraint_file = self._save_prerequisites() - self.post_monster_step() - self.unbound_pose = self.params.test() - self._checkpoint_alpha() - # ***** EGOR ******* - self.journal.debug(f'{self.long_name} - setting up Igor') - self.igor = Igor.from_pdbblock(pdbblock=self.unminimised_pdbblock, - params_file=params_file, - constraint_file=constraint_file, - ligand_residue=self.ligand_resi, - key_residues=[self.covalent_resi]) - # user custom code. - if self.pose_fx is not None: - self.journal.debug(f'{self.long_name} - running custom pose mod.') - self.pose_fx(self.igor.pose) - else: - self.pose_mod_step() - # storing a roundtrip - self.unminimised_pdbblock = self.igor.pose2str() - # minimise until the ddG is negative. - if self.quick_renanimation: - ddG = self.quick_reanimate() - else: - ddG = self.reanimate() - self.minimised_pdbblock = self.igor.pose2str() - self.post_igor_step() - self.minimised_mol = self._fix_minimised() - self.mrmsd = self._calculate_rmsd() - self.journal.info(f'{self.long_name} - final score: {ddG} kcal/mol {self.mrmsd.mrmsd}.') - self._checkpoint_charlie() - self.journal.debug(f'{self.long_name} - Completed') - - # =================== Init called methods ========================================================================== - - def slugify(self, name: str): - return re.sub(r'[\W_.-]+', '-', name) - - def _make_output_folder(self): - path = os.path.join(self.work_path, self.long_name) - if not os.path.exists(self.work_path): - os.mkdir(self.work_path) - if not os.path.exists(path): - os.mkdir(path) - else: - self.journal.warning(f'{self.long_name} - Folder {path} exists.') - - def _assert_inputs(self): - assert len(self.ligand_resn) == 3, f'{self.long_name} - {self.ligand_resn} is not 3 char long.' - assert len(self.hits), f'{self.long_name} - No hits to use to construct' - assert self.ligand_resn != 'UNL', f'{self.long_name} - It cannot be UNL as it s the unspecified resn in rdkit' - if self.covalent_resn and len( - [d for d in self.covalent_definitions if d['residue'] == self.covalent_resn]) == 0: - raise ValueError(f'{self.long_name} - Unrecognised type {self.covalent_resn}') - - def _make_coordinate_constraints(self): - """ - See also ``_make_coordinate_constraints_for_unnovels`` in automerge. - This is the normal function and uses the origin data, - while the other constrains based on lack of novel attribute. - """ - lines = [] - origins = self.monster.origin_from_mol(self.monster.positioned_mol) - std = self.monster.stdev_from_mol(self.monster.positioned_mol) - mx = self.monster.max_from_mol(self.monster.positioned_mol) - conf = self.monster.positioned_mol.GetConformer() - for i in range(self.monster.positioned_mol.GetNumAtoms()): - if len(origins[i]) > 0: - atom = self.monster.positioned_mol.GetAtomWithIdx(i) - if atom.GetSymbol() == '*': - continue - elif atom.GetPDBResidueInfo() is None: - self.journal.critical(f'Atom {i} ({atom.GetSymbol()}) has no name!') - continue - pos = conf.GetAtomPosition(i) - if self.constraint_function_type.upper() == 'HARMONIC': - fxn = f'HARMONIC 0 {std[i] + 1}' - elif self.constraint_function_type.upper() == 'FLAT_HARMONIC': - if len(origins[i]) > 1: - fxn = f'FLAT_HARMONIC 0 1.0 {mx[i]}' - else: - fxn = f'HARMONIC 0 1.0' - elif self.constraint_function_type.upper() == 'BOUNDED': - fxn = f'BOUNDED 0 {mx[i]} 1 0.5 TAG' - else: - raise ValueError(f'{self.constraint_function_type} is not HARMONIC or FADE or BOUNDED') - atomname = atom.GetPDBResidueInfo().GetName() - lines.append(f'CoordinateConstraint {atomname} {self.ligand_resi} ' + \ - f'CA {self.covalent_resi} ' + \ - f'{pos.x} {pos.y} {pos.z} {fxn}\n') - return ''.join(lines) - - # ------------- Plonk in structure ------------------------------------------------------------------------------ - # the following is here as opposed to Monster, because it requires the template, ligand connections etc. - # the stupid name "plonk" is to distinguish it from place and placement, which have a different meaning in Monster. - - def _get_LINK_record(self): - if self.is_covalent: - # get correct chain names. - l_resi, l_chain = re.match('(\d+)(\D?)', str(self.ligand_resi)).groups() - if self.covalent_resi: - p_resi, p_chain = re.match('(\d+)(\D?)', str(self.covalent_resi)).groups() - else: - p_resi, p_chain = None, None - if not p_chain: - p_chain = 'A' - if not l_chain: - l_chain = 'B' - # get the cx atom name - cx = self.params.pad_name(self.params.CONNECT[0].atom_name) - # TODO the SG connection is hardcoded. - return f'LINK SG {self.covalent_resn} {p_chain} {p_resi: >3} ' + \ - f'{cx} {self.ligand_resn} {l_chain} {l_resi: >3} 1555 1555 1.8\n' - else: - return '' - - def _correct_ligand_info(self, mol: Optional[Chem.Mol]=None) -> Chem.Mol: - """ - Corrects in place the given mol based on self.ligand_resi. - If none provided it assumed self.monster.positioned_mol - Correcting the serial unfortunately does not do anything. - """ - if mol is None: - mol = self.monster.positioned_mol - l_resi, l_chain = re.match('(\d+)(\D?)', str(self.ligand_resi)).groups() #TODO improve ligand_resi - for atom in mol.GetAtoms(): - info = atom.GetPDBResidueInfo() - info.SetResidueNumber(int(l_resi)) - info.SetChainId(l_chain) - info.SetIsHeteroAtom(True) - info.SetOccupancy(1.) - info.SetResidueName(self.ligand_resn) - return mol - - def _plonk_monster_in_structure(self, use_pymol=False): - self._correct_ligand_info() - self.journal.debug(f'{self.long_name} - placing monster in structure') - if use_pymol: - return self._plonk_monster_in_structure_pymol() - else: - # _plonk_monster_in_structure_raw does no corrections. - return self._plonk_monster_in_structure_minimal() - - def _get_preminimised_undummied_monster(self): - """ - This method is called by the plonking into structure methods. - Not "positioning" as intended by ``monster`` is done. - Opening a PDB in RDKit is doable but gets exponentially slow with chain length - """ - mol = AllChem.DeleteSubstructs(self.monster.positioned_mol, Chem.MolFromSmiles('*')) - if self.monster_mmff_minisation: - self.journal.debug(f'{self.long_name} - pre-minimising monster (MMFF)') - self.monster.mmff_minimise(mol) - return mol - - - def _plonk_monster_in_structure_minimal(self): - """ - Plonks the molecule in the structure without using pymol. - Uses a custom miniparser. see minimalPDB - - :return: - """ - mol = self._get_preminimised_undummied_monster() - pdbdata = MinimalPDBParser(self.apo_pdbblock) - moldata = MinimalPDBParser(Chem.MolToPDBBlock(mol)) - if self.is_covalent: - pdbdata.headers.append(self._get_LINK_record()) - pdbdata.append(moldata) # fixes offsets in ATOM/HETATM and CONECT lines. - return str(pdbdata) - - def _plonk_monster_in_structure_raw(self): - """ - Plonks the molecule in the structure without using pymol. - Not "positioning" as intended by ``monster`` is done. - Opening a PDB in RDKit is doable but gets exponentially slow with chain length - - :return: - """ - mol = self._get_preminimised_undummied_monster() - mol_block = Chem.MolToPDBBlock(mol) - return '\n'.join([self._get_LINK_record().strip(), - self.apo_pdbblock.strip(), - mol_block - ]).strip() - - def _plonk_monster_in_structure_pymol(self): - """ - Plonks the molecule in the structure using pymol. - Not "positioning" as intended by ``monster`` is done. - - :return: - """ - import pymol2 - mol = self._get_preminimised_undummied_monster() - with pymol2.PyMOL() as pymol: - pymol.cmd.read_pdbstr(self.apo_pdbblock, 'apo') - pos_mol = Chem.MolToPDBBlock(mol) - #pymol.cmd.read_pdbstr(pos_mol, 'scaffold') - pymol.cmd.remove('name R') # no dummy atoms! - for c in self._connected_names: - pymol.cmd.remove(f'name {c}') # no conns - pymol.cmd.remove('resn UNL') # no unmatched stuff. - pdbblock = pymol.cmd.get_pdbstr('*') - pymol.cmd.delete('*') - return self._get_LINK_record() + pdbblock - - # ------------- Igor ------------------------------------------------------------------------------ - - def _fix_minimised(self) -> Chem.Mol: - """ - PDBs are terrible for bond order etc. and Rosetta addes these based on atom types - :return: - """ - self.journal.debug(f'{self.long_name} - making ligand only') - ligand = self.igor.mol_from_pose() - template = AllChem.DeleteSubstructs(self.params.mol, Chem.MolFromSmiles('*')) - return AllChem.AssignBondOrdersFromTemplate(template, ligand) - - def quick_reanimate(self) -> float: - """ - Correct small deviations from what the forcefield likes. Generally flattens buckled rings and that is it. - Reanimate is normal. - - :return: - """ - self.igor.coordinate_constraint = 10. - self.igor.minimise(cycles=5, default_coord_constraint=False) - self.energy_score = self.calculate_score() - dG_bound = self.energy_score['ligand_ref2015']['total_score'] - dG_unbound = self.energy_score['unbound_ref2015']['total_score'] - ddG = dG_bound - dG_unbound - return ddG - - def reanimate(self) -> float: - """ - Calls Igor recursively until the ddG is negative or zero. - igor.minimise does a good job. this is just to get everything as a normal molecule - - :return: ddG (kcal/mol) - """ - ddG = 999 - self.igor.coordinate_constraint = 0. - # self.igor.fa_intra_rep = 0.02 # 4x - # quick unconstrained minimisation to wiggle it out of nasty local minima - self.igor.minimise(cycles=15, default_coord_constraint=False) - self.igor.coordinate_constraint = 2 - self.igor.minimise(cycles=5, default_coord_constraint=False) - self.igor.coordinate_constraint = 1 - while ddG > 0: - self.journal.debug(f'{self.long_name} - Igor minimising') - self.igor.minimise(default_coord_constraint=False) - self.energy_score = self.calculate_score() - dG_bound = self.energy_score['ligand_ref2015']['total_score'] - dG_unbound = self.energy_score['unbound_ref2015']['total_score'] - ddG = dG_bound - dG_unbound - if ddG > 0: - self.igor.coordinate_constraint /= 2 - self.journal.debug( - f'{self.long_name} - coord_constraint lowered: {self.igor.coordinate_constraint}: {ddG} kcal/mol.') - if self.igor.coordinate_constraint == 0.: - self.journal.warn(f'{self.long_name} - failed to minimise without constraints: {ddG} kcal/mol.') - break - elif self.igor.coordinate_constraint < 0.005: - self.igor.coordinate_constraint = 0. - return ddG - - # =================== Constraint & attachment ====================================================================== - - def _get_constraint(self, extra_constraint: Optional[str] = None) -> Union[Constraints, None]: - # deal with covalent and non covalent separately - if self.is_covalent: - self.journal.debug(f'{self.long_name} - is covalent.') - constraint = self._fix_covalent() - if extra_constraint: - constraint.custom_constraint += self.extra_constraint - return constraint - else: - self.journal.debug(f'{self.long_name} - is not covalent.') - constraint = self._fix_uncovalent() - if extra_constraint: - constraint.custom_constraint += self.extra_constraint - return constraint - - def _fix_uncovalent(self): - return Constraints.mock() - - def _get_war_def(self): - for war_def in self.warhead_definitions: - warhead = Chem.MolFromSmiles(war_def['covalent']) - if self.mol.HasSubstructMatch(warhead): - return war_def - else: - if self.mol.HasSubstructMatch(Chem.MolFromSmiles('*C')): - self.journal.warning('Unknown type of covalent') - return {'name': 'unknown', - 'covalent': 'C~C*', - 'covalent_atomnames': ['CY', 'CX', 'CONN1'], - 'noncovalent': 'C~[C+]', # clearly not - 'noncovalent_atomnames': ['CY', 'CX'] - } - else: - raise ValueError(f'{self.long_name} - Unsure what the warhead is {self.smiles}.') - - def _fix_covalent(self): - self.journal.debug(f'{self.long_name} - fixing for covalent') - # to make life easier for analysis, CX is the attachment atom, CY is the one before it. - war_def = self._get_war_def() - warhead = Chem.MolFromSmiles(war_def['covalent']) - self.params.rename_by_substructure(warhead, war_def['covalent_atomnames']) - cov_def = [d for d in self.covalent_definitions if d['residue'] == self.covalent_resn][0] - self.journal.debug(f'{self.long_name} - has a {war_def["name"]}') - cons = Constraints(smiles=(war_def['covalent'], cov_def['smiles']), - names=[*war_def['covalent_atomnames'], *cov_def['atomnames']], - ligand_res=self.ligand_resi, - target_res=self.covalent_resi) - # user added constraint - if 'constraint' in war_def: - cons.custom_constraint = war_def['constraint'] - return cons - - def _get_attachment_from_pdbblock(self) -> Union[None, Chem.Mol]: - """ - Yes, yes, I see the madness in using pymol to get an atom for rdkit to make a pose for pyrosetta. - Hence why `find_attachment` will replace it. - todo `_get_attachment_from_pdbblock` --> `find_attachment` - """ - import pymol2 - - self.journal.debug(f'{self.long_name} - getting attachemnt atom') - if not self.covalent_resn: - return None - else: - if isinstance(self.covalent_resi, str): - resi, chain = re.match('(\d+)(\w)', self.covalent_resi).groups() - resi = int(resi) - else: - resi = self.covalent_resi - chain = None - with pymol2.PyMOL() as pymol: - pymol.cmd.read_pdbstr(self.apo_pdbblock, 'prot') - if self.covalent_resn == 'CYS': - name = 'SG' - else: - raise NotImplementedError('only done for cys atm') - try: - if chain is not None: - pdb = pymol.cmd.get_pdbstr(f'resi {resi} and name {name} and chain {chain}') - else: - pdb = pymol.cmd.get_pdbstr(f'resi {resi} and name {name}') - except: - pdb = pymol.cmd.get_pdbstr(f'resi {resi} and name {name}') - return Chem.MolFromPDBBlock(pdb) - - def _calculate_rmsd(self): - self.journal.debug(f'{self.long_name} - calculating mRMSD') - return mRSMD.from_other_annotated_mols(self.minimised_mol, self.hits, self.monster.positioned_mol) - - def calculate_score(self): - return {**self.igor.ligand_score(), - 'unbound_ref2015': self.igor.detailed_scores(self.unbound_pose, 1)} - - # =================== Other ======================================================================================== - - def _log_warnings(self): - if len(self._warned): - for w in self._warned: - self.journal.warning(f'{self.long_name} - {w.message} ({w.category})') - self._warned.clear() - - # =================== Overridables ================================================================================= - - def post_params_step(self): - """ - This method is intended for make inherited mods easier. - :return: - """ - pass - - def post_monster_step(self): - """ - This method is intended for make inherited mods easier. - :return: - """ - pass - - def pose_mod_step(self): - """ - This method is intended for make inherited mods easier. - :return: - """ - pass - - def post_igor_step(self): - """ - This method is intended for make inherited mods easier. - :return: - """ - pass - - # =================== Logging ====================================================================================== - - def _save_prerequisites(self): - self._log_warnings() - # saving params - self.journal.debug(f'{self.long_name} - saving params') - params_file = os.path.join(self.work_path, self.long_name, self.long_name + '.params') - self.params.dump(params_file) - # saving holo - self.journal.debug(f'{self.long_name} - saving holo (unmimised)') - holo_file = os.path.join(self.work_path, self.long_name, self.long_name + '.holo_unminimised.pdb') - with open(holo_file, 'w') as w: - w.write(self.unminimised_pdbblock) - # saving constraint - if self.constraint is not None: - self.journal.debug(f'{self.long_name} - saving constraint') - constraint_file = os.path.join(self.work_path, self.long_name, self.long_name + '.con') - self.constraint.dump(constraint_file) - else: # basically impossible. - constraint_file = '' - return params_file, holo_file, constraint_file - - def _checkpoint_alpha(self): - self._log_warnings() - # saving hits (without copying) - for h, hit in enumerate(self.hits): - if hit.HasProp("_Name") and hit.GetProp("_Name").strip(): - name = hit.GetProp("_Name") - else: - name = f'hit{h}' - hfile = os.path.join(self.work_path, self.long_name, f'{name}.pdb') - Chem.MolToPDBFile(hit, hfile) - mfile = os.path.join(self.work_path, self.long_name, f'{name}.mol') - Chem.MolToMolFile(hit, mfile, kekulize=False) - # saving params template - params_template_file = os.path.join(self.work_path, self.long_name, self.long_name + '.params_template.pdb') - Chem.MolToPDBFile(self.params.mol, params_template_file) - params_template_file = os.path.join(self.work_path, self.long_name, self.long_name + '.params_template.mol') - Chem.MolToMolFile(self.params.mol, params_template_file) - # checking all is in order - ptest_file = os.path.join(self.work_path, self.long_name, self.long_name + '.params_test.pdb') - self.unbound_pose.dump_pdb(ptest_file) - pscore_file = os.path.join(self.work_path, self.long_name, self.long_name + '.params_test.score') - scorefxn = pyrosetta.get_fa_scorefxn() - with open(pscore_file, 'w') as w: - w.write(str(scorefxn(self.unbound_pose))) - self._log_warnings() - - def _checkpoint_bravo(self): - self._log_warnings() - self.journal.debug(f'{self.long_name} - saving mols from monster') - # if self.monster.scaffold is not None: - # scaffold_file = os.path.join(self.work_path, self.long_name, self.long_name + '.scaffold.mol') - # Chem.MolToMolFile(self.monster.scaffold, scaffold_file, kekulize=False) - # if self.monster.scaffold.HasProp('parts'): - # disregard = json.loads(self.monster.scaffold.GetProp('parts')) - # self.journal.info(f'{self.long_name} - disregarded {disregard}') - # else: - # disregard = [] - # if self.monster.chimera is not None: - # chimera_file = os.path.join(self.work_path, self.long_name, self.long_name + '.chimera.mol') - # Chem.MolToMolFile(self.monster.chimera, chimera_file, kekulize=False) - if self.monster.positioned_mol is not None: - pos_file = os.path.join(self.work_path, self.long_name, self.long_name + '.positioned.mol') - Chem.MolToMolFile(self.monster.positioned_mol, pos_file, kekulize=False) - if self.monster.mol_options: - opt_file = os.path.join(self.work_path, self.long_name, self.long_name + '.mol_options.sdf') - writer = Chem.SDWriter(opt_file) - writer.SetKekulize(False) - for t in self.monster.mol_options: - writer.write(t) - writer.close() - - frag_file = os.path.join(self.work_path, self.long_name, self.long_name + '.monster.json') - data = {'smiles': self.smiles, - 'origin': self.monster.origin_from_mol(self.monster.positioned_mol), - 'stdev': self.monster.stdev_from_mol(self.monster.positioned_mol)} - # if disregard: - # data['disregard'] = disregard - with open(frag_file, 'w') as w: - json.dump(data, w) - self._log_warnings() - # unminimised_pdbblock will be saved by igor (round trip via pose) - - def _checkpoint_charlie(self): - self._log_warnings() - self.journal.debug(f'{self.long_name} - saving pose from igor') - min_file = os.path.join(self.work_path, self.long_name, self.long_name + '.holo_minimised.pdb') - self.igor.pose.dump_pdb(min_file) - self.journal.debug(f'{self.long_name} - calculating Gibbs') - # recover bonds - lig_file = os.path.join(self.work_path, self.long_name, self.long_name + '.minimised.mol') - Chem.MolToMolFile(self.minimised_mol, lig_file) - score_file = os.path.join(self.work_path, self.long_name, self.long_name + '.minimised.json') - with open(score_file, 'w') as w: - json.dump({'Energy': self.energy_score, - 'mRMSD': self.mrmsd.mrmsd, - 'RMSDs': self.mrmsd.rmsds}, w) - self._log_warnings() - - @property - def constrained_atoms(self) -> int: - """ - Do note that the whole Origins list contains hydrogens. So do not divided by len! - :return: - """ - try: - conn = sum([o != [] for o in self.monster.origin_from_mol(self.monster.positioned_mol)]) - except Exception as err: - self.journal.warning(f'{self.long_name} - {err.__class__.__name__}: {err}') - conn = float('nan') - return conn - - @property - def unconstrained_heavy_atoms(self) -> int: - try: - origins = self.monster.origin_from_mol(self.monster.positioned_mol) - unconn = sum([o == [] and atom.GetSymbol() != 'H' for o, atom in - zip(origins, self.monster.positioned_mol.GetAtoms())]) - except Exception as err: - self.journal.warning(f'{self.long_name} - {err.__class__.__name__}: {err}') - unconn = float('nan') - return unconn -######### Make params use the same log. -Params.log = Victor.journal diff --git a/fragmenstein/victor/_loggerwriter.py b/fragmenstein/victor/_loggerwriter.py index 4dd15b1..a7b736b 100644 --- a/fragmenstein/victor/_loggerwriter.py +++ b/fragmenstein/victor/_loggerwriter.py @@ -2,7 +2,7 @@ class LoggerWriter: """ - Write stderr to logger. See log_errors method of Victor + Write stderr to logger. See capture_rdkit_log method of Victor """ def __init__(self, writer): self._writer = writer diff --git a/fragmenstein/victor/_victor_automerge_mixin.py b/fragmenstein/victor/_victor_automerge_mixin.py deleted file mode 100644 index 38596f0..0000000 --- a/fragmenstein/victor/_victor_automerge_mixin.py +++ /dev/null @@ -1,301 +0,0 @@ -from ._victor_base_mixin import _VictorBaseMixin -from ..monster import Monster -from ..igor import Igor -from ..m_rmsd import mRSMD -from molecular_rectifier import Rectifier -from typing import List, Optional, Dict, Union, Callable -from rdkit import Chem -from rdkit.Chem import AllChem -from rdkit_to_params import Params, Constraints -import time, warnings - - -class _VictorAutomergeMixin(_VictorBaseMixin): - - - @classmethod - def combine(cls, - hits: List[Chem.Mol], - pdb_filename: str, - ligand_resn: str = 'LIG', - ligand_resi: Union[int, str] = '1B', - covalent_resn: str = 'CYS', # no other option is accepted. - covalent_resi: Optional[Union[int, str]] = None, - extra_constraint: Union[str] = None, - pose_fx: Optional[Callable] = None, - atomnames: Optional[Dict[int, str]] = None, - warhead_harmonisation: str='first' - ): - """ - Combines the hits without a template. - If the class attribute ``monster_throw_on_discard`` is True, it will raise an exception if it cannot. - - The cutoff distance is controlled by class attribute ``monster_joining_cutoff``. - At present this just adds a hydrocarbon chain, no fancy checking for planarity. - - The hits are collapsed, merged, expanded and bonded by proximity. - In ``(self.monster.expand_ring(..., bonded_as_original=False)`` changing to True, might work, but most likely won't. - - ``warhead_harmonisation`` fixes the warhead in the hits to be homogeneous. - - * ``keep``. Don't do anything - * ``none``. strip warheads - * ``first``. Use first warhead - * warhead name. Use this warhead. - - :param hits: - :param pdb_filename: - :param ligand_resn: - :param ligand_resi: - :param covalent_resn: - :param covalent_resi: - :param extra_constraint: - :param pose_fx: - :param atomnames: - :param warhead_harmonisation: keep | strip | first | chloracetimide | nitrile ... - :return: - """ - self = cls.__new__(cls) - self.monster_merging_mode = 'full' # needed solely for logkeeping - self.long_name = '-'.join([h.GetProp('_Name') for h in hits]) - with open(pdb_filename) as fh: - self.apo_pdbblock = fh.read() - self.journal.debug(f'{self.long_name} - harmonising warheads on hits in "{warhead_harmonisation}" mode') - with warnings.catch_warnings(record=True) as self._warned: - self.hits = self.harmonise_warheads(hits, warhead_harmonisation, covalent_form=True) - self._log_warnings() - self.ligand_resn = ligand_resn.upper() - self.ligand_resi = ligand_resi - self.covalent_resn = covalent_resn.upper() - self.covalent_resi = covalent_resi - self.atomnames = atomnames - self.extra_constraint = extra_constraint - self.pose_fx = pose_fx - # these are calculated - starhits = any(['*' in Chem.MolToSmiles(h) for h in hits]) - if starhits and (self.covalent_resi is None or self.covalent_resn is None): - raise ValueError(f'{self.long_name} - is covalent but without known covalent residues') - elif warhead_harmonisation == 'strip': - self.is_covalent = False - elif starhits: - self.is_covalent = True - else: - self.is_covalent = False - self.params = None - self.mol = None - self.smiles = None - self.constraint = None - self.monster = None - # ====== debug: absent in main mode. - self.modifications = {} # list of the various steps during fragment merging mode. - # ====== - self.unminimised_pdbblock = None - self.igor = None - self.minimised_pdbblock = None - self.minimised_mol = None - if self.monster_average_position: - # I need to code this case. - self.journal.warning('`monster_average_position` class attribute == True does not apply here') - # buffers etc. - self._warned = [] - self.energy_score = {'ligand_ref2015': {'total_score': float('nan')}, - 'unbound_ref2015': {'total_score': float('nan')}} - self.mrmsd = mRSMD.mock() - self.tick = time.time() - self.tock = float('inf') - self.error = '' - self._safely_do(execute=self._combine_main, - resolve=self._resolve, - reject=self._reject) - return self - - def _combine_main(self): - attachment = self._get_attachment_from_pdbblock() if self.is_covalent else None - self.monster = Monster(hits=self.hits, - average_position=self.monster_average_position - ) - self.monster.modifications = self.modifications - self.monster.combine(keep_all=self.monster_throw_on_discard, - collapse_rings=True, - joining_cutoff=self.monster_joining_cutoff # Å - ) - self.mol = self.monster.positioned_mol - self.smiles = Chem.MolToSmiles(self.mol) - # making folder. - self._make_output_folder() - # paramterise - self.journal.debug(f'{self.long_name} - Starting parameterisation') - self.params = Params.load_mol(self.mol, name=self.ligand_resn) - self.params.NAME = self.ligand_resn # force it. - self.params.polish_mol() - # get constraint - self.constraint = self._get_constraint(self.extra_constraint) - self.constraint.custom_constraint += self._make_coordinate_constraints_for_unnovels() - # _get_constraint will have changed the names in params.mol so the others need changing too! - # namely self.params.rename_by_substructure happend. - self.mol = Chem.Mol(self.params.mol) - self.monster.positioned_mol = Chem.Mol(self.mol) - # those Hs lack correct names and charge!! - self.params.add_Hs() - self.params.convert_mol() - # self.journal.warning(f'{self.long_name} - CHI HAS BEEN DISABLED') - # self.params.CHI.data = [] # TODO check if chi fix is okay - self._log_warnings() - self.post_params_step() - self.monster_merging_mode = 'full' - self.unminimised_pdbblock = self._plonk_monster_in_structure() - params_file, holo_file, constraint_file = self._save_prerequisites() - self.unbound_pose = self.params.test() - self._checkpoint_alpha() - self._checkpoint_bravo() - self.igor = Igor.from_pdbblock(pdbblock=self.unminimised_pdbblock, - params_file=params_file, - constraint_file=constraint_file, - ligand_residue=self.ligand_resi, - key_residues=[self.covalent_resi]) - # user custom code. - if self.pose_fx is not None: - self.journal.debug(f'{self.long_name} - running custom pose mod.') - self.pose_fx(self.igor.pose) - else: - self.pose_mod_step() - # storing a roundtrip - self.unminimised_pdbblock = self.igor.pose2str() - # minimise until the ddG is negative. - self.reanimate_n_store() - self.journal.debug(f'{self.long_name} - Completed') - - def reanimate_n_store(self): - ddG = self.reanimate() - self.minimised_pdbblock = self.igor.pose2str() - self.post_igor_step() - self.minimised_mol = self._fix_minimised() - self.mrmsd = self._calculate_rmsd() - self.journal.info(f'{self.long_name} - final score: {ddG} kcal/mol {self.mrmsd.mrmsd}.') - self._checkpoint_charlie() - self.journal.debug(f'{self.long_name} - Completed') - - def _make_coordinate_constraints_for_unnovels(self): - """ - See also ``cls._make_coordinate_constraints``. - This operates based on ``atom.HasProp('_Novel')``, not origins! - :return: - """ - lines = [] - conf = self.monster.positioned_mol.GetConformer() - for i, atom in enumerate(self.monster.positioned_mol.GetAtoms()): - if atom.GetSymbol() == '*': - continue - elif atom.HasProp('_Novel') and atom.GetBoolProp('_Novel'): - continue # novels - elif atom.GetPDBResidueInfo() is None: - self.journal.critical(f'Atom {i} ({atom.GetSymbol()}) has no name!') - continue - else: - pos = conf.GetAtomPosition(i) - fxn = f'HARMONIC 0 1' # the other do not make sense here. - lines.append(f'CoordinateConstraint {atom.GetPDBResidueInfo().GetName()} {self.ligand_resi} ' + \ - f'CA {self.covalent_resi} ' + \ - f'{pos.x} {pos.y} {pos.z} {fxn}\n') - return ''.join(lines) - - @classmethod - def inventorise_warheads(cls, hits: List[Chem.Mol], covalent_form: bool=True) -> List[str]: - """ - Get the warhead types of the list of hits - - :param hits: - :param covalent_form: Are the hits already covalent (with *) - :return: list of non-covalent, chloroacetimide, etc. - """ - inventory = ['noncovalent'] * len(hits) - for war_def in cls.warhead_definitions: - wh = cls._get_warhead_from_definition(war_def, covalent_form) - for i, hit in enumerate(hits): - if hit.HasSubstructMatch(wh): - inventory[i] = war_def['name'] - return inventory - - @classmethod - def _get_warhead_from_name(cls, warhead_name:str, covalent_form:bool) -> Chem.Mol: - """ - get_warhead_definition returns a definition, this retursn a mol. - - :param warhead_name: - :param covalent_form: - :return: - """ - war_def = cls.get_warhead_definition(warhead_name) - wh = cls._get_warhead_from_definition(war_def, covalent_form) - return wh - - @classmethod - def _get_warhead_from_definition(cls, war_def:dict, covalent_form:bool): - if covalent_form: - wh = Chem.MolFromSmiles(war_def['covalent']) - else: - wh = Chem.MolFromSmiles(war_def['noncovalent']) - return wh - - def harmonise_warheads(self, hits, warhead_harmonisation, covalent_form=True): - """ - Harmonises and marks the atoms with `_Warhead` Prop. - - :param hits: - :param warhead_harmonisation: - :param covalent_form: - :return: - """ - inventory = self.inventorise_warheads(hits, covalent_form) - # mark warhead atoms. - for hit, warhead_name in zip(hits, inventory): - if warhead_name != 'noncovalent': - wh = self._get_warhead_from_name(warhead_name, covalent_form) - match = hit.GetSubstructMatch(wh) - if match == (): - self.journal.warning(f'{self.long_name} - failed to mark warhead. What is it??') - else: - for i in match: - hit.GetAtomWithIdx(i).SetBoolProp('_Warhead', True) - # harmonise - if warhead_harmonisation == 'keep': - return hits - elif warhead_harmonisation == 'strip': - new_hits = [] - for hit, warhead_name in zip(hits, inventory): - if warhead_name != 'noncovalent': - wh = self._get_warhead_from_name(warhead_name, covalent_form) - nhit = AllChem.DeleteSubstructs(hit, wh) - Chem.SanitizeMol(nhit) - new_hits.append(nhit) - else: - new_hits.append(hit) - - return new_hits - elif warhead_harmonisation == 'first': - if len(set(inventory) - {'noncovalent'}) <= 1: - return hits - else: - first = None - new_hits = [] - for hit, warhead_name in zip(hits, inventory): - if warhead_name != 'noncovalent': - if first is None: - first = warhead_name - new_hits.append(hit) - elif warhead_name == first: - new_hits.append(hit) - else: - wh = self._get_warhead_from_name(warhead_name, covalent_form) - nhit = AllChem.DeleteSubstructs(hit, wh) - Chem.SanitizeMol(nhit) - new_hits.append(nhit) - else: - new_hits.append(hit) - return new_hits - else: # it is a warhead name. - raise NotImplementedError - - - - diff --git a/fragmenstein/victor/_victor_base.py b/fragmenstein/victor/_victor_base.py new file mode 100644 index 0000000..cd55953 --- /dev/null +++ b/fragmenstein/victor/_victor_base.py @@ -0,0 +1,164 @@ +######################################################################################################################## + +__doc__ = \ + """ +Base metho=ods + """ + +__author__ = "Matteo Ferla. [Github](https://github.com/matteoferla)" +__email__ = "matteo.ferla@gmail.com" +__date__ = "2020 A.D." +__license__ = "MIT" +__version__ = "0.4" +__citation__ = "" + +######################################################################################################################## + + +import logging, warnings +import re +import time +from typing import List, Union, Optional, Callable, Dict + +from rdkit import Chem +from ..m_rmsd import mRSMD +from ..monster import Monster + + +class _VictorBase: + quick_renanimation = False # thorugh reanimation? + monster_average_position = False + monster_throw_on_discard = False + monster_mmff_minisation = True + constraint_function_type = 'FLAT_HARMONIC' + work_path = 'output' + journal = logging.getLogger('Fragmenstein') + journal.setLevel(logging.DEBUG) + + covalent_definitions = [{'residue': 'CYS', 'smiles': '*SC', 'atomnames': ['CONN3', 'SG', 'CB']}] + warhead_definitions = [{'name': 'acrylamide', + 'covalent': 'C(=O)CC*', # the N may be secondary etc. so best not do mad substitutions. + 'covalent_atomnames': ['CZ', 'OZ', 'CY', 'CX', 'CONN1'], + # OZ needs to tautomerise & h-bond happily. + 'noncovalent': 'C(=O)C=C', + 'noncovalent_atomnames': ['CZ', 'OZ', 'CY', 'CX']}, + {'name': 'chloroacetamide', + 'covalent': 'C(=O)C*', # the N may be secondary etc. so best not do mad substitutions. + 'covalent_atomnames': ['CY', 'OY', 'CX', 'CONN1'], + # OY needs to tautomerise & h-bond happily. + 'noncovalent': 'C(=O)C[Cl]', + 'noncovalent_atomnames': ['CY', 'OY', 'CX', 'CLX'] + }, + {'name': 'nitrile', + 'covalent': 'C(=N)*', # zeroth atom is attached to the rest + 'covalent_atomnames': ['CX', 'NX', 'CONN1'], + 'noncovalent': 'C(#N)', # zeroth atom is attached to the rest + 'noncovalent_atomnames': ['CX', 'NX'] + }, + {'name': 'vinylsulfonamide', + 'covalent': 'S(=O)(=O)CC*', # the N may be secondary etc. so best not do mad substitutions. + 'covalent_atomnames': ['SZ', 'OZ1', 'OZ2', 'CY', 'CX', 'CONN1'], # OZ tauto + 'noncovalent': 'S(=O)(=O)C=C', + 'noncovalent_atomnames': ['SZ', 'OZ1', 'OZ2', 'CY', 'CX'] + }, + {'name': 'bromoalkyne', + 'covalent': 'C(=C)*', + 'covalent_atomnames': ['CX', 'CY', 'CONN1'], + # OY needs to tautomerise & h-bond happily. + 'noncovalent': 'C#C[Br]', + 'noncovalent_atomnames': ['CX', 'CY', 'BRX'] + }, + ] + + # these may be wrong and need checking. + possible_definitions = [{'name': 'aurothiol', # gold salt + 'covalent': 'S[Au]*', + 'covalent_atomnames': ['SY', 'AUX', 'CONN1'], + # OY needs to tautomerise & h-bond happily. + 'noncovalent': 'S[Au]P(CC)(CC)CC', + 'noncovalent_atomnames': ['SY', 'AUX', 'PL', 'CL1', 'CL2', 'CL3', 'CL4', 'CL5', 'CL6'] + }, + {'name': 'aldehyde', + 'covalent': 'C(O)*', + 'covalent_atomnames': ['CX', 'OX', 'CONN1'], + 'noncovalent': '[C:H1]=O', # this at + 'noncovalent_atomnames': ['CX', 'OX'] + }, + ] + + _connected_names = ('CONN', 'LOWE', 'UPPE', 'CONN1', 'CONN2', 'CONN3', 'LOWER', 'UPPER') + + error_to_catch = () # Exception + + # ================== Init ========================================================================================== + + def __init__(self, + hits: List[Chem.Mol], + pdb_filename: str, + ligand_resn: str = 'LIG', + ligand_resi: Union[int, str] = '1B', + covalent_resn: str = 'CYS', # no other option is accepted. + covalent_resi: Optional[Union[int, str]] = None, + extra_constraint: Union[str] = None, + pose_fx: Optional[Callable] = None, + ): + """ + Initialise Victor in order to allow either combinations (merging/linking without a given aimed for molecule) + or placements (using a given aimed for molecule). + + :param smiles: smiles of followup, optionally covalent (_e.g._ ``*CC(=O)CCC``) + :param hits: list of rdkit molecules + :param pdb_filename: file of apo structure + :param ligand_resn: 3 letter code or your choice + :param ligand_resi: Rosetta-style pose(int) or pdb(str) + :param covalent_resn: only CYS accepted. if smiles has no * it is ignored + :param covalent_resi: Rosetta-style pose(int) or pdb(str) + :param extra_constraint: multiline string of constraints.. + :param pose_fx: a function to call with pose to tweak or change something before minimising. + :param atomnames: an optional dictionary that gets used by ``Params.from_smiles`` + """ + # ## Store + # entry attributes + with open(pdb_filename) as fh: + self.apo_pdbblock = fh.read() + self.hits = hits + self.ligand_resn = ligand_resn.upper() + self.ligand_resi = ligand_resi + self.covalent_resn = covalent_resn.upper() + self.covalent_resi = covalent_resi + self.extra_constraint = extra_constraint + self.pose_fx = pose_fx + # ## Fill by place or combine + self.long_name = 'ligand' + # ## Filled by place + self.merging_mode = "none_permissive" + self.smiles = None + # ## Filled by combine + self.joining_cutoff = None + # ## Calculated + self.is_covalent = None + self.params = None + self.mol = None + self.constraint = None + self.modifications = {} + self.unminimised_pdbblock = None + self.monster = Monster(hits, average_position=self.monster_average_position) + self.igor = None + self.unbound_pose = None + self.minimised_pdbblock = None + self.minimised_mol = None + self.reference_mol = None # filled only for validate + # buffers etc. + self._warned = [] + self.energy_score = {'ligand_ref2015': {'total_score': float('nan')}, + 'unbound_ref2015': {'total_score': float('nan')}} + self.mrmsd = mRSMD.mock() + # for debug purposes + self.tick = time.time() + self.tock = float('inf') + self.error_msg = '' + + # ----------------- init called methods ---------------------------------------------------------------------------- + + def slugify(self, name: str): + return re.sub(r'[\W_.-]+', '-', name) diff --git a/fragmenstein/victor/_victor_base_mixin.py b/fragmenstein/victor/_victor_base_mixin.py deleted file mode 100644 index c7c5ee2..0000000 --- a/fragmenstein/victor/_victor_base_mixin.py +++ /dev/null @@ -1,110 +0,0 @@ -######################################################################################################################## - -__doc__ = \ - """ -Base metho=ods - """ - -__author__ = "Matteo Ferla. [Github](https://github.com/matteoferla)" -__email__ = "matteo.ferla@gmail.com" -__date__ = "2020 A.D." -__license__ = "MIT" -__version__ = "0.4" -__citation__ = "" - -######################################################################################################################## - - -import logging - - -class _VictorBaseMixin: - quick_renanimation = False # thorugh reanimation? - monster_merging_mode = 'none_permissive' - monster_average_position = False - monster_joining_cutoff = 5. # Å - monster_throw_on_discard = False - monster_mmff_minisation = True - constraint_function_type = 'FLAT_HARMONIC' - work_path = 'output' - journal = logging.getLogger('Fragmenstein') - journal.setLevel(logging.DEBUG) - - covalent_definitions = [{'residue': 'CYS', 'smiles': '*SC', 'atomnames': ['CONN3', 'SG', 'CB']}] - warhead_definitions = [{'name': 'acrylamide', - 'covalent': 'C(=O)CC*', # the N may be secondary etc. so best not do mad substitutions. - 'covalent_atomnames': ['CZ', 'OZ', 'CY', 'CX', 'CONN1'], - # OZ needs to tautomerise & h-bond happily. - 'noncovalent': 'C(=O)C=C', - 'noncovalent_atomnames': ['CZ', 'OZ', 'CY', 'CX']}, - {'name': 'chloroacetamide', - 'covalent': 'C(=O)C*', # the N may be secondary etc. so best not do mad substitutions. - 'covalent_atomnames': ['CY', 'OY', 'CX', 'CONN1'], - # OY needs to tautomerise & h-bond happily. - 'noncovalent': 'C(=O)C[Cl]', - 'noncovalent_atomnames': ['CY', 'OY', 'CX', 'CLX'] - }, - {'name': 'nitrile', - 'covalent': 'C(=N)*', # zeroth atom is attached to the rest - 'covalent_atomnames': ['CX', 'NX', 'CONN1'], - 'noncovalent': 'C(#N)', # zeroth atom is attached to the rest - 'noncovalent_atomnames': ['CX', 'NX'] - }, - {'name': 'vinylsulfonamide', - 'covalent': 'S(=O)(=O)CC*', # the N may be secondary etc. so best not do mad substitutions. - 'covalent_atomnames': ['SZ', 'OZ1', 'OZ2', 'CY', 'CX', 'CONN1'], # OZ tauto - 'noncovalent': 'S(=O)(=O)C=C', - 'noncovalent_atomnames': ['SZ', 'OZ1', 'OZ2', 'CY', 'CX'] - }, - {'name': 'bromoalkyne', - 'covalent': 'C(=C)*', - 'covalent_atomnames': ['CX', 'CY', 'CONN1'], - # OY needs to tautomerise & h-bond happily. - 'noncovalent': 'C#C[Br]', - 'noncovalent_atomnames': ['CX', 'CY', 'BRX'] - }, - ] - - # these may be wrong and need checking. - possible_definitions =[{'name': 'aurothiol', # gold salt - 'covalent': 'S[Au]*', - 'covalent_atomnames': ['SY', 'AUX', 'CONN1'], - # OY needs to tautomerise & h-bond happily. - 'noncovalent': 'S[Au]P(CC)(CC)CC', - 'noncovalent_atomnames': ['SY', 'AUX', 'PL', 'CL1', 'CL2', 'CL3', 'CL4', 'CL5', 'CL6'] - }, - {'name': 'aldehyde', - 'covalent': 'C(O)*', - 'covalent_atomnames': ['CX', 'OX', 'CONN1'], - 'noncovalent': '[C:H1]=O', # this at - 'noncovalent_atomnames': ['CX', 'OX'] - }, - ] - - _connected_names = ('CONN', 'LOWE', 'UPPE', 'CONN1', 'CONN2', 'CONN3', 'LOWER', 'UPPER') - - error_to_catch = Exception - - def __init__(self): - # raise NotImplementedError('Abstract method') - # gets overridden - self.long_name = str() - self.smiles = str() - self.apo_pdbblock = str() - self.hits = list() - self.ligand_resn = str() - self.ligand_resi = str() - self.covalent_resn = str() - self.covalent_resi = str() - self.extra_constraint = str() - self.pose_fx = lambda x: None - self.is_covalent = False - # these are calculated. - self.params = 'Params' - self.mol = 'Chem.Mol' - self.constraint = 'Constraint' - self.monster = 'Monster' - self.modifications = {} - self.unminimised_pdbblock = str() - self.igor = 'Igor' - self.minimised_pdbblock = str() diff --git a/fragmenstein/victor/_victor_combine.py b/fragmenstein/victor/_victor_combine.py new file mode 100644 index 0000000..fcba590 --- /dev/null +++ b/fragmenstein/victor/_victor_combine.py @@ -0,0 +1,149 @@ +from ._victor_common import _VictorCommon +from ..monster import Monster +from ..igor import Igor +from ..m_rmsd import mRSMD +from molecular_rectifier import Rectifier +from typing import List, Optional, Dict, Union, Callable +from rdkit import Chem +from rdkit.Chem import AllChem +from rdkit_to_params import Params, Constraints +import time, warnings + + +# ================== Main entry===================================================================================== + + + + +class _VictorCombine(_VictorCommon): + """ + Combines the hits without a template. + If the class attribute ``monster_throw_on_discard`` is True, it will raise an exception if it cannot. + + The cutoff distance is controlled by class attribute ``monster_joining_cutoff``. + At present this just adds a hydrocarbon chain, no fancy checking for planarity. + + The hits are collapsed, merged, expanded and bonded by proximity. + In ``(self.monster.expand_ring(..., bonded_as_original=False)`` changing to True, might work, but most likely won't. + + ``warhead_harmonisation`` fixes the warhead in the hits to be homogeneous. + + * ``keep``. Don't do anything + * ``none``. strip warheads + * ``first``. Use first warhead + * warhead name. Use this warhead. + + :param hits: + :param pdb_filename: + :param ligand_resn: + :param ligand_resi: + :param covalent_resn: + :param covalent_resi: + :param extra_constraint: + :param pose_fx: + :param atomnames: + :param warhead_harmonisation: keep | strip | first | chloracetimide | nitrile ... + :return: + """ + + def combine(self, + long_name: Optional[str] = None, + atomnames: Optional[Dict[int, str]] = None, + warhead_harmonisation: str = 'first', + joining_cutoff=5., # Å + ): + self.joining_cutoff = joining_cutoff + self.atomnames = atomnames + self.warhead_harmonisation = warhead_harmonisation + if long_name is None: + self.long_name = '-'.join([h.GetProp('_Name') for h in self.hits]) + else: + self.long_name = self.slugify(long_name) + # ## Analyse + self._safely_do(execute=self._calculate_combination, resolve=self._resolve, reject=self._reject) + return self + + def _harmonise_warhead_combine(self): + """ + Runs self.harmonise_warheads on the hits, but also determines covalency + + :return: + """ + self.journal.debug(f'{self.long_name} - harmonising warheads on hits in "{self.warhead_harmonisation}" mode') + with warnings.catch_warnings(record=True) as self._warned: + self.hits = self.harmonise_warheads(self.hits, self.warhead_harmonisation, covalent_form=True) + self._log_warnings() + # these are calculated + starhits = any(['*' in Chem.MolToSmiles(h) for h in self.hits]) + if starhits and (self.covalent_resi is None or self.covalent_resn is None): + raise ValueError(f'{self.long_name} - is covalent but without known covalent residues') + elif self.warhead_harmonisation == 'strip': + self.is_covalent = False + elif starhits: + self.is_covalent = True + else: + self.is_covalent = False + + + def _calculate_combination(self): + attachment = self._get_attachment_from_pdbblock() if self.is_covalent else None + self.monster = Monster(hits=self.hits, + average_position=self.monster_average_position + ) + self.monster.modifications = self.modifications + self.monster.combine(keep_all=self.monster_throw_on_discard, + collapse_rings=True, + joining_cutoff=self.joining_cutoff # Å + ) + self.mol = self.monster.positioned_mol + self.smiles = Chem.MolToSmiles(self.mol) + # making folder. + self.make_output_folder() + # paramterise + self.journal.debug(f'{self.long_name} - Starting parameterisation') + self.params = Params.load_mol(self.mol, name=self.ligand_resn) + self.params.NAME = self.ligand_resn # force it. + self.params.polish_mol() + # get constraint + self.constraint = self._get_constraint(self.extra_constraint) + self.constraint.custom_constraint += self.make_coordinate_constraints_for_unnovels() + # _get_constraint will have changed the names in params.mol so the others need changing too! + # namely self.params.rename_by_substructure happend. + self.mol = Chem.Mol(self.params.mol) + self.monster.positioned_mol = Chem.Mol(self.mol) + # those Hs lack correct names and charge!! + self.params.add_Hs() + self.params.convert_mol() + # self.journal.warning(f'{self.long_name} - CHI HAS BEEN DISABLED') + # self.params.CHI.data = [] # TODO check if chi fix is okay + self._log_warnings() + self.post_params_step() # empty overridable + self.mmerging_mode = 'full' + self.unminimised_pdbblock = self._plonk_monster_in_structure() + params_file, holo_file, constraint_file = self._save_prerequisites() + self.unbound_pose = self.params.test() + self._checkpoint_alpha() + self._checkpoint_bravo() + self.igor = Igor.from_pdbblock(pdbblock=self.unminimised_pdbblock, + params_file=params_file, + constraint_file=constraint_file, + ligand_residue=self.ligand_resi, + key_residues=[self.covalent_resi]) + # user custom code. + if self.pose_fx is not None: + self.journal.debug(f'{self.long_name} - running custom pose mod.') + self.pose_fx(self.igor.pose) + else: + self.pose_mod_step() # empty overridable + # storing a roundtrip + self.unminimised_pdbblock = self.igor.pose2str() + # minimise until the ddG is negative. + self.reanimate_n_store() + self.journal.debug(f'{self.long_name} - Completed') + + + + + + + diff --git a/fragmenstein/victor/_victor_common.py b/fragmenstein/victor/_victor_common.py new file mode 100644 index 0000000..ad7eb53 --- /dev/null +++ b/fragmenstein/victor/_victor_common.py @@ -0,0 +1,350 @@ +from ._victor_igor import _VictorIgor + +import os, re +from typing import * +from rdkit import Chem +from rdkit.Chem import AllChem +from rdkit_to_params import Constraints + +# ---------------------------------------------------------------------------------------------------------------------- + +class _VictorCommon(_VictorIgor): + + def make_output_folder(self): + path = os.path.join(self.work_path, self.long_name) + if not os.path.exists(self.work_path): + os.mkdir(self.work_path) + if not os.path.exists(path): + os.mkdir(path) + else: + self.journal.warning(f'{self.long_name} - Folder {path} exists.') + + def _save_prerequisites(self): + self._log_warnings() + # saving params + self.journal.debug(f'{self.long_name} - saving params') + params_file = os.path.join(self.work_path, self.long_name, self.long_name + '.params') + self.params.dump(params_file) + # saving holo + self.journal.debug(f'{self.long_name} - saving holo (unmimised)') + holo_file = os.path.join(self.work_path, self.long_name, self.long_name + '.holo_unminimised.pdb') + with open(holo_file, 'w') as w: + w.write(self.unminimised_pdbblock) + # saving constraint + if self.constraint is not None: + self.journal.debug(f'{self.long_name} - saving constraint') + constraint_file = os.path.join(self.work_path, self.long_name, self.long_name + '.con') + self.constraint.dump(constraint_file) + else: # basically impossible. + constraint_file = '' + return params_file, holo_file, constraint_file + + # =================== Constraint & attachment ====================================================================== + + def _get_constraint(self, extra_constraint: Optional[str] = None) -> Union[Constraints, None]: + # deal with covalent and non covalent separately + if self.is_covalent: + self.journal.debug(f'{self.long_name} - is covalent.') + constraint = self._fix_covalent() + if extra_constraint: + constraint.custom_constraint += self.extra_constraint + return constraint + else: + self.journal.debug(f'{self.long_name} - is not covalent.') + constraint = self._fix_uncovalent() + if extra_constraint: + constraint.custom_constraint += self.extra_constraint + return constraint + + def _fix_uncovalent(self): + return Constraints.mock() + + def _fix_covalent(self): + self.journal.debug(f'{self.long_name} - fixing for covalent') + # to make life easier for analysis, CX is the attachment atom, CY is the one before it. + war_def = self._get_war_def() + warhead = Chem.MolFromSmiles(war_def['covalent']) + self.params.rename_by_substructure(warhead, war_def['covalent_atomnames']) + cov_def = [d for d in self.covalent_definitions if d['residue'] == self.covalent_resn][0] + self.journal.debug(f'{self.long_name} - has a {war_def["name"]}') + cons = Constraints(smiles=(war_def['covalent'], cov_def['smiles']), + names=[*war_def['covalent_atomnames'], *cov_def['atomnames']], + ligand_res=self.ligand_resi, + target_res=self.covalent_resi) + # user added constraint + if 'constraint' in war_def: + cons.custom_constraint = war_def['constraint'] + return cons + + def make_coordinate_constraints(self, + mol: Optional[Chem.Mol] = None, + origins: Optional[List[List[str]]] = None, + std: Optional[List[float]] = None, + mx: Optional[List[float]] = None) -> str: + """ + See also ``make_coordinate_constraints_for_unnovels`` in automerge. + This is the normal function and uses the origin data, + while the other constrains based on lack of novel attribute. + + :param mol: self.monster.positioned_mol if ommitted + :param origins: self.monster.origin_from_mol(self.monster.positioned_mol) if ommitted + list of list of names of hit atoms used as original position + :param std: self.monster.stdev_from_mol(mol)(self.monster.positioned_mol) if omitted + list of standard devs + :param mx: elf.monster.max_from_mol(self.monster.positioned_mol) if omitted + list of maximum euclidean distance + :return: + """ + lines = [] + if mol is None: + mol = self.monster.positioned_mol + if origins is None: + origins = self.monster.origin_from_mol(mol) + if std is None: + std = self.monster.stdev_from_mol(mol) + if mx is None: + mx = self.monster.max_from_mol(mol) + conf = self.monster.positioned_mol.GetConformer() + # Calculate + for i in range(mol.GetNumAtoms()): + if len(origins[i]) > 0: + atom = mol.GetAtomWithIdx(i) + if atom.GetSymbol() == '*': + continue + elif atom.GetPDBResidueInfo() is None: + self.journal.critical(f'Atom {i} ({atom.GetSymbol()}) has no name!') + continue + pos = conf.GetAtomPosition(i) + if self.constraint_function_type.upper() == 'HARMONIC': + fxn = f'HARMONIC 0 {std[i] + 1}' + elif self.constraint_function_type.upper() == 'FLAT_HARMONIC': + if len(origins[i]) > 1: + fxn = f'FLAT_HARMONIC 0 1.0 {mx[i]}' + else: + fxn = f'HARMONIC 0 1.0' + elif self.constraint_function_type.upper() == 'BOUNDED': + fxn = f'BOUNDED 0 {mx[i]} 1 0.5 TAG' + else: + raise ValueError(f'{self.constraint_function_type} is not HARMONIC or FADE or BOUNDED') + atomname = atom.GetPDBResidueInfo().GetName() + lines.append(f'CoordinateConstraint {atomname} {self.ligand_resi} ' + + f'CA {self.covalent_resi} ' + + f'{pos.x} {pos.y} {pos.z} {fxn}\n') + return ''.join(lines) + + def make_coordinate_constraints_for_unnovels(self): + """ + See also ``cls.make_coordinate_constraints``. + This operates based on ``atom.HasProp('_Novel')``, not origins! + :return: + """ + lines = [] + conf = self.monster.positioned_mol.GetConformer() + for i, atom in enumerate(self.monster.positioned_mol.GetAtoms()): + if atom.GetSymbol() == '*': + continue + elif atom.HasProp('_Novel') and atom.GetBoolProp('_Novel'): + continue # novels + elif atom.GetPDBResidueInfo() is None: + self.journal.critical(f'Atom {i} ({atom.GetSymbol()}) has no name!') + continue + else: + pos = conf.GetAtomPosition(i) + fxn = f'HARMONIC 0 1' # the other do not make sense here. + lines.append(f'CoordinateConstraint {atom.GetPDBResidueInfo().GetName()} {self.ligand_resi} ' + \ + f'CA {self.covalent_resi} ' + \ + f'{pos.x} {pos.y} {pos.z} {fxn}\n') + return ''.join(lines) + + # ------------------------------------------------------------------------------------------------------------------ + + def _get_attachment_from_pdbblock(self) -> Union[None, Chem.Mol]: + """ + Yes, yes, I see the madness in using pymol to get an atom for rdkit to make a pose for pyrosetta. + Hence why `find_attachment` will replace it. + todo `_get_attachment_from_pdbblock` --> `find_attachment` + """ + import pymol2 + + self.journal.debug(f'{self.long_name} - getting attachemnt atom') + if not self.covalent_resn: + return None + else: + if isinstance(self.covalent_resi, str): + resi, chain = re.match('(\d+)(\w)', self.covalent_resi).groups() + resi = int(resi) + else: + resi = self.covalent_resi + chain = None + with pymol2.PyMOL() as pymol: + pymol.cmd.read_pdbstr(self.apo_pdbblock, 'prot') + if self.covalent_resn == 'CYS': + name = 'SG' + else: + raise NotImplementedError('only done for cys atm') + try: + if chain is not None: + pdb = pymol.cmd.get_pdbstr(f'resi {resi} and name {name} and chain {chain}') + else: + pdb = pymol.cmd.get_pdbstr(f'resi {resi} and name {name}') + except: + pdb = pymol.cmd.get_pdbstr(f'resi {resi} and name {name}') + return Chem.MolFromPDBBlock(pdb) + + def _get_war_def(self): + for war_def in self.warhead_definitions: + warhead = Chem.MolFromSmiles(war_def['covalent']) + if self.mol.HasSubstructMatch(warhead): + return war_def + else: + if self.mol.HasSubstructMatch(Chem.MolFromSmiles('*C')): + self.journal.warning('Unknown type of covalent') + return {'name': 'unknown', + 'covalent': 'C~C*', + 'covalent_atomnames': ['CY', 'CX', 'CONN1'], + 'noncovalent': 'C~[C+]', # clearly not + 'noncovalent_atomnames': ['CY', 'CX'] + } + else: + raise ValueError(f'{self.long_name} - Unsure what the warhead is {self.smiles}.') + + @classmethod + def inventorise_warheads(cls, hits: List[Chem.Mol], covalent_form: bool = True) -> List[str]: + """ + Get the warhead types of the list of hits + + :param hits: + :param covalent_form: Are the hits already covalent (with *) + :return: list of non-covalent, chloroacetimide, etc. + """ + inventory = ['noncovalent'] * len(hits) + for war_def in cls.warhead_definitions: + wh = cls._get_warhead_from_definition(war_def, covalent_form) + for i, hit in enumerate(hits): + if hit.HasSubstructMatch(wh): + inventory[i] = war_def['name'] + return inventory + + @classmethod + def _get_warhead_from_name(cls, warhead_name: str, covalent_form: bool) -> Chem.Mol: + """ + get_warhead_definition returns a definition, this retursn a mol. + + :param warhead_name: + :param covalent_form: + :return: + """ + war_def = cls.get_warhead_definition(warhead_name) + wh = cls._get_warhead_from_definition(war_def, covalent_form) + return wh + + @classmethod + def _get_warhead_from_definition(cls, war_def: dict, covalent_form: bool): + if covalent_form: + wh = Chem.MolFromSmiles(war_def['covalent']) + else: + wh = Chem.MolFromSmiles(war_def['noncovalent']) + return wh + + @classmethod + def get_warhead_definition(cls, warhead_name: str): + return cls._get_warhead_definitions(warhead_name)[0] + + @classmethod + def _get_warhead_definitions(cls, warhead_name: str): + """ + It is unlikely that alternative definitions are present. hence why hidden method. + + :param warhead_name: + :return: + """ + options = [wd for wd in cls.warhead_definitions if wd['name'] == warhead_name.lower()] + if len(options) == 0: + raise ValueError(f'{warhead_name} is not valid.') + else: + return options + + @classmethod + def make_all_warhead_combinations(cls, smiles: str, warhead_name: str, canonical=True) -> Union[dict, None]: + """ + Convert a unreacted warhead to a reacted one in the SMILES + + :param smiles: unreacted SMILES + :param warhead_name: name in the definitions + :param canonical: the SMILES canonical? (makes sense...) + :return: dictionary of SMILES + """ + mol = Chem.MolFromSmiles(smiles) + war_def = cls.get_warhead_definition(warhead_name) + ncv = Chem.MolFromSmiles(war_def['noncovalent']) + if mol.HasSubstructMatch(ncv): + combinations = {} + for wd in cls.warhead_definitions: + x = Chem.ReplaceSubstructs(mol, ncv, Chem.MolFromSmiles(wd['covalent']), + replacementConnectionPoint=0) + combinations[wd['name'] + '_covalent'] = Chem.MolToSmiles(x[0], canonical=canonical) + x = Chem.ReplaceSubstructs(mol, ncv, Chem.MolFromSmiles(wd['noncovalent']), + replacementConnectionPoint=0) + combinations[wd['name'] + '_noncovalent'] = Chem.MolToSmiles(x[0], canonical=canonical) + return combinations + else: + return None + + def harmonise_warheads(self, hits, warhead_harmonisation, covalent_form=True): + """ + Harmonises and marks the atoms with `_Warhead` Prop. + + :param hits: + :param warhead_harmonisation: + :param covalent_form: + :return: + """ + inventory = self.inventorise_warheads(hits, covalent_form) + # mark warhead atoms. + for hit, warhead_name in zip(hits, inventory): + if warhead_name != 'noncovalent': + wh = self._get_warhead_from_name(warhead_name, covalent_form) + match = hit.GetSubstructMatch(wh) + if match == (): + self.journal.warning(f'{self.long_name} - failed to mark warhead. What is it??') + else: + for i in match: + hit.GetAtomWithIdx(i).SetBoolProp('_Warhead', True) + # harmonise + if warhead_harmonisation == 'keep': + return hits + elif warhead_harmonisation == 'strip': + new_hits = [] + for hit, warhead_name in zip(hits, inventory): + if warhead_name != 'noncovalent': + wh = self._get_warhead_from_name(warhead_name, covalent_form) + nhit = AllChem.DeleteSubstructs(hit, wh) + Chem.SanitizeMol(nhit) + new_hits.append(nhit) + else: + new_hits.append(hit) + + return new_hits + elif warhead_harmonisation == 'first': + if len(set(inventory) - {'noncovalent'}) <= 1: + return hits + else: + first = None + new_hits = [] + for hit, warhead_name in zip(hits, inventory): + if warhead_name != 'noncovalent': + if first is None: + first = warhead_name + new_hits.append(hit) + elif warhead_name == first: + new_hits.append(hit) + else: + wh = self._get_warhead_from_name(warhead_name, covalent_form) + nhit = AllChem.DeleteSubstructs(hit, wh) + Chem.SanitizeMol(nhit) + new_hits.append(nhit) + else: + new_hits.append(hit) + return new_hits + else: # it is a warhead name. + raise NotImplementedError diff --git a/fragmenstein/victor/_victor_igor.py b/fragmenstein/victor/_victor_igor.py new file mode 100644 index 0000000..e5e70bd --- /dev/null +++ b/fragmenstein/victor/_victor_igor.py @@ -0,0 +1,109 @@ +from ._victor_store import _VictorStore +from rdkit import Chem +from rdkit.Chem import AllChem +from ..m_rmsd import mRSMD + +class _VictorIgor(_VictorStore): + + def _fix_minimised(self) -> Chem.Mol: + """ + PDBs are terrible for bond order etc. and Rosetta addes these based on atom types + :return: + """ + self.journal.debug(f'{self.long_name} - making ligand only') + ligand = self.igor.mol_from_pose() + template = AllChem.DeleteSubstructs(self.params.mol, Chem.MolFromSmiles('*')) + return AllChem.AssignBondOrdersFromTemplate(template, ligand) + + def quick_reanimate(self) -> float: + """ + Correct small deviations from what the forcefield likes. Generally flattens buckled rings and that is it. + Reanimate is normal. + + :return: + """ + self.igor.coordinate_constraint = 10. + self.igor.minimise(cycles=5, default_coord_constraint=False) + self.energy_score = self.calculate_score() + dG_bound = self.energy_score['ligand_ref2015']['total_score'] + dG_unbound = self.energy_score['unbound_ref2015']['total_score'] + ddG = dG_bound - dG_unbound + return ddG + + def reanimate(self) -> float: + """ + Calls Igor recursively until the ddG is negative or zero. + igor.minimise does a good job. this is just to get everything as a normal molecule + + :return: ddG (kcal/mol) + """ + ddG = 999 + self.igor.coordinate_constraint = 0. + # self.igor.fa_intra_rep = 0.02 # 4x + # quick unconstrained minimisation to wiggle it out of nasty local minima + self.igor.minimise(cycles=15, default_coord_constraint=False) + self.igor.coordinate_constraint = 2 + self.igor.minimise(cycles=5, default_coord_constraint=False) + self.igor.coordinate_constraint = 1 + while ddG > 0: + self.journal.debug(f'{self.long_name} - Igor minimising') + self.igor.minimise(default_coord_constraint=False) + self.energy_score = self.calculate_score() + dG_bound = self.energy_score['ligand_ref2015']['total_score'] + dG_unbound = self.energy_score['unbound_ref2015']['total_score'] + ddG = dG_bound - dG_unbound + if ddG > 0: + self.igor.coordinate_constraint /= 2 + self.journal.debug( + f'{self.long_name} - coord_constraint lowered: {self.igor.coordinate_constraint}: {ddG} kcal/mol.') + if self.igor.coordinate_constraint == 0.: + self.journal.warn(f'{self.long_name} - failed to minimise without constraints: {ddG} kcal/mol.') + break + elif self.igor.coordinate_constraint < 0.005: + self.igor.coordinate_constraint = 0. + return ddG + + def reanimate_n_store(self): + ddG = self.reanimate() + self._store_after_reanimation(ddG) + + def _store_after_reanimation(self, ddG: float): + self.minimised_pdbblock = self.igor.pose2str() + self.post_igor_step() # empty overridable + self.minimised_mol = self._fix_minimised() + self.mrmsd = self._calculate_rmsd() + self.journal.info(f'{self.long_name} - final score: {ddG} kcal/mol {self.mrmsd.mrmsd}.') + self._checkpoint_charlie() + self.journal.debug(f'{self.long_name} - Completed') + + def _calculate_rmsd(self): + self.journal.debug(f'{self.long_name} - calculating mRMSD') + return mRSMD.from_other_annotated_mols(self.minimised_mol, self.hits, self.monster.positioned_mol) + + def calculate_score(self): + return {**self.igor.ligand_score(), + 'unbound_ref2015': self.igor.detailed_scores(self.unbound_pose, 1)} + + @property + def constrained_atoms(self) -> int: + """ + Do note that the whole Origins list contains hydrogens. So do not divided by len! + :return: + """ + try: + conn = sum([o != [] for o in self.monster.origin_from_mol(self.monster.positioned_mol)]) + except Exception as err: + self.journal.warning(f'{self.long_name} - {err.__class__.__name__}: {err}') + conn = float('nan') + return conn + + @property + def unconstrained_heavy_atoms(self) -> int: + try: + origins = self.monster.origin_from_mol(self.monster.positioned_mol) + unconn = sum([o == [] and atom.GetSymbol() != 'H' for o, atom in + zip(origins, self.monster.positioned_mol.GetAtoms())]) + except Exception as err: + self.journal.warning(f'{self.long_name} - {err.__class__.__name__}: {err}') + unconn = float('nan') + return unconn \ No newline at end of file diff --git a/fragmenstein/victor/_victor_journal.py b/fragmenstein/victor/_victor_journal.py new file mode 100644 index 0000000..8d1755f --- /dev/null +++ b/fragmenstein/victor/_victor_journal.py @@ -0,0 +1,122 @@ +from ._victor_safety import _VictorSafety +from ._loggerwriter import LoggerWriter +import logging, sys, os, re, requests, unicodedata +from rdkit import Chem +from rdkit_to_params import Params + + +class _VictorJournal(_VictorSafety): + + def _log_warnings(self): + if len(self._warned): + for w in self._warned: + self.journal.warning(f'{self.long_name} - {w.message} ({w.category})') + self._warned.clear() + + @classmethod + def enable_stdout(cls, + level=logging.INFO, + captured: bool = True) -> None: + """ + The ``cls.journal`` is output to the terminal. + Running it twice can be used to change level. + + :param level: logging level + :param captured: capture rdkit and pyrosetta? + :return: None + """ + cls.journal.handlers = [h for h in cls.journal.handlers if h.name != 'stdout'] + handler = logging.StreamHandler(sys.stdout) + handler.setLevel(level) + handler.set_name('stdout') + handler.setFormatter(logging.Formatter('[%(asctime)s] %(levelname)s - %(message)s')) + cls.journal.addHandler(handler) + # logging.getLogger('py.warnings').addHandler(handler) + if captured: + cls.capture_logs() + + @classmethod + def enable_logfile(cls, filename='reanimation.log', + level=logging.INFO, + captured: bool = True) -> None: + """ + The journal is output to a file. + Running it twice can be used to change level. + + :param filename: file to write. + :param level: logging level + :param captured: capture rdkit and pyrosetta? + :return: None + """ + cls.journal.handlers = [h for h in cls.journal.handlers if h.name != 'logfile'] + handler = logging.FileHandler(filename) + handler.setLevel(level) + handler.set_name('logfile') + handler.setFormatter(logging.Formatter('[%(asctime)s] %(levelname)s - %(message)s')) + cls.journal.addHandler(handler) + # logging.getLogger('py.warnings').addHandler(handler) + if captured: + cls.capture_logs() + + _rdkit_captured = False + + @classmethod + def capture_rdkit_log(cls): + """ + RDKit spits a few warning and errors. + This makes them inline with the logger. + """ + if cls._rdkit_captured: + return + Chem.WrapLogs() + sys.stderr = LoggerWriter(cls.journal.warning) + cls._rdkit_captured = True + + _rosetta_captured = False + + @classmethod + def capture_rosetta_log(cls): + """ + Rosetta normally prints to stout. This captures the messages into ``journal``. + It technically simply passes the handlers of journal to that of the Rosetta logger. + For alternatives, https://github.com/matteoferla/pyrosetta_scripts/tree/main/init_helper + """ + if cls._rosetta_captured: + return + import pyrosetta + pyrosetta.logging_support.set_logging_sink() + logger = logging.getLogger("rosetta") + logger.setLevel(logging.DEBUG) + logger.handlers = cls.journal.handlers + cls._rosetta_captured = True + + @classmethod + def capture_logs(cls): + cls.capture_rdkit_log() + cls.capture_rosetta_log() + + @classmethod + def slack_me(cls, msg: str) -> bool: + """ + Send message to a slack webhook + + :param msg: Can be dirty and unicode-y. + :return: did it work? + :rtype: bool + """ + webhook = os.environ['SLACK_WEBHOOK'] + # sanitise. + msg = unicodedata.normalize('NFKD', msg).encode('ascii', 'ignore').decode('ascii') + msg = re.sub('[^\w\s\-.,;?!@#()\[\]]', '', msg) + r = requests.post(url=webhook, + headers={'Content-type': 'application/json'}, + data=f"{{'text': '{msg}'}}") + if r.status_code == 200 and r.content == b'ok': + return True + else: + return False + + +# ----------------------- Make params use the same log. + +Params.log = _VictorJournal.journal diff --git a/fragmenstein/victor/_victor_overridables.py b/fragmenstein/victor/_victor_overridables.py new file mode 100644 index 0000000..c1f66cb --- /dev/null +++ b/fragmenstein/victor/_victor_overridables.py @@ -0,0 +1,31 @@ +from ._victor_plonk import _VictorPlonk + +class _VictorOverridables(_VictorPlonk): + + def post_params_step(self): + """ + This method is intended for make inherited mods easier. + :return: + """ + pass + + def post_monster_step(self): + """ + This method is intended for make inherited mods easier. + :return: + """ + pass + + def pose_mod_step(self): + """ + This method is intended for make inherited mods easier. + :return: + """ + pass + + def post_igor_step(self): + """ + This method is intended for make inherited mods easier. + :return: + """ + pass \ No newline at end of file diff --git a/fragmenstein/victor/_victor_place.py b/fragmenstein/victor/_victor_place.py new file mode 100644 index 0000000..505519d --- /dev/null +++ b/fragmenstein/victor/_victor_place.py @@ -0,0 +1,111 @@ +from typing import * +from ._victor_common import _VictorCommon +from rdkit_to_params import Params +from ..monster import Monster +from ..igor import Igor + +class _VictorPlace(_VictorCommon): + def place(self, + smiles: str, + long_name: str = 'ligand', + merging_mode='none_permissive', + atomnames: Optional[Dict[int, str]] = None): + """ + :param smiles: + :param long_name: gets used for filenames so will get slugified + :param merging_mode: + :param atomnames: + :return: + """ + # ## Store + self.long_name = self.slugify(long_name) + self.smiles = smiles + self.atomnames = atomnames + self.merging_mode = merging_mode + # ## Analyse + self._safely_do(execute=self._calculate_placement, resolve=self._resolve, reject=self._reject) + return self + + def _calculate_placement(self): + """ + This does all the work + + :return: + """ + # check they are okay + self._assert_placement_inputs() + # ***** PARAMS & CONSTRAINT ******* + self.journal.info(f'{self.long_name} - Starting work') + self._log_warnings() + # making folder. + self.make_output_folder() + # make params + self.journal.debug(f'{self.long_name} - Starting parameterisation') + self.params = Params.from_smiles(self.smiles, name=self.ligand_resn, generic=False, atomnames=self.atomnames) + # self.journal.warning(f'{self.long_name} - CHI HAS BEEN DISABLED') + # self.params.CHI.data = [] # Chi is fixed, but older version. should probably check version + self.mol = self.params.mol + self._log_warnings() + # get constraint + self.constraint = self._get_constraint(self.extra_constraint) + attachment = self._get_attachment_from_pdbblock() if self.is_covalent else None + self._log_warnings() + self.post_params_step() # empty overridable + # ***** FRAGMENSTEIN Monster ******* + # make monster + self.journal.debug(f'{self.long_name} - Starting fragmenstein') + # monster_throw_on_discard controls if disconnected. + self.monster = Monster(hits=self.hits, + average_position=self.monster_average_position) + self.monster.place(mol=self.mol, + attachment=attachment, + merging_mode=self.merging_mode) + self.journal.debug(f'{self.long_name} - Tried {len(self.monster.mol_options)} combinations') + self.unminimised_pdbblock = self._plonk_monster_in_structure() + self.constraint.custom_constraint += self.make_coordinate_constraints() + self._checkpoint_bravo() + # save stuff + params_file, holo_file, constraint_file = self._save_prerequisites() + self.post_monster_step() # empty overridable + self.unbound_pose = self.params.test() + self._checkpoint_alpha() + # ***** EGOR ******* + self.journal.debug(f'{self.long_name} - setting up Igor') + self.igor = Igor.from_pdbblock(pdbblock=self.unminimised_pdbblock, + params_file=params_file, + constraint_file=constraint_file, + ligand_residue=self.ligand_resi, + key_residues=[self.covalent_resi]) + # user custom code. + if self.pose_fx is not None: + self.journal.debug(f'{self.long_name} - running custom pose mod.') + self.pose_fx(self.igor.pose) + else: + self.pose_mod_step() # empty overridable + # storing a roundtrip + self.unminimised_pdbblock = self.igor.pose2str() + # minimise until the ddG is negative. + if self.quick_renanimation: + ddG = self.quick_reanimate() + else: + ddG = self.reanimate() + self._store_after_reanimation(ddG) + + def _assert_placement_inputs(self): + if '*' in self.smiles and (self.covalent_resi is None or self.covalent_resn is None): + raise ValueError(f'{self.long_name} - is covalent but without known covalent residues') + # TODO '*' in self.smiles is bad. user might start with a mol file. + elif '*' in self.smiles: + self.is_covalent = True + else: + self.is_covalent = False + assert len(self.ligand_resn) == 3, f'{self.long_name} - {self.ligand_resn} is not 3 char long.' + assert len(self.hits), f'{self.long_name} - No hits to use to construct' + assert self.ligand_resn != 'UNL', f'{self.long_name} - It cannot be UNL as it s the unspecified resn in rdkit' + if self.covalent_resn and len( + [d for d in self.covalent_definitions if d['residue'] == self.covalent_resn]) == 0: + raise ValueError(f'{self.long_name} - Unrecognised type {self.covalent_resn}') + + + + diff --git a/fragmenstein/victor/_victor_plonk.py b/fragmenstein/victor/_victor_plonk.py new file mode 100644 index 0000000..3ffd439 --- /dev/null +++ b/fragmenstein/victor/_victor_plonk.py @@ -0,0 +1,125 @@ +import re +from typing import Optional + +from rdkit import Chem +from rdkit.Chem import AllChem +from rdkit_to_params import Params, Constraints +from ._victor_journal import _VictorJournal +from .minimalPDB import MinimalPDBParser + + +class _VictorPlonk(_VictorJournal): + # the following is here as opposed to Monster, because it requires the template, ligand connections etc. + # the stupid name "plonk" is to distinguish it from place and placement, which have a different meaning in Monster. + + def _get_LINK_record(self): + if self.is_covalent: + # get correct chain names. + l_resi, l_chain = re.match('(\d+)(\D?)', str(self.ligand_resi)).groups() + if self.covalent_resi: + p_resi, p_chain = re.match('(\d+)(\D?)', str(self.covalent_resi)).groups() + else: + p_resi, p_chain = None, None + if not p_chain: + p_chain = 'A' + if not l_chain: + l_chain = 'B' + # get the cx atom name + cx = self.params.pad_name(self.params.CONNECT[0].atom_name) + # TODO the SG connection is hardcoded. + return f'LINK SG {self.covalent_resn} {p_chain} {p_resi: >3} ' + \ + f'{cx} {self.ligand_resn} {l_chain} {l_resi: >3} 1555 1555 1.8\n' + else: + return '' + + def _correct_ligand_info(self, mol: Optional[Chem.Mol] = None) -> Chem.Mol: + """ + Corrects in place the given mol based on self.ligand_resi. + If none provided it assumed self.monster.positioned_mol + Correcting the serial unfortunately does not do anything. + """ + if mol is None: + mol = self.monster.positioned_mol + l_resi, l_chain = re.match('(\d+)(\D?)', str(self.ligand_resi)).groups() # TODO improve ligand_resi + for atom in mol.GetAtoms(): + info = atom.GetPDBResidueInfo() + info.SetResidueNumber(int(l_resi)) + info.SetChainId(l_chain) + info.SetIsHeteroAtom(True) + info.SetOccupancy(1.) + info.SetResidueName(self.ligand_resn) + return mol + + def _plonk_monster_in_structure(self, use_pymol=False): + self._correct_ligand_info() + self.journal.debug(f'{self.long_name} - placing monster in structure') + if use_pymol: + return self._plonk_monster_in_structure_pymol() + else: + # _plonk_monster_in_structure_raw does no corrections. + return self._plonk_monster_in_structure_minimal() + + def _get_preminimised_undummied_monster(self): + """ + This method is called by the plonking into structure methods. + Not "positioning" as intended by ``monster`` is done. + Opening a PDB in RDKit is doable but gets exponentially slow with chain length + """ + mol = AllChem.DeleteSubstructs(self.monster.positioned_mol, Chem.MolFromSmiles('*')) + if self.monster_mmff_minisation: + self.journal.debug(f'{self.long_name} - pre-minimising monster (MMFF)') + self.monster.mmff_minimise(mol) + return mol + + def _plonk_monster_in_structure_minimal(self): + """ + Plonks the molecule in the structure without using pymol. + Uses a custom miniparser. see minimalPDB + + :return: + """ + mol = self._get_preminimised_undummied_monster() + pdbdata = MinimalPDBParser(self.apo_pdbblock) + moldata = MinimalPDBParser(Chem.MolToPDBBlock(mol)) + if self.is_covalent: + pdbdata.headers.append(self._get_LINK_record()) + pdbdata.append(moldata) # fixes offsets in ATOM/HETATM and CONECT lines. + return str(pdbdata) + + def _plonk_monster_in_structure_raw(self): + """ + Plonks the molecule in the structure without using pymol. + Not "positioning" as intended by ``monster`` is done. + Opening a PDB in RDKit is doable but gets exponentially slow with chain length + + :return: + """ + mol = self._get_preminimised_undummied_monster() + mol_block = Chem.MolToPDBBlock(mol) + return '\n'.join([self._get_LINK_record().strip(), + self.apo_pdbblock.strip(), + mol_block + ]).strip() + + def _plonk_monster_in_structure_pymol(self): + """ + Plonks the molecule in the structure using pymol. + Not "positioning" as intended by ``monster`` is done. + + :return: + """ + import pymol2 + mol = self._get_preminimised_undummied_monster() + with pymol2.PyMOL() as pymol: + pymol.cmd.read_pdbstr(self.apo_pdbblock, 'apo') + pos_mol = Chem.MolToPDBBlock(mol) + # pymol.cmd.read_pdbstr(pos_mol, 'scaffold') + pymol.cmd.remove('name R') # no dummy atoms! + for c in self._connected_names: + pymol.cmd.remove(f'name {c}') # no conns + pymol.cmd.remove('resn UNL') # no unmatched stuff. + pdbblock = pymol.cmd.get_pdbstr('*') + pymol.cmd.delete('*') + return self._get_LINK_record() + pdbblock + + diff --git a/fragmenstein/victor/_victor_safety.py b/fragmenstein/victor/_victor_safety.py new file mode 100644 index 0000000..2c77128 --- /dev/null +++ b/fragmenstein/victor/_victor_safety.py @@ -0,0 +1,53 @@ +from typing import * +from ._victor_base import _VictorBase +import warnings, time + +class _VictorSafety(_VictorBase): + + # cvar: error_to_catch = Exception + + def _safely_do(self, + execute: Optional[Callable] = None, + resolve: Optional[Callable] = None, + reject: Optional[Callable] = None): + """ + A safety net around the analysis. + Ought to be a decorator and ought to not use the same names as a JS Promise. + The class attribute ``error_to_catch`` is by default Exception + + :param execute: what to run (main) + :param resolve: what to run at the end (regardless of failure) + :param reject: what to run if ``exceute`` fails + :return: + """ + # warnings + with warnings.catch_warnings(record=True) as self._warned: + try: + if execute is not None: + execute() + except self.error_to_catch as err: + self.error_msg = f'{err.__class__.__name__}: {err}' + if reject is not None: + reject(err) + finally: + if resolve is not None: + resolve() + + def _resolve(self) -> None: + """ + This gets called at the end of ``_safely_do``, regardless of the whether it worked or not. + So the name is a bit misleading. + + :return: + """ + self.tock = time.time() + self.journal.info(f'{self.long_name} - Time taken: {self.tock - self.tick}') + + def _reject(self, err) -> None: + """ + This gets called by ``_safely_do`` on error. + + :param err: the error raised. + :return: + """ + self.journal.error(f'{self.long_name} — {err.__class__.__name__}: {err}') \ No newline at end of file diff --git a/fragmenstein/victor/_victor_store.py b/fragmenstein/victor/_victor_store.py new file mode 100644 index 0000000..bfd5524 --- /dev/null +++ b/fragmenstein/victor/_victor_store.py @@ -0,0 +1,93 @@ +import json +import os + +import pyrosetta +from rdkit import Chem + +from ._victor_overridables import _VictorOverridables + + +class _VictorStore(_VictorOverridables): + # _save_prerequisites is in VictorCommon + + def checkpoint(self): + self._checkpoint_alpha() + self._checkpoint_bravo() + self._checkpoint_charlie() + + def _checkpoint_alpha(self): + self._log_warnings() + # saving hits (without copying) + for h, hit in enumerate(self.hits): + if hit.HasProp("_Name") and hit.GetProp("_Name").strip(): + name = hit.GetProp("_Name") + else: + name = f'hit{h}' + hfile = os.path.join(self.work_path, self.long_name, f'{name}.pdb') + Chem.MolToPDBFile(hit, hfile) + mfile = os.path.join(self.work_path, self.long_name, f'{name}.mol') + Chem.MolToMolFile(hit, mfile, kekulize=False) + # saving params template + params_template_file = os.path.join(self.work_path, self.long_name, self.long_name + '.params_template.pdb') + Chem.MolToPDBFile(self.params.mol, params_template_file) + params_template_file = os.path.join(self.work_path, self.long_name, self.long_name + '.params_template.mol') + Chem.MolToMolFile(self.params.mol, params_template_file) + # checking all is in order + ptest_file = os.path.join(self.work_path, self.long_name, self.long_name + '.params_test.pdb') + self.unbound_pose.dump_pdb(ptest_file) + pscore_file = os.path.join(self.work_path, self.long_name, self.long_name + '.params_test.score') + scorefxn = pyrosetta.get_fa_scorefxn() + with open(pscore_file, 'w') as w: + w.write(str(scorefxn(self.unbound_pose))) + self._log_warnings() + + def _checkpoint_bravo(self): + self._log_warnings() + self.journal.debug(f'{self.long_name} - saving mols from monster') + # if self.monster.scaffold is not None: + # scaffold_file = os.path.join(self.work_path, self.long_name, self.long_name + '.scaffold.mol') + # Chem.MolToMolFile(self.monster.scaffold, scaffold_file, kekulize=False) + # if self.monster.scaffold.HasProp('parts'): + # disregard = json.loads(self.monster.scaffold.GetProp('parts')) + # self.journal.info(f'{self.long_name} - disregarded {disregard}') + # else: + # disregard = [] + # if self.monster.chimera is not None: + # chimera_file = os.path.join(self.work_path, self.long_name, self.long_name + '.chimera.mol') + # Chem.MolToMolFile(self.monster.chimera, chimera_file, kekulize=False) + if self.monster.positioned_mol is not None: + pos_file = os.path.join(self.work_path, self.long_name, self.long_name + '.positioned.mol') + Chem.MolToMolFile(self.monster.positioned_mol, pos_file, kekulize=False) + if self.monster.mol_options: + opt_file = os.path.join(self.work_path, self.long_name, self.long_name + '.mol_options.sdf') + writer = Chem.SDWriter(opt_file) + writer.SetKekulize(False) + for t in self.monster.mol_options: + writer.write(t) + writer.close() + frag_file = os.path.join(self.work_path, self.long_name, self.long_name + '.monster.json') + data = {'smiles': self.smiles, + 'origin': self.monster.origin_from_mol(self.monster.positioned_mol), + 'stdev': self.monster.stdev_from_mol(self.monster.positioned_mol)} + # if disregard: + # data['disregard'] = disregard + with open(frag_file, 'w') as w: + json.dump(data, w) + self._log_warnings() + # unminimised_pdbblock will be saved by igor (round trip via pose) + + def _checkpoint_charlie(self): + self._log_warnings() + self.journal.debug(f'{self.long_name} - saving pose from igor') + min_file = os.path.join(self.work_path, self.long_name, self.long_name + '.holo_minimised.pdb') + self.igor.pose.dump_pdb(min_file) + self.journal.debug(f'{self.long_name} - calculating Gibbs') + # recover bonds + lig_file = os.path.join(self.work_path, self.long_name, self.long_name + '.minimised.mol') + Chem.MolToMolFile(self.minimised_mol, lig_file) + score_file = os.path.join(self.work_path, self.long_name, self.long_name + '.minimised.json') + with open(score_file, 'w') as w: + json.dump({'Energy': self.energy_score, + 'mRMSD': self.mrmsd.mrmsd, + 'RMSDs': self.mrmsd.rmsds}, w) + self._log_warnings() \ No newline at end of file diff --git a/fragmenstein/victor/_victor_utils_mixin.py b/fragmenstein/victor/_victor_utils.py similarity index 79% rename from fragmenstein/victor/_victor_utils_mixin.py rename to fragmenstein/victor/_victor_utils.py index 903df5b..055b249 100644 --- a/fragmenstein/victor/_victor_utils_mixin.py +++ b/fragmenstein/victor/_victor_utils.py @@ -26,15 +26,14 @@ from rdkit import Chem from rdkit.Chem import rdFMCS, AllChem -from ._victor_base_mixin import _VictorBaseMixin +from ._victor_common import _VictorCommon from ..m_rmsd import mRSMD from ..monster import Monster from rdkit_to_params import Params from ..igor import Igor -from ._loggerwriter import LoggerWriter -class _VictorUtilsMixin(_VictorBaseMixin): +class _VictorUtils(_VictorCommon): def dock(self) -> Chem.Mol: """ @@ -54,7 +53,7 @@ def dock(self) -> Chem.Mol: # print(pyrosetta.get_fa_scorefxn()(docked) - v.energy_score['unbound_ref2015']['total_score']) def summarise(self): - if self.error: + if self.error_msg: if self.monster is None: N_constrained_atoms = float('nan') N_unconstrained_atoms = float('nan') @@ -66,7 +65,7 @@ def summarise(self): N_unconstrained_atoms = self.unconstrained_heavy_atoms return {'name': self.long_name, 'smiles': self.smiles, - 'error': self.error, + 'error': self.error_msg, 'mode': self.monster_merging_mode, '∆∆G': float('nan'), '∆G_bound': float('nan'), @@ -81,8 +80,8 @@ def summarise(self): else: return {'name': self.long_name, 'smiles': self.smiles, - 'error': self.error, - 'mode': self.monster_merging_mode, + 'error': self.error_msg, + 'mode': self.monster.merging_mode, '∆∆G': self.energy_score['ligand_ref2015']['total_score'] - \ self.energy_score['unbound_ref2015']['total_score'], '∆G_bound': self.energy_score['ligand_ref2015']['total_score'], @@ -95,75 +94,7 @@ def summarise(self): 'disregarded': self.monster.unmatched } - # =================== Logging ====================================================================================== - - @classmethod - def enable_stdout(cls, level=logging.INFO) -> None: - """ - The ``cls.journal`` is output to the terminal. - Running it twice can be used to change level. - - :param level: logging level - :return: None - """ - cls.journal.handlers = [h for h in cls.journal.handlers if h.name != 'stdout'] - handler = logging.StreamHandler(sys.stdout) - handler.setLevel(level) - handler.set_name('stdout') - handler.setFormatter(logging.Formatter('[%(asctime)s] %(levelname)s - %(message)s')) - cls.journal.addHandler(handler) - # logging.getLogger('py.warnings').addHandler(handler) - - @classmethod - def enable_logfile(cls, filename='reanimation.log', level=logging.INFO) -> None: - """ - The journal is output to a file. - Running it twice can be used to change level. - :param filename: file to write. - :param level: logging level - :return: None - """ - cls.journal.handlers = [h for h in cls.journal.handlers if h.name != 'logfile'] - handler = logging.FileHandler(filename) - handler.setLevel(level) - handler.set_name('logfile') - handler.setFormatter(logging.Formatter('[%(asctime)s] %(levelname)s - %(message)s')) - cls.journal.addHandler(handler) - # logging.getLogger('py.warnings').addHandler(handler) - - @classmethod - def log_errors(cls): - """ - RDKit spits a few warning and errors. - Pyrosetta sends messages to stdout. I might implement a tracer capturing. - This makes them inline with the logger. - - :return: - """ - Chem.WrapLogs() - sys.stderr = LoggerWriter(cls.journal.warning) - - @classmethod - def slack_me(cls, msg: str) -> bool: - """ - Send message to a slack webhook - - :param msg: Can be dirty and unicode-y. - :return: did it work? - :rtype: bool - """ - webhook = os.environ['SLACK_WEBHOOK'] - # sanitise. - msg = unicodedata.normalize('NFKD', msg).encode('ascii', 'ignore').decode('ascii') - msg = re.sub('[^\w\s\-.,;?!@#()\[\]]', '', msg) - r = requests.post(url=webhook, - headers={'Content-type': 'application/json'}, - data=f"{{'text': '{msg}'}}") - if r.status_code == 200 and r.content == b'ok': - return True - else: - return False # =================== Other ======================================================================================== @@ -286,64 +217,17 @@ def make_covalent(cls, smiles: str, else: return None - @classmethod - def get_warhead_definition(cls, warhead_name: str): - return cls._get_warhead_definitions(warhead_name)[0] - - @classmethod - def _get_warhead_definitions(cls, warhead_name: str): - """ - It is unlikely that alternative definitions are present. hence why hidden method. - - :param warhead_name: - :return: - """ - options = [wd for wd in cls.warhead_definitions if wd['name'] == warhead_name.lower()] - if len(options) == 0: - raise ValueError(f'{warhead_name} is not valid.') - else: - return options - - @classmethod - def make_all_warhead_combinations(cls, smiles: str, warhead_name: str, canonical=True) -> Union[dict, None]: - """ - Convert a unreacted warhead to a reacted one in the SMILES - - :param smiles: unreacted SMILES - :param warhead_name: name in the definitions - :param canonical: the SMILES canonical? (makes sense...) - :return: dictionary of SMILES - """ - mol = Chem.MolFromSmiles(smiles) - war_def = cls.get_warhead_definition(warhead_name) - ncv = Chem.MolFromSmiles(war_def['noncovalent']) - if mol.HasSubstructMatch(ncv): - combinations = {} - for wd in cls.warhead_definitions: - x = Chem.ReplaceSubstructs(mol, ncv, Chem.MolFromSmiles(wd['covalent']), - replacementConnectionPoint=0) - combinations[wd['name'] + '_covalent'] = Chem.MolToSmiles(x[0], canonical=canonical) - x = Chem.ReplaceSubstructs(mol, ncv, Chem.MolFromSmiles(wd['noncovalent']), - replacementConnectionPoint=0) - combinations[wd['name'] + '_noncovalent'] = Chem.MolToSmiles(x[0], canonical=canonical) - return combinations - else: - return None - - # =================== pre-encounter ================================================================================ - - # @classmethod - # =================== save ======================================================================================== - def make_pse(self, filename: str = 'combo.pse', extra_mols:Optional[Chem.Mol]=None): + def make_pse(self, filename: str = 'combo.pse', + extra_mols:Optional[Chem.Mol]=None): """ Save a pse in the relevant folder. This is the Victor one. - - :param filename: - :return: """ assert '.pse' in filename, f'{filename} not .pse file' + if extra_mols is None: + extra_mols = [] + # ------------------------ import pymol2 with pymol2.PyMOL() as pymol: for hit in self.hits: @@ -372,11 +256,10 @@ def make_pse(self, filename: str = 'combo.pse', extra_mols:Optional[Chem.Mol]=No pymol.cmd.color('gray20', f'element C and unmin_protein') pymol.cmd.hide('sticks', 'unmin_protein') pymol.cmd.disable('unmin_protein') - if extra_mols: - for mol in extra_mols: - name = mol.GetProp('_Name') - pymol.cmd.read_molstr(Chem.MolToMolBlock(mol, kekulize=False), name) - pymol.cmd.color('magenta', f'{name} and name C*') + for mol in extra_mols: + name = mol.GetProp('_Name') + pymol.cmd.read_molstr(Chem.MolToMolBlock(mol, kekulize=False), name) + pymol.cmd.color('magenta', f'{name} and name C*') pymol.cmd.save(os.path.join(self.work_path, self.long_name, filename)) def make_steps_pse(self, filename: str='step.pse'): @@ -416,8 +299,9 @@ def find_attachment(cls, pdb: Chem.Mol, ligand_resn: str) -> Tuple[Union[Chem.At def find_closest_to_ligand(cls, pdb: Chem.Mol, ligand_resn: str) -> Tuple[Chem.Atom, Chem.Atom]: """ Find the closest atom to the ligand + Warning requires the protein to be loaded as an rdkit.Chem.Mol - :param pdb: a rdkit Chem object + :param pdb: a rdkit Chem.Mol object :param ligand_resn: 3 letter code :return: tuple of non-ligand atom and ligand atom """ @@ -555,16 +439,10 @@ def extract_mol(cls, return mol - - - - - - # =================== From Files =================================================================================== @classmethod - def from_files(cls, folder: str) -> _VictorBaseMixin: + def from_files(cls, folder: str) -> 'self': """ This creates an instance form the output files. Likely to be unstable. Assumes the checkpoints were not altered. @@ -609,12 +487,11 @@ def from_files(cls, folder: str) -> _VictorBaseMixin: fd = json.load(open(fragjson)) self.smiles = fd['smiles'] self.is_covalent = True if '*' in self.smiles else False - self.monster = Monster(mol=self.mol, - hits=self.hits, - attachment=None, - merging_mode='off', - average_position=self.monster_average_position - ) + self.monster = Monster(hits=self.hits, + average_position=self.monster_average_position) + self.monster.place(mol=self.mol, + attachment=None, + merging_mode='off') self.monster.positioned_mol = self.mol self.monster.positioned_mol.SetProp('_Origins', json.dumps(fd['origin'])) diff --git a/fragmenstein/victor/_victor_validate_mixin.py b/fragmenstein/victor/_victor_validate.py similarity index 91% rename from fragmenstein/victor/_victor_validate_mixin.py rename to fragmenstein/victor/_victor_validate.py index a4804c9..91c0168 100644 --- a/fragmenstein/victor/_victor_validate_mixin.py +++ b/fragmenstein/victor/_victor_validate.py @@ -1,4 +1,4 @@ -from ._victor_base_mixin import _VictorBaseMixin +from ._victor_base import _VictorBase from ..monster import Monster from ..igor import Igor from ..m_rmsd import mRSMD @@ -9,7 +9,7 @@ from rdkit_to_params import Params, Constraints import time, warnings, os -class _VictorValidateMixin(_VictorBaseMixin): +class _VictorValidate(_VictorBase): def validate(self, reference_mol: Chem.Mol): """ From 60dde3b7d90c3f0804947cfd2956ad593c58f402 Mon Sep 17 00:00:00 2001 From: matteoferla Date: Sat, 13 Feb 2021 14:36:54 +0000 Subject: [PATCH 32/32] :fire: cleaned up documentation --- README.md | 114 ++- documentation/pipeline.md | 9 +- documentation/sphinx-docs.md | 667 +----------------- .../fragmenstein.igor.md | 48 ++ .../fragmenstein.laboratory.md | 9 + .../sphinx_autodocumentation/fragmenstein.md | 319 +++++++++ .../fragmenstein.monster.md | 479 +++++++++++++ .../fragmenstein.mpro.md | 121 ++++ .../fragmenstein.victor.md | 158 +++++ documentation/wip.md | 17 +- fragmenstein/igor/__init__.py | 2 +- .../{_igor_utils_mixin.py => _igor_utils.py} | 0 fragmenstein/laboratory/_process.py | 2 +- fragmenstein/m_rmsd.py | 78 +- fragmenstein/monster/unmerge_mapper.py | 1 + fragmenstein/mpro/__init__.py | 130 ++-- fragmenstein/victor/__init__.py | 118 +++- fragmenstein/victor/_victor_base.py | 16 +- fragmenstein/victor/_victor_combine.py | 55 +- fragmenstein/victor/_victor_common.py | 8 + fragmenstein/victor/_victor_igor.py | 9 +- fragmenstein/victor/_victor_place.py | 20 +- fragmenstein/victor/_victor_utils.py | 2 - fragmenstein/victor/_victor_validate.py | 11 +- test.py | 130 ++-- 25 files changed, 1586 insertions(+), 937 deletions(-) create mode 100644 documentation/sphinx_autodocumentation/fragmenstein.igor.md create mode 100644 documentation/sphinx_autodocumentation/fragmenstein.laboratory.md create mode 100644 documentation/sphinx_autodocumentation/fragmenstein.md create mode 100644 documentation/sphinx_autodocumentation/fragmenstein.monster.md create mode 100644 documentation/sphinx_autodocumentation/fragmenstein.mpro.md create mode 100644 documentation/sphinx_autodocumentation/fragmenstein.victor.md rename fragmenstein/igor/{_igor_utils_mixin.py => _igor_utils.py} (100%) diff --git a/README.md b/README.md index 601d41e..71eb367 100644 --- a/README.md +++ b/README.md @@ -7,12 +7,64 @@ Scaffold hopping between bound compounds by stitching them together like a reani Fragmenstein can perform two different tasks. -* **Merge** hits +* **Combine** hits * **Place** a given followup molecule (SMILES) based on series of hits Like Frankenstein's creation it may violate the laws of chemistry. Planar trigonal topologies may be tetrahedral, bonds unnaturally long _etc._ -This monstrosity is therefore then energy minimised with strong constraints. +This monstrosity is therefore then energy minimised with strong constraints within the protein. + +## Classes + +There are three main classes, named after characters from the Fragmenstein book and movies: + +* ``Monster`` makes the stitched together molecules indepent of the protein — [documentation](documentation/monster/monster.md) +* ``Igor`` uses PyRosetta to minimise in the protein the fragmenstein followup — [documentation](documentation/igor.md) +* ``Victor`` is a pipeline that calls the parts, with several features, such as warhead switching —[documentation](documentation/victor.md) + +NB. In the absence of `pyrosetta` (which requires an academic licence), all bar ``Igor`` work. + +Additionally, there are a few minor classes. + +One of these is ``mRMSD``, a multiple RMSD variant which does not align and bases which atoms +to use on coordinates —[documentation](documentation/mrmsd.md) + +There are two module hosted elsewhere: + +* ``Rectifier`` from [molecular_rectifier](https://github.com/matteoferla/molecular_rectifier) is a class that corrects mistakes in the molecule automatically merged by ``Monster``. +* ``Params`` from [rdkit to params module](https://github.com/matteoferla/rdkit_to_params) parameterises the ligands + +### Combine +It can also merge and link fragment hits by itself and find the best scoring mergers. +For details about linking see [linking notes](documentation/linking.md) +It uses the same overlapping position clustering, but also has a decent amount of impossible/uncommon chemistry prevention. + +Monster: + + from fragmenstein import Monster + monster = Monster(hits=[hits_a, hit_b]) + monster.combine() + monster.positioned_mol # RDKit.Chem.Mol + +Victor: + + from fragmenstein import Monster + victor = Victor(hits=[hits_a, hit_b], + pdb_filename='foo.pdb', + covalent_resi=1) # if not covalent, just put the first residue or something. + victor.combine() + victor.minimised_mol + +The two seem similar, but Victor places with Monster and minimises with Igor. +As a result it has energy scores + + victor.ddG + +Fragmenstein is not really a docking algorithm as it does not find the pose with the **lowest energy** +within a given volume. +Consequently, it is a method to find how **faithful** is a given followup to the hits provided. +Hence the minimised pose should be assessed by the RMSD metric or similar +and the ∆∆G score used solely as a cutoff —lower than zero. ## Place Here is [an interactive example of placed molecules](https://michelanglo.sgc.ox.ac.uk/r/fragmenstein). @@ -27,37 +79,43 @@ For example, note here that the benzene and the pyridine rings overlap, not the -### Merge -It can also merge fragment hits by itself and find the best scoring mergers. -It uses the same overlapping position clustering, but also has a decent amount of impossible/uncommon chemistry prevention. - -## Not-docking -As a consequence, it is not really a docking algorithm as it does not find the pose with the lowest energy -within a given volume. Consequently, it is a method to find how faithful is a given followup to the hits provided. -Hence the minimised pose should be assessed by the RMSD metric and the ∆∆G score used solely as a cutoff —lower than zero. +### Examples -## Installation +Monster: + + from fragmenstein import Monster + monster = Monster(hits=[hits_a, hit_b]) + monster.place_smiles('CCO') + monster.positioned_mol + +Victor: -## Dramatis personae + from fragmenstein import Monster + victor = Victor(hits=[hits_a, hit_b], pdb_filename='foo.pdb') + victor.place('CCO') + victor.minimised_mol -> Victor, the pipeline, requires my [rdkit to params module](https://github.com/matteoferla/rdkit_to_params). +## Other features -There are three main classes, named after characters from the Fragmenstein book and movies: +* [Covalent hits](documentation/covalents.md) +* [Logging](documentation/logging_and_debugging.md) -* ``Monster`` makes the stitched together molecules — [documentation](documentation/monster/monster.md) -* ``Igor`` uses PyRosetta to minimise in the protein the fragmenstein followup — [documentation](documentation/igor.md) -* ``Victor`` is a pipeline that calls the parts, with several features, such as warhead switching —[documentation](documentation/victor.md) +## Installation -An honourable mention goes to: +Requires RDKit -* ``mRMSD`` is a multiple RMSD variant which does not align and bases which atoms to use on coordinates —[documentation](documentation/mrmsd.md) -* ``Rectifier`` is a class that corrects mistakes in the molecule automatically merged by ``Fragmenstein``. + sudo apt-get install python3-rdkit librdkit1 rdkit-data -In the absence of `pyrosetta` (which requires an academic licence), all bar ``Igor`` work. +Requires Pyrosetta + + curl -u 👾👾👾:👾👾👾https://graylab.jhu.edu/download/PyRosetta4/archive/release/PyRosetta4.Release.python38.linux/PyRosetta4.Release.python38.linux.release-273.tar.bz2 -o a.tar.bz2 + tar -xf a.tar.bz2 + cd PyRosetta4.Release.python38.linux + sudo pip3 install . -## Features +Install from pipy -* [Covalent hits](documentation/covalents.md) + sudo pip3 install fragmenstein ## Origin @@ -69,13 +127,13 @@ fragment based screening. [This dataset](https://github.com/postera-ai/COVID_moonshot_submissions) has some unique peculiarities that potentially are not encountered in other projects. -## Work in progress - -Some changes to the algorithm may happen, see [wip.md](documentation/wip.md) for more or drop me (matteo) an email. +## Autogenerated documentations +For more see the source code or the [Sphinx converted documentation](documentation/sphinx-docs.md). +## Changes -## Autogenerated documentations +Some changes to the algorithm may happen, +see [changelog](documentation/changelog_0.6.md) and [wip.md](documentation/wip.md) for more. -For more see the source code or the [Sphinx converted documentation](documentation/sphinx-docs.md). diff --git a/documentation/pipeline.md b/documentation/pipeline.md index b08db8c..e5d5a6f 100644 --- a/documentation/pipeline.md +++ b/documentation/pipeline.md @@ -1,6 +1,7 @@ Here is an example of a pipeline to iterate across all the compounds in a list, merge them, score then and upload them. For MPro, see the MPro. + ## Prerequisite ### Template @@ -117,10 +118,10 @@ definite the process task return mol frags = [loadmol(file) for file in x] - v = Victor.combine(hits=frags, - pdb_filename='input/template.pdb', - covalent_resi='81A', # a random residue is still required for the constaint ref atom. - covalent_resn='CYS') + v = Victor(pdb_filename='input/template.pdb', + covalent_resi='81A', # a random residue is still required for the constaint ref atom. + covalent_resn='CYS') + v.combine(hits=frags) results = SqliteDict(db_name, encode=json.dumps, decode=json.loads, autocommit=True) results[v.long_name] = v.summarise() if not v.error: diff --git a/documentation/sphinx-docs.md b/documentation/sphinx-docs.md index dffdefa..dca26a7 100644 --- a/documentation/sphinx-docs.md +++ b/documentation/sphinx-docs.md @@ -1,663 +1,6 @@ -# fragmenstein.core package +## Autogenerated documentation -## Module contents - -This is Fragmenstein proper. and contains the class `Fragmenstein`. - - -### class fragmenstein.core.Fragmenstein(mol, hits, attachment=None, debug_draw=False) -Bases: `fragmenstein.core._utility_mixin._FragmensteinUtil` - -Given a RDKit molecule and a series of hits it makes a spatially stitched together version of the initial molecule based on the hits. -The reason is to do place the followup compound to the hits as faithfully as possible regardless of the screaming forcefields. - - -* `.scaffold` is the combined version of the hits (rdkit.Chem.Mol object). - - -* `.chimera` is the combined version of the hits, but with differing atoms made to match the followup (rdkit.Chem.Mol object). - - -* `.positioned_mol` is the desired output (rdkit.Chem.Mol object) - -Note, the hits have to be spatially aligned —i.e. extracted from crystal structures in bond form. - -`.get_positional_mapping`, which works also as a class method, creates a dictionary of mol_A atom index to mol_B atom index -based on distance (cutoff 2Å) and not MCS. - -The code works in two broad steps, first a scaffold is made, which is the combination of the hits (by position). -Then the followup is placed. It is not embedded with constraint embed, which requires the reference molecule to have a valid geometry. -`.scaffold` and `.chimera` and `.positioned_mol` absolutely do not have this. -Novel side chains are added by aligning an optimised conformer against the closest 3-4 reference atoms. -Note that `.initial_mol` is not touched. `.positioned_mol` may have lost some custom properties, but the atom idices are the same. - -If an atom in a Chem.Mol object is provided via `attachment` argument and the molecule contains a dummy atom as -defined in the `dummy` class variable. Namely element R in mol file or \* in string is the default. - - -#### \__init__(mol, hits, attachment=None, debug_draw=False) -Initialize self. See help(type(self)) for accurate signature. - - -#### dummy( = ) -The virtual atom where the targets attaches - - -#### dummy_symbol( = '\*') - -#### get_mcs_mapping(molA, molB) -This is a weird method. It does a strict MCS match. -And then it uses laxer searches and finds the case where a lax search includes the strict search. - - -* **Parameters** - - - * **molA** – query molecule - - - * **molB** – target/ref molecule - - - -* **Return type** - - `Tuple`[`Dict`[`int`, `int`], `dict`] - - - -* **Returns** - - mapping and mode - - - -#### classmethod get_positional_mapping(mol_A, mol_B, cutoff=2) -Returns a map to convert overlapping atom of A onto B -Cutoff 2 Å. - - -* **Parameters** - - - * **mol_A** (`Mol`) – first molecule (Chem.Mol) will form keys - - - * **mol_B** (`Mol`) – second molecule (Chem.Mol) will form values - - - -* **Return type** - - `Dict`[`int`, `int`] - - - -* **Returns** - - dictionary mol A atom idx -> mol B atom idx. - - - -#### make_chimera() -This is to avoid extreme corner corner cases. E.g. here the MCS is ringMatchesRingOnly=True and AtomCompare.CompareAny, -while for the positioning this is not the case. - - -* **Return type** - - `Mol` - - - -* **Returns** - - - - -#### merge(scaffold, fragmentanda, anchor_index, attachment_details) - -* **Return type** - - `Mol` - - - -#### simply_merge_hits() -Recursively stick the hits together and average the positions. - - -* **Return type** - - `Mol` - - - -* **Returns** - - the rdkit.Chem.Mol object that will fill `.scaffold` - - - -#### place_from_map(mol=None) - -* **Return type** - - `Mol` - - - -#### posthoc_refine(scaffold) -Averages the overlapping atoms. - - -* **Parameters** - - **scaffold** – - - - -* **Returns** - - - - -#### pretweak() -What if the fragments were prealigned slightly? Really bad things. - - -* **Return type** - - `None` - - - -* **Returns** - -# fragmenstein.igor package - -## Module contents - -Igor energy minises the blended compound using pyrosetta. - - -### class fragmenstein.igor.Igor(pose, constraint_file, ligand_residue='LIG', key_residues=None) -Bases: `fragmenstein.igor._igor_init_mixin._IgorInitMixin`, `fragmenstein.igor._igor_min_mixin._IgorMinMixin`, `fragmenstein.igor._igor_utils_mixin._IgorUtilsMixin` - -Regular Igor(..) accepts pyrosetta pose. -`Igor.from_pdbblock(..)` accepts pdb block as str, -while `Igorfrom_pdbfile(..)` accepts filename as str. - -`ligand` can be one of many things. default is ‘LIG’. But it can be - - -* pose index (123) - - -* PDB index ‘123A’ - - -* a tuple of (PDB resi, PDB chain) - - -* a residue name in uppercase “LIG” - - -* a pyrosetta.Vector1 where 1 == the ligand. - -If key_residues is None, only the connecting residue is added (if present in the LINK record). -This is overridden if one of many options are given. -If it is a pyrosetta.Vector1 it is assumed that 1 mean select this residue (as a result of a `selector.apply(pose)` operation) -If it is a list or tuple, the elements are interpreted similarly to ligand. - - -#### residues_in_selector(pose, selector) -This method is just for checking purposes for humans basically. - - -* **Return type** - - `List`[`str`] - - - -#### residues_in_vector(pose, vector) -This method is just for checking purposes for humans basically. - - -* **Return type** - - `List`[`str`] - -# fragmenstein.victor package - -## Module contents - -Victor (after Dr Victor Frankenstein) is a class that uses both Fragmenstein (makes blended compounds) and Igor (energy minimises). -This master reanimator keeps a `.journal` (logging, class attribute). -And can be called via the class method `.laboratory` where he can process multiple compounds at once. - - -### class fragmenstein.victor.Victor(smiles, hits, pdb_filename, long_name='ligand', ligand_resn='LIG', ligand_resi='1B', covalent_resn='CYS', covalent_resi=None, extra_constraint=None, pose_fx=None) -Bases: `object` - - -* `smiles` SMILES string (inputted) - - -* `long_name` name for files - - -* `ligand_resn` the residue name for the ligand. - - -* `ligand_resi` the residue index (PDB) for the ligand. - - -* `covalent_resi` the residue index (PDB) for the covalent attachment - - -* `covalent_resn` the residue name for the covalent attachment. For now can only be ‘CYS’ - - -* `params` Params instance - - -* `constraint` Constraint or None depending on if covalent. - - -* `mol` the molecule - - -* `covalent_definitions` class attr. that stores for each possible attachment residue (CYS) defs for constraints. - - -* `warhead_definitions` class attr. that stores warheader info - - -* `journal` class attr. logging - - -* `work_path` class attr. where to save stuff - -`warhead_definitions` and `covalent_definitions` are class attributes that can be modified beforehand to -allow a new attachment. `covalent_definitions` is a list of dictionaries of ‘residue’, ‘smiles’, ‘names’, -which are needed for the constraint file making. Namely smiles is two atoms and the connection and names is the -names of each. Cysteine is `{'residue': 'CYS', 'smiles': '\*SC', 'names': ['CONN3', 'SG', 'CB']}`. -While `warhead_definitions` is a list of ‘name’ (name of warhead for humans), -‘covalent’ (the smiles of the warhead, where the zeroth atom is the one attached to the rest), -‘noncovalent’ (the warhead unreacted), -‘covalent_atomnames’ and ‘noncovalent_atomnames’ (list of atom names). -The need for atomnames is actually not for the code but to allow lazy tweaks and analysis downstream -(say typing in pymol: show sphere, name CX). -Adding a ‘constraint’ to an entry will apply that constraint. - - -#### \__init__(smiles, hits, pdb_filename, long_name='ligand', ligand_resn='LIG', ligand_resi='1B', covalent_resn='CYS', covalent_resi=None, extra_constraint=None, pose_fx=None) - -* **Parameters** - - - * **smiles** (`str`) – smiles of followup, optionally covalent (_e.g._ `\*CC(=O)CCC`) - - - * **hits** (`List`[`Mol`]) – list of rdkit molecules - - - * **pdb_filename** (`str`) – file of apo structure - - - * **long_name** (`str`) – gets used for filenames so will get slugified - - - * **ligand_resn** (`str`) – 3 letter code or your choice - - - * **ligand_resi** (`Union`[`int`, `str`]) – Rosetta-style pose(int) or pdb(str) - - - * **covalent_resn** (`str`) – only CYS accepted. if smiles has no \* it is ignored - - - * **covalent_resi** (`Union`[`int`, `str`, `None`]) – Rosetta-style pose(int) or pdb(str) - - - * **extra_constraint** (`Optional`[`str`]) – multiline string of constraints.. - - - * **pose_fx** (`Optional`[`Callable`]) – a function to call with pose to tweak or change something before minimising. - - - -#### classmethod add_constraint_to_warhead(name, constraint) -Add a constraint (multiline is fine) to a warhead definition. -This will be added and run by Igor’s minimiser. - - -* **Parameters** - - - * **name** (`str`) – - - - * **constraint** (`str`) – - - - -* **Returns** - - None - - - -#### classmethod closest_hit(pdb_filenames, target_resi, target_chain, target_atomname, ligand_resn='LIG') -This classmethod helps choose which pdb based on which is closer to a given atom. - - -* **Parameters** - - - * **pdb_filenames** (`List`[`str`]) – - - - * **target_resi** (`int`) – - - - * **target_chain** (`str`) – - - - * **target_atomname** (`str`) – - - - * **ligand_resn** – - - - -* **Return type** - - `str` - - - -* **Returns** - - - - -#### classmethod copy_names(acceptor_mol, donor_mol) - -#### covalent_definitions( = [{'residue': 'CYS', 'smiles': '\*SC', 'atomnames': ['CONN3', 'SG', 'CB']}]) - -#### classmethod enable_logfile(filename='reanimation.log', level=20) -The journal is output to a file. - - -* **Parameters** - - - * **filename** – file to write. - - - * **level** – logging level - - - -* **Return type** - - `None` - - - -* **Returns** - - None - - - -#### classmethod enable_stdout(level=20) -The `cls.journal` is output to the terminal. - - -* **Parameters** - - **level** – logging level - - - -* **Return type** - - `None` - - - -* **Returns** - - None - - - -#### hits_path( = 'hits') - -#### journal( = ) - -#### classmethod laboratory(entries, cores=1) - -#### classmethod make_all_warhead_combinations(smiles, warhead_name) -Convert a unreacted warhead to a reacted one in the SMILES - - -* **Parameters** - - - * **smiles** (`str`) – unreacted SMILES - - - * **warhead_name** (`str`) – name in the definitions - - - -* **Return type** - - `Optional`[`str`] - - - -* **Returns** - - SMILES - - - -#### classmethod make_covalent(smiles, warhead_name=None) -Convert a unreacted warhead to a reacted one in the SMILES - - -* **Parameters** - - - * **smiles** (`str`) – unreacted SMILES - - - * **warhead_name** (`Optional`[`str`]) – name in the definitions. If unspecified it will try and guess (less preferrable) - - - -* **Return type** - - `Optional`[`str`] - - - -* **Returns** - - SMILES - - - -#### pose_mod_step() -This method is intended for make inherited mods easier. -:return: - - -#### post_igor_step() -This method is intended for make inherited mods easier. -:return: - - -#### post_fragmenstein_step() -This method is intended for make inherited mods easier. -:return: - - -#### post_params_step() -This method is intended for make inherited mods easier. -:return: - - -#### classmethod slack_me(msg) -Send message to a slack webhook - - -* **Parameters** - - **msg** (`str`) – Can be dirty and unicode-y. - - - -* **Returns** - - did it work? - - - -* **Return type** - - bool - - - -#### slugify(name) - -#### warhead_definitions( = [{'name': 'nitrile', 'covalent': 'C(=N)\*', 'covalent_atomnames': ['CX', 'NX', 'CONN1'], 'noncovalent': 'C(#N)', 'noncovalent_atomnames': ['CX', 'NX']}, {'name': 'acrylamide', 'covalent': 'C(=O)CC\*', 'covalent_atomnames': ['CZ', 'OZ', 'CY', 'CX', 'CONN1'], 'noncovalent': 'C(=O)C=C', 'noncovalent_atomnames': ['CZ', 'OZ', 'CY', 'CX']}, {'name': 'chloroacetamide', 'covalent': 'C(=O)C\*', 'covalent_atomnames': ['CY', 'OY', 'CX', 'CONN1'], 'noncovalent': 'C(=O)C[Cl]', 'noncovalent_atomnames': ['CY', 'OY', 'CX', 'CLX']}, {'name': 'vinylsulfonamide', 'covalent': 'S(=O)(=O)CC\*', 'covalent_atomnames': ['SZ', 'OZ1', 'OZ2', 'CY', 'CX', 'CONN1'], 'noncovalent': 'S(=O)(=O)C=C', 'noncovalent_atomnames': ['SZ', 'OZ1', 'OZ2', 'CY', 'CX']}]) - -#### work_path( = 'output') - -## fragmenstein.m_rmsd module - - -### class fragmenstein.m_rmsd.mRSMD(followup, hits, mappings) -Bases: `object` - -RMSD are unaligned and in Å. - -> The RMSD has been calculated differently. -> The inbuilt RMSD calculations in RDKit (`Chem.rdMolAlign.GetBestRMS`) align the two molecules, -> this does not align them. -> This deals with the case of multiple hits. -> As a comparision, For euclidean distance the square root of the sum of the differences in each coordinates is taken. -> As a comparision, For a regular RMSD the still-squared distance is averaged before taking the root. -> Here the average is done across all the atom pairs between each hit and the followup. -> Therefore, atoms in followup that derive in the blended molecule by multiple atom are scored multiple times. - -> $sqrt{ - -rac{sum_{i}^{N_{ -m{hits}}} (sum_{i}^{n} (q_{i, -m{x}} - h_{i, -m{x}})^2 + (q_{i, -m{y}} - h_{i, -m{y}})^2 + (q_{i, -m{z}} - h_{i, -m{z}})^2 }{ncdot m}}$ - - -#### \__init__(followup, hits, mappings) -This is not meant to be called directly. -mappings is a list of len(hits) containing lists of tuples of atom idx that go from followup to hit - -The hit _Name must match that in origin! -currected output of fragmenstein.origin_from_mol() or cls.get_origins(to-be-scored-mol, annotated) - - -* **Parameters** - - - * **followup** (`Mol`) – the followup compounds - - - * **hits** (`Sequence`[`Mol`]) – the fragment hits - - - * **mappings** (`List`[`List`[`Tuple`[`int`, `int`]]]) – a complicated affair… - - - -#### calculate_msd(molA, molB, mapping) -A nonroot rmsd. - - -* **Parameters** - - - * **molA** – - - - * **molB** – - - - * **mapping** – lists of tuples of atom idx that go from molA to molB - - - -* **Returns** - - nonroot rmsd - - - -#### calculate_rmsd(molA, molB, mapping) - -#### classmethod copy_origins(annotated, target) -Fragmenstein leaves a note of what it did. atom prop _Origin is a json of a list of mol _Name dot AtomIdx. -However, the atom order seems to be maintained but I dont trust it. Also dummy atoms are stripped. - - -* **Parameters** - - - * **annotated** (`Mol`) – - - - * **target** (`Mol`) – - - - -* **Returns** - - a list of origins - - - -#### classmethod from_annotated_mols(annotated_followup, hits) -Fragmenstein leaves a note of what it did. atom prop _Origin is a json of a list of mol _Name dot AtomIdx. -This classmethod accepts a followup with has this. - - -* **Parameters** - - - * **annotated_followup** (`Mol`) – - - - * **hits** (`Sequence`[`Mol`]) – - - - -* **Returns** - - - - -#### classmethod from_other_annotated_mols(followup, hits, annotated) - -#### classmethod from_unannotated_mols(moved_followup, hits, placed_followup) \ No newline at end of file +* [Monster](sphinx_autodocumentation/fragmenstein.monster.md) +* [Igor](sphinx_autodocumentation/fragmenstein.igor.md) +* [Victor](sphinx_autodocumentation/fragmenstein.victor.md) +* [Mpro Victor](sphinx_autodocumentation/fragmenstein.mpro.md) \ No newline at end of file diff --git a/documentation/sphinx_autodocumentation/fragmenstein.igor.md b/documentation/sphinx_autodocumentation/fragmenstein.igor.md new file mode 100644 index 0000000..59afc11 --- /dev/null +++ b/documentation/sphinx_autodocumentation/fragmenstein.igor.md @@ -0,0 +1,48 @@ +# fragmenstein.igor package + +## Module contents + +Igor energy minises the blended compound using pyrosetta. + + +### class fragmenstein.igor.Igor(pose, constraint_file, ligand_residue='LIG', key_residues=None) +Bases: `fragmenstein.igor._igor_init._IgorInit`, `fragmenstein.igor._igor_min._IgorMin`, `fragmenstein.igor._igor_utils._IgorUtils` + +Regular Igor(..) accepts pyrosetta pose. +`Igor.from_pdbblock(..)` accepts pdb block as str, +while `Igorfrom_pdbfile(..)` accepts filename as str. + +`ligand` can be one of many things. default is ‘LIG’. But it can be + + +* pose index (123) +* PDB index ‘123A’ +* a tuple of (PDB resi, PDB chain) +* a residue name in uppercase “LIG” + + +* a pyrosetta.Vector1 where 1 == the ligand. + +If key_residues is None, only the connecting residue is added (if present in the LINK record). +This is overridden if one of many options are given. +If it is a pyrosetta.Vector1 it is assumed that 1 mean select this residue (as a result of a `selector.apply(pose)` operation) +If it is a list or tuple, the elements are interpreted similarly to ligand. + + +#### residues_in_selector(pose, selector) +This method is just for checking purposes for humans basically. + + +* **Return type** + + `List`[`str`] + + + +#### residues_in_vector(pose, vector) +This method is just for checking purposes for humans basically. + + +* **Return type** + + `List`[`str`] diff --git a/documentation/sphinx_autodocumentation/fragmenstein.laboratory.md b/documentation/sphinx_autodocumentation/fragmenstein.laboratory.md new file mode 100644 index 0000000..fe3d90f --- /dev/null +++ b/documentation/sphinx_autodocumentation/fragmenstein.laboratory.md @@ -0,0 +1,9 @@ +# fragmenstein.laboratory package + +## Submodules + +## fragmenstein.laboratory.laboratory module + +## fragmenstein.laboratory.make_pyrosetta_options module + +## Module contents diff --git a/documentation/sphinx_autodocumentation/fragmenstein.md b/documentation/sphinx_autodocumentation/fragmenstein.md new file mode 100644 index 0000000..85a80b5 --- /dev/null +++ b/documentation/sphinx_autodocumentation/fragmenstein.md @@ -0,0 +1,319 @@ +# fragmenstein package + +## Subpackages + + +* fragmenstein.cli package + + + * Module contents + + +* fragmenstein.igor package + + + * Module contents + + +* fragmenstein.laboratory package + + + * Submodules + + + * fragmenstein.laboratory.laboratory module + + + * fragmenstein.laboratory.make_pyrosetta_options module + + + * Module contents + + +* fragmenstein.monster package + + + * Submodules + + + * fragmenstein.monster.bond_provenance module + + + * fragmenstein.monster.positional_mapping module + + + * fragmenstein.monster.unmerge_mapper module + + + * Module contents + + +* fragmenstein.mpro package + + + * Module contents + + +* fragmenstein.victor package + + + * Submodules + + + * fragmenstein.victor.minimalPDB module + + + * Module contents + + +## Submodules + +## fragmenstein.m_rmsd module + +Combined RMSD + + +### class fragmenstein.m_rmsd.mRSMD(followup, hits, mappings) +Bases: `object` + +RMSD are unaligned and in Å. + +> The RMSD has been calculated differently. +> The inbuilt RMSD calculations in RDKit (`Chem.rdMolAlign.GetBestRMS`) align the two molecules, +> this does not align them. +> This deals with the case of multiple hits. +> As a comparision, For euclidean distance the square root of the sum of the differences in each coordinates is taken. +> As a comparision, For a regular RMSD the still-squared distance is averaged before taking the root. +> Here the average is done across all the atom pairs between each hit and the followup. +> Therefore, atoms in followup that derive in the blended molecule by multiple atom are scored multiple times. + +> $sqrt{ + +rac{sum_{i}^{N_{ +m{hits}}} (sum_{i}^{n} (q_{i, +m{x}} - h_{i, +m{x}})^2 + (q_{i, +m{y}} - h_{i, +m{y}})^2 + (q_{i, +m{z}} - h_{i, +m{z}})^2 }{ncdot m}}$ + + +#### \__init__(followup, hits, mappings) +This is not meant to be called directly. +mappings is a list of len(hits) containing lists of tuples of atom idx that go from followup to hit + +The hit _Name must match that in origin! +currected output of monster.origin_from_mol() or cls.get_origins(to-be-scored-mol, annotated) + + +* **Parameters** + + + * **followup** (`Mol`) – the followup compounds + + + * **hits** (`Sequence`[`Mol`]) – the fragment hits + + + * **mappings** (`List`[`List`[`Tuple`[`int`, `int`]]]) – a complicated affair… + + + +#### calculate_msd(molA, molB, mapping) +A nonroot rmsd. + + +* **Parameters** + + + * **molA** – + + + * **molB** – + + + * **mapping** – lists of tuples of atom idx that go from molA to molB + + + +* **Returns** + + nonroot rmsd + + + +#### calculate_rmsd(molA, molB, mapping) + +#### classmethod copy_all_possible_origins(annotated, target) +Monster leaves a note of what it did. atom prop _Origin is a json of a list of mol _Name dot AtomIdx. +However, the atom order seems to be maintained but I dont trust it. Also dummy atoms are stripped. + + +* **Parameters** + + + * **annotated** (`Mol`) – + + + * **target** (`Mol`) – + + + +* **Return type** + + `Tuple`[`List`[`Mol`], `List`[`List`[`int`]]] + + + +* **Returns** + + a list of mols and a list of orgins (a list too) + + + +#### classmethod copy_origins(annotated, target) +Monster leaves a note of what it did. atom prop _Origin is a json of a list of mol _Name dot AtomIdx. +However, the atom order seems to be maintained but I dont trust it. Also dummy atoms are stripped. + + +* **Parameters** + + + * **annotated** (`Mol`) – + + + * **target** (`Mol`) – + + + +* **Returns** + + a list of origins + + + +#### classmethod from_annotated_mols(annotated_followup, hits=None) +Monster leaves a note of what it did. atom prop _Origin is a json of a list of mol _Name dot AtomIdx. +This classmethod accepts a followup with has this. + + +* **Parameters** + + + * **annotated_followup** (`Mol`) – + + + * **hits** (`Optional`[`Sequence`[`Mol`]]) – + + + +* **Return type** + + `mRSMD` + + + +* **Returns** + + + + +#### classmethod from_internal_xyz(annotated_followup) +This is an alternative for when the atoms have _x, _y, _z + + +* **Parameters** + + **annotated_followup** – + + + +* **Returns** + + + + +#### classmethod from_other_annotated_mols(followup, hits, annotated) + +* **Return type** + + `mRSMD` + + + +#### classmethod from_unannotated_mols(moved_followup, hits, placed_followup) +Mapping is done by positional overlap between placed_followup and hits +This mapping is the applied to moved_followup. + + +* **Parameters** + + + * **moved_followup** (`Mol`) – The mol to be scored + + + * **hits** (`Sequence`[`Mol`]) – the hits to score against + + + * **placed_followup** (`Mol`) – the mol to determine how to score + + + +* **Return type** + + `mRSMD` + + + +* **Returns** + + + + +#### classmethod is_origin_annotated(mol) + +* **Return type** + + `bool` + + + +#### classmethod is_xyz_annotated(mol) + +* **Return type** + + `bool` + + + +#### classmethod migrate_origin(mol, tag='_Origin') +The origin list may be saved as a molecule property rather than an atom -saved as a mol say. + + +* **Parameters** + + + * **mol** (`Mol`) – mol to fix + + + * **tag** – name of prop + + + +* **Return type** + + `Mol` + + + +* **Returns** + + the same mol + + + +#### classmethod mock() +## Module contents + +See GitHub documentation diff --git a/documentation/sphinx_autodocumentation/fragmenstein.monster.md b/documentation/sphinx_autodocumentation/fragmenstein.monster.md new file mode 100644 index 0000000..7182352 --- /dev/null +++ b/documentation/sphinx_autodocumentation/fragmenstein.monster.md @@ -0,0 +1,479 @@ +# fragmenstein.monster package + +## Submodules + +## fragmenstein.monster.bond_provenance module + + +### class fragmenstein.monster.bond_provenance.BondProvenance() +Bases: `enum.Enum` + +Where does the bond come from. This is used to keep names consistent… +For now original is used in places. The others are interchangeable TBH. + +* ORIGINAL( = 1) +* MAIN_NOVEL( = 2) +* OTHER_NOVEL( = 3) +* LINKER( = 4) +* UNASSIGNED( = 5) + +#### classmethod copy_bond(donor, acceptor) + +* **Return type** + + `None` + + + +#### classmethod get_bond(bond) + +* **Return type** + + `BondProvenance` + + + +#### classmethod get_bonds(bonds) + +* **Return type** + + `List`[`BondProvenance`] + + + +#### classmethod has_bond(bond) + +* **Return type** + + `bool` + + + +#### classmethod set_all_bonds(mol, provenance_name) +Sets the provenance of all bonds in mol to a category, which is a string from the provenance + + +* **Parameters** + + * **mol** (`Mol`) – + * **provenance_name** (`str`) – A string original | main_novel ” other_novel | linker + + + +* **Return type** + + `None` + + + +* **Returns** + + + + +#### classmethod set_bond(bond, provenance_name) + +* **Return type** + + `None` + + + +#### classmethod set_bonds(bonds, provenance_name) + +* **Return type** + + `None` + + +## fragmenstein.monster.positional_mapping module + +Positional mapping + + +### class fragmenstein.monster.positional_mapping.GPM() +Bases: `object` + +This class simply contains `get_positional_mapping` and is inherited both by Monster and Unmerge. +`get_positional_mapping` teturns a map to convert overlapping atom of A onto B + + +#### cutoff( = 2) + +#### classmethod get_positional_mapping(mol_A, mol_B, dummy_w_dummy=True) +Returns a map to convert overlapping atom of A onto B +Cutoff 2 Å (see class attr.) + + +**Parameters** + +* **mol_A** (`Mol`) – first molecule (Chem.Mol) will form keys +* **mol_B** (`Mol`) – second molecule (Chem.Mol) will form values +* **dummy_w_dummy** – match + + + +* **Return type** + + `Dict`[`int`, `int`] + + + +* **Returns** + + dictionary mol A atom idx -> mol B atom idx. + + +## fragmenstein.monster.unmerge_mapper module + +Unmerge mapper (not inherited) + + +### class fragmenstein.monster.unmerge_mapper.Unmerge(followup, mols, maps, no_discard=False) +Bases: `fragmenstein.monster.positional_mapping.GPM` + +This class tries to solve the mapping problem by try all possible mappings of the target to the ligand. +It is one of three in Monster (full merge, partial merge, unmerge. + +It is great with fragments that do not connect, but is bad when a hit has a typo. + + +* the positions must overlap if any atom is mapped in two maps + + +* no bond can be over 3 A + +The chosen map `combined_map` is a dict that goes from `followup` mol to `combined` mol which +is the hits in a single molecule. + +Note that some molecules are discarded entirely. + + +#### \__init__(followup, mols, maps, no_discard=False) + +**Parameters** + + +* **followup** (*Chem.Mol*) – the molecule to place +* **mols** (*List**[**Chem.Mol**]*) – 3D molecules +* **maps** (*Dict**[**List**[**Dict**[**int**, **int**]**]**]*) – can be generated outseide of Monster by `.make_maps`. +* **no_discard** (`bool`) – do not allow any to be discarded + +#### bond(idx=None) + +#### check_possible_distances(other, possible_map, combined, combined_map, cutoff=3) + +#### distance_cutoff( = 3) +how distance is too distant in Å + + +#### get_inter_distance(molA, molB, idxA, idxB) + +* **Return type** + + `float` + + + +#### get_key(d, v) +Given a value and a dict and a value get the key. +:type d: `dict` +:param d: +:type v: `Any` +:param v: +:return: + + +#### get_possible_map(other, label, o_map, inter_map, combined, combined_map) +This analyses a single map (o_map) and returns a possible map + + +* **Parameters** + + +* **other** (`Mol`) – +* **label** (`str`) – +* **o_map** (`Dict`[`int`, `int`]) – followup -> other +* **inter_map** (`Dict`[`int`, `int`]) – +* **combined** (`Mol`) – +* **combined_map** (`Dict`[`int`, `int`]) – followup -> combined + + +* **Return type** + + `Dict`[`int`, `int`] + + + +* **Returns** + + followup -> other + + + +#### judge_n_move_on(combined, combined_map, other, possible_map, others, disregarded) +The mutables need to be within their own scope + + +* **Parameters** + + +* **combined** – +* **combined_map** – +* **other** – +* **possible_map** – +* **others** – +* **disregarded** – + + + +* **Returns** + + + + +#### classmethod make_maps(target, mols, mode=None) +This is basically if someone is using this class outside of Monster + +Returns a dictionary of key mol name and +value a list of possible dictionary with idex of target to the index given mol. +Note that a bunch of mapping modes can be found in Monster init mixin class. + + +* **Parameters** + + +* **target** (`Mol`) – the molecule to be mapped +* **mols** (`List`[`Mol`]) – the list of molecules with positional data to be mapped to +* **mode** (`Optional`[`Dict`[`str`, `Any`]]) – dict of setting for MCS step + + + +* **Return type** + + `Dict`[`str`, `List`[`Dict`[`int`, `int`]]] + + + +* **Returns** + + + + +#### max_strikes( = 3) +number of discrepancies tollerated. + + +#### measure_map(mol, mapping) + +* **Parameters** + + +* **mol** (`Mol`) – +* **mapping** (`Dict`[`int`, `int`]) – followup to comined + + + +* **Return type** + + `array` + + + +* **Returns** + + + + +#### offness(mol, mapping) +How many bonds are too long? +:type mol: `Mol` +:param mol: +:type mapping: `Dict`[`int`, `int`] +:param mapping: +:rtype: `float` +:return: + + +#### pick( = 0) + +#### rotational_approach( = True) + +#### store(combined, combined_map, disregarded) + +#### template_sorter_factory(accounted_for) +returns the number of atoms that have not already been accounted for. + + +* **Return type** + + `Callable` + + + +#### unmerge_inner(combined, combined_map, others, disregarded) +Assesses a combination of maps +rejections: unmapped (nothing maps) / unnovel (adds nothing) + + +* **Parameters** + + +* **combined** (`Mol`) – +* **combined_map** (`Dict`[`int`, `int`]) – +* **others** (`List`[`Mol`]) – +* **disregarded** (`List`[`Mol`]) – + + + +* **Return type** + + `None` + + + +* **Returns** + + + +## Module contents + +This is Monster proper. and contains the class `Monster`. +The inheritance is as follows: + +**_MonsterCombine** inherits: + + +* `_MonsterMerge` (`_MonsterCommunal` <- `_MonsterTracker` <- `_MonsterBase`) +* `_MonsterRing` + +**_MonsterPlace** inherits: + + +* `_MonsterMerge` (`_MonsterBlend` < - `_MonsterCommunal` <- `_MonsterTracker` <- `_MonsterBase`) + +**_MonsterUtils** inherits + + +* `_MonsterCommunal` ( <- `_MonsterTracker` <- `_MonsterBase`) +* `GPM` + +Where: + +**_MonsterBase** adds the cvars and the `__init__` and its dependent methods + +**_MonsterTracker** inherits `_MonsterBase` and adds just a method to better store modifications + +**_MonsterCommunal** inherits `_MonsterTracker` ( <- `_MonsterBase`) + +It adds methods for misc purposes beyond place/combine. +It is inherited by `Monster` only. + + +### class fragmenstein.monster.Monster(hits, average_position=False) +Bases: `fragmenstein.monster._utility._MonsterUtil`, `fragmenstein.monster._place._MonsterPlace`, `fragmenstein.monster._combine._MonsterCombine` + +This creates a stitched together monster. +For initilialisation for either placing or combining, it needs a list of hits (rdkit.Chem.Mol). + +Note, the hits have to be 3D embedded as present in the protein —it would defeat the point otherwise! +For a helper method to extract them from crystal structures see Victor.extract_mol. + +The calculation are done either by place or merge. + +## Place + + monster.place(mol) + +Given a RDKit molecule and a series of hits it makes a spatially stitched together version +of the initial molecule based on the hits. +The reason is to do place the followup compound to the hits as faithfully as possible +regardless of the screaming forcefields. + + +* `.mol_options` are the possible equiprobable alternatives. +* `.positioned_mol` is the desired output (rdkit.Chem.Mol object) +* `.initial_mol` is the input (rdkit.Chem.Mol object), this is None in a .combine call. +* `.modifications['scaffold']` is the combined version of the hits (rdkit.Chem.Mol object). +* `.modifications['chimera']` is the combined version of the hits, but with differing atoms made to match the followup (rdkit.Chem.Mol object). + +`.get_positional_mapping`, which works also as a class method, +creates a dictionary of mol_A atom index to mol_B atom index +based on distance (cutoff 2Å) and not MCS. + +The code works in two broad steps, first a scaffold is made, which is the combination of the hits (by position). +Then the followup is placed. It is not embedded with constrained embedding functionality of RDKit as this +requires the reference molecule to have a valid geometry, which these absolutely do not have this. +Novel side chains are added by aligning an optimised conformer against the closest 3-4 reference atoms. +Note that `.initial_mol` is not touched. `.positioned_mol` may have lost some custom properties, +but the atom indices are the same. + +If an atom in a Chem.Mol object is provided via `attachment` argument and the molecule contains a dummy atom. +Namely element R in mol file or \* in string. + +## Combine + + monster.combine(keep_all=True, collapse_rings=True, joining_cutoff= 5)) + +Combines the hits by merging and linking. `collapse_rings` argument results in rings being collapsed +before merging to avoid oddities. +The last step within the call is fixing any oddities of impossible chemistry via the call `rectify`. +This uses the separate class `Rectifier` to fix it. + +## Attributes + +Common input derived + + +* **Variables** + + + * **hits** (*list*) – + * **throw_on_discard** (*bool*) – filled by keep_all + + +Common derived + +**Variables** + + +* **matched** (*List**[**str**]*) – (dynamic) accepted hit names +* **unmatched** (*List**[**str**]*) – discarded hit names +* **journal** (*Logger*) – The “journal” is the log of Dr Victor Frankenstein (see Victor for more) +* **modifications** (*dict*) – copies of the mols along the way +* **mol_options** (*list*) – equally valid alternatives to self.positioned_mol + +`place` specific: + + +* **Variables** + + +* **positioned_mol** (*Mol*) – +* **attachment** (*NoneType*) – +* **initial_mol** (*NoneType*) – +* **average_position** (*bool*) – +* **num_common** (*int*) – (dynamic) number of atoms in common between follow-up and hits +* **percent_common** (*float*) – (dynamic) percentage of atoms of follow-up that are present in the hits + + +`combine` specific: + + +* **Variables** + + +* **joining_cutoff** (*int*) – how distant (in Å) is too much? +* **atoms_in_bridge_cutoff** (*int*) – how many bridge atoms can be deleted? +(0 = preserves norbornane, 1 = preserves adamantane) + + +Class attributes best ignored: + + +* **Variables** + +* **closeness_weights** (*list*) – list of functions to penalise closeness (ignore for most applications) +* **dummy** (*Mol*) – The virtual atom where the targets attaches. by default \*. Best not override. +* **dummy_symbol** (*str*) – The virtual atom where the targets attaches. by default \*. Best not override. +* **matching_modes** (*list*) – \ No newline at end of file diff --git a/documentation/sphinx_autodocumentation/fragmenstein.mpro.md b/documentation/sphinx_autodocumentation/fragmenstein.mpro.md new file mode 100644 index 0000000..8930760 --- /dev/null +++ b/documentation/sphinx_autodocumentation/fragmenstein.mpro.md @@ -0,0 +1,121 @@ +# fragmenstein.mpro package + +## Module contents + +This is a variant of Victor for MPro that uses data from PostEra + + +### class fragmenstein.mpro.MProVictor(category=None, \*\*options) +Bases: `fragmenstein.victor.Victor` + + +#### \__init__(category=None, \*\*options) +Initialise Victor in order to allow either combinations (merging/linking without a given aimed for molecule) +or placements (using a given aimed for molecule). + + +* **Parameters** + + + * **hits** – list of rdkit molecules + + + * **pdb_filename** – file of apo structure + + + * **ligand_resn** – 3 letter code or your choice + + + * **ligand_resi** – Rosetta-style pose(int) or pdb(str) + + + * **covalent_resn** – only CYS accepted. if smiles has no \* it is ignored + + + * **covalent_resi** – Rosetta-style pose(int) or pdb(str) + + + * **extra_protein_constraint** – multiline string of constraints relevant to the protein + + + * **pose_fx** – a function to call with pose to tweak or change something before minimising. + + + +#### classmethod add_category(postera) +Postera table has categories as True/False. But it is unlikely that there are multiple. +Turns out these categories are **not** user submitted. +However, for consistency with other analysis by other people these are used. + + +* **Parameters** + + **postera** (`DataFrame`) – pandas table modified in place + + + +* **Return type** + + `None` + + + +* **Returns** + + + + +#### classmethod analyse_postera() + +#### constraint_function_type( = 'FLAT_HARMONIC') + +#### classmethod fetch_postera() +Reads the submission file off Github. +For a local version, just `postera = pd.read_csv(file)` and `MProVictor.add_category(postera)`. +:return: + + +#### classmethod from_hit_codes(hit_codes, \*\*options) + +#### classmethod from_postera_row(row, results=None) + +#### classmethod get_mol(xnumber) + +#### classmethod get_mpro_path() + +#### place(\*\*options) +Places a followup (smiles) into the protein based upon the hits. +Do note that while Monster’s place accepts a mol, while place_smiles a smiles +Victor’s place accepts only smiles. + + +* **Parameters** + + + * **smiles** – smiles of followup, optionally covalent (_e.g._ `\*CC(=O)CCC`) + + + * **long_name** – gets used for filenames so will get corrected + + + * **merging_mode** – + + + * **atomnames** – an optional dictionary that gets used by `Params.from_smiles` + + + * **extra_ligand_constraint** – + + + +* **Returns** + + + + +### fragmenstein.mpro.poised_pose_fx(pose) +Histidine in delta and cysteine in thiolate. + + +### fragmenstein.mpro.pose_fx(pose) +Histidine in delta. diff --git a/documentation/sphinx_autodocumentation/fragmenstein.victor.md b/documentation/sphinx_autodocumentation/fragmenstein.victor.md new file mode 100644 index 0000000..4ac0cd4 --- /dev/null +++ b/documentation/sphinx_autodocumentation/fragmenstein.victor.md @@ -0,0 +1,158 @@ +# fragmenstein.victor package + +## Submodules + +## fragmenstein.victor.minimalPDB module + + +### class fragmenstein.victor.minimalPDB.MinimalPDBParser(block) +Bases: `object` + +This purpose build PDB parser simply fixes the serial numbers. +The reason is that writing a custom 50 line class is easier that +having biopython or other non-builtin requirement as a requirement +Importing the PDB into RDKit is inadvisable. + + +#### \__init__(block) +Initialize self. See help(type(self)) for accurate signature. + + +#### append(other) +Add a second parser data to it. But only its coordinates and connections. + + +#### get_max_serial() + +* **Return type** + + `int` + + + +#### get_serial(entry) + +#### offset_connections(offset) + +* **Return type** + + `None` + + + +#### offset_serials(offset) + +* **Return type** + + `None` + + + +#### parse(block) + +* **Return type** + + `None` + + + +#### set_serial(entry, value) + +* **Return type** + + `None` + + +## Module contents + + +The class Victor is assembled via a various class that inherit VictorCommon +This is made by series of classes, whose dependency is not really linear, +but for simplicity is have been written that way. + +1. VictorBase => constructor +2. VictorSafety => error catching +3. VictorJournal => logging +4. VictorPlonk => place +5. VictorOverridables => empty methods +5. VictorStore => save +6. VictorIgor => call igor +7. VictorCommon => common + +* VctorPlace => placement +* VictorCombine => merging/linking +* VictorUtils => Bits and bobs + + +### class fragmenstein.victor.Victor(hits, pdb_filename, ligand_resn='LIG', ligand_resi='1B', covalent_resn='CYS', covalent_resi=None, extra_protein_constraint=None, pose_fx=None) +Bases: `fragmenstein.victor._victor_utils._VictorUtils`, `fragmenstein.victor._victor_validate._VictorValidate`, `fragmenstein.victor._victor_combine._VictorCombine`, `fragmenstein.victor._victor_place._VictorPlace` + +and Igor (energy minimises). +This master reanimator keeps a `.journal` (logging, class attribute). + +The constructor sets the protein detail. While, place or combine deal do the analyses. + + +* **Variables** + + +* **apo_pdbblock** (*str*) – The apo protein template PDB block (inputted) +* **atomnames** (*Union**[**None**, **List**, **Dict**]*) – an optional dictionary that gets used by `Params.from_smiles` to assigned atom names (inputted) +* **category** (*None/str*) – MPro only. +* **constrained_atoms** (*int*) – number of atoms constrained (dynamic) +* **constraint** (*Constraints*) – constrains object from rdkit_to_params +* **constraint_function_type** (*str*) – name of constraint function. Best not to change. +* **covalent_definitions** (*list*) – definitions of warheads (advanced) +* **covalent_resi** (*str*) – the residue index (PDB) for the covalent attachment (int or int + chain) or reference residue +* **covalent_resn** (*str*) – reference residue name3. the residue name for the covalent attachment. + +For now can only be ‘CYS’ (or anything else if not covalent) + +* **energy_score** (*dict*) – dict of splits of scores +* **error_msg** (*str*) – error message if an error of the type error_to_catch was raised and caught +* **error_to_catch** (*tuple*) – catch error_to_catch. +* **extra_constraint** (*str*) – extra constraint text +* **hits** (*List**[**Chem.Mol**]*) – +* **igor** (*Igor*) – igor object +* **is_covalent** (*bool/None*) – +* **joining_cutoff** (*float*) – max distance between joining mol +* **journal** (*Logger*) – log +* **ligand_resi** (*str*) – the residue index (PDB) for the ligand. +* **ligand_resn** (*str*) – the residue name for the ligand. +* **long_name** (*str*) – name for files +* **merging_mode** (*str*) – +* **minimised_mol** (*Mol*) – +* **minimised_pdbblock** (*str*) – +* **mmerging_mode** (*str*) – +* **modifications** (*dict*) – +* **mol** (*Mol*) – +* **monster** (*Monster*) – +* **monster_average_position** (*bool*) – +* **monster_mmff_minisation** (*bool*) – +* **monster_throw_on_discard** (*bool*) – +* **mrmsd** (*mRSMD*) – +* **params** (*Params*) – +* **pose_fx** (*function*) – +* **possible_definitions** (*list*) – +* **quick_renanimation** (*bool*) – +* **reference_mol** (*NoneType*) – +* **smiles** (*str*) – +* **tick** (*float*) – +* **tock** (*float*) – +* **unbound_pose** (*Pose*) – +* **unconstrained_heavy_atoms** (*int*) – +* **unminimised_pdbblock** (*str*) – +* **warhead_definitions** (*list*) – +* **warhead_harmonisation** (*str*) – +* **work_path** (*str*) – class attr. where to save stuff + +`warhead_definitions` and `covalent_definitions` are class attributes that can be modified beforehand to +allow a new attachment. `covalent_definitions` is a list of dictionaries of ‘residue’, ‘smiles’, ‘names’, +which are needed for the constraint file making. Namely smiles is two atoms and the connection and names is the +names of each. Cysteine is `{'residue': 'CYS', 'smiles': '\*SC', 'names': ['CONN3', 'SG', 'CB']}`. +While `warhead_definitions` is a list of ‘name’ (name of warhead for humans), +‘covalent’ (the smiles of the warhead, where the zeroth atom is the one attached to the rest), +‘noncovalent’ (the warhead unreacted), +‘covalent_atomnames’ and ‘noncovalent_atomnames’ (list of atom names). +The need for atomnames is actually not for the code but to allow lazy tweaks and analysis downstream +(say typing in pymol: show sphere, name CX). diff --git a/documentation/wip.md b/documentation/wip.md index c9080a7..fed1071 100644 --- a/documentation/wip.md +++ b/documentation/wip.md @@ -1,16 +1,5 @@ -* `test.py` and the various jupyter notebook I have need to go into a proper testing suite. -* Complete validation classmethod -* The mapping function can get stuck on nasty submissions in the MCS call. thread. -* Figures need remaking to reflect the current code +## Work in progress -## Future idea -This is all a bit messy. +Feedback welcome! -Furthermore, the module is called `fragmenstein`, -which contains a class `Fragmenstein`, yet the pipeline is called `Victor`. - -One _possible_ future change could be to break up the class `Fragmenstein` -into its two main modes (no-merge SMILES and automerging) and -removing the less productive options. - -Feedback welcome! \ No newline at end of file +* store RDKit Mols see [mol properties](mol_properties.md) \ No newline at end of file diff --git a/fragmenstein/igor/__init__.py b/fragmenstein/igor/__init__.py index ea26c31..fc8cd0d 100644 --- a/fragmenstein/igor/__init__.py +++ b/fragmenstein/igor/__init__.py @@ -17,7 +17,7 @@ from ._igor_init import _IgorInit, pyrosetta from ._igor_min import _IgorMin -from ._igor_utils_mixin import _IgorUtils +from ._igor_utils import _IgorUtils # this contains the init and the two classmethods. diff --git a/fragmenstein/igor/_igor_utils_mixin.py b/fragmenstein/igor/_igor_utils.py similarity index 100% rename from fragmenstein/igor/_igor_utils_mixin.py rename to fragmenstein/igor/_igor_utils.py diff --git a/fragmenstein/laboratory/_process.py b/fragmenstein/laboratory/_process.py index 7c69bf7..04c2709 100644 --- a/fragmenstein/laboratory/_process.py +++ b/fragmenstein/laboratory/_process.py @@ -39,7 +39,7 @@ def process(data: Dict[str, Union[str, dict]]): v = MProVictor.combine(hits=hits) results = SqliteDict(db_name, encode=json.dumps, decode=json.loads, autocommit=True) results[v.long_name] = v.summarise() - if not v.error: + if not v.error_msg: v.make_pse() print('DONE', [hit.GetProp('_Name') for hit in hits]) return v.minimised_mol diff --git a/fragmenstein/m_rmsd.py b/fragmenstein/m_rmsd.py index 3edec23..c6552f7 100644 --- a/fragmenstein/m_rmsd.py +++ b/fragmenstein/m_rmsd.py @@ -109,7 +109,7 @@ def from_unannotated_mols(cls, @classmethod def from_annotated_mols(cls, annotated_followup: Chem.Mol, - hits: Sequence[Chem.Mol] + hits: Optional[Sequence[Chem.Mol]]=None ) -> mRSMD: """ Monster leaves a note of what it did. atom prop _Origin is a json of a list of mol _Name dot AtomIdx. @@ -119,6 +119,32 @@ def from_annotated_mols(cls, :param hits: :return: """ + if cls.is_xyz_annotated(annotated_followup): + return cls.from_internal_xyz(annotated_followup) + mappings = cls._mapping_from_annotated_and_hits(annotated_followup, hits) + return cls(annotated_followup, hits, mappings) + + @classmethod + def is_origin_annotated(cls, mol: Chem.Mol) -> bool: + for atom in mol.GetAtoms(): + if len(cls._get_origin(atom)) > 0: + return True + else: + return False + + @classmethod + def is_xyz_annotated(cls, mol: Chem.Mol) -> bool: + for atom in mol.GetAtoms(): + if len(cls._get_xyz(atom)) > 0: + return True + else: + return False + + @classmethod + def _mapping_from_annotated_and_hits(cls, + annotated_followup: Chem.Mol, + hits: Sequence[Chem.Mol]): + assert cls.is_origin_annotated(annotated_followup), 'This molecules is not annotated.' mappings = [] for h, hit in enumerate(hits): hname = hit.GetProp('_Name') @@ -129,12 +155,12 @@ def from_annotated_mols(cls, for i in range(annotated_followup.GetNumAtoms()): atom = annotated_followup.GetAtomWithIdx(i) for oel in cls._get_origin(atom): - rex = re.match(hname+'\.(\d+)', oel) + rex = re.match(hname + '\.(\d+)', oel) if rex is not None: h = int(rex.group(1)) mapping.append((i, h)) mappings.append(mapping) - return cls(annotated_followup, hits, mappings) + return mappings @classmethod def from_other_annotated_mols(cls, @@ -234,6 +260,9 @@ def copy_all_possible_origins(cls, annotated: Chem.Mol, target: Chem.Mol) -> Tup tatom = option.GetAtomWithIdx(i) o = cls._get_origin(atom) tatom.SetProp('_Origin', json.dumps(o)) + xyz = cls._get_xyz(atom) + if xyz: + cls._set_xyz(tatom, xyz) options.append(option) originss.append(origins) return options, originss @@ -266,4 +295,47 @@ def _get_origin(cls, atom: Chem.Atom) -> List[str]: else: return [] + @classmethod + def _get_xyz(cls, atom: Chem.Atom) -> Tuple[float]: + if atom.HasProp('_x'): + return (atom.GetDoubleProp('_x'), + atom.GetDoubleProp('_y'), + atom.GetDoubleProp('_z')) + else: + return () + + @classmethod + def _set_xyz(cls, atom: Chem.Atom, xyz): + if len(xyz): + atom.SetDoubleProp('_x', xyz[0]), + atom.SetDoubleProp('_y', xyz[1]), + atom.SetDoubleProp('_z', xyz[2]) + + @classmethod + def from_internal_xyz(cls, annotated_followup): + """ + This is an alternative for when the atoms have _x, _y, _z + + :param annotated_followup: + :return: + """ + self = cls.__new__(cls) + self.followup = annotated_followup + self.hits = [] + self.mappings = [] + self.rmsds = [] + self.mrmsd = float('nan') + conf = annotated_followup.GetConformer() + n = 0 + tatoms = 0 + for a, atom in enumerate(annotated_followup.GetAtoms()): + if atom.HasProp('_x'): + x, y, z = cls._get_xyz(atom) + tatoms += 1 + n += sum([(conf.GetAtomPosition(a).x - x) ** 2 + + (conf.GetAtomPosition(a).y - y) ** 2 + + (conf.GetAtomPosition(a).z - z) ** 2]) + self.mrmsd = (n / tatoms) ** 0.5 + return self + diff --git a/fragmenstein/monster/unmerge_mapper.py b/fragmenstein/monster/unmerge_mapper.py index 0e7d8a5..549e874 100644 --- a/fragmenstein/monster/unmerge_mapper.py +++ b/fragmenstein/monster/unmerge_mapper.py @@ -416,6 +416,7 @@ def measure_map(self, mol: Chem.Mol, mapping: Dict[int, int]) -> np.array: def offness(self, mol: Chem.Mol, mapping: Dict[int, int]) -> float: """ How many bonds are too long? + :param mol: :param mapping: :return: diff --git a/fragmenstein/mpro/__init__.py b/fragmenstein/mpro/__init__.py index 37a9831..b518f05 100644 --- a/fragmenstein/mpro/__init__.py +++ b/fragmenstein/mpro/__init__.py @@ -5,13 +5,6 @@ This is a variant of Victor for MPro that uses data from PostEra """ -__author__ = "Matteo Ferla. [Github](https://github.com/matteoferla)" -__email__ = "matteo.ferla@gmail.com" -__date__ = "2020 A.D." -__license__ = "MIT" -__version__ = "0.4" -__citation__ = "" - ######################################################################################################################## @@ -67,9 +60,9 @@ def get_mol(cls, xnumber): return mol @classmethod - def from_hit_codes(cls, smiles: str, hit_codes:List[str], long_name:str, category:Optional[str]=None): + def from_hit_codes(cls, hit_codes: List[str], **options): hits = [cls.get_mol(xnumber) for xnumber in hit_codes] - return cls(smiles=smiles, hits=hits, long_name=long_name, category=category) + return cls(hits=hits, **options) @classmethod def from_postera_row(cls, row: pd.Series, results:Optional=None): @@ -82,97 +75,61 @@ def from_postera_row(cls, row: pd.Series, results:Optional=None): return None elif row.covalent_warhead in (False, 'False', 'false'): # parse - return cls.from_hit_codes(long_name=row.CID, - hit_codes=row.fragments.split(','), - smiles=row.SMILES, - category='noncolavent') + return cls.from_hit_codes(hit_codes=row.fragments.split(','), + category='noncolavent')\ + .place(long_name=row.CID, + smiles=row.SMILES) elif row.category not in ('Acrylamide', 'Chloroacetamide', 'Vinylsulfonamide', 'Nitrile'): cls.journal.warning(f'What is {row["CID"]}? Treating like a non-covalent.') - return cls.from_hit_codes(long_name=row.CID, - hit_codes=row.fragments.split(','), - smiles=row.SMILES, - category='noncolavent') - else: - return cls.from_hit_codes(long_name=row.CID, - hit_codes=row.fragments.split(','), - smiles=cls.make_covalent(row.SMILES), - category=row.category) - - def __init__(self, smiles: str, hits:List[Chem.Mol], long_name:str, category:Optional[str]=None): - mpro_folder = self.get_mpro_path() - apo = os.path.join(mpro_folder, 'template.pdb') - atomnames = {} - if category == 'noncolavent': - fx = poised_pose_fx + return cls.from_hit_codes(hit_codes=row.fragments.split(','), + category='noncolavent')\ + .place(long_name=row.CID, + smiles=row.SMILES) else: - fx = pose_fx - extra_constraint = 'AtomPair SG 145A NE2 41A HARMONIC 3.5 0.2\n' - if category not in (None, 'noncovalent') and '_' in category: - cname, rxd = category.split('_') - if rxd == 'noncovalent': - wd = [wd for wd in self.warhead_definitions if wd['name'] == cname][0] - mol = Chem.MolFromSmiles(smiles) - nc = Chem.MolFromSmiles(wd['noncovalent']) - atomnames = dict(zip(mol.GetSubstructMatch(nc), wd['noncovalent_atomnames'])) - fx = poised_pose_fx - extra_constraint += 'AtomPair SG 145A CX 1B HARMONIC 3.2 0.5\n' - extra_constraint += wd['constraint'] - - super().__init__(smiles=smiles, - hits=hits, - pdb_filename=apo, - long_name=long_name, - ligand_resn='LIG', - ligand_resi='1B', - covalent_resn='CYS', covalent_resi='145A', - extra_constraint=extra_constraint, - pose_fx=fx, - atomnames=atomnames) + return cls.from_hit_codes(hit_codes=row.fragments.split(','), + category=row.category)\ + .place(long_name=row.CID, + smiles=row.SMILES) def __init__(self, category:Optional[str]=None, **options): - # this category flag is solely for Mpro. # TODO check. + # this category flag is solely for Mpro? + # it stems from the Moonshot file. + self.category = category if category == 'noncolavent': fx = poised_pose_fx else: fx = pose_fx - extra_constraint = 'AtomPair SG 145A NE2 41A HARMONIC 3.5 0.2\n' - if category not in (None, 'noncovalent') and '_' in category: - cname, rxd = category.split('_') - if rxd == 'noncovalent': - wd = [wd for wd in self.warhead_definitions if wd['name'] == cname][0] - mol = Chem.MolFromSmiles(options['smiles']) - nc = Chem.MolFromSmiles(wd['noncovalent']) - atomnames = dict(zip(mol.GetSubstructMatch(nc), wd['noncovalent_atomnames'])) - fx = poised_pose_fx - extra_constraint += 'AtomPair SG 145A CX 1B HARMONIC 3.2 0.5\n' - extra_constraint += wd['constraint'] # -------------------- defaults = dict( pdb_filename=os.path.join(self.get_mpro_path(), 'template.pdb'), ligand_resn='LIG', ligand_resi='1B', covalent_resn='CYS', covalent_resi='145A', - extra_constraint='AtomPair SG 145A NE2 41A HARMONIC 3.5 0.2\n', + extra_protein_constraint='AtomPair SG 145A NE2 41A HARMONIC 3.5 0.2\n', pose_fx=fx # from the above. ) super().__init__(**{**defaults, **options}) - @classmethod - def combine_codes(cls, hit_codes: List[str], **options): - hits = [cls.get_mol(xnumber) for xnumber in hit_codes] - return cls.combine(hits=hits, **options) + def _determine_extras(self, smiles): + defaults = dict() + if self.category not in (None, 'noncovalent') and '_' in self.category: + cname, rxd = self.category.split('_') + if rxd == 'noncovalent': + wd = [wd for wd in self.warhead_definitions if wd['name'] == cname][0] + mol = Chem.MolFromSmiles(smiles) + nc = Chem.MolFromSmiles(wd['noncovalent']) + atomnames = dict(zip(mol.GetSubstructMatch(nc), wd['noncovalent_atomnames'])) + extra_constraint = 'AtomPair SG 145A CX 1B HARMONIC 3.2 0.5\n' + extra_constraint += wd['constraint'] + defaults = dict(atomnames=atomnames, + extra_ligand_constraint=extra_constraint) + return defaults - @classmethod - def combine(cls, **options): - defaults = dict( - pdb_filename=os.path.join(cls.get_mpro_path(), 'template.pdb'), - ligand_resn='LIG', - ligand_resi='1B', - covalent_resn='CYS', covalent_resi='145A', - extra_constraint='AtomPair SG 145A NE2 41A HARMONIC 3.5 0.2\n', - pose_fx=pose_fx # from the module namespace. - ) - return super().combine(**{**defaults, **options}) + #self.combine(**options) unchanged. + + def place(self, **options): + defaults = self._determine_extras(options['smiles']) + return super().place(**{**defaults, **options}) # ======= postera csv file ops ===================================================================================== @@ -183,14 +140,23 @@ def fetch_postera(cls): For a local version, just ``postera = pd.read_csv(file)`` and ``MProVictor.add_category(postera)``. :return: """ - url = "https://raw.githubusercontent.com/postera-ai/COVID_moonshot_submissions/master/covid_submissions_all_info.csv" + url = "https://raw.githubusercontent.com/postera-ai/" + \ + "COVID_moonshot_submissions/master/covid_submissions_all_info.csv" s = requests.get(url).content postera = pd.read_csv(io.StringIO(s.decode('utf-8'))) cls.add_category(postera) return postera @classmethod - def add_category(cls, postera): + def add_category(cls, postera: pd.DataFrame) -> None: + """ + Postera table has categories as True/False. But it is unlikely that there are multiple. + Turns out these categories are **not** user submitted. + However, for consistency with other analysis by other people these are used. + + :param postera: pandas table modified in place + :return: + """ def get_category(row): for category in ('Acrylamide', 'Chloroacetamide', 'Vinylsulfonamide', 'Nitrile'): if row[category] in ('True', 'true', True): diff --git a/fragmenstein/victor/__init__.py b/fragmenstein/victor/__init__.py index ded7109..fbc595b 100644 --- a/fragmenstein/victor/__init__.py +++ b/fragmenstein/victor/__init__.py @@ -4,8 +4,7 @@ __doc__ = \ """ -Victor (after Dr Victor Frankenstein) is a class that uses both Monster (makes blended compounds) and Igor (energy minimises). -This master reanimator keeps a ``.journal`` (logging, class attribute). +?? And can be called via the class method ``.laboratory`` where he can process multiple compounds at once. The class Victor is assembled via a various class that inherit VictorCommon @@ -39,19 +38,105 @@ class Victor(_VictorUtils, _VictorValidate, _VictorCombine, _VictorPlace): """ - * ``smiles`` SMILES string (inputted) - * ``long_name`` name for files - * ``ligand_resn`` the residue name for the ligand. - * ``ligand_resi`` the residue index (PDB) for the ligand. - * ``covalent_resi`` the residue index (PDB) for the covalent attachment - * ``covalent_resn`` the residue name for the covalent attachment. For now can only be 'CYS' - * ``params`` Params instance - * ``constraint`` Constraint or None depending on if covalent. - * ``mol`` the molecule - * ``covalent_definitions`` class attr. that stores for each possible attachment residue (CYS) defs for constraints. - * ``warhead_definitions`` class attr. that stores warheader info - * ``journal`` class attr. logging - * ``work_path`` class attr. where to save stuff + Victor (after Dr Victor Frankenstein) is a class that uses both Monster (makes blended compounds) + and Igor (energy minimises). + This master reanimator keeps a ``.journal`` (logging, class attribute). + + The constructor sets the protein detail. While, place or combine deal do the analyses. + + :ivar apo_pdbblock: The apo protein template PDB block (inputted) + :vartype apo_pdbblock: str + :ivar atomnames: an optional dictionary that gets used by ``Params.from_smiles`` to assigned atom names (inputted) + :vartype atomnames: Union[None, List, Dict] + :ivar category: MPro only. + :vartype category: None/str + :cvar constrained_atoms: number of atoms constrained (dynamic) + :vartype constrained_atoms: int + :ivar constraint: constrains object from rdkit_to_params + :vartype constraint: Constraints + :cvar constraint_function_type: name of constraint function. Best not to change. + :vartype constraint_function_type: str + :cvar covalent_definitions: definitions of warheads (advanced) + :vartype covalent_definitions: list + :ivar covalent_resi: the residue index (PDB) for the covalent attachment (int or int + chain) or reference residue + :vartype covalent_resi: str + :ivar covalent_resn: reference residue name3. the residue name for the covalent attachment. + For now can only be 'CYS' (or anything else if not covalent) + :vartype covalent_resn: str + :ivar energy_score: dict of splits of scores + :vartype energy_score: dict + :ivar error_msg: error message if an error of the type error_to_catch was raised and caught + :vartype error_msg: str + :cvar error_to_catch: catch error_to_catch. + :vartype error_to_catch: tuple + :ivar extra_constraint: extra constraint text + :vartype extra_constraint: str + :ivar hits: + :vartype hits: List[Chem.Mol] + :ivar igor: igor object + :vartype igor: Igor + :ivar is_covalent: + :vartype is_covalent: bool/None + :ivar joining_cutoff: max distance between joining mol + :vartype joining_cutoff: float + :cvar journal: log + :vartype journal: Logger + :ivar ligand_resi: the residue index (PDB) for the ligand. + :vartype ligand_resi: str + :ivar ligand_resn: the residue name for the ligand. + :vartype ligand_resn: str + :ivar long_name: name for files + :vartype long_name: str + :ivar merging_mode: + :vartype merging_mode: str + :ivar minimised_mol: + :vartype minimised_mol: Mol + :ivar minimised_pdbblock: + :vartype minimised_pdbblock: str + :ivar mmerging_mode: + :vartype mmerging_mode: str + :ivar modifications: + :vartype modifications: dict + :ivar mol: + :vartype mol: Mol + :ivar monster: + :vartype monster: Monster + :cvar monster_average_position: + :vartype monster_average_position: bool + :cvar monster_mmff_minisation: + :vartype monster_mmff_minisation: bool + :cvar monster_throw_on_discard: + :vartype monster_throw_on_discard: bool + :ivar mrmsd: + :vartype mrmsd: mRSMD + :ivar params: + :vartype params: Params + :ivar pose_fx: + :vartype pose_fx: function + :cvar possible_definitions: + :vartype possible_definitions: list + :cvar quick_renanimation: + :vartype quick_renanimation: bool + :ivar reference_mol: + :vartype reference_mol: NoneType + :ivar smiles: + :vartype smiles: str + :ivar tick: + :vartype tick: float + :ivar tock: + :vartype tock: float + :ivar unbound_pose: + :vartype unbound_pose: Pose + :cvar unconstrained_heavy_atoms: + :vartype unconstrained_heavy_atoms: int + :ivar unminimised_pdbblock: + :vartype unminimised_pdbblock: str + :cvar warhead_definitions: + :vartype warhead_definitions: list + :ivar warhead_harmonisation: + :vartype warhead_harmonisation: str + :cvar work_path: class attr. where to save stuff + :vartype work_path: str ``warhead_definitions`` and ``covalent_definitions`` are class attributes that can be modified beforehand to allow a new attachment. ``covalent_definitions`` is a list of dictionaries of 'residue', 'smiles', 'names', @@ -63,9 +148,6 @@ class Victor(_VictorUtils, _VictorValidate, _VictorCombine, _VictorPlace): 'covalent_atomnames' and 'noncovalent_atomnames' (list of atom names). The need for atomnames is actually not for the code but to allow lazy tweaks and analysis downstream (say typing in pymol: `show sphere, name CX`). - Adding a 'constraint' to an entry will apply that constraint. - ``merging_mode:str`` is class attributes that control Monster. - """ pass diff --git a/fragmenstein/victor/_victor_base.py b/fragmenstein/victor/_victor_base.py index cd55953..b3cb90f 100644 --- a/fragmenstein/victor/_victor_base.py +++ b/fragmenstein/victor/_victor_base.py @@ -99,23 +99,21 @@ def __init__(self, ligand_resi: Union[int, str] = '1B', covalent_resn: str = 'CYS', # no other option is accepted. covalent_resi: Optional[Union[int, str]] = None, - extra_constraint: Union[str] = None, + extra_protein_constraint: Union[str] = None, pose_fx: Optional[Callable] = None, ): """ Initialise Victor in order to allow either combinations (merging/linking without a given aimed for molecule) or placements (using a given aimed for molecule). - :param smiles: smiles of followup, optionally covalent (_e.g._ ``*CC(=O)CCC``) :param hits: list of rdkit molecules :param pdb_filename: file of apo structure :param ligand_resn: 3 letter code or your choice :param ligand_resi: Rosetta-style pose(int) or pdb(str) :param covalent_resn: only CYS accepted. if smiles has no * it is ignored :param covalent_resi: Rosetta-style pose(int) or pdb(str) - :param extra_constraint: multiline string of constraints.. + :param extra_protein_constraint: multiline string of constraints relevant to the protein :param pose_fx: a function to call with pose to tweak or change something before minimising. - :param atomnames: an optional dictionary that gets used by ``Params.from_smiles`` """ # ## Store # entry attributes @@ -126,13 +124,13 @@ def __init__(self, self.ligand_resi = ligand_resi self.covalent_resn = covalent_resn.upper() self.covalent_resi = covalent_resi - self.extra_constraint = extra_constraint + self.extra_constraint = extra_protein_constraint self.pose_fx = pose_fx - # ## Fill by place or combine + # ## Fill by place and combine differently self.long_name = 'ligand' + self.smiles = None # ## Filled by place self.merging_mode = "none_permissive" - self.smiles = None # ## Filled by combine self.joining_cutoff = None # ## Calculated @@ -142,7 +140,8 @@ def __init__(self, self.constraint = None self.modifications = {} self.unminimised_pdbblock = None - self.monster = Monster(hits, average_position=self.monster_average_position) + self.monster = Monster(hits, + average_position=self.monster_average_position) self.igor = None self.unbound_pose = None self.minimised_pdbblock = None @@ -153,6 +152,7 @@ def __init__(self, self.energy_score = {'ligand_ref2015': {'total_score': float('nan')}, 'unbound_ref2015': {'total_score': float('nan')}} self.mrmsd = mRSMD.mock() + self.ddG = float('nan') # for debug purposes self.tick = time.time() self.tock = float('inf') diff --git a/fragmenstein/victor/_victor_combine.py b/fragmenstein/victor/_victor_combine.py index fcba590..a068ae7 100644 --- a/fragmenstein/victor/_victor_combine.py +++ b/fragmenstein/victor/_victor_combine.py @@ -16,42 +16,38 @@ class _VictorCombine(_VictorCommon): - """ - Combines the hits without a template. - If the class attribute ``monster_throw_on_discard`` is True, it will raise an exception if it cannot. - The cutoff distance is controlled by class attribute ``monster_joining_cutoff``. - At present this just adds a hydrocarbon chain, no fancy checking for planarity. + def combine(self, + long_name: Optional[str] = None, + atomnames: Optional[Dict[int, str]] = None, + warhead_harmonisation: str = 'first', + joining_cutoff=5., # Å + extra_ligand_constraint: Union[str] = None + ): + """ + Combines the hits without a template. + If the class attribute ``monster_throw_on_discard`` is True, it will raise an exception if it cannot. - The hits are collapsed, merged, expanded and bonded by proximity. - In ``(self.monster.expand_ring(..., bonded_as_original=False)`` changing to True, might work, but most likely won't. + The cutoff distance is controlled by class attribute ``monster_joining_cutoff``. + At present this just adds a hydrocarbon chain, no fancy checking for planarity. - ``warhead_harmonisation`` fixes the warhead in the hits to be homogeneous. + The hits are collapsed, merged, expanded and bonded by proximity. + In ``(self.monster.expand_ring(..., bonded_as_original=False)`` changing to True, might work, but most likely won't. + + ``warhead_harmonisation`` fixes the warhead in the hits to be homogeneous. * ``keep``. Don't do anything * ``none``. strip warheads * ``first``. Use first warhead * warhead name. Use this warhead. - :param hits: - :param pdb_filename: - :param ligand_resn: - :param ligand_resi: - :param covalent_resn: - :param covalent_resi: - :param extra_constraint: - :param pose_fx: - :param atomnames: - :param warhead_harmonisation: keep | strip | first | chloracetimide | nitrile ... - :return: - """ - - def combine(self, - long_name: Optional[str] = None, - atomnames: Optional[Dict[int, str]] = None, - warhead_harmonisation: str = 'first', - joining_cutoff=5., # Å - ): + :param long_name: + :param atomnames: an optional dictionary that gets used by ``Params.from_smiles`` + :param warhead_harmonisation: keep | strip | first | chloracetimide | nitrile ... + :param joining_cutoff: + :param extra_ligand_constraint: + :return: + """ self.joining_cutoff = joining_cutoff self.atomnames = atomnames self.warhead_harmonisation = warhead_harmonisation @@ -59,6 +55,7 @@ def combine(self, self.long_name = '-'.join([h.GetProp('_Name') for h in self.hits]) else: self.long_name = self.slugify(long_name) + self.add_extra_constraint(extra_ligand_constraint) # ## Analyse self._safely_do(execute=self._calculate_combination, resolve=self._resolve, reject=self._reject) return self @@ -87,9 +84,7 @@ def _harmonise_warhead_combine(self): def _calculate_combination(self): attachment = self._get_attachment_from_pdbblock() if self.is_covalent else None - self.monster = Monster(hits=self.hits, - average_position=self.monster_average_position - ) + # TODO Does combine not need attachment?? self.monster.modifications = self.modifications self.monster.combine(keep_all=self.monster_throw_on_discard, collapse_rings=True, diff --git a/fragmenstein/victor/_victor_common.py b/fragmenstein/victor/_victor_common.py index ad7eb53..e1cb6ef 100644 --- a/fragmenstein/victor/_victor_common.py +++ b/fragmenstein/victor/_victor_common.py @@ -76,6 +76,14 @@ def _fix_covalent(self): cons.custom_constraint = war_def['constraint'] return cons + def add_extra_constraint(self, new_constraint:Union[str]=None): + if new_constraint is None: + return # do nothing + new_constraint = new_constraint.strip() + if self.extra_constraint is None: + self.extra_constraint = new_constraint + self.extra_constraint = self.extra_constraint.strip() + '\n' + new_constraint.strip() + def make_coordinate_constraints(self, mol: Optional[Chem.Mol] = None, origins: Optional[List[List[str]]] = None, diff --git a/fragmenstein/victor/_victor_igor.py b/fragmenstein/victor/_victor_igor.py index e5e70bd..08682b1 100644 --- a/fragmenstein/victor/_victor_igor.py +++ b/fragmenstein/victor/_victor_igor.py @@ -61,18 +61,19 @@ def reanimate(self) -> float: break elif self.igor.coordinate_constraint < 0.005: self.igor.coordinate_constraint = 0. + self.ddG = ddG return ddG def reanimate_n_store(self): - ddG = self.reanimate() - self._store_after_reanimation(ddG) + self.reanimate() + self._store_after_reanimation() - def _store_after_reanimation(self, ddG: float): + def _store_after_reanimation(self): self.minimised_pdbblock = self.igor.pose2str() self.post_igor_step() # empty overridable self.minimised_mol = self._fix_minimised() self.mrmsd = self._calculate_rmsd() - self.journal.info(f'{self.long_name} - final score: {ddG} kcal/mol {self.mrmsd.mrmsd}.') + self.journal.info(f'{self.long_name} - final score: {self.ddG} kcal/mol, RMSD: {self.mrmsd.mrmsd}.') self._checkpoint_charlie() self.journal.debug(f'{self.long_name} - Completed') diff --git a/fragmenstein/victor/_victor_place.py b/fragmenstein/victor/_victor_place.py index 505519d..674ca07 100644 --- a/fragmenstein/victor/_victor_place.py +++ b/fragmenstein/victor/_victor_place.py @@ -9,12 +9,18 @@ def place(self, smiles: str, long_name: str = 'ligand', merging_mode='none_permissive', - atomnames: Optional[Dict[int, str]] = None): + atomnames: Optional[Dict[int, str]] = None, + extra_ligand_constraint: Union[str] = None): """ - :param smiles: - :param long_name: gets used for filenames so will get slugified + Places a followup (smiles) into the protein based upon the hits. + Do note that while Monster's place accepts a mol, while place_smiles a smiles + Victor's place accepts only smiles. + + :param smiles: smiles of followup, optionally covalent (_e.g._ ``*CC(=O)CCC``) + :param long_name: gets used for filenames so will get corrected :param merging_mode: - :param atomnames: + :param atomnames: an optional dictionary that gets used by ``Params.from_smiles`` + :param extra_ligand_constraint: :return: """ # ## Store @@ -22,6 +28,7 @@ def place(self, self.smiles = smiles self.atomnames = atomnames self.merging_mode = merging_mode + self.add_extra_constraint(extra_ligand_constraint) # ## Analyse self._safely_do(execute=self._calculate_placement, resolve=self._resolve, reject=self._reject) return self @@ -55,8 +62,6 @@ def _calculate_placement(self): # make monster self.journal.debug(f'{self.long_name} - Starting fragmenstein') # monster_throw_on_discard controls if disconnected. - self.monster = Monster(hits=self.hits, - average_position=self.monster_average_position) self.monster.place(mol=self.mol, attachment=attachment, merging_mode=self.merging_mode) @@ -89,7 +94,8 @@ def _calculate_placement(self): ddG = self.quick_reanimate() else: ddG = self.reanimate() - self._store_after_reanimation(ddG) + self.ddG = ddG + self._store_after_reanimation() def _assert_placement_inputs(self): if '*' in self.smiles and (self.covalent_resi is None or self.covalent_resn is None): diff --git a/fragmenstein/victor/_victor_utils.py b/fragmenstein/victor/_victor_utils.py index 055b249..68705c2 100644 --- a/fragmenstein/victor/_victor_utils.py +++ b/fragmenstein/victor/_victor_utils.py @@ -487,8 +487,6 @@ def from_files(cls, folder: str) -> 'self': fd = json.load(open(fragjson)) self.smiles = fd['smiles'] self.is_covalent = True if '*' in self.smiles else False - self.monster = Monster(hits=self.hits, - average_position=self.monster_average_position) self.monster.place(mol=self.mol, attachment=None, merging_mode='off') diff --git a/fragmenstein/victor/_victor_validate.py b/fragmenstein/victor/_victor_validate.py index 91c0168..ab0997b 100644 --- a/fragmenstein/victor/_victor_validate.py +++ b/fragmenstein/victor/_victor_validate.py @@ -1,13 +1,8 @@ +from rdkit import Chem + from ._victor_base import _VictorBase -from ..monster import Monster -from ..igor import Igor from ..m_rmsd import mRSMD -from molecular_rectifier import Rectifier -from typing import List, Optional, Dict, Union, Callable -from rdkit import Chem -from rdkit.Chem import AllChem -from rdkit_to_params import Params, Constraints -import time, warnings, os + class _VictorValidate(_VictorBase): diff --git a/test.py b/test.py index 6f18096..e3869c8 100644 --- a/test.py +++ b/test.py @@ -17,7 +17,7 @@ # ====================================================================================================================== -class MProTargetTester(unittest.TestCase): +class MProPlaceTester(unittest.TestCase): def test_easy(self): """ @@ -28,10 +28,9 @@ def test_easy(self): """ # PAU-UNI-52c0427f-1 MProVictor.quick_renanimation = True - victor = MProVictor.from_hit_codes(smiles='CCNc1ncc(C#N)cc1CN1CCN(C(=O)C*)CC1', - hit_codes=['x0692', 'x0305', 'x1249'], - long_name='2_ACL') - self.assertEqual(victor.error, '', victor.error) + victor = MProVictor.from_hit_codes(hit_codes=['x0692', 'x0305', 'x1249']) + victor.place(smiles='CCNc1ncc(C#N)cc1CN1CCN(C(=O)C*)CC1', long_name='2_ACL') + self.assertEqual(victor.error_msg, '', victor.error_msg) self.assertIsNotNone(victor.minimised_mol, 'Failed minimisation') msg = f'x1249 is the red herring, prediction: {victor.monster.unmatched}, ' + \ f'while x0305 and x0692 the true inspirations {victor.monster.matched}' @@ -48,10 +47,10 @@ def test_nasty(self): :return: """ MProVictor.quick_renanimation = True - victor = MProVictor.from_hit_codes(smiles='*CCC(=O)N1CC(CCN(C(=O)Nc2c(C)ncc(C)c2CCN2CCOCC2)c2cc(C)ccn2)C1', - hit_codes=['x0434', 'x0540'], - long_name='AGN-NEW-5f0-1_ACR1') - self.assertEqual(str(victor.error), '', str(victor.error)) + victor = MProVictor.from_hit_codes(hit_codes=['x0434', 'x0540']) + victor.place(smiles='*CCC(=O)N1CC(CCN(C(=O)Nc2c(C)ncc(C)c2CCN2CCOCC2)c2cc(C)ccn2)C1', + long_name='AGN-NEW-5f0-1_ACR1') + self.assertEqual(str(victor.error_msg), '', str(victor.error_msg)) self.assertIsNotNone(victor.minimised_mol, 'Failed minimisation') self.assertEqual(len(victor.monster.unmatched), 0, f'Both were correct but {victor.monster.unmatched} was discarded') @@ -65,10 +64,10 @@ def test_incorrect(self): :return: """ MProVictor.quick_renanimation = True - victor = MProVictor.from_hit_codes(smiles='*C(=N)CN1CCN(Cc2ccc(-c3cc(CC)ncn3)c(F)c2)CC1', - hit_codes='x0692,x0770,x0995'.split(','), - long_name='BEN-VAN-c98-4') - self.assertEqual(victor.error, '', victor.error) + victor = MProVictor.from_hit_codes(hit_codes='x0692,x0770,x0995'.split(',')) + victor.place(smiles='*C(=N)CN1CCN(Cc2ccc(-c3cc(CC)ncn3)c(F)c2)CC1', + long_name='BEN-VAN-c98-4') + self.assertEqual(victor.error_msg, '', victor.error_msg) self.assertIsNotNone(victor.minimised_mol, 'Failed minimisation') victor.make_pse() self.assertIn('x0995', victor.monster.unmatched) @@ -90,11 +89,11 @@ def test_pentachromatic(self): MProVictor.quick_renanimation = True # ,'x2646' Victor.monster_throw_on_discard = True - victor = MProVictor.from_hit_codes(smiles='Cc1ccncc1NC(=O)Cc1cccc(Cl)c1', - # hit_codes=['x0107','x0434','x0678','x0995','x1382'], - hit_codes=['x0107', 'x0434', 'x1382'], - long_name='TRY-UNI-714a760b-6') - self.assertEqual(victor.error, '', victor.error) + victor = MProVictor.from_hit_codes(# hit_codes=['x0107','x0434','x0678','x0995','x1382'], + hit_codes=['x0107', 'x0434', 'x1382']) + victor.place(smiles='Cc1ccncc1NC(=O)Cc1cccc(Cl)c1', + long_name='TRY-UNI-714a760b-6') + self.assertEqual(victor.error_msg, '', victor.error_msg) self.assertIsNotNone(victor.minimised_mol, 'Failed minimisation') actual = MProVictor.get_mol('x2646') victor.make_pse(extra_mols=[actual]) @@ -106,82 +105,82 @@ def test_pentachromatic(self): # ====================================================================================================================== -class RingTestsVictor(unittest.TestCase): +class VictorCombineTests(unittest.TestCase): + def test_noncovalent(self): + MProVictor.quick_renanimation = False + victor = MProVictor.from_hit_codes(hit_codes=['x0305', 'x1249']) + victor.combine() + self.assertLess(victor.mrmsd.mrmsd, 1, f'RMSD great that one ({victor.mrmsd.mrmsd})') + self.assertLess(victor.ddG, -1, f'ddG {victor.ddG}') + + def test_covalent(self): + MProVictor.quick_renanimation = False + victor = MProVictor.from_hit_codes(hit_codes=['x0692', 'x0305', 'x1249']) + victor.combine() + self.assertLess(victor.mrmsd.mrmsd, 1, f'RMSD great that one ({victor.mrmsd.mrmsd})') + self.assertLess(victor.ddG, -1, f'ddG {victor.ddG}') + +class MonsterCombineTests(unittest.TestCase): + def test_phenylene(self): + # make carboxy and amide benzenes that overlap so that the end result is a phenylene where one ring is oxazine + conjoined = Chem.MolFromSmiles('c3c1cccc2\C(=O)O/C(-N)c(c12)cc3') + before = Chem.MolToSmiles(conjoined) # structure from wiki is not canonical + AllChem.EmbedMolecule(conjoined) + bonds = [conjoined.GetBondBetweenAtoms(0, 1).GetIdx(), + conjoined.GetBondBetweenAtoms(12, 11).GetIdx(), + conjoined.GetBondBetweenAtoms(8, 9).GetIdx()] + fragged = Chem.FragmentOnBonds(conjoined, bonds, addDummies=False) + fore = Chem.GetMolFrags(fragged, asMols=True, sanitizeFrags=False)[1] + Chem.SanitizeMol(fore) + bonds = [conjoined.GetBondBetweenAtoms(2, 1).GetIdx(), + conjoined.GetBondBetweenAtoms(12, 5).GetIdx(), + conjoined.GetBondBetweenAtoms(8, 6).GetIdx()] + fragged = Chem.FragmentOnBonds(conjoined, bonds, addDummies=False) + aft = Chem.GetMolFrags(fragged, asMols=True, sanitizeFrags=False)[0] + Chem.SanitizeMol(aft) + # merge them + mol = Monster([fore, aft]).combine().positioned_mol + after = Chem.MolToSmiles(mol) + self.assertEqual(before, after) def test_orthomethyltoluene(self): name = 'orthomethyltoluene' after = 'Cc1cccc(C)c1' - template = os.path.join(MProVictor.get_mpro_path(), 'template.pdb') toluene = Chem.MolFromMolFile('test_mols/toluene.mol') toluene.SetProp('_Name', 'toluene') rototoluene = Chem.MolFromMolFile('test_mols/rototoluene.mol') rototoluene.SetProp('_Name', 'rototoluene') - victor = Victor.combine(hits=[toluene, rototoluene], - pdb_filename=template, - covalent_resi='3A', # a random residue is still required for the constaint ref atom. - covalent_resn='VAL') - self.assertEqual(victor.error, '', victor.error) - gotten = Chem.MolToSmiles(Chem.RemoveHs(victor.minimised_mol)) + mol = Monster(hits=[toluene, rototoluene]).combine(keep_all=True).positioned_mol + gotten = Chem.MolToSmiles(Chem.RemoveHs(mol)) self.assertEqual(gotten, after, f'{name} failed {gotten} (expected {after})') def test_peridimethylnaphthalene(self): name = 'peridimethylnaphthalene' after = 'Cc1cccc2cccc(C)c12' - template = os.path.join(MProVictor.get_mpro_path(), 'template.pdb') toluene = Chem.MolFromMolFile('test_mols/toluene.mol') toluene.SetProp('_Name', 'toluene') transtolueneF = Chem.MolFromMolFile('test_mols/transtoluene.mol') transtolueneF.SetProp('_Name', 'transtoluene-fuse') - victor = Victor.combine(hits=[toluene, transtolueneF], - pdb_filename=template, - covalent_resi='3A', # a random residue is still required for the constaint ref atom. - covalent_resn='VAL') - self.assertEqual(victor.error, '', victor.error) - gotten = Chem.MolToSmiles(Chem.RemoveHs(victor.minimised_mol)) + mol=Monster(hits=[toluene, transtolueneF]).combine(keep_all=True).positioned_mol + gotten = Chem.MolToSmiles(Chem.RemoveHs(mol)) self.assertEqual(gotten, after, f'{name} failed {gotten} (expected {after})') def test_spirodituluene(self): name = 'spirodituluene' - after = ('C[C@@H]1C=CC[C@]2(C=C[C@H](C)C=C2)C1', + after = ('CC1C=CC2(C=C1)CC=CC(C)C2', + 'C[C@@H]1C=CC[C@]2(C=C[C@H](C)C=C2)C1', 'C[C@@H]1C=CC[C@]2(C=C[C@@H](C)C=C2)C1', 'C[C@H]1C=CC[C@]2(C=C[C@H](C)C=C2)C1', 'C[C@H]1C=CC[C@]2(C=C[C@@H](C)C=C2)C1') - template = os.path.join(MProVictor.get_mpro_path(), 'template.pdb') toluene = Chem.MolFromMolFile('test_mols/toluene.mol') toluene.SetProp('_Name', 'toluene') transtolueneS = Chem.MolFromMolFile('test_mols/transtoluene2.mol') transtolueneS.SetProp('_Name', 'transtoluene-spiro') # cmd.rotate('z', -90, 'rototoluene', camera=0) - victor = Victor.combine(hits=[toluene, transtolueneS], - pdb_filename=template, - covalent_resi='3A', # a random residue is still required for the constaint ref atom. - covalent_resn='VAL') - self.assertEqual(victor.error, '', victor.error) - gotten = Chem.MolToSmiles(Chem.RemoveHs(victor.minimised_mol)) + mol=Monster(hits=[toluene, transtolueneS]).combine(keep_all=True).positioned_mol + gotten = Chem.MolToSmiles(Chem.RemoveHs(mol)) self.assertIn(gotten, after, f'{name} failed {gotten} (expected {after})') - def test_phenylene(self): - # make carboxy and amide benzenes that overlap so that the end result is a phenylene where one ring is oxazine - conjoined = Chem.MolFromSmiles('c3c1cccc2\C(=O)O/C(-N)c(c12)cc3') - before = Chem.MolToSmiles(conjoined) # structure from wiki is not canonical - AllChem.EmbedMolecule(conjoined) - bonds = [conjoined.GetBondBetweenAtoms(0, 1).GetIdx(), - conjoined.GetBondBetweenAtoms(12, 11).GetIdx(), - conjoined.GetBondBetweenAtoms(8, 9).GetIdx()] - fragged = Chem.FragmentOnBonds(conjoined, bonds, addDummies=False) - fore = Chem.GetMolFrags(fragged, asMols=True, sanitizeFrags=False)[1] - Chem.SanitizeMol(fore) - bonds = [conjoined.GetBondBetweenAtoms(2, 1).GetIdx(), - conjoined.GetBondBetweenAtoms(12, 5).GetIdx(), - conjoined.GetBondBetweenAtoms(8, 6).GetIdx()] - fragged = Chem.FragmentOnBonds(conjoined, bonds, addDummies=False) - aft = Chem.GetMolFrags(fragged, asMols=True, sanitizeFrags=False)[0] - Chem.SanitizeMol(aft) - # merge them - mol = Monster([fore, aft]).combine().positioned_mol - after = Chem.MolToSmiles(mol) - self.assertEqual(before, after) - # ---------------------------------------------------------------------------------------------------------------------- @@ -265,8 +264,9 @@ class UnresolvedProblems(unittest.TestCase): def test_recto_fail_A(self): """This used to fail.""" MProVictor.monster_throw_on_discard = True - victor = MProVictor.combine_codes(hit_codes=['x11612', 'x11475']) - self.assertEqual(victor.error, '', victor.error) + victor = MProVictor.from_hit_codes(hit_codes=['x11612', 'x11475']) + victor.combine() + self.assertEqual(victor.error_msg, '', victor.error_msg) def test_supplementary1_to_recto_fail_A(self): """