merge from 2_4_Release branch
[jalview.git] / src / jalview / analysis / AlignSeq.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer (Version 2.4)
3  * Copyright (C) 2008 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle
4  * 
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  * 
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  * 
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
18  */
19 package jalview.analysis;
20
21 import java.util.*;
22
23 import java.awt.*;
24
25 import jalview.datamodel.*;
26 import jalview.schemes.*;
27 import jalview.util.*;
28
29 /**
30  * 
31  * 
32  * @author $author$
33  * @version $Revision$
34  */
35 public class AlignSeq
36 {
37   public static final String PEP = "pep";
38
39   public static final String DNA = "dna";
40
41   static String[] dna =
42   { "A", "C", "G", "T", "-" };
43
44   // "C", "T", "A", "G", "-"};
45   static String[] pep =
46   { "A", "R", "N", "D", "C", "Q", "E", "G", "H", "I", "L", "K", "M", "F",
47       "P", "S", "T", "W", "Y", "V", "B", "Z", "X", "-" };
48
49   int[][] score;
50
51   int[][] E;
52
53   int[][] F;
54
55   int[][] traceback;
56
57   int[] seq1;
58
59   int[] seq2;
60
61   SequenceI s1;
62
63   SequenceI s2;
64
65   public String s1str;
66
67   public String s2str;
68
69   int maxi;
70
71   int maxj;
72
73   int[] aseq1;
74
75   int[] aseq2;
76
77   public String astr1 = "";
78
79   public String astr2 = "";
80
81   /** DOCUMENT ME!! */
82   public int seq1start;
83
84   /** DOCUMENT ME!! */
85   public int seq1end;
86
87   /** DOCUMENT ME!! */
88   public int seq2start;
89
90   /** DOCUMENT ME!! */
91   public int seq2end;
92
93   int count;
94
95   /** DOCUMENT ME!! */
96   public int maxscore;
97
98   float pid;
99
100   int prev = 0;
101
102   int gapOpen = 120;
103
104   int gapExtend = 20;
105
106   int[][] lookup = ResidueProperties.getBLOSUM62();
107
108   String[] intToStr = pep;
109
110   int defInt = 23;
111
112   StringBuffer output = new StringBuffer();
113
114   String type;
115
116   /**
117    * Creates a new AlignSeq object.
118    * 
119    * @param s1
120    *                DOCUMENT ME!
121    * @param s2
122    *                DOCUMENT ME!
123    * @param type
124    *                DOCUMENT ME!
125    */
126   public AlignSeq(SequenceI s1, SequenceI s2, String type)
127   {
128     SeqInit(s1, s1.getSequenceAsString(), s2, s2.getSequenceAsString(),
129             type);
130   }
131
132   /**
133    * Creates a new AlignSeq object.
134    * 
135    * @param s1
136    *                DOCUMENT ME!
137    * @param s2
138    *                DOCUMENT ME!
139    * @param type
140    *                DOCUMENT ME!
141    */
142   public AlignSeq(SequenceI s1, String string1, SequenceI s2,
143           String string2, String type)
144   {
145     SeqInit(s1, string1, s2, string2, type);
146   }
147
148   /**
149    * DOCUMENT ME!
150    * 
151    * @return DOCUMENT ME!
152    */
153   public int getMaxScore()
154   {
155     return maxscore;
156   }
157
158   /**
159    * DOCUMENT ME!
160    * 
161    * @return DOCUMENT ME!
162    */
163   public int getSeq2Start()
164   {
165     return seq2start;
166   }
167
168   /**
169    * DOCUMENT ME!
170    * 
171    * @return DOCUMENT ME!
172    */
173   public int getSeq2End()
174   {
175     return seq2end;
176   }
177
178   /**
179    * DOCUMENT ME!
180    * 
181    * @return DOCUMENT ME!
182    */
183   public int getSeq1Start()
184   {
185     return seq1start;
186   }
187
188   /**
189    * DOCUMENT ME!
190    * 
191    * @return DOCUMENT ME!
192    */
193   public int getSeq1End()
194   {
195     return seq1end;
196   }
197
198   /**
199    * DOCUMENT ME!
200    * 
201    * @return DOCUMENT ME!
202    */
203   public String getOutput()
204   {
205     return output.toString();
206   }
207
208   /**
209    * DOCUMENT ME!
210    * 
211    * @return DOCUMENT ME!
212    */
213   public String getAStr1()
214   {
215     return astr1;
216   }
217
218   /**
219    * DOCUMENT ME!
220    * 
221    * @return DOCUMENT ME!
222    */
223   public String getAStr2()
224   {
225     return astr2;
226   }
227
228   /**
229    * DOCUMENT ME!
230    * 
231    * @return DOCUMENT ME!
232    */
233   public int[] getASeq1()
234   {
235     return aseq1;
236   }
237
238   /**
239    * DOCUMENT ME!
240    * 
241    * @return DOCUMENT ME!
242    */
243   public int[] getASeq2()
244   {
245     return aseq2;
246   }
247
248   /**
249    * DOCUMENT ME!
250    * 
251    * @return DOCUMENT ME!
252    */
253   public SequenceI getS1()
254   {
255     return s1;
256   }
257
258   /**
259    * DOCUMENT ME!
260    * 
261    * @return DOCUMENT ME!
262    */
263   public SequenceI getS2()
264   {
265     return s2;
266   }
267
268   /**
269    * DOCUMENT ME!
270    * 
271    * @param s1
272    *                DOCUMENT ME!
273    * @param string1 -
274    *                string to align for sequence1
275    * @param s2
276    *                sequence 2
277    * @param string2 -
278    *                string to align for sequence2
279    * @param type
280    *                DNA or PEPTIDE
281    */
282   public void SeqInit(SequenceI s1, String string1, SequenceI s2,
283           String string2, String type)
284   {
285     this.s1 = s1;
286     this.s2 = s2;
287     setDefaultParams(type);
288     SeqInit(string1, string2);
289   }
290
291   public void SeqInit(SequenceI s1, String string1, SequenceI s2,
292           String string2, ScoreMatrix scoreMatrix)
293   {
294     this.s1 = s1;
295     this.s2 = s2;
296     setType(scoreMatrix.isDNA() ? AlignSeq.DNA : AlignSeq.PEP);
297     lookup = scoreMatrix.getMatrix();
298   }
299
300   /**
301    * construct score matrix for string1 and string2 (after removing any existing
302    * gaps
303    * 
304    * @param string1
305    * @param string2
306    */
307   private void SeqInit(String string1, String string2)
308   {
309     s1str = extractGaps(jalview.util.Comparison.GapChars, string1);
310     s2str = extractGaps(jalview.util.Comparison.GapChars, string2);
311
312     if (s1str.length() == 0 || s2str.length() == 0)
313     {
314       output.append("ALL GAPS: "
315               + (s1str.length() == 0 ? s1.getName() : " ")
316               + (s2str.length() == 0 ? s2.getName() : ""));
317       return;
318     }
319
320     // System.out.println("lookuip " + rt.freeMemory() + " "+ rt.totalMemory());
321     seq1 = new int[s1str.length()];
322
323     // System.out.println("seq1 " + rt.freeMemory() +" " + rt.totalMemory());
324     seq2 = new int[s2str.length()];
325
326     // System.out.println("seq2 " + rt.freeMemory() + " " + rt.totalMemory());
327     score = new int[s1str.length()][s2str.length()];
328
329     // System.out.println("score " + rt.freeMemory() + " " + rt.totalMemory());
330     E = new int[s1str.length()][s2str.length()];
331
332     // System.out.println("E " + rt.freeMemory() + " " + rt.totalMemory());
333     F = new int[s1str.length()][s2str.length()];
334     traceback = new int[s1str.length()][s2str.length()];
335
336     // System.out.println("F " + rt.freeMemory() + " " + rt.totalMemory());
337     seq1 = stringToInt(s1str, type);
338
339     // System.out.println("seq1 " + rt.freeMemory() + " " + rt.totalMemory());
340     seq2 = stringToInt(s2str, type);
341
342     // System.out.println("Seq2 " + rt.freeMemory() + " " + rt.totalMemory());
343     // long tstart = System.currentTimeMillis();
344     // calcScoreMatrix();
345     // long tend = System.currentTimeMillis();
346     // System.out.println("Time take to calculate score matrix = " +
347     // (tend-tstart) + " ms");
348     // printScoreMatrix(score);
349     // System.out.println();
350     // printScoreMatrix(traceback);
351     // System.out.println();
352     // printScoreMatrix(E);
353     // System.out.println();
354     // /printScoreMatrix(F);
355     // System.out.println();
356     // tstart = System.currentTimeMillis();
357     // traceAlignment();
358     // tend = System.currentTimeMillis();
359     // System.out.println("Time take to traceback alignment = " + (tend-tstart)
360     // + " ms");
361   }
362
363   private void setDefaultParams(String type)
364   {
365     setType(type);
366
367     if (type.equals(AlignSeq.PEP))
368     {
369       lookup = ResidueProperties.getDefaultPeptideMatrix();
370     }
371     else if (type.equals(AlignSeq.DNA))
372     {
373       lookup = ResidueProperties.getDefaultDnaMatrix();
374     }
375   }
376
377   private void setType(String type2)
378   {
379     this.type = type2;
380     if (type.equals(AlignSeq.PEP))
381     {
382       intToStr = pep;
383       defInt = 23;
384     }
385     else if (type.equals(AlignSeq.DNA))
386     {
387       intToStr = dna;
388       defInt = 4;
389     }
390     else
391     {
392       output.append("Wrong type = dna or pep only");
393       throw new Error("Unknown Type " + type2
394               + " - dna or pep are the only allowed values.");
395     }
396   }
397
398   /**
399    * DOCUMENT ME!
400    */
401   public void traceAlignment()
402   {
403     // Find the maximum score along the rhs or bottom row
404     int max = -9999;
405
406     for (int i = 0; i < seq1.length; i++)
407     {
408       if (score[i][seq2.length - 1] > max)
409       {
410         max = score[i][seq2.length - 1];
411         maxi = i;
412         maxj = seq2.length - 1;
413       }
414     }
415
416     for (int j = 0; j < seq2.length; j++)
417     {
418       if (score[seq1.length - 1][j] > max)
419       {
420         max = score[seq1.length - 1][j];
421         maxi = seq1.length - 1;
422         maxj = j;
423       }
424     }
425
426     // System.out.println(maxi + " " + maxj + " " + score[maxi][maxj]);
427     int i = maxi;
428     int j = maxj;
429     int trace;
430     maxscore = score[i][j] / 10;
431
432     seq1end = maxi + 1;
433     seq2end = maxj + 1;
434
435     aseq1 = new int[seq1.length + seq2.length];
436     aseq2 = new int[seq1.length + seq2.length];
437
438     count = (seq1.length + seq2.length) - 1;
439
440     while ((i > 0) && (j > 0))
441     {
442       if ((aseq1[count] != defInt) && (i >= 0))
443       {
444         aseq1[count] = seq1[i];
445         astr1 = s1str.charAt(i) + astr1;
446       }
447
448       if ((aseq2[count] != defInt) && (j > 0))
449       {
450         aseq2[count] = seq2[j];
451         astr2 = s2str.charAt(j) + astr2;
452       }
453
454       trace = findTrace(i, j);
455
456       if (trace == 0)
457       {
458         i--;
459         j--;
460       }
461       else if (trace == 1)
462       {
463         j--;
464         aseq1[count] = defInt;
465         astr1 = "-" + astr1.substring(1);
466       }
467       else if (trace == -1)
468       {
469         i--;
470         aseq2[count] = defInt;
471         astr2 = "-" + astr2.substring(1);
472       }
473
474       count--;
475     }
476
477     seq1start = i + 1;
478     seq2start = j + 1;
479
480     if (aseq1[count] != defInt)
481     {
482       aseq1[count] = seq1[i];
483       astr1 = s1str.charAt(i) + astr1;
484     }
485
486     if (aseq2[count] != defInt)
487     {
488       aseq2[count] = seq2[j];
489       astr2 = s2str.charAt(j) + astr2;
490     }
491   }
492
493   /**
494    * DOCUMENT ME!
495    */
496   public void printAlignment(java.io.PrintStream os)
497   {
498     // TODO: Use original sequence characters rather than re-translated
499     // characters in output
500     // Find the biggest id length for formatting purposes
501     int maxid = s1.getName().length();
502     if (s2.getName().length() > maxid)
503     {
504       maxid = s2.getName().length();
505     }
506
507     int len = 72 - maxid - 1;
508     int nochunks = ((aseq1.length - count) / len) + 1;
509     pid = 0;
510
511     output.append("Score = " + score[maxi][maxj] + "\n");
512     output.append("Length of alignment = " + (aseq1.length - count) + "\n");
513     output.append("Sequence ");
514     output.append(new Format("%" + maxid + "s").form(s1.getName()));
515     output.append(" :  " + s1.getStart() + " - " + s1.getEnd()
516             + " (Sequence length = " + s1str.length() + ")\n");
517     output.append("Sequence ");
518     output.append(new Format("%" + maxid + "s").form(s2.getName()));
519     output.append(" :  " + s2.getStart() + " - " + s2.getEnd()
520             + " (Sequence length = " + s2str.length() + ")\n\n");
521
522     for (int j = 0; j < nochunks; j++)
523     {
524       // Print the first aligned sequence
525       output.append(new Format("%" + (maxid) + "s").form(s1.getName())
526               + " ");
527
528       for (int i = 0; i < len; i++)
529       {
530         if ((i + (j * len)) < astr1.length())
531         {
532           output.append(astr1.charAt(i + (j * len)));
533         }
534       }
535
536       output.append("\n");
537       output.append(new Format("%" + (maxid) + "s").form(" ") + " ");
538
539       // Print out the matching chars
540       for (int i = 0; i < len; i++)
541       {
542         if ((i + (j * len)) < astr1.length())
543         {
544           if (astr1.charAt(i + (j * len)) == astr2.charAt(i + (j * len))
545                   && !jalview.util.Comparison.isGap(astr1.charAt(i
546                           + (j * len))))
547           {
548             pid++;
549             output.append("|");
550           }
551           else if (type.equals("pep"))
552           {
553             if (ResidueProperties.getPAM250(astr1.charAt(i + (j * len)),
554                     astr2.charAt(i + (j * len))) > 0)
555             {
556               output.append(".");
557             }
558             else
559             {
560               output.append(" ");
561             }
562           }
563           else
564           {
565             output.append(" ");
566           }
567         }
568       }
569
570       // Now print the second aligned sequence
571       output = output.append("\n");
572       output = output.append(new Format("%" + (maxid) + "s").form(s2
573               .getName())
574               + " ");
575
576       for (int i = 0; i < len; i++)
577       {
578         if ((i + (j * len)) < astr2.length())
579         {
580           output.append(astr2.charAt(i + (j * len)));
581         }
582       }
583
584       output = output.append("\n\n");
585     }
586
587     pid = pid / (float) (aseq1.length - count) * 100;
588     output = output.append(new Format("Percentage ID = %2.2f\n\n")
589             .form(pid));
590
591     try
592     {
593       os.print(output.toString());
594     } catch (Exception ex)
595     {
596     }
597   }
598
599   /**
600    * DOCUMENT ME!
601    * 
602    * @param mat
603    *                DOCUMENT ME!
604    */
605   public void printScoreMatrix(int[][] mat)
606   {
607     int n = seq1.length;
608     int m = seq2.length;
609
610     for (int i = 0; i < n; i++)
611     {
612       // Print the top sequence
613       if (i == 0)
614       {
615         Format.print(System.out, "%8s", s2str.substring(0, 1));
616
617         for (int jj = 1; jj < m; jj++)
618         {
619           Format.print(System.out, "%5s", s2str.substring(jj, jj + 1));
620         }
621
622         System.out.println();
623       }
624
625       for (int j = 0; j < m; j++)
626       {
627         if (j == 0)
628         {
629           Format.print(System.out, "%3s", s1str.substring(i, i + 1));
630         }
631
632         Format.print(System.out, "%3d ", mat[i][j] / 10);
633       }
634
635       System.out.println();
636     }
637   }
638
639   /**
640    * DOCUMENT ME!
641    * 
642    * @param i
643    *                DOCUMENT ME!
644    * @param j
645    *                DOCUMENT ME!
646    * 
647    * @return DOCUMENT ME!
648    */
649   public int findTrace(int i, int j)
650   {
651     int t = 0;
652     int max = score[i - 1][j - 1] + (lookup[seq1[i]][seq2[j]] * 10);
653
654     if (F[i][j] > max)
655     {
656       max = F[i][j];
657       t = -1;
658     }
659     else if (F[i][j] == max)
660     {
661       if (prev == -1)
662       {
663         max = F[i][j];
664         t = -1;
665       }
666     }
667
668     if (E[i][j] >= max)
669     {
670       max = E[i][j];
671       t = 1;
672     }
673     else if (E[i][j] == max)
674     {
675       if (prev == 1)
676       {
677         max = E[i][j];
678         t = 1;
679       }
680     }
681
682     prev = t;
683
684     return t;
685   }
686
687   /**
688    * DOCUMENT ME!
689    */
690   public void calcScoreMatrix()
691   {
692     int n = seq1.length;
693     int m = seq2.length;
694
695     // top left hand element
696     score[0][0] = lookup[seq1[0]][seq2[0]] * 10;
697     E[0][0] = -gapExtend;
698     F[0][0] = 0;
699
700     // Calculate the top row first
701     for (int j = 1; j < m; j++)
702     {
703       // What should these values be? 0 maybe
704       E[0][j] = max(score[0][j - 1] - gapOpen, E[0][j - 1] - gapExtend);
705       F[0][j] = -gapExtend;
706
707       score[0][j] = max(lookup[seq1[0]][seq2[j]] * 10, -gapOpen, -gapExtend);
708
709       traceback[0][j] = 1;
710     }
711
712     // Now do the left hand column
713     for (int i = 1; i < n; i++)
714     {
715       E[i][0] = -gapOpen;
716       F[i][0] = max(score[i - 1][0] - gapOpen, F[i - 1][0] - gapExtend);
717
718       score[i][0] = max(lookup[seq1[i]][seq2[0]] * 10, E[i][0], F[i][0]);
719       traceback[i][0] = -1;
720     }
721
722     // Now do all the other rows
723     for (int i = 1; i < n; i++)
724     {
725       for (int j = 1; j < m; j++)
726       {
727         E[i][j] = max(score[i][j - 1] - gapOpen, E[i][j - 1] - gapExtend);
728         F[i][j] = max(score[i - 1][j] - gapOpen, F[i - 1][j] - gapExtend);
729
730         score[i][j] = max(score[i - 1][j - 1]
731                 + (lookup[seq1[i]][seq2[j]] * 10), E[i][j], F[i][j]);
732         traceback[i][j] = findTrace(i, j);
733       }
734     }
735   }
736
737   /**
738    * DOCUMENT ME!
739    * 
740    * @param gapChar
741    *                DOCUMENT ME!
742    * @param seq
743    *                DOCUMENT ME!
744    * 
745    * @return DOCUMENT ME!
746    */
747   public static String extractGaps(String gapChar, String seq)
748   {
749     StringTokenizer str = new StringTokenizer(seq, gapChar);
750     StringBuffer newString = new StringBuffer();
751
752     while (str.hasMoreTokens())
753     {
754       newString.append(str.nextToken());
755     }
756
757     return newString.toString();
758   }
759
760   /**
761    * DOCUMENT ME!
762    * 
763    * @param i1
764    *                DOCUMENT ME!
765    * @param i2
766    *                DOCUMENT ME!
767    * @param i3
768    *                DOCUMENT ME!
769    * 
770    * @return DOCUMENT ME!
771    */
772   public int max(int i1, int i2, int i3)
773   {
774     int max = i1;
775
776     if (i2 > i1)
777     {
778       max = i2;
779     }
780
781     if (i3 > max)
782     {
783       max = i3;
784     }
785
786     return max;
787   }
788
789   /**
790    * DOCUMENT ME!
791    * 
792    * @param i1
793    *                DOCUMENT ME!
794    * @param i2
795    *                DOCUMENT ME!
796    * 
797    * @return DOCUMENT ME!
798    */
799   public int max(int i1, int i2)
800   {
801     int max = i1;
802
803     if (i2 > i1)
804     {
805       max = i2;
806     }
807
808     return max;
809   }
810
811   /**
812    * DOCUMENT ME!
813    * 
814    * @param s
815    *                DOCUMENT ME!
816    * @param type
817    *                DOCUMENT ME!
818    * 
819    * @return DOCUMENT ME!
820    */
821   public int[] stringToInt(String s, String type)
822   {
823     int[] seq1 = new int[s.length()];
824
825     for (int i = 0; i < s.length(); i++)
826     {
827       // String ss = s.substring(i, i + 1).toUpperCase();
828       char c = s.charAt(i);
829       if ('a' <= c && c <= 'z')
830       {
831         // TO UPPERCASE !!!
832         c -= ('a' - 'A');
833       }
834
835       try
836       {
837         if (type.equals("pep"))
838         {
839           seq1[i] = ResidueProperties.aaIndex[c];
840           if (seq1[i] > 23)
841           {
842             seq1[i] = 23;
843           }
844         }
845         else if (type.equals("dna"))
846         {
847           seq1[i] = ResidueProperties.nucleotideIndex[c];
848           if (seq1[i] > 4)
849           {
850             seq1[i] = 4;
851           }
852         }
853
854       } catch (Exception e)
855       {
856         if (type.equals("dna"))
857         {
858           seq1[i] = 4;
859         }
860         else
861         {
862           seq1[i] = 23;
863         }
864       }
865     }
866
867     return seq1;
868   }
869
870   /**
871    * DOCUMENT ME!
872    * 
873    * @param g
874    *                DOCUMENT ME!
875    * @param mat
876    *                DOCUMENT ME!
877    * @param n
878    *                DOCUMENT ME!
879    * @param m
880    *                DOCUMENT ME!
881    * @param psize
882    *                DOCUMENT ME!
883    */
884   public static void displayMatrix(Graphics g, int[][] mat, int n, int m,
885           int psize)
886   {
887     int max = -1000;
888     int min = 1000;
889
890     for (int i = 0; i < n; i++)
891     {
892       for (int j = 0; j < m; j++)
893       {
894         if (mat[i][j] >= max)
895         {
896           max = mat[i][j];
897         }
898
899         if (mat[i][j] <= min)
900         {
901           min = mat[i][j];
902         }
903       }
904     }
905
906     System.out.println(max + " " + min);
907
908     for (int i = 0; i < n; i++)
909     {
910       for (int j = 0; j < m; j++)
911       {
912         int x = psize * i;
913         int y = psize * j;
914
915         // System.out.println(mat[i][j]);
916         float score = (float) (mat[i][j] - min) / (float) (max - min);
917         g.setColor(new Color(score, 0, 0));
918         g.fillRect(x, y, psize, psize);
919
920         // System.out.println(x + " " + y + " " + score);
921       }
922     }
923   }
924 }