1 /* 2 * Copyright 2006-2011 Sam Adams <sea36 at users.sourceforge.net> 3 * 4 * This file is part of JNI-InChI. 5 * 6 * JNI-InChI is free software: you can redistribute it and/or modify 7 * it under the terms of the GNU Lesser General Public License as published 8 * by the Free Software Foundation, either version 3 of the License, or 9 * (at your option) any later version. 10 * 11 * JNI-InChI is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public License 17 * along with JNI-InChI. If not, see <http://www.gnu.org/licenses/>. 18 */ 19 package org.jmol.inchi; 20 21 import java.io.BufferedReader; 22 import java.io.IOException; 23 import java.io.StringReader; 24 import java.util.Hashtable; 25 import java.util.Map; 26 27 import org.jmol.adapter.smarter.AtomSetCollection; 28 import org.jmol.api.JmolAdapter; 29 import org.jmol.api.JmolAdapterAtomIterator; 30 import org.jmol.api.JmolAdapterBondIterator; 31 import org.jmol.api.JmolInChI; 32 import org.jmol.modelset.Atom; 33 import org.jmol.modelset.Bond; 34 import org.jmol.util.Edge; 35 import org.jmol.util.Elements; 36 import org.jmol.viewer.Viewer; 37 38 import javajs.util.BS; 39 import javajs.util.P3; 40 import net.sf.jniinchi.INCHI_BOND_TYPE; 41 import net.sf.jniinchi.JniInchiAtom; 42 import net.sf.jniinchi.JniInchiBond; 43 import net.sf.jniinchi.JniInchiInput; 44 import net.sf.jniinchi.JniInchiInputInchi; 45 import net.sf.jniinchi.JniInchiStructure; 46 import net.sf.jniinchi.JniInchiWrapper; 47 48 public class InChIJNI implements JmolInChI { 49 InChIJNI()50 public InChIJNI() { 51 // for dynamic loading 52 } 53 54 @Override getInchi(Viewer vwr, BS atoms, String molData, String options)55 public String getInchi(Viewer vwr, BS atoms, String molData, String options) { 56 try { 57 if (atoms == null ? molData == null : atoms.cardinality() == 0) 58 return ""; 59 if (options == null) 60 options = ""; 61 if (options.startsWith("structure/")) { 62 String inchi = options.substring(10); 63 JniInchiInputInchi in = new JniInchiInputInchi(inchi); 64 return getStructure(JniInchiWrapper.getStructureFromInchi(in)); 65 } 66 String inchi = null; 67 boolean haveKey = false; 68 if (molData != null && molData.startsWith("InChI=")) { 69 inchi = molData; 70 haveKey = true; 71 } else { 72 options = options.toLowerCase(); 73 haveKey = (options.indexOf("key") >= 0); 74 if (haveKey) { 75 options = options.replace("inchikey", ""); 76 options = options.replace("key", ""); 77 } 78 JniInchiInput in = new JniInchiInput(options); 79 if (atoms == null) { 80 in.setStructure(newJniInchiStructure(vwr, molData)); 81 } else { 82 in.setStructure(newJniInchiStructure(vwr, atoms)); 83 } 84 inchi = JniInchiWrapper.getInchi(in).getInchi(); 85 } 86 return (haveKey ? JniInchiWrapper.getInchiKey(inchi).getKey() : inchi); 87 } catch (Exception e) { 88 if (e.getMessage().indexOf("ption") >= 0) 89 System.out.println(e.getMessage() + ": " + options.toLowerCase() 90 + "\n See https://www.inchi-trust.org/download/104/inchi-faq.pdf for valid options"); 91 else 92 e.printStackTrace(); 93 return ""; 94 } 95 } 96 getStructure(JniInchiStructure mol)97 private String getStructure(JniInchiStructure mol) { 98 return toString(mol); 99 } 100 101 /** 102 * Jmol addition to create a JniInchiStructure from Jmol atoms. Currently only 103 * supports single, double, aromatic_single and aromatic_double. 104 * 105 * @param vwr 106 * @param bsAtoms 107 * @return a structure for JniInput 108 */ newJniInchiStructure(Viewer vwr, BS bsAtoms)109 private static JniInchiStructure newJniInchiStructure(Viewer vwr, BS bsAtoms) { 110 JniInchiStructure mol = new JniInchiStructure(); 111 JniInchiAtom[] atoms = new JniInchiAtom[bsAtoms.cardinality()]; 112 int[] map = new int[bsAtoms.length()]; 113 BS bsBonds = vwr.ms.getBondsForSelectedAtoms(bsAtoms, false); 114 for (int pt = 0, i = bsAtoms.nextSetBit(0); i >= 0; i = bsAtoms 115 .nextSetBit(i + 1)) { 116 Atom a = vwr.ms.at[i]; 117 String sym = a.getElementSymbol(); 118 int iso = a.getIsotopeNumber(); 119 if (a.getElementNumber() == 1) { 120 sym = "H"; // in case this is D 121 } 122 mol.addAtom( 123 atoms[pt] = new JniInchiAtom(a.x, a.y, a.z, sym)); 124 atoms[pt].setCharge(a.getFormalCharge()); 125 if (iso > 0) 126 atoms[pt].setIsotopicMass(iso); 127 map[i] = pt++; 128 } 129 Bond[] bonds = vwr.ms.bo; 130 for (int i = bsBonds.nextSetBit(0); i >= 0; i = bsBonds.nextSetBit(i + 1)) { 131 Bond bond = bonds[i]; 132 INCHI_BOND_TYPE order = getOrder(bond.order); 133 if (order != null) 134 mol.addBond(new JniInchiBond(atoms[map[bond.getAtomIndex1()]], 135 atoms[map[bond.getAtomIndex2()]], order)); 136 } 137 return mol; 138 } 139 140 /** 141 * Jmol addition to create a JniInchiStructure from MOL data. Currently only 142 * supports single, double, aromatic_single and aromatic_double. 143 * 144 * @param vwr 145 * @param molData 146 * @return a structure for JniInput 147 */ newJniInchiStructure(Viewer vwr, String molData)148 private static JniInchiStructure newJniInchiStructure(Viewer vwr, 149 String molData) { 150 JniInchiStructure mol = new JniInchiStructure(); 151 BufferedReader r = new BufferedReader(new StringReader(molData)); 152 try { 153 Map<String, Object> htParams = new Hashtable<String, Object>(); 154 JmolAdapter adapter = vwr.getModelAdapter(); 155 Object atomSetReader = adapter.getAtomSetCollectionReader("String", null, 156 r, htParams); 157 if (atomSetReader instanceof String) { 158 System.err.println("InChIJNI could not read molData"); 159 return null; 160 } 161 AtomSetCollection asc = (AtomSetCollection) adapter 162 .getAtomSetCollection(atomSetReader); 163 JmolAdapterAtomIterator ai = adapter.getAtomIterator(asc); 164 JmolAdapterBondIterator bi = adapter.getBondIterator(asc); 165 JniInchiAtom[] atoms = new JniInchiAtom[asc.getAtomSetAtomCount(0)]; 166 int n = 0; 167 while (ai.hasNext() && n < atoms.length) { 168 P3 p = ai.getXYZ(); 169 JniInchiAtom a = new JniInchiAtom(p.x, p.y, p.z, 170 Elements.elementSymbolFromNumber(ai.getElementNumber())); 171 a.setCharge(ai.getFormalCharge()); 172 mol.addAtom(a); 173 atoms[n++] = a; 174 } 175 while (bi.hasNext()) { 176 INCHI_BOND_TYPE order = getOrder(bi.getEncodedOrder()); 177 if (order != null) 178 mol.addBond(new JniInchiBond( 179 atoms[((Integer) bi.getAtomUniqueID1()).intValue()], 180 atoms[((Integer) bi.getAtomUniqueID2()).intValue()], order)); 181 } 182 } finally { 183 try { 184 r.close(); 185 } catch (IOException e) { 186 } 187 } 188 return mol; 189 } 190 getOrder(int order)191 private static INCHI_BOND_TYPE getOrder(int order) { 192 switch (order) { 193 case Edge.BOND_COVALENT_SINGLE: 194 case Edge.BOND_AROMATIC_SINGLE: 195 return INCHI_BOND_TYPE.SINGLE; 196 case Edge.BOND_AROMATIC_DOUBLE: 197 case Edge.BOND_COVALENT_DOUBLE: 198 return INCHI_BOND_TYPE.DOUBLE; 199 case Edge.BOND_COVALENT_TRIPLE: 200 return INCHI_BOND_TYPE.TRIPLE; 201 default: 202 return null; 203 } 204 } 205 toString(JniInchiStructure mol)206 private static String toString(JniInchiStructure mol) { 207 int na = mol.getNumAtoms(); 208 int nb = mol.getNumBonds(); 209 String s = ""; 210 for (int i = 0; i < na; i++) { 211 s += mol.getAtom(i).getDebugString() + "\n"; 212 } 213 for (int i = 0; i < nb; i++) { 214 s += mol.getBond(i).getDebugString() + "\n"; 215 } 216 return s; 217 } 218 219 } 220