3e4a82b6ca34724d3a69455499fa535e3866236d
[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) + 1;
581     pid = 0;
582
583     output.append("Sequence \u27f7 Structure mapping details: ")
584             .append(NEWLINE);
585     output.append(new Format("%" + maxid + "s").form(s1.getName()));
586     output.append(" :  ").append(String.valueOf(s1.getStart()))
587             .append(" - ").append(String.valueOf(s1.getEnd()));
588     output.append(" (Sequence length = ")
589             .append(String.valueOf(s1str.length())).append(")")
590             .append(NEWLINE);
591     // output.append("Sequence ");
592     output.append(new Format("%" + maxid + "s").form(s2.getName()));
593     output.append(" :  ").append(String.valueOf(s2.getStart()))
594             .append(" - ").append(String.valueOf(s2.getEnd()));
595     output.append(" (Sequence length = ")
596             .append(String.valueOf(s2str.length())).append(")")
597             .append(NEWLINE).append(NEWLINE);
598
599     // output mappings
600     for (int j = 0; j < nochunks; j++)
601     {
602       // Print the first aligned sequence
603       output.append(new Format("%" + (maxid) + "s").form(s1id)).append(" ");
604
605       for (int i = 0; i < len; i++)
606       {
607         if ((i + (j * len)) < astr1.length())
608         {
609           output.append(astr1.charAt(i + (j * len)));
610         }
611       }
612
613       output.append(NEWLINE);
614       output.append(new Format("%" + (maxid) + "s").form(" ")).append(" ");
615
616       // Print out the matching chars
617       for (int i = 0; i < len; i++)
618       {
619         if ((i + (j * len)) < astr1.length())
620         {
621           if (astr1.charAt(i + (j * len)) == astr2.charAt(i + (j * len))
622                   && !jalview.util.Comparison.isGap(astr1.charAt(i
623                           + (j * len))))
624           {
625             pid++;
626             output.append("|");
627           }
628           else if (type.equals("pep"))
629           {
630             if (ResidueProperties.getPAM250(astr1.charAt(i + (j * len)),
631                     astr2.charAt(i + (j * len))) > 0)
632             {
633               output.append(".");
634             }
635             else
636             {
637               output.append(" ");
638             }
639           }
640           else
641           {
642             output.append(" ");
643           }
644         }
645       }
646
647       // Now print the second aligned sequence
648       output = output.append(NEWLINE);
649       output = output.append(new Format("%" + (maxid) + "s").form(s2id))
650               .append(" ");
651
652       for (int i = 0; i < len; i++)
653       {
654         if ((i + (j * len)) < astr2.length())
655         {
656           output.append(astr2.charAt(i + (j * len)));
657         }
658       }
659
660       output.append(NEWLINE).append(NEWLINE);
661     }
662
663     output.append("Length of alignment = ")
664             .append(String.valueOf(aseq1.length - count)).append(NEWLINE);
665     output.append("Score = ").append(score[maxi][maxj]).append(NEWLINE);
666
667     pid = pid / (aseq1.length - count) * 100;
668     output = output.append(new Format("Percentage ID = %2.2f\n\n")
669             .form(pid));
670
671     output.append(NEWLINE).append(
672             "Mapping method: Needleman & Wunsch Alignment");
673     try
674     {
675       os.print(output.toString());
676     } catch (Exception ex)
677     {
678     }
679   }
680
681   /**
682    * DOCUMENT ME!
683    * 
684    * @param mat
685    *          DOCUMENT ME!
686    */
687   public void printScoreMatrix(int[][] mat)
688   {
689     int n = seq1.length;
690     int m = seq2.length;
691
692     for (int i = 0; i < n; i++)
693     {
694       // Print the top sequence
695       if (i == 0)
696       {
697         Format.print(System.out, "%8s", s2str.substring(0, 1));
698
699         for (int jj = 1; jj < m; jj++)
700         {
701           Format.print(System.out, "%5s", s2str.substring(jj, jj + 1));
702         }
703
704         System.out.println();
705       }
706
707       for (int j = 0; j < m; j++)
708       {
709         if (j == 0)
710         {
711           Format.print(System.out, "%3s", s1str.substring(i, i + 1));
712         }
713
714         Format.print(System.out, "%3d ", mat[i][j] / 10);
715       }
716
717       System.out.println();
718     }
719   }
720
721   /**
722    * DOCUMENT ME!
723    * 
724    * @param i
725    *          DOCUMENT ME!
726    * @param j
727    *          DOCUMENT ME!
728    * 
729    * @return DOCUMENT ME!
730    */
731   public int findTrace(int i, int j)
732   {
733     int t = 0;
734     int max = score[i - 1][j - 1] + (lookup[seq1[i]][seq2[j]] * 10);
735
736     if (F[i][j] > max)
737     {
738       max = F[i][j];
739       t = -1;
740     }
741     else if (F[i][j] == max)
742     {
743       if (prev == -1)
744       {
745         max = F[i][j];
746         t = -1;
747       }
748     }
749
750     if (E[i][j] >= max)
751     {
752       max = E[i][j];
753       t = 1;
754     }
755     else if (E[i][j] == max)
756     {
757       if (prev == 1)
758       {
759         max = E[i][j];
760         t = 1;
761       }
762     }
763
764     prev = t;
765
766     return t;
767   }
768
769   /**
770    * DOCUMENT ME!
771    */
772   public void calcScoreMatrix()
773   {
774     int n = seq1.length;
775     int m = seq2.length;
776
777     // top left hand element
778     score[0][0] = lookup[seq1[0]][seq2[0]] * 10;
779     E[0][0] = -gapExtend;
780     F[0][0] = 0;
781
782     // Calculate the top row first
783     for (int j = 1; j < m; j++)
784     {
785       // What should these values be? 0 maybe
786       E[0][j] = max(score[0][j - 1] - gapOpen, E[0][j - 1] - gapExtend);
787       F[0][j] = -gapExtend;
788
789       score[0][j] = max(lookup[seq1[0]][seq2[j]] * 10, -gapOpen, -gapExtend);
790
791       traceback[0][j] = 1;
792     }
793
794     // Now do the left hand column
795     for (int i = 1; i < n; i++)
796     {
797       E[i][0] = -gapOpen;
798       F[i][0] = max(score[i - 1][0] - gapOpen, F[i - 1][0] - gapExtend);
799
800       score[i][0] = max(lookup[seq1[i]][seq2[0]] * 10, E[i][0], F[i][0]);
801       traceback[i][0] = -1;
802     }
803
804     // Now do all the other rows
805     for (int i = 1; i < n; i++)
806     {
807       for (int j = 1; j < m; j++)
808       {
809         E[i][j] = max(score[i][j - 1] - gapOpen, E[i][j - 1] - gapExtend);
810         F[i][j] = max(score[i - 1][j] - gapOpen, F[i - 1][j] - gapExtend);
811
812         score[i][j] = max(score[i - 1][j - 1]
813                 + (lookup[seq1[i]][seq2[j]] * 10), E[i][j], F[i][j]);
814         traceback[i][j] = findTrace(i, j);
815       }
816     }
817   }
818
819   /**
820    * Returns the given sequence with all of the given gap characters removed.
821    * 
822    * @param gapChars
823    *          a string of characters to be treated as gaps
824    * @param seq
825    *          the input sequence
826    * 
827    * @return
828    */
829   public static String extractGaps(String gapChars, String seq)
830   {
831     if (gapChars == null || seq == null)
832     {
833       return null;
834     }
835     StringTokenizer str = new StringTokenizer(seq, gapChars);
836     StringBuilder newString = new StringBuilder(seq.length());
837
838     while (str.hasMoreTokens())
839     {
840       newString.append(str.nextToken());
841     }
842
843     return newString.toString();
844   }
845
846   /**
847    * DOCUMENT ME!
848    * 
849    * @param i1
850    *          DOCUMENT ME!
851    * @param i2
852    *          DOCUMENT ME!
853    * @param i3
854    *          DOCUMENT ME!
855    * 
856    * @return DOCUMENT ME!
857    */
858   public int max(int i1, int i2, int i3)
859   {
860     int max = i1;
861
862     if (i2 > i1)
863     {
864       max = i2;
865     }
866
867     if (i3 > max)
868     {
869       max = i3;
870     }
871
872     return max;
873   }
874
875   /**
876    * DOCUMENT ME!
877    * 
878    * @param i1
879    *          DOCUMENT ME!
880    * @param i2
881    *          DOCUMENT ME!
882    * 
883    * @return DOCUMENT ME!
884    */
885   public int max(int i1, int i2)
886   {
887     int max = i1;
888
889     if (i2 > i1)
890     {
891       max = i2;
892     }
893
894     return max;
895   }
896
897   /**
898    * DOCUMENT ME!
899    * 
900    * @param s
901    *          DOCUMENT ME!
902    * @param type
903    *          DOCUMENT ME!
904    * 
905    * @return DOCUMENT ME!
906    */
907   public int[] stringToInt(String s, String type)
908   {
909     int[] seq1 = new int[s.length()];
910
911     for (int i = 0; i < s.length(); i++)
912     {
913       // String ss = s.substring(i, i + 1).toUpperCase();
914       char c = s.charAt(i);
915       if ('a' <= c && c <= 'z')
916       {
917         // TO UPPERCASE !!!
918         c -= ('a' - 'A');
919       }
920
921       try
922       {
923         seq1[i] = charToInt[c]; // set accordingly from setType
924         if (seq1[i] < 0 || seq1[i] > defInt) // set from setType: 23 for
925                                              // peptides, or 4 for NA.
926         {
927           seq1[i] = defInt;
928         }
929
930       } catch (Exception e)
931       {
932         seq1[i] = defInt;
933       }
934     }
935
936     return seq1;
937   }
938
939   /**
940    * DOCUMENT ME!
941    * 
942    * @param g
943    *          DOCUMENT ME!
944    * @param mat
945    *          DOCUMENT ME!
946    * @param n
947    *          DOCUMENT ME!
948    * @param m
949    *          DOCUMENT ME!
950    * @param psize
951    *          DOCUMENT ME!
952    */
953   public static void displayMatrix(Graphics g, int[][] mat, int n, int m,
954           int psize)
955   {
956     // TODO method dosen't seem to be referenced anywhere delete??
957     int max = -1000;
958     int min = 1000;
959
960     for (int i = 0; i < n; i++)
961     {
962       for (int j = 0; j < m; j++)
963       {
964         if (mat[i][j] >= max)
965         {
966           max = mat[i][j];
967         }
968
969         if (mat[i][j] <= min)
970         {
971           min = mat[i][j];
972         }
973       }
974     }
975
976     System.out.println(max + " " + min);
977
978     for (int i = 0; i < n; i++)
979     {
980       for (int j = 0; j < m; j++)
981       {
982         int x = psize * i;
983         int y = psize * j;
984
985         // System.out.println(mat[i][j]);
986         float score = (float) (mat[i][j] - min) / (float) (max - min);
987         g.setColor(new Color(score, 0, 0));
988         g.fillRect(x, y, psize, psize);
989
990         // System.out.println(x + " " + y + " " + score);
991       }
992     }
993   }
994
995   /**
996    * Compute a globally optimal needleman and wunsch alignment between two
997    * sequences
998    * 
999    * @param s1
1000    * @param s2
1001    * @param type
1002    *          AlignSeq.DNA or AlignSeq.PEP
1003    */
1004   public static AlignSeq doGlobalNWAlignment(SequenceI s1, SequenceI s2,
1005           String type)
1006   {
1007     AlignSeq as = new AlignSeq(s1, s2, type);
1008
1009     as.calcScoreMatrix();
1010     as.traceAlignment();
1011     return as;
1012   }
1013
1014   /**
1015    * 
1016    * @return mapping from positions in S1 to corresponding positions in S2
1017    */
1018   public jalview.datamodel.Mapping getMappingFromS1(boolean allowmismatch)
1019   {
1020     ArrayList<Integer> as1 = new ArrayList<Integer>(), as2 = new ArrayList<Integer>();
1021     int pdbpos = s2.getStart() + getSeq2Start() - 2;
1022     int alignpos = s1.getStart() + getSeq1Start() - 2;
1023     int lp2 = pdbpos - 3, lp1 = alignpos - 3;
1024     boolean lastmatch = false;
1025     // and now trace the alignment onto the atom set.
1026     for (int i = 0; i < astr1.length(); i++)
1027     {
1028       char c1 = astr1.charAt(i), c2 = astr2.charAt(i);
1029       if (c1 != '-')
1030       {
1031         alignpos++;
1032       }
1033
1034       if (c2 != '-')
1035       {
1036         pdbpos++;
1037       }
1038
1039       if (allowmismatch || c1 == c2)
1040       {
1041         // extend mapping interval
1042         if (lp1 + 1 != alignpos || lp2 + 1 != pdbpos)
1043         {
1044           as1.add(Integer.valueOf(alignpos));
1045           as2.add(Integer.valueOf(pdbpos));
1046         }
1047         lastmatch = true;
1048         lp1 = alignpos;
1049         lp2 = pdbpos;
1050       }
1051       else
1052       {
1053         // extend mapping interval
1054         if (lastmatch)
1055         {
1056           as1.add(Integer.valueOf(lp1));
1057           as2.add(Integer.valueOf(lp2));
1058         }
1059         lastmatch = false;
1060       }
1061     }
1062     // construct range pairs
1063
1064     int[] mapseq1 = new int[as1.size() + (lastmatch ? 1 : 0)], mapseq2 = new int[as2
1065             .size() + (lastmatch ? 1 : 0)];
1066     int i = 0;
1067     for (Integer ip : as1)
1068     {
1069       mapseq1[i++] = ip;
1070     }
1071     ;
1072     i = 0;
1073     for (Integer ip : as2)
1074     {
1075       mapseq2[i++] = ip;
1076     }
1077     ;
1078     if (lastmatch)
1079     {
1080       mapseq1[mapseq1.length - 1] = alignpos;
1081       mapseq2[mapseq2.length - 1] = pdbpos;
1082     }
1083     MapList map = new MapList(mapseq1, mapseq2, 1, 1);
1084
1085     jalview.datamodel.Mapping mapping = new Mapping(map);
1086     mapping.setTo(s2);
1087     return mapping;
1088   }
1089
1090   /**
1091    * matches ochains against al and populates seqs with the best match between
1092    * each ochain and the set in al
1093    * 
1094    * @param ochains
1095    * @param al
1096    * @param dnaOrProtein
1097    * @param removeOldAnnots
1098    *          when true, old annotation is cleared before new annotation
1099    *          transferred
1100    * @return List<List<SequenceI> originals, List<SequenceI> replacement,
1101    *         List<AlignSeq> alignment between each>
1102    */
1103   public static List<List<? extends Object>> replaceMatchingSeqsWith(
1104           List<SequenceI> seqs, List<AlignmentAnnotation> annotations,
1105           List<SequenceI> ochains, AlignmentI al, String dnaOrProtein,
1106           boolean removeOldAnnots)
1107   {
1108     List<SequenceI> orig = new ArrayList<SequenceI>(), repl = new ArrayList<SequenceI>();
1109     List<AlignSeq> aligs = new ArrayList<AlignSeq>();
1110     if (al != null && al.getHeight() > 0)
1111     {
1112       ArrayList<SequenceI> matches = new ArrayList<SequenceI>();
1113       ArrayList<AlignSeq> aligns = new ArrayList<AlignSeq>();
1114
1115       for (SequenceI sq : ochains)
1116       {
1117         SequenceI bestm = null;
1118         AlignSeq bestaseq = null;
1119         int bestscore = 0;
1120         for (SequenceI msq : al.getSequences())
1121         {
1122           AlignSeq aseq = doGlobalNWAlignment(msq, sq, dnaOrProtein);
1123           if (bestm == null || aseq.getMaxScore() > bestscore)
1124           {
1125             bestscore = aseq.getMaxScore();
1126             bestaseq = aseq;
1127             bestm = msq;
1128           }
1129         }
1130         System.out.println("Best Score for " + (matches.size() + 1) + " :"
1131                 + bestscore);
1132         matches.add(bestm);
1133         aligns.add(bestaseq);
1134         al.deleteSequence(bestm);
1135       }
1136       for (int p = 0, pSize = seqs.size(); p < pSize; p++)
1137       {
1138         SequenceI sq, sp = seqs.get(p);
1139         int q;
1140         if ((q = ochains.indexOf(sp)) > -1)
1141         {
1142           seqs.set(p, sq = matches.get(q));
1143           orig.add(sp);
1144           repl.add(sq);
1145           sq.setName(sp.getName());
1146           sq.setDescription(sp.getDescription());
1147           Mapping sp2sq;
1148           sq.transferAnnotation(sp,
1149                   sp2sq = aligns.get(q).getMappingFromS1(false));
1150           aligs.add(aligns.get(q));
1151           int inspos = -1;
1152           for (int ap = 0; ap < annotations.size();)
1153           {
1154             if (annotations.get(ap).sequenceRef == sp)
1155             {
1156               if (inspos == -1)
1157               {
1158                 inspos = ap;
1159               }
1160               if (removeOldAnnots)
1161               {
1162                 annotations.remove(ap);
1163               }
1164               else
1165               {
1166                 AlignmentAnnotation alan = annotations.remove(ap);
1167                 alan.liftOver(sq, sp2sq);
1168                 alan.setSequenceRef(sq);
1169                 sq.addAlignmentAnnotation(alan);
1170               }
1171             }
1172             else
1173             {
1174               ap++;
1175             }
1176           }
1177           if (sq.getAnnotation() != null && sq.getAnnotation().length > 0)
1178           {
1179             annotations.addAll(inspos == -1 ? annotations.size() : inspos,
1180                     Arrays.asList(sq.getAnnotation()));
1181           }
1182         }
1183       }
1184     }
1185     return Arrays.asList(orig, repl, aligs);
1186   }
1187
1188   /**
1189    * compute the PID vector used by the redundancy filter.
1190    * 
1191    * @param originalSequences
1192    *          - sequences in alignment that are to filtered
1193    * @param omitHidden
1194    *          - null or strings to be analysed (typically, visible portion of
1195    *          each sequence in alignment)
1196    * @param start
1197    *          - first column in window for calculation
1198    * @param end
1199    *          - last column in window for calculation
1200    * @param ungapped
1201    *          - if true then use ungapped sequence to compute PID
1202    * @return vector containing maximum PID for i-th sequence and any sequences
1203    *         longer than that seuqence
1204    */
1205   public static float[] computeRedundancyMatrix(
1206           SequenceI[] originalSequences, String[] omitHidden, int start,
1207           int end, boolean ungapped)
1208   {
1209     int height = originalSequences.length;
1210     float[] redundancy = new float[height];
1211     int[] lngth = new int[height];
1212     for (int i = 0; i < height; i++)
1213     {
1214       redundancy[i] = 0f;
1215       lngth[i] = -1;
1216     }
1217
1218     // long start = System.currentTimeMillis();
1219
1220     float pid;
1221     String seqi, seqj;
1222     for (int i = 0; i < height; i++)
1223     {
1224
1225       for (int j = 0; j < i; j++)
1226       {
1227         if (i == j)
1228         {
1229           continue;
1230         }
1231
1232         if (omitHidden == null)
1233         {
1234           seqi = originalSequences[i].getSequenceAsString(start, end);
1235           seqj = originalSequences[j].getSequenceAsString(start, end);
1236         }
1237         else
1238         {
1239           seqi = omitHidden[i];
1240           seqj = omitHidden[j];
1241         }
1242         if (lngth[i] == -1)
1243         {
1244           String ug = AlignSeq.extractGaps(Comparison.GapChars, seqi);
1245           lngth[i] = ug.length();
1246           if (ungapped)
1247           {
1248             seqi = ug;
1249           }
1250         }
1251         if (lngth[j] == -1)
1252         {
1253           String ug = AlignSeq.extractGaps(Comparison.GapChars, seqj);
1254           lngth[j] = ug.length();
1255           if (ungapped)
1256           {
1257             seqj = ug;
1258           }
1259         }
1260         pid = Comparison.PID(seqi, seqj);
1261
1262         // use real sequence length rather than string length
1263         if (lngth[j] < lngth[i])
1264         {
1265           redundancy[j] = Math.max(pid, redundancy[j]);
1266         }
1267         else
1268         {
1269           redundancy[i] = Math.max(pid, redundancy[i]);
1270         }
1271
1272       }
1273     }
1274     return redundancy;
1275   }
1276 }