1 /* $RCSfile$
2  * $Author: hansonr $
3  * $Date: 2006-03-05 12:22:08 -0600 (Sun, 05 Mar 2006) $
4  * $Revision: 4545 $
5  *
6  * Copyright (C) 2002-2005  The Jmol Development Team
7  *
8  * Contact: jmol-developers@lists.sf.net
9  *
10  *  This library is free software; you can redistribute it and/or
11  *  modify it under the terms of the GNU Lesser General Public
12  *  License as published by the Free Software Foundation; either
13  *  version 2.1 of the License, or (at your option) any later version.
14  *
15  *  This library is distributed in the hope that it will be useful,
16  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  *  Lesser General Public License for more details.
19  *
20  *  You should have received a copy of the GNU Lesser General Public
21  *  License along with this library; if not, write to the Free Software
22  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
23  */
24 
25 package org.jmol.scriptext;
26 
27 import javajs.util.AU;
28 import javajs.util.Lst;
29 import javajs.util.M4;
30 import javajs.util.Measure;
31 import javajs.util.P3;
32 
33 import java.util.Map;
34 
35 import org.jmol.api.Interface;
36 import org.jmol.api.SmilesMatcherInterface;
37 import javajs.util.BS;
38 import org.jmol.modelset.Atom;
39 import org.jmol.script.ScriptEval;
40 import org.jmol.script.ScriptException;
41 import org.jmol.util.Logger;
42 import org.jmol.viewer.JC;
43 
44 public class SmilesExt {
45 
46   private ScriptEval e;
47 
SmilesExt()48   public SmilesExt() {
49     // used by Reflection
50   }
51 
init(Object se)52   public SmilesExt init(Object se) {
53     e = (ScriptEval) se;
54     return this;
55   }
56 
57   ///////////// ScriptMathProcessor extensions ///////////
58 
59   /**
60    * The major interface to org.jmol.smiles, this method allows for a wide
61    * variety of correlation functionality.
62    *
63    * @param bsA
64    * @param bsB
65    * @param smiles
66    * @param ptsA
67    * @param ptsB
68    * @param m4
69    * @param vReturn
70    * @param asMap
71    * @param mapSet
72    * @param center
73    * @param bestMap
74    * @param flags
75    * @return standard deviation
76    * @throws ScriptException
77    */
getSmilesCorrelation(BS bsA, BS bsB, String smiles, Lst<P3> ptsA, Lst<P3> ptsB, M4 m4, Lst<BS> vReturn, boolean asMap, int[][] mapSet, P3 center, boolean bestMap, int flags)78   public float getSmilesCorrelation(BS bsA, BS bsB, String smiles, Lst<P3> ptsA,
79                                     Lst<P3> ptsB, M4 m4, Lst<BS> vReturn,
80                                     boolean asMap, int[][] mapSet, P3 center,
81                                     boolean bestMap, int flags)
82       throws ScriptException {
83 
84     //   middle two: boolean isSmarts,boolean firstMatchOnly,
85     float tolerance = (mapSet == null ? 0.1f : Float.MAX_VALUE);
86     try {
87       if (ptsA == null) {
88         ptsA = new Lst<P3>();
89         ptsB = new Lst<P3>();
90       }
91       M4 m = new M4();
92       P3 c = new P3();
93 
94       Atom[] atoms = e.vwr.ms.at;
95       int ac = e.vwr.ms.ac;
96       SmilesMatcherInterface sm = e.vwr.getSmilesMatcher();
97       int[][] maps = sm.getCorrelationMaps(smiles, atoms, ac, bsA,
98           flags | JC.SMILES_FIRST_MATCH_ONLY);
99       if (maps == null)
100         e.evalError(sm.getLastException(), null);
101       if (maps.length == 0)
102         return Float.NaN;
103       int[] mapFirst = maps[0];
104       for (int i = 0; i < mapFirst.length; i++)
105         ptsA.addLast(atoms[mapFirst[i]]);
106       maps = sm.getCorrelationMaps(smiles, atoms, ac, bsB, flags);
107       if (maps == null)
108         e.evalError(sm.getLastException(), null);
109       if (maps.length == 0)
110         return Float.NaN;
111       Logger.info(maps.length + " mappings found");
112       if (bestMap || !asMap) {
113         float lowestStdDev = Float.MAX_VALUE;
114         int[] mapBest = null;
115         for (int i = 0; i < maps.length; i++) {
116           ptsB.clear();
117           for (int j = 0; j < maps[i].length; j++)
118             ptsB.addLast(atoms[maps[i][j]]);
119           Interface.getInterface("javajs.util.Eigen", e.vwr, "script");
120           float stddev = (ptsB.size() == 1 ? 0
121               : Measure.getTransformMatrix4(ptsA, ptsB, m, null));
122           Logger.info("getSmilesCorrelation stddev=" + stddev);
123           if (vReturn != null) {
124             if (stddev < tolerance) {
125               BS bs = new BS();
126               for (int j = 0; j < maps[i].length; j++)
127                 bs.set(maps[i][j]);
128               vReturn.addLast(bs);
129             }
130           }
131           if (stddev < lowestStdDev) {
132             mapBest = maps[i];
133             if (m4 != null)
134               m4.setM4(m);
135             if (center != null)
136               center.setT(c);
137             lowestStdDev = stddev;
138           }
139         }
140         if (mapSet != null) {
141           mapSet[0] = mapFirst;
142           mapSet[1] = mapBest;
143         }
144         ptsB.clear();
145         for (int i = 0; i < mapBest.length; i++)
146           ptsB.addLast(atoms[mapBest[i]]);
147         return lowestStdDev;
148       }
149       // deliver all maps as a list of points
150       for (int i = 0; i < maps.length; i++)
151         for (int j = 0; j < maps[i].length; j++)
152           ptsB.addLast(atoms[maps[i][j]]);
153     } catch (Exception ex) {
154       e.evalError(ex.getMessage(), null);
155     }
156     return 0;
157   }
158 
159   /**
160    * @param pattern
161    *        e
162    * @param smiles
163    * @param bsSelected
164    * @param bsMatch3D
165    * @param flags
166    * @param asOneBitset
167    * @param firstMatchOnly
168    * @return Object
169    * @throws ScriptException
170    */
getSmilesMatches(String pattern, String smiles, BS bsSelected, BS bsMatch3D, int flags, boolean asOneBitset, boolean firstMatchOnly)171   public Object getSmilesMatches(String pattern, String smiles, BS bsSelected,
172                                  BS bsMatch3D, int flags, boolean asOneBitset,
173                                  boolean firstMatchOnly)
174       throws ScriptException {
175 
176     // just retrieving the SMILES or bioSMILES string
177     if (pattern.length() == 0 || pattern.endsWith("///") || pattern.equals("H")
178         || pattern.equals("H2") || pattern.equals("top")
179         || pattern.equalsIgnoreCase("NOAROMATIC")) {
180       try {
181 
182         return e.vwr.getSmilesOpt(bsSelected, 0, 0,
183             flags | (pattern.equals("H2") ? JC.SMILES_GEN_EXPLICIT_H2_ONLY : 0)
184                 | (pattern.equals("H") ? JC.SMILES_GEN_EXPLICIT_H_ALL : 0)
185                 | (pattern.equals("top") ? JC.SMILES_GEN_TOPOLOGY : 0)
186                 | (pattern.equalsIgnoreCase("NOAROMATIC")
187                     ? JC.SMILES_NO_AROMATIC
188                     : 0),
189             (pattern.endsWith("///") ? pattern : null));
190       } catch (Exception ex) {
191         e.evalError(ex.getMessage(), null);
192       }
193     }
194     BS[] b;
195     if (bsMatch3D == null) {
196       // getting a BitSet or BitSet[] from a set of atoms or a pattern.
197       // not for string.find(string....)
198       try {
199         if (smiles == null) {
200           b = e.vwr.getSubstructureSetArray(pattern, bsSelected, flags);
201         } else if (pattern.equals("chirality")) {
202           return e.vwr.calculateChiralityForSmiles(smiles);
203         } else {
204           boolean isSmarts = ((flags
205               & JC.SMILES_TYPE_SMARTS) == JC.SMILES_TYPE_SMARTS);
206           boolean ignoreElements = ((flags
207               & JC.SMILES_GEN_TOPOLOGY) == JC.SMILES_GEN_TOPOLOGY);
208           int[][] map = e.vwr.getSmilesMatcher().find(pattern, smiles,
209               (isSmarts ? JC.SMILES_TYPE_SMARTS : JC.SMILES_TYPE_SMILES)
210                   | (firstMatchOnly ? JC.SMILES_FIRST_MATCH_ONLY : 0)
211                   | (ignoreElements ? JC.SMILES_GEN_TOPOLOGY : 0));
212           if (!asOneBitset)
213             return (!firstMatchOnly ? map
214                 : map.length == 0 ? new int[0] : map[0]);
215           BS bs = new BS();
216           for (int j = 0; j < map.length; j++) {
217             int[] a = map[j];
218             for (int k = a.length; --k >= 0;)
219               if (a[k] >= 0)
220                 bs.set(a[k]);
221           }
222           if (!isSmarts)
223             return new int[bs.cardinality()];
224           int[] iarray = new int[bs.cardinality()];
225           int pt = 0;
226           for (int i = bs.nextSetBit(0); i >= 0; i = bs.nextSetBit(i + 1))
227             iarray[pt++] = i;
228           return iarray;
229         }
230       } catch (Exception ex) {
231         e.evalError(ex.getMessage(), null);
232         return null;
233       }
234     } else {
235 
236       // getting a correlation
237 
238       Lst<BS> vReturn = new Lst<BS>();
239       float stddev = getSmilesCorrelation(bsMatch3D, bsSelected, pattern, null,
240           null, null, vReturn, false, null, null, false, flags);
241       if (Float.isNaN(stddev))
242         return (asOneBitset ? new BS() : new String[] {});
243       e.showString("RMSD " + stddev + " Angstroms");
244       b = vReturn.toArray(new BS[vReturn.size()]);
245     }
246     if (asOneBitset) {
247       // sum total of all now, not just first
248       BS bs = new BS();
249       for (int j = 0; j < b.length; j++)
250         bs.or(b[j]);
251       return bs;
252     }
253     Lst<BS> list = new Lst<BS>();
254     for (int j = 0; j < b.length; j++)
255       list.addLast(b[j]);
256     return list;
257   }
258 
getFlexFitList(BS bs1, BS bs2, String smiles1, boolean isSmarts)259   public float[] getFlexFitList(BS bs1, BS bs2, String smiles1,
260                                 boolean isSmarts)
261       throws ScriptException {
262     int[][] mapSet = AU.newInt2(2);
263     getSmilesCorrelation(bs1, bs2, smiles1, null, null, null, null, false,
264         mapSet, null, false,
265         isSmarts ? JC.SMILES_TYPE_SMARTS : JC.SMILES_TYPE_SMILES);
266     if (mapSet[0] == null)
267       return null;
268     int[][] bondMap1 = e.vwr.ms.getDihedralMap(mapSet[0]);
269     int[][] bondMap2 = (bondMap1 == null ? null
270         : e.vwr.ms.getDihedralMap(mapSet[1]));
271     if (bondMap2 == null || bondMap2.length != bondMap1.length)
272       return null;
273     float[][] angles = new float[bondMap1.length][3];
274     Atom[] atoms = e.vwr.ms.at;
275     getTorsions(atoms, bondMap2, angles, 0);
276     getTorsions(atoms, bondMap1, angles, 1);
277     float[] data = new float[bondMap1.length * 6];
278     for (int i = 0, pt = 0; i < bondMap1.length; i++) {
279       int[] map = bondMap1[i];
280       data[pt++] = map[0];
281       data[pt++] = map[1];
282       data[pt++] = map[2];
283       data[pt++] = map[3];
284       data[pt++] = angles[i][0];
285       data[pt++] = angles[i][1];
286     }
287     return data;
288   }
289 
getTorsions(Atom[] atoms, int[][] bondMap, float[][] diff, int pt)290   private static void getTorsions(Atom[] atoms, int[][] bondMap, float[][] diff,
291                                   int pt) {
292     for (int i = bondMap.length; --i >= 0;) {
293       int[] map = bondMap[i];
294       float v = Measure.computeTorsion(atoms[map[0]], atoms[map[1]],
295           atoms[map[2]], atoms[map[3]], true);
296       if (pt == 1) {
297         if (v - diff[i][0] > 180)
298           v -= 360;
299         else if (v - diff[i][0] <= -180)
300           v += 360;
301       }
302       diff[i][pt] = v;
303     }
304   }
305 
306   @SuppressWarnings("unchecked")
mapPolyhedra(int i1, int i2, boolean isSmiles, M4 m)307   public float mapPolyhedra(int i1, int i2, boolean isSmiles, M4 m)
308       throws ScriptException {
309     Lst<P3> ptsA = new Lst<P3>();
310     Lst<P3> ptsB = new Lst<P3>();
311     Object[] data;
312     data = new Object[] { Integer.valueOf(i1), null };
313     e.getShapePropertyData(JC.SHAPE_POLYHEDRA, "syminfo", data);
314     Map<String, Object> p1 = (Map<String, Object>) data[1];
315     data[0] = Integer.valueOf(i2);
316     data[1] = null;
317     e.getShapePropertyData(JC.SHAPE_POLYHEDRA, "syminfo", data);
318     Map<String, Object> p2 = (Map<String, Object>) data[1];
319     if (p1 == null || p2 == null)
320       return Float.NaN;
321     String smiles1 = (String) p1.get("polySmiles");
322     String smiles2 = (String) p2.get("polySmiles");
323     int[] map = (int[]) getSmilesMatches(smiles2, smiles1, null, null,
324         isSmiles ? JC.SMILES_TYPE_SMILES
325             : JC.SMILES_GEN_TOPOLOGY | JC.SMILES_TYPE_SMILES,
326         false, true);
327     if (map.length == 0)
328       return Float.NaN;
329     // map new list
330     ptsA.addLast((P3) p1.get("center"));
331     P3[] a = (P3[]) p1.get("vertices");
332     for (int i = 0, n = a.length; i < n; i++)
333       ptsA.add(a[map[i + 1] - 1]);
334     ptsB.addLast((P3) p2.get("center"));
335     a = (P3[]) p2.get("vertices");
336     for (int i = 0, n = a.length; i < n; i++)
337       ptsB.add(a[i]);
338     Interface.getInterface("javajs.util.Eigen", e.vwr, "script");
339     return Measure.getTransformMatrix4(ptsA, ptsB, m, null);
340   }
341 
342 }
343