$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.rcoserver.RCOSocketServerClient;
44import denoptim.integration.tinker.ConformationalSearchPSSROT;
45import denoptim.integration.tinker.TinkerException;
46import denoptim.molecularmodeling.zmatrix.ZMatrix;
47import denoptim.molecularmodeling.zmatrix.ZMatrixAtom;
48import denoptim.programs.RunTimeParameters.ParametersType;
49import denoptim.programs.moldecularmodelbuilder.MMBuilderParameters;
50import denoptim.utils.ObjectPair;
51
62public class RingClosureTool
63{
67 private int itn = 0;
68
72 final String fsep = System.getProperty("file.separator");
73
78
82 private Logger logger;
83
84//------------------------------------------------------------------------------
85
90 {
91 this.settings = settings;
92 this.logger = settings.getLogger();
93 }
94
95//------------------------------------------------------------------------------
96
108 public ArrayList<ChemicalObjectModel> attemptAllRingClosures(
110 {
111 ArrayList<ChemicalObjectModel> rcMols = new ArrayList<ChemicalObjectModel>();
112 for (int i=0; i<mol.getRCACombinations().size(); i++)
113 {
114 Set<ObjectPair> rcaComb = mol.getRCACombinations().get(i);
115 if (rcaComb.isEmpty())
116 {
117 logger.log(Level.WARNING,"Attempt to close rings with "
118 + "no compatible RCA combination. "
119 + "This is most likely a mistake. Please, "
120 + "make sure that ring-closing vertexes are"
121 + "properly detected.");
122 }
123 if (logger.isLoggable(Level.FINE))
124 {
125 String s = "";
126 for (ObjectPair p : rcaComb)
127 {
128 s = s + p.getFirst() + ":" + p.getSecond() + " ";
129 }
130 logger.log(Level.FINE,"Attempting Ring Closure with RCA "
131 + "Combination (" + i + "): " + s);
132 }
133
134 // Try to create new molecule
135 ChemicalObjectModel molTo3d = mol.deepcopy();
136 if (settings.getPSSROTTool() != null)
137 {
138 try
139 {
141 molTo3d.getRCACombinations().get(i));
142 } catch (TinkerException te)
143 {
144 String msg = "ERROR! Tinker failed on task '"
145 + te.taskName + "'!";
146 if (te.solution != "")
147 {
148 msg = msg + settings.NL + te.solution;
149 }
150 logger.log(Level.SEVERE, msg);
151 throw new DENOPTIMException(msg, te);
152 }
153 } else {
155 molTo3d.getRCACombinations().get(i));
156 }
157
158 // If some ring remains open, report in the MOL_ERROR field
159 int newRingClosed = molTo3d.getNewRingClosures().size();
160 if (newRingClosed < rcaComb.size())
161 {
162 String err = "#RingClosureTool: uncomplete closure (closed "
163 + newRingClosed + "/" + rcaComb.size() + ")";
164 molTo3d.getIAtomContainer().setProperty(
166 }
167 rcMols.add(molTo3d);
168 }
169
170 // Sort
171 Collections.sort(rcMols, new RingClosedMolComparator());
172
173 return rcMols;
174 }
175
176//------------------------------------------------------------------------------
177
186 private class RingClosedMolComparator implements Comparator<ChemicalObjectModel>
187 {
189 {
190 final int FIRST = 1;
191 final int EQUAL = 0;
192 final int LAST = -1;
193
194 // First criterion is the number of RingClosures
195 int nRcA = mA.getNewRingClosures().size();
196 int nRcB = mB.getNewRingClosures().size();
197 if (nRcA < nRcB) // The HIGHER the number, the BETTER
198 {
199 return FIRST;
200 }
201 else if (nRcA > nRcB)
202 {
203 return LAST;
204 }
205
206 // Second, the quality (closeness to perfection) of RingClosures
207 double scoreA = mA.getNewRingClosuresQuality();
208 double scoreB = mB.getNewRingClosuresQuality();
209 double dist = scoreA - scoreB;
210 double trsh = Math.min(scoreA,scoreB) * 0.05;
211 if (dist > 0.0 && dist > trsh) // The LOWER the score, the BETTER
212 {
213 return FIRST;
214 }
215 if (dist < 0.0 && Math.abs(dist) > trsh)
216 {
217 return LAST;
218 }
219
220 // Third, atom proximity
221 double proxScoreA = mA.getAtomOverlapScore();
222 double proxScoreB = mB.getAtomOverlapScore();
223 if (proxScoreA < proxScoreB) // The HIGHER the proxScore, the BETTER
224 {
225 return FIRST;
226 }
227 else if (proxScoreA > proxScoreB)
228 {
229 return LAST;
230 }
231
232 return EQUAL;
233 }
234 }
235
236//------------------------------------------------------------------------------
237
254 ChemicalObjectModel chemObj,
255 Set<ObjectPair> rcaCombination) throws DENOPTIMException
256 {
257 String molName = chemObj.getName();
258
259 // Increment iteration number (to make unique file names)
260 itn++;
261
262 logger.log(Level.INFO, "Attempting Ring Closure via conformational"
263 + " adaptation for " + molName
264 + " (Iteration: " + itn + ")");
265
267
268 long startTime = System.nanoTime();
269 try {
270 rcoServer.runConformationalOptimization(chemObj, rcaCombination, logger);
271 } catch (Exception e) {
272 logger.log(Level.SEVERE, "Error optimizing ring closing conformation: " + e.getMessage());
273 throw new DENOPTIMException("Error optimizing ring closing conformation: " + e.getMessage(), e);
274 }
275 long endTime = System.nanoTime();
276 long time = (endTime - startTime);
277 logger.log(Level.FINE, "TIME (RC conf. search): "+time/1000000+" ms"
278 + " #frags: " + chemObj.getGraph().getVertexList().size()
279 + " #atoms: " + chemObj.getIAtomContainer().getAtomCount()
280 + " #rotBnds: " + chemObj.getRotatableBonds().size());
281
282 logger.log(Level.INFO, "Ring-closing conformational optimization done. "
283 + "Now, post-processing.");
284
285 // Evaluate proximity of RingClosingAttractor and close rings
286 closeRings(chemObj, rcaCombination);
287
288 // Update list rotatable bonds
289 chemObj.purgeListRotatableBonds();
290
291 // Finalize the molecule: saturate free RCA
293
294 return chemObj;
295 }
296
297//------------------------------------------------------------------------------
298
318 ChemicalObjectModel chemObj, Set<ObjectPair> rcaCombination)
320 {
321 IAtomContainer fmol = chemObj.getIAtomContainer();
322 String workDir = settings.getWorkingDirectory();
323 String molName = chemObj.getName();
324
325 // Increment iteration number (to make unique file names)
326 itn++;
327
328 logger.log(Level.INFO, "Attempting Ring Closure via conformational"
329 + " adaptation for " + molName
330 + " (PSSROT - Iteration: " + itn + ")");
331
332 List<String> molSpecificKeyFileLines = new ArrayList<String>();
333 molSpecificKeyFileLines.addAll(settings.getRSKeyFileParams());
334 for (ObjectPair op : rcaCombination)
335 {
336 int iZMatRcaA = chemObj.getZMatIdxOfRCA(
337 (RingClosingAttractor) op.getFirst());
338 int iZMatRcaB = chemObj.getZMatIdxOfRCA(
339 (RingClosingAttractor) op.getSecond());
340 molSpecificKeyFileLines.add("RC-PAIR " + iZMatRcaA + " "
341 + iZMatRcaB);
342 }
343
344 // Definition of RingClosingPotential
345 molSpecificKeyFileLines.add("RC11BNDTERM");
346 molSpecificKeyFileLines.add("RC12BNDTERM NONE");
347 for (ObjectPair op : rcaCombination)
348 {
349 RingClosingAttractor rca0 = (RingClosingAttractor) op.getFirst();
350 RingClosingAttractor rca1 = (RingClosingAttractor) op.getSecond();
351 int s0t = fmol.indexOf(rca0.getSrcAtom()) + 1;
352 int s1t = fmol.indexOf(rca1.getSrcAtom()) + 1;
353 int i0t = chemObj.getZMatIdxOfRCA(rca0);
354 int i1t = chemObj.getZMatIdxOfRCA(rca1);
355
356 double parA = 0.0;
357 double parB = 0.0;
358 parA = (rca0.getParamA11() + rca1.getParamA11()) / 2.0;
359 parB = (rca0.getParamB11() + rca1.getParamB11()) / 2.0;
360
361 molSpecificKeyFileLines.add("RC-11-PAIRS " + i0t + " " +s1t + " "
362 + parA + " " + parB);
363 molSpecificKeyFileLines.add("RC-11-PAIRS " + s0t + " " + i1t + " "
364 + parA + " " + parB);
365 }
366
367 long startTime = System.nanoTime();
370 itn, "rs",
372 molSpecificKeyFileLines,
377 workDir,
379 long endTime = System.nanoTime();
380 long time = (endTime - startTime);
381 logger.log(Level.FINE, "TIME (RC conf. search): "+time/1000000+" ms"
382 + " #frags: " + chemObj.getGraph().getVertexList().size()
383 + " #atoms: " + chemObj.getIAtomContainer().getAtomCount()
384 + " #rotBnds: " + chemObj.getRotatableBonds().size());
385
386 logger.log(Level.INFO, "RC-PSSROT done. Now, post-processing.");
387
388 // Evaluate proximity of RingClosingAttractor and close rings
389 closeRings(chemObj, rcaCombination);
390
391 // Update list rotatable bonds
392 chemObj.purgeListRotatableBonds();
393
394 // Finalize the molecule: saturate free RCA
396
397 // Cleanup
398 FileUtils.deleteFilesContaining(workDir,molName + "_rs" + itn);
399
400 return chemObj;
401 }
402
403//------------------------------------------------------------------------------
404
415 public void closeRings(ChemicalObjectModel mol, Set<ObjectPair> rcaCombination)
416 {
417 // get settings //TODO: this should happen inside RunTimeParameters
420 {
423 }
424
425 // Collect candidate RingClosures
426 List<RingClosure> candidatesClosures = new ArrayList<RingClosure>();
427 for (ObjectPair op : rcaCombination)
428 {
429 logger.log(Level.FINEST, "closeRings: evaluating closure of " + op);
430 RingClosingAttractor rcaA = (RingClosingAttractor) op.getFirst();
431 RingClosingAttractor rcaB = (RingClosingAttractor) op.getSecond();
432 Point3d srcA = rcaA.getSrcAtom().getPoint3d();
433 Point3d atmA = rcaA.getIAtom().getPoint3d();
434 Point3d srcB = rcaB.getSrcAtom().getPoint3d();
435 Point3d atmB = rcaB.getIAtom().getPoint3d();
436 RingClosure rc = new RingClosure(srcA, atmA, srcB, atmB);
437 candidatesClosures.add(rc);
438
439 //Define closability conditions
440 double lenH = srcA.distance(atmA);
441 double lenT = srcB.distance(atmB);
442 double distTolerance = (lenH + lenT) / 2.0;
443 distTolerance = distTolerance * rcParams.getRCDistTolerance();
444 double minDistH1T2 = -1.0;
445 double minDistH2T1 = -1.0;
446 double minDistH2T2 = -1.0;
447 double maxDistH1T2 = 0.0;
448 double maxDistH2T1 = 0.0;
449 double maxDistH2T2 = 0.0;
450 double maxDotProdHT = rcParams.getRCDotPrTolerance();
451
452 maxDistH1T2 = distTolerance;
453 maxDistH2T1 = distTolerance;
454 maxDistH2T2 = lenH + lenT;
455
456 boolean closeThisBnd = rc.isClosable(minDistH1T2, maxDistH1T2,
457 minDistH2T1, maxDistH2T1,
458 minDistH2T2, maxDistH2T2,
459 maxDotProdHT,
460 logger);
461
462 if (closeThisBnd)
463 {
464 BondType bndTyp = rcaA.getRCBondType();
465 if (bndTyp.hasCDKAnalogue())
466 {
467 mol.addBond(rcaA.getSrcAtom(),rcaB.getSrcAtom(),rc, bndTyp);
468 } else {
469 logger.log(Level.WARNING, "WARNING! "
470 + "Attempt to add ring closing bond "
471 + "did not add any actual chemical bond because the "
472 + "bond type of the chord is '" + bndTyp +"'.");
473 }
474 rcaA.setUsed();
475 rcaB.setUsed();
476 }
477 }
478 }
479
480//------------------------------------------------------------------------------
481
497 throws DENOPTIMException
498 {
499 IAtomContainer fmol = mol.getIAtomContainer();
500 ZMatrix zmat = mol.getZMatrix();
501 String duSymbol = DENOPTIMConstants.DUMMYATMSYMBOL;
502 for (RingClosingAttractor rca : mol.getAttractorsList())
503 {
504 if (rca.isUsed())
505 {
506 // Used RCA are changed to inert dummy atoms (to keep ZMatrix)
507 IAtom fatm = rca.getIAtom();
508 ZMatrixAtom zatm = zmat.getAtom(fmol.indexOf(fatm));
509 zatm.setSymbol(duSymbol);
510
511 IAtom newAtm = new PseudoAtom(duSymbol,new Point3d(fatm.getPoint3d()));
512 newAtm.setProperties(fatm.getProperties());
513 AtomContainerManipulator.replaceAtomByAtom(
514 mol.getIAtomContainer(),fatm,newAtm);
515 rca.setIAtom(newAtm);
516 }
517 else
518 {
519 // Unused RCA are replaced by capping group
520
521 //TODO: select capping group (if any) and use that to saturate the free AP
522 // Note that to do that the capping og the RingClosure-related APclasses must be
523 // reported in the CompatibilityMatrix. Thus, it is also necessary to make DenoptimGA
524 // prefer RingClosure-related APclasses over other capping groups
525 /*
526 //Choose capping group
527 String freeAPClass = rca.getApClass();
528 ArrayList<String> capAPClasses =
529 CGParameters.getCompatibilityMap().get(freeAPClass);
530 */
531 // We force the conversion to H with a fixed bond length
532 // This code is temporary as will be removed by the introduction
533 // proper capping group selection and use (TODO)
534 IAtom fatm = rca.getIAtom();
535 ZMatrixAtom zatm = zmat.getAtom(fmol.indexOf(fatm));
536 zatm.setSymbol("H");
537 zatm.setBondLength(1.10);
538 //UPGRADE: this cannot be done since CDK 2.*. So, we must
539 // create a new IAtom object to replace the old one.
540 /*
541 ((PseudoAtom) fatm).setLabel("H");
542 fatm.setSymbol("H");
543 */
544 IAtom newAtm = new PseudoAtom("H",new Point3d(fatm.getPoint3d()));
545 newAtm.setProperties(fatm.getProperties());
546 AtomContainerManipulator.replaceAtomByAtom(
547 mol.getIAtomContainer(),fatm,newAtm);
548 rca.setIAtom(newAtm);
549 }
550 }
551
552 // Update XYZ
553 mol.updateXYZFromINT();
554 }
555
556//------------------------------------------------------------------------------
557}
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.
Sends the request to produce a socket server running the RingClosingMM service.
static synchronized RCOSocketServerClient getInstance(String hostname, Integer port)
Gets the singleton instance of RCOSocketServerClient.
void runConformationalOptimization(ChemicalObjectModel chemObj, Logger logger)
Runs a conformational optimization using the services provided by the socket server configured for th...
Tool to perform conformational search via Tinker PSSROT program.
static void performPSSROT(ArrayList< ChemicalObjectModel > mols, Map< String, Integer > atmTypeMap, 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.
Exceptions resulting from a failure of Tinker.
String solution
Proposed solution to the failure, or empty string.
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.
List< Set< ObjectPair > > getRCACombinations()
Returns the list of combinations of RingClosingAttractor.
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.
List< 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 attemptRingClosureWithRCOServer(ChemicalObjectModel chemObj, Set< ObjectPair > rcaCombination)
Attempts to close rings by finding the conformation that allows to join heads and tails of specific a...
ChemicalObjectModel attemptRingClosureWithTinker(ChemicalObjectModel chemObj, Set< ObjectPair > rcaCombination)
Attempts to close rings by finding the conformation that allows to join heads and tails of specific a...
Logger logger
Program.specific logger.
Representation of an atom in the ZMatrix.
Definition: ZMatrixAtom.java:9
void setBondLength(Double bondLength)
Set the bond length.
void setSymbol(String symbol)
Set the symbol of the atom.
Representation of an atom container's geometry with internal coordinates.
Definition: ZMatrix.java:27
ZMatrixAtom getAtom(int index)
Get the atom at the given index.
Definition: ZMatrix.java:223
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.