JAL-1645 Version-Rel Version 2.9 Year-Rel 2015 Licensing glob
[jalview.git] / src / jalview / analysis / AlignSeq.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer (Version 2.9)
3  * Copyright (C) 2015 The Jalview Authors
4  * 
5  * This file is part of Jalview.
6  * 
7  * Jalview is free software: you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License 
9  * as published by the Free Software Foundation, either version 3
10  * of the License, or (at your option) any later version.
11  *  
12  * Jalview is distributed in the hope that it will be useful, but 
13  * WITHOUT ANY WARRANTY; without even the implied warranty 
14  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
15  * PURPOSE.  See the GNU General Public License for more details.
16  * 
17  * You should have received a copy of the GNU General Public License
18  * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
19  * The Jalview Authors are detailed in the 'AUTHORS' file.
20  */
21 package jalview.analysis;
22
23 import jalview.datamodel.AlignmentAnnotation;
24 import jalview.datamodel.AlignmentI;
25 import jalview.datamodel.Mapping;
26 import jalview.datamodel.Sequence;
27 import jalview.datamodel.SequenceI;
28 import jalview.schemes.ResidueProperties;
29 import jalview.schemes.ScoreMatrix;
30 import jalview.util.Comparison;
31 import jalview.util.Format;
32 import jalview.util.MapList;
33 import jalview.util.MessageManager;
34
35 import java.awt.Color;
36 import java.awt.Graphics;
37 import java.util.ArrayList;
38 import java.util.Arrays;
39 import java.util.List;
40 import java.util.StringTokenizer;
41
42 /**
43  * 
44  * 
45  * @author $author$
46  * @version $Revision$
47  */
48 public class AlignSeq
49 {
50   public static final String PEP = "pep";
51
52   public static final String DNA = "dna";
53
54   private static final String NEWLINE = System.lineSeparator();
55
56   static String[] dna = { "A", "C", "G", "T", "-" };
57
58   // "C", "T", "A", "G", "-"};
59   static String[] pep = { "A", "R", "N", "D", "C", "Q", "E", "G", "H", "I",
60       "L", "K", "M", "F", "P", "S", "T", "W", "Y", "V", "B", "Z", "X", "-" };
61
62   int[][] score;
63
64   int[][] E;
65
66   int[][] F;
67
68   int[][] traceback;
69
70   int[] seq1;
71
72   int[] seq2;
73
74   SequenceI s1;
75
76   SequenceI s2;
77
78   public String s1str;
79
80   public String s2str;
81
82   int maxi;
83
84   int maxj;
85
86   int[] aseq1;
87
88   int[] aseq2;
89
90   public String astr1 = "";
91
92   public String astr2 = "";
93
94   /** DOCUMENT ME!! */
95   public int seq1start;
96
97   /** DOCUMENT ME!! */
98   public int seq1end;
99
100   /** DOCUMENT ME!! */
101   public int seq2start;
102
103   /** DOCUMENT ME!! */
104   public int seq2end;
105
106   int count;
107
108   /** DOCUMENT ME!! */
109   public int maxscore;
110
111   float pid;
112
113   int prev = 0;
114
115   int gapOpen = 120;
116
117   int gapExtend = 20;
118
119   int[][] lookup = ResidueProperties.getBLOSUM62();
120
121   String[] intToStr = pep;
122
123   int defInt = 23;
124
125   StringBuffer output = new StringBuffer();
126
127   String type;
128
129   private int[] charToInt;
130
131   /**
132    * Creates a new AlignSeq object.
133    * 
134    * @param s1
135    *          DOCUMENT ME!
136    * @param s2
137    *          DOCUMENT ME!
138    * @param type
139    *          DOCUMENT ME!
140    */
141   public AlignSeq(SequenceI s1, SequenceI s2, String type)
142   {
143     SeqInit(s1, s1.getSequenceAsString(), s2, s2.getSequenceAsString(),
144             type);
145   }
146
147   /**
148    * Creates a new AlignSeq object.
149    * 
150    * @param s1
151    *          DOCUMENT ME!
152    * @param s2
153    *          DOCUMENT ME!
154    * @param type
155    *          DOCUMENT ME!
156    */
157   public AlignSeq(SequenceI s1, String string1, SequenceI s2,
158           String string2, String type)
159   {
160     SeqInit(s1, string1.toUpperCase(), s2, string2.toUpperCase(), type);
161   }
162
163   /**
164    * DOCUMENT ME!
165    * 
166    * @return DOCUMENT ME!
167    */
168   public int getMaxScore()
169   {
170     return maxscore;
171   }
172
173   /**
174    * DOCUMENT ME!
175    * 
176    * @return DOCUMENT ME!
177    */
178   public int getSeq2Start()
179   {
180     return seq2start;
181   }
182
183   /**
184    * DOCUMENT ME!
185    * 
186    * @return DOCUMENT ME!
187    */
188   public int getSeq2End()
189   {
190     return seq2end;
191   }
192
193   /**
194    * DOCUMENT ME!
195    * 
196    * @return DOCUMENT ME!
197    */
198   public int getSeq1Start()
199   {
200     return seq1start;
201   }
202
203   /**
204    * DOCUMENT ME!
205    * 
206    * @return DOCUMENT ME!
207    */
208   public int getSeq1End()
209   {
210     return seq1end;
211   }
212
213   /**
214    * DOCUMENT ME!
215    * 
216    * @return DOCUMENT ME!
217    */
218   public String getOutput()
219   {
220     return output.toString();
221   }
222
223   /**
224    * DOCUMENT ME!
225    * 
226    * @return DOCUMENT ME!
227    */
228   public String getAStr1()
229   {
230     return astr1;
231   }
232
233   /**
234    * DOCUMENT ME!
235    * 
236    * @return DOCUMENT ME!
237    */
238   public String getAStr2()
239   {
240     return astr2;
241   }
242
243   /**
244    * DOCUMENT ME!
245    * 
246    * @return DOCUMENT ME!
247    */
248   public int[] getASeq1()
249   {
250     return aseq1;
251   }
252
253   /**
254    * DOCUMENT ME!
255    * 
256    * @return DOCUMENT ME!
257    */
258   public int[] getASeq2()
259   {
260     return aseq2;
261   }
262
263   /**
264    * DOCUMENT ME!
265    * 
266    * @return DOCUMENT ME!
267    */
268   public SequenceI getS1()
269   {
270     return s1;
271   }
272
273   /**
274    * DOCUMENT ME!
275    * 
276    * @return DOCUMENT ME!
277    */
278   public SequenceI getS2()
279   {
280     return s2;
281   }
282
283   /**
284    * 
285    * @return aligned instance of Seq 1
286    */
287   public SequenceI getAlignedSeq1()
288   {
289     SequenceI alSeq1 = new Sequence(s1.getName(), getAStr1());
290     alSeq1.setStart(s1.getStart() + getSeq1Start() - 1);
291     alSeq1.setEnd(s1.getStart() + getSeq1End() - 1);
292     alSeq1.setDatasetSequence(s1.getDatasetSequence() == null ? s1 : s1
293             .getDatasetSequence());
294     return alSeq1;
295   }
296
297   /**
298    * 
299    * @return aligned instance of Seq 2
300    */
301   public SequenceI getAlignedSeq2()
302   {
303     SequenceI alSeq2 = new Sequence(s2.getName(), getAStr2());
304     alSeq2.setStart(s2.getStart() + getSeq2Start() - 1);
305     alSeq2.setEnd(s2.getStart() + getSeq2End() - 1);
306     alSeq2.setDatasetSequence(s2.getDatasetSequence() == null ? s2 : s2
307             .getDatasetSequence());
308     return alSeq2;
309   }
310
311   /**
312    * Construct score matrix for sequences with standard DNA or PEPTIDE matrix
313    * 
314    * @param s1
315    *          - sequence 1
316    * @param string1
317    *          - string to use for s1
318    * @param s2
319    *          - sequence 2
320    * @param string2
321    *          - string to use for s2
322    * @param type
323    *          DNA or PEPTIDE
324    */
325   public void SeqInit(SequenceI s1, String string1, SequenceI s2,
326           String string2, String type)
327   {
328     this.s1 = s1;
329     this.s2 = s2;
330     setDefaultParams(type);
331     SeqInit(string1, string2);
332   }
333
334   /**
335    * Construct score matrix for sequences with custom substitution matrix
336    * 
337    * @param s1
338    *          - sequence 1
339    * @param string1
340    *          - string to use for s1
341    * @param s2
342    *          - sequence 2
343    * @param string2
344    *          - string to use for s2
345    * @param scoreMatrix
346    *          - substitution matrix to use for alignment
347    */
348   public void SeqInit(SequenceI s1, String string1, SequenceI s2,
349           String string2, ScoreMatrix scoreMatrix)
350   {
351     this.s1 = s1;
352     this.s2 = s2;
353     setType(scoreMatrix.isDNA() ? AlignSeq.DNA : AlignSeq.PEP);
354     lookup = scoreMatrix.getMatrix();
355   }
356
357   /**
358    * construct score matrix for string1 and string2 (after removing any existing
359    * gaps
360    * 
361    * @param string1
362    * @param string2
363    */
364   private void SeqInit(String string1, String string2)
365   {
366     s1str = extractGaps(jalview.util.Comparison.GapChars, string1);
367     s2str = extractGaps(jalview.util.Comparison.GapChars, string2);
368
369     if (s1str.length() == 0 || s2str.length() == 0)
370     {
371       output.append("ALL GAPS: "
372               + (s1str.length() == 0 ? s1.getName() : " ")
373               + (s2str.length() == 0 ? s2.getName() : ""));
374       return;
375     }
376
377     // System.out.println("lookuip " + rt.freeMemory() + " "+ rt.totalMemory());
378     seq1 = new int[s1str.length()];
379
380     // System.out.println("seq1 " + rt.freeMemory() +" " + rt.totalMemory());
381     seq2 = new int[s2str.length()];
382
383     // System.out.println("seq2 " + rt.freeMemory() + " " + rt.totalMemory());
384     score = new int[s1str.length()][s2str.length()];
385
386     // System.out.println("score " + rt.freeMemory() + " " + rt.totalMemory());
387     E = new int[s1str.length()][s2str.length()];
388
389     // System.out.println("E " + rt.freeMemory() + " " + rt.totalMemory());
390     F = new int[s1str.length()][s2str.length()];
391     traceback = new int[s1str.length()][s2str.length()];
392
393     // System.out.println("F " + rt.freeMemory() + " " + rt.totalMemory());
394     seq1 = stringToInt(s1str, type);
395
396     // System.out.println("seq1 " + rt.freeMemory() + " " + rt.totalMemory());
397     seq2 = stringToInt(s2str, type);
398
399     // System.out.println("Seq2 " + rt.freeMemory() + " " + rt.totalMemory());
400     // long tstart = System.currentTimeMillis();
401     // calcScoreMatrix();
402     // long tend = System.currentTimeMillis();
403     // System.out.println("Time take to calculate score matrix = " +
404     // (tend-tstart) + " ms");
405     // printScoreMatrix(score);
406     // System.out.println();
407     // printScoreMatrix(traceback);
408     // System.out.println();
409     // printScoreMatrix(E);
410     // System.out.println();
411     // /printScoreMatrix(F);
412     // System.out.println();
413     // tstart = System.currentTimeMillis();
414     // traceAlignment();
415     // tend = System.currentTimeMillis();
416     // System.out.println("Time take to traceback alignment = " + (tend-tstart)
417     // + " ms");
418   }
419
420   private void setDefaultParams(String type)
421   {
422     setType(type);
423
424     if (type.equals(AlignSeq.PEP))
425     {
426       lookup = ResidueProperties.getDefaultPeptideMatrix();
427     }
428     else if (type.equals(AlignSeq.DNA))
429     {
430       lookup = ResidueProperties.getDefaultDnaMatrix();
431     }
432   }
433
434   private void setType(String type2)
435   {
436     this.type = type2;
437     if (type.equals(AlignSeq.PEP))
438     {
439       intToStr = pep;
440       charToInt = ResidueProperties.aaIndex;
441       defInt = ResidueProperties.maxProteinIndex;
442     }
443     else if (type.equals(AlignSeq.DNA))
444     {
445       intToStr = dna;
446       charToInt = ResidueProperties.nucleotideIndex;
447       defInt = ResidueProperties.maxNucleotideIndex;
448     }
449     else
450     {
451       output.append("Wrong type = dna or pep only");
452       throw new Error(MessageManager.formatMessage(
453               "error.unknown_type_dna_or_pep", new String[] { type2 }));
454     }
455   }
456
457   /**
458    * DOCUMENT ME!
459    */
460   public void traceAlignment()
461   {
462     // Find the maximum score along the rhs or bottom row
463     int max = -9999;
464
465     for (int i = 0; i < seq1.length; i++)
466     {
467       if (score[i][seq2.length - 1] > max)
468       {
469         max = score[i][seq2.length - 1];
470         maxi = i;
471         maxj = seq2.length - 1;
472       }
473     }
474
475     for (int j = 0; j < seq2.length; j++)
476     {
477       if (score[seq1.length - 1][j] > max)
478       {
479         max = score[seq1.length - 1][j];
480         maxi = seq1.length - 1;
481         maxj = j;
482       }
483     }
484
485     // System.out.println(maxi + " " + maxj + " " + score[maxi][maxj]);
486     int i = maxi;
487     int j = maxj;
488     int trace;
489     maxscore = score[i][j] / 10;
490
491     seq1end = maxi + 1;
492     seq2end = maxj + 1;
493
494     aseq1 = new int[seq1.length + seq2.length];
495     aseq2 = new int[seq1.length + seq2.length];
496
497     count = (seq1.length + seq2.length) - 1;
498
499     while ((i > 0) && (j > 0))
500     {
501       if ((aseq1[count] != defInt) && (i >= 0))
502       {
503         aseq1[count] = seq1[i];
504         astr1 = s1str.charAt(i) + astr1;
505       }
506
507       if ((aseq2[count] != defInt) && (j > 0))
508       {
509         aseq2[count] = seq2[j];
510         astr2 = s2str.charAt(j) + astr2;
511       }
512
513       trace = findTrace(i, j);
514
515       if (trace == 0)
516       {
517         i--;
518         j--;
519       }
520       else if (trace == 1)
521       {
522         j--;
523         aseq1[count] = defInt;
524         astr1 = "-" + astr1.substring(1);
525       }
526       else if (trace == -1)
527       {
528         i--;
529         aseq2[count] = defInt;
530         astr2 = "-" + astr2.substring(1);
531       }
532
533       count--;
534     }
535
536     seq1start = i + 1;
537     seq2start = j + 1;
538
539     if (aseq1[count] != defInt)
540     {
541       aseq1[count] = seq1[i];
542       astr1 = s1str.charAt(i) + astr1;
543     }
544
545     if (aseq2[count] != defInt)
546     {
547       aseq2[count] = seq2[j];
548       astr2 = s2str.charAt(j) + astr2;
549     }
550   }
551
552   /**
553    * DOCUMENT ME!
554    */
555   public void printAlignment(java.io.PrintStream os)
556   {
557     // TODO: Use original sequence characters rather than re-translated
558     // characters in output
559     // Find the biggest id length for formatting purposes
560     String s1id = s1.getName(), s2id = s2.getName();
561     int maxid = s1.getName().length();
562     if (s2.getName().length() > maxid)
563     {
564       maxid = s2.getName().length();
565     }
566     if (maxid > 30)
567     {
568       maxid = 30;
569       // JAL-527 - truncate the sequence ids
570       if (s1.getName().length() > maxid)
571       {
572         s1id = s1.getName().substring(0, 30);
573       }
574       if (s2.getName().length() > maxid)
575       {
576         s2id = s2.getName().substring(0, 30);
577       }
578     }
579     int len = 72 - maxid - 1;
580     int nochunks = ((aseq1.length - count) / len) + 1;
581     pid = 0;
582
583     output.append("Score = ").append(score[maxi][maxj]).append(NEWLINE);
584     output.append("Length of alignment = ")
585             .append(String.valueOf(aseq1.length - count)).append(NEWLINE);
586     output.append("Sequence ");
587     output.append(new Format("%" + maxid + "s").form(s1.getName()));
588     output.append(" :  ").append(String.valueOf(s1.getStart()))
589             .append(" - ").append(String.valueOf(s1.getEnd()));
590     output.append(" (Sequence length = ")
591             .append(String.valueOf(s1str.length())).append(")")
592             .append(NEWLINE);
593     output.append("Sequence ");
594     output.append(new Format("%" + maxid + "s").form(s2.getName()));
595     output.append(" :  ").append(String.valueOf(s2.getStart()))
596             .append(" - ").append(String.valueOf(s2.getEnd()));
597     output.append(" (Sequence length = ")
598             .append(String.valueOf(s2str.length())).append(")")
599             .append(NEWLINE).append(NEWLINE);
600
601     for (int j = 0; j < nochunks; j++)
602     {
603       // Print the first aligned sequence
604       output.append(new Format("%" + (maxid) + "s").form(s1id)).append(" ");
605
606       for (int i = 0; i < len; i++)
607       {
608         if ((i + (j * len)) < astr1.length())
609         {
610           output.append(astr1.charAt(i + (j * len)));
611         }
612       }
613
614       output.append(NEWLINE);
615       output.append(new Format("%" + (maxid) + "s").form(" ")).append(" ");
616
617       // Print out the matching chars
618       for (int i = 0; i < len; i++)
619       {
620         if ((i + (j * len)) < astr1.length())
621         {
622           if (astr1.charAt(i + (j * len)) == astr2.charAt(i + (j * len))
623                   && !jalview.util.Comparison.isGap(astr1.charAt(i
624                           + (j * len))))
625           {
626             pid++;
627             output.append("|");
628           }
629           else if (type.equals("pep"))
630           {
631             if (ResidueProperties.getPAM250(astr1.charAt(i + (j * len)),
632                     astr2.charAt(i + (j * len))) > 0)
633             {
634               output.append(".");
635             }
636             else
637             {
638               output.append(" ");
639             }
640           }
641           else
642           {
643             output.append(" ");
644           }
645         }
646       }
647
648       // Now print the second aligned sequence
649       output = output.append(NEWLINE);
650       output = output.append(new Format("%" + (maxid) + "s").form(s2id))
651               .append(" ");
652
653       for (int i = 0; i < len; i++)
654       {
655         if ((i + (j * len)) < astr2.length())
656         {
657           output.append(astr2.charAt(i + (j * len)));
658         }
659       }
660
661       output.append(NEWLINE).append(NEWLINE);
662     }
663
664     pid = pid / (aseq1.length - count) * 100;
665     output = output.append(new Format("Percentage ID = %2.2f\n\n")
666             .form(pid));
667
668     try
669     {
670       os.print(output.toString());
671     } catch (Exception ex)
672     {
673     }
674   }
675
676   /**
677    * DOCUMENT ME!
678    * 
679    * @param mat
680    *          DOCUMENT ME!
681    */
682   public void printScoreMatrix(int[][] mat)
683   {
684     int n = seq1.length;
685     int m = seq2.length;
686
687     for (int i = 0; i < n; i++)
688     {
689       // Print the top sequence
690       if (i == 0)
691       {
692         Format.print(System.out, "%8s", s2str.substring(0, 1));
693
694         for (int jj = 1; jj < m; jj++)
695         {
696           Format.print(System.out, "%5s", s2str.substring(jj, jj + 1));
697         }
698
699         System.out.println();
700       }
701
702       for (int j = 0; j < m; j++)
703       {
704         if (j == 0)
705         {
706           Format.print(System.out, "%3s", s1str.substring(i, i + 1));
707         }
708
709         Format.print(System.out, "%3d ", mat[i][j] / 10);
710       }
711
712       System.out.println();
713     }
714   }
715
716   /**
717    * DOCUMENT ME!
718    * 
719    * @param i
720    *          DOCUMENT ME!
721    * @param j
722    *          DOCUMENT ME!
723    * 
724    * @return DOCUMENT ME!
725    */
726   public int findTrace(int i, int j)
727   {
728     int t = 0;
729     int max = score[i - 1][j - 1] + (lookup[seq1[i]][seq2[j]] * 10);
730
731     if (F[i][j] > max)
732     {
733       max = F[i][j];
734       t = -1;
735     }
736     else if (F[i][j] == max)
737     {
738       if (prev == -1)
739       {
740         max = F[i][j];
741         t = -1;
742       }
743     }
744
745     if (E[i][j] >= max)
746     {
747       max = E[i][j];
748       t = 1;
749     }
750     else if (E[i][j] == max)
751     {
752       if (prev == 1)
753       {
754         max = E[i][j];
755         t = 1;
756       }
757     }
758
759     prev = t;
760
761     return t;
762   }
763
764   /**
765    * DOCUMENT ME!
766    */
767   public void calcScoreMatrix()
768   {
769     int n = seq1.length;
770     int m = seq2.length;
771
772     // top left hand element
773     score[0][0] = lookup[seq1[0]][seq2[0]] * 10;
774     E[0][0] = -gapExtend;
775     F[0][0] = 0;
776
777     // Calculate the top row first
778     for (int j = 1; j < m; j++)
779     {
780       // What should these values be? 0 maybe
781       E[0][j] = max(score[0][j - 1] - gapOpen, E[0][j - 1] - gapExtend);
782       F[0][j] = -gapExtend;
783
784       score[0][j] = max(lookup[seq1[0]][seq2[j]] * 10, -gapOpen, -gapExtend);
785
786       traceback[0][j] = 1;
787     }
788
789     // Now do the left hand column
790     for (int i = 1; i < n; i++)
791     {
792       E[i][0] = -gapOpen;
793       F[i][0] = max(score[i - 1][0] - gapOpen, F[i - 1][0] - gapExtend);
794
795       score[i][0] = max(lookup[seq1[i]][seq2[0]] * 10, E[i][0], F[i][0]);
796       traceback[i][0] = -1;
797     }
798
799     // Now do all the other rows
800     for (int i = 1; i < n; i++)
801     {
802       for (int j = 1; j < m; j++)
803       {
804         E[i][j] = max(score[i][j - 1] - gapOpen, E[i][j - 1] - gapExtend);
805         F[i][j] = max(score[i - 1][j] - gapOpen, F[i - 1][j] - gapExtend);
806
807         score[i][j] = max(score[i - 1][j - 1]
808                 + (lookup[seq1[i]][seq2[j]] * 10), E[i][j], F[i][j]);
809         traceback[i][j] = findTrace(i, j);
810       }
811     }
812   }
813
814   /**
815    * Returns the given sequence with all of the given gap characters removed.
816    * 
817    * @param gapChars
818    *          a string of characters to be treated as gaps
819    * @param seq
820    *          the input sequence
821    * 
822    * @return
823    */
824   public static String extractGaps(String gapChars, String seq)
825   {
826     if (gapChars == null || seq == null)
827     {
828       return null;
829     }
830     StringTokenizer str = new StringTokenizer(seq, gapChars);
831     StringBuilder newString = new StringBuilder(seq.length());
832
833     while (str.hasMoreTokens())
834     {
835       newString.append(str.nextToken());
836     }
837
838     return newString.toString();
839   }
840
841   /**
842    * DOCUMENT ME!
843    * 
844    * @param i1
845    *          DOCUMENT ME!
846    * @param i2
847    *          DOCUMENT ME!
848    * @param i3
849    *          DOCUMENT ME!
850    * 
851    * @return DOCUMENT ME!
852    */
853   public int max(int i1, int i2, int i3)
854   {
855     int max = i1;
856
857     if (i2 > i1)
858     {
859       max = i2;
860     }
861
862     if (i3 > max)
863     {
864       max = i3;
865     }
866
867     return max;
868   }
869
870   /**
871    * DOCUMENT ME!
872    * 
873    * @param i1
874    *          DOCUMENT ME!
875    * @param i2
876    *          DOCUMENT ME!
877    * 
878    * @return DOCUMENT ME!
879    */
880   public int max(int i1, int i2)
881   {
882     int max = i1;
883
884     if (i2 > i1)
885     {
886       max = i2;
887     }
888
889     return max;
890   }
891
892   /**
893    * DOCUMENT ME!
894    * 
895    * @param s
896    *          DOCUMENT ME!
897    * @param type
898    *          DOCUMENT ME!
899    * 
900    * @return DOCUMENT ME!
901    */
902   public int[] stringToInt(String s, String type)
903   {
904     int[] seq1 = new int[s.length()];
905
906     for (int i = 0; i < s.length(); i++)
907     {
908       // String ss = s.substring(i, i + 1).toUpperCase();
909       char c = s.charAt(i);
910       if ('a' <= c && c <= 'z')
911       {
912         // TO UPPERCASE !!!
913         c -= ('a' - 'A');
914       }
915
916       try
917       {
918         seq1[i] = charToInt[c]; // set accordingly from setType
919         if (seq1[i] < 0 || seq1[i] > defInt) // set from setType: 23 for
920                                              // peptides, or 4 for NA.
921         {
922           seq1[i] = defInt;
923         }
924
925       } catch (Exception e)
926       {
927         seq1[i] = defInt;
928       }
929     }
930
931     return seq1;
932   }
933
934   /**
935    * DOCUMENT ME!
936    * 
937    * @param g
938    *          DOCUMENT ME!
939    * @param mat
940    *          DOCUMENT ME!
941    * @param n
942    *          DOCUMENT ME!
943    * @param m
944    *          DOCUMENT ME!
945    * @param psize
946    *          DOCUMENT ME!
947    */
948   public static void displayMatrix(Graphics g, int[][] mat, int n, int m,
949           int psize)
950   {
951     int max = -1000;
952     int min = 1000;
953
954     for (int i = 0; i < n; i++)
955     {
956       for (int j = 0; j < m; j++)
957       {
958         if (mat[i][j] >= max)
959         {
960           max = mat[i][j];
961         }
962
963         if (mat[i][j] <= min)
964         {
965           min = mat[i][j];
966         }
967       }
968     }
969
970     System.out.println(max + " " + min);
971
972     for (int i = 0; i < n; i++)
973     {
974       for (int j = 0; j < m; j++)
975       {
976         int x = psize * i;
977         int y = psize * j;
978
979         // System.out.println(mat[i][j]);
980         float score = (float) (mat[i][j] - min) / (float) (max - min);
981         g.setColor(new Color(score, 0, 0));
982         g.fillRect(x, y, psize, psize);
983
984         // System.out.println(x + " " + y + " " + score);
985       }
986     }
987   }
988
989   /**
990    * Compute a globally optimal needleman and wunsch alignment between two
991    * sequences
992    * 
993    * @param s1
994    * @param s2
995    * @param type
996    *          AlignSeq.DNA or AlignSeq.PEP
997    */
998   public static AlignSeq doGlobalNWAlignment(SequenceI s1, SequenceI s2,
999           String type)
1000   {
1001     AlignSeq as = new AlignSeq(s1, s2, type);
1002
1003     as.calcScoreMatrix();
1004     as.traceAlignment();
1005     return as;
1006   }
1007
1008   /**
1009    * 
1010    * @return mapping from positions in S1 to corresponding positions in S2
1011    */
1012   public jalview.datamodel.Mapping getMappingFromS1(boolean allowmismatch)
1013   {
1014     ArrayList<Integer> as1 = new ArrayList<Integer>(), as2 = new ArrayList<Integer>();
1015     int pdbpos = s2.getStart() + getSeq2Start() - 2;
1016     int alignpos = s1.getStart() + getSeq1Start() - 2;
1017     int lp2 = pdbpos - 3, lp1 = alignpos - 3;
1018     boolean lastmatch = false;
1019     // and now trace the alignment onto the atom set.
1020     for (int i = 0; i < astr1.length(); i++)
1021     {
1022       char c1 = astr1.charAt(i), c2 = astr2.charAt(i);
1023       if (c1 != '-')
1024       {
1025         alignpos++;
1026       }
1027
1028       if (c2 != '-')
1029       {
1030         pdbpos++;
1031       }
1032
1033       if (allowmismatch || c1 == c2)
1034       {
1035         // extend mapping interval
1036         if (lp1 + 1 != alignpos || lp2 + 1 != pdbpos)
1037         {
1038           as1.add(Integer.valueOf(alignpos));
1039           as2.add(Integer.valueOf(pdbpos));
1040         }
1041         lastmatch = true;
1042         lp1 = alignpos;
1043         lp2 = pdbpos;
1044       }
1045       else
1046       {
1047         // extend mapping interval
1048         if (lastmatch)
1049         {
1050           as1.add(Integer.valueOf(lp1));
1051           as2.add(Integer.valueOf(lp2));
1052         }
1053         lastmatch = false;
1054       }
1055     }
1056     // construct range pairs
1057
1058     int[] mapseq1 = new int[as1.size() + (lastmatch ? 1 : 0)], mapseq2 = new int[as2
1059             .size() + (lastmatch ? 1 : 0)];
1060     int i = 0;
1061     for (Integer ip : as1)
1062     {
1063       mapseq1[i++] = ip;
1064     }
1065     ;
1066     i = 0;
1067     for (Integer ip : as2)
1068     {
1069       mapseq2[i++] = ip;
1070     }
1071     ;
1072     if (lastmatch)
1073     {
1074       mapseq1[mapseq1.length - 1] = alignpos;
1075       mapseq2[mapseq2.length - 1] = pdbpos;
1076     }
1077     MapList map = new MapList(mapseq1, mapseq2, 1, 1);
1078
1079     jalview.datamodel.Mapping mapping = new Mapping(map);
1080     mapping.setTo(s2);
1081     return mapping;
1082   }
1083
1084   /**
1085    * matches ochains against al and populates seqs with the best match between
1086    * each ochain and the set in al
1087    * 
1088    * @param ochains
1089    * @param al
1090    * @param dnaOrProtein
1091    * @param removeOldAnnots
1092    *          when true, old annotation is cleared before new annotation
1093    *          transferred
1094    * @return List<List<SequenceI> originals, List<SequenceI> replacement,
1095    *         List<AlignSeq> alignment between each>
1096    */
1097   public static List<List<? extends Object>> replaceMatchingSeqsWith(
1098           List<SequenceI> seqs, List<AlignmentAnnotation> annotations,
1099           List<SequenceI> ochains, AlignmentI al, String dnaOrProtein,
1100           boolean removeOldAnnots)
1101   {
1102     List<SequenceI> orig = new ArrayList<SequenceI>(), repl = new ArrayList<SequenceI>();
1103     List<AlignSeq> aligs = new ArrayList<AlignSeq>();
1104     if (al != null && al.getHeight() > 0)
1105     {
1106       ArrayList<SequenceI> matches = new ArrayList<SequenceI>();
1107       ArrayList<AlignSeq> aligns = new ArrayList<AlignSeq>();
1108
1109       for (SequenceI sq : ochains)
1110       {
1111         SequenceI bestm = null;
1112         AlignSeq bestaseq = null;
1113         int bestscore = 0;
1114         for (SequenceI msq : al.getSequences())
1115         {
1116           AlignSeq aseq = doGlobalNWAlignment(msq, sq, dnaOrProtein);
1117           if (bestm == null || aseq.getMaxScore() > bestscore)
1118           {
1119             bestscore = aseq.getMaxScore();
1120             bestaseq = aseq;
1121             bestm = msq;
1122           }
1123         }
1124         System.out.println("Best Score for " + (matches.size() + 1) + " :"
1125                 + bestscore);
1126         matches.add(bestm);
1127         aligns.add(bestaseq);
1128         al.deleteSequence(bestm);
1129       }
1130       for (int p = 0, pSize = seqs.size(); p < pSize; p++)
1131       {
1132         SequenceI sq, sp = seqs.get(p);
1133         int q;
1134         if ((q = ochains.indexOf(sp)) > -1)
1135         {
1136           seqs.set(p, sq = matches.get(q));
1137           orig.add(sp);
1138           repl.add(sq);
1139           sq.setName(sp.getName());
1140           sq.setDescription(sp.getDescription());
1141           Mapping sp2sq;
1142           sq.transferAnnotation(sp,
1143                   sp2sq = aligns.get(q).getMappingFromS1(false));
1144           aligs.add(aligns.get(q));
1145           int inspos = -1;
1146           for (int ap = 0; ap < annotations.size();)
1147           {
1148             if (annotations.get(ap).sequenceRef == sp)
1149             {
1150               if (inspos == -1)
1151               {
1152                 inspos = ap;
1153               }
1154               if (removeOldAnnots)
1155               {
1156                 annotations.remove(ap);
1157               }
1158               else
1159               {
1160                 AlignmentAnnotation alan = annotations.remove(ap);
1161                 alan.liftOver(sq, sp2sq);
1162                 alan.setSequenceRef(sq);
1163                 sq.addAlignmentAnnotation(alan);
1164               }
1165             }
1166             else
1167             {
1168               ap++;
1169             }
1170           }
1171           if (sq.getAnnotation() != null && sq.getAnnotation().length > 0)
1172           {
1173             annotations.addAll(inspos == -1 ? annotations.size() : inspos,
1174                     Arrays.asList(sq.getAnnotation()));
1175           }
1176         }
1177       }
1178     }
1179     return Arrays.asList(orig, repl, aligs);
1180   }
1181
1182   /**
1183    * compute the PID vector used by the redundancy filter.
1184    * 
1185    * @param originalSequences
1186    *          - sequences in alignment that are to filtered
1187    * @param omitHidden
1188    *          - null or strings to be analysed (typically, visible portion of
1189    *          each sequence in alignment)
1190    * @param start
1191    *          - first column in window for calculation
1192    * @param end
1193    *          - last column in window for calculation
1194    * @param ungapped
1195    *          - if true then use ungapped sequence to compute PID
1196    * @return vector containing maximum PID for i-th sequence and any sequences
1197    *         longer than that seuqence
1198    */
1199   public static float[] computeRedundancyMatrix(
1200           SequenceI[] originalSequences, String[] omitHidden, int start,
1201           int end, boolean ungapped)
1202   {
1203     int height = originalSequences.length;
1204     float[] redundancy = new float[height];
1205     int[] lngth = new int[height];
1206     for (int i = 0; i < height; i++)
1207     {
1208       redundancy[i] = 0f;
1209       lngth[i] = -1;
1210     }
1211
1212     // long start = System.currentTimeMillis();
1213
1214     float pid;
1215     String seqi, seqj;
1216     for (int i = 0; i < height; i++)
1217     {
1218
1219       for (int j = 0; j < i; j++)
1220       {
1221         if (i == j)
1222         {
1223           continue;
1224         }
1225
1226         if (omitHidden == null)
1227         {
1228           seqi = originalSequences[i].getSequenceAsString(start, end);
1229           seqj = originalSequences[j].getSequenceAsString(start, end);
1230         }
1231         else
1232         {
1233           seqi = omitHidden[i];
1234           seqj = omitHidden[j];
1235         }
1236         if (lngth[i] == -1)
1237         {
1238           String ug = AlignSeq.extractGaps(Comparison.GapChars, seqi);
1239           lngth[i] = ug.length();
1240           if (ungapped)
1241           {
1242             seqi = ug;
1243           }
1244         }
1245         if (lngth[j] == -1)
1246         {
1247           String ug = AlignSeq.extractGaps(Comparison.GapChars, seqj);
1248           lngth[j] = ug.length();
1249           if (ungapped)
1250           {
1251             seqj = ug;
1252           }
1253         }
1254         pid = Comparison.PID(seqi, seqj);
1255
1256         // use real sequence length rather than string length
1257         if (lngth[j] < lngth[i])
1258         {
1259           redundancy[j] = Math.max(pid, redundancy[j]);
1260         }
1261         else
1262         {
1263           redundancy[i] = Math.max(pid, redundancy[i]);
1264         }
1265
1266       }
1267     }
1268     return redundancy;
1269   }
1270 }