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