49c4fb3da481f847c875dd3553d16089b17bec8f
[jalview.git] / src / jalview / ws / jws1 / JPredWSUtils.java
1 package jalview.ws.jws1;
2
3 import jalview.datamodel.Alignment;
4 import jalview.datamodel.AlignmentAnnotation;
5 import jalview.datamodel.AlignmentI;
6 import jalview.datamodel.AlignmentView;
7 import jalview.datamodel.ColumnSelection;
8 import jalview.datamodel.SequenceI;
9 import jalview.io.FileParse;
10 import jalview.io.FormatAdapter;
11 import jalview.util.MessageManager;
12
13 import java.io.IOException;
14 import java.util.Hashtable;
15 import java.util.List;
16
17
18 /**
19  * extraction of processing routines to allow mocking
20  * 
21  * @author jprocter
22  *
23  */
24 public class JPredWSUtils
25 {
26   /**
27    * Process data extracted from service result set to generate a JPred result
28    * view.
29    * 
30    * @param currentView
31    * 
32    * @param input
33    *          - original input alignment
34    * @param gapChar
35    *          - character to use for reconstructing alignment used for
36    *          prediction
37    * @param SequenceInfo
38    *          - from SeqHash
39    * @param msaPred
40    *          - true if a prediction based on existing MSA
41    * @param predMap
42    *          - position
43    * @param result_PredFile
44    * @param result_Aligfile
45    * @param full_alignment
46    * @return { Alignment, ColumnSelection }
47    * @throws Exception
48    */
49   public static Object[] processJnetResult(AlignmentI currentView,
50           AlignmentView input,
51           char gapChar, Hashtable SequenceInfo,
52           boolean msaPred, int[] predMap, String result_PredFile,
53           String result_Aligfile, FileParse full_alignment)
54           throws Exception
55   {
56
57     AlignmentI al = null;
58     ColumnSelection alcsel = null;
59
60     // the position of the query sequence in Alignment al
61     int FirstSeq = -1;
62
63     // the position of the original sequence in the array of
64     // Sequences in the input object that this job holds a
65     // prediction for
66     int msaIndex = 0;
67
68     // JPredFile prediction = new JPredFile("C:/JalviewX/files/jpred.txt",
69     // "File");
70     jalview.io.JPredFile prediction = new jalview.io.JPredFile(
71             result_PredFile, "Paste");
72     SequenceI[] preds = prediction.getSeqsAsArray();
73     jalview.bin.Cache.log.debug("Got prediction profile.");
74
75     if (msaPred && (result_Aligfile != null))
76     {
77       jalview.bin.Cache.log.debug("Getting associated alignment.");
78       // we ignore the returned alignment if we only predicted on a single
79       // sequence
80       String format = new jalview.io.IdentifyFile().identify(
81               result_Aligfile, "Paste");
82
83       if (jalview.io.FormatAdapter.isValidFormat(format))
84       {
85         SequenceI sqs[];
86         if (predMap != null)
87         {
88           Object[] alandcolsel = input
89                   .getAlignmentAndColumnSelection(gapChar);
90           sqs = (SequenceI[]) alandcolsel[0];
91           al = new Alignment(sqs);
92           alcsel = (ColumnSelection) alandcolsel[1];
93         }
94         else
95         {
96           al = new FormatAdapter().readFile(result_Aligfile, "Paste",
97                   format);
98           sqs = new SequenceI[al.getHeight()];
99
100           for (int i = 0, j = al.getHeight(); i < j; i++)
101           {
102             sqs[i] = al.getSequenceAt(i);
103           }
104           if (!jalview.analysis.SeqsetUtils.deuniquify(SequenceInfo, sqs))
105           {
106             throw (new Exception(
107                     MessageManager
108                             .getString("exception.couldnt_recover_sequence_properties_for_alignment")));
109           }
110         }
111         FirstSeq = 0;
112         if (currentView.getDataset() != null)
113         {
114           al.setDataset(currentView.getDataset());
115
116         }
117         else
118         {
119           al.setDataset(null);
120         }
121         jalview.io.JnetAnnotationMaker.add_annotation(prediction, al,
122                 FirstSeq, false, predMap);
123
124       }
125       else
126       {
127         throw (new Exception(MessageManager.formatMessage(
128                 "exception.unknown_format_for_file", new String[] { format,
129                     result_Aligfile })));
130       }
131     }
132     else
133     {
134       AlignmentI fullAlignment = null;
135       try
136       {
137         // read full alignment if present.
138         if (!msaPred && full_alignment != null)
139         {
140           fullAlignment = new FormatAdapter().readFromFile(full_alignment,
141                   "FASTA");
142         }
143       } catch (IOException q)
144       {
145
146       }
147       {
148         if (fullAlignment != null)
149         {
150           al = fullAlignment;
151           FirstSeq = 0;
152         }
153         else
154         {
155           al = new Alignment(preds);
156           FirstSeq = prediction.getQuerySeqPosition();
157         }
158       }
159
160       if (predMap != null)
161       {
162         // map the prediction onto the query sequence, excluding positions
163         // corresponding to hidden regions in the original input.
164         char gc = gapChar;
165         SequenceI[] sqs = (SequenceI[]) input
166                 .getAlignmentAndColumnSelection(gc)[0];
167         if (msaIndex >= sqs.length)
168         {
169           throw new Error(
170                   MessageManager
171                           .getString("error.implementation_error_invalid_msa_index_for_job"));
172         }
173         if (fullAlignment == null)
174         {
175           // //
176           // Uses RemoveGapsCommand
177           // //
178           new jalview.commands.RemoveGapsCommand(
179                   MessageManager.getString("label.remove_gaps"),
180                   new SequenceI[] { sqs[msaIndex] }, currentView);
181
182           SequenceI profileseq = al.getSequenceAt(FirstSeq);
183           profileseq.setSequence(sqs[msaIndex].getSequenceAsString());
184         }
185       }
186
187       if (!jalview.analysis.SeqsetUtils.SeqCharacterUnhash(
188               al.getSequenceAt(FirstSeq), SequenceInfo))
189       {
190         throw (new Exception(
191                 MessageManager
192                         .getString("exception.couldnt_recover_sequence_props_for_jnet_query")));
193       }
194       else
195       {
196         if (currentView.getDataset() != null)
197         {
198           al.setDataset(currentView.getDataset());
199
200         }
201         else
202         {
203           al.setDataset(null);
204         }
205         if (fullAlignment != null)
206         {
207           // map gapMap from positions in visible sequence to positions in
208           // original sequence
209           if (predMap != null)
210           {
211
212           }
213         }
214         jalview.io.JnetAnnotationMaker.add_annotation(prediction, al,
215                 FirstSeq, true, predMap);
216         SequenceI profileseq = al.getSequenceAt(0); // this includes any gaps.
217         if (fullAlignment == null)
218         {
219           alignToProfileSeq(al, profileseq);
220         }
221         if (fullAlignment == null && predMap != null)
222         {
223           // Adjust input view for gaps
224           // propagate insertions into profile
225           alcsel = ColumnSelection.propagateInsertions(profileseq, al,
226                   input);
227         }
228       }
229     }
230
231     // transfer to dataset
232     for (AlignmentAnnotation alant : al.getAlignmentAnnotation())
233     {
234       if (alant.sequenceRef != null)
235       {
236         replaceAnnotationOnAlignmentWith(alant, alant.label,
237                 "jalview.jws1.Jpred" + (msaPred ? "MSA" : ""),
238                 alant.sequenceRef);
239       }
240     }
241
242     return new Object[] { al, alcsel }; // , FirstSeq, noMsa};
243   }
244
245   /**
246    * copied from JabawsCalcWorker
247    * 
248    * @param newAnnot
249    * @param typeName
250    * @param calcId
251    * @param aSeq
252    */
253   public static void replaceAnnotationOnAlignmentWith(
254           AlignmentAnnotation newAnnot, String typeName, String calcId,
255           SequenceI aSeq)
256   {
257     SequenceI dsseq = aSeq.getDatasetSequence();
258     while (dsseq.getDatasetSequence() != null)
259     {
260       dsseq = dsseq.getDatasetSequence();
261     }
262     // look for same annotation on dataset and lift this one over
263     List<AlignmentAnnotation> dsan = dsseq.getAlignmentAnnotations(calcId,
264             typeName);
265     if (dsan != null && dsan.size() > 0)
266     {
267       for (AlignmentAnnotation dssan : dsan)
268       {
269         dsseq.removeAlignmentAnnotation(dssan);
270       }
271     }
272     AlignmentAnnotation dssan = new AlignmentAnnotation(newAnnot);
273     dsseq.addAlignmentAnnotation(dssan);
274     dssan.adjustForAlignment();
275   }
276
277   /**
278    * Given an alignment where all other sequences except profileseq are aligned
279    * to the ungapped profileseq, insert gaps in the other sequences to realign
280    * them with the residues in profileseq
281    * 
282    * @param al
283    * @param profileseq
284    */
285   public static void alignToProfileSeq(AlignmentI al, SequenceI profileseq)
286   {
287     char gc = al.getGapCharacter();
288     int[] gapMap = profileseq.gapMap();
289     insertGapsInto(al, gc, gapMap);
290   }
291
292   /**
293    * Given an original sequence, and an alignment involving just the visible
294    * region insert gaps into the alignment and add in the missing residues from
295    * the original sequence
296    * 
297    * @param al
298    * @param c
299    * @param profileseq
300    */
301   public static void insertHiddenResidues(AlignmentI al, char gc,
302           int[] predMap,
303           SequenceI origseq)
304   {
305     // orig: asdfPPPPPPPasdfPPPPasdf
306     // pred: PPPPPPPPPPP
307     // al: -----P-P-P---P---P----P---P-P--PP---P---
308     // s1: SSSSSSS-SS---S---SSSSSS---S-S--SSSSSSSSS
309     // s2: SSSSSSS-SSSSSSSSSSS----SSS-S-SSS-----SSS
310     //
311     // result:
312     //
313     // al: asdf-----P-P-P---P---P----P---Pasdf-P--PP---P---asdf
314     // s1: ....SSSSSSS-SS---S---SSSSSS---S....-S--SSSSSSSSS....
315     // s2: ....SSSSSSS-SSSSSSSSSSS----SSS-....S-SSS-----SSS....
316     String alseq = "";
317     int lsp = 0;
318     SequenceI predseq = al.getSequenceAt(0);
319     int predIdx = 0; // next column of prediction to preserve
320     // positions in original and prediction sequence
321     int lp = origseq.getStart(), predPos = predseq.getStart();
322     for (int r = 0; r < predMap.length; r++)
323     {
324       // also need to keep track of trimmed prediction sequence numbering
325       if (predMap[r] - lp > 1)
326       {
327         // hidden region insert from origseq
328         String insert = origseq.getSequenceAsString(
329                 origseq.findIndex(lp) - 1,
330                 origseq.findIndex(predMap[r]) - 1);
331
332         insertGapsAt(al, gc, alseq.length(), insert.length());
333         alseq += insert;
334       }
335       // Now update prediction sequence for next position.
336       {
337         int predIdxNext = predseq.findIndex(predPos + 1) - 1;
338         if (predIdxNext <= predIdx)
339         {
340           predIdxNext = predseq.getLength();
341         }
342         // just add in next segment of predseq
343         String predsert = predseq.getSequenceAsString(predIdx, predIdxNext);
344         alseq += predsert;
345         predIdx = predIdxNext;
346       }
347       lp = predMap[r];
348       predPos++;
349     }
350     // append final bits
351     if (lp < origseq.getEnd())
352     {
353       String insert = origseq.getSequenceAsString(
354               origseq.findIndex(lp) - 1, origseq.getLength());
355       insertGapsAt(al, gc, alseq.length(), insert.length());
356       alseq += insert;
357     }
358     // then add in origseq data.
359     predseq.setSequence(alseq);
360   }
361
362   public static void insertGapsInto(AlignmentI al, char gc, int[] gapMap)
363   {
364     // insert gaps into profile
365     for (int lp = 0, r = 0; r < gapMap.length; r++)
366     {
367       if (gapMap[r] - lp > 1)
368       {
369         insertGapsAt(al, gc, gapMap[r], gapMap[r]-lp);
370       }
371       lp = gapMap[r];
372     }
373   }
374
375   private static void insertGapsAt(AlignmentI al, char gc, int i, int lp)
376   {
377
378     StringBuffer sb = new StringBuffer();
379     for (int s = 0, ns = lp; s < ns; s++)
380     {
381       sb.append(gc);
382     }
383     for (int s = 1, ns = al.getHeight(); s < ns; s++)
384     {
385       String sq = al.getSequenceAt(s).getSequenceAsString();
386       int diff = i - sq.length();
387       if (diff > 0)
388       {
389         // pad gaps
390         sq = sq + sb;
391         while ((diff = i - sq.length()) > 0)
392         {
393           sq = sq
394                   + ((diff >= sb.length()) ? sb.toString() : sb.substring(
395                           0, diff));
396         }
397         al.getSequenceAt(s).setSequence(sq);
398       }
399       else
400       {
401         al.getSequenceAt(s).setSequence(
402                 sq.substring(0, i) + sb.toString() + sq.substring(i));
403       }
404     }
405   }
406
407 }