$darkmode
DENOPTIM
RingClosureTool.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.molecularmodeling;
20
21import java.util.ArrayList;
22import java.util.Collections;
23import java.util.Comparator;
24import java.util.List;
25import java.util.Set;
26import java.util.logging.Level;
27import java.util.logging.Logger;
28
29import javax.vecmath.Point3d;
30
31import org.openscience.cdk.PseudoAtom;
32import org.openscience.cdk.interfaces.IAtom;
33import org.openscience.cdk.interfaces.IAtomContainer;
34import org.openscience.cdk.tools.manipulator.AtomContainerManipulator;
35
36import denoptim.constants.DENOPTIMConstants;
37import denoptim.exception.DENOPTIMException;
38import denoptim.files.FileUtils;
39import denoptim.graph.Edge.BondType;
40import denoptim.graph.rings.RingClosingAttractor;
41import denoptim.graph.rings.RingClosure;
42import denoptim.graph.rings.RingClosureParameters;
43import denoptim.integration.tinker.ConformationalSearchPSSROT;
44import denoptim.integration.tinker.TinkerAtom;
45import denoptim.integration.tinker.TinkerException;
46import denoptim.integration.tinker.TinkerMolecule;
47import denoptim.programs.RunTimeParameters.ParametersType;
48import denoptim.programs.moldecularmodelbuilder.MMBuilderParameters;
49import denoptim.utils.ObjectPair;
50
58public class RingClosureTool
59{
63 private int itn = 0;
64
68 final String fsep = System.getProperty("file.separator");
69
74
78 private Logger logger;
79
80//------------------------------------------------------------------------------
81
86 {
87 this.settings = settings;
88 this.logger = settings.getLogger();
89 }
90
91//------------------------------------------------------------------------------
92
105 {
106
107 ArrayList<TinkerAtom> lstAtoms = tmol.getAtoms();
108 int numberOfAtoms = lstAtoms.size();
109 for (int i = 0; i < numberOfAtoms; i++)
110 {
111 TinkerAtom tatom = lstAtoms.get(i);
112
113 String st = tatom.getAtomString().trim();
114 if (!settings.getTinkerMap().containsKey(st))
115 {
116 String msg = "Unable to assign atom type to atom '" + st +"'.";
117 throw new DENOPTIMException(msg);
118 }
119 Integer val = settings.getTinkerMap().get(st);
120 if (val != null)
121 {
122 tatom.setAtomType(val.intValue());
123 logger.log(Level.FINEST, "Set parameter for " + st);
124 }
125 else
126 {
127 String msg = "No valid Tinker atom type for atom " + st;
128 throw new DENOPTIMException(msg);
129 }
130 }
131 }
132
133//------------------------------------------------------------------------------
134
146 public ArrayList<ChemicalObjectModel> attemptAllRingClosures(
148 {
149 ArrayList<ChemicalObjectModel> rcMols = new ArrayList<ChemicalObjectModel>();
150 for (int i=0; i<mol.getRCACombinations().size(); i++)
151 {
152 Set<ObjectPair> rcaComb = mol.getRCACombinations().get(i);
153 if (rcaComb.isEmpty())
154 {
155 logger.log(Level.WARNING,"Attempt to close rings with "
156 + "no compatible RCA combination. "
157 + "This is most likely a mistake. Please, "
158 + "make sure that ring-closing vertexes are"
159 + "properly detected.");
160 }
161 if (logger.isLoggable(Level.FINE))
162 {
163 String s = "";
164 for (ObjectPair p : rcaComb)
165 {
166 s = s + p.getFirst() + ":" + p.getSecond() + " ";
167 }
168 logger.log(Level.FINE,"Attempting Ring Closure with RCA "
169 + "Combination (" + i + "): " + s);
170 }
171
172 // Try to create new molecule
173 ChemicalObjectModel molTo3d = mol.deepcopy();
175 molTo3d.getRCACombinations().get(i));
176
177 // If some ring remains open, report in the MOL_ERROR field
178 int newRingClosed = rcMol.getNewRingClosures().size();
179 if (newRingClosed < rcaComb.size())
180 {
181 String err = "#RingClosureTool: uncomplete closure (closed "
182 + newRingClosed + "/" + rcaComb.size() + ")";
183 rcMol.getIAtomContainer().setProperty(
185 }
186 rcMols.add(rcMol);
187 }
188
189 // Sort
190 Collections.sort(rcMols, new RingClosedMolComparator());
191
192 return rcMols;
193 }
194
195//------------------------------------------------------------------------------
196
205 private class RingClosedMolComparator implements Comparator<ChemicalObjectModel>
206 {
208 {
209 final int FIRST = 1;
210 final int EQUAL = 0;
211 final int LAST = -1;
212
213 // First criterion is the number of RingClosures
214 int nRcA = mA.getNewRingClosures().size();
215 int nRcB = mB.getNewRingClosures().size();
216 if (nRcA < nRcB) // The HIGHER the number, the BETTER
217 {
218 return FIRST;
219 }
220 else if (nRcA > nRcB)
221 {
222 return LAST;
223 }
224
225 // Second, the quality (closeness to perfection) of RingClosures
226 double scoreA = mA.getNewRingClosuresQuality();
227 double scoreB = mB.getNewRingClosuresQuality();
228 double dist = scoreA - scoreB;
229 double trsh = Math.min(scoreA,scoreB) * 0.05;
230 if (dist > 0.0 && dist > trsh) // The LOWER the score, the BETTER
231 {
232 return FIRST;
233 }
234 if (dist < 0.0 && Math.abs(dist) > trsh)
235 {
236 return LAST;
237 }
238
239 // Third, atom proximity
240 double proxScoreA = mA.getAtomOverlapScore();
241 double proxScoreB = mB.getAtomOverlapScore();
242 if (proxScoreA < proxScoreB) // The HIGHER the proxScore, the BETTER
243 {
244 return FIRST;
245 }
246 else if (proxScoreA > proxScoreB)
247 {
248 return LAST;
249 }
250
251 return EQUAL;
252 }
253 }
254
255//------------------------------------------------------------------------------
256
277 Set<ObjectPair> rcaCombination) throws DENOPTIMException, TinkerException
278 {
279 IAtomContainer fmol = chemObj.getIAtomContainer();
280 String workDir = settings.getWorkingDirectory();
281 String molName = chemObj.getName();
282
283 // Increment iteration number (to make unique file names)
284 itn++;
285
286 logger.log(Level.INFO, "Attempting Ring Closure via conformational"
287 + " adaptation for " + molName
288 + " (PSSROT - Iteration: " + itn + ")");
289
290 List<String> molSpecificKeyFileLines = new ArrayList<String>();
291 molSpecificKeyFileLines.addAll(settings.getRSKeyFileParams());
292 for (ObjectPair op : rcaCombination)
293 {
294 int iTnkAtmRcaA = chemObj.getTnkAtmIdOfRCA(
295 (RingClosingAttractor) op.getFirst());
296 int iTnkAtmRcaB = chemObj.getTnkAtmIdOfRCA(
297 (RingClosingAttractor) op.getSecond());
298 molSpecificKeyFileLines.add("RC-PAIR " + iTnkAtmRcaA + " "
299 + iTnkAtmRcaB);
300 }
301
302 // Definition of RingClosingPotential
303 molSpecificKeyFileLines.add("RC11BNDTERM");
304 molSpecificKeyFileLines.add("RC12BNDTERM NONE");
305 for (ObjectPair op : rcaCombination)
306 {
307 RingClosingAttractor rca0 = (RingClosingAttractor) op.getFirst();
308 RingClosingAttractor rca1 = (RingClosingAttractor) op.getSecond();
309 int s0t = fmol.indexOf(rca0.getSrcAtom()) + 1;
310 int s1t = fmol.indexOf(rca1.getSrcAtom()) + 1;
311 int i0t = chemObj.getTnkAtmIdOfRCA(rca0);
312 int i1t = chemObj.getTnkAtmIdOfRCA(rca1);
313
314 double parA = 0.0;
315 double parB = 0.0;
316 parA = (rca0.getParamA11() + rca1.getParamA11()) / 2.0;
317 parB = (rca0.getParamB11() + rca1.getParamB11()) / 2.0;
318
319 molSpecificKeyFileLines.add("RC-11-PAIRS " + i0t + " " +s1t + " "
320 + parA + " " + parB);
321 molSpecificKeyFileLines.add("RC-11-PAIRS " + s0t + " " + i1t + " "
322 + parA + " " + parB);
323 }
324
325 long startTime = System.nanoTime();
328 molSpecificKeyFileLines,
333 workDir,
335 long endTime = System.nanoTime();
336 long time = (endTime - startTime);
337 logger.log(Level.FINE, "TIME (RC conf. search): "+time/1000000+" ms"
338 + " #frags: " + chemObj.getGraph().getVertexList().size()
339 + " #atoms: " + chemObj.getIAtomContainer().getAtomCount()
340 + " #rotBnds: " + chemObj.getRotatableBonds().size());
341
342 logger.log(Level.INFO, "RC-PSSROT done. Now, post-processing.");
343
344 // Evaluate proximity of RingClosingAttractor and close rings
345 closeRings(chemObj, rcaCombination);
346
347 // Update list rotatable bonds
348 chemObj.purgeListRotatableBonds();
349
350 // Finalize the molecule: saturate free RCA
352
353 // Cleanup
354 FileUtils.deleteFilesContaining(workDir,molName + "_rs" + itn);
355
356 return chemObj;
357 }
358
359//------------------------------------------------------------------------------
360
371 public void closeRings(ChemicalObjectModel mol, Set<ObjectPair> rcaCombination)
372 {
373 // get settings //TODO: this should happen inside RunTimeParameters
376 {
379 }
380
381 // Collect candidate RingClosures
382 List<RingClosure> candidatesClosures = new ArrayList<RingClosure>();
383 for (ObjectPair op : rcaCombination)
384 {
385 logger.log(Level.FINEST, "closeRings: evaluating closure of " + op);
386 RingClosingAttractor rcaA = (RingClosingAttractor) op.getFirst();
387 RingClosingAttractor rcaB = (RingClosingAttractor) op.getSecond();
388 Point3d srcA = rcaA.getSrcAtom().getPoint3d();
389 Point3d atmA = rcaA.getIAtom().getPoint3d();
390 Point3d srcB = rcaB.getSrcAtom().getPoint3d();
391 Point3d atmB = rcaB.getIAtom().getPoint3d();
392 RingClosure rc = new RingClosure(srcA, atmA, srcB, atmB);
393 candidatesClosures.add(rc);
394
395 //Define closability conditions
396 double lenH = srcA.distance(atmA);
397 double lenT = srcB.distance(atmB);
398 double distTolerance = (lenH + lenT) / 2.0;
399 distTolerance = distTolerance * rcParams.getRCDistTolerance();
400 double minDistH1T2 = -1.0;
401 double minDistH2T1 = -1.0;
402 double minDistH2T2 = -1.0;
403 double maxDistH1T2 = 0.0;
404 double maxDistH2T1 = 0.0;
405 double maxDistH2T2 = 0.0;
406 double maxDotProdHT = rcParams.getRCDotPrTolerance();
407
408 maxDistH1T2 = distTolerance;
409 maxDistH2T1 = distTolerance;
410 maxDistH2T2 = lenH + lenT;
411
412 boolean closeThisBnd = rc.isClosable(minDistH1T2, maxDistH1T2,
413 minDistH2T1, maxDistH2T1,
414 minDistH2T2, maxDistH2T2,
415 maxDotProdHT,
416 logger);
417
418 if (closeThisBnd)
419 {
420 BondType bndTyp = rcaA.getRCBondType();
421 if (bndTyp.hasCDKAnalogue())
422 {
423 mol.addBond(rcaA.getSrcAtom(),rcaB.getSrcAtom(),rc, bndTyp);
424 } else {
425 logger.log(Level.WARNING, "WARNING! "
426 + "Attempt to add ring closing bond "
427 + "did not add any actual chemical bond because the "
428 + "bond type of the chord is '" + bndTyp +"'.");
429 }
430 rcaA.setUsed();
431 rcaB.setUsed();
432 }
433 }
434 }
435
436//------------------------------------------------------------------------------
437
453 throws DENOPTIMException
454 {
455 IAtomContainer fmol = mol.getIAtomContainer();
456 TinkerMolecule tmol = mol.getTinkerMolecule();
457 String duSymbol = DENOPTIMConstants.DUMMYATMSYMBOL;
458 for (RingClosingAttractor rca : mol.getAttractorsList())
459 {
460 if (rca.isUsed())
461 {
462 // Used RCA are changed to inert dummy atoms (to keep ZMatrix)
463 IAtom fatm = rca.getIAtom();
464 TinkerAtom tatm = tmol.getAtom(fmol.indexOf(fatm) + 1);
465 tatm.setAtomString(duSymbol);
466
467 IAtom newAtm = new PseudoAtom(duSymbol,new Point3d(fatm.getPoint3d()));
468 newAtm.setProperties(fatm.getProperties());
469 AtomContainerManipulator.replaceAtomByAtom(
470 mol.getIAtomContainer(),fatm,newAtm);
471 rca.setIAtom(newAtm);
472 }
473 else
474 {
475 // Unused RCA are replaced by capping group
476
477 //TODO: select capping group (if any) and use that to saturate the free AP
478 // Note that to do that the capping og the RingClosure-related APclasses must be
479 // reported in the CompatibilityMatrix. Thus, it is also necessary to make DenoptimGA
480 // prefer RingClosure-related APclasses over other capping groups
481 /*
482 //Choose capping group
483 String freeAPClass = rca.getApClass();
484 ArrayList<String> capAPClasses =
485 CGParameters.getCompatibilityMap().get(freeAPClass);
486 */
487 // We force the conversion to H with a fixed bond length
488 // This code is temporary as will be removed by the introduction
489 // proper capping group selection and use (TODO)
490 IAtom fatm = rca.getIAtom();
491 TinkerAtom tatm = tmol.getAtom(fmol.indexOf(fatm) + 1);
492 tatm.setAtomString("H");
493 double[] ic = tatm.getDistAngle();
494 ic[0] = 1.10; //hard coded bond
495 tatm.setDistAngle(ic);
496
497 //UPGRADE: this cannot be done since CDK 2.*. So, we must
498 // create a new IAtom object to replace the old one.
499 /*
500 ((PseudoAtom) fatm).setLabel("H");
501 fatm.setSymbol("H");
502 */
503 IAtom newAtm = new PseudoAtom("H",new Point3d(fatm.getPoint3d()));
504 newAtm.setProperties(fatm.getProperties());
505 AtomContainerManipulator.replaceAtomByAtom(
506 mol.getIAtomContainer(),fatm,newAtm);
507 rca.setIAtom(newAtm);
508 }
509 }
510
511 // Update XYZ
512 mol.updateXYZFromINT();
513
514 // Update Tinker atom types
515 setTinkerTypes(tmol);
516 }
517
518//------------------------------------------------------------------------------
519}
General set of constants used in DENOPTIM.
static final String MOLERRORTAG
SDF tag containing errors during execution of molecule specific tasks.
static final String DUMMYATMSYMBOL
Symbol of dummy atom.
static void deleteFilesContaining(String path, String pattern)
Delete all files with pathname containing a given string.
Definition: FileUtils.java:289
The RingClosingAttractor represent the available valence/connection that allows to close a ring.
IAtom getSrcAtom()
Get the atom in the parent fragment that holds the attachment point occupied by this RingClosingAttra...
void setUsed()
Set this RingClosingAttractor to 'used'.
IAtom getIAtom()
Get the atom corresponding to this RingClosingAttractor in the molecular representation.
BondType getRCBondType()
Get the type of bond this attractor is meant to close.
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.
Parameters and setting related to handling ring closures.
Toolkit to perform conformational search via Tinker PSSROT program.
static void performPSSROT(ArrayList< ChemicalObjectModel > mols, String runLabel, String ffFilePathName, List< String > keyFileLines, List< String > subParamsInit, List< String > subParamsRest, String pssExePathName, String xyzintPathName, String workDir, int taskId, Logger logger)
Performs PSSROT conformational search for all chemical objects in the list.
Based on the code from ffx.kenai.com Michael J.
Definition: TinkerAtom.java:26
void setDistAngle(double[] distAngles)
Exceptions resulting from a failure of Tinker.
TinkerAtom getAtom(int pos)
Returns the atom which has the XYZ index set to pos.
Collector of molecular information, related to a single chemical object, that is deployed within the ...
double getAtomOverlapScore()
Return the atoms overlap score which is calculated for all atoms pairs not in 1-4 or lower relationsh...
double getNewRingClosuresQuality()
Return the overal evaluation of the whole list of RingClosures.
ChemicalObjectModel deepcopy()
Return a new Molecule3DBuilder having exactly the same features of this Molecule3DBuilder.
IAtomContainer getIAtomContainer()
Returns the CDK representation of the molecular system.
void addBond(IAtom atmA, IAtom atmB, RingClosure nRc, BondType bndTyp)
Modify the molecule adding a cyclic bond between two atoms.
ArrayList< Set< ObjectPair > > getRCACombinations()
Returns the list of combinations of RingClosingAttractor.
ArrayList< RingClosure > getNewRingClosures()
Return the list of RingClosures that have been identified as closable head/tail of atom chains during...
Compares the Molecule3DBuilder afters ring closing-biased conformational adaptation.
int compare(ChemicalObjectModel mA, ChemicalObjectModel mB)
Toolkit to perform ring closing conformational search.
void closeRings(ChemicalObjectModel mol, Set< ObjectPair > rcaCombination)
Makes new rings by connecting pairs of atoms that hold properly arranged RingClosingAttractors.
int itn
Iteration counter for making unique filenames.
MMBuilderParameters settings
Settings controlling the calculation.
void saturateRingClosingAttractor(ChemicalObjectModel mol)
Looks for unused RingClosingAttractors and attach proper capping group saturating the free valency/bo...
ArrayList< ChemicalObjectModel > attemptAllRingClosures(ChemicalObjectModel mol)
Performs one or more attempts to close rings by conformational adaptation.
RingClosureTool(MMBuilderParameters settings)
Construct an empty RingClosureTool.
ChemicalObjectModel attemptRingClosure(ChemicalObjectModel chemObj, Set< ObjectPair > rcaCombination)
Attempts to close rings by finding the conformation that allows to join heads and tails of atom speci...
void setTinkerTypes(TinkerMolecule tmol)
Conversion to tinker IC may not always have the necessary atom types.
Logger logger
Program.specific logger.
boolean containsParameters(ParametersType type)
RunTimeParameters getParameters(ParametersType type)
Logger getLogger()
Get the name of the program specific logger.
Parameters for the conformer generator (3D builder).
This class is the equivalent of the Pair data structure used in C++ Although AbstractMap....
Definition: ObjectPair.java:30
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
RC_PARAMS
Parameters pertaining to ring closures in graphs.