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