$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 (logger.isLoggable(Level.FINE))
154 {
155 String s = "";
156 for (ObjectPair p : rcaComb)
157 {
158 s = s + p.getFirst() + ":" + p.getSecond() + " ";
159 }
160 logger.log(Level.FINE,"Attempting Ring Closure with RCA "
161 + "Combination (" + i + "): " + s);
162 }
163
164 // Try to create new molecule
165 ChemicalObjectModel molTo3d = mol.deepcopy();
167 molTo3d.getRCACombinations().get(i));
168
169 // If some ring remains open, report in the MOL_ERROR field
170 int newRingClosed = rcMol.getNewRingClosures().size();
171 if (newRingClosed < rcaComb.size())
172 {
173 String err = "#RingClosureTool: uncomplete closure (closed "
174 + newRingClosed + "/" + rcaComb.size() + ")";
175 rcMol.getIAtomContainer().setProperty(
177 }
178 rcMols.add(rcMol);
179 }
180
181 // Sort
182 Collections.sort(rcMols, new RingClosedMolComparator());
183
184 return rcMols;
185 }
186
187//------------------------------------------------------------------------------
188
197 private class RingClosedMolComparator implements Comparator<ChemicalObjectModel>
198 {
200 {
201 final int FIRST = 1;
202 final int EQUAL = 0;
203 final int LAST = -1;
204
205 // First criterion is the number of RingClosures
206 int nRcA = mA.getNewRingClosures().size();
207 int nRcB = mB.getNewRingClosures().size();
208 if (nRcA < nRcB) // The HIGHER the number, the BETTER
209 {
210 return FIRST;
211 }
212 else if (nRcA > nRcB)
213 {
214 return LAST;
215 }
216
217 // Second, the quality (closeness to perfection) of RingClosures
218 double scoreA = mA.getNewRingClosuresQuality();
219 double scoreB = mB.getNewRingClosuresQuality();
220 double dist = scoreA - scoreB;
221 double trsh = Math.min(scoreA,scoreB) * 0.05;
222 if (dist > 0.0 && dist > trsh) // The LOWER the score, the BETTER
223 {
224 return FIRST;
225 }
226 if (dist < 0.0 && Math.abs(dist) > trsh)
227 {
228 return LAST;
229 }
230
231 // Third, atom proximity
232 double proxScoreA = mA.getAtomOverlapScore();
233 double proxScoreB = mB.getAtomOverlapScore();
234 if (proxScoreA < proxScoreB) // The HIGHER the proxScore, the BETTER
235 {
236 return FIRST;
237 }
238 else if (proxScoreA > proxScoreB)
239 {
240 return LAST;
241 }
242
243 return EQUAL;
244 }
245 }
246
247//------------------------------------------------------------------------------
248
269 Set<ObjectPair> rcaCombination) throws DENOPTIMException, TinkerException
270 {
271 IAtomContainer fmol = chemObj.getIAtomContainer();
272 String workDir = settings.getWorkingDirectory();
273 String molName = chemObj.getName();
274
275 // Increment iteration number (to make unique file names)
276 itn++;
277
278 logger.log(Level.INFO, "Attempting Ring Closure via conformational"
279 + " adaptation for " + molName
280 + " (PSSROT - Iteration: " + itn + ")");
281
282 List<String> molSpecificKeyFileLines = new ArrayList<String>();
283 molSpecificKeyFileLines.addAll(settings.getRSKeyFileParams());
284 for (ObjectPair op : rcaCombination)
285 {
286 int iTnkAtmRcaA = chemObj.getTnkAtmIdOfRCA(
287 (RingClosingAttractor) op.getFirst());
288 int iTnkAtmRcaB = chemObj.getTnkAtmIdOfRCA(
289 (RingClosingAttractor) op.getSecond());
290 molSpecificKeyFileLines.add("RC-PAIR " + iTnkAtmRcaA + " "
291 + iTnkAtmRcaB);
292 }
293
294 // Definition of RingClosingPotential
295 molSpecificKeyFileLines.add("RC11BNDTERM");
296 molSpecificKeyFileLines.add("RC12BNDTERM NONE");
297 for (ObjectPair op : rcaCombination)
298 {
299 RingClosingAttractor rca0 = (RingClosingAttractor) op.getFirst();
300 RingClosingAttractor rca1 = (RingClosingAttractor) op.getSecond();
301 int s0t = fmol.indexOf(rca0.getSrcAtom()) + 1;
302 int s1t = fmol.indexOf(rca1.getSrcAtom()) + 1;
303 int i0t = chemObj.getTnkAtmIdOfRCA(rca0);
304 int i1t = chemObj.getTnkAtmIdOfRCA(rca1);
305
306 double parA = 0.0;
307 double parB = 0.0;
308 parA = (rca0.getParamA11() + rca1.getParamA11()) / 2.0;
309 parB = (rca0.getParamB11() + rca1.getParamB11()) / 2.0;
310
311 molSpecificKeyFileLines.add("RC-11-PAIRS " + i0t + " " +s1t + " "
312 + parA + " " + parB);
313 molSpecificKeyFileLines.add("RC-11-PAIRS " + s0t + " " + i1t + " "
314 + parA + " " + parB);
315 }
316
317 long startTime = System.nanoTime();
320 molSpecificKeyFileLines,
325 workDir,
327 long endTime = System.nanoTime();
328 long time = (endTime - startTime);
329 logger.log(Level.FINE, "TIME (RC conf. search): "+time/1000000+" ms"
330 + " #frags: " + chemObj.getGraph().getVertexList().size()
331 + " #atoms: " + chemObj.getIAtomContainer().getAtomCount()
332 + " #rotBnds: " + chemObj.getRotatableBonds().size());
333
334 logger.log(Level.INFO, "RC-PSSROT done. Now, post-processing.");
335
336 // Evaluate proximity of RingClosingAttractor and close rings
337 closeRings(chemObj, rcaCombination);
338
339 // Update list rotatable bonds
340 chemObj.purgeListRotatableBonds();
341
342 // Finalize the molecule: saturate free RCA
344
345 // Cleanup
346 FileUtils.deleteFilesContaining(workDir,molName + "_rs" + itn);
347
348 return chemObj;
349 }
350
351//------------------------------------------------------------------------------
352
363 public void closeRings(ChemicalObjectModel mol, Set<ObjectPair> rcaCombination)
364 {
365 // get settings //TODO: this should happen inside RunTimeParameters
368 {
371 }
372
373 // Collect candidate RingClosures
374 List<RingClosure> candidatesClosures = new ArrayList<RingClosure>();
375 for (ObjectPair op : rcaCombination)
376 {
377 logger.log(Level.FINEST, "closeRings: evaluating closure of " + op);
378 RingClosingAttractor rcaA = (RingClosingAttractor) op.getFirst();
379 RingClosingAttractor rcaB = (RingClosingAttractor) op.getSecond();
380 Point3d srcA = rcaA.getSrcAtom().getPoint3d();
381 Point3d atmA = rcaA.getIAtom().getPoint3d();
382 Point3d srcB = rcaB.getSrcAtom().getPoint3d();
383 Point3d atmB = rcaB.getIAtom().getPoint3d();
384 RingClosure rc = new RingClosure(srcA, atmA, srcB, atmB);
385 candidatesClosures.add(rc);
386
387 //Define closability conditions
388 double lenH = srcA.distance(atmA);
389 double lenT = srcB.distance(atmB);
390 double distTolerance = (lenH + lenT) / 2.0;
391 distTolerance = distTolerance * rcParams.getRCDistTolerance();
392 double minDistH1T2 = -1.0;
393 double minDistH2T1 = -1.0;
394 double minDistH2T2 = -1.0;
395 double maxDistH1T2 = 0.0;
396 double maxDistH2T1 = 0.0;
397 double maxDistH2T2 = 0.0;
398 double maxDotProdHT = rcParams.getRCDotPrTolerance();
399
400 maxDistH1T2 = distTolerance;
401 maxDistH2T1 = distTolerance;
402 maxDistH2T2 = lenH + lenT;
403
404 boolean closeThisBnd = rc.isClosable(minDistH1T2, maxDistH1T2,
405 minDistH2T1, maxDistH2T1,
406 minDistH2T2, maxDistH2T2,
407 maxDotProdHT,
408 logger);
409
410 if (closeThisBnd)
411 {
412 BondType bndTyp = rcaA.getRCBondType();
413 if (bndTyp.hasCDKAnalogue())
414 {
415 mol.addBond(rcaA.getSrcAtom(),rcaB.getSrcAtom(),rc, bndTyp);
416 } else {
417 logger.log(Level.WARNING, "WARNING! "
418 + "Attempt to add ring closing bond "
419 + "did not add any actual chemical bond because the "
420 + "bond type of the chord is '" + bndTyp +"'.");
421 }
422 rcaA.setUsed();
423 rcaB.setUsed();
424 }
425 }
426 }
427
428//------------------------------------------------------------------------------
429
445 throws DENOPTIMException
446 {
447 IAtomContainer fmol = mol.getIAtomContainer();
448 TinkerMolecule tmol = mol.getTinkerMolecule();
449 String duSymbol = DENOPTIMConstants.DUMMYATMSYMBOL;
450 for (RingClosingAttractor rca : mol.getAttractorsList())
451 {
452 if (rca.isUsed())
453 {
454 // Used RCA are changed to inert dummy atoms (to keep ZMatrix)
455 IAtom fatm = rca.getIAtom();
456 TinkerAtom tatm = tmol.getAtom(fmol.indexOf(fatm) + 1);
457 tatm.setAtomString(duSymbol);
458
459 IAtom newAtm = new PseudoAtom(duSymbol,new Point3d(fatm.getPoint3d()));
460 newAtm.setProperties(fatm.getProperties());
461 AtomContainerManipulator.replaceAtomByAtom(
462 mol.getIAtomContainer(),fatm,newAtm);
463 rca.setIAtom(newAtm);
464 }
465 else
466 {
467 // Unused RCA are replaced by capping group
468
469 //TODO: select capping group (if any) and use that to saturate the free AP
470 // Note that to do that the capping og the RingClosure-related APclasses must be
471 // reported in the CompatibilityMatrix. Thus, it is also necessary to make DenoptimGA
472 // prefer RingClosure-related APclasses over other capping groups
473 /*
474 //Choose capping group
475 String freeAPClass = rca.getApClass();
476 ArrayList<String> capAPClasses =
477 CGParameters.getCompatibilityMap().get(freeAPClass);
478 */
479 // We force the conversion to H with a fixed bond length
480 // This code is temporary as will be removed by the introduction
481 // proper capping group selection and use (TODO)
482 IAtom fatm = rca.getIAtom();
483 TinkerAtom tatm = tmol.getAtom(fmol.indexOf(fatm) + 1);
484 tatm.setAtomString("H");
485 double[] ic = tatm.getDistAngle();
486 ic[0] = 1.10; //hard coded bond
487 tatm.setDistAngle(ic);
488
489 //UPGRADE: this cannot be done since CDK 2.*. So, we must
490 // create a new IAtom object to replace the old one.
491 /*
492 ((PseudoAtom) fatm).setLabel("H");
493 fatm.setSymbol("H");
494 */
495 IAtom newAtm = new PseudoAtom("H",new Point3d(fatm.getPoint3d()));
496 newAtm.setProperties(fatm.getProperties());
497 AtomContainerManipulator.replaceAtomByAtom(
498 mol.getIAtomContainer(),fatm,newAtm);
499 rca.setIAtom(newAtm);
500 }
501 }
502
503 // Update XYZ
504 mol.updateXYZFromINT();
505
506 // Update Tinker atom types
507 setTinkerTypes(tmol);
508 }
509
510//------------------------------------------------------------------------------
511}
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.