1970ff2bf699d68694d99ec18b0a5747dc4aaa8c
[jalview.git] / test / jalview / structure / Mapping.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.structure;
22
23 import static org.testng.AssertJUnit.assertEquals;
24 import static org.testng.AssertJUnit.assertTrue;
25
26 import jalview.bin.Cache;
27 import jalview.datamodel.AlignmentAnnotation;
28 import jalview.datamodel.Annotation;
29 import jalview.datamodel.Sequence;
30 import jalview.datamodel.SequenceI;
31 import jalview.gui.AlignFrame;
32 import jalview.gui.JvOptionPane;
33 import jalview.io.DataSourceType;
34 import jalview.io.FileFormat;
35 import jalview.io.FileLoader;
36 import jalview.io.StructureFile;
37
38 import org.testng.Assert;
39 import org.testng.AssertJUnit;
40 import org.testng.annotations.BeforeClass;
41 import org.testng.annotations.Test;
42
43 public class Mapping
44 {
45   @BeforeClass(alwaysRun = true)
46   public void setUp()
47   {
48     Cache.initLogger();
49   }
50
51   @BeforeClass(alwaysRun = true)
52   public void setUpJvOptionPane()
53   {
54     JvOptionPane.setInteractiveMode(false);
55     JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION);
56   }
57
58   /*
59    * more test data
60    * 
61    * 1QCF|A/101-121 SFQKGDQMVVLEESGEWWKAR Ser 114 jumps to Gly 116 at position
62    * 115 in PDB Res Numbering secondary structure numbers in jmol seem to be in
63    * msd numbering, not pdb res numbering.
64    */
65   @Test(groups = { "Functional" }, enabled = false)
66   public void pdbEntryPositionMap() throws Exception
67   {
68     Assert.fail("This test intentionally left to fail");
69     for (int offset = 0; offset < 20; offset += 6)
70     {
71       // check we put the secondary structure in the right position
72       Sequence uprot = new Sequence("TheProtSeq",
73               "DAWEIPRESLKLEKKLGAGQFGEVWMATYNKHTKVAVKTMKPGSMSVEAFLAEANVMKTL");
74       uprot.setStart(offset + 258); // make it harder - create a fake
75                                     // relocation problem for jalview to
76                                     // deal with
77       uprot.setEnd(uprot.getStart() + uprot.getLength() - 1);
78       // original numbers taken from
79       // http://www.ebi.ac.uk/pdbe-srv/view/entry/1qcf/secondary.html
80       // these are in numbering relative to the subsequence above
81       int coils[] = { 266, 275, 278, 287, 289, 298, 302, 316 }, helices[] = new int[]
82       { 303, 315 }, sheets[] = new int[] { 267, 268, 269, 270 };
83
84       StructureSelectionManager ssm = StructureSelectionManager
85               .getStructureSelectionManager(null);
86       StructureFile pmap = ssm.setMapping(true, new SequenceI[] { uprot },
87               new String[] { "A" }, "test/jalview/ext/jmol/1QCF.pdb",
88               DataSourceType.FILE);
89       assertTrue(pmap != null);
90       SequenceI protseq = pmap.getSeqsAsArray()[0];
91       AlignmentAnnotation pstra = protseq
92               .getAnnotation("Secondary Structure")[0];
93       int pinds, pinde;
94       pstra.restrict((pinds = protseq.findIndex(258) - 1),
95               pinde = (protseq.findIndex(317) - 1));
96       int op;
97       System.out.println("PDB Annot");
98       for (char c : protseq.getSubSequence(pinds, pinde).getSequence())
99       {
100         System.out.print(c + ", ");
101       }
102       System.out.println("\n" + pstra + "\n\nsubsequence\n");
103       for (char c : uprot.getSequence())
104       {
105         System.out.print(c + ", ");
106       }
107       System.out.println("");
108       for (AlignmentAnnotation ss : uprot
109               .getAnnotation("Secondary Structure"))
110       {
111         ss.adjustForAlignment();
112         System.out.println("Uniprot Annot\n" + ss);
113         assertTrue(ss.hasIcons);
114         char expected = 'H';
115         for (int p : helices)
116         {
117           Annotation a = ss.annotations[op = (uprot.findIndex(offset + p) - 1)];
118           assertTrue(
119                   "Expected a helix at position " + p + uprot.getCharAt(op)
120                           + " but got coil", a != null);
121           assertEquals("Expected a helix at position " + p,
122                   a.secondaryStructure, expected);
123         }
124         expected = 'E';
125         for (int p : sheets)
126         {
127           Annotation a = ss.annotations[uprot.findIndex(offset + p) - 1];
128           assertTrue(
129                   "Expected a strand at position " + p + " but got coil",
130                   a != null);
131           assertEquals("Expected a strand at position " + p,
132                   a.secondaryStructure, expected);
133         }
134         expected = ' ';
135         for (int p : coils)
136         {
137           Annotation a = ss.annotations[uprot.findIndex(offset + p) - 1];
138           assertTrue("Expected coil at position " + p + " but got "
139                   + a.secondaryStructure, a == null);
140         }
141       }
142     }
143   }
144
145   @Test(groups = { "Functional" }, enabled = false)
146   public void testPDBentryMapping() throws Exception
147   {
148     Assert.fail("This test intentionally left to fail");
149     Sequence sq = new Sequence(
150             "1GAQ A subseq 126 to 219",
151             "EIVKGVCSNFLCDLQPGDNVQITGPVGKEMLMPKDPNATIIMLATGTGIAPFRSFLWKMFFEKHDDYKFNGLGWLFLGVPTSSSLLYKEEFGKM");
152     Sequence sq1 = new Sequence(sq);
153     String inFile;
154     StructureSelectionManager ssm = StructureSelectionManager
155             .getStructureSelectionManager(null);
156     // Associate the 1GAQ pdb file with the subsequence 'imported' from another
157     // source
158     StructureFile pde = ssm.setMapping(true, new SequenceI[] { sq },
159             new String[]
160     { "A" }, inFile = "examples/1gaq.txt", DataSourceType.FILE);
161     assertTrue("PDB File couldn't be found", pde != null);
162     StructureMapping[] mp = ssm.getMapping(inFile);
163     assertTrue("No mappings made.", mp != null && mp.length > 0);
164     int nsecStr = 0, nsTemp = 0;
165     // test for presence of transferred annotation on sequence
166     for (AlignmentAnnotation alan : sq.getAnnotation())
167     {
168       if (alan.hasIcons)
169       {
170         nsecStr++;
171       }
172       if (alan.graph == alan.LINE_GRAPH)
173       {
174         nsTemp++;
175       }
176     }
177     assertEquals(
178             "Only one secondary structure should be transferred to associated sequence.",
179             1, nsecStr);
180     assertEquals(
181             "Only two line graphs should be transferred to associated sequence.",
182             2, nsTemp);
183     // Now test the transfer function and compare annotated positions
184     for (StructureMapping origMap : mp)
185     {
186       if (origMap.getSequence() == sq)
187       {
188         assertEquals("Mapping was incomplete.", sq.getLength() - 1,
189                 (origMap.getPDBResNum(sq.getEnd()) - origMap
190                         .getPDBResNum(sq.getStart())));
191         // sanity check - if this fails, mapping from first position in sequence
192         // we want to transfer to is not where we expect
193         assertEquals(1, origMap.getSeqPos(126));
194         SequenceI firstChain = pde.getSeqs().get(0);
195         // Compare the annotated positions on the PDB chain sequence with the
196         // annotation on the associated sequence
197         for (AlignmentAnnotation alan : firstChain.getAnnotation())
198         {
199           AlignmentAnnotation transfer = origMap.transfer(alan);
200           System.out.println("pdb:" + firstChain.getSequenceAsString());
201           System.out.println("ann:" + alan.toString());
202           System.out.println("pdb:" + sq.getSequenceAsString());
203           System.out.println("ann:" + transfer.toString());
204
205           for (int p = 0, pSize = firstChain.getLength(); p < pSize; p++)
206           {
207             // walk along the pdb chain's jalview sequence
208             int rseqpos;
209             int fpos = origMap.getSeqPos(rseqpos = firstChain
210                     .findPosition(p));
211             // only look at positions where there is a corresponding position in
212             // mapping
213             if (fpos < 1)
214             {
215               continue;
216             }
217             // p is index into PDB residue entries
218             // rseqpos is pdb sequence position for position p
219             // fpos is sequence position for associated position for rseqpos
220             // tanpos is the column for the mapped sequence position
221             int tanpos = sq.findIndex(fpos) - 1;
222             if (tanpos < 0 || transfer.annotations.length <= tanpos)
223             {
224               // gone beyond mapping to the sequence
225               break;
226             }
227
228             Annotation a = transfer.annotations[tanpos], b = alan.annotations[p];
229             assertEquals("Non-equivalent annotation element at " + p + "("
230                     + rseqpos + ")" + " expected at " + fpos + " (alIndex "
231                     + tanpos + ")", a == null ? a : a.toString(),
232                     b == null ? b : b.toString());
233             System.out.print("(" + a + "|" + b + ")");
234           }
235
236         }
237       }
238     }
239   }
240
241   /**
242    * corner case for pdb mapping - revealed a problem with the AlignSeq->Mapping
243    * transform
244    * 
245    */
246   @Test(groups = { "Functional" })
247   public void mapFer1From3W5V() throws Exception
248   {
249     AlignFrame seqf = new FileLoader(false)
250             .LoadFileWaitTillLoaded(
251                     ">FER1_MAIZE/1-150 Ferredoxin-1, chloroplast precursor\nMATVLGSPRAPAFFFSSSSLRAAPAPTAVALPAAKVGIMGRSASSRRRLRAQATYNVKLITPEGEVELQVPD\nDVYILDQAEEDGIDLPYSCRAGSCSSCAGKVVSGSVDQSDQSYLDDGQIADGWVLTCHAYPTSDVVIETHKE\nEELTGA",
252                     DataSourceType.PASTE, FileFormat.Fasta);
253     SequenceI newseq = seqf.getViewport().getAlignment().getSequenceAt(0);
254     StructureSelectionManager ssm = StructureSelectionManager
255             .getStructureSelectionManager(null);
256     StructureFile pmap = ssm.setMapping(true, new SequenceI[] { newseq },
257             new String[] { null }, "examples/3W5V.pdb",
258             DataSourceType.FILE);
259     if (pmap == null)
260     {
261       AssertJUnit.fail("Couldn't make a mapping for 3W5V to FER1_MAIZE");
262     }
263   }
264
265   /**
266    * compare reference annotation for imported pdb sequence to identical
267    * seuqence with transferred annotation from mapped pdb file
268    */
269   @Test(groups = { "Functional" })
270   public void compareTransferredToRefPDBAnnot() throws Exception
271   {
272     StructureImportSettings.setProcessSecondaryStructure(true);
273     StructureImportSettings.setVisibleChainAnnotation(true);
274     StructureImportSettings.setShowSeqFeatures(true);
275     AlignFrame ref = new FileLoader(false)
276             .LoadFileWaitTillLoaded("test/jalview/ext/jmol/1QCF.pdb",
277                     DataSourceType.FILE);
278     SequenceI refseq = ref.getViewport().getAlignment().getSequenceAt(0);
279     SequenceI newseq = new Sequence(refseq.getName() + "Copy",
280             refseq.getSequenceAsString());
281     // make it harder by shifting the copy vs the reference
282     newseq.setStart(refseq.getStart() + 25);
283     newseq.setEnd(refseq.getLength() + 25 + refseq.getStart());
284     StructureSelectionManager ssm = StructureSelectionManager
285             .getStructureSelectionManager(null);
286     ssm.setProcessSecondaryStructure(true);
287     ssm.setAddTempFacAnnot(true);
288     StructureFile pmap = ssm.setMapping(true, new SequenceI[] { newseq },
289             new String[] { null }, "test/jalview/ext/jmol/1QCF.pdb",
290             DataSourceType.FILE);
291     assertTrue(pmap != null);
292     assertEquals("Original and copied sequence of different lengths.",
293             refseq.getLength(), newseq.getLength());
294     assertTrue(refseq.getAnnotation() != null
295             && refseq.getAnnotation().length > 0);
296     assertTrue(newseq.getAnnotation() != null
297             && newseq.getAnnotation().length > 0);
298     for (AlignmentAnnotation oannot : refseq.getAnnotation())
299     {
300       for (AlignmentAnnotation tannot : newseq.getAnnotation(oannot.label))
301       {
302         for (int p = 0, pSize = refseq.getLength(); p < pSize; p++)
303         {
304           Annotation orig = oannot.annotations[p], tran = tannot.annotations[p];
305           assertTrue("Mismatch: coil and non coil site " + p, orig == tran
306                   || orig != null && tran != null);
307           if (tran != null)
308           {
309             assertEquals("Mismatch in secondary structure at site " + p,
310                     tran.secondaryStructure, orig.secondaryStructure);
311           }
312         }
313       }
314     }
315   }
316 }