/* * MX Cheminformatics Tools for Java * * Copyright (c) 2007, 2008 Metamolecular, LLC * * http://metamolecular.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.chemhack.jsMolEditor.client.io.mdl; import java.util.ArrayList; import java.util.List; import com.chemhack.jsMolEditor.client.model.Atom; import com.chemhack.jsMolEditor.client.model.Molecule; import com.chemhack.jsMolEditor.client.jre.emulation.java.io.LineNumberReader; import com.chemhack.jsMolEditor.client.jre.emulation.java.io.IOException; /** * @author Richard L. Apodaca * Duan Lian */ public class MolfileReader { private boolean readChargesInAtomBlock; public MolfileReader() { readChargesInAtomBlock = false; } public void read(Molecule mol, String molfile) { if ("".equals(molfile)) { mol.clear(); return; } LineNumberReader bufferedReader = getBufferedReader(molfile); mol.beginModify(); try { setup(molfile); readHeader(mol, bufferedReader); int startLine = readConnectionTable(mol, bufferedReader); readProperties(mol, bufferedReader, startLine); } catch (IOException e) { throw new RuntimeException(e); } mol.endModify(); } private void setup(String molfile) { if (molfile.indexOf("M CHG") != -1) { readChargesInAtomBlock = false; } else { readChargesInAtomBlock = true; } } private void readHeader(Molecule mol, LineNumberReader reader) throws IOException { readLine(reader); readLine(reader); readLine(reader); } private int readConnectionTable(Molecule mol, LineNumberReader reader) throws IOException { String countsLine = MDLStringKit.padRight(readLine(reader), 84); int atomCount = 0; try { atomCount = MDLStringKit.extractInt(countsLine, 0, 3); } catch (Exception e) { throw new RuntimeException("Error parsing atom count on line 4:\n" + countsLine); } int bondCount = 0; try { bondCount = MDLStringKit.extractInt(countsLine, 3, 6); } catch (Exception e) { throw new RuntimeException("Error parsing bond count in counts line:\n" + countsLine); } String[] atomBlock = readLines(atomCount, reader); String[] bondBlock = readLines(bondCount, reader); createAtoms(mol, atomBlock, 5); createBonds(mol, bondBlock, 5 + atomCount); return 5 + atomCount + bondCount; } private void createAtoms(Molecule mol, String[] lines, int startLine) { for (int i = 0; i < lines.length; i++) { String line = MDLStringKit.padRight(lines[i], 69); try { createAtom(mol, line); } catch (Exception e) { throw new RuntimeException("Can't parse line " + (startLine + i) + " as atom.\n" + e.getLocalizedMessage() + "\n" + line, e); } } } private void createAtom(Molecule mol, String line) { float x = MDLStringKit.extractFloat(line, 0, 10); float y = MDLStringKit.extractFloat(line, 10, 20); float z = MDLStringKit.extractFloat(line, 20, 30); String symbol = MDLStringKit.extractString(line, 31, 34); Atom atom = mol.addAtom(symbol, x, y, z); if (readChargesInAtomBlock) { int chargeType = MDLStringKit.extractInt(line, 36, 39); int charge = 0; switch (chargeType) { case 0: break; case 1: charge = 3; break; case 2: charge = 2; break; case 3: charge = 1; break; case 5: charge = -1; break; case 6: charge = -2; break; case 7: charge = -3; break; } if (charge != 0) { atom.setCharge(charge); //mol.setCharge(atom, charge); } } } private void createBonds(Molecule mol, String[] lines, int startLine) throws IOException { for (int i = 0; i < lines.length; i++) { String line = lines[i]; try { createBond(mol, line); } catch (Exception e) { throw new RuntimeException("Can't parse line " + (i + startLine) + " as bond.\n" + e.getLocalizedMessage() + "\n" + line, e); } } } private void createBond(Molecule mol, String line) { int source = MDLStringKit.extractInt(line, 0, 3); int target = MDLStringKit.extractInt(line, 3, 6); int bondType = MDLStringKit.extractInt(line, 6, 9); int stereo = MDLStringKit.extractInt(line, 9, 12); mol.connect(mol.getAtom(source - 1), mol.getAtom(target - 1), bondType, stereo); } private void readProperties(Molecule mol, LineNumberReader reader, int startLine) throws IOException { createProperties(mol, readLinesUntil("M END", reader), startLine); } private void createProperties(Molecule mol, String[] lines, int startLine) { for (int i = 0; i < lines.length; i++) { try { createProperty(mol, lines[i]); } catch (Exception ignore) { //throw new RuntimeException("Can't create property at line " + (startLine + i) + ".\n" + e.getLocalizedMessage() + "\n" + lines[i]); } } } private void createProperty(Molecule mol, String line) { String property = MDLStringKit.extractString(line, 0, 6); int entryCount = MDLStringKit.extractInt(line, 6, 9); for (int i = 0; i < entryCount; i++) { int offset = i * 8; int atomIndex = MDLStringKit.extractInt(line, offset + 10, offset + 13); int value = MDLStringKit.extractInt(line, offset + 14, offset + 17); Atom atom = mol.getAtom(atomIndex - 1); if ("M CHG".equals(property)) { setChargeProperty(mol, atom, value); } else if ("M RAD".equals(property)) { setRadicalProperty(mol, atom, value); } else if ("M ISO".equals(property)) { setIsotopeProperty(mol, atom, value); } } } private void setChargeProperty(Molecule mol, Atom atom, int charge) { atom.setCharge(charge); } private void setRadicalProperty(Molecule mol, Atom atom, int radical) { atom.setRadical(radical); } private void setIsotopeProperty(Molecule mol, Atom atom, int isotope) { atom.setIsotope(isotope); } private LineNumberReader getBufferedReader(String molfile) { LineNumberReader result = new LineNumberReader(molfile); return result; } private String readLine(LineNumberReader input) throws IOException { String line = input.readLine(); if (line == null) { throw new IOException("Unexpected EOF at line " + input.getLineNumber() + ".\n"); } /* if (line.length() > 80) { throw new RuntimeException("Line exceeds 80 characters in length at line " + input.getLineNumber() + ".\n" + line); } */ return line; } private String[] readLines(int count, LineNumberReader input) throws IOException { String[] result = new String[count]; for (int i = 0; i < count; i++) { result[i] = readLine(input); } return result; } private String[] readLinesUntil(String stop, LineNumberReader input) throws IOException { List strings = new ArrayList(); while (input.ready()) { String line = null; try { line = readLine(input); } catch (IOException e) { throw new RuntimeException("Expected stop token \"" + stop + "\" not found."); } if (stop.equals(line)) { break; } strings.add(line); } return (String[]) strings.toArray(new String[0]); } }