$darkmode
DENOPTIM
PathClosabilityTools.java
Go to the documentation of this file.
1/*
2 * DENOPTIM
3 * Copyright (C) 2019 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 java.util.ArrayList;
22import java.util.Arrays;
23import java.util.Collections;
24import java.util.HashMap;
25import java.util.Iterator;
26import java.util.List;
27import java.util.Map;
28import java.util.Set;
29import java.util.logging.Level;
30import java.util.logging.Logger;
31
32import javax.vecmath.Point3d;
33
34import org.openscience.cdk.Bond;
35import org.openscience.cdk.graph.ShortestPaths;
36import org.openscience.cdk.graph.matrix.TopologicalMatrix;
37import org.openscience.cdk.interfaces.IAtom;
38import org.openscience.cdk.interfaces.IAtomContainer;
39import org.openscience.cdk.interfaces.IBond;
40import org.openscience.cdk.interfaces.IChemObjectBuilder;
41import org.openscience.cdk.silent.SilentChemObjectBuilder;
42
43import denoptim.constants.DENOPTIMConstants;
44import denoptim.exception.DENOPTIMException;
45import denoptim.fragspace.FragmentSpace;
46import denoptim.graph.APClass;
47import denoptim.graph.AttachmentPoint;
48import denoptim.graph.DGraph;
49import denoptim.graph.Edge;
50import denoptim.graph.Edge.BondType;
51import denoptim.graph.EmptyVertex;
52import denoptim.graph.Fragment;
53import denoptim.graph.Ring;
54import denoptim.graph.Vertex;
55import denoptim.graph.Vertex.BBType;
56import denoptim.utils.ManySMARTSQuery;
57import denoptim.utils.MoleculeUtils;
58import denoptim.utils.ObjectPair;
59import denoptim.utils.RingClosingUtils;
60
61
71{
72
73//-----------------------------------------------------------------------------
74
86 public static boolean isCloseable(PathSubGraph subGraph,
87 IAtomContainer mol, RingClosureParameters settings)
88 {
89 boolean closable = false;
90 switch (settings.getClosabilityEvalMode())
91 {
92 case -1:
93 closable = true; // ring size has been evaluated before
94 break;
95 case 0:
96 closable = evaluateConstitutionalClosability(subGraph, mol,
97 settings);
98 break;
99 case 1:
100 closable = evaluate3DPathClosability(subGraph, mol, settings);
101 break;
102 case 2:
103 closable = evaluateConstitutionalClosability(subGraph, mol,
104 settings) && evaluate3DPathClosability(subGraph, mol,
105 settings);
106 break;
107 default:
108 String s = "Unrecognized closability evaluation mode";
109 throw new IllegalArgumentException(s);
110 }
111 return closable;
112 }
113
114//-----------------------------------------------------------------------------
115
128 private static boolean evaluateConstitutionalClosability(
129 PathSubGraph subGraph, IAtomContainer iac,
130 RingClosureParameters settings)
131 {
132 settings.getLogger().log(Level.FINE, "Evaluating constitutional "
133 + "closability of path: " + subGraph.getVertecesPath());
134
135 // Get a working copy of the molecular container
136 IChemObjectBuilder builder = SilentChemObjectBuilder.getInstance();
137 IAtomContainer mol = builder.newAtomContainer();
138 try
139 {
140 mol = iac.clone();
141 }
142 catch (CloneNotSupportedException e)
143 {
144 throw new IllegalArgumentException(e);
145 }
147
148 // Identify atoms of molecular representation that correspond to
149 // this path of vertices
150 Map<Vertex,ArrayList<Integer>> vIdToAtmId =
152 (ArrayList<Vertex>) subGraph.getVertecesPath(),
153 mol);
154 List<Integer> atmIdsInVrtxPath = new ArrayList<Integer>();
155 for (Vertex v : subGraph.getVertecesPath())
156 {
157 atmIdsInVrtxPath.addAll(vIdToAtmId.get(v));
158 }
159
160 // Find atoms to remove: keep only the atoms that belong to the
161 // vertex path and their neighbours
162 ArrayList<IAtom> toRemove = new ArrayList<IAtom>();
163 for (int i=0; i<mol.getAtomCount(); i++)
164 {
165 if (!atmIdsInVrtxPath.contains(i))
166 {
167 IAtom candAtm = mol.getAtom(i);
168 boolean isNeighbour = false;
169 List<IAtom> nbrs = mol.getConnectedAtomsList(candAtm);
170 for (IAtom nbrAtm : nbrs)
171 {
172 if (atmIdsInVrtxPath.contains(mol.indexOf(nbrAtm)))
173 {
174 isNeighbour = true;
175 break;
176 }
177 }
178 if (!isNeighbour)
179 {
180 toRemove.add(candAtm);
181 }
182 }
183 }
184 // Deal with RCAs: head and tail vertices
185 IAtom atmH = mol.getAtom(vIdToAtmId.get(subGraph.getHeadVertex()).get(0));
186 IAtom atmT = mol.getAtom(vIdToAtmId.get(subGraph.getTailVertex()).get(0));
187 IAtom srcH = mol.getConnectedAtomsList(atmH).get(0);
188 IAtom srcT = mol.getConnectedAtomsList(atmT).get(0);
189 int iSrcH = mol.indexOf(srcH);
190 int iSrcT = mol.indexOf(srcT);
191 toRemove.add(atmH);
192 toRemove.add(atmT);
193
194 BondType bndTyp = subGraph.getEdgesPath().get(0).getBondType();
195 if (bndTyp.hasCDKAnalogue())
196 {
197 mol.addBond(iSrcH, iSrcT, bndTyp.getCDKOrder());
198 } else {
199 settings.getLogger().log(Level.WARNING,
200 "WARNING! Attempt to add ring closing bond "
201 + "did not add any actual chemical bond because the "
202 + "bond type of the chord is '" + bndTyp +"'.");
203 }
204
205 // Remove atoms
206 for (IAtom a : toRemove)
207 {
208 mol.removeAtom(a);
209 }
210
211 StringBuilder sb = new StringBuilder();
212 sb.append("Molecular representation of path includes:");
213 for (IAtom a : mol.atoms())
214 {
215 sb.append(" " + a.getSymbol() + mol.indexOf(a) + " "
216 + a.getProperties());
217 }
218 settings.getLogger().log(Level.FINEST, sb.toString());
219
220 boolean closable = false;
221
222 // Evaluate requirement based on elements contained in the ring
223 boolean spanRequiredEls = false;
224 Set<String> reqRingEl = settings.getRequiredRingElements();
225 if (reqRingEl.size() != 0)
226 {
227 // Prepare shortest atom path
228 List<IAtom> atomsPath = new ArrayList<IAtom>();
229 ShortestPaths sp = new ShortestPaths(mol, srcH);
230 atomsPath = new ArrayList<IAtom>(Arrays.asList(sp.atomsTo(srcT)));
231
232 // Look for the required elements
233 for (String el : reqRingEl)
234 {
235 for (IAtom a : atomsPath)
236 {
237 if (MoleculeUtils.getSymbolOrLabel(a).equals(el))
238 {
239 spanRequiredEls = true;
240 break;
241 }
242 }
243 if (spanRequiredEls)
244 {
245 break;
246 }
247 }
248 if (!spanRequiredEls)
249 {
250 settings.getLogger().log(Level.FINER,
251 "Candidate ring doesn't involve any among the required "
252 + "elements.");
253 return false;
254 }
255 closable = true;
256 }
257
258 // Try to find a match for any of the SMARTS queries
259 Map<String,String> smarts = settings.getConstitutionalClosabilityConds();
260 if (smarts.size() != 0)
261 {
262 closable = false;
263 ManySMARTSQuery msq = new ManySMARTSQuery(mol,smarts);
264 if (msq.hasProblems())
265 {
266 String msg = "Attempt to match SMARTS for "
267 + "constitution-based ring-closability conditions "
268 + "returned an error! Ignoring " + msq.getMessage();
269 settings.getLogger().log(Level.WARNING,msg);
270 }
271 for (String name : smarts.keySet())
272 {
273 if (msq.getNumMatchesOfQuery(name) > 0)
274 {
275 settings.getLogger().log(Level.FINER,
276 "Candidate closable path matches constitutional "
277 + "closability criterion: " + smarts.get(name));
278 closable = true;
279 break;
280 }
281 }
282 }
283
284 settings.getLogger().log(Level.FINE,
285 "Contitutional closability: " + closable);
286 return closable;
287 }
288
289//-----------------------------------------------------------------------------
290
306 private static boolean evaluate3DPathClosability(PathSubGraph subGraph,
307 IAtomContainer mol, RingClosureParameters settings)
308 {
309 String chainId = subGraph.getChainID();
310 settings.getLogger().log(Level.FINE,
311 "Evaluating 3D closability of path: "
312 + subGraph.getVertecesPath()+" ChainID: "+chainId);
313
315
317 boolean closable = false;
318
319 String foundID = rca.containsChain(subGraph);
320 if (foundID != "")
321 {
322 // Get all info from archive
323 closable = rca.getClosabilityOfChain(foundID);
324 rcc = rca.getRCCsOfChain(foundID);
325 if (settings.checkInterdependentChains()
326 && settings.doExhaustiveConfSrch())
327 {
328 try
329 {
330 subGraph.makeMolecularRepresentation(mol, false,
331 settings.getLogger(), settings.getRandomizer());
332 } catch (DENOPTIMException e)
333 {
334 settings.getLogger().warning("Could not create 3D model "
335 + "for potentially closeable path that will be "
336 + "considered not ring-closable.");
337 return false;
338 }
339 subGraph.setRCC(rcc);
340 }
341 }
342 else
343 {
344 // Need to generate 3D molecular representation
345 try {
346 subGraph.makeMolecularRepresentation(mol, true,
347 settings.getLogger(), settings.getRandomizer());
348 } catch (DENOPTIMException e)
349 {
350 settings.getLogger().warning("Could not create 3D model "
351 + "for potentially closeable path that will be "
352 + "considered not ring-closable.");
353 return false;
354 }
355
356 List<IAtom> atomsPath = subGraph.getAtomPath();
357 List<IBond> bondsPath = subGraph.getBondPath();
358
359 // Define rotatability
360 ArrayList<Boolean> rotatability = new ArrayList<Boolean>();
361 for (int i=0; i < bondsPath.size(); i++)
362 {
363 IBond bnd = bondsPath.get(i);
364 Object rotFlag = bnd.getProperty(
366 if (rotFlag == null || !Boolean.valueOf(rotFlag.toString()))
367 {
368 rotatability.add(false);
369 }
370 else
371 {
372 rotatability.add(true);
373 }
374 }
375 settings.getLogger().log(Level.FINE, "Rotatability: "+rotatability);
376
377 // Define initial values of dihedrals
378 // NOTE: these angles are not calculated on the atoms of the chain,
379 // but on the reference points that are unique for each bond
380 // This should allow to compare conformations of different
381 // chains that share one or more bonds
382 ArrayList<ArrayList<Point3d>> dihRefs =
383 subGraph.getDihedralRefPoints();
384 if (dihRefs.size() != rotatability.size()-2)
385 {
386 throw new IllegalStateException("Number of bonds and number of "
387 + "dihidrals angles are inconsistent in PathSubGraph."
388 + " Contact the author.");
389 }
390
391 // find ring closing conformations
392 ArrayList<ArrayList<Double>> closableConfs =
393 new ArrayList<ArrayList<Double>>();
394 closable = RingClosureFinder.evaluateClosability(atomsPath,
395 rotatability,
396 dihRefs,
397 closableConfs,
398 settings);
399
400 // store in object graph
401 rcc = new RingClosingConformations(chainId, closableConfs);
402 subGraph.setRCC(rcc);
403
404 // put ring-closure information in archive for further use
405 rca.storeEntry(chainId,closable,rcc);
406 }
407
408 settings.getLogger().log(Level.FINE, "Path closablility: "+closable);
409
410 return closable;
411 }
412
413//-----------------------------------------------------------------------------
414
415}
General set of constants used in DENOPTIM.
static final String BONDPROPROTATABLE
String tag of Bond's property used to store the property of being rotatable.
A vertex is a data structure that has an identity and holds a list of AttachmentPoints.
Definition: Vertex.java:61
Tool box for determining whether a chain of atoms, i.e., a path, can be folded as to form a ring-clos...
static boolean evaluate3DPathClosability(PathSubGraph subGraph, IAtomContainer mol, RingClosureParameters settings)
Method to evaluate the closability of a single path in a graph representing a molecule.
static boolean evaluateConstitutionalClosability(PathSubGraph subGraph, IAtomContainer iac, RingClosureParameters settings)
Method to evaluate the closability of a single path considering only its constitution.
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.
List< IBond > getBondPath()
Returns the list of bonds in the path between the head and the tail.
void makeMolecularRepresentation(IAtomContainer mol, boolean make3D, Logger logger, Randomizer randomizer)
Creates the molecular representation, list of atoms and bonds involved in the path between the head a...
List< Vertex > getVertecesPath()
Returns the list of verteces involved.
String getChainID()
Returns the string representation of the path.
List< IAtom > getAtomPath()
Returns the list of atoms in the path between the head and the tail.
Vertex getHeadVertex()
Returns the vertex representing the head of the chain.
ArrayList< ArrayList< Point3d > > getDihedralRefPoints()
Returns the list of point to be used to define the torsion of a bond uniquely (independently on the s...
Vertex getTailVertex()
Returns the vertex representing the tail of the chain.
List< Edge > getEdgesPath()
Returns the list of edges involved.
void setRCC(RingClosingConformations rcc)
Set the ring closing conformations to this object.
Serializable object to store/get a list of conformations that allow to close a ring from an open chai...
Tool to explore the conformational space of chains of atoms and identify ring closing conformations.
static boolean evaluateClosability(List< IAtom > path, ArrayList< Boolean > rotatability, ArrayList< ArrayList< Point3d > > dihRefs, ArrayList< ArrayList< Double > > closableConfs, RingClosureParameters settings)
Giving a list of points in 3D space (the path) this method evaluates whether it exists at least one c...
Parameters and setting related to handling ring closures.
Data structure to store and handle information about sub-structures (i.e., chains of fragments) and r...
RingClosingConformations getRCCsOfChain(String chainId)
void storeEntry(String chainId, boolean closable, RingClosingConformations rcc)
Append a new closable chain entry to the archive.
Logger getLogger()
Get the name of the program specific logger.
Randomizer getRandomizer()
Returns the current program-specific randomizer.
Container of lists of atoms matching a list of SMARTS.
int getNumMatchesOfQuery(String query)
Utilities for molecule conversion.
static void removeRCA(IAtomContainer mol)
Replace any PseudoAtoms representing ring closing attractors with H.
static String getSymbolOrLabel(IAtom atm)
Gets either the elemental symbol (for standard atoms) of the label (for pseudo-atoms).
static Map< Vertex, ArrayList< Integer > > getVertexToAtomIdMap(ArrayList< Vertex > vertLst, IAtomContainer mol)
Method to generate the map making in relation DENOPTIMVertex ID and atom index in the IAtomContainer ...
Possible chemical bond types an edge can represent.
Definition: Edge.java:303
boolean hasCDKAnalogue()
Checks if it is possible to convert this edge type into a CDK bond.
Definition: Edge.java:328