JAL-3438 spotless for 2.11.2.0
[jalview.git] / test / jalview / analysis / scoremodels / FeatureDistanceModelTest.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.AlignmentI;
30 import jalview.datamodel.AlignmentView;
31 import jalview.datamodel.Sequence;
32 import jalview.datamodel.SequenceFeature;
33 import jalview.datamodel.SequenceI;
34 import jalview.gui.AlignFrame;
35 import jalview.gui.AlignViewport;
36 import jalview.gui.JvOptionPane;
37 import jalview.io.DataSourceType;
38 import jalview.io.FileLoader;
39 import jalview.math.MatrixI;
40
41 import java.util.Arrays;
42
43 import org.testng.Assert;
44 import org.testng.annotations.BeforeClass;
45 import org.testng.annotations.Test;
46
47 public class FeatureDistanceModelTest
48 {
49
50   @BeforeClass(alwaysRun = true)
51   public void setUpJvOptionPane()
52   {
53     JvOptionPane.setInteractiveMode(false);
54     JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION);
55   }
56
57   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";
58
59   int[] sf1 = new int[] { 74, 74, 73, 73, 23, 23, -1, -1 };
60
61   int[] sf2 = new int[] { -1, -1, 74, 75, -1, -1, 76, 77 };
62
63   int[] sf3 = new int[] { -1, -1, -1, -1, -1, -1, 76, 77 };
64
65   /**
66    * <pre>
67    * Load test alignment and add features to sequences: 
68    *      FER1_MESCR FER1_SPIOL FER3_RAPSA FER1_MAIZE 
69    *  sf1     X          X          X  
70    *  sf2                X                     X 
71    *  sf3                                      X
72    * </pre>
73    * 
74    * @return
75    */
76   public AlignFrame getTestAlignmentFrame()
77   {
78     AlignFrame alf = new FileLoader(false)
79             .LoadFileWaitTillLoaded(alntestFile, DataSourceType.PASTE);
80     AlignmentI al = alf.getViewport().getAlignment();
81     Assert.assertEquals(al.getHeight(), 4);
82     Assert.assertEquals(al.getWidth(), 5);
83     for (int i = 0; i < 4; i++)
84     {
85       SequenceI ds = al.getSequenceAt(i).getDatasetSequence();
86       if (sf1[i * 2] > 0)
87       {
88         ds.addSequenceFeature(new SequenceFeature("sf1", "sf1", sf1[i * 2],
89                 sf1[i * 2 + 1], "sf1"));
90       }
91       if (sf2[i * 2] > 0)
92       {
93         ds.addSequenceFeature(new SequenceFeature("sf2", "sf2", sf2[i * 2],
94                 sf2[i * 2 + 1], "sf2"));
95       }
96       if (sf3[i * 2] > 0)
97       {
98         ds.addSequenceFeature(new SequenceFeature("sf3", "sf3", sf3[i * 2],
99                 sf3[i * 2 + 1], "sf3"));
100       }
101     }
102     alf.setShowSeqFeatures(true);
103     alf.getFeatureRenderer().setVisible("sf1");
104     alf.getFeatureRenderer().setVisible("sf2");
105     alf.getFeatureRenderer().setVisible("sf3");
106     alf.getFeatureRenderer().findAllFeatures(true);
107     Assert.assertEquals(
108             alf.getFeatureRenderer().getDisplayedFeatureTypes().size(), 3,
109             "Number of feature types");
110     assertTrue(alf.getCurrentView().areFeaturesDisplayed());
111     return alf;
112   }
113
114   @Test(groups = { "Functional" })
115   public void testFeatureScoreModel() throws Exception
116   {
117     AlignFrame alf = getTestAlignmentFrame();
118     ScoreModelI sm = new FeatureDistanceModel();
119     sm = ScoreModels.getInstance().getScoreModel(sm.getName(),
120             alf.getCurrentView().getAlignPanel());
121     alf.selectAllSequenceMenuItem_actionPerformed(null);
122
123     MatrixI dm = sm.findDistances(alf.getViewport().getAlignmentView(true),
124             SimilarityParams.Jalview);
125     assertEquals(dm.getValue(0, 2), 0d,
126             "FER1_MESCR (0) should be identical with RAPSA (2)");
127     assertTrue(dm.getValue(0, 1) > dm.getValue(0, 2),
128             "FER1_MESCR (0) should be further from SPIOL (1) than it is from RAPSA (2)");
129   }
130
131   @Test(groups = { "Functional" })
132   public void testFeatureScoreModel_hiddenFirstColumn() throws Exception
133   {
134     AlignFrame alf = getTestAlignmentFrame();
135     // hiding first two columns shouldn't affect the tree
136     alf.getViewport().hideColumns(0, 1);
137     ScoreModelI sm = new FeatureDistanceModel();
138     sm = ScoreModels.getInstance().getScoreModel(sm.getName(),
139             alf.getCurrentView().getAlignPanel());
140     alf.selectAllSequenceMenuItem_actionPerformed(null);
141     MatrixI dm = sm.findDistances(alf.getViewport().getAlignmentView(true),
142             SimilarityParams.Jalview);
143     assertEquals(dm.getValue(0, 2), 0d,
144             "FER1_MESCR (0) should be identical with RAPSA (2)");
145     assertTrue(dm.getValue(0, 1) > dm.getValue(0, 2),
146             "FER1_MESCR (0) should be further from SPIOL (1) than it is from RAPSA (2)");
147   }
148
149   @Test(groups = { "Functional" })
150   public void testFeatureScoreModel_HiddenColumns() throws Exception
151   {
152     AlignFrame alf = getTestAlignmentFrame();
153     // hide columns and check tree changes
154     alf.getViewport().hideColumns(3, 4);
155     alf.getViewport().hideColumns(0, 1);
156     // getName() can become static in Java 8
157     ScoreModelI sm = new FeatureDistanceModel();
158     sm = ScoreModels.getInstance().getScoreModel(sm.getName(),
159             alf.getCurrentView().getAlignPanel());
160     alf.selectAllSequenceMenuItem_actionPerformed(null);
161     MatrixI dm = sm.findDistances(alf.getViewport().getAlignmentView(true),
162             SimilarityParams.Jalview);
163     assertEquals(dm.getValue(0, 2), 0d,
164             "After hiding last two columns FER1_MESCR (0) should still be identical with RAPSA (2)");
165     assertEquals(dm.getValue(0, 1), 0d,
166             "After hiding last two columns FER1_MESCR (0) should now also be identical with SPIOL (1)");
167     for (int s = 0; s < 3; s++)
168     {
169       assertTrue(dm.getValue(s, 3) > 0d,
170               "After hiding last two columns "
171                       + alf.getViewport().getAlignment().getSequenceAt(s)
172                               .getName()
173                       + "(" + s
174                       + ") should still be distinct from FER1_MAIZE (3)");
175     }
176   }
177
178   /**
179    * Check findFeatureAt doesn't return contact features except at contact
180    * points TODO:move to under the FeatureRendererModel test suite
181    */
182   @Test(groups = { "Functional" })
183   public void testFindFeatureAt_PointFeature() throws Exception
184   {
185     String alignment = "a CCCCCCGGGGGGCCCCCC\n" + "b CCCCCCGGGGGGCCCCCC\n"
186             + "c CCCCCCGGGGGGCCCCCC\n";
187     AlignFrame af = new jalview.io.FileLoader(false)
188             .LoadFileWaitTillLoaded(alignment, DataSourceType.PASTE);
189     SequenceI aseq = af.getViewport().getAlignment().getSequenceAt(0);
190     SequenceFeature sf = null;
191     sf = new SequenceFeature("disulphide bond", "", 2, 5, Float.NaN, "");
192     aseq.addSequenceFeature(sf);
193     assertTrue(sf.isContactFeature());
194     af.refreshFeatureUI(true);
195     af.getFeatureRenderer().setAllVisible(Arrays.asList("disulphide bond"));
196     Assert.assertEquals(
197             af.getFeatureRenderer().getDisplayedFeatureTypes().size(), 1,
198             "Should be just one feature type displayed");
199     // step through and check for pointwise feature presence/absence
200     Assert.assertEquals(
201             af.getFeatureRenderer().findFeaturesAtColumn(aseq, 1).size(),
202             0);
203     // step through and check for pointwise feature presence/absence
204     Assert.assertEquals(
205             af.getFeatureRenderer().findFeaturesAtColumn(aseq, 2).size(),
206             1);
207     // step through and check for pointwise feature presence/absence
208     Assert.assertEquals(
209             af.getFeatureRenderer().findFeaturesAtColumn(aseq, 3).size(),
210             0);
211     // step through and check for pointwise feature presence/absence
212     Assert.assertEquals(
213             af.getFeatureRenderer().findFeaturesAtColumn(aseq, 4).size(),
214             0);
215     // step through and check for pointwise feature presence/absence
216     Assert.assertEquals(
217             af.getFeatureRenderer().findFeaturesAtColumn(aseq, 5).size(),
218             1);
219     // step through and check for pointwise feature presence/absence
220     Assert.assertEquals(
221             af.getFeatureRenderer().findFeaturesAtColumn(aseq, 6).size(),
222             0);
223   }
224
225   @Test(groups = { "Functional" })
226   public void testFindDistances() throws Exception
227   {
228     String seqs = ">s1\nABCDE\n>seq2\nABCDE\n";
229     AlignFrame alf = new FileLoader().LoadFileWaitTillLoaded(seqs,
230             DataSourceType.PASTE);
231     SequenceI s1 = alf.getViewport().getAlignment().getSequenceAt(0);
232     SequenceI s2 = alf.getViewport().getAlignment().getSequenceAt(1);
233
234     /*
235      * set domain and variant features thus:
236      *     ----5
237      *  s1 ddd..
238      *  s1 .vvv.
239      *  s1 ..vvv    
240      *  s2 .ddd. 
241      *  s2 vv..v
242      *  The number of unshared feature types per column is
243      *     20120 (two features of the same type doesn't affect score)
244      *  giving an average (pairwise distance) of 5/5 or 1.0 
245      */
246     s1.addSequenceFeature(
247             new SequenceFeature("domain", null, 1, 3, 0f, null));
248     s1.addSequenceFeature(
249             new SequenceFeature("variant", null, 2, 4, 0f, null));
250     s1.addSequenceFeature(
251             new SequenceFeature("variant", null, 3, 5, 0f, null));
252     s2.addSequenceFeature(
253             new SequenceFeature("domain", null, 2, 4, 0f, null));
254     s2.addSequenceFeature(
255             new SequenceFeature("variant", null, 1, 2, 0f, null));
256     s2.addSequenceFeature(
257             new SequenceFeature("variant", null, 5, 5, 0f, null));
258     alf.setShowSeqFeatures(true);
259     alf.getFeatureRenderer().findAllFeatures(true);
260
261     ScoreModelI sm = new FeatureDistanceModel();
262     sm = ScoreModels.getInstance().getScoreModel(sm.getName(),
263             alf.getCurrentView().getAlignPanel());
264     alf.selectAllSequenceMenuItem_actionPerformed(null);
265
266     AlignmentView alignmentView = alf.getViewport().getAlignmentView(true);
267     MatrixI distances = sm.findDistances(alignmentView,
268             SimilarityParams.Jalview);
269     assertEquals(distances.width(), 2);
270     assertEquals(distances.height(), 2);
271     assertEquals(distances.getValue(0, 0), 0d);
272     assertEquals(distances.getValue(1, 1), 0d);
273
274     assertEquals(distances.getValue(0, 1), 1d,
275             "expected identical pairs. (check normalisation for similarity score)");
276     assertEquals(distances.getValue(1, 0), 1d);
277   }
278
279   /**
280    * Verify computed distances with varying parameter options
281    */
282   @Test(groups = "Functional")
283   public void testFindDistances_withParams()
284   {
285     AlignFrame af = setupAlignmentView();
286     AlignViewport viewport = af.getViewport();
287     AlignmentView view = viewport.getAlignmentView(false);
288
289     ScoreModelI sm = new FeatureDistanceModel();
290     sm = ScoreModels.getInstance().getScoreModel(sm.getName(),
291             af.alignPanel);
292
293     /*
294      * feature distance model always normalises by region width
295      * gap-gap is always included (but scores zero)
296      * the only variable parameter is 'includeGaps'
297      */
298
299     /*
300      * include gaps
301      * score = 3 + 3 + 0 + 2 + 3 + 2 = 13/6
302      */
303     SimilarityParamsI params = new SimilarityParams(true, true, true, true);
304     MatrixI distances = sm.findDistances(view, params);
305     assertEquals(distances.getValue(0, 0), 0d);
306     assertEquals(distances.getValue(1, 1), 0d);
307     assertEquals(distances.getValue(0, 1), 13d / 6); // should be 13d/6
308     assertEquals(distances.getValue(1, 0), 13d / 6);
309
310     /*
311      * exclude gaps
312      * score = 3 + 3 + 0 + 0 + 0 + 0 = 6/6
313      */
314     params = new SimilarityParams(true, true, false, true);
315     distances = sm.findDistances(view, params);
316     assertEquals(distances.getValue(0, 1), 6d / 6);// should be 6d/6
317   }
318
319   /**
320    * <pre>
321    * Set up
322    *   column      1 2 3 4 5 6
323    *        seq s1 F R - K - S
324    *        seq s2 F S - - L
325    *   s1 chain    c c   c   c
326    *   s1 domain   d d   d   d
327    *   s2 chain    c c     c
328    *   s2 metal    m m     m
329    *   s2 Pfam     P P     P
330    *      scores:  3 3 0 2 3 2
331    * </pre>
332    * 
333    * @return
334    */
335   protected AlignFrame setupAlignmentView()
336   {
337     /*
338      * for now, using space for gap to match callers of
339      * AlignmentView.getSequenceStrings()
340      * may change this to '-' (with corresponding change to matrices)
341      */
342     SequenceI s1 = new Sequence("s1", "FR K S");
343     SequenceI s2 = new Sequence("s2", "FS  L");
344
345     s1.addSequenceFeature(
346             new SequenceFeature("chain", null, 1, 4, 0f, null));
347     s1.addSequenceFeature(
348             new SequenceFeature("domain", null, 1, 4, 0f, null));
349     s2.addSequenceFeature(
350             new SequenceFeature("chain", null, 1, 3, 0f, null));
351     s2.addSequenceFeature(
352             new SequenceFeature("metal", null, 1, 3, 0f, null));
353     s2.addSequenceFeature(
354             new SequenceFeature("Pfam", null, 1, 3, 0f, null));
355     AlignmentI al = new Alignment(new SequenceI[] { s1, s2 });
356     AlignFrame af = new AlignFrame(al, 300, 300);
357     af.setShowSeqFeatures(true);
358     af.getFeatureRenderer().findAllFeatures(true);
359     return af;
360   }
361
362 }