From a5481d6e853a962af603f4a21b171ba6fc9c200d Mon Sep 17 00:00:00 2001 From: jprocter Date: Fri, 6 Oct 2006 16:54:03 +0000 Subject: [PATCH] Added filter so that input to a JPred job is *solely* the visible residues, and the profile and prediction are correctly mapped back to the original seuence. --- src/jalview/gui/AlignFrame.java | 6 +- src/jalview/io/JnetAnnotationMaker.java | 326 ++++++++-------- src/jalview/ws/JPredClient.java | 618 ++++--------------------------- src/jalview/ws/JPredThread.java | 553 +++++++++++++++++++++++++++ src/jalview/ws/MsaWSThread.java | 2 +- 5 files changed, 809 insertions(+), 696 deletions(-) create mode 100644 src/jalview/ws/JPredThread.java diff --git a/src/jalview/gui/AlignFrame.java b/src/jalview/gui/AlignFrame.java index 1bcd39e..f7c8840 100755 --- a/src/jalview/gui/AlignFrame.java +++ b/src/jalview/gui/AlignFrame.java @@ -2884,7 +2884,7 @@ public class AlignFrame if (msa.getSequences().length == 1) { // Single Sequence prediction - new jalview.ws.JPredClient(sh, title, false, msa, af); + new jalview.ws.JPredClient(sh, title, false, msa, af, true); } else { @@ -2892,7 +2892,7 @@ public class AlignFrame { // Sequence profile based prediction new jalview.ws.JPredClient(sh, - title, true, msa, af); + title, true, msa, af, true); } } } @@ -3210,4 +3210,4 @@ public void drop(DropTargetDropEvent evt) { return viewport; } -} +} \ No newline at end of file diff --git a/src/jalview/io/JnetAnnotationMaker.java b/src/jalview/io/JnetAnnotationMaker.java index 61f0ce1..577e874 100755 --- a/src/jalview/io/JnetAnnotationMaker.java +++ b/src/jalview/io/JnetAnnotationMaker.java @@ -1,145 +1,181 @@ -/* -* Jalview - A Sequence Alignment Editor and Viewer -* Copyright (C) 2006 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle -* -* This program 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 2 -* of the License, or (at your option) any later version. -* -* This program 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 this program; if not, write to the Free Software -* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA -*/package jalview.io; - -import jalview.datamodel.*; - -public class JnetAnnotationMaker -{ - /** - * adds the annotation parsed by prediction to al. - * @param prediction JPredFile - * @param al AlignmentI - * @param FirstSeq int - - * @param noMsa boolean - */ - public static void add_annotation(JPredFile prediction, AlignmentI al, - int FirstSeq, boolean noMsa) - throws Exception - { - int i = 0; - SequenceI[] preds = prediction.getSeqsAsArray(); - // in the future we could search for the query - // sequence in the alignment before calling this function. - SequenceI seqRef = al.getSequenceAt(FirstSeq); - int width = preds[0].getSequence().length(); - int[] gapmap = al.getSequenceAt(FirstSeq).gapMap(); - if (gapmap.length != width) - { - throw (new Exception( - "Number of residues in supposed query sequence ('" + - al.getSequenceAt(FirstSeq).getName() + "'\n" + - al.getSequenceAt(FirstSeq).getSequence() + - ")\ndiffer from number of prediction sites in prediction (" + width + - ")")); - } - - AlignmentAnnotation annot; - Annotation[] annotations = null; - - int existingAnnotations = 0; - if(al.getAlignmentAnnotation()!=null) - existingAnnotations = al.getAlignmentAnnotation().length; - - - while (i < preds.length) - { - String id = preds[i].getName().toUpperCase(); - - if (id.startsWith("LUPAS") || id.startsWith("JNET") || - id.startsWith("JPRED")) - { - annotations = new Annotation[al.getWidth()]; - - if (id.equals("JNETPRED") || id.equals("JNETPSSM") || - id.equals("JNETFREQ") || id.equals("JNETHMM") || - id.equals("JNETALIGN") || id.equals("JPRED")) - { - for (int j = 0; j < width; j++) - { - annotations[gapmap[j]] = new Annotation("", "", - preds[i].getCharAt(j), 0); - } - } - else if (id.equals("JNETCONF")) - { - for (int j = 0; j < width; j++) - { - float value = new Float(preds[i].getCharAt( - j) + "").floatValue(); - annotations[gapmap[j]] = new Annotation(preds[i].getCharAt( - j) + "", "", preds[i].getCharAt(j), - value); - } - } - else - { - for (int j = 0; j < width; j++) - { - annotations[gapmap[j]] = new Annotation(preds[i].getCharAt( - j) + "", "", ' ', 0); - } - } - - if (id.equals("JNETCONF")) - { - annot = new AlignmentAnnotation(preds[i].getName(), - "JNet Output", annotations, 0f, - 10f, - AlignmentAnnotation.BAR_GRAPH); - } - else - { - annot = new AlignmentAnnotation(preds[i].getName(), - "JNet Output", annotations); - } - - if (seqRef != null) - { - annot.createSequenceMapping(seqRef, 1, true); - seqRef.addAlignmentAnnotation(annot); - } - - al.addAnnotation(annot); - al.setAnnotationIndex(annot, - al.getAlignmentAnnotation(). - length - existingAnnotations - 1); - - if (noMsa) - { - al.deleteSequence(preds[i]); - } - } - - i++; - } - - //Hashtable scores = prediction.getScores(); - - /* addFloatAnnotations(al, gapmap, (Vector)scores.get("JNETPROPH"), - "JnetpropH", "Jnet Helix Propensity", 0f,1f,1); - - addFloatAnnotations(al, gapmap, (Vector)scores.get("JNETPROPB"), - "JnetpropB", "Jnet Beta Sheet Propensity", 0f,1f,1); - - addFloatAnnotations(al, gapmap, (Vector)scores.get("JNETPROPC"), - "JnetpropC", "Jnet Coil Propensity", 0f,1f,1); - */ - - } -} +/* +* Jalview - A Sequence Alignment Editor and Viewer +* Copyright (C) 2006 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle +* +* This program 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 2 +* of the License, or (at your option) any later version. +* +* This program 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 this program; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA +*/package jalview.io; + +import jalview.datamodel.*; + +public class JnetAnnotationMaker +{ + public static void add_annotation(JPredFile prediction, AlignmentI al, + int firstSeq, boolean noMsa) throws Exception { + JnetAnnotationMaker.add_annotation(prediction, al, firstSeq, noMsa, (int[]) null); + } + /** + * adds the annotation parsed by prediction to al. + * @param prediction JPredFile + * @param al AlignmentI + * @param firstSeq int - + * @param noMsa boolean + * @param delMap mapping from columns in JPredFile prediction to residue number in al.getSequence(firstSeq) + */ + public static void add_annotation(JPredFile prediction, AlignmentI al, + int firstSeq, boolean noMsa, int[] delMap) + throws Exception + { + int i = 0; + SequenceI[] preds = prediction.getSeqsAsArray(); + // in the future we could search for the query + // sequence in the alignment before calling this function. + SequenceI seqRef = al.getSequenceAt(firstSeq); + int width = preds[0].getSequence().length(); + int[] gapmap = al.getSequenceAt(firstSeq).gapMap(); + if ((delMap!=null && delMap.length > width) || (delMap==null && gapmap.length!=width)) + { + throw (new Exception( + "Number of residues in "+(delMap==null ? "" : " mapped ")+"supposed query sequence ('" + + al.getSequenceAt(firstSeq).getName() + "'\n" + + al.getSequenceAt(firstSeq).getSequence() + + ")\ndiffer from number of prediction sites in prediction (" + width + + ")")); + } + + AlignmentAnnotation annot; + Annotation[] annotations = null; + + int existingAnnotations = 0; + if(al.getAlignmentAnnotation()!=null) + existingAnnotations = al.getAlignmentAnnotation().length; + + + while (i < preds.length) + { + String id = preds[i].getName().toUpperCase(); + + if (id.startsWith("LUPAS") || id.startsWith("JNET") || + id.startsWith("JPRED")) + { + annotations = new Annotation[al.getWidth()]; + /* if (delMap!=null) { + for (int j=0; j 1) { - - String altitle = "JNet prediction on " + seq.getName() + + + String altitle = "JNet prediction on "+(viewonly?"visible ":"") + seq.getName() + " using alignment from " + title; - wsInfo.setProgressText("Job details for MSA based prediction (" + - title + ") on sequence :\n>" + seq.getName() + - "\n" + - AlignSeq.extractGaps("-. ", seq.getSequence()) + - "\n"); SequenceI aln[] = new SequenceI[msf.length]; for (int i = 0, j = msf.length; i < j; i++) { aln[i] = msf[i].getSeq('-'); } - + + Hashtable SequenceInfo = jalview.analysis.SeqsetUtils.uniquify(aln, true); - + if (viewonly) { + // Remove hidden regions from sequence objects. + String seqs[] = alview.getSequenceStrings('-'); + for (int i = 0, j = msf.length; i < j; i++) + { + aln[i].setSequence(seqs[i]); + } + seq.setSequence(seqs[0]); + } + wsInfo.setProgressText("Job details for "+(viewonly?"visible ":"")+"MSA based prediction (" + + title + ") on sequence :\n>" + seq.getName() + + "\n" + + AlignSeq.extractGaps("-. ", seq.getSequence()) + + "\n"); JPredThread jthread = new JPredThread(wsInfo, altitle, server, - SequenceInfo, aln, alview, parentFrame); + SequenceInfo, aln, delMap, alview, parentFrame, WsURL); wsInfo.setthisService(jthread); jthread.start(); } @@ -105,19 +145,23 @@ public class JPredClient { if (!msa && msf.length>1) throw new Error("Implementation Error! Multiple single sequence prediction jobs are not yet supported."); - wsInfo.setProgressText("Job details for prediction on sequence :\n>" + - seq.getName() + "\n" + - AlignSeq.extractGaps("-. ", seq.getSequence()) + - "\n"); - String altitle = "JNet prediction for sequence " + seq.getName() + + String altitle = "JNet prediction for "+(viewonly?"visible ":"")+"sequence " + seq.getName() + " from " + title; - + String seqname = seq.getName(); Hashtable SequenceInfo = jalview.analysis.SeqsetUtils.SeqCharacterHash( seq); - - JPredThread jthread = new JPredThread(wsInfo, altitle, server, - SequenceInfo, seq, alview, parentFrame); + if (viewonly) { + // Remove hidden regions from input sequence + String seqs[] = alview.getSequenceStrings('-'); + seq.setSequence(seqs[0]); + } + wsInfo.setProgressText("Job details for prediction on "+(viewonly?"visible ":"")+"sequence :\n>" + + seqname + "\n" + + AlignSeq.extractGaps("-. ", seq.getSequence()) + + "\n"); + JPredThread jthread = new JPredThread(wsInfo, altitle, server, WsURL, + SequenceInfo, seq, delMap, alview, parentFrame); wsInfo.setthisService(jthread); jthread.start(); } @@ -175,7 +219,7 @@ public class JPredClient return; } - JPredThread jthread = new JPredThread(wsInfo, altitle, server, SequenceInfo, aln,null, parentFrame); + JPredThread jthread = new JPredThread(wsInfo, altitle, server, SequenceInfo, aln,null, null, parentFrame, WsURL); wsInfo.setthisService(jthread); jthread.start(); } @@ -201,7 +245,7 @@ public class JPredClient return; } - JPredThread jthread = new JPredThread(wsInfo, altitle, server, SequenceInfo, seq,null, parentFrame); + JPredThread jthread = new JPredThread(wsInfo, altitle, server, WsURL, SequenceInfo, seq,null, null, parentFrame); wsInfo.setthisService(jthread); jthread.start(); } @@ -251,525 +295,5 @@ public class JPredClient return server; } - - class JPredThread - extends WSThread - implements WSClientI - { - class JPredJob - extends WSThread.WSJob - { - - vamsas.objects.simple.Sequence sequence; - vamsas.objects.simple.Msfalignment msa; - java.util.Hashtable SequenceInfo = null; - /** - * - * @return true if getResultSet will return a valid alignment and prediction result. - */ - public boolean hasResults() - { - if (subjobComplete && result != null && result.isFinished() - && ( (JpredResult) result).getPredfile() != null && - ( (JpredResult) result).getAligfile() != null) - { - return true; - } - return false; - } - - boolean hasValidInput() - { - if (sequence != null) - { - return true; - } - return false; - } - - public Alignment getResultSet() - throws Exception - { - if (result == null || !result.isFinished()) - { - return null; - } - Alignment al = null; - int FirstSeq = -1; // the position of the query sequence in Alignment al - - JpredResult result = (JpredResult)this.result; - - jalview.bin.Cache.log.debug("Parsing output from JNet job."); - // JPredFile prediction = new JPredFile("C:/JalviewX/files/jpred.txt", "File"); - jalview.io.JPredFile prediction = new jalview.io.JPredFile(result. - getPredfile(), - "Paste"); - SequenceI[] preds = prediction.getSeqsAsArray(); - jalview.bin.Cache.log.debug("Got prediction profile."); - - if ( (this.msa != null) && (result.getAligfile() != null)) - { - jalview.bin.Cache.log.debug("Getting associated alignment."); - // we ignore the returned alignment if we only predicted on a single sequence - String format = new jalview.io.IdentifyFile().Identify(result. - getAligfile(), - "Paste"); - - if (jalview.io.FormatAdapter.isValidFormat(format)) - { - al = new Alignment(new FormatAdapter().readFile(result.getAligfile(), - "Paste", format)); - SequenceI sqs[] = new SequenceI[al.getHeight()]; - for (int i = 0, j = al.getHeight(); i < j; i++) - { - sqs[i] = al.getSequenceAt(i); - } - if (!jalview.analysis.SeqsetUtils.deuniquify( (Hashtable) - SequenceInfo, sqs)) - { - throw (new Exception( - "Couldn't recover sequence properties for alignment.")); - } - - FirstSeq = 0; - al.setDataset(null); - - jalview.io.JnetAnnotationMaker.add_annotation(prediction, al, FirstSeq, - false); - - } - else - { - throw (new Exception( - "Unknown format "+format+" for file : \n" + - result.getAligfile())); - } - } - else - { - al = new Alignment(preds); - FirstSeq = prediction.getQuerySeqPosition(); - if (!jalview.analysis.SeqsetUtils.SeqCharacterUnhash( - al.getSequenceAt(FirstSeq), SequenceInfo)) - { - throw (new Exception( - "Couldn't recover sequence properties for JNet Query sequence!")); - } else { - al.setDataset(null); - jalview.io.JnetAnnotationMaker.add_annotation(prediction, al, FirstSeq, - true); - } - } - - return al; // , FirstSeq, noMsa}; - } - public JPredJob(Hashtable SequenceInfo, SequenceI seq) - { - super(); - String sq = AlignSeq.extractGaps(Comparison.GapChars, seq.getSequence()); - if (sq.length() >= 20) - { - this.SequenceInfo = SequenceInfo; - sequence = new vamsas.objects.simple.Sequence(); - sequence.setId(seq.getName()); - sequence.setSeq(sq); - } - } - - public JPredJob(Hashtable SequenceInfo, SequenceI[] msf) - { - this(SequenceInfo, msf[0]); - if (sequence != null) - { - if (msf.length > 1) - { - msa = new vamsas.objects.simple.Msfalignment(); - jalview.io.PileUpfile pileup = new jalview.io.PileUpfile(); - msa.setMsf(pileup.print(msf)); - } - } - } - } - ext.vamsas.Jpred server; - String altitle = ""; - JPredThread(WebserviceInfo wsinfo, String altitle, ext.vamsas.Jpred server, AlignmentView alview, AlignFrame alframe) { - this.altitle = altitle; - this.server = server; - this.wsInfo = wsinfo; - this.input = alview; - this.alignFrame = alframe; - } - -// String OutputHeader; -// vamsas.objects.simple.JpredResult result; - - JPredThread(WebserviceInfo wsinfo, String altitle, ext.vamsas.Jpred server, Hashtable SequenceInfo,SequenceI seq, AlignmentView alview, AlignFrame alframe) - { - this(wsinfo, altitle, server,alview, alframe); - JPredJob job = new JPredJob(SequenceInfo, seq); - if (job.hasValidInput()) - { - OutputHeader = wsInfo.getProgressText(); - jobs = new WSJob[] - { - job}; - job.jobnum = 0; - } - } - - JPredThread(WebserviceInfo wsinfo, String altitle, ext.vamsas.Jpred server, Hashtable SequenceInfo, SequenceI[] msf, AlignmentView alview, AlignFrame alframe) - { - this(wsinfo, altitle, server,alview, alframe); - JPredJob job = new JPredJob(SequenceInfo, msf); - if (job.hasValidInput()) - { - jobs = new WSJob[] - { - job}; - OutputHeader = wsInfo.getProgressText(); - job.jobnum = 0; - } - } - - /* - public void run() - { - StartJob(); - - while (!jobComplete && (allowedServerExceptions > 0)) - { - try - { - if ( (result = server.getresult(jobId)) == null) - { - throw (new Exception( - "Timed out when communicating with server\nTry again later.\n")); - } - if (result.getState()==0) - jalview.bin.Cache.log.debug("Finished "+jobId); - if (result.isRunning()) - { - wsInfo.setStatus(WebserviceInfo.STATE_RUNNING); - } - if (result.isQueued()) - { - wsInfo.setStatus(WebserviceInfo.STATE_QUEUING); - } - - wsInfo.setProgressText(OutputHeader + "\n" + - result.getStatus()); - - if (result.isFinished()) - { - - parseResult(); - jobComplete = true; - jobsRunning--; - } else { - // catch exceptions - if (! (result.isJobFailed() || result.isServerError())) - { - try - { - Thread.sleep(5000); - } - catch (InterruptedException ex1) - { - } - - // System.out.println("I'm alive "+seqid+" "+jobid); - } - else - { - wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_ERROR); - jobsRunning--; - jobComplete = true; - } - } - } - catch (Exception ex) - { - allowedServerExceptions--; - - wsInfo.appendProgressText("\nJPredWS Server exception!\n" + - ex.getMessage()); - - try - { - if (allowedServerExceptions > 0) - { - Thread.sleep(5000); - } - } - catch (InterruptedException ex1) - { - } - } - catch (OutOfMemoryError er) - { - jobComplete = true; - wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_ERROR); - JOptionPane.showInternalMessageDialog(Desktop.desktop, - "Out of memory handling result!!" - + - "\nSee help files for increasing Java Virtual Machine memory." - , "Out of memory", - JOptionPane.WARNING_MESSAGE); - System.out.println("JPredClient: "+er); - System.gc(); - } - } - if (result!=null) - if (! (result.isJobFailed() || result.isServerError())) - { - wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_OK); - } - else - { - wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_ERROR); - } - } - */ - void StartJob(WSJob j) - { - if (! (j instanceof JPredJob)) - { - throw new Error("Implementation error - StartJob(JpredJob) called on " + - j.getClass()); - } - try - { - JPredJob job = (JPredJob) j; - if (job.msa != null) - { - job.jobId = server.predictOnMsa(job.msa); - } - else - if (job.sequence!=null) - { - job.jobId = server.predict(job.sequence); // debug like : job.jobId = "/jobs/www-jpred/jp_Yatat29";// - } - - if (job.jobId != null) - { - if (job.jobId.startsWith("Broken")) - { - job.result = (vamsas.objects.simple.Result)new JpredResult(); - job.result.setInvalid(true); - job.result.setStatus("Submission " + job.jobId); - } - else - { - job.submitted = true; - job.subjobComplete = false; - Cache.log.info(WsURL + " Job Id '" + job.jobId + "'"); - } - } - else - { - throw new Exception("Server timed out - try again later\n"); - } - } - catch (Exception e) - { - if (e.getMessage().indexOf("Exception") > -1) - { - wsInfo.setStatus(j.jobnum, WebserviceInfo.STATE_STOPPED_SERVERERROR); - wsInfo.setProgressText(j.jobnum, - "Failed to submit the prediction. (Just close the window)\n" - + - "It is most likely that there is a problem with the server.\n"); - System.err.println( - "JPredWS Client: Failed to submit the prediction. Quite possibly because of a server error - see below)\n" + - e.getMessage() + "\n"); - - jalview.bin.Cache.log.warn("Server Exception", e); - } - else - { - wsInfo.setStatus(j.jobnum, WebserviceInfo.STATE_STOPPED_ERROR); - // JBPNote - this could be a popup informing the user of the problem. - wsInfo.appendProgressText(j.jobnum, - "Failed to submit the prediction:\n" - + e.getMessage() + - wsInfo.getProgressText()); - - jalview.bin.Cache.log.debug("Failed Submission of job " + j.jobnum, e); - - } - j.allowedServerExceptions = -1; - j.subjobComplete = true; - } - } - - /* private void addFloatAnnotations(Alignment al, int[] gapmap, - Vector values, String Symname, - String Visname, float min, - float max, int winLength) - { - Annotation[] annotations = new Annotation[al.getWidth()]; - - for (int j = 0; j < values.size(); j++) - { - float value = Float.parseFloat(values.get(j).toString()); - annotations[gapmap[j]] = new Annotation("", value + "", ' ', - value); - } - - al.addAnnotation(new AlignmentAnnotation(Symname, Visname, - annotations, min, max, winLength)); - }*/ - - void parseResult() - { - int results = 0; // number of result sets received - JobStateSummary finalState = new JobStateSummary(); - try - { - for (int j = 0; j < jobs.length; j++) - { - finalState.updateJobPanelState(wsInfo, OutputHeader, jobs[j]); - if (jobs[j].submitted && jobs[j].subjobComplete && jobs[j].hasResults()) - { - results++; - } - } - } - catch (Exception ex) - { - - Cache.log.error("Unexpected exception when processing results for " + - altitle, ex); - wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_ERROR); - } - if (results > 0) - { - wsInfo.showResultsNewFrame - .addActionListener(new java.awt.event.ActionListener() - { - public void actionPerformed( - java.awt.event.ActionEvent evt) - { - displayResults(true); - } - }); - wsInfo.mergeResults - .addActionListener(new java.awt.event.ActionListener() - { - public void actionPerformed( - java.awt.event.ActionEvent evt) - { - displayResults(false); - } - }); - wsInfo.setResultsReady(); - } - else - { - wsInfo.setFinishedNoResults(); - } - } - - void displayResults(boolean newWindow) - { - // TODO: cope with multiple subjobs. - if (jobs != null) - { - Alignment res = null; - boolean msa=false; - for (int jn = 0; jn < jobs.length; jn++) - { - Alignment jobres = null; - JPredJob j = (JPredJob) jobs[jn]; - - if (j.hasResults()) - { - // hack - we only deal with all single seuqence predictions or all profile predictions - msa = (j.msa!=null) ? true : msa; - try - { - jalview.bin.Cache.log.debug("Parsing output of job " + jn); - jobres = j.getResultSet(); - jalview.bin.Cache.log.debug("Finished parsing output."); - if (jobs.length==1) - res = jobres; - else { - // do merge with other job results - throw new Error("Multiple JNet subjob merging not yet implemented."); - } - } - catch (Exception e) - { - jalview.bin.Cache.log.error( - "JNet Client: JPred Annotation Parse Error", - e); - wsInfo.setStatus(j.jobnum, WebserviceInfo.STATE_STOPPED_ERROR); - wsInfo.appendProgressText(j.jobnum, - OutputHeader + "\n" + - j.result.getStatus() + - "\nInvalid JNet job result data!\n" + - e.getMessage()); - j.result.setBroken(true); - } - } - } - - if (res != null) - { - if (newWindow) - { - AlignFrame af; - if (input==null) { - af = new AlignFrame(res, - AlignFrame.DEFAULT_WIDTH, - AlignFrame.DEFAULT_HEIGHT); - - } else { - java.lang.Object[] alandcolsel = input.getAlignmentAndColumnSelection(alignFrame.getViewport().getGapCharacter()); - - if (((SequenceI[])alandcolsel[0])[0].getLength()!=res.getWidth()) { - if (msa) { - throw new Error("Implementation Error! ColumnSelection from input alignment will not map to result alignment!"); - } else { - // test this. - ((ColumnSelection) alandcolsel[1]).pruneDeletions(ShiftList.parseMap(((SequenceI[]) alandcolsel[0])[0].gapMap()));//gapMap returns insert list, interpreted as delete list by pruneDeletions - } - } - af = new AlignFrame(res, (ColumnSelection) alandcolsel[1], - AlignFrame.DEFAULT_WIDTH, - AlignFrame.DEFAULT_HEIGHT); - } - Desktop.addInternalFrame(af, altitle, - AlignFrame.DEFAULT_WIDTH, - AlignFrame.DEFAULT_HEIGHT); - } - else - { - Cache.log.info("Append results onto existing alignment."); - } - } - } - } - void pollJob(WSJob job) - throws Exception - { - job.result = server.getresult(job.jobId); - } - public boolean isCancellable() - { - return false; - } - - public void cancelJob() - { - throw new Error("Implementation error!"); - } - - public boolean canMergeResults() - { - return false; - } - - } } diff --git a/src/jalview/ws/JPredThread.java b/src/jalview/ws/JPredThread.java new file mode 100644 index 0000000..6aebfdc --- /dev/null +++ b/src/jalview/ws/JPredThread.java @@ -0,0 +1,553 @@ +package jalview.ws; + +import java.util.*; + +import javax.swing.*; + +import vamsas.objects.simple.JpredResult; + +import ext.vamsas.*; +import jalview.analysis.*; +import jalview.bin.*; +import jalview.datamodel.*; +import jalview.gui.*; +import jalview.io.*; +import jalview.util.*; +import jalview.ws.WSThread.*; + +class JPredThread +extends WSThread +implements WSClientI +{ + // TODO: put mapping between JPredJob input and input data here - JNetAnnotation adding is done after result parsing. + class JPredJob + extends WSThread.WSJob + { + // TODO: make JPredJob deal only with what was sent to and received from a JNet service + int[] predMap=null; // mapping from sequence(i) to the original sequence(predMap[i]) being predicted on + vamsas.objects.simple.Sequence sequence; + vamsas.objects.simple.Msfalignment msa; + java.util.Hashtable SequenceInfo = null; + int msaIndex=0; // the position of the original sequence in the array of Sequences in the input object that this job holds a prediction for + /** + * + * @return true if getResultSet will return a valid alignment and prediction result. + */ + public boolean hasResults() + { + if (subjobComplete && result != null && result.isFinished() + && ( (JpredResult) result).getPredfile() != null && + ( (JpredResult) result).getAligfile() != null) + { + return true; + } + return false; + } + + boolean hasValidInput() + { + if (sequence != null) + { + return true; + } + return false; + } + /** + * + * @return null or Object[] { annotated alignment for this prediction, ColumnSelection for this prediction} or null if no results available. + * @throws Exception + */ + public Object[] getResultSet() + throws Exception + { + if (result == null || !result.isFinished()) + { + return null; + } + Alignment al = null; + ColumnSelection alcsel=null; + int FirstSeq = -1; // the position of the query sequence in Alignment al + + JpredResult result = (JpredResult)this.result; + + jalview.bin.Cache.log.debug("Parsing output from JNet job."); + // JPredFile prediction = new JPredFile("C:/JalviewX/files/jpred.txt", "File"); + jalview.io.JPredFile prediction = new jalview.io.JPredFile(result. + getPredfile(), + "Paste"); + SequenceI[] preds = prediction.getSeqsAsArray(); + jalview.bin.Cache.log.debug("Got prediction profile."); + + if ( (this.msa != null) && (result.getAligfile() != null)) + { + jalview.bin.Cache.log.debug("Getting associated alignment."); + // we ignore the returned alignment if we only predicted on a single sequence + String format = new jalview.io.IdentifyFile().Identify(result. + getAligfile(), + "Paste"); + + if (jalview.io.FormatAdapter.isValidFormat(format)) + { + SequenceI sqs[]; + if (predMap!=null) { + Object[] alandcolsel = input.getAlignmentAndColumnSelection(alignFrame.getViewport().getGapCharacter()); + sqs = (SequenceI[]) alandcolsel[0]; + al = new Alignment(sqs); + alcsel=(ColumnSelection) alandcolsel[1]; + } else { + al = new Alignment(new FormatAdapter().readFile(result.getAligfile(), + "Paste", format)); + sqs = new SequenceI[al.getHeight()]; + + for (int i = 0, j = al.getHeight(); i < j; i++) + { + sqs[i] = al.getSequenceAt(i); + } + if (!jalview.analysis.SeqsetUtils.deuniquify( (Hashtable) + SequenceInfo, sqs)) + { + throw (new Exception( + "Couldn't recover sequence properties for alignment.")); + } + } + FirstSeq = 0; + al.setDataset(null); + + jalview.io.JnetAnnotationMaker.add_annotation(prediction, al, FirstSeq, + false,predMap); + + } + else + { + throw (new Exception( + "Unknown format "+format+" for file : \n" + + result.getAligfile())); + } + } + else + { + al = new Alignment(preds); + FirstSeq = prediction.getQuerySeqPosition(); + if (predMap!=null) { + char gc = alignFrame.getViewport().getGapCharacter(); + SequenceI[] sqs = (SequenceI[]) ((java.lang.Object[]) input.getAlignmentAndColumnSelection(gc))[0]; + if (this.msaIndex>=sqs.length) + throw new Error("Implementation Error! Invalid msaIndex for JPredJob on parent MSA input object!"); + sqs[msaIndex].removeGaps(); + SequenceI profileseq=al.getSequenceAt(FirstSeq); + profileseq.setSequence(sqs[msaIndex].getSequence()); + } + + if (!jalview.analysis.SeqsetUtils.SeqCharacterUnhash( + al.getSequenceAt(FirstSeq), SequenceInfo)) + { + throw (new Exception( + "Couldn't recover sequence properties for JNet Query sequence!")); + } else { + al.setDataset(null); + jalview.io.JnetAnnotationMaker.add_annotation(prediction, al, FirstSeq, + true, predMap); + SequenceI profileseq=al.getSequenceAt(0); // this includes any gaps. + alignToProfileSeq(al, profileseq); + if (predMap!=null) { + // Adjust input view for gaps + // propagate insertions into profile + alcsel=propagateInsertions(profileseq, al, input); + } + } + } + return new Object[] { al, alcsel}; // , FirstSeq, noMsa}; + } + /** + * Given an alignment where all other sequences except profileseq are aligned to the ungapped profileseq, insert gaps in the other sequences to realign them with the residues in profileseq + * @param al + * @param profileseq + */ + private void alignToProfileSeq(Alignment al, SequenceI profileseq) { + char gc = al.getGapCharacter(); + int[] gapMap = profileseq.gapMap(); + // insert gaps into profile + for (int lp=0,r=0; r1) { + StringBuffer sb=new StringBuffer(); + for (int s=0, ns=gapMap[r]-lp; s0) { + // pad gaps + sq=sq+sb; + while ((diff=gapMap[r]-sq.length())>0) { + sq=sq+((diff>=sb.length()) ? sb.toString() : sb.substring(0, diff)); + } + al.getSequenceAt(s).setSequence(sq); + } else { + al.getSequenceAt(s).setSequence(sq.substring(0,gapMap[r])+sb.toString()+sq.substring(gapMap[r])); + } + } + } + lp=gapMap[r]; + } + } + + /** + * Add gaps into the sequences aligned to profileseq under the given AlignmentView + * @param profileseq + * @param al + * @param input + */ + private ColumnSelection propagateInsertions(SequenceI profileseq, Alignment al, AlignmentView input) { + char gc = al.getGapCharacter(); + Object[] alandcolsel = input.getAlignmentAndColumnSelection(gc); + ColumnSelection nview = (ColumnSelection) alandcolsel[1]; + SequenceI origseq; + nview.pruneDeletions(ShiftList.parseMap((origseq=((SequenceI[]) alandcolsel[0])[0]).gapMap())); // recover original prediction sequence's mapping to view. + int[] viscontigs=nview.getVisibleContigs(0, profileseq.getLength()); + int spos=0; + int offset=0; + // input.pruneDeletions(ShiftList.parseMap(((SequenceI[]) alandcolsel[0])[0].gapMap())) + // add profile to visible contigs + for (int v=0; vspos) { + StringBuffer sb=new StringBuffer(); + for (int s=0, ns=viscontigs[v]-spos; s0) { + // pad gaps + sq=sq+sb; + while ((diff=spos+offset-sq.length()-1)>0) { + sq=sq+((diff>=sb.length()) ? sb.toString() : sb.substring(0, diff)); + } + } + sq+=sb.toString(); + } else { + al.getSequenceAt(s).setSequence(sq.substring(0,spos+offset)+sb.toString()+sq.substring(spos+offset)); + } + } + } + //offset+=sb.length(); + } + spos = viscontigs[v+1]+1; + } + if ((offset+spos)0) { + sq=sq+((diff>=sb.length()) ? sb.toString() : sb.substring(0, diff)); + diff=origseq.getLength()-sq.length(); + } + } + } + return nview; + } + + public JPredJob(Hashtable SequenceInfo, SequenceI seq, int[] delMap) + { + super(); + this.predMap = delMap; + String sq = AlignSeq.extractGaps(Comparison.GapChars, seq.getSequence()); + if (sq.length() >= 20) + { + this.SequenceInfo = SequenceInfo; + sequence = new vamsas.objects.simple.Sequence(); + sequence.setId(seq.getName()); + sequence.setSeq(sq); + } + } + + public JPredJob(Hashtable SequenceInfo, SequenceI[] msf, int[] delMap) + { + this(SequenceInfo, msf[0], delMap); + if (sequence != null) + { + if (msf.length > 1) + { + msa = new vamsas.objects.simple.Msfalignment(); + jalview.io.PileUpfile pileup = new jalview.io.PileUpfile(); + msa.setMsf(pileup.print(msf)); + } + } + } + } + ext.vamsas.Jpred server; + String altitle = ""; + JPredThread(WebserviceInfo wsinfo, String altitle, ext.vamsas.Jpred server, String wsurl, AlignmentView alview, AlignFrame alframe) { + super(); + this.altitle = altitle; + this.server = server; + this.wsInfo = wsinfo; + this.input = alview; + this.alignFrame = alframe; + WsUrl = wsurl; + } + + + JPredThread(WebserviceInfo wsinfo, String altitle, ext.vamsas.Jpred server, String wsurl, Hashtable SequenceInfo,SequenceI seq, int[] delMap, AlignmentView alview, AlignFrame alframe) + { + this(wsinfo, altitle, server,wsurl, alview, alframe); + JPredJob job = new JPredJob(SequenceInfo, seq, delMap); + if (job.hasValidInput()) + { + OutputHeader = wsInfo.getProgressText(); + jobs = new WSJob[] + { + job}; + job.jobnum = 0; + } + } + + JPredThread(WebserviceInfo wsinfo, String altitle, ext.vamsas.Jpred server, Hashtable SequenceInfo, SequenceI[] msf, int[] delMap, AlignmentView alview, AlignFrame alframe, String wsurl) + { + this(wsinfo, altitle, server,wsurl, alview, alframe); + JPredJob job = new JPredJob(SequenceInfo, msf, delMap); + if (job.hasValidInput()) + { + jobs = new WSJob[] + { + job}; + OutputHeader = wsInfo.getProgressText(); + job.jobnum = 0; + } + } + void StartJob(WSJob j) + { + if (! (j instanceof JPredJob)) + { + throw new Error("Implementation error - StartJob(JpredJob) called on " + + j.getClass()); + } + try + { + JPredJob job = (JPredJob) j; + if (job.msa != null) + { + job.jobId = server.predictOnMsa(job.msa); + } + else + if (job.sequence!=null) + { + job.jobId = server.predict(job.sequence); // debug like : job.jobId = "/jobs/www-jpred/jp_Yatat29";// + } + + if (job.jobId != null) + { + if (job.jobId.startsWith("Broken")) + { + job.result = (vamsas.objects.simple.Result)new JpredResult(); + job.result.setInvalid(true); + job.result.setStatus("Submission " + job.jobId); + } + else + { + job.submitted = true; + job.subjobComplete = false; + Cache.log.info(WsUrl + " Job Id '" + job.jobId + "'"); + } + } + else + { + throw new Exception("Server timed out - try again later\n"); + } + } + catch (Exception e) + { + if (e.getMessage().indexOf("Exception") > -1) + { + wsInfo.setStatus(j.jobnum, WebserviceInfo.STATE_STOPPED_SERVERERROR); + wsInfo.setProgressText(j.jobnum, + "Failed to submit the prediction. (Just close the window)\n" + + + "It is most likely that there is a problem with the server.\n"); + System.err.println( + "JPredWS Client: Failed to submit the prediction. Quite possibly because of a server error - see below)\n" + + e.getMessage() + "\n"); + + jalview.bin.Cache.log.warn("Server Exception", e); + } + else + { + wsInfo.setStatus(j.jobnum, WebserviceInfo.STATE_STOPPED_ERROR); + // JBPNote - this could be a popup informing the user of the problem. + wsInfo.appendProgressText(j.jobnum, + "Failed to submit the prediction:\n" + + e.getMessage() + + wsInfo.getProgressText()); + + jalview.bin.Cache.log.debug("Failed Submission of job " + j.jobnum, e); + + } + j.allowedServerExceptions = -1; + j.subjobComplete = true; + } + } + + void parseResult() + { + int results = 0; // number of result sets received + JobStateSummary finalState = new JobStateSummary(); + try + { + for (int j = 0; j < jobs.length; j++) + { + finalState.updateJobPanelState(wsInfo, OutputHeader, jobs[j]); + if (jobs[j].submitted && jobs[j].subjobComplete && jobs[j].hasResults()) + { + results++; + } + } + } + catch (Exception ex) + { + + Cache.log.error("Unexpected exception when processing results for " + + altitle, ex); + wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_ERROR); + } + if (results > 0) + { + wsInfo.showResultsNewFrame + .addActionListener(new java.awt.event.ActionListener() + { + public void actionPerformed( + java.awt.event.ActionEvent evt) + { + displayResults(true); + } + }); + wsInfo.mergeResults + .addActionListener(new java.awt.event.ActionListener() + { + public void actionPerformed( + java.awt.event.ActionEvent evt) + { + displayResults(false); + } + }); + wsInfo.setResultsReady(); + } + else + { + wsInfo.setFinishedNoResults(); + } + } + + void displayResults(boolean newWindow) + { + // TODO: cope with multiple subjobs. + if (jobs != null) + { + Object[] res = null; + boolean msa=false; + for (int jn = 0; jn < jobs.length; jn++) + { + Object[] jobres = null; + JPredJob j = (JPredJob) jobs[jn]; + + if (j.hasResults()) + { + // hack - we only deal with all single seuqence predictions or all profile predictions + msa = (j.msa!=null) ? true : msa; + try + { + jalview.bin.Cache.log.debug("Parsing output of job " + jn); + jobres = j.getResultSet(); + jalview.bin.Cache.log.debug("Finished parsing output."); + if (jobs.length==1) + res = jobres; + else { + // do merge with other job results + throw new Error("Multiple JNet subjob merging not yet implemented."); + } + } + catch (Exception e) + { + jalview.bin.Cache.log.error( + "JNet Client: JPred Annotation Parse Error", + e); + wsInfo.setStatus(j.jobnum, WebserviceInfo.STATE_STOPPED_ERROR); + wsInfo.appendProgressText(j.jobnum, + OutputHeader + "\n" + + j.result.getStatus() + + "\nInvalid JNet job result data!\n" + + e.getMessage()); + j.result.setBroken(true); + } + } + } + + if (res != null) + { + if (newWindow) + { + AlignFrame af; + if (input==null) { + if (res[1]!=null) { + af = new AlignFrame((Alignment)res[0], (ColumnSelection) res[1], AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT); + } else { + af = new AlignFrame((Alignment)res[0], AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT); + } + } else { + /*java.lang.Object[] alandcolsel = input.getAlignmentAndColumnSelection(alignFrame.getViewport().getGapCharacter()); + + if (((SequenceI[])alandcolsel[0])[0].getLength()!=res.getWidth()) { + if (msa) { + throw new Error("Implementation Error! ColumnSelection from input alignment will not map to result alignment!"); + } + } + if (!msa) { + // update hidden regions to account for loss of gaps in profile. - if any + // gapMap returns insert list, interpreted as delete list by pruneDeletions + //((ColumnSelection) alandcolsel[1]).pruneDeletions(ShiftList.parseMap(((SequenceI[]) alandcolsel[0])[0].gapMap())); + }*/ + + af = new AlignFrame((Alignment) res[0], (ColumnSelection) res[1],AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT); + } + Desktop.addInternalFrame(af, altitle, + AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT); + } + else + { + Cache.log.info("Append results onto existing alignment."); + } + } + } + } + void pollJob(WSJob job) + throws Exception + { + job.result = server.getresult(job.jobId); + } + public boolean isCancellable() + { + return false; + } + + public void cancelJob() + { + throw new Error("Implementation error!"); + } + + public boolean canMergeResults() + { + return false; + } + +} + + diff --git a/src/jalview/ws/MsaWSThread.java b/src/jalview/ws/MsaWSThread.java index 2946ba8..e87bcf3 100644 --- a/src/jalview/ws/MsaWSThread.java +++ b/src/jalview/ws/MsaWSThread.java @@ -694,4 +694,4 @@ class MsaWSThread { return false; } -} +} \ No newline at end of file -- 1.7.10.2