$darkmode
DENOPTIM
PathClosabilityToolsTest.java
Go to the documentation of this file.
1/*
2 * DENOPTIM
3 * Copyright (C) 2022 Marco Foscato <marco.foscato@uib.no>
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU Affero General Public License as published
7 * by the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Affero General Public License for more details.
14 *
15 * You should have received a copy of the GNU Affero General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19package denoptim.graph.rings;
20
21import static org.junit.jupiter.api.Assertions.assertEquals;
22import static org.junit.jupiter.api.Assertions.assertFalse;
23import static org.junit.jupiter.api.Assertions.assertTrue;
24
25import java.util.HashMap;
26import java.util.HashSet;
27import java.util.List;
28import java.util.Map;
29import java.util.Set;
30import java.util.logging.Logger;
31
32import javax.vecmath.Point3d;
33
34import org.junit.jupiter.api.Test;
35import org.openscience.cdk.Atom;
36import org.openscience.cdk.PseudoAtom;
37import org.openscience.cdk.interfaces.IAtom;
38import org.openscience.cdk.interfaces.IAtomContainer;
39import org.openscience.cdk.interfaces.IChemObjectBuilder;
40import org.openscience.cdk.silent.SilentChemObjectBuilder;
41
42import denoptim.graph.APClass;
43import denoptim.graph.DGraph;
44import denoptim.graph.Fragment;
45import denoptim.graph.Vertex;
46import denoptim.graph.Vertex.BBType;
47import denoptim.molecularmodeling.ThreeDimTreeBuilder;
48import denoptim.utils.Randomizer;
49
57{
58
59//------------------------------------------------------------------------------
60
61 @Test
62 public void testEvaluateConstitutionalClosability() throws Exception
63 {
64 /*
65 * Make the test graph (make it here so we have direct access to vertexes)
66 *
67 * RCV_P RCV_P RCV_P RCV_M
68 * | | | |
69 * RCV_M--[O]----[C]--[C]--[C]--[C]--[C]----[N]--RCV_M
70 * vO vC vC2 vC3 vC4 vC5 vN
71 *
72 */
73
74 APClass apc = APClass.make("A", 0);
75
76 IChemObjectBuilder builder = SilentChemObjectBuilder.getInstance();
77
78 IAtomContainer iacO = builder.newAtomContainer();
79 IAtom aO = new Atom("O",new Point3d(0,0,0));
80 iacO.addAtom(aO);
81 Fragment vO = new Fragment(0, iacO,BBType.FRAGMENT);
82 vO.addAP(0, new Point3d(0,-1,0), apc);
83 vO.addAP(0, new Point3d(2,0,0), apc);
84 vO.addAP(0, new Point3d(0,1,0), apc);
85
86 IAtomContainer iacC = builder.newAtomContainer();
87 IAtom aC = new Atom("C",new Point3d(0,0,0));
88 iacC.addAtom(aC);
89 Fragment vC = new Fragment(1, iacC,BBType.FRAGMENT);
90 vC.addAP(0, new Point3d(0,-1,0), apc);
91 vC.addAP(0, new Point3d(2,0,0), apc);
92 vC.addAP(0, new Point3d(0,1,0), apc);
93
94 IAtomContainer iacCd = builder.newAtomContainer();
95 IAtom aCd = new Atom("C",new Point3d(0,0,0));
96 iacCd.addAtom(aCd);
97 Fragment vC2 = new Fragment(2, iacCd,BBType.FRAGMENT);
98 vC2.addAP(0, new Point3d(0,-1,0), apc);
99 vC2.addAP(0, new Point3d(0,1,0), apc);
100
101 Fragment vC3 = vC2.clone();
102 vC3.setVertexId(33);
103
104 Fragment vC4 = vC2.clone();
105 vC4.setVertexId(34);
106
107 Fragment vC5 = vC.clone();
108 vC5.setVertexId(3);
109
110 IAtomContainer iacN = builder.newAtomContainer();
111 IAtom aN = new Atom("N",new Point3d(0,0,0));
112 iacN.addAtom(aN);
113 Fragment vN = new Fragment(4, iacN,BBType.FRAGMENT);
114 vN.addAP(0, new Point3d(0,-1,0), apc);
115 vN.addAP(0, new Point3d(2,0,0), apc);
116 vN.addAP(0, new Point3d(0,1,0), apc);
117
118 APClass atMinus = APClass.RCACLASSMINUS;
119
120 IAtomContainer iacD = builder.newAtomContainer();
121 iacD.addAtom(new PseudoAtom(RingClosingAttractor.RCALABELPERAPCLASS.get(atMinus),
122 new Point3d(0,0,0)));
123 Fragment rcvM = new Fragment(5, iacD,BBType.FRAGMENT);
124 rcvM.addAP(0, new Point3d(-1,0,0), atMinus);
125 rcvM.setAsRCV(true);
126
127 Fragment rcvM2 = rcvM.clone();
128 rcvM2.setVertexId(6);
129
130 Fragment rcvM3 = rcvM.clone();
131 rcvM3.setVertexId(7);
132
134
135 IAtomContainer iacE = builder.newAtomContainer();
136 iacE.addAtom(new PseudoAtom(RingClosingAttractor.RCALABELPERAPCLASS.get(atPlus),
137 new Point3d(0,0,0)));
138 Fragment rcvP = new Fragment(8, iacE,BBType.FRAGMENT);
139 rcvP.addAP(0, new Point3d(-1,0,0), atPlus);
140 rcvP.setAsRCV(true);
141
142 Fragment rcvP2 = rcvP.clone();
143 rcvP2.setVertexId(9);
144
145 Fragment rcvP3 = rcvP.clone();
146 rcvP3.setVertexId(10);
147
148 DGraph graph = new DGraph();
149 graph.addVertex(vC);
150 graph.appendVertexOnAP(vC.getAP(0), vO.getAP(2));
151 graph.appendVertexOnAP(vO.getAP(0), rcvM.getAP(0));
152 graph.appendVertexOnAP(vO.getAP(1), rcvP.getAP(0));
153 graph.appendVertexOnAP(vC.getAP(1), rcvP2.getAP(0));
154 graph.appendVertexOnAP(vC.getAP(2), vC2.getAP(1));
155 graph.appendVertexOnAP(vC2.getAP(0), vC3.getAP(0));
156 graph.appendVertexOnAP(vC3.getAP(1), vC4.getAP(0));
157 graph.appendVertexOnAP(vC4.getAP(1), vC5.getAP(0));
158 graph.appendVertexOnAP(vC5.getAP(1), rcvP3.getAP(0));
159 graph.appendVertexOnAP(vC5.getAP(2), vN.getAP(0));
160 graph.appendVertexOnAP(vN.getAP(1), rcvM2.getAP(0));
161 graph.appendVertexOnAP(vN.getAP(2), rcvM3.getAP(0));
162
163 // Prepare all that it is needed to run a ring-size management case
164
165 Logger logger = Logger.getLogger("DummyLogger");
166 Randomizer rng = new Randomizer();
167
168 //DenoptimIO.writeGraphToSDF(new File("/tmp/graph.sdf"), graph, false, logger, rng);
169
170 ThreeDimTreeBuilder t3d = new ThreeDimTreeBuilder(logger, rng);
171 t3d.setAlignBBsIn3D(false); //3D not needed
172 IAtomContainer mol = t3d.convertGraphTo3DAtomContainer(graph, true);
173
175 // By default no constitutional check is expected.
176
177 // uncomment to log on console
178 //rcParams.startConsoleLogger("logger");
179 //rcParams.setVerbosity(2);
180
181 //
182 // First case: no checking of constitution
183 //
184
185 List<Vertex> rcvs = graph.getRCVertices();
186 int numCompatibilities = 0;
187 for (int i=0; i<rcvs.size(); i++)
188 {
189 Vertex vI = rcvs.get(i);
190 for (int j=i+1; j<rcvs.size(); j++)
191 {
192 Vertex vJ = rcvs.get(j);
193 PathSubGraph path = new PathSubGraph(vI, vJ, graph);
194 if (PathClosabilityTools.isCloseable(path, mol, rcParams))
195 {
196 numCompatibilities++;
197 } else {
198 assertTrue(false);
199 }
200 }
201 }
202 assertEquals(15, numCompatibilities);
203
204 //
205 // Second case: constitutional constrains are empty, so any combination
206 // of RCVs is forbidden
207 //
208
209 rcParams.rceMode = 0; // ONLY constitution
210 for (int i=0; i<rcvs.size(); i++)
211 {
212 Vertex vI = rcvs.get(i);
213 for (int j=i+1; j<rcvs.size(); j++)
214 {
215 Vertex vJ = rcvs.get(j);
216 PathSubGraph path = new PathSubGraph(vI, vJ, graph);
217 assertFalse(PathClosabilityTools.isCloseable(path, mol, rcParams));
218 }
219 }
220
221 //
222 // Third case: constitutional constrains are present and allow
223 // to close rings only for a minority of possible combinations of RCVs.
224 //
225
226 Map<String,String> allowedConstitutions = new HashMap<String,String>();
227 allowedConstitutions.put("case-1", "[#6]1[#6][#8][#6][#6][#6]1");
228 allowedConstitutions.put("case-2", "[#6]1[#6][#7][#6][#6][#6]1");
229 rcParams.setConstitutionalClosabilityConds(allowedConstitutions);
230
231 Map<Vertex,Set<Vertex>> expectedRCCompatibilities =
232 new HashMap<Vertex,Set<Vertex>>();
233 expectedRCCompatibilities.put(rcvM, new HashSet<Vertex>());
234 expectedRCCompatibilities.get(rcvM).add(rcvP3);
235 expectedRCCompatibilities.put(rcvP2, new HashSet<Vertex>());
236 expectedRCCompatibilities.get(rcvP2).add(rcvM2);
237 expectedRCCompatibilities.get(rcvP2).add(rcvM3);
238 // NB: the following are combinations of RCVs that are NOT
239 // permitted by compatibility matrix, but the PathClosabilityTools
240 // do not check for APClass or RCV type compatibility, which is meant
241 // to be done elsewhere.
242 expectedRCCompatibilities.put(rcvP, new HashSet<Vertex>());
243 expectedRCCompatibilities.get(rcvP).add(rcvP3);
244
245 numCompatibilities = 0;
246 for (int i=0; i<rcvs.size(); i++)
247 {
248 Vertex vI = rcvs.get(i);
249 for (int j=i+1; j<rcvs.size(); j++)
250 {
251 Vertex vJ = rcvs.get(j);
252 PathSubGraph path = new PathSubGraph(vI, vJ, graph);
253 if (PathClosabilityTools.isCloseable(path, mol, rcParams))
254 {
255 numCompatibilities++;
256 assertTrue(expectedRCCompatibilities.containsKey(vI));
257 assertTrue(expectedRCCompatibilities.get(vI).contains(vJ));
258 }
259 }
260 }
261 assertEquals(4, numCompatibilities);
262
263 //
264 // Fourth case: constitutional constrains pertain only the presence of
265 // certain elements in the newly generated rings
266 //
267
268 rcParams = new RingClosureParameters();
269 rcParams.rceMode = 0; // ONLY constitution
270 Set<String> elementsRequired = new HashSet<String>();
271 elementsRequired.add("N");
272 elementsRequired.add("Ru");
273 rcParams.reqElInRings = elementsRequired;
274
275 expectedRCCompatibilities = new HashMap<Vertex,Set<Vertex>>();
276 expectedRCCompatibilities.put(rcvP, new HashSet<Vertex>());
277 expectedRCCompatibilities.get(rcvP).add(rcvM2);
278 expectedRCCompatibilities.get(rcvP).add(rcvM3);
279 expectedRCCompatibilities.put(rcvP2, new HashSet<Vertex>());
280 expectedRCCompatibilities.get(rcvP2).add(rcvM2);
281 expectedRCCompatibilities.get(rcvP2).add(rcvM3);
282 // NB: the following are combinations of RCVs that are NOT
283 // permitted by compatibility matrix, but the PathClosabilityTools
284 // do not check for APClass or RCV type compatibility, which is meant
285 // to be done elsewhere.
286 expectedRCCompatibilities.put(rcvM, new HashSet<Vertex>());
287 expectedRCCompatibilities.get(rcvM).add(rcvM2);
288 expectedRCCompatibilities.get(rcvM).add(rcvM3);
289 expectedRCCompatibilities.put(rcvP3, new HashSet<Vertex>());
290 expectedRCCompatibilities.get(rcvP3).add(rcvM2);
291 expectedRCCompatibilities.get(rcvP3).add(rcvM3);
292 expectedRCCompatibilities.put(rcvM2, new HashSet<Vertex>());
293 expectedRCCompatibilities.get(rcvM2).add(rcvM3);
294
295 numCompatibilities = 0;
296 for (int i=0; i<rcvs.size(); i++)
297 {
298 Vertex vI = rcvs.get(i);
299 for (int j=i+1; j<rcvs.size(); j++)
300 {
301 Vertex vJ = rcvs.get(j);
302 PathSubGraph path = new PathSubGraph(vI, vJ, graph);
303 if (PathClosabilityTools.isCloseable(path, mol, rcParams))
304 {
305 numCompatibilities++;
306 assertTrue(expectedRCCompatibilities.containsKey(vI));
307 assertTrue(expectedRCCompatibilities.get(vI).contains(vJ));
308 }
309 }
310 }
311 assertEquals(9, numCompatibilities);
312 }
313
314//------------------------------------------------------------------------------
315
316}
static final APClass RCACLASSPLUS
Conventional class of attachment points on ring-closing vertexes.
Definition: APClass.java:85
static final APClass RCACLASSMINUS
Conventional class of attachment points on ring-closing vertexes.
Definition: APClass.java:92
static APClass make(String ruleAndSubclass)
Creates an APClass if it does not exist already, or returns the reference to the existing instance.
Definition: APClass.java:164
Container for the list of vertices and the edges that connect them.
Definition: DGraph.java:102
void addVertex(Vertex vertex)
Appends a vertex to this graph without creating any edge.
Definition: DGraph.java:1325
ArrayList< Vertex > getRCVertices()
Search for ring closing vertices: vertices that contain only a RingClosingAttractor
Definition: DGraph.java:1190
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,...
Definition: DGraph.java:6005
Class representing a continuously connected portion of chemical object holding attachment points.
Definition: Fragment.java:61
void addAP(int atomPositionNumber)
Adds an attachment point with a dummy APClass.
Definition: Fragment.java:343
Fragment clone()
Returns a deep copy of this fragments.
Definition: Fragment.java:733
A vertex is a data structure that has an identity and holds a list of AttachmentPoints.
Definition: Vertex.java:61
void setVertexId(long vertexId2)
Definition: Vertex.java:281
void setAsRCV(boolean isRCV)
Definition: Vertex.java:274
AttachmentPoint getAP(int i)
Get attachment point i on this vertex.
Definition: Vertex.java:1007
Tool box for determining whether a chain of atoms, i.e., a path, can be folded as to form a ring-clos...
static boolean isCloseable(PathSubGraph subGraph, IAtomContainer mol, RingClosureParameters settings)
Method to evaluate the closability of a single path in a graph.
This object represents a path in a DGraph.
The RingClosingAttractor represent the available valence/connection that allows to close a ring.
static final HashMap< APClass, String > RCALABELPERAPCLASS
Conventional labels for attractor pseudoatom.
Parameters and setting related to handling ring closures.
void setConstitutionalClosabilityConds(Map< String, String > ringClosabCondAsSMARTS)
Sets the list of constitutions that can be formed by ring closure.
Tool to build build three-dimensional (3D) tree-like molecular structures from DGraph.
void setAlignBBsIn3D(boolean align)
Sets the flag that controls whether building blocks have to be aligned according to the AP vectors or...
IAtomContainer convertGraphTo3DAtomContainer(DGraph graph)
Created a three-dimensional molecular representation from a given DGraph.
Tool to generate random numbers and random decisions.
Definition: Randomizer.java:35
The type of building block.
Definition: Vertex.java:86