JAL-1952 bugfix
[jalview.git] / src / jalview / analysis / AlignSeq.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3  * Copyright (C) $$Year-Rel$$ 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)
581             + ((aseq1.length - count) % len > 0 ? 1 : 0);
582     pid = 0;
583
584     output.append("Score = ").append(score[maxi][maxj]).append(NEWLINE);
585     output.append("Length of alignment = ")
586             .append(String.valueOf(aseq1.length - count)).append(NEWLINE);
587     output.append("Sequence ");
588     output.append(new Format("%" + maxid + "s").form(s1.getName()));
589     output.append(" :  ").append(String.valueOf(s1.getStart()))
590             .append(" - ").append(String.valueOf(s1.getEnd()));
591     output.append(" (Sequence length = ")
592             .append(String.valueOf(s1str.length())).append(")")
593             .append(NEWLINE);
594     output.append("Sequence ");
595     output.append(new Format("%" + maxid + "s").form(s2.getName()));
596     output.append(" :  ").append(String.valueOf(s2.getStart()))
597             .append(" - ").append(String.valueOf(s2.getEnd()));
598     output.append(" (Sequence length = ")
599             .append(String.valueOf(s2str.length())).append(")")
600             .append(NEWLINE).append(NEWLINE);
601
602     for (int j = 0; j < nochunks; j++)
603     {
604       // Print the first aligned sequence
605       output.append(new Format("%" + (maxid) + "s").form(s1id)).append(" ");
606
607       for (int i = 0; i < len; i++)
608       {
609         if ((i + (j * len)) < astr1.length())
610         {
611           output.append(astr1.charAt(i + (j * len)));
612         }
613       }
614
615       output.append(NEWLINE);
616       output.append(new Format("%" + (maxid) + "s").form(" ")).append(" ");
617
618       // Print out the matching chars
619       for (int i = 0; i < len; i++)
620       {
621         if ((i + (j * len)) < astr1.length())
622         {
623           if (astr1.charAt(i + (j * len)) == astr2.charAt(i + (j * len))
624                   && !jalview.util.Comparison.isGap(astr1.charAt(i
625                           + (j * len))))
626           {
627             pid++;
628             output.append("|");
629           }
630           else if (type.equals("pep"))
631           {
632             if (ResidueProperties.getPAM250(astr1.charAt(i + (j * len)),
633                     astr2.charAt(i + (j * len))) > 0)
634             {
635               output.append(".");
636             }
637             else
638             {
639               output.append(" ");
640             }
641           }
642           else
643           {
644             output.append(" ");
645           }
646         }
647       }
648
649       // Now print the second aligned sequence
650       output = output.append(NEWLINE);
651       output = output.append(new Format("%" + (maxid) + "s").form(s2id))
652               .append(" ");
653
654       for (int i = 0; i < len; i++)
655       {
656         if ((i + (j * len)) < astr2.length())
657         {
658           output.append(astr2.charAt(i + (j * len)));
659         }
660       }
661
662       output.append(NEWLINE).append(NEWLINE);
663     }
664
665     pid = pid / (aseq1.length - count) * 100;
666     output = output.append(new Format("Percentage ID = %2.2f\n")
667             .form(pid));
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     // TODO method dosen't seem to be referenced anywhere delete??
952     int max = -1000;
953     int min = 1000;
954
955     for (int i = 0; i < n; i++)
956     {
957       for (int j = 0; j < m; j++)
958       {
959         if (mat[i][j] >= max)
960         {
961           max = mat[i][j];
962         }
963
964         if (mat[i][j] <= min)
965         {
966           min = mat[i][j];
967         }
968       }
969     }
970
971     System.out.println(max + " " + min);
972
973     for (int i = 0; i < n; i++)
974     {
975       for (int j = 0; j < m; j++)
976       {
977         int x = psize * i;
978         int y = psize * j;
979
980         // System.out.println(mat[i][j]);
981         float score = (float) (mat[i][j] - min) / (float) (max - min);
982         g.setColor(new Color(score, 0, 0));
983         g.fillRect(x, y, psize, psize);
984
985         // System.out.println(x + " " + y + " " + score);
986       }
987     }
988   }
989
990   /**
991    * Compute a globally optimal needleman and wunsch alignment between two
992    * sequences
993    * 
994    * @param s1
995    * @param s2
996    * @param type
997    *          AlignSeq.DNA or AlignSeq.PEP
998    */
999   public static AlignSeq doGlobalNWAlignment(SequenceI s1, SequenceI s2,
1000           String type)
1001   {
1002     AlignSeq as = new AlignSeq(s1, s2, type);
1003
1004     as.calcScoreMatrix();
1005     as.traceAlignment();
1006     return as;
1007   }
1008
1009   /**
1010    * 
1011    * @return mapping from positions in S1 to corresponding positions in S2
1012    */
1013   public jalview.datamodel.Mapping getMappingFromS1(boolean allowmismatch)
1014   {
1015     ArrayList<Integer> as1 = new ArrayList<Integer>(), as2 = new ArrayList<Integer>();
1016     int pdbpos = s2.getStart() + getSeq2Start() - 2;
1017     int alignpos = s1.getStart() + getSeq1Start() - 2;
1018     int lp2 = pdbpos - 3, lp1 = alignpos - 3;
1019     boolean lastmatch = false;
1020     // and now trace the alignment onto the atom set.
1021     for (int i = 0; i < astr1.length(); i++)
1022     {
1023       char c1 = astr1.charAt(i), c2 = astr2.charAt(i);
1024       if (c1 != '-')
1025       {
1026         alignpos++;
1027       }
1028
1029       if (c2 != '-')
1030       {
1031         pdbpos++;
1032       }
1033
1034       if (allowmismatch || c1 == c2)
1035       {
1036         // extend mapping interval
1037         if (lp1 + 1 != alignpos || lp2 + 1 != pdbpos)
1038         {
1039           as1.add(Integer.valueOf(alignpos));
1040           as2.add(Integer.valueOf(pdbpos));
1041         }
1042         lastmatch = true;
1043         lp1 = alignpos;
1044         lp2 = pdbpos;
1045       }
1046       else
1047       {
1048         // extend mapping interval
1049         if (lastmatch)
1050         {
1051           as1.add(Integer.valueOf(lp1));
1052           as2.add(Integer.valueOf(lp2));
1053         }
1054         lastmatch = false;
1055       }
1056     }
1057     // construct range pairs
1058
1059     int[] mapseq1 = new int[as1.size() + (lastmatch ? 1 : 0)], mapseq2 = new int[as2
1060             .size() + (lastmatch ? 1 : 0)];
1061     int i = 0;
1062     for (Integer ip : as1)
1063     {
1064       mapseq1[i++] = ip;
1065     }
1066     ;
1067     i = 0;
1068     for (Integer ip : as2)
1069     {
1070       mapseq2[i++] = ip;
1071     }
1072     ;
1073     if (lastmatch)
1074     {
1075       mapseq1[mapseq1.length - 1] = alignpos;
1076       mapseq2[mapseq2.length - 1] = pdbpos;
1077     }
1078     MapList map = new MapList(mapseq1, mapseq2, 1, 1);
1079
1080     jalview.datamodel.Mapping mapping = new Mapping(map);
1081     mapping.setTo(s2);
1082     return mapping;
1083   }
1084
1085   /**
1086    * matches ochains against al and populates seqs with the best match between
1087    * each ochain and the set in al
1088    * 
1089    * @param ochains
1090    * @param al
1091    * @param dnaOrProtein
1092    * @param removeOldAnnots
1093    *          when true, old annotation is cleared before new annotation
1094    *          transferred
1095    * @return List<List<SequenceI> originals, List<SequenceI> replacement,
1096    *         List<AlignSeq> alignment between each>
1097    */
1098   public static List<List<? extends Object>> replaceMatchingSeqsWith(
1099           List<SequenceI> seqs, List<AlignmentAnnotation> annotations,
1100           List<SequenceI> ochains, AlignmentI al, String dnaOrProtein,
1101           boolean removeOldAnnots)
1102   {
1103     List<SequenceI> orig = new ArrayList<SequenceI>(), repl = new ArrayList<SequenceI>();
1104     List<AlignSeq> aligs = new ArrayList<AlignSeq>();
1105     if (al != null && al.getHeight() > 0)
1106     {
1107       ArrayList<SequenceI> matches = new ArrayList<SequenceI>();
1108       ArrayList<AlignSeq> aligns = new ArrayList<AlignSeq>();
1109
1110       for (SequenceI sq : ochains)
1111       {
1112         SequenceI bestm = null;
1113         AlignSeq bestaseq = null;
1114         int bestscore = 0;
1115         for (SequenceI msq : al.getSequences())
1116         {
1117           AlignSeq aseq = doGlobalNWAlignment(msq, sq, dnaOrProtein);
1118           if (bestm == null || aseq.getMaxScore() > bestscore)
1119           {
1120             bestscore = aseq.getMaxScore();
1121             bestaseq = aseq;
1122             bestm = msq;
1123           }
1124         }
1125         System.out.println("Best Score for " + (matches.size() + 1) + " :"
1126                 + bestscore);
1127         matches.add(bestm);
1128         aligns.add(bestaseq);
1129         al.deleteSequence(bestm);
1130       }
1131       for (int p = 0, pSize = seqs.size(); p < pSize; p++)
1132       {
1133         SequenceI sq, sp = seqs.get(p);
1134         int q;
1135         if ((q = ochains.indexOf(sp)) > -1)
1136         {
1137           seqs.set(p, sq = matches.get(q));
1138           orig.add(sp);
1139           repl.add(sq);
1140           sq.setName(sp.getName());
1141           sq.setDescription(sp.getDescription());
1142           Mapping sp2sq;
1143           sq.transferAnnotation(sp,
1144                   sp2sq = aligns.get(q).getMappingFromS1(false));
1145           aligs.add(aligns.get(q));
1146           int inspos = -1;
1147           for (int ap = 0; ap < annotations.size();)
1148           {
1149             if (annotations.get(ap).sequenceRef == sp)
1150             {
1151               if (inspos == -1)
1152               {
1153                 inspos = ap;
1154               }
1155               if (removeOldAnnots)
1156               {
1157                 annotations.remove(ap);
1158               }
1159               else
1160               {
1161                 AlignmentAnnotation alan = annotations.remove(ap);
1162                 alan.liftOver(sq, sp2sq);
1163                 alan.setSequenceRef(sq);
1164                 sq.addAlignmentAnnotation(alan);
1165               }
1166             }
1167             else
1168             {
1169               ap++;
1170             }
1171           }
1172           if (sq.getAnnotation() != null && sq.getAnnotation().length > 0)
1173           {
1174             annotations.addAll(inspos == -1 ? annotations.size() : inspos,
1175                     Arrays.asList(sq.getAnnotation()));
1176           }
1177         }
1178       }
1179     }
1180     return Arrays.asList(orig, repl, aligs);
1181   }
1182
1183   /**
1184    * compute the PID vector used by the redundancy filter.
1185    * 
1186    * @param originalSequences
1187    *          - sequences in alignment that are to filtered
1188    * @param omitHidden
1189    *          - null or strings to be analysed (typically, visible portion of
1190    *          each sequence in alignment)
1191    * @param start
1192    *          - first column in window for calculation
1193    * @param end
1194    *          - last column in window for calculation
1195    * @param ungapped
1196    *          - if true then use ungapped sequence to compute PID
1197    * @return vector containing maximum PID for i-th sequence and any sequences
1198    *         longer than that seuqence
1199    */
1200   public static float[] computeRedundancyMatrix(
1201           SequenceI[] originalSequences, String[] omitHidden, int start,
1202           int end, boolean ungapped)
1203   {
1204     int height = originalSequences.length;
1205     float[] redundancy = new float[height];
1206     int[] lngth = new int[height];
1207     for (int i = 0; i < height; i++)
1208     {
1209       redundancy[i] = 0f;
1210       lngth[i] = -1;
1211     }
1212
1213     // long start = System.currentTimeMillis();
1214
1215     float pid;
1216     String seqi, seqj;
1217     for (int i = 0; i < height; i++)
1218     {
1219
1220       for (int j = 0; j < i; j++)
1221       {
1222         if (i == j)
1223         {
1224           continue;
1225         }
1226
1227         if (omitHidden == null)
1228         {
1229           seqi = originalSequences[i].getSequenceAsString(start, end);
1230           seqj = originalSequences[j].getSequenceAsString(start, end);
1231         }
1232         else
1233         {
1234           seqi = omitHidden[i];
1235           seqj = omitHidden[j];
1236         }
1237         if (lngth[i] == -1)
1238         {
1239           String ug = AlignSeq.extractGaps(Comparison.GapChars, seqi);
1240           lngth[i] = ug.length();
1241           if (ungapped)
1242           {
1243             seqi = ug;
1244           }
1245         }
1246         if (lngth[j] == -1)
1247         {
1248           String ug = AlignSeq.extractGaps(Comparison.GapChars, seqj);
1249           lngth[j] = ug.length();
1250           if (ungapped)
1251           {
1252             seqj = ug;
1253           }
1254         }
1255         pid = Comparison.PID(seqi, seqj);
1256
1257         // use real sequence length rather than string length
1258         if (lngth[j] < lngth[i])
1259         {
1260           redundancy[j] = Math.max(pid, redundancy[j]);
1261         }
1262         else
1263         {
1264           redundancy[i] = Math.max(pid, redundancy[i]);
1265         }
1266
1267       }
1268     }
1269     return redundancy;
1270   }
1271 }