$darkmode
DENOPTIM
RingClosureFinder.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.List;
23import java.util.logging.Level;
24import java.util.logging.Logger;
25
26import javax.vecmath.AxisAngle4d;
27import javax.vecmath.Matrix3d;
28import javax.vecmath.Point3d;
29import javax.vecmath.Vector3d;
30
31import org.openscience.cdk.Atom;
32import org.openscience.cdk.interfaces.IAtom;
33import org.openscience.cdk.interfaces.IAtomContainer;
34import org.openscience.cdk.interfaces.IBond;
35import org.openscience.cdk.interfaces.IChemObjectBuilder;
36import org.openscience.cdk.silent.SilentChemObjectBuilder;
37
38import denoptim.constants.DENOPTIMConstants;
39import denoptim.io.DenoptimIO;
40import denoptim.utils.MathUtils;
41
50{
51
52 private final static String NL = DENOPTIMConstants.EOL;
53//----------------------------------------------------------------------------
54
65 public static boolean evaluateClosability(List<IAtom> path,
66 ArrayList<Boolean> rotatability,
67 ArrayList<ArrayList<Point3d>> dihRefs,
68 ArrayList<ArrayList<Double>> closableConfs,
69 RingClosureParameters settings)
70 {
71 boolean res = false;
72
73 // Check input
74 int sz = path.size();
75 if (rotatability.size() != sz-1)
76 {
77 throw new Error("ERROR! Cannot evaluate closability of path: "
78 + "path and list of bonds are not compatible!"
79 + "(" + sz + ", " + rotatability.size() + ")"
80 + " Please, Report this bug to the author.");
81 }
82 //NB: the '+2' comes from the 'bonds' to RCAs: 2 per fundamental ring
83 if (sz > settings.getMaxNumberRotatableBonds()+2)
84 {
85 settings.getLogger().log(Level.WARNING, "Too many rotatable bonds "
86 + "for systematic search. We assume the path is closable.");
87 return true;
88 }
89
90 // Create the chain of points to work with
91 List<Point3d> ptsChain = new ArrayList<Point3d>();
92 for (int i=0; i<path.size(); i++)
93 {
94 ptsChain.add(new Point3d(path.get(i).getPoint3d()));
95 }
96
97 // Get closability condition
98 // Nomenclature:
99 // head vector tail vector
100 // h2-----h1|..........|t1-----t2
101 int h1 = 1;
102 int h2 = 0;
103 int t1 = sz - 2;
104 int t2 = sz - 1;
105 RingClosure rc = new RingClosure(path.get(h1).getPoint3d(),
106 path.get(h2).getPoint3d(),
107 path.get(t1).getPoint3d(),
108 path.get(t2).getPoint3d());
109 ArrayList<Double> clsablConds = rc.getClosabilityConditions(
110 settings.getConfPathExtraTolerance());
111 settings.getLogger().log(Level.FINE, "RingClosability conditions "
112 + "vector:" + clsablConds);
113
114 // Make work vector of dihedrals (angles around rotatable bonds)
115 // avoiding linearities
116 ArrayList<Double> dihedrals = new ArrayList<Double>();
117 ArrayList<Double> dihIncement = new ArrayList<Double>();
118 int nn = 0;
119 for (int i=2; i<ptsChain.size(); i++)
120 {
121 double a = MathUtils.angle(ptsChain.get(i-2),
122 ptsChain.get(i-1),
123 ptsChain.get(i));
124 if (a >= settings.getLinearityLimit())
125 {
126 settings.getLogger().log(Level.FINE, "Skipping linearity in "
127 + "point "+i);
128 rotatability.set(i-1,false);
129 }
130 else
131 {
132 nn++;
133 }
134 if (i==2)
135 {
136 // add FIRST even if it is always not rotatable
137 dihedrals.add(0.0);
138 dihIncement.add(0.0);
139 }
140 else
141 {
142 ArrayList<Point3d> refPoints = dihRefs.get(i-3);
143 dihedrals.add(MathUtils.computeDihedralAngle(
144 refPoints.get(0),
145 refPoints.get(1),
146 refPoints.get(2),
147 refPoints.get(3)));
148 dihIncement.add(0.0);
149 }
150 }
151 // add LAST even if it is always not rotatable
152 dihedrals.add(0.0);
153 dihIncement.add(0.0);
154
155 settings.getLogger().log(Level.FINE, "Exploring torsional space... (dim:"
156 + nn + " - complete:" + settings.doExhaustiveConfSrch()+")");
157
158 long startTime = System.nanoTime();
159 hasClosableRotamer(ptsChain,
160 rotatability,
161 dihedrals,
162 dihIncement,
163 0,
164 settings.getPathConfSearchStep(),
165 h1,h2,t1,t2,
166 clsablConds,
167 closableConfs,
168 settings.doExhaustiveConfSrch(),
169 false, //true for debug only!
170 settings.getLogger(),
171 0);
172 long endTime = System.nanoTime();
173 long time = (endTime - startTime) / (long) 1000.0;
174
175 settings.getLogger().log(Level.FINE, "TIME (microsec) for exploration "
176 + "of torsional space: "+ time);
177
178 if (closableConfs.size() > 0)
179 res = true;
180
181 return res;
182 }
183
184//----------------------------------------------------------------------------
185
204 public static boolean hasClosableRotamer(List<Point3d> chain,
205 ArrayList<Boolean> rotatability,
206 ArrayList<Double> dihedrals,
207 ArrayList<Double> dihIncement,
208 int activeRot,
209 double step,
210 int h1, int h2, int t1, int t2,
211 ArrayList<Double> clsablConds,
212 ArrayList<ArrayList<Double>> closableConfs,
213 boolean doExhaustiveSearch,
214 boolean writeAllConfs,
215 Logger logger,
216 int rec)
217 {
218
219 boolean res = false;
220 logger.log(Level.FINEST,"-Rec: "+activeRot);
221 int totStp = (int) (360.0 / step);
222 if (!rotatability.get(activeRot))
223 {
224 logger.log(Level.FINEST, rec+"-Rec: not active");
225 totStp = 1;
226 }
227 for (int i=0; i<totStp; i++)
228 {
229 logger.log(Level.FINEST,rec+"-RecLop: "+activeRot+" I:"+i);
230 if (i != 0)
231 {
232 dihIncement.set(activeRot,dihIncement.get(activeRot) + step);
233
234 // Move the whole branch of points that lie after the rotbond
235 Point3d srcRotBnd = chain.get(activeRot);
236 Point3d endRotBnd = chain.get(activeRot+1);
237 Vector3d rotAxis = new Vector3d(endRotBnd.x - srcRotBnd.x,
238 endRotBnd.y - srcRotBnd.y,
239 endRotBnd.z - srcRotBnd.z);
240 rotAxis.normalize();
241 Matrix3d rotMat = new Matrix3d();
242
243 rotMat.set(new AxisAngle4d(rotAxis,Math.toRadians(step)));
244
245 logger.log(Level.FINEST," srcRotBnd: " + srcRotBnd+NL
246 +" endRotBnd: " + endRotBnd+NL
247 +" rotAxis: " + rotAxis+NL
248 +" rotMat: " + rotMat);
249
250 for (int ip = activeRot+2; ip<chain.size(); ip++)
251 {
252 Point3d pt = chain.get(ip);
253 // Translate to origin of rot. axis while making vector
254 Vector3d newVec = new Vector3d(pt.x - srcRotBnd.x,
255 pt.y - srcRotBnd.y,
256 pt.z - srcRotBnd.z);
257 // Rotate
258 rotMat.transform(newVec);
259
260 // Translate back to original space
261 pt.x = newVec.x + srcRotBnd.x;
262 pt.y = newVec.y + srcRotBnd.y;
263 pt.z = newVec.z + srcRotBnd.z;
264 }
265 }
266
267 if (activeRot+1 < dihedrals.size())
268 {
269 // Lauch exploration of next level
270 rec++;
271 int nextRot = activeRot+1;
272 res = hasClosableRotamer(chain,
273 rotatability,
274 dihedrals,
275 dihIncement,
276 nextRot,
277 step,
278 h1,h2,t1,t2,
279 clsablConds,
280 closableConfs,
281 doExhaustiveSearch,
282 writeAllConfs,
283 logger,
284 rec);
285 rec--;
286 }
287 else
288 {
289 // Evaluate current conformation
290 Point3d pH1 = chain.get(h1);
291 Point3d pH2 = chain.get(h2);
292 Point3d pT1 = chain.get(t1);
293 Point3d pT2 = chain.get(t2);
294 RingClosure rc = new RingClosure(pH1,pH2,pT1,pT2);
295 res = rc.isClosable(clsablConds, logger);
296 if (res)
297 {
298 // Store vector of dihedrals
299 ArrayList<Double> conf = new ArrayList<Double>();
300 for (int ib=0; ib<dihedrals.size(); ib++)
301 {
302 double tot = dihedrals.get(ib) + dihIncement.get(ib);
303 if (tot > 180.0)
304 {
305 tot = tot - 360.0;
306 }
307 conf.add(tot);
308 }
309 closableConfs.add(conf);
310
311 StringBuilder sb = new StringBuilder();
312 sb.append("Found closable path conformation!");
313 if (writeAllConfs)
314 {
315 reportForDebug("closable.sdf",chain);
316 sb.append(" Dihedrals: " + dihedrals+NL);
317 sb.append(" Increments: " + dihIncement+NL);
318 sb.append(" Conf.: " + conf+NL);
319 sb.append(" See 'closable.sdf'"+NL);
320 }
321 logger.log(Level.FINE, sb.toString());
322 }
323 else
324 {
325 if (writeAllConfs)
326 {
327 StringBuilder sb = new StringBuilder();
328 reportForDebug("not_closable.sdf",chain);
329 sb.append("Conformation of path is NOT "
330 +"closable! See 'not_closable.sdf'");
331 sb.append(" Dihedrals: " + dihedrals+NL);
332 sb.append(" Increments: " + dihIncement+NL);
333 sb.append(" Chain:"+NL);
334 for (int ii=0; ii<chain.size(); ii++)
335 sb.append(" " + chain.get(ii)+NL);
336 logger.log(Level.FINE, sb.toString());
337 }
338 }
339 }
340 if (!doExhaustiveSearch)
341 {
342 if (res)
343 {
344 logger.log(Level.FINE, "Stop recursive conf. search."
345 + " (rec.: " + rec + ")");
346 break;
347 }
348 }
349 }
350
351 // reset
352 if (rotatability.get(activeRot))
353 {
354 dihIncement.set(activeRot,dihIncement.get(activeRot)-step*(totStp-1));
355
356 // Move back the whole branch of points that lie after the rotbond
357 Point3d srcRotBnd = chain.get(activeRot);
358 Point3d endRotBnd = chain.get(activeRot+1);
359 Vector3d rotAxis = new Vector3d(endRotBnd.x - srcRotBnd.x,
360 endRotBnd.y - srcRotBnd.y,
361 endRotBnd.z - srcRotBnd.z);
362 rotAxis.normalize();
363 Matrix3d rotMat = new Matrix3d();
364 rotMat.set(new AxisAngle4d(rotAxis,
365 Math.toRadians(-step * (totStp - 1))));
366
367 for (int ip = activeRot+2; ip<chain.size(); ip++)
368 {
369 Point3d pt = chain.get(ip);
370 // Translate to origin of rot. axis while making vector
371 Vector3d newVec = new Vector3d(pt.x - srcRotBnd.x,
372 pt.y - srcRotBnd.y,
373 pt.z - srcRotBnd.z);
374 // Rotate
375 rotMat.transform(newVec);
376
377 // Translate back to original space
378 pt.x = newVec.x + srcRotBnd.x;
379 pt.y = newVec.y + srcRotBnd.y;
380 pt.z = newVec.z + srcRotBnd.z;
381 }
382 }
383 return res;
384 }
385
386//----------------------------------------------------------------------------
387
392 private static void reportForDebug(String filename, List<Point3d> chain)
393 {
394 IChemObjectBuilder builder = SilentChemObjectBuilder.getInstance();
395 IAtomContainer mol = builder.newAtomContainer();
396 for (int ia=0 ; ia<chain.size(); ia++)
397 {
398 Atom atm = new Atom("He",chain.get(ia));
399 mol.addAtom(atm);
400 if (ia > 0)
401 mol.addBond(ia-1,ia,IBond.Order.valueOf("SINGLE"));
402 }
403 try
404 {
405 DenoptimIO.writeSDFFile(filename, mol, true);
406 } catch (Throwable thr)
407 {
408 System.out.println("Unable to write SDF: "+thr);
409 }
410 }
411
412//----------------------------------------------------------------------------
413
414}
General set of constants used in DENOPTIM.
static final String EOL
new line character
Tool to explore the conformational space of chains of atoms and identify ring closing conformations.
static void reportForDebug(String filename, List< Point3d > chain)
Method for reporting a path of atoms (list of points) as SDF file.
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...
static boolean hasClosableRotamer(List< Point3d > chain, ArrayList< Boolean > rotatability, ArrayList< Double > dihedrals, ArrayList< Double > dihIncement, int activeRot, double step, int h1, int h2, int t1, int t2, ArrayList< Double > clsablConds, ArrayList< ArrayList< Double > > closableConfs, boolean doExhaustiveSearch, boolean writeAllConfs, Logger logger, int rec)
Scan rotatable space looking for conformations that satisfy closability condition.
RingClosure represents the arrangement of atoms and PseudoAtoms identifying the head and tail of a ch...
boolean isClosable(ArrayList< Double > clsablConds, Logger logger)
Evaluate closability by comparing the distances and the dot product with the given critera.
ArrayList< Double > getClosabilityConditions(double etrxTol)
Returns the list of min/max values defining the closability conditions.
Parameters and setting related to handling ring closures.
Utility methods for input/output.
static void writeSDFFile(String fileName, IAtomContainer mol)
Writes IAtomContainer to SDF file.
Logger getLogger()
Get the name of the program specific logger.
Some useful math operations.
Definition: MathUtils.java:39
static double angle(Point3d a, Point3d b, Point3d c)
Calculate the angle between the 3 points.
Definition: MathUtils.java:284
static double computeDihedralAngle(Point3d p0, Point3d p1, Point3d p2, Point3d p3)
Compute the dihedral angle.
Definition: MathUtils.java:218