JAL-4386 Comparing secondary structure similarity directly with a basic
[jalview.git] / test / jalview / analysis / scoremodels / SecondaryStructureDistanceModelTest.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.scoremodels;
22
23 import static org.testng.Assert.assertEquals;
24 import static org.testng.Assert.assertTrue;
25
26 import jalview.api.analysis.ScoreModelI;
27 import jalview.api.analysis.SimilarityParamsI;
28 import jalview.datamodel.Alignment;
29 import jalview.datamodel.AlignmentAnnotation;
30 import jalview.datamodel.AlignmentI;
31 import jalview.datamodel.AlignmentView;
32 import jalview.datamodel.Annotation;
33 import jalview.datamodel.Sequence;
34 import jalview.datamodel.SequenceFeature;
35 import jalview.datamodel.SequenceI;
36 import jalview.gui.AlignFrame;
37 import jalview.gui.AlignViewport;
38 import jalview.gui.JvOptionPane;
39 import jalview.io.DataSourceType;
40 import jalview.io.FileLoader;
41 import jalview.math.MatrixI;
42
43 import org.testng.Assert;
44 import org.testng.annotations.BeforeClass;
45 import org.testng.annotations.Test;
46
47 // This class tests methods in Class SecondaryStructureDistanceModel 
48 public class SecondaryStructureDistanceModelTest
49 {
50
51   @BeforeClass(alwaysRun = true)
52   public void setUpJvOptionPane()
53   {
54     JvOptionPane.setInteractiveMode(false);
55     JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION);
56   }
57
58   public static String alntestFile = "FER1_MESCR/72-76 DVYIL\nFER1_SPIOL/71-75 DVYIL\nFER3_RAPSA/21-25 DVYVL\nFER1_MAIZE/73-77 DVYIL\n";
59
60   int[] sf1 = new int[] { 74, 74, 73, 73, 23, 23, -1, -1 };
61
62   int[] sf2 = new int[] { -1, -1, 74, 75, -1, -1, 76, 77 };
63
64   int[] sf3 = new int[] { -1, -1, -1, -1, -1, -1, 76, 77 };
65
66   /**
67    * <pre>
68    * Load test alignment and add features to sequences: 
69    *      FER1_MESCR FER1_SPIOL FER3_RAPSA FER1_MAIZE 
70    *  sf1     X          X          X  
71    *  sf2                X                     X 
72    *  sf3                                      X
73    * </pre>
74    * 
75    * @return
76    */
77   public AlignFrame getTestAlignmentFrame()
78   {
79     AlignFrame alf = new FileLoader(false)
80             .LoadFileWaitTillLoaded(alntestFile, DataSourceType.PASTE);
81     AlignmentI al = alf.getViewport().getAlignment();
82     Assert.assertEquals(al.getHeight(), 4);
83     Assert.assertEquals(al.getWidth(), 5);
84     for (int i = 0; i < 4; i++)
85     {
86       SequenceI ds = al.getSequenceAt(i).getDatasetSequence();
87       if (sf1[i * 2] > 0)
88       {
89         ds.addSequenceFeature(new SequenceFeature("sf1", "sf1", sf1[i * 2],
90                 sf1[i * 2 + 1], "sf1"));
91       }
92       if (sf2[i * 2] > 0)
93       {
94         ds.addSequenceFeature(new SequenceFeature("sf2", "sf2", sf2[i * 2],
95                 sf2[i * 2 + 1], "sf2"));
96       }
97       if (sf3[i * 2] > 0)
98       {
99         ds.addSequenceFeature(new SequenceFeature("sf3", "sf3", sf3[i * 2],
100                 sf3[i * 2 + 1], "sf3"));
101       }
102     }
103     alf.setShowSeqFeatures(true);
104     alf.getFeatureRenderer().setVisible("sf1");
105     alf.getFeatureRenderer().setVisible("sf2");
106     alf.getFeatureRenderer().setVisible("sf3");
107     alf.getFeatureRenderer().findAllFeatures(true);
108     Assert.assertEquals(
109             alf.getFeatureRenderer().getDisplayedFeatureTypes().size(), 3,
110             "Number of feature types");
111     assertTrue(alf.getCurrentView().areFeaturesDisplayed());
112     return alf;
113   }
114
115
116
117   /**
118    * Verify computed distances of sequences with similar secondary structures
119    */
120   @Test(groups = "Functional")
121   public void testFindDistances_AllSimilar()
122   {
123     AlignFrame af = setupAlignmentView("All Similar");
124     AlignViewport viewport = af.getViewport();
125     AlignmentView view = viewport.getAlignmentView(false);
126
127     ScoreModelI sm = new SecondaryStructureDistanceModel();
128     sm = ScoreModels.getInstance().getScoreModel(sm.getName(),
129             af.alignPanel);
130
131     /*
132      * feature distance model always normalises by region width
133      */
134
135     SimilarityParamsI params = new SimilarityParams(false, true, true, true);
136     params.setSecondaryStructureSource("3D Structures");
137     MatrixI distances = sm.findDistances(view, params);
138     assertEquals(distances.getValue(0, 0), 0d);
139     assertEquals(distances.getValue(1, 1), 0d);
140     assertEquals(distances.getValue(0, 1), 0d / 4); 
141     assertEquals(distances.getValue(1, 0), 0d / 4);
142   }
143   
144   /**
145    * Verify computed distances of sequences with partially similar secondary structures
146    */
147   @Test(groups = "Functional")
148   public void testFindDistances_PartiallySimilar()
149   {
150     AlignFrame af = setupAlignmentView("Partially Similar");
151     AlignViewport viewport = af.getViewport();
152     AlignmentView view = viewport.getAlignmentView(false);
153
154     ScoreModelI sm = new SecondaryStructureDistanceModel();
155     sm = ScoreModels.getInstance().getScoreModel(sm.getName(),
156             af.alignPanel);
157
158     /*
159      * score = 0 + 0 + 2 + 2 = 4/4
160      */
161     SimilarityParamsI params = new SimilarityParams(false, true, true, true);
162     params.setSecondaryStructureSource("3D Structures");
163     MatrixI distances = sm.findDistances(view, params);
164     assertEquals(distances.getValue(0, 0), 0d);
165     assertEquals(distances.getValue(1, 1), 0d);
166     assertEquals(distances.getValue(0, 1), 1d); 
167     assertEquals(distances.getValue(1, 0), 1d);
168   }
169   
170   /**
171    * Verify computed distances of sequences with dissimilar secondary structures
172    */
173   @Test(groups = "Functional")
174   public void testFindDistances_notSimilar()
175   {
176     AlignFrame af = setupAlignmentView("Not Similar");
177     AlignViewport viewport = af.getViewport();
178     AlignmentView view = viewport.getAlignmentView(false);
179
180     ScoreModelI sm = new SecondaryStructureDistanceModel();
181     sm = ScoreModels.getInstance().getScoreModel(sm.getName(),
182             af.alignPanel);
183
184     /*
185      * score = 2 + 2 + 2 + 2 = 8/4
186      */
187     SimilarityParamsI params = new SimilarityParams(false, true, true, true);
188     params.setSecondaryStructureSource("3D Structures");
189     MatrixI distances = sm.findDistances(view, params);
190     assertEquals(distances.getValue(0, 0), 0d);
191     assertEquals(distances.getValue(1, 1), 0d);
192     assertEquals(distances.getValue(0, 1), 2d); 
193     assertEquals(distances.getValue(1, 0), 2d);
194   }
195   
196   /**
197    * Verify computed distances of sequences with dissimilar secondary structures
198    * with coil structure represented as null
199    */
200   @Test(groups = "Functional")
201   public void testFindDistances_withCoil()
202   {
203     AlignFrame af = setupAlignmentView("With Coil");
204     AlignViewport viewport = af.getViewport();
205     AlignmentView view = viewport.getAlignmentView(false);
206
207     ScoreModelI sm = new SecondaryStructureDistanceModel();
208     sm = ScoreModels.getInstance().getScoreModel(sm.getName(),
209             af.alignPanel);
210
211     /*
212      * score = 2 + 2 + 2 + 2 = 8/4
213      */
214     SimilarityParamsI params = new SimilarityParams(false, true, true, true);
215     params.setSecondaryStructureSource("3D Structures");
216     MatrixI distances = sm.findDistances(view, params);
217     assertEquals(distances.getValue(0, 0), 0d);
218     assertEquals(distances.getValue(1, 1), 0d);
219     assertEquals(distances.getValue(0, 1), 2d); 
220     assertEquals(distances.getValue(1, 0), 2d);
221   }
222   
223   /**
224    * Verify computed distances of sequences with gap
225    */
226   @Test(groups = "Functional")
227   public void testFindDistances_withGap()
228   {
229     AlignFrame af = setupAlignmentViewWithGap();
230     AlignViewport viewport = af.getViewport();
231     AlignmentView view = viewport.getAlignmentView(false);
232
233     ScoreModelI sm = new SecondaryStructureDistanceModel();
234     sm = ScoreModels.getInstance().getScoreModel(sm.getName(),
235             af.alignPanel);
236     
237     /*
238      * feature distance model always normalises by region width
239      * gap-gap is always included (but scores zero)
240      * the only variable parameter is 'includeGaps'
241      */
242
243     /*
244      * include gaps
245      * score = 0 + 0 + 1 + 0 = 1/4
246      */
247     SimilarityParamsI params = new SimilarityParams(false, true, true, true);
248     params.setSecondaryStructureSource("3D Structures");
249     MatrixI distances = sm.findDistances(view, params);
250     assertEquals(distances.getValue(0, 0), 0d);
251     assertEquals(distances.getValue(1, 1), 0d);
252     assertEquals(distances.getValue(0, 1), 1d/4); 
253     assertEquals(distances.getValue(1, 0), 1d/4);
254     
255     /*
256      * exclude gaps
257      * score = 0 + 0 + 0 + 0 = 0/4
258      */
259     
260     SimilarityParamsI params2 = new SimilarityParams(false, true, false, true);
261     MatrixI distances2 = sm.findDistances(view, params2);
262     assertEquals(distances2.getValue(0, 1), 0d); 
263     assertEquals(distances2.getValue(1, 0), 0d);
264   }
265   
266   
267   /**
268    * Verify computed distances of sequences with gap
269    */
270   @Test(groups = "Functional")
271   public void testFindDistances_withSSUndefinedInEitherOneSeq()
272   {
273     AlignFrame af = setupAlignmentViewWithoutSS("either");
274     AlignViewport viewport = af.getViewport();
275     AlignmentView view = viewport.getAlignmentView(false);
276
277     ScoreModelI sm = new SecondaryStructureDistanceModel();
278     sm = ScoreModels.getInstance().getScoreModel(sm.getName(),
279             af.alignPanel);
280     
281     /*
282      * feature distance model always normalises by region width
283      * gap-gap is always included (but scores zero)
284      * the only variable parameter is 'includeGaps'
285      */
286
287     /*
288      * include gaps
289      * score = 0 + 0 + 2 + 2 = 2/4
290      */
291     SimilarityParamsI params = new SimilarityParams(false, true, true, true);
292     params.setSecondaryStructureSource("3D Structures");
293     MatrixI distances = sm.findDistances(view, params);
294     assertEquals(distances.getValue(0, 0), 0d);
295     assertEquals(distances.getValue(1, 1), 0d);
296     assertEquals(distances.getValue(0, 1), 2d); 
297     assertEquals(distances.getValue(1, 0), 2d);
298     
299     /*
300      * exclude gaps
301      * score = 0 + 0 + 2 + 2 = 2/4
302      */
303     
304     SimilarityParamsI params2 = new SimilarityParams(false, true, false, true);
305     params2.setSecondaryStructureSource("3D Structures");
306     MatrixI distances2 = sm.findDistances(view, params2);
307     assertEquals(distances2.getValue(0, 1), 2d); 
308     assertEquals(distances2.getValue(1, 0), 2d);
309   }
310
311   
312   /**
313    * Verify computed distances of sequences with gap
314    */
315   @Test(groups = "Functional")
316   public void testFindDistances_withSSUndefinedInBothSeqs()
317   {
318     AlignFrame af = setupAlignmentViewWithoutSS("both");
319     AlignViewport viewport = af.getViewport();
320     AlignmentView view = viewport.getAlignmentView(false);
321
322     ScoreModelI sm = new SecondaryStructureDistanceModel();
323     sm = ScoreModels.getInstance().getScoreModel(sm.getName(),
324             af.alignPanel);
325     
326     /*
327      * feature distance model always normalises by region width
328      * gap-gap is always included (but scores zero)
329      * the only variable parameter is 'includeGaps'
330      */
331
332     /*
333      * include gaps
334      * score = 0 + 0 + 2 + 2 = 2/4
335      */
336     SimilarityParamsI params = new SimilarityParams(false, true, true, true);
337     params.setSecondaryStructureSource("3D Structures");
338     MatrixI distances = sm.findDistances(view, params);
339     assertEquals(distances.getValue(0, 0), 0d);
340     assertEquals(distances.getValue(1, 1), 0d);
341     assertEquals(distances.getValue(0, 1), 0d); 
342     assertEquals(distances.getValue(1, 0), 0d);
343     
344     /*
345      * exclude gaps
346      * score = 0 + 0 + 2 + 2 = 2/4
347      */
348     
349     SimilarityParamsI params2 = new SimilarityParams(false, true, false, true);
350     params2.setSecondaryStructureSource("3D Structures");
351     MatrixI distances2 = sm.findDistances(view, params2);
352     assertEquals(distances2.getValue(0, 1), 0d); 
353     assertEquals(distances2.getValue(1, 0), 0d);
354   }
355
356
357   
358   /**
359    * <pre>
360    * Set up
361    *   column      1 2 3 4 
362    *        seq s1 F R K S
363    *        
364    *        seq s2 F S J L
365    * </pre>
366    * 
367    * @return
368    */
369   protected AlignFrame setupAlignmentView(String similar)
370   {
371     /*
372      * sequences without gaps
373      */
374     SequenceI s1 = new Sequence("s1", "FRKS");
375     SequenceI s2 = new Sequence("s2", "FSJL");
376
377     s1.addSequenceFeature(
378             new SequenceFeature("chain", null, 1, 4, 0f, null));
379     s1.addSequenceFeature(
380             new SequenceFeature("domain", null, 1, 4, 0f, null));
381     s2.addSequenceFeature(
382             new SequenceFeature("chain", null, 1, 4, 0f, null));
383     s2.addSequenceFeature(
384             new SequenceFeature("metal", null, 1, 4, 0f, null));
385     s2.addSequenceFeature(
386             new SequenceFeature("Pfam", null, 1, 4, 0f, null));
387     
388     
389     /*
390      * Set up secondary structure annotations
391      */
392     Annotation ssE = new Annotation("","",'E',0);
393     Annotation ssH = new Annotation("","",'H',0);
394     Annotation ssC = new Annotation(".","",' ',0);
395     
396     Annotation[] anns1;
397     Annotation[] anns2;
398     
399     /* All secondary structure annotations are similar for each column
400      * Set up
401     *   column      1 2 3 4 
402     *        seq s1 F R K S
403     *            ss E H S E
404     *        
405     *        seq s2 F S J L
406     *            ss E H S E
407     */
408     if(similar == "All Similar") {
409     
410         anns1 = new Annotation[] { ssE, ssH, ssC, ssE};
411         anns2 = new Annotation[] { ssE, ssH, ssC, ssE};
412     
413     }
414     
415     /* All secondary structure annotations are dissimilar for each column
416      * Set up
417      *   column      1 2 3 4 
418      *        seq s1 F R K S
419      *            ss E E C E
420      *        
421      *        seq s2 F S J L
422      *            ss H E E C
423      */
424     else if(similar == "Not Similar") {
425         
426         anns1 = new Annotation[] { ssE, ssE, ssC, ssE};
427         anns2 = new Annotation[] { ssH, ssH, ssE, ssC};
428     
429     }
430     
431     /* All secondary structure annotations are dissimilar for each column
432      * Set up
433      *   column      1 2 3 4 
434      *        seq s1 F R K S
435      *            ss E E C E
436      *        
437      *        seq s2 F S J L
438      *            ss H E E C
439      */
440     else if(similar == "With Coil") {
441         
442       anns1 = new Annotation[] { ssE, ssE, null, ssE};
443       anns2 = new Annotation[] { ssH, ssH, ssE, null};
444     
445     }
446     
447     /*  Set up
448      *   column      1 2 3 4 
449      *        seq s1 F R K S
450      *            ss H E C E
451      *        
452      *        seq s2 F S J L
453      *            ss H E E C
454      */
455     else {
456         
457         anns1 = new Annotation[] { ssH, ssE, ssC, ssE};
458         anns2 = new Annotation[] { ssH, ssE, ssE, ssC};
459     }
460     
461     
462     AlignmentAnnotation ann1 = new AlignmentAnnotation("Secondary Structure",
463             "Secondary Structure", anns1);
464     AlignmentAnnotation ann2 = new AlignmentAnnotation("Secondary Structure",
465             "Secondary Structure", anns2);
466     
467     s1.addAlignmentAnnotation(ann1);
468     s2.addAlignmentAnnotation(ann2);    
469     
470     AlignmentI al = new Alignment(new SequenceI[] { s1, s2 });
471     AlignFrame af = new AlignFrame(al, 300, 300);
472     af.setShowSeqFeatures(true);
473     af.getFeatureRenderer().findAllFeatures(true);
474     return af;
475   }
476   
477
478   /**
479    * <pre>
480    * Set up
481    *   column      1 2 3 4 
482    *        seq s1 F R   S
483    *              SS H E   C
484    *        
485    *        seq s2 F S J L
486    *              ss H E E C
487    * </pre>
488    * 
489    * @return
490    */
491   protected AlignFrame setupAlignmentViewWithGap()
492   {
493     
494     SequenceI s1 = new Sequence("s1", "FR S");
495     SequenceI s2 = new Sequence("s2", "FSJL");
496
497     s1.addSequenceFeature(
498             new SequenceFeature("chain", null, 1, 3, 0f, null));
499     s1.addSequenceFeature(
500             new SequenceFeature("domain", null, 1, 3, 0f, null));
501     s2.addSequenceFeature(
502             new SequenceFeature("chain", null, 1, 4, 0f, null));
503     s2.addSequenceFeature(
504             new SequenceFeature("metal", null, 1, 4, 0f, null));
505     s2.addSequenceFeature(
506             new SequenceFeature("Pfam", null, 1, 4, 0f, null));
507     
508     
509     Annotation ssE = new Annotation("","",'E',0);
510     Annotation ssH = new Annotation("","",'H',0);
511     Annotation ssC = new Annotation(".","",' ',0);
512     
513     Annotation[] anns1;
514     Annotation[] anns2;
515         
516     anns1 = new Annotation[] { ssH, ssE, ssC};
517     anns2 = new Annotation[] { ssH, ssE, ssE, ssC};    
518     
519     AlignmentAnnotation ann1 = new AlignmentAnnotation("Secondary Structure",
520             "Secondary Structure", anns1);
521     AlignmentAnnotation ann2 = new AlignmentAnnotation("Secondary Structure",
522             "Secondary Structure", anns2);
523     
524     s1.addAlignmentAnnotation(ann1);
525     s2.addAlignmentAnnotation(ann2);    
526         
527     AlignmentI al = new Alignment(new SequenceI[] { s1, s2 });
528     AlignFrame af = new AlignFrame(al, 300, 300);
529     af.setShowSeqFeatures(true);
530     af.getFeatureRenderer().findAllFeatures(true);
531     
532     return af;
533   }
534   
535   protected AlignFrame setupAlignmentViewWithoutSS(String type) {
536     
537     SequenceI s1 = new Sequence("s1", "FR S");
538     SequenceI s2 = new Sequence("s2", "FSJL");
539     
540     s1.addSequenceFeature(
541             new SequenceFeature("chain", null, 1, 3, 0f, null));
542     s1.addSequenceFeature(
543             new SequenceFeature("domain", null, 1, 3, 0f, null));
544     s2.addSequenceFeature(
545             new SequenceFeature("chain", null, 1, 4, 0f, null));
546     s2.addSequenceFeature(
547             new SequenceFeature("metal", null, 1, 4, 0f, null));
548     s2.addSequenceFeature(
549             new SequenceFeature("Pfam", null, 1, 4, 0f, null));
550     
551     if(!type.equals("both")) {    
552       Annotation ssE = new Annotation("","",'E',0);
553       Annotation ssH = new Annotation("","",'H',0);
554       Annotation ssC = new Annotation(".","",' ',0);
555       
556       Annotation[] anns1;
557         
558       anns1 = new Annotation[] { ssH, ssE, ssC};
559           
560       AlignmentAnnotation ann1 = new AlignmentAnnotation("Secondary Structure",
561               "Secondary Structure", anns1);    
562   
563       s1.addAlignmentAnnotation(ann1);    
564     }
565     
566     AlignmentI al = new Alignment(new SequenceI[] { s1, s2 });
567     AlignFrame af = new AlignFrame(al, 300, 300);
568     af.setShowSeqFeatures(true);
569     af.getFeatureRenderer().findAllFeatures(true);
570     return af;
571   }
572
573 }