From 5d559ba1007072cbf2e7065a3a32356a188fea7f Mon Sep 17 00:00:00 2001 From: jprocter Date: Tue, 4 Dec 2012 11:06:45 +0000 Subject: [PATCH] JAL-1213 JAL-674 - import a PDB file using Jmol data api and decorate any peptide sequences with secondary structure annotation --- src/jalview/ext/jmol/PDBFileWithJmol.java | 431 ++++++++++++++++++++++++ src/jalview/io/AppletFormatAdapter.java | 2 + test/jalview/ext/jmol/PDBFileWithJmolTest.java | 31 ++ 3 files changed, 464 insertions(+) create mode 100644 src/jalview/ext/jmol/PDBFileWithJmol.java create mode 100644 test/jalview/ext/jmol/PDBFileWithJmolTest.java diff --git a/src/jalview/ext/jmol/PDBFileWithJmol.java b/src/jalview/ext/jmol/PDBFileWithJmol.java new file mode 100644 index 0000000..962fe3c --- /dev/null +++ b/src/jalview/ext/jmol/PDBFileWithJmol.java @@ -0,0 +1,431 @@ +/* + * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8) + * Copyright (C) 2012 J Procter, AM Waterhouse, LM Lui, J Engelhardt, G Barton, M Clamp, S Searle + * + * This file is part of Jalview. + * + * Jalview is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + * + * Jalview is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with Jalview. If not, see . + */ +package jalview.ext.jmol; + +import java.io.IOException; +import java.util.Map; + +import javax.xml.parsers.ParserConfigurationException; + +import org.jmol.api.JmolStatusListener; +import org.jmol.api.JmolViewer; +import org.jmol.constant.EnumCallback; +import org.jmol.constant.EnumStructure; +import org.jmol.modelset.Chain; +import org.jmol.modelset.Group; +import org.jmol.modelset.Model; +import org.jmol.modelset.ModelSet; +import org.jmol.modelset.Polymer; +import org.jmol.modelsetbio.BioPolymer; +import org.jmol.viewer.Viewer; +import org.openscience.jmol.app.JmolApp; +import org.xml.sax.SAXException; + +import fr.orsay.lri.varna.exceptions.ExceptionFileFormatOrSyntax; +import fr.orsay.lri.varna.exceptions.ExceptionLoadingFailed; +import fr.orsay.lri.varna.exceptions.ExceptionPermissionDenied; +import fr.orsay.lri.varna.exceptions.ExceptionUnmatchedClosingParentheses; +import jalview.datamodel.AlignmentAnnotation; +import jalview.datamodel.Annotation; +import jalview.datamodel.PDBEntry; +import jalview.datamodel.Sequence; +import jalview.datamodel.SequenceI; +import jalview.io.AlignFile; + +/** + * Import and process PDB files with Jmol + * + * @author jprocter + * + */ +public class PDBFileWithJmol extends AlignFile implements + JmolStatusListener +{ + + JmolApp jmolApp = null; + + Viewer viewer = null; + + public PDBFileWithJmol(String inFile, String type) + throws ExceptionUnmatchedClosingParentheses, IOException, + ExceptionFileFormatOrSyntax, ParserConfigurationException, + SAXException, ExceptionPermissionDenied, ExceptionLoadingFailed, + InterruptedException + { + super(inFile, type); + } + + public PDBFileWithJmol() + { + // TODO Auto-generated constructor stub + } + + /** + * create a headless jmol instance for dataprocessing + * + * @return + */ + private Viewer getJmolData() + { + if (viewer == null) + { // note that -o -n -x are all implied + jmolApp = new JmolApp(); + jmolApp.isDataOnly = true; + jmolApp.haveConsole = false; + jmolApp.haveDisplay = false; + jmolApp.exitUponCompletion = true; + try + { + viewer = (Viewer) JmolViewer.allocateViewer(null, null, null, null, + null, jmolApp.commandOptions, this); + viewer.setScreenDimension(jmolApp.startupWidth, + jmolApp.startupHeight); + jmolApp.startViewer(viewer, null); + } catch (ClassCastException x) + { + throw new Error( + "Jmol version " + + JmolViewer.getJmolVersion() + + " is not compatible with this version of Jalview. Report this problem at issues.jalview.org", + x); + } + } + return viewer; + } + + private void waitForScript(Viewer jmd) + { + while (jmd.isScriptExecuting()) + { + try + { + Thread.sleep(50); + + } catch (InterruptedException x) + { + } + } + } + + /* + * (non-Javadoc) + * + * @see jalview.io.AlignFile#parse() + */ + @Override + public void parse() throws IOException, ExceptionFileFormatOrSyntax, + ParserConfigurationException, SAXException, + ExceptionPermissionDenied, ExceptionLoadingFailed, + InterruptedException, ExceptionUnmatchedClosingParentheses + { + Viewer jmd = getJmolData(); + jmd.openReader(getDataName(), getDataName(), getReader()); + waitForScript(jmd); + if (jmd.getModelCount() > 0) + { + ModelSet ms = jmd.getModelSet(); + String structs = ms.calculateStructures(null, true, false, true); + // System.out.println("Structs\n"+structs); + for (Model model : ms.getModels()) + { + for (int _bp = 0, _bpc = model.getBioPolymerCount(); _bp < _bpc; _bp++) + { + Polymer bp = model.getBioPolymer(_bp); + if (bp instanceof BioPolymer) + { + BioPolymer biopoly = (BioPolymer) bp; + char _lastChainId = 0; + int[] groups = biopoly.getLeadAtomIndices(); + Group[] bpgrp = biopoly.getGroups(); + char seq[] = new char[groups.length], secstr[] = new char[groups.length], secstrcode[] = new char[groups.length]; + int groupc = 0, len = 0, firstrnum = 1, lastrnum = 0; + do + { + if (groupc >= groups.length + || ms.atoms[groups[groupc]].getChainID() != _lastChainId) + { + if (len > 0) + { + char newseq[] = new char[len]; + System.arraycopy(seq, 0, newseq, 0, len); + Annotation asecstr[] = new Annotation[len]; + for (int p = 0; p < len; p++) + { + if (secstr[p] >= 'A' && secstr[p] <= 'z') + { + asecstr[p] = new Annotation("" + secstr[p], null, + secstrcode[p], Float.NaN); + } + } + SequenceI sq = new Sequence("" + getDataName() + "|" + + model.getModelTitle() + "|" + _lastChainId, + newseq, firstrnum, lastrnum); + PDBEntry pdbe = new PDBEntry(); + pdbe.setFile(getDataName()); + pdbe.setId(getDataName()); + sq.addPDBId(pdbe); + seqs.add(sq); + if (!(biopoly.isDna() || biopoly.isRna())) + { + AlignmentAnnotation ann = new AlignmentAnnotation( + "Secondary Structure", + "Secondary Structure from PDB File", asecstr); + sq.addAlignmentAnnotation(ann); + annotations.add(ann); + } + } + len = 0; + firstrnum = 1; + lastrnum = 0; + } + if (groupc < groups.length) + { + if (len == 0) + { + firstrnum = bpgrp[groupc].getResno(); + _lastChainId = bpgrp[groupc].getChainID(); + } + else + { + lastrnum = bpgrp[groupc].getResno(); + } + seq[len] = bpgrp[groupc].getGroup1(); + switch (bpgrp[groupc].getProteinStructureSubType()) + { + case HELIX_310: + if (secstr[len] == 0) + { + secstr[len] = '3'; + } + case HELIX_ALPHA: + if (secstr[len] == 0) + { + secstr[len] = 'H'; + } + case HELIX_PI: + if (secstr[len] == 0) + { + secstr[len] = 'P'; + } + case HELIX: + if (secstr[len] == 0) + { + secstr[len] = 'H'; + } + secstrcode[len] = 'H'; + break; + case SHEET: + secstr[len] = 'E'; + secstrcode[len] = 'E'; + break; + default: + secstr[len] = 0; + secstrcode[len] = 0; + } + len++; + } + } while (groupc++ < groups.length); + + } + } + } + + /* + * lastScriptTermination = -9465; String dsspOut = + * jmd.evalString("calculate STRUCTURE"); if (dsspOut.equals("pending")) { + * while (lastScriptTermination == -9465) { try { Thread.sleep(50); } + * catch (Exception x) { } ; } } System.out.println(lastConsoleEcho); + */ + } + } + + /* + * (non-Javadoc) + * + * @see jalview.io.AlignFile#print() + */ + @Override + public String print() + { + // TODO Auto-generated method stub + return null; + } + + @Override + public void setCallbackFunction(String callbackType, + String callbackFunction) + { + // TODO Auto-generated method stub + + } + + /* + * @Override public void notifyCallback(EnumCallback type, Object[] data) { + * try { switch (type) { case ERROR: case SCRIPT: + * notifyScriptTermination((String) data[2], ((Integer) data[3]).intValue()); + * break; case MESSAGE: sendConsoleMessage((data == null) ? ((String) null) : + * (String) data[1]); break; case LOADSTRUCT: notifyFileLoaded((String) + * data[1], (String) data[2], (String) data[3], (String) data[4], ((Integer) + * data[5]).intValue()); + * + * break; default: // System.err.println("Unhandled callback " + type + " " // + * + data[1].toString()); break; } } catch (Exception e) { + * System.err.println("Squashed Jmol callback handler error:"); + * e.printStackTrace(); } } + */ + public void notifyCallback(EnumCallback type, Object[] data) + { + String strInfo = (data == null || data[1] == null ? null : data[1] + .toString()); + switch (type) + { + case ECHO: + sendConsoleEcho(strInfo); + break; + case SCRIPT: + notifyScriptTermination((String) data[2], + ((Integer) data[3]).intValue()); + break; + case MEASURE: + String mystatus = (String) data[3]; + if (mystatus.indexOf("Picked") >= 0 + || mystatus.indexOf("Sequence") >= 0) // picking mode + sendConsoleMessage(strInfo); + else if (mystatus.indexOf("Completed") >= 0) + sendConsoleEcho(strInfo.substring(strInfo.lastIndexOf(",") + 2, + strInfo.length() - 1)); + break; + case MESSAGE: + sendConsoleMessage(data == null ? null : strInfo); + break; + case PICK: + sendConsoleMessage(strInfo); + break; + default: + break; + } + } + + private void notifyFileLoaded(String string, String string2, + String string3, String string4, int intValue) + { + // TODO Auto-generated method stub + + } + + String lastConsoleEcho = ""; + + private void sendConsoleEcho(String string) + { + lastConsoleEcho += string; + lastConsoleEcho += "\n"; + } + + String lastConsoleMessage = ""; + + private void sendConsoleMessage(String string) + { + lastConsoleMessage += string; + lastConsoleMessage += "\n"; + } + + int lastScriptTermination = -1; + + String lastScriptMessage = ""; + + private void notifyScriptTermination(String string, int intValue) + { + lastScriptMessage += string; + lastScriptMessage += "\n"; + lastScriptTermination = intValue; + } + + @Override + public boolean notifyEnabled(EnumCallback callbackPick) + { + switch (callbackPick) + { + case MESSAGE: + case SCRIPT: + case ECHO: + case LOADSTRUCT: + case ERROR: + return true; + case MEASURE: + case PICK: + case HOVER: + case RESIZE: + case SYNC: + case CLICK: + case ANIMFRAME: + case MINIMIZATION: + } + return false; + } + + @Override + public String eval(String strEval) + { + // TODO Auto-generated method stub + return null; + } + + @Override + public float[][] functionXY(String functionName, int x, int y) + { + // TODO Auto-generated method stub + return null; + } + + @Override + public float[][][] functionXYZ(String functionName, int nx, int ny, int nz) + { + // TODO Auto-generated method stub + return null; + } + + @Override + public String createImage(String fileName, String type, + Object text_or_bytes, int quality) + { + // TODO Auto-generated method stub + return null; + } + + @Override + public Map getRegistryInfo() + { + // TODO Auto-generated method stub + return null; + } + + @Override + public void showUrl(String url) + { + // TODO Auto-generated method stub + + } + + @Override + public void resizeInnerPanel(String data) + { + // TODO Auto-generated method stub + + } + +} diff --git a/src/jalview/io/AppletFormatAdapter.java b/src/jalview/io/AppletFormatAdapter.java index 637db81..85ea8e0 100755 --- a/src/jalview/io/AppletFormatAdapter.java +++ b/src/jalview/io/AppletFormatAdapter.java @@ -228,6 +228,8 @@ public class AppletFormatAdapter else if (format.equals("PDB")) { afile = new MCview.PDBfile(inFile, type); + // Uncomment to test Jmol data based PDB processing: JAL-1213 + // afile = new jalview.ext.jmol.PDBFileWithJmol(inFile, type); } else if (format.equals("STH")) { diff --git a/test/jalview/ext/jmol/PDBFileWithJmolTest.java b/test/jalview/ext/jmol/PDBFileWithJmolTest.java new file mode 100644 index 0000000..2b53822 --- /dev/null +++ b/test/jalview/ext/jmol/PDBFileWithJmolTest.java @@ -0,0 +1,31 @@ +/** + * + */ +package jalview.ext.jmol; + +import static org.junit.Assert.*; + +import java.util.Vector; + +import jalview.datamodel.SequenceI; + +import org.junit.Test; + +/** + * @author jimp + * + */ +public class PDBFileWithJmolTest +{ + + @Test + public void test() throws Exception + { + PDBFileWithJmol jtest=new PDBFileWithJmol("./examples/1vsp", jalview.io.AppletFormatAdapter.FILE); + Vector seqs=jtest.getSeqs(); + assertTrue("No sequences extracted from testfile", seqs!=null && seqs.size()>0); + assertTrue("No annotation generated.", seqs.get(0).getAnnotation()!=null && seqs.get(0).getAnnotation().length!=0); + + } + +} -- 1.7.10.2