$darkmode
DENOPTIM
RingSizeManagerTest.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.assertNotEquals;
24import static org.junit.jupiter.api.Assertions.assertTrue;
25
26import java.util.ArrayList;
27import java.util.HashMap;
28import java.util.HashSet;
29import java.util.List;
30import java.util.Map;
31import java.util.Set;
32import java.util.logging.Logger;
33
34import javax.vecmath.Point3d;
35
36import org.junit.jupiter.api.Test;
37import org.openscience.cdk.Atom;
38import org.openscience.cdk.PseudoAtom;
39import org.openscience.cdk.interfaces.IAtom;
40import org.openscience.cdk.interfaces.IAtomContainer;
41import org.openscience.cdk.interfaces.IChemObjectBuilder;
42import org.openscience.cdk.silent.SilentChemObjectBuilder;
43
44import denoptim.exception.DENOPTIMException;
45import denoptim.fragspace.FragmentSpace;
46import denoptim.fragspace.FragmentSpaceParameters;
47import denoptim.graph.APClass;
48import denoptim.graph.DGraph;
49import denoptim.graph.Fragment;
50import denoptim.graph.Vertex;
51import denoptim.graph.Vertex.BBType;
52import denoptim.molecularmodeling.ThreeDimTreeBuilder;
53import denoptim.utils.Randomizer;
54
62{
63
64//------------------------------------------------------------------------------
79 public static DGraph makeTestGraphA() throws DENOPTIMException
80 {
81 APClass apc = APClass.make("A",0);
82
83 IChemObjectBuilder builder = SilentChemObjectBuilder.getInstance();
84
85 IAtomContainer iacO = builder.newAtomContainer();
86 IAtom aO = new Atom("O",new Point3d(0,0,0));
87 iacO.addAtom(aO);
88 Fragment vO = new Fragment(0, iacO,BBType.FRAGMENT);
89 vO.addAP(0, new Point3d(0,-1,0), apc);
90 vO.addAP(0, new Point3d(2,0,0), apc);
91 vO.addAP(0, new Point3d(0,1,0), apc);
92
93 IAtomContainer iacC = builder.newAtomContainer();
94 IAtom aC = new Atom("C",new Point3d(0,0,0));
95 iacC.addAtom(aC);
96 Fragment vC = new Fragment(1, iacC,BBType.FRAGMENT);
97 vC.addAP(0, new Point3d(0,-1,0), apc);
98 vC.addAP(0, new Point3d(2,0,0), apc);
99 vC.addAP(0, new Point3d(0,1,0), apc);
100
101 IAtomContainer iacCd = builder.newAtomContainer();
102 IAtom aCd = new Atom("C",new Point3d(0,0,0));
103 iacCd.addAtom(aCd);
104 Fragment vC2 = new Fragment(2, iacCd,BBType.FRAGMENT);
105 vC2.addAP(0, new Point3d(0,-1,0), apc);
106 vC2.addAP(0, new Point3d(0,1,0), apc);
107
108 Fragment vC3 = vC2.clone();
109 vC3.setVertexId(33);
110
111 Fragment vC4 = vC2.clone();
112 vC4.setVertexId(34);
113
114 Fragment vC5 = vC.clone();
115 vC5.setVertexId(3);
116
117 IAtomContainer iacN = builder.newAtomContainer();
118 IAtom aN = new Atom("N",new Point3d(0,0,0));
119 iacN.addAtom(aN);
120 Fragment vN = new Fragment(4, iacN,BBType.FRAGMENT);
121 vN.addAP(0, new Point3d(0,-1,0), apc);
122 vN.addAP(0, new Point3d(2,0,0), apc);
123 vN.addAP(0, new Point3d(0,1,0), apc);
124
125 APClass atMinus = APClass.RCACLASSMINUS;
126
127 IAtomContainer iacD = builder.newAtomContainer();
128 iacD.addAtom(new PseudoAtom(RingClosingAttractor.RCALABELPERAPCLASS.get(atMinus),
129 new Point3d(0,0,0)));
130 Fragment rcvM = new Fragment(5, iacD,BBType.FRAGMENT);
131 rcvM.addAP(0, new Point3d(-1,0,0), atMinus);
132 rcvM.setAsRCV(true);
133
134 Fragment rcvM2 = rcvM.clone();
135 rcvM2.setVertexId(6);
136
137 Fragment rcvM3 = rcvM.clone();
138 rcvM3.setVertexId(7);
139
141
142 IAtomContainer iacE = builder.newAtomContainer();
143 iacE.addAtom(new PseudoAtom(RingClosingAttractor.RCALABELPERAPCLASS.get(atPlus),
144 new Point3d(0,0,0)));
145 Fragment rcvP = new Fragment(8, iacE,BBType.FRAGMENT);
146 rcvP.addAP(0, new Point3d(-1,0,0), atPlus);
147 rcvP.setAsRCV(true);
148
149 Fragment rcvP2 = rcvP.clone();
150 rcvP2.setVertexId(9);
151
152 Fragment rcvP3 = rcvP.clone();
153 rcvP3.setVertexId(10);
154
155 DGraph graph = new DGraph();
156 graph.addVertex(vC);
157 graph.appendVertexOnAP(vC.getAP(0), vO.getAP(2));
158 graph.appendVertexOnAP(vO.getAP(0), rcvM.getAP(0));
159 graph.appendVertexOnAP(vO.getAP(1), rcvP.getAP(0));
160 graph.appendVertexOnAP(vC.getAP(1), rcvP2.getAP(0));
161 graph.appendVertexOnAP(vC.getAP(2), vC2.getAP(1));
162 graph.appendVertexOnAP(vC2.getAP(0), vC3.getAP(0));
163 graph.appendVertexOnAP(vC3.getAP(1), vC4.getAP(0));
164 graph.appendVertexOnAP(vC4.getAP(1), vC5.getAP(0));
165 graph.appendVertexOnAP(vC5.getAP(1), rcvP3.getAP(0));
166 graph.appendVertexOnAP(vC5.getAP(2), vN.getAP(0));
167 graph.appendVertexOnAP(vN.getAP(1), rcvM2.getAP(0));
168 graph.appendVertexOnAP(vN.getAP(2), rcvM3.getAP(0));
169 return graph;
170 }
171
172//------------------------------------------------------------------------------
173
174 @Test
175 public void testEvaluateRCVPair() throws Exception
176 {
177 // Make the test graph (make it here so we have direct access to vertexes)
178
179 APClass apc = APClass.make("A",0);
180
181 IChemObjectBuilder builder = SilentChemObjectBuilder.getInstance();
182
183 IAtomContainer iacO = builder.newAtomContainer();
184 IAtom aO = new Atom("O",new Point3d(0,0,0));
185 iacO.addAtom(aO);
186 Fragment vO = new Fragment(0, iacO,BBType.FRAGMENT);
187 vO.addAP(0, new Point3d(0,-1,0), apc);
188 vO.addAP(0, new Point3d(2,0,0), apc);
189 vO.addAP(0, new Point3d(0,1,0), apc);
190
191 IAtomContainer iacC = builder.newAtomContainer();
192 IAtom aC = new Atom("C",new Point3d(0,0,0));
193 iacC.addAtom(aC);
194 Fragment vC = new Fragment(1, iacC,BBType.FRAGMENT);
195 vC.addAP(0, new Point3d(0,-1,0), apc);
196 vC.addAP(0, new Point3d(2,0,0), apc);
197 vC.addAP(0, new Point3d(0,1,0), apc);
198
199 IAtomContainer iacCd = builder.newAtomContainer();
200 IAtom aCd = new Atom("C",new Point3d(0,0,0));
201 iacCd.addAtom(aCd);
202 Fragment vC2 = new Fragment(2, iacCd,BBType.FRAGMENT);
203 vC2.addAP(0, new Point3d(0,-1,0), apc);
204 vC2.addAP(0, new Point3d(0,1,0), apc);
205
206 Fragment vC3 = vC2.clone();
207 vC3.setVertexId(33);
208
209 Fragment vC4 = vC2.clone();
210 vC4.setVertexId(34);
211
212 Fragment vC5 = vC.clone();
213 vC5.setVertexId(3);
214
215 IAtomContainer iacN = builder.newAtomContainer();
216 IAtom aN = new Atom("N",new Point3d(0,0,0));
217 iacN.addAtom(aN);
218 Fragment vN = new Fragment(4, iacN,BBType.FRAGMENT);
219 vN.addAP(0, new Point3d(0,-1,0), apc);
220 vN.addAP(0, new Point3d(2,0,0), apc);
221 vN.addAP(0, new Point3d(0,1,0), apc);
222
223 APClass atMinus = APClass.RCACLASSMINUS;
224
225 IAtomContainer iacD = builder.newAtomContainer();
226 iacD.addAtom(new PseudoAtom(RingClosingAttractor.RCALABELPERAPCLASS.get(atMinus),
227 new Point3d(0,0,0)));
228 Fragment rcvM = new Fragment(5, iacD,BBType.FRAGMENT);
229 rcvM.addAP(0, new Point3d(-1,0,0), atMinus);
230 rcvM.setAsRCV(true);
231
232 Fragment rcvM2 = rcvM.clone();
233 rcvM2.setVertexId(6);
234
235 Fragment rcvM3 = rcvM.clone();
236 rcvM3.setVertexId(7);
237
239
240 IAtomContainer iacE = builder.newAtomContainer();
241 iacE.addAtom(new PseudoAtom(RingClosingAttractor.RCALABELPERAPCLASS.get(atPlus),
242 new Point3d(0,0,0)));
243 Fragment rcvP = new Fragment(8, iacE,BBType.FRAGMENT);
244 rcvP.addAP(0, new Point3d(-1,0,0), atPlus);
245 rcvP.setAsRCV(true);
246
247 Fragment rcvP2 = rcvP.clone();
248 rcvP2.setVertexId(9);
249
250 Fragment rcvP3 = rcvP.clone();
251 rcvP3.setVertexId(10);
252
253 DGraph graph = new DGraph();
254 graph.addVertex(vC);
255 graph.appendVertexOnAP(vC.getAP(0), vO.getAP(2));
256 graph.appendVertexOnAP(vO.getAP(0), rcvM.getAP(0));
257 graph.appendVertexOnAP(vO.getAP(1), rcvP.getAP(0));
258 graph.appendVertexOnAP(vC.getAP(1), rcvP2.getAP(0));
259 graph.appendVertexOnAP(vC.getAP(2), vC2.getAP(1));
260 graph.appendVertexOnAP(vC2.getAP(0), vC3.getAP(0));
261 graph.appendVertexOnAP(vC3.getAP(1), vC4.getAP(0));
262 graph.appendVertexOnAP(vC4.getAP(1), vC5.getAP(0));
263 graph.appendVertexOnAP(vC5.getAP(1), rcvP3.getAP(0));
264 graph.appendVertexOnAP(vC5.getAP(2), vN.getAP(0));
265 graph.appendVertexOnAP(vN.getAP(1), rcvM2.getAP(0));
266 graph.appendVertexOnAP(vN.getAP(2), rcvM3.getAP(0));
267
268 // Prepare all that it is needed to run a ring-size management case
269
270 Logger logger = Logger.getLogger("DummyLogger");
271 Randomizer rng = new Randomizer();
272
273 //DenoptimIO.writeGraphToSDF(new File("/tmp/graph.sdf"), graph, false, logger, rng);
274
275 ThreeDimTreeBuilder t3d = new ThreeDimTreeBuilder(logger,rng);
276 t3d.setAlignBBsIn3D(false); //3D not needed
277 IAtomContainer molA = t3d.convertGraphTo3DAtomContainer(graph, true);
278
279 //
280 // First case: no APClass compatibility. Cannot close any ring!
281 //
283 FragmentSpace fs = new FragmentSpace(fsp,
284 new ArrayList<Vertex>(),
285 new ArrayList<Vertex>(),
286 new ArrayList<Vertex>(),
287 new HashMap<APClass,ArrayList<APClass>>(),
288 new HashMap<APClass,APClass>(),
289 new HashSet<APClass>(),
290 new HashMap<APClass,ArrayList<APClass>>());
292
294
295 // uncomment to log on console
296 // rcParams.startConsoleLogger("logger");
297 // rcParams.setVerbosity(2);
298
299 RingSizeManager rsm = new RingSizeManager(fs, rcParams);
300 rsm.initialize(molA, graph);
301
302 List<Vertex> wLst = rsm.getRSBiasedListOfCandidates();
303 assertEquals(0, wLst.size());
304 List<Vertex> rcvs = graph.getRCVertices();
305 for (int i=0; i<rcvs.size(); i++)
306 {
307 // NB: we intentionally check also i=j
308 for (int j=i; j<rcvs.size(); j++)
309 {
310 assertFalse(rsm.getCompatibilityOfPair(rcvs.get(i), rcvs.get(j)));
311 }
312 }
313
314 //
315 // Second case: AP compatibility allows to make rings of various sizes
316 //
317
318 APClass apcA = APClass.make("A",0);
319 HashMap<APClass,ArrayList<APClass>> cpMap =
320 new HashMap<APClass,ArrayList<APClass>>();
321 ArrayList<APClass> lstA = new ArrayList<APClass>();
322 lstA.add(apcA);
323 cpMap.put(apcA, lstA);
324 fs = new FragmentSpace(fsp,
325 new ArrayList<Vertex>(),
326 new ArrayList<Vertex>(),
327 new ArrayList<Vertex>(),
328 cpMap,
329 new HashMap<APClass,APClass>(),
330 new HashSet<APClass>(),
331 cpMap);
333
334 rsm = new RingSizeManager(fs, rcParams);
335 rsm.initialize(molA, graph);
336
337 wLst = rsm.getRSBiasedListOfCandidates();
338 assertNotEquals(0, wLst.size());
339 Map<Vertex,Set<Vertex>> expectedRCCompatibilities =
340 new HashMap<Vertex,Set<Vertex>>();
341 expectedRCCompatibilities.put(rcvM, new HashSet<Vertex>());
342 expectedRCCompatibilities.get(rcvM).add(rcvP3);
343 expectedRCCompatibilities.put(rcvP, new HashSet<Vertex>());
344 expectedRCCompatibilities.get(rcvP).add(rcvM2);
345 expectedRCCompatibilities.get(rcvP).add(rcvM3);
346 expectedRCCompatibilities.put(rcvP2, new HashSet<Vertex>());
347 expectedRCCompatibilities.get(rcvP2).add(rcvM2);
348 expectedRCCompatibilities.get(rcvP2).add(rcvM3);
349 int numCompatibilities = 0;
350 for (int i=0; i<rcvs.size(); i++)
351 {
352 Vertex vI = rcvs.get(i);
353 // NB: we intentionally check also i=j
354 for (int j=i; j<rcvs.size(); j++)
355 {
356 Vertex vJ = rcvs.get(j);
357 if (rsm.getCompatibilityOfPair(vI, vJ))
358 {
359 numCompatibilities++;
360 assertTrue(expectedRCCompatibilities.containsKey(vI));
361 assertTrue(expectedRCCompatibilities.get(vI).contains(vJ));
362 }
363 }
364 }
365 assertEquals(5,numCompatibilities);
366
367 //
368 // Third case: ring-size constrain prevent some combination of RCVs
369 //
370 List<Integer> biases = new ArrayList<Integer>();
371 for (int i=0; i<8; i++)
372 {
373 biases.add(0); // 0 means prevent rings with this size!
374 }
375 biases.set(6, 1); // i.e., allows only 6-member rings
376 rcParams.setRingSizeBias(biases);
377
378 rsm = new RingSizeManager(fs, rcParams);
379 rsm.initialize(molA, graph);
380
381 wLst = rsm.getRSBiasedListOfCandidates();
382 assertNotEquals(0, wLst.size());
383 expectedRCCompatibilities = new HashMap<Vertex,Set<Vertex>>();
384 expectedRCCompatibilities.put(rcvM, new HashSet<Vertex>());
385 expectedRCCompatibilities.get(rcvM).add(rcvP3);
386 expectedRCCompatibilities.put(rcvP2, new HashSet<Vertex>());
387 expectedRCCompatibilities.get(rcvP2).add(rcvM2);
388 expectedRCCompatibilities.get(rcvP2).add(rcvM3);
389 numCompatibilities = 0;
390 for (int i=0; i<rcvs.size(); i++)
391 {
392 Vertex vI = rcvs.get(i);
393 // NB: we intentionally check also i=j
394 for (int j=i; j<rcvs.size(); j++)
395 {
396 Vertex vJ = rcvs.get(j);
397 if (rsm.getCompatibilityOfPair(vI, vJ))
398 {
399 numCompatibilities++;
400 assertTrue(expectedRCCompatibilities.containsKey(vI));
401 assertTrue(expectedRCCompatibilities.get(vI).contains(vJ));
402 }
403 }
404 }
405 assertEquals(3, numCompatibilities);
406
407 //
408 // Same as before but with different preference for ring size
409 //
410 biases = new ArrayList<Integer>();
411 for (int i=0; i<8; i++)
412 {
413 biases.add(0); // 0 means prevent rings with this size!
414 }
415 biases.set(7, 1); // i.e., allows only 7-member rings
416 rcParams.setRingSizeBias(biases);
417
418 rsm = new RingSizeManager(fs, rcParams);
419 rsm.initialize(molA, graph);
420
421 wLst = rsm.getRSBiasedListOfCandidates();
422 assertNotEquals(0, wLst.size());
423 expectedRCCompatibilities = new HashMap<Vertex,Set<Vertex>>();
424 expectedRCCompatibilities.put(rcvP, new HashSet<Vertex>());
425 expectedRCCompatibilities.get(rcvP).add(rcvM2);
426 expectedRCCompatibilities.get(rcvP).add(rcvM3);
427 numCompatibilities = 0;
428 for (int i=0; i<rcvs.size(); i++)
429 {
430 Vertex vI = rcvs.get(i);
431 // NB: we intentionally check also i=j
432 for (int j=i; j<rcvs.size(); j++)
433 {
434 Vertex vJ = rcvs.get(j);
435 if (rsm.getCompatibilityOfPair(vI, vJ))
436 {
437 numCompatibilities++;
438 assertTrue(expectedRCCompatibilities.containsKey(vI));
439 assertTrue(expectedRCCompatibilities.get(vI).contains(vJ));
440 }
441 }
442 }
443 assertEquals(2, numCompatibilities);
444
445 //
446 // Same as before but with unmatched preference
447 //
448 biases = new ArrayList<Integer>();
449 for (int i=0; i<8; i++)
450 {
451 biases.add(0); // 0 means prevent rings with this size!
452 }
453 biases.set(3, 1); // i.e., allows only 3-member rings
454 rcParams.setRingSizeBias(biases);
455
456 rsm = new RingSizeManager(fs, rcParams);
457 rsm.initialize(molA, graph);
458
459 wLst = rsm.getRSBiasedListOfCandidates();
460 assertEquals(0, wLst.size());
461 numCompatibilities = 0;
462 for (int i=0; i<rcvs.size(); i++)
463 {
464 Vertex vI = rcvs.get(i);
465 // NB: we intentionally check also i=j
466 for (int j=i; j<rcvs.size(); j++)
467 {
468 Vertex vJ = rcvs.get(j);
469 if (rsm.getCompatibilityOfPair(vI, vJ))
470 {
471 numCompatibilities++;
472 }
473 }
474 }
475 assertEquals(0, numCompatibilities);
476 }
477
478//------------------------------------------------------------------------------
479
480}
Class defining a space of building blocks.
void setAPclassBasedApproach(boolean useAPC)
Set the fragment space to behave according to APClass-based approach.
Parameters defining the fragment space.
static final APClass RCACLASSPLUS
Conventional class of attachment points on ring-closing vertexes.
Definition: APClass.java:84
static final APClass RCACLASSMINUS
Conventional class of attachment points on ring-closing vertexes.
Definition: APClass.java:91
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:136
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:1097
ArrayList< Vertex > getRCVertices()
Search for ring closing vertices: vertices that contain only a RingClosingAttractor
Definition: DGraph.java:962
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:5776
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:261
void setAsRCV(boolean isRCV)
Definition: Vertex.java:254
AttachmentPoint getAP(int i)
Get attachment point i on this vertex.
Definition: Vertex.java:920
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 setRingSizeBias(List< Integer > biases)
Sets the preference for certain ring sizes or the prohibition to generate certain rings (i....
Utility class to calculate and manage the alternative ring sizes achievable by formation of Rings.
boolean getCompatibilityOfPair(Vertex vI, Vertex vJ)
void initialize(IAtomContainer origMol, DGraph graph)
Makes this ring size manager work on a specific system that has a molecular representation and a DENO...
static DGraph makeTestGraphA()
Build a graph meant to be used in unit tests.
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