19package denoptim.graph;
21import static org.junit.jupiter.api.Assertions.assertEquals;
22import static org.junit.jupiter.api.Assertions.assertSame;
23import static org.junit.jupiter.api.Assertions.assertThrows;
24import static org.junit.jupiter.api.Assertions.assertTrue;
25import static org.junit.jupiter.api.Assertions.fail;
28import java.util.ArrayList;
29import java.util.Arrays;
31import java.util.Random;
33import javax.vecmath.Point3d;
35import org.junit.jupiter.api.Test;
36import org.junit.jupiter.api.io.TempDir;
37import org.openscience.cdk.DefaultChemObjectBuilder;
38import org.openscience.cdk.exception.CDKException;
39import org.openscience.cdk.geometry.alignment.KabschAlignment;
40import org.openscience.cdk.interfaces.IAtom;
41import org.openscience.cdk.interfaces.IAtomContainer;
42import org.openscience.cdk.interfaces.IBond;
43import org.openscience.cdk.interfaces.IChemObjectBuilder;
45import denoptim.exception.DENOPTIMException;
46import denoptim.graph.Vertex.BBType;
47import denoptim.io.DenoptimIO;
48import denoptim.utils.GraphUtils;
49import denoptim.utils.MoleculeUtils;
59 static IChemObjectBuilder
chemBuilder = DefaultChemObjectBuilder.getInstance();
64 private final String
NL = System.getProperty(
"line.separator");
65 private final String
SEP = System.getProperty(
"file.separator");
97 Ring r =
new Ring(
new ArrayList<Vertex>(
98 Arrays.asList(vRcvA, vA, vB, vC, vRcvC)));
110 "Different #free APs");
111 assertEquals(
"PROVALUE",c.
getProperty(
"PROPNAME"));
116 assertTrue(oriAP.hashCode() != cloAP.hashCode(),
"Hashcode of APs");
124 assertTrue(oriIG.hashCode() != cloIG.hashCode(),
125 "InnerGraph graph hash");
132 assertTrue(ov.hashCode() != cv.hashCode(),
"InnerGraph vertex hash");
137 assertEquals(oriIG.
getRings().get(0).getSize(),
138 cloIG.
getRings().get(0).getSize(),
"InnerGraph ring count");
148 assertTrue(t.
sameAs(clone,
new StringBuilder()));
150 fail(
"Unexpected exception thrown.");
198 IAtomContainer atomContainer =
chemBuilder.newAtomContainer();
199 String[] elements =
new String[]{
"C",
"H",
"H"};
200 Point3d[] atmCoords =
new Point3d[]{
201 new Point3d(0.0, 0.0, 0.0),
202 new Point3d(0.0000, -0.8900, -0.6293),
203 new Point3d(0.0000, 0.8900, -0.6293),
205 for (
int i=0; i<elements.length; i++) {
207 atom.setSymbol(elements[i]);
208 atom.setPoint3d(atmCoords[i]);
209 atomContainer.addAtom(atom);
211 atomContainer.addBond(0, 1, IBond.Order.SINGLE);
212 atomContainer.addBond(0, 2, IBond.Order.SINGLE);
219 Point3d[] apCoords =
new Point3d[]{
220 new Point3d(-0.8900, 0.0000, 0.6293),
221 new Point3d(0.8900, 0.0000, 0.6293),
223 for (
int i = 0; i < 2; i++) {
225 v.
addAP(0, apClass, apCoords[i]);
240 IAtomContainer atomContainer =
chemBuilder.newAtomContainer();
241 String[] elements =
new String[]{
"C",
"O",
"N"};
242 Point3d[] atmCoords =
new Point3d[]{
243 new Point3d(0.6748, -0.1898, -0.0043),
244 new Point3d(1.0460, -1.3431, -0.0581),
245 new Point3d(-0.6427, 0.0945, -0.0002),
247 for (
int i=0; i<elements.length; i++) {
249 atom.setSymbol(elements[i]);
250 atom.setPoint3d(atmCoords[i]);
251 atomContainer.addAtom(atom);
253 atomContainer.addBond(0, 1, IBond.Order.DOUBLE);
254 atomContainer.addBond(0, 2, IBond.Order.SINGLE);
261 Point3d[] apCoords =
new Point3d[]{
262 new Point3d(1.6864, 0.9254, 0.0580),
263 new Point3d(-1.6259, -0.9902, 0.0560),
264 new Point3d(-1.0915, 1.4881, -0.0518),
266 int[] srcAtm =
new int[] {0, 2, 2};
271 for (
int i = 0; i < 3; i++) {
272 v.
addAP(srcAtm[i], apClass[i],apCoords[i]);
284 IAtomContainer atomContainer =
chemBuilder.newAtomContainer();
285 String[] elements =
new String[]{
"O",
"H"};
286 for (String e : elements) {
289 atomContainer.addAtom(atom);
292 atomContainer.addBond(0, 1, IBond.Order.SINGLE);
298 double precision = 10*10*10*10;
304 (
double) (Math.round(
rng.nextDouble() * precision)) / precision,
305 (
double) (Math.round(
rng.nextDouble() * precision)) / precision,
306 (
double) (Math.round(
rng.nextDouble() * precision)) / precision)
322 template.setInnerGraph(innerGraph);
324 int totalAPCount = 1;
325 for (
int i = 0; i < totalAPCount; i++) {
328 assertSame(template, actualOwner);
340 int requiredAPCount = 2;
345 for (
int i = 0; i < requiredAPCount; i++) {
346 template.addRequiredAP(
null,
null);
348 for (
int i = 0; i < v1APCount; i++) {
351 for (
int i = 0; i < v2APCount; i++) {
357 template.setInnerGraph(innerGraph);
362 int expectedAPCount = v1APCount + v2APCount - 2;
363 int actualAPCount =
template.getAttachmentPoints().size();
364 assertEquals(expectedAPCount, actualAPCount);
373 List<Point3d> dirVecs = Arrays.asList(
374 new Point3d(1.0, -2.1,3.2),
375 new Point3d(-2.0, 1.1, -3.2)
377 List<APClass> APClasses = Arrays.asList(
385 for (
int i = 0; i < numberOfAPs; i++) {
386 template.addRequiredAP(dirVecs.get(i),
388 v.
addAP(APClasses.get(i));
405 assertThrows(IllegalArgumentException.class,
407 }
catch (Exception e) {
408 fail(
"Expected " + IllegalArgumentException.class +
", but was "
419 for (
int i = 0; i < expNumberOfAPs - 1; i++) {
424 assertThrows(IllegalArgumentException.class,
425 () -> t.setInnerGraph(innerGraph));
435 assertThrows(IllegalArgumentException.class, () -> t.
addRequiredAP(
486 String[] elements =
new String[]{
"C",
"H",
"N",
"O"};
487 int[] expected =
new int[]{5, 8, 1, 1};
488 for (
int i=0; i<elements.length; i++)
490 assertEquals(expected[i],
492 "Number of '" + elements[i] +
"'.");
495 String refGeometry =
NL +
496 " CDK 04132117333D" +
NL +
498 " 15 14 0 0 0 0 0 0 0 0999 V2000" +
NL +
499 " 0.0000 0.0000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0" +
NL +
500 " 0.0000 -0.8900 -0.6293 H 0 0 0 0 0 0 0 0 0 0 0 0" +
NL +
501 " 0.0000 0.8900 -0.6293 H 0 0 0 0 0 0 0 0 0 0 0 0" +
NL +
502 " -1.0602 0.0000 0.7497 C 0 0 0 0 0 0 0 0 0 0 0 0" +
NL +
503 " -1.4136 -1.0211 1.3004 O 0 0 0 0 0 0 0 0 0 0 0 0" +
NL +
504 " -1.7681 1.1349 0.9158 N 0 0 0 0 0 0 0 0 0 0 0 0" +
NL +
505 " 0.8900 0.0000 0.6293 C 0 0 0 0 0 0 0 0 0 0 0 0" +
NL +
506 " 0.8900 -0.8900 1.2586 H 0 0 0 0 0 0 0 0 0 0 0 0" +
NL +
507 " 0.8900 0.8900 1.2586 H 0 0 0 0 0 0 0 0 0 0 0 0" +
NL +
508 " 1.7800 0.0000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0" +
NL +
509 " 2.3733 -0.8900 0.2098 H 0 0 0 0 0 0 0 0 0 0 0 0" +
NL +
510 " 2.3733 0.8900 0.2098 H 0 0 0 0 0 0 0 0 0 0 0 0" +
NL +
511 " 1.4834 0.0000 -1.0489 C 0 0 0 0 0 0 0 0 0 0 0 0" +
NL +
512 " 0.8901 -0.8900 -1.2587 H 0 0 0 0 0 0 0 0 0 0 0 0" +
NL +
513 " 0.8901 0.8900 -1.2587 H 0 0 0 0 0 0 0 0 0 0 0 0" +
NL +
514 " 1 2 1 0 0 0 0" +
NL +
515 " 1 3 1 0 0 0 0" +
NL +
516 " 4 5 2 0 0 0 0" +
NL +
517 " 4 6 1 0 0 0 0" +
NL +
518 " 1 4 1 0 0 0 0" +
NL +
519 " 7 8 1 0 0 0 0" +
NL +
520 " 7 9 1 0 0 0 0" +
NL +
521 " 1 7 1 0 0 0 0" +
NL +
522 " 10 11 1 0 0 0 0" +
NL +
523 " 10 12 1 0 0 0 0" +
NL +
524 " 7 10 1 0 0 0 0" +
NL +
525 " 13 14 1 0 0 0 0" +
NL +
526 " 13 15 1 0 0 0 0" +
NL +
527 " 10 13 1 0 0 0 0" +
NL +
530 assertTrue(this.tempDir.isDirectory(),
"Should be a directory ");
531 String fileName =
tempDir.getAbsolutePath() +
SEP +
"refMol.sdf";
536 KabschAlignment sa =
null;
538 sa =
new KabschAlignment(refMol,mol);
540 }
catch (CDKException e){
542 fail(
"KabschAlignment failed: "+e.getMessage());
544 assertTrue(sa.getRMSD()<0.0001,
"RMSD between generated and expected "
548 Point3d[] expectedAPHeads =
new Point3d[] {
549 new Point3d(-2.8954,1.1648,1.8510),
550 new Point3d(-1.4101,2.3385,0.1613),
551 new Point3d(2.3734,0.0000,-1.6782)};
554 Point3d apHead =
new Point3d(ap.getDirectionVector());
555 boolean found =
false;
556 double[] dists =
new double[3];
557 for (
int i=0; i<expectedAPHeads.length; i++)
559 Point3d expectedAPHead = expectedAPHeads[i];
560 double dist = apHead.distance(expectedAPHead);
568 assertTrue(found,
"Inconsistent placement of outer AP (errors: "
569 + dists[0] +
", " + dists[1] +
", " + dists[2] +
"). "
579 for (
int i =0; i<10; i++)
606 String[] elements =
new String[]{
"C",
"H",
"N",
"O"};
607 int[] expected =
new int[]{15, 28, 1, 1};
608 for (
int i=0; i<elements.length; i++)
610 assertEquals(expected[i],
612 "Number of '" + elements[i] +
"'.");
615 String refGeometry =
NL +
616 " CDK 02222322323D" +
NL +
618 " 45 44 0 0 0 0 0 0 0 0999 V2000" +
NL +
619 " 0.0000 0.0000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0" +
NL +
620 " 0.0000 -0.8900 -0.6293 H 0 0 0 0 0 0 0 0 0 0 0 0" +
NL +
621 " 0.0000 0.8900 -0.6293 H 0 0 0 0 0 0 0 0 0 0 0 0" +
NL +
622 " -1.0602 0.0000 0.7497 C 0 0 0 0 0 0 0 0 0 0 0 0" +
NL +
623 " -1.4136 -1.0211 1.3004 O 0 0 0 0 0 0 0 0 0 0 0 0" +
NL +
624 " -1.7681 1.1349 0.9158 N 0 0 0 0 0 0 0 0 0 0 0 0" +
NL +
625 " 0.8900 0.0000 0.6293 C 0 0 0 0 0 0 0 0 0 0 0 0" +
NL +
626 " 0.8900 -0.8900 1.2586 H 0 0 0 0 0 0 0 0 0 0 0 0" +
NL +
627 " 0.8900 0.8900 1.2586 H 0 0 0 0 0 0 0 0 0 0 0 0" +
NL +
628 " 1.7800 0.0000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0" +
NL +
629 " 2.3733 -0.8900 0.2098 H 0 0 0 0 0 0 0 0 0 0 0 0" +
NL +
630 " 2.3733 0.8900 0.2098 H 0 0 0 0 0 0 0 0 0 0 0 0" +
NL +
631 " 1.4834 0.0000 -1.0489 C 0 0 0 0 0 0 0 0 0 0 0 0" +
NL +
632 " 0.8901 -0.8900 -1.2587 H 0 0 0 0 0 0 0 0 0 0 0 0" +
NL +
633 " 0.8901 0.8900 -1.2587 H 0 0 0 0 0 0 0 0 0 0 0 0" +
NL +
634 " -2.7511 1.1609 1.7313 C 0 0 0 0 0 0 0 0 0 0 0 0" +
NL +
635 " -2.4728 0.6487 2.6523 H 0 0 0 0 0 0 0 0 0 0 0 0" +
NL +
636 " -3.0101 2.1958 1.9552 H 0 0 0 0 0 0 0 0 0 0 0 0" +
NL +
637 " -1.4559 2.1845 0.2578 C 0 0 0 0 0 0 0 0 0 0 0 0" +
NL +
638 " -1.2473 1.9156 -0.7777 H 0 0 0 0 0 0 0 0 0 0 0 0" +
NL +
639 " -2.2838 2.8928 0.2896 H 0 0 0 0 0 0 0 0 0 0 0 0" +
NL +
640 " 2.3734 0.0000 -1.6782 C 0 0 0 0 0 0 0 0 0 0 0 0" +
NL +
641 " 2.3734 -0.8900 -2.3075 H 0 0 0 0 0 0 0 0 0 0 0 0" +
NL +
642 " 2.3734 0.8900 -2.3075 H 0 0 0 0 0 0 0 0 0 0 0 0" +
NL +
643 " -3.6091 0.6606 1.2823 C 0 0 0 0 0 0 0 0 0 0 0 0" +
NL +
644 " -4.2319 0.2324 2.0677 H 0 0 0 0 0 0 0 0 0 0 0 0" +
NL +
645 " -4.1916 1.3822 0.7094 H 0 0 0 0 0 0 0 0 0 0 0 0" +
NL +
646 " -0.5703 2.6407 0.7002 C 0 0 0 0 0 0 0 0 0 0 0 0" +
NL +
647 " 0.3217 2.1322 0.3340 H 0 0 0 0 0 0 0 0 0 0 0 0" +
NL +
648 " -0.5275 3.6941 0.4234 H 0 0 0 0 0 0 0 0 0 0 0 0" +
NL +
649 " 3.2634 0.0000 -1.0489 C 0 0 0 0 0 0 0 0 0 0 0 0" +
NL +
650 " 3.8567 -0.8900 -1.2587 H 0 0 0 0 0 0 0 0 0 0 0 0" +
NL +
651 " 3.8567 0.8900 -1.2587 H 0 0 0 0 0 0 0 0 0 0 0 0" +
NL +
652 " -3.2617 -0.1330 0.6208 C 0 0 0 0 0 0 0 0 0 0 0 0" +
NL +
653 " -4.0122 -0.9222 0.5749 H 0 0 0 0 0 0 0 0 0 0 0 0" +
NL +
654 " -3.0987 0.2719 -0.3780 H 0 0 0 0 0 0 0 0 0 0 0 0" +
NL +
655 " -0.6194 2.5519 1.7855 C 0 0 0 0 0 3 0 0 0 0 0 0" +
NL +
656 " -0.2733 1.5626 2.0851 H 0 0 0 0 0 0 0 0 0 0 0 0" +
NL +
657 " 0.0148 3.3122 2.2413 H 0 0 0 0 0 0 0 0 0 0 0 0" +
NL +
658 " 2.9668 0.0000 0.0000 C 0 0 0 0 0 3 0 0 0 0 0 0" +
NL +
659 " 3.3624 -0.8900 0.4894 H 0 0 0 0 0 0 0 0 0 0 0 0" +
NL +
660 " 3.3624 0.8900 0.4894 H 0 0 0 0 0 0 0 0 0 0 0 0" +
NL +
661 " -2.3270 -0.5423 1.0039 C 0 0 0 0 0 3 0 0 0 0 0 0" +
NL +
662 " -2.2364 -1.5857 0.7018 H 0 0 0 0 0 0 0 0 0 0 0 0" +
NL +
663 " -1.4891 0.0267 0.6010 H 0 0 0 0 0 0 0 0 0 0 0 0" +
NL +
664 " 1 2 1 0 0 0 0" +
NL +
665 " 1 3 1 0 0 0 0" +
NL +
666 " 4 5 2 0 0 0 0" +
NL +
667 " 4 6 1 0 0 0 0" +
NL +
668 " 1 4 1 0 0 0 0" +
NL +
669 " 7 8 1 0 0 0 0" +
NL +
670 " 7 9 1 0 0 0 0" +
NL +
671 " 1 7 1 0 0 0 0" +
NL +
672 " 10 11 1 0 0 0 0" +
NL +
673 " 10 12 1 0 0 0 0" +
NL +
674 " 7 10 1 0 0 0 0" +
NL +
675 " 13 14 1 0 0 0 0" +
NL +
676 " 13 15 1 0 0 0 0" +
NL +
677 " 10 13 1 0 0 0 0" +
NL +
678 " 16 17 1 0 0 0 0" +
NL +
679 " 16 18 1 0 0 0 0" +
NL +
680 " 6 16 1 0 0 0 0" +
NL +
681 " 19 20 1 0 0 0 0" +
NL +
682 " 19 21 1 0 0 0 0" +
NL +
683 " 6 19 1 0 0 0 0" +
NL +
684 " 22 23 1 0 0 0 0" +
NL +
685 " 22 24 1 0 0 0 0" +
NL +
686 " 13 22 1 0 0 0 0" +
NL +
687 " 25 26 1 0 0 0 0" +
NL +
688 " 25 27 1 0 0 0 0" +
NL +
689 " 16 25 1 0 0 0 0" +
NL +
690 " 28 29 1 0 0 0 0" +
NL +
691 " 28 30 1 0 0 0 0" +
NL +
692 " 19 28 1 0 0 0 0" +
NL +
693 " 31 32 1 0 0 0 0" +
NL +
694 " 31 33 1 0 0 0 0" +
NL +
695 " 22 31 1 0 0 0 0" +
NL +
696 " 34 35 1 0 0 0 0" +
NL +
697 " 34 36 1 0 0 0 0" +
NL +
698 " 25 34 1 0 0 0 0" +
NL +
699 " 37 38 1 0 0 0 0" +
NL +
700 " 37 39 1 0 0 0 0" +
NL +
701 " 28 37 1 0 0 0 0" +
NL +
702 " 40 41 1 0 0 0 0" +
NL +
703 " 40 42 1 0 0 0 0" +
NL +
704 " 31 40 1 0 0 0 0" +
NL +
705 " 43 44 1 0 0 0 0" +
NL +
706 " 43 45 1 0 0 0 0" +
NL +
707 " 34 43 1 0 0 0 0" +
NL +
710 assertTrue(this.tempDir.isDirectory(),
"Should be a directory ");
711 String fileName =
tempDir.getAbsolutePath() +
SEP +
"refMol.sdf";
716 KabschAlignment sa =
null;
718 sa =
new KabschAlignment(refMol, mol);
720 }
catch (CDKException e){
722 fail(
"KabschAlignment failed: "+e.getMessage());
724 assertTrue(sa.getRMSD()<0.0001,
"RMSD between generated and expected "
728 Point3d[] expectedAPHeads =
new Point3d[] {
729 new Point3d(-1.6488,2.6919,2.1153),
730 new Point3d(1.8790, 0.0, 0.0700),
731 new Point3d(-2.3207,-0.4772,2.0919)};
734 Point3d apHead =
new Point3d(ap.getDirectionVector());
735 boolean found =
false;
736 double[] dists =
new double[3];
737 for (
int i=0; i<expectedAPHeads.length; i++)
739 Point3d expectedAPHead = expectedAPHeads[i];
740 double dist = apHead.distance(expectedAPHead);
748 assertTrue(found,
"Inconsistent placement of outer AP (errors: "
749 + dists[0] +
", " + dists[1] +
", " + dists[2] +
"). "
static APClass make(String ruleAndSubclass)
Creates an APClass if it does not exist already, or returns the reference to the existing instance.
An attachment point (AP) is a possibility to attach a Vertex onto the vertex holding the AP (i....
void setAPClass(String apClass)
Set the Attachment Point class.
APClass getAPClass()
Returns the Attachment Point class.
int getAtomPositionNumber()
The index of the source atom in the atom list of the fragment.
Container for the list of vertices and the edges that connect them.
void addVertex(Vertex vertex)
Appends a vertex to this graph without creating any edge.
Vertex getVertexAtPosition(int pos)
Returns the vertex that is in the given position of the list of vertices belonging to this graph.
void appendVertexOnAP(AttachmentPoint srcAP, AttachmentPoint trgAP)
Append a vertex to this graph: adds the new vertex to the list of vertices belonging to the graph,...
An empty vertex has the behaviors of a vertex, but has no molecular structure.
void addAP()
Adds an attachment point with no APClass or other attribute.
Class representing a continuously connected portion of chemical object holding attachment points.
void addAP(int atomPositionNumber)
Adds an attachment point with a dummy APClass.
This class represents the closure of a ring in a spanning tree.
void setInnerGraph(DGraph innerGraph)
boolean sameAs(Template other, StringBuilder reason)
Compares this and another template ignoring vertex IDs.
boolean freezeTemplate()
Promotes the contract level of this template to the most constrained one (i.e., ContractLevel#FIXED),...
ArrayList< AttachmentPoint > getAttachmentPoints()
Return the list of attachment points visible from outside the template, i.e., the so-called outer APs...
void addRequiredAP(Point3d pt, APClass apClass)
Adds attachment point (AP) to the list of required APs on this template.
IAtomContainer getIAtomContainer()
The molecular representation, if any, is generated by this method and stored until further changes in...
Template clone()
Returns a deep copy of this template.
Unit test for DENOPTIMTemplate.
void testGetAttachmentPoints_returnsAPsWithTemplateAsOwner()
static Template getTestAmideTemplate()
Builds a template object meant for tests.
void testAddAP_after_setInnerGraph_throwsException()
static Vertex getAmideFragment()
The coordinates hard coded in this method must not be changed because they are needed to reproduce re...
void testNestedTemplateCloning()
void testGetIAtomContainer_DeepVertex()
Template getTemplateDeepTest()
void testSetInnerGraph_throws_on_graph_incompatible_w_requiredAPs()
void testSameAPClass(Template t, DGraph innerGraph)
static IChemObjectBuilder chemBuilder
void testGetAttachmentPoints_returnsCorrectNumberOfAPs()
void testAtLeastSameNumberOfAPs(Template t, int expNumberOfAPs)
Template getNestedTemplate()
Creating a template that contains another template with the following structure: |-------------------...
void testGetIAtomContainer()
static Vertex getCH2Fragment()
The coordinates hard coded in this method must not be changed because they are needed to reproduce re...
A vertex is a data structure that has an identity and holds a list of AttachmentPoints.
void setVertexId(long vertexId2)
void setAsRCV(boolean isRCV)
abstract List< AttachmentPoint > getAttachmentPoints()
Object getProperty(Object property)
void setProperty(Object key, Object property)
AttachmentPoint getAP(int i)
Get attachment point i on this vertex.
Utility methods for input/output.
static ArrayList< IAtomContainer > readSDFFile(String fileName)
Reads a file containing multiple molecules (multiple SD format))
static void writeData(String fileName, String data, boolean append)
Write text-like data file.
static synchronized long getUniqueVertexIndex()
Unique counter for the number of graph vertices generated.
Utilities for molecule conversion.
static int countAtomsOfElement(IAtomContainer mol, String symbol)
Count atoms with the given elemental symbol.
The type of building block.