$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.List;
24import java.util.Map;
25import java.util.Set;
26import java.util.logging.Level;
27
28import javax.vecmath.Point3d;
29
30import org.openscience.cdk.graph.ShortestPaths;
31import org.openscience.cdk.interfaces.IAtom;
32import org.openscience.cdk.interfaces.IAtomContainer;
33import org.openscience.cdk.interfaces.IBond;
34import org.openscience.cdk.interfaces.IChemObjectBuilder;
35import org.openscience.cdk.silent.SilentChemObjectBuilder;
36
37import denoptim.constants.DENOPTIMConstants;
38import denoptim.exception.DENOPTIMException;
39import denoptim.graph.Edge.BondType;
40import denoptim.graph.Vertex;
41import denoptim.utils.ManySMARTSQuery;
42import denoptim.utils.MoleculeUtils;
43
44
54{
55
56//-----------------------------------------------------------------------------
57
69 public static boolean isCloseable(PathSubGraph subGraph,
70 IAtomContainer mol, RingClosureParameters settings)
71 {
72 boolean closable = false;
73
74
75 // Cases that we may want to exclude:
76 //
77 // Exclude adding fused cycle of vertexes on already fused system.
78 // This can be achieved by controlling APClass compatibilities, if the
79 // APClasses are also chosen to describe the role of the vertex bearing
80 // the AP in the system, e.g., its role in an aromatic system.
81 // Otherwise, we can see if the vertexes in the path already belong to
82 // cycles: This is fast, so it might be better to do it even if acting
83 // at the level of the molecular representation will deliver the same
84 // information.
85
86
87 switch (settings.getClosabilityEvalMode())
88 {
89 case -1:
90 closable = true; // ring size has been evaluated before
91 break;
92 case 0:
93 closable = evaluateConstitutionalClosability(subGraph, mol,
94 settings);
95 break;
96 case 1:
97 closable = evaluate3DPathClosability(subGraph, mol, settings);
98 break;
99 case 2:
100 closable = evaluateConstitutionalClosability(subGraph, mol,
101 settings) && evaluate3DPathClosability(subGraph, mol,
102 settings);
103 break;
104 default:
105 String s = "Unrecognized closability evaluation mode";
106 throw new IllegalArgumentException(s);
107 }
108 return closable;
109 }
110
111//-----------------------------------------------------------------------------
112
125 private static boolean evaluateConstitutionalClosability(
126 PathSubGraph subGraph, IAtomContainer iac,
127 RingClosureParameters settings)
128 {
129 settings.getLogger().log(Level.FINE, "Evaluating constitutional "
130 + "closability of path: " + subGraph.getVertecesPath());
131
132 // Get a working copy of the molecular container
133 IChemObjectBuilder builder = SilentChemObjectBuilder.getInstance();
134 IAtomContainer mol = builder.newAtomContainer();
135 try
136 {
137 mol = iac.clone();
138 }
139 catch (CloneNotSupportedException e)
140 {
141 throw new IllegalArgumentException(e);
142 }
144
145 // Identify atoms of molecular representation that correspond to
146 // this path of vertices
147 Map<Vertex,ArrayList<Integer>> vIdToAtmId =
149 (ArrayList<Vertex>) subGraph.getVertecesPath(),
150 mol);
151 List<Integer> atmIdsInVrtxPath = new ArrayList<Integer>();
152 for (Vertex v : subGraph.getVertecesPath())
153 {
154 atmIdsInVrtxPath.addAll(vIdToAtmId.get(v));
155 }
156
157 // Find atoms to remove: keep only the atoms that belong to the
158 // vertex path and their neighbours
159 ArrayList<IAtom> toRemove = new ArrayList<IAtom>();
160 for (int i=0; i<mol.getAtomCount(); i++)
161 {
162 if (!atmIdsInVrtxPath.contains(i))
163 {
164 IAtom candAtm = mol.getAtom(i);
165 boolean isNeighbour = false;
166 List<IAtom> nbrs = mol.getConnectedAtomsList(candAtm);
167 for (IAtom nbrAtm : nbrs)
168 {
169 if (atmIdsInVrtxPath.contains(mol.indexOf(nbrAtm)))
170 {
171 isNeighbour = true;
172 break;
173 }
174 }
175 if (!isNeighbour)
176 {
177 toRemove.add(candAtm);
178 }
179 }
180 }
181 // Deal with RCAs: head and tail vertices
182 IAtom atmH = mol.getAtom(vIdToAtmId.get(subGraph.getHeadVertex()).get(0));
183 IAtom atmT = mol.getAtom(vIdToAtmId.get(subGraph.getTailVertex()).get(0));
184 IAtom srcH = mol.getConnectedAtomsList(atmH).get(0);
185 IAtom srcT = mol.getConnectedAtomsList(atmT).get(0);
186 int iSrcH = mol.indexOf(srcH);
187 int iSrcT = mol.indexOf(srcT);
188 toRemove.add(atmH);
189 toRemove.add(atmT);
190
191 BondType bndTyp = subGraph.getEdgesPath().get(0).getBondType();
192 if (bndTyp.hasCDKAnalogue())
193 {
194 mol.addBond(iSrcH, iSrcT, bndTyp.getCDKOrder());
195 } else {
196 settings.getLogger().log(Level.WARNING,
197 "WARNING! Attempt to add ring closing bond "
198 + "did not add any actual chemical bond because the "
199 + "bond type of the chord is '" + bndTyp +"'.");
200 }
201
202 // Remove atoms
203 for (IAtom a : toRemove)
204 {
205 mol.removeAtom(a);
206 }
207
208 StringBuilder sb = new StringBuilder();
209 sb.append("Molecular representation of path includes:");
210 for (IAtom a : mol.atoms())
211 {
212 sb.append(" " + a.getSymbol() + mol.indexOf(a) + " "
213 + a.getProperties());
214 }
215 settings.getLogger().log(Level.FINEST, sb.toString());
216
217 boolean closable = false;
218
219 // Evaluate requirement based on elements contained in the ring
220 boolean spanRequiredEls = false;
221 Set<String> reqRingEl = settings.getRequiredRingElements();
222 if (reqRingEl.size() != 0)
223 {
224 // Prepare shortest atom path
225 List<IAtom> atomsPath = new ArrayList<IAtom>();
226 ShortestPaths sp = new ShortestPaths(mol, srcH);
227 atomsPath = new ArrayList<IAtom>(Arrays.asList(sp.atomsTo(srcT)));
228
229 // Look for the required elements
230 for (String el : reqRingEl)
231 {
232 for (IAtom a : atomsPath)
233 {
234 if (MoleculeUtils.getSymbolOrLabel(a).equals(el))
235 {
236 spanRequiredEls = true;
237 break;
238 }
239 }
240 if (spanRequiredEls)
241 {
242 break;
243 }
244 }
245 if (!spanRequiredEls)
246 {
247 settings.getLogger().log(Level.FINER,
248 "Candidate ring doesn't involve any among the required "
249 + "elements.");
250 return false;
251 }
252 closable = true;
253 }
254
255 // Try to find a match for any of the SMARTS queries
256 Map<String,String> smarts = settings.getConstitutionalClosabilityConds();
257 if (smarts.size() != 0)
258 {
259 closable = false;
260 ManySMARTSQuery msq = new ManySMARTSQuery(mol,smarts);
261 if (msq.hasProblems())
262 {
263 String msg = "Attempt to match SMARTS for "
264 + "constitution-based ring-closability conditions "
265 + "returned an error! Ignoring " + msq.getMessage();
266 settings.getLogger().log(Level.WARNING,msg);
267 }
268 for (String name : smarts.keySet())
269 {
270 if (msq.getNumMatchesOfQuery(name) > 0)
271 {
272 settings.getLogger().log(Level.FINER,
273 "Candidate closable path matches constitutional "
274 + "closability criterion: " + smarts.get(name));
275 closable = true;
276 break;
277 }
278 }
279 }
280
281 settings.getLogger().log(Level.FINE,
282 "Contitutional closability: " + closable);
283 return closable;
284 }
285
286//-----------------------------------------------------------------------------
287
303 private static boolean evaluate3DPathClosability(PathSubGraph subGraph,
304 IAtomContainer mol, RingClosureParameters settings)
305 {
306 String chainId = subGraph.getChainID();
307 settings.getLogger().log(Level.FINE,
308 "Evaluating 3D closability of path: "
309 + subGraph.getVertecesPath()+" ChainID: "+chainId);
310
312
314 boolean closable = false;
315
316 String foundID = rca.containsChain(subGraph);
317 if (foundID != "")
318 {
319 // Get all info from archive
320 closable = rca.getClosabilityOfChain(foundID);
321 rcc = rca.getRCCsOfChain(foundID);
322 if (settings.checkInterdependentChains()
323 && settings.doExhaustiveConfSrch())
324 {
325 try
326 {
327 subGraph.makeMolecularRepresentation(mol, false,
328 settings.getLogger(), settings.getRandomizer());
329 } catch (DENOPTIMException e)
330 {
331 settings.getLogger().warning("Could not create 3D model "
332 + "for potentially closeable path that will be "
333 + "considered not ring-closable.");
334 return false;
335 }
336 subGraph.setRCC(rcc);
337 }
338 }
339 else
340 {
341 // Need to generate 3D molecular representation
342 try {
343 subGraph.makeMolecularRepresentation(mol, true,
344 settings.getLogger(), settings.getRandomizer());
345 } catch (DENOPTIMException e)
346 {
347 settings.getLogger().warning("Could not create 3D model "
348 + "for potentially closeable path that will be "
349 + "considered not ring-closable.");
350 return false;
351 }
352
353 List<IAtom> atomsPath = subGraph.getAtomPath();
354 List<IBond> bondsPath = subGraph.getBondPath();
355
356 // Define rotatability
357 ArrayList<Boolean> rotatability = new ArrayList<Boolean>();
358 for (int i=0; i < bondsPath.size(); i++)
359 {
360 IBond bnd = bondsPath.get(i);
361 Object rotFlag = bnd.getProperty(
363 if (rotFlag == null || !Boolean.valueOf(rotFlag.toString()))
364 {
365 rotatability.add(false);
366 }
367 else
368 {
369 rotatability.add(true);
370 }
371 }
372 settings.getLogger().log(Level.FINE, "Rotatability: "+rotatability);
373
374 // Define initial values of dihedrals
375 // NOTE: these angles are not calculated on the atoms of the chain,
376 // but on the reference points that are unique for each bond
377 // This should allow to compare conformations of different
378 // chains that share one or more bonds
379 ArrayList<ArrayList<Point3d>> dihRefs =
380 subGraph.getDihedralRefPoints();
381 if (dihRefs.size() != rotatability.size()-2)
382 {
383 throw new IllegalStateException("Number of bonds and number of "
384 + "dihidrals angles are inconsistent in PathSubGraph."
385 + " Contact the author.");
386 }
387
388 // find ring closing conformations
389 ArrayList<ArrayList<Double>> closableConfs =
390 new ArrayList<ArrayList<Double>>();
391 closable = RingClosureFinder.evaluateClosability(atomsPath,
392 rotatability,
393 dihRefs,
394 closableConfs,
395 settings);
396
397 // store in object graph
398 rcc = new RingClosingConformations(chainId, closableConfs);
399 subGraph.setRCC(rcc);
400
401 // put ring-closure information in archive for further use
402 rca.storeEntry(chainId,closable,rcc);
403 }
404
405 settings.getLogger().log(Level.FINE, "Path closablility: "+closable);
406
407 return closable;
408 }
409
410//-----------------------------------------------------------------------------
411
412}
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