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