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