1 /* Copyright (C) 2004-2007 The Chemistry Development Kit (CDK) project 2 * 3 * Contact: cdk-devel@lists.sourceforge.net 4 * 5 * This program is free software; you can redistribute it and/or 6 * modify it under the terms of the GNU Lesser General Public License 7 * as published by the Free Software Foundation; either version 2.1 8 * of the License, or (at your option) any later version. 9 * All we ask is that proper credit is given for our work, which includes 10 * - but is not limited to - adding the above copyright notice to the beginning 11 * of your source code files, and to any copyright notice that you may distribute 12 * with programs based on this work. 13 * 14 * This program is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 * GNU Lesser General Public License for more details. 18 * 19 * You should have received a copy of the GNU Lesser General Public License 20 * along with this program; if not, write to the Free Software 21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 22 * 23 */ 24 package org.openscience.cdk.modeling.builder3d; 25 26 import org.openscience.cdk.config.Isotopes; 27 import org.openscience.cdk.interfaces.IAtomType; 28 import org.openscience.cdk.interfaces.IChemObjectBuilder; 29 import org.openscience.cdk.interfaces.IIsotope; 30 import org.openscience.cdk.tools.ILoggingTool; 31 import org.openscience.cdk.tools.LoggingToolFactory; 32 import org.openscience.cdk.tools.periodictable.PeriodicTable; 33 34 import java.awt.Color; 35 import java.io.BufferedReader; 36 import java.io.IOException; 37 import java.io.InputStream; 38 import java.io.InputStreamReader; 39 import java.util.Hashtable; 40 import java.util.List; 41 import java.util.Map; 42 import java.util.StringTokenizer; 43 import java.util.Vector; 44 45 /** 46 * AtomType list configurator that uses the ParameterSet originally defined in 47 * mmff94.prm from moe. This class was added to be able to port mmff94 to CDK. 48 * 49 * @author chhoppe 50 * @cdk.created 2004-09-07 51 * @cdk.module forcefield 52 * @cdk.githash 53 * @cdk.keyword atom type, mmff94 54 */ 55 public class MMFF94BasedParameterSetReader { 56 57 private final ILoggingTool LOG = LoggingToolFactory 58 .createLoggingTool(MMFF94BasedParameterSetReader.class); 59 60 private String configFile = "org/openscience/cdk/modeling/forcefield/data/mmff94.prm"; 61 private InputStream ins = null; 62 private Map<String, Object> parameterSet; 63 private List<IAtomType> atomTypes; 64 private StringTokenizer st; 65 private String key = ""; 66 private String sid; 67 68 private String configFilevdW = "org/openscience/cdk/modeling/forcefield/data/mmffvdw.prm"; 69 private InputStream insvdW = null; 70 private StringTokenizer stvdW; 71 private String sidvdW; 72 73 private String configFileDFSB = "org/openscience/cdk/modeling/forcefield/data/mmffdfsb.par"; 74 private InputStream insDFSB; 75 private StringTokenizer stDFSB; 76 77 /** 78 * Constructor for the MM2BasedParameterSetReader object 79 */ MMFF94BasedParameterSetReader()80 public MMFF94BasedParameterSetReader() { 81 parameterSet = new Hashtable<String, Object>(); 82 atomTypes = new Vector<IAtomType>(); 83 } 84 getParamterSet()85 public Map<String, Object> getParamterSet() { 86 return parameterSet; 87 } 88 getAtomTypes()89 public List<IAtomType> getAtomTypes() { 90 return atomTypes; 91 } 92 93 /** 94 * Sets the file containing the config data 95 * 96 * @param ins The new inputStream type InputStream 97 */ setInputStream(InputStream ins)98 public void setInputStream(InputStream ins) { 99 this.ins = ins; 100 } 101 102 /** 103 * Read a text based configuration file out of the force field mm2 file 104 * 105 * @throws Exception Description of the Exception 106 */ setAtomTypeData()107 private void setAtomTypeData() throws Exception { 108 109 key = "data" + sid; 110 List data = new Vector(); 111 112 String sradius = st.nextToken(); 113 String swell = st.nextToken(); 114 String sapol = st.nextToken(); 115 String sNeff = st.nextToken(); 116 //st.nextToken(); 117 String sDA = st.nextToken(); 118 String sq0 = st.nextToken(); 119 String spbci = st.nextToken(); 120 String sfcadj = st.nextToken(); 121 122 stvdW.nextToken(); 123 stvdW.nextToken(); 124 String sA = stvdW.nextToken(); 125 String sG = stvdW.nextToken(); 126 127 try { 128 double well = new Double(swell).doubleValue(); 129 double apol = new Double(sapol).doubleValue(); 130 double Neff = new Double(sNeff).doubleValue(); 131 double fcadj = new Double(sfcadj).doubleValue(); 132 //double pbci = new Double(spbci).doubleValue(); 133 double a = new Double(sA).doubleValue(); 134 double g = new Double(sG).doubleValue(); 135 136 data.add(new Double(well)); 137 data.add(new Double(apol)); 138 data.add(new Double(Neff)); 139 data.add(new String(sDA)); 140 data.add(new Double(fcadj)); 141 data.add(new Double(spbci)); 142 data.add(new Double(a)); 143 data.add(new Double(g)); 144 145 } catch (NumberFormatException nfe) { 146 throw new IOException("Data: Malformed Number due to:" + nfe); 147 } 148 149 LOG.debug("data : well,apol,Neff,sDA,fcadj,spbci,a,g " + data); 150 parameterSet.put(key, data); 151 152 key = "vdw" + sid; 153 data = new Vector(); 154 try { 155 double radius = new Double(sradius).doubleValue(); 156 data.add(new Double(radius)); 157 158 } catch (NumberFormatException nfe2) { 159 LOG.debug("vdwError: Malformed Number due to:" + nfe2); 160 } 161 parameterSet.put(key, data); 162 163 key = "charge" + sid; 164 data = new Vector(); 165 try { 166 double q0 = new Double(sq0).doubleValue(); 167 data.add(new Double(q0)); 168 } catch (NumberFormatException nfe3) { 169 System.err.println("Charge: Malformed Number due to:" + nfe3); 170 } 171 parameterSet.put(key, data); 172 } 173 174 /** 175 * Read and stores the atom types in a vector 176 * 177 * @throws Exception Description of the Exception 178 */ setAtomTypes(IChemObjectBuilder builder)179 private void setAtomTypes(IChemObjectBuilder builder) throws Exception { 180 String name = ""; 181 String rootType = ""; 182 //int an = 0; 183 int rl = 255; 184 int gl = 20; 185 int bl = 147; 186 int maxbond = 0; 187 int atomNr = 0; 188 189 double mass = 0.0; 190 st.nextToken(); 191 String sid = st.nextToken(); 192 rootType = st.nextToken(); 193 String smaxbond = st.nextToken(); 194 String satomNr = st.nextToken(); 195 String smass = st.nextToken(); 196 name = st.nextToken(); 197 198 try { 199 maxbond = Integer.parseInt(smaxbond); 200 mass = Double.parseDouble(smass); 201 atomNr = Integer.parseInt(satomNr); 202 203 } catch (NumberFormatException nfe) { 204 throw new IOException("AtomTypeTable.ReadAtypes: " + "Malformed Number"); 205 } 206 207 IAtomType atomType = builder.newInstance(IAtomType.class, name, rootType); 208 atomType.setAtomicNumber(atomNr); 209 atomType.setExactMass(mass); 210 atomType.setMassNumber(massNumber(atomNr, mass)); 211 atomType.setFormalNeighbourCount(maxbond); 212 atomType.setSymbol(rootType); 213 Color co = new Color(rl, gl, bl); 214 atomType.setProperty("org.openscience.cdk.renderer.color", co); 215 atomType.setAtomTypeName(sid); 216 atomTypes.add(atomType); 217 } 218 219 /** 220 * Sets the bond attribute stored into the parameter set 221 * 222 * @throws Exception Description of the Exception 223 */ setBond()224 private void setBond() throws Exception { 225 List data = new Vector(); 226 st.nextToken(); 227 String scode = st.nextToken(); 228 String sid1 = st.nextToken(); 229 String sid2 = st.nextToken(); 230 String slen = st.nextToken(); 231 String sk2 = st.nextToken(); 232 String sk3 = st.nextToken(); 233 String sk4 = st.nextToken(); 234 String sbci = st.nextToken(); 235 236 try { 237 double len = new Double(slen).doubleValue(); 238 double k2 = new Double(sk2).doubleValue(); 239 double k3 = new Double(sk3).doubleValue(); 240 double k4 = new Double(sk4).doubleValue(); 241 double bci = new Double(sbci).doubleValue(); 242 data.add(new Double(len)); 243 data.add(new Double(k2)); 244 data.add(new Double(k3)); 245 data.add(new Double(k4)); 246 data.add(new Double(bci)); 247 248 } catch (NumberFormatException nfe) { 249 throw new IOException("setBond: Malformed Number due to:" + nfe); 250 } 251 // key = "bond" + scode + ";" + sid1 + ";" + sid2; 252 key = "bond" + sid1 + ";" + sid2; 253 parameterSet.put(key, data); 254 } 255 256 /** 257 * Sets the angle attribute stored into the parameter set 258 * 259 * @throws Exception Description of the Exception 260 */ setAngle()261 private void setAngle() throws Exception { 262 List data = new Vector(); 263 st.nextToken(); 264 String scode = st.nextToken(); // String scode 265 String sid1 = st.nextToken(); 266 String sid2 = st.nextToken(); 267 String sid3 = st.nextToken(); 268 String value1 = st.nextToken(); 269 String value2 = st.nextToken(); 270 String value3 = st.nextToken(); 271 String value4 = st.nextToken(); 272 273 try { 274 //int code=new Integer(scode).intValue(); 275 double va1 = new Double(value1).doubleValue(); 276 double va2 = new Double(value2).doubleValue(); 277 double va3 = new Double(value3).doubleValue(); 278 double va4 = new Double(value4).doubleValue(); 279 data.add(new Double(va1)); 280 data.add(new Double(va2)); 281 data.add(new Double(va3)); 282 data.add(new Double(va4)); 283 284 // key = "angle" + scode + ";" + sid1 + ";" + sid2 + ";" + sid3; 285 key = "angle" + sid1 + ";" + sid2 + ";" + sid3; 286 if (parameterSet.containsKey(key)) { 287 data = (Vector) parameterSet.get(key); 288 data.add(new Double(va1)); 289 data.add(new Double(va2)); 290 data.add(new Double(va3)); 291 data.add(new Double(va4)); 292 } 293 parameterSet.put(key, data); 294 295 } catch (NumberFormatException nfe) { 296 throw new IOException("setAngle: Malformed Number due to:" + nfe); 297 } 298 } 299 300 /** 301 * Sets the strBnd attribute stored into the parameter set 302 * 303 * @throws Exception Description of the Exception 304 */ setStrBnd()305 private void setStrBnd() throws Exception { 306 List data = new Vector(); 307 st.nextToken(); 308 String scode = st.nextToken(); // String scode 309 String sid1 = st.nextToken(); 310 String sid2 = st.nextToken(); 311 String sid3 = st.nextToken(); 312 String value1 = st.nextToken(); 313 String value2 = st.nextToken(); 314 315 try { 316 //int code=new Integer(scode).intValue(); 317 double va1 = new Double(value1).doubleValue(); 318 double va2 = new Double(value2).doubleValue(); 319 data.add(new Double(va1)); 320 data.add(new Double(va2)); 321 322 } catch (NumberFormatException nfe) { 323 throw new IOException("setStrBnd: Malformed Number due to:" + nfe); 324 } 325 key = "strbnd" + scode + ";" + sid1 + ";" + sid2 + ";" + sid3; 326 LOG.debug("key =" + key); 327 parameterSet.put(key, data); 328 } 329 330 /** 331 * Sets the torsion attribute stored into the parameter set 332 * 333 * @throws Exception Description of the Exception 334 */ setTorsion()335 private void setTorsion() throws Exception { 336 List data = null; 337 st.nextToken(); 338 String scode = st.nextToken(); // String scode 339 String sid1 = st.nextToken(); 340 String sid2 = st.nextToken(); 341 String sid3 = st.nextToken(); 342 String sid4 = st.nextToken(); 343 String value1 = st.nextToken(); 344 String value2 = st.nextToken(); 345 String value3 = st.nextToken(); 346 String value4 = st.nextToken(); 347 String value5 = st.nextToken(); 348 349 try { 350 double va1 = new Double(value1).doubleValue(); 351 double va2 = new Double(value2).doubleValue(); 352 double va3 = new Double(value3).doubleValue(); 353 double va4 = new Double(value4).doubleValue(); 354 double va5 = new Double(value5).doubleValue(); 355 356 key = "torsion" + scode + ";" + sid1 + ";" + sid2 + ";" + sid3 + ";" + sid4; 357 LOG.debug("key = " + key); 358 if (parameterSet.containsKey(key)) { 359 data = (Vector) parameterSet.get(key); 360 data.add(new Double(va1)); 361 data.add(new Double(va2)); 362 data.add(new Double(va3)); 363 data.add(new Double(va4)); 364 data.add(new Double(va5)); 365 LOG.debug("data = " + data); 366 } else { 367 data = new Vector(); 368 data.add(new Double(va1)); 369 data.add(new Double(va2)); 370 data.add(new Double(va3)); 371 data.add(new Double(va4)); 372 data.add(new Double(va5)); 373 LOG.debug("data = " + data); 374 } 375 376 parameterSet.put(key, data); 377 378 } catch (NumberFormatException nfe) { 379 throw new IOException("setTorsion: Malformed Number due to:" + nfe); 380 } 381 } 382 383 /** 384 * Sets the opBend attribute stored into the parameter set 385 * 386 * @throws Exception Description of the Exception 387 */ setOpBend()388 private void setOpBend() throws Exception { 389 List data = new Vector(); 390 st.nextToken(); 391 String sid1 = st.nextToken(); 392 String sid2 = st.nextToken(); 393 String sid3 = st.nextToken(); 394 String sid4 = st.nextToken(); 395 String value1 = st.nextToken(); 396 397 try { 398 double va1 = new Double(value1).doubleValue(); 399 data.add(new Double(va1)); 400 key = "opbend" + sid1 + ";" + sid2 + ";" + sid3 + ";" + sid4; 401 if (parameterSet.containsKey(key)) { 402 data = (Vector) parameterSet.get(key); 403 data.add(new Double(va1)); 404 } 405 parameterSet.put(key, data); 406 407 } catch (NumberFormatException nfe) { 408 throw new IOException("setOpBend: Malformed Number due to:" + nfe); 409 } 410 } 411 412 /** 413 * Sets the Default Stretch-Bend Parameters into the parameter set 414 * 415 * @throws Exception Description of the Exception 416 */ setDefaultStrBnd()417 private void setDefaultStrBnd() throws Exception { 418 LOG.debug("Sets the Default Stretch-Bend Parameters"); 419 List data = new Vector(); 420 stDFSB.nextToken(); 421 String sIR = stDFSB.nextToken(); 422 String sJR = stDFSB.nextToken(); 423 String sKR = stDFSB.nextToken(); 424 String skbaIJK = stDFSB.nextToken(); 425 String skbaKJI = stDFSB.nextToken(); 426 427 try { 428 key = "DFSB" + sIR + ";" + sJR + ";" + sKR; 429 double kbaIJK = new Double(skbaIJK).doubleValue(); 430 double kbaKJI = new Double(skbaKJI).doubleValue(); 431 data.add(new Double(kbaIJK)); 432 data.add(new Double(kbaKJI)); 433 parameterSet.put(key, data); 434 435 } catch (NumberFormatException nfe) { 436 throw new IOException("setDFSB: Malformed Number due to:" + nfe); 437 } 438 } 439 440 /** 441 * The main method which parses through the force field configuration file 442 * 443 * @throws Exception Description of the Exception 444 */ readParameterSets(IChemObjectBuilder builder)445 public void readParameterSets(IChemObjectBuilder builder) throws Exception { 446 //vdW,bond,angle,strbond,opbend,torsion,data 447 LOG.debug("------ Read MMFF94 ParameterSets ------"); 448 449 if (ins == null) { 450 ClassLoader loader = this.getClass().getClassLoader(); 451 ins = loader.getResourceAsStream(configFile); 452 } 453 if (ins == null) { 454 throw new IOException("There was a problem getting the default stream: " + configFile); 455 } 456 457 BufferedReader r = new BufferedReader(new InputStreamReader(ins), 1024); 458 String s; 459 int[] a = {0, 0, 0, 0, 0, 0, 0, 0}; 460 461 if (insvdW == null) { 462 insvdW = this.getClass().getClassLoader().getResourceAsStream(configFilevdW); 463 } 464 if (insvdW == null) { 465 throw new IOException("There was a problem getting the default stream: " + configFilevdW); 466 } 467 468 BufferedReader rvdW = new BufferedReader(new InputStreamReader(insvdW), 1024); 469 String svdW; 470 int ntvdW; 471 472 if (insDFSB == null) { 473 insDFSB = this.getClass().getClassLoader().getResourceAsStream(configFileDFSB); 474 } 475 if (insDFSB == null) { 476 throw new IOException("There was a problem getting the default stream: " + configFileDFSB); 477 } 478 479 BufferedReader rDFSB = new BufferedReader(new InputStreamReader(insDFSB), 1024); 480 String sDFSB; 481 int ntDFSB; 482 483 try { 484 while (true) { 485 s = r.readLine(); 486 if (s == null) { 487 break; 488 } 489 st = new StringTokenizer(s, "\t; "); 490 int nt = st.countTokens(); 491 if (s.startsWith("atom") & nt <= 8) { 492 setAtomTypes(builder); 493 a[0]++; 494 } else if (s.startsWith("bond") & nt == 9) { 495 setBond(); 496 a[1]++; 497 } else if (s.startsWith("angle") & nt <= 10) { 498 setAngle(); 499 a[2]++; 500 } else if (s.startsWith("strbnd") & nt == 7) { 501 setStrBnd(); 502 a[3]++; 503 } else if (s.startsWith("torsion") & nt == 11) { 504 setTorsion(); 505 a[4]++; 506 } else if (s.startsWith("opbend") & nt == 6) { 507 setOpBend(); 508 a[5]++; 509 } else if (s.startsWith("data") & nt == 10) { 510 readatmmffvdw: while (true) { 511 svdW = rvdW.readLine(); 512 if (svdW == null) { 513 break; 514 } 515 stvdW = new StringTokenizer(svdW, "\t; "); 516 ntvdW = stvdW.countTokens(); 517 LOG.debug("ntvdW : " + ntvdW); 518 if (svdW.startsWith("vdw") & ntvdW == 9) { 519 st.nextToken(); 520 sid = st.nextToken(); 521 stvdW.nextToken(); 522 sidvdW = stvdW.nextToken(); 523 if (sid.equals(sidvdW)) { 524 setAtomTypeData(); 525 a[6]++; 526 } 527 break readatmmffvdw; 528 } 529 }// end while 530 } 531 }// end while 532 533 ins.close(); 534 insvdW.close(); 535 } catch (IOException e) { 536 throw new IOException("There was a problem parsing the mmff94 forcefield"); 537 } 538 539 try { 540 LOG.debug("Parses the Default Stretch-Bend Parameters"); 541 while (true) { 542 sDFSB = rDFSB.readLine(); 543 LOG.debug("sDFSB = " + sDFSB); 544 if (sDFSB == null) { 545 LOG.debug("sDFSB == null, break"); 546 break; 547 } 548 stDFSB = new StringTokenizer(sDFSB, "\t; "); 549 ntDFSB = stDFSB.countTokens(); 550 LOG.debug("ntDFSB : " + ntDFSB); 551 if (sDFSB.startsWith("DFSB") & ntDFSB == 6) { 552 setDefaultStrBnd(); 553 } 554 } 555 insDFSB.close(); 556 LOG.debug("insDFSB closed"); 557 } catch (IOException e) { 558 throw new IOException("There was a problem parsing the Default Stretch-Bend Parameters (mmffdfsb.par)"); 559 } 560 } 561 562 /** 563 * Mass number for a atom with a given atomic number and exact mass. 564 * 565 * @param atomicNumber atomic number 566 * @param exactMass exact mass 567 * @return the mass number (or null) if no mass number was found 568 * @throws IOException isotope configuration could not be loaded 569 */ massNumber(int atomicNumber, double exactMass)570 private Integer massNumber(int atomicNumber, double exactMass) throws IOException { 571 String symbol = PeriodicTable.getSymbol(atomicNumber); 572 IIsotope isotope = Isotopes.getInstance().getIsotope(symbol, exactMass, 0.001); 573 return isotope != null ? isotope.getMassNumber() : null; 574 } 575 576 } 577