1 //
2 // Copyright (C) 2017-2020 Greg Landrum
3 //
4 // @@ All Rights Reserved @@
5 // This file is part of the RDKit.
6 // The contents are covered by the terms of the BSD license
7 // which is included in the file license.txt, found at the root
8 // of the RDKit source tree.
9 //
10 #include <iostream>
11
12 #include <fstream>
13 #include <GraphMol/RDKitBase.h>
14 #include <GraphMol/SmilesParse/SmilesParse.h>
15 #include <GraphMol/FileParsers/FileParsers.h>
16 #include <GraphMol/Substruct/SubstructMatch.h>
17 #include <GraphMol/MolAlign/AlignMolecules.h>
18 #include <GraphMol/MolTransforms/MolTransforms.h>
19 #include <GraphMol/ChemTransforms/ChemTransforms.h>
20
21 #include <RDGeneral/RDLog.h>
22
23 #include "coordgen/sketcherMinimizer.h"
24 #include <CoordGen/CoordGen.h>
25
26 using namespace RDKit;
27
test1()28 void test1() {
29 BOOST_LOG(rdInfoLog) << "-------------------------------------" << std::endl;
30 BOOST_LOG(rdInfoLog) << "test1: basics" << std::endl;
31 #if 1
32 {
33 ROMol* m = SmilesToMol("c1cc(CC)cnc1CC(=O)O");
34 TEST_ASSERT(m);
35 m->setProp("_Name", "test1");
36
37 TEST_ASSERT(CoordGen::addCoords(*m) == 0);
38 TEST_ASSERT(m->getNumConformers() == 1);
39 auto mb = MolToMolBlock(*m);
40 std::cerr << mb << std::endl;
41 delete m;
42 }
43 {
44 // ROMol* m = SmilesToMol("c1ccncc1");
45
46 ROMol* m = SmilesToMol("ClC(O)(F)C");
47 TEST_ASSERT(m);
48 m->setProp("_Name", "test2");
49
50 TEST_ASSERT(CoordGen::addCoords(*m) == 0);
51 TEST_ASSERT(m->getNumConformers() == 1);
52 auto mb = MolToMolBlock(*m);
53 std::cerr << mb << std::endl;
54 delete m;
55 }
56
57 {
58 ROMol* m = SmilesToMol(
59 "CC[C@H]1C(=O)N(CC(=O)N([C@H](C(=O)N[C@H](C(=O)N([C@H](C(=O)N[C@H](C(="
60 "O)N[C@@H](C(=O)N([C@H](C(=O)N([C@H](C(=O)N([C@H](C(=O)N([C@H](C(=O)N1)"
61 "[C@@H]([C@H](C)C/C=C/"
62 "C)O)C)C(C)C)C)CC(C)C)C)CC(C)C)C)C)C)CC(C)C)C)C(C)C)CC(C)C)C)C");
63 TEST_ASSERT(m);
64 m->setProp("_Name", "cyclosporine a");
65
66 TEST_ASSERT(CoordGen::addCoords(*m) == 0);
67 TEST_ASSERT(m->getNumConformers() == 1);
68 auto mb = MolToMolBlock(*m);
69 std::cerr << mb << std::endl;
70 delete m;
71 }
72
73 {
74 // ROMol* m = SmilesToMol("c1ccncc1");
75
76 ROMol* m = SmilesToMol("CCCNC=CNCOC=CC=CC=COC");
77 TEST_ASSERT(m);
78 m->setProp("_Name", "single-double");
79
80 TEST_ASSERT(CoordGen::addCoords(*m) == 0);
81 TEST_ASSERT(m->getNumConformers() == 1);
82 auto mb = MolToMolBlock(*m);
83 std::cerr << mb << std::endl;
84 delete m;
85 }
86 #endif
87
88 {
89 ROMol* m = SmilesToMol("O/C=C/C=C/C=C\\C=C/N");
90 TEST_ASSERT(m);
91 m->setProp("_Name", "cis-trans");
92
93 TEST_ASSERT(CoordGen::addCoords(*m) == 0);
94 TEST_ASSERT(m->getNumConformers() == 1);
95 auto mb = MolToMolBlock(*m);
96 std::cerr << mb << std::endl;
97 delete m;
98 }
99
100 {
101 ROMol* m = SmilesToMol("C1C3CC2CC(CC1C2)C3");
102 TEST_ASSERT(m);
103 m->setProp("_Name", "admntn");
104
105 TEST_ASSERT(CoordGen::addCoords(*m) == 0);
106 TEST_ASSERT(m->getNumConformers() == 1);
107 auto mb = MolToMolBlock(*m);
108 std::cerr << mb << std::endl;
109 delete m;
110 }
111
112 BOOST_LOG(rdInfoLog) << "done" << std::endl;
113 }
114
115 namespace {
compareConfs(const ROMol * m,ROMol * templ,const MatchVectType & mv,bool alignFirst=false,int molConfId=-1,int templateConfId=-1,double postol=1e-2,double rmstol=0.1)116 bool compareConfs(const ROMol* m, ROMol* templ, const MatchVectType& mv,
117 bool alignFirst = false, int molConfId = -1,
118 int templateConfId = -1, double postol = 1e-2,
119 double rmstol = 0.1) {
120 PRECONDITION(m, "bad pointer");
121 PRECONDITION(templ, "bad pointer");
122 TEST_ASSERT(m->getNumAtoms() >= templ->getNumAtoms());
123
124 if (alignFirst) {
125 double rmsd =
126 MolAlign::alignMol(*templ, *m, molConfId, templateConfId, &mv);
127 if (rmsd > rmstol) {
128 return false;
129 }
130 }
131
132 const Conformer& conf1 = m->getConformer(molConfId);
133 const Conformer& conf2 = templ->getConformer(templateConfId);
134 for (unsigned int i = 0; i < templ->getNumAtoms(); i++) {
135 TEST_ASSERT(m->getAtomWithIdx(mv[i].second)->getAtomicNum() ==
136 templ->getAtomWithIdx(mv[i].first)->getAtomicNum());
137
138 RDGeom::Point3D pt1i = conf1.getAtomPos(mv[i].second);
139 RDGeom::Point3D pt2i = conf2.getAtomPos(mv[i].first);
140 if ((pt1i - pt2i).length() >= postol) {
141 return false;
142 }
143 }
144 return true;
145 }
146 } // namespace
147
test2()148 void test2() {
149 BOOST_LOG(rdInfoLog) << "-------------------------------------" << std::endl;
150 BOOST_LOG(rdInfoLog) << "test2: using templates" << std::endl;
151
152 {
153 ROMol* core = SmilesToMol("C1CON1");
154 TEST_ASSERT(core);
155 core->setProp("_Name", "core");
156
157 TEST_ASSERT(CoordGen::addCoords(*core) == 0);
158 TEST_ASSERT(core->getNumConformers() == 1);
159 auto mb = MolToMolBlock(*core);
160 std::cerr << mb << std::endl;
161
162 ROMol* m = SmilesToMol("C1C(CCC)ON1");
163 TEST_ASSERT(m);
164 m->setProp("_Name", "core+sidechain");
165
166 MatchVectType mv;
167 SubstructMatch(*m, *core, mv);
168
169 TEST_ASSERT(CoordGen::addCoords(*m) == 0);
170 TEST_ASSERT(m->getNumConformers() == 1);
171 mb = MolToMolBlock(*m);
172 std::cerr << mb << std::endl;
173 TEST_ASSERT(!compareConfs(m, core, mv));
174
175 {
176 auto coreConf = core->getConformer();
177 RDGeom::INT_POINT2D_MAP coordMap;
178 for (auto& i : mv) {
179 coordMap[i.second] = RDGeom::Point2D(coreConf.getAtomPos(i.first).x,
180 coreConf.getAtomPos(i.first).y);
181 }
182 CoordGen::CoordGenParams params;
183 params.coordMap = coordMap;
184 params.dbg_useFixed = true;
185 TEST_ASSERT(CoordGen::addCoords(*m, ¶ms) == 0);
186 TEST_ASSERT(m->getNumConformers() == 1);
187 // m->setProp("_Name", "templated");
188 // mb = MolToMolBlock(*m);
189 // std::cerr << mb << std::endl;
190 TEST_ASSERT(compareConfs(m, core, mv));
191 }
192 {
193 CoordGen::CoordGenParams params;
194 params.templateMol = core;
195 params.dbg_useFixed = true;
196 TEST_ASSERT(CoordGen::addCoords(*m, ¶ms) == 0);
197 TEST_ASSERT(m->getNumConformers() == 1);
198 m->setProp("_Name", "templated");
199 mb = MolToMolBlock(*m);
200 std::cerr << mb << std::endl;
201 TEST_ASSERT(compareConfs(m, core, mv));
202 }
203 delete m;
204 delete core;
205 }
206
207 {
208 ROMol* core = SmilesToMol("C1CCCCCONCN1");
209 TEST_ASSERT(core);
210 core->setProp("_Name", "core");
211
212 TEST_ASSERT(CoordGen::addCoords(*core) == 0);
213 TEST_ASSERT(core->getNumConformers() == 1);
214 auto mb = MolToMolBlock(*core);
215 std::cerr << mb << std::endl;
216
217 ROMol* m = SmilesToMol("C1CCCCONC(CC)NC1");
218 TEST_ASSERT(m);
219 m->setProp("_Name", "core+sidechain");
220
221 MatchVectType mv;
222 SubstructMatch(*m, *core, mv);
223
224 TEST_ASSERT(CoordGen::addCoords(*m) == 0);
225 TEST_ASSERT(m->getNumConformers() == 1);
226 mb = MolToMolBlock(*m);
227 std::cerr << mb << std::endl;
228 TEST_ASSERT(!compareConfs(m, core, mv));
229
230 {
231 auto coreConf = core->getConformer();
232 RDGeom::INT_POINT2D_MAP coordMap;
233 for (auto& i : mv) {
234 coordMap[i.second] = RDGeom::Point2D(coreConf.getAtomPos(i.first).x,
235 coreConf.getAtomPos(i.first).y);
236 }
237 CoordGen::CoordGenParams params;
238 params.coordMap = coordMap;
239 params.dbg_useFixed = true;
240 TEST_ASSERT(CoordGen::addCoords(*m, ¶ms) == 0);
241 TEST_ASSERT(m->getNumConformers() == 1);
242 // m->setProp("_Name", "templated");
243 // mb = MolToMolBlock(*m);
244 // std::cerr << mb << std::endl;
245 TEST_ASSERT(compareConfs(m, core, mv));
246 }
247 {
248 CoordGen::CoordGenParams params;
249 params.templateMol = core;
250 params.dbg_useFixed = true;
251 TEST_ASSERT(CoordGen::addCoords(*m, ¶ms) == 0);
252 TEST_ASSERT(m->getNumConformers() == 1);
253 m->setProp("_Name", "templated");
254 mb = MolToMolBlock(*m);
255 std::cerr << mb << std::endl;
256 TEST_ASSERT(compareConfs(m, core, mv));
257 }
258
259 delete m;
260 delete core;
261 }
262
263 {
264 ROMol* core = SmilesToMol("C1CCCCCONCN1");
265 TEST_ASSERT(core);
266 core->setProp("_Name", "core");
267
268 TEST_ASSERT(CoordGen::addCoords(*core) == 0);
269 TEST_ASSERT(core->getNumConformers() == 1);
270 auto mb = MolToMolBlock(*core);
271 std::cerr << mb << std::endl;
272
273 ROMol* m = SmilesToMol("C1CCCCONC(CCCCCC)NC1");
274 TEST_ASSERT(m);
275 m->setProp("_Name", "core+sidechain");
276
277 MatchVectType mv;
278 SubstructMatch(*m, *core, mv);
279
280 TEST_ASSERT(CoordGen::addCoords(*m) == 0);
281 TEST_ASSERT(m->getNumConformers() == 1);
282 mb = MolToMolBlock(*m);
283 std::cerr << mb << std::endl;
284 TEST_ASSERT(!compareConfs(m, core, mv));
285
286 {
287 auto coreConf = core->getConformer();
288 RDGeom::INT_POINT2D_MAP coordMap;
289 for (auto& i : mv) {
290 coordMap[i.second] = RDGeom::Point2D(coreConf.getAtomPos(i.first).x,
291 coreConf.getAtomPos(i.first).y);
292 }
293
294 CoordGen::CoordGenParams params;
295 params.coordMap = coordMap;
296 params.dbg_useFixed = true;
297 TEST_ASSERT(CoordGen::addCoords(*m, ¶ms) == 0);
298 TEST_ASSERT(m->getNumConformers() == 1);
299 // m->setProp("_Name", "templated");
300 // mb = MolToMolBlock(*m);
301 // std::cerr << mb << std::endl;
302 TEST_ASSERT(compareConfs(m, core, mv));
303 }
304 {
305 CoordGen::CoordGenParams params;
306 params.templateMol = core;
307 params.dbg_useFixed = true;
308 TEST_ASSERT(CoordGen::addCoords(*m, ¶ms) == 0);
309 TEST_ASSERT(m->getNumConformers() == 1);
310 m->setProp("_Name", "templated");
311 mb = MolToMolBlock(*m);
312 std::cerr << mb << std::endl;
313 TEST_ASSERT(compareConfs(m, core, mv));
314 }
315 delete m;
316 delete core;
317 }
318
319 {
320 ROMol* core = SmilesToMol("C1CCCC2C1NCC2");
321 TEST_ASSERT(core);
322 core->setProp("_Name", "core");
323
324 CoordGen::addCoords(*core);
325 TEST_ASSERT(core->getNumConformers() == 1);
326 auto mb = MolToMolBlock(*core);
327 std::cerr << mb << std::endl;
328
329 ROMol* m = SmilesToMol("C1C(CCC)CC(CC3CC3)C2C1N(C(C)C)CC2");
330 TEST_ASSERT(m);
331 m->setProp("_Name", "core+sidechain");
332
333 MatchVectType mv;
334 SubstructMatch(*m, *core, mv);
335
336 CoordGen::addCoords(*m);
337 TEST_ASSERT(m->getNumConformers() == 1);
338 mb = MolToMolBlock(*m);
339 std::cerr << mb << std::endl;
340 // This is a rigid core: if we provide the matching substructure,
341 // and do alignment, the conformations will still match.
342 TEST_ASSERT(!compareConfs(m, core, mv, false));
343
344 {
345 CoordGen::CoordGenParams params;
346 params.templateMol = core;
347 CoordGen::addCoords(*m, ¶ms);
348 TEST_ASSERT(m->getNumConformers() == 1);
349 m->setProp("_Name", "templated");
350 mb = MolToMolBlock(*m);
351 std::cerr << mb << std::endl;
352 TEST_ASSERT(compareConfs(m, core, mv, true, -1, -1, 0.3));
353 }
354 delete m;
355 delete core;
356 }
357
358 {
359 ROMol* core = SmilesToMol("CC(N)CC");
360 TEST_ASSERT(core);
361 core->setProp("_Name", "core");
362
363 CoordGen::addCoords(*core);
364 TEST_ASSERT(core->getNumConformers() == 1);
365 auto mb = MolToMolBlock(*core);
366 std::cerr << mb << std::endl;
367
368 ROMol* m = SmilesToMol("CC(N)CC(O)C");
369 TEST_ASSERT(m);
370 m->setProp("_Name", "core+sidechain");
371
372 MatchVectType mv;
373 SubstructMatch(*m, *core, mv);
374
375 CoordGen::addCoords(*m);
376 TEST_ASSERT(m->getNumConformers() == 1);
377 mb = MolToMolBlock(*m);
378 std::cerr << mb << std::endl;
379 // This mol is just slightly bigger than the core, providing
380 // the matching substructure and doing alignment will cause
381 // the conformations to match.
382 TEST_ASSERT(!compareConfs(m, core, mv, false));
383
384 {
385 CoordGen::CoordGenParams params;
386 params.templateMol = core;
387 CoordGen::addCoords(*m, ¶ms);
388 TEST_ASSERT(m->getNumConformers() == 1);
389 m->setProp("_Name", "templated");
390 mb = MolToMolBlock(*m);
391 std::cerr << mb << std::endl;
392 TEST_ASSERT(compareConfs(m, core, mv, true, -1, -1, 0.05));
393 }
394 delete m;
395 delete core;
396 }
397
398 BOOST_LOG(rdInfoLog) << "done" << std::endl;
399 }
400
testGithub1929()401 void testGithub1929() {
402 BOOST_LOG(rdInfoLog) << "-------------------------------------" << std::endl;
403 BOOST_LOG(rdInfoLog)
404 << "testing github1929: make sure coordgen works with bogus file names"
405 << std::endl;
406 {
407 ROMol* m = SmilesToMol("c1cc(CC)cnc1CC(=O)O");
408 TEST_ASSERT(m);
409 m->setProp("_Name", "test1");
410 CoordGen::CoordGenParams params;
411 params.templateFileDir = "I_do_not_exist";
412
413 TEST_ASSERT(CoordGen::addCoords(*m, ¶ms) == 0);
414 TEST_ASSERT(m->getNumConformers() == 1);
415 delete m;
416 }
417
418 BOOST_LOG(rdInfoLog) << "done" << std::endl;
419 }
420
testGithub3131()421 void testGithub3131() {
422 BOOST_LOG(rdInfoLog) << "-------------------------------------" << std::endl;
423 BOOST_LOG(rdInfoLog)
424 << "testing github3131: results from coordgen are sometimes not centered"
425 << std::endl;
426 {
427 auto m1 =
428 "CC1=C(C=C(C=C1)NC(=O)C2=CC=C(C=C2)CN3CCN(CC3)C)NC4=NC=CC(=N4)C5=CN=CC="
429 "C5"_smiles;
430 TEST_ASSERT(m1);
431 TEST_ASSERT(CoordGen::addCoords(*m1) == 0);
432 TEST_ASSERT(m1->getNumConformers() == 1);
433 auto center = MolTransforms::computeCentroid(m1->getConformer());
434 TEST_ASSERT(feq(center.x, 0.0));
435 TEST_ASSERT(feq(center.y, 0.0));
436 }
437
438 {
439 auto m1 =
440 "CCC1=C2N=C(C=C(N2N=C1)NCC3=C[N+](=CC=C3)[O-])N4CCCC[C@H]4CCO"_smiles;
441 TEST_ASSERT(m1);
442 TEST_ASSERT(CoordGen::addCoords(*m1) == 0);
443 TEST_ASSERT(m1->getNumConformers() == 1);
444 auto center = MolTransforms::computeCentroid(m1->getConformer());
445 TEST_ASSERT(feq(center.x, 0.0));
446 TEST_ASSERT(feq(center.y, 0.0));
447 }
448
449 {
450 // make sure that it's not recentered if we provide a coordmap:
451 auto m1 =
452 "CCC1=C2N=C(C=C(N2N=C1)NCC3=C[N+](=CC=C3)[O-])N4CCCC[C@H]4CCO"_smiles;
453 TEST_ASSERT(m1);
454 CoordGen::CoordGenParams params;
455 params.coordMap[0] = {10.0, 10.0};
456 params.coordMap[1] = {11.0, 10.0};
457 TEST_ASSERT(CoordGen::addCoords(*m1, ¶ms) == 0);
458 TEST_ASSERT(m1->getNumConformers() == 1);
459 auto center = MolTransforms::computeCentroid(m1->getConformer());
460 TEST_ASSERT(!feq(center.x, 0.0));
461 TEST_ASSERT(!feq(center.y, 0.0));
462 }
463
464 {
465 // make sure that it's not recentered if we provide a template:
466 auto templateMol =
467 "C1=C2N=C(C=C(N2N=C1)NCC3=C[N+](=CC=C3))N4CCCC[C@H]4"_smiles;
468 TEST_ASSERT(templateMol);
469 TEST_ASSERT(CoordGen::addCoords(*templateMol) == 0);
470 TEST_ASSERT(templateMol->getNumConformers() == 1);
471
472 auto center = MolTransforms::computeCentroid(templateMol->getConformer());
473 TEST_ASSERT(feq(center.x, 0.0));
474 TEST_ASSERT(feq(center.y, 0.0));
475
476 auto m1 =
477 "CCC1=C2N=C(C=C(N2N=C1)NCC3=C[N+](=CC=C3)[O-])N4CCCC[C@H]4CCO"_smiles;
478 TEST_ASSERT(m1);
479 CoordGen::CoordGenParams params;
480 params.templateMol = templateMol.get();
481 TEST_ASSERT(CoordGen::addCoords(*m1, ¶ms) == 0);
482 TEST_ASSERT(m1->getNumConformers() == 1);
483 center = MolTransforms::computeCentroid(m1->getConformer());
484 TEST_ASSERT(!feq(center.x, 0.0));
485 TEST_ASSERT(!feq(center.y, 0.0));
486 }
487
488 BOOST_LOG(rdInfoLog) << "done" << std::endl;
489 }
490
testCoordgenMinimize()491 void testCoordgenMinimize() {
492 BOOST_LOG(rdInfoLog) << "-------------------------------------" << std::endl;
493 BOOST_LOG(rdInfoLog) << "testing coordgen minimize" << std::endl;
494 {
495 auto m1 =
496 R"CTAB(
497 Mrv2014 08052005142D
498
499 0 0 0 0 0 999 V3000
500 M V30 BEGIN CTAB
501 M V30 COUNTS 8 8 0 0 0
502 M V30 BEGIN ATOM
503 M V30 1 C -2.1121 -0.3399 0 0
504 M V30 2 C -3.3708 0.5474 0 0
505 M V30 3 C -1.9835 0.9311 0 0
506 M V30 4 C -0.7248 0.0437 0 0
507 M V30 5 C 0.7926 0.3064 0 0
508 M V30 6 O 1.3239 1.7518 0 0
509 M V30 7 O 0.612 -1.2514 0 0
510 M V30 8 C 1.3429 -0.2989 0 0
511 M V30 END ATOM
512 M V30 BEGIN BOND
513 M V30 1 1 1 2
514 M V30 2 1 2 3
515 M V30 3 1 3 4
516 M V30 4 1 4 5
517 M V30 5 2 5 6
518 M V30 6 1 5 7
519 M V30 7 1 7 8
520 M V30 8 1 4 1
521 M V30 END BOND
522 M V30 END CTAB
523 M END
524 )CTAB"_ctab;
525 TEST_ASSERT(m1);
526 TEST_ASSERT(m1->getNumConformers() == 1);
527 auto ref = R"CTAB(
528 RDKit 2D
529
530 8 8 0 0 0 0 0 0 0 0999 V2000
531 -1.5738 -1.1409 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
532 -2.7946 -0.3071 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
533 -1.9122 0.8790 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
534 -0.6914 0.0452 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
535 0.7517 0.2885 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
536 1.2665 1.6721 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0
537 1.6941 -0.8483 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0
538 3.1500 -0.6002 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
539 1 2 1 0
540 2 3 1 0
541 3 4 1 0
542 4 5 1 0
543 5 6 2 0
544 5 7 1 0
545 7 8 1 0
546 4 1 1 0
547 M END
548 )CTAB"_ctab;
549 TEST_ASSERT(ref);
550 TEST_ASSERT(ref->getNumConformers() == 1);
551
552 CoordGen::CoordGenParams ps;
553 ps.minimizeOnly = true;
554 CoordGen::addCoords(*m1, &ps);
555 ROMol m2(*m1);
556 double rmsd = MolAlign::alignMol(m2, *ref);
557 TEST_ASSERT(rmsd < 0.1);
558 }
559 BOOST_LOG(rdInfoLog) << "done" << std::endl;
560 }
561
testZOBs()562 void testZOBs() {
563 BOOST_LOG(rdInfoLog) << "-------------------------------------" << std::endl;
564 BOOST_LOG(rdInfoLog) << "testing the zero-order bond setting with coordgen"
565 << std::endl;
566 {
567 auto m1 =
568 R"CTAB(
569 RDKit 2D
570
571 0 0 0 0 0 0 0 0 0 0999 V3000
572 M V30 BEGIN CTAB
573 M V30 COUNTS 8 7 0 0 0
574 M V30 BEGIN ATOM
575 M V30 1 Al 0.108450 -0.062175 0.000000 0 VAL=3
576 M V30 2 C 0.976250 -0.558975 0.000000 0
577 M V30 3 C 0.104850 0.937825 0.000000 0
578 M V30 4 C -0.755750 -0.565175 0.000000 0
579 M V30 5 C 1.840650 -0.055775 0.000000 0
580 M V30 6 C -1.623550 -0.068375 0.000000 0
581 M V30 7 C -2.487750 -0.571375 0.000000 0
582 M V30 8 C 1.836850 0.944025 0.000000 0
583 M V30 END ATOM
584 M V30 BEGIN BOND
585 M V30 1 1 1 2
586 M V30 2 1 1 3
587 M V30 3 1 1 4
588 M V30 4 2 2 5
589 M V30 5 2 4 6
590 M V30 6 1 6 7
591 M V30 7 1 5 8
592 M V30 END BOND
593 M V30 END CTAB
594 M END
595 )CTAB"_ctab;
596 TEST_ASSERT(m1);
597 TEST_ASSERT(m1->getNumConformers() == 1);
598 CoordGen::addCoords(*m1);
599 TEST_ASSERT(m1->getNumConformers() == 1);
600 {
601 std::unique_ptr<ROMol> nm{MolBlockToMol(MolToMolBlock(*m1))};
602 TEST_ASSERT(nm);
603 TEST_ASSERT(nm->getBondWithIdx(3)->getStereo() ==
604 m1->getBondWithIdx(3)->getStereo());
605 TEST_ASSERT(nm->getBondWithIdx(4)->getStereo() ==
606 m1->getBondWithIdx(4)->getStereo());
607 }
608
609 CoordGen::CoordGenParams ps;
610 ps.treatNonterminalBondsToMetalAsZeroOrder = true;
611 CoordGen::addCoords(*m1, &ps);
612 {
613 // the ZOB behavior screws up the double bond stereo here... detect that
614 std::unique_ptr<ROMol> nm{MolBlockToMol(MolToMolBlock(*m1))};
615 TEST_ASSERT(nm);
616 TEST_ASSERT(nm->getBondWithIdx(3)->getStereo() !=
617 m1->getBondWithIdx(3)->getStereo());
618 TEST_ASSERT(nm->getBondWithIdx(4)->getStereo() !=
619 m1->getBondWithIdx(4)->getStereo());
620 }
621 }
622 BOOST_LOG(rdInfoLog) << "done" << std::endl;
623 }
624
main(int argc,char * argv[])625 int main(int argc, char* argv[]) {
626 (void)argc;
627 (void)argv;
628 RDLog::InitLogs();
629 #if 1
630 test2();
631 test1();
632 testGithub1929();
633 testGithub3131();
634 #endif
635 testCoordgenMinimize();
636 testZOBs();
637 }
638