JAL-1919 fixed bug causing PDBfile test failure
[jalview.git] / src / jalview / io / StructureFile.java
1 package jalview.io;
2
3 import jalview.analysis.AlignSeq;
4 import jalview.datamodel.Alignment;
5 import jalview.datamodel.AlignmentAnnotation;
6 import jalview.datamodel.AlignmentI;
7 import jalview.datamodel.DBRefEntry;
8 import jalview.datamodel.DBRefSource;
9 import jalview.datamodel.PDBEntry;
10 import jalview.datamodel.SequenceI;
11
12 import java.awt.Color;
13 import java.io.IOException;
14 import java.lang.reflect.Constructor;
15 import java.util.Hashtable;
16 import java.util.List;
17 import java.util.Vector;
18
19 import MCview.PDBChain;
20
21 public abstract class StructureFile extends AlignFile
22 {
23
24   private String id;
25
26   /**
27    * set to true to add derived sequence annotations (temp factor read from
28    * file, or computed secondary structure) to the alignment
29    */
30   protected boolean visibleChainAnnotation = false;
31
32   /*
33    * Set true to predict secondary structure (using JMol for protein, Annotate3D
34    * for RNA)
35    */
36   protected boolean predictSecondaryStructure = true;
37
38   /*
39    * Set true (with predictSecondaryStructure=true) to predict secondary
40    * structure using an external service (currently Annotate3D for RNA only)
41    */
42   protected boolean externalSecondaryStructure = false;
43
44   private Vector<PDBChain> chains;
45
46   public StructureFile(String inFile, String type) throws IOException
47   {
48     super(inFile, type);
49   }
50
51   public StructureFile(FileParse fp) throws IOException
52   {
53     super(fp);
54   }
55
56   public StructureFile(boolean parseImmediately, String inFile, String type)
57           throws IOException
58   {
59     super(parseImmediately, inFile, type);
60   }
61
62   public StructureFile(boolean a, FileParse fp) throws IOException
63   {
64     super(a, fp);
65   }
66
67   public StructureFile()
68   {
69   }
70
71   @SuppressWarnings("rawtypes")
72   protected SequenceI postProcessChain(PDBChain chain)
73   {
74     SequenceI pdbSequence = chain.sequence;
75     pdbSequence.setName(getId() + "|" + pdbSequence.getName());
76     PDBEntry entry = new PDBEntry();
77     entry.setId(getId());
78     entry.setType(PDBEntry.Type.PDB);
79     entry.setProperty(new Hashtable());
80     if (chain.id != null)
81     {
82       entry.setChainCode(String.valueOf(chain.id));
83     }
84     if (inFile != null)
85     {
86       entry.setFile(inFile.getAbsolutePath());
87     }
88     else
89     {
90       entry.setFile(getDataName());
91     }
92
93     DBRefEntry sourceDBRef = new DBRefEntry();
94     sourceDBRef.setAccessionId(getId());
95     sourceDBRef.setSource(DBRefSource.PDB);
96     sourceDBRef.setStartRes(pdbSequence.getStart());
97     sourceDBRef.setEndRes(pdbSequence.getEnd());
98
99     SequenceI chainseq = pdbSequence.deriveSequence();
100     chainseq.setSourceDBRef(sourceDBRef);
101     chainseq.addPDBId(entry);
102     chainseq.addDBRef(sourceDBRef);
103
104     seqs.addElement(chainseq);
105
106     AlignmentAnnotation[] chainannot = chainseq.getAnnotation();
107
108     if (chainannot != null && visibleChainAnnotation)
109     {
110       for (int ai = 0; ai < chainannot.length; ai++)
111       {
112         chainannot[ai].visible = visibleChainAnnotation;
113         annotations.addElement(chainannot[ai]);
114       }
115     }
116     return chainseq;
117   }
118
119   @SuppressWarnings({ "unchecked", "rawtypes" })
120   protected void processPdbFileWithAnnotate3d(List<SequenceI> rna)
121           throws Exception
122   {
123     // System.out.println("this is a PDB format and RNA sequence");
124     // note: we use reflection here so that the applet can compile and run
125     // without the HTTPClient bits and pieces needed for accessing Annotate3D
126     // web service
127     try
128     {
129       Class cl = Class.forName("jalview.ws.jws1.Annotate3D");
130       if (cl != null)
131       {
132         // TODO: use the PDB ID of the structure if one is available, to save
133         // bandwidth and avoid uploading the whole structure to the service
134         Object annotate3d = cl.getConstructor(new Class[] {}).newInstance(
135                 new Object[] {});
136         AlignmentI al = ((AlignmentI) cl.getMethod("getRNAMLFor",
137                 new Class[] { FileParse.class }).invoke(annotate3d,
138                 new Object[] { new FileParse(getDataName(), type) }));
139         for (SequenceI sq : al.getSequences())
140         {
141           if (sq.getDatasetSequence() != null)
142           {
143             if (sq.getDatasetSequence().getAllPDBEntries() != null)
144             {
145               sq.getDatasetSequence().getAllPDBEntries().clear();
146             }
147           }
148           else
149           {
150             if (sq.getAllPDBEntries() != null)
151             {
152               sq.getAllPDBEntries().clear();
153             }
154           }
155         }
156         replaceAndUpdateChains(rna, al, AlignSeq.DNA, false);
157       }
158     } catch (ClassNotFoundException x)
159     {
160       // ignore classnotfounds - occurs in applet
161     }
162   }
163
164   @SuppressWarnings("unchecked")
165   protected void replaceAndUpdateChains(List<SequenceI> prot,
166           AlignmentI al,
167           String pep, boolean b)
168   {
169     List<List<? extends Object>> replaced = AlignSeq
170             .replaceMatchingSeqsWith(seqs, annotations, prot, al, pep,
171                     false);
172     for (PDBChain ch : getChains())
173     {
174       int p = 0;
175       for (SequenceI sq : (List<SequenceI>) replaced.get(0))
176       {
177         p++;
178         if (sq == ch.sequence || sq.getDatasetSequence() == ch.sequence)
179         {
180           p = -p;
181           break;
182         }
183       }
184       if (p < 0)
185       {
186         p = -p - 1;
187         // set shadow entry for chains
188         ch.shadow = (SequenceI) replaced.get(1).get(p);
189         ch.shadowMap = ((AlignSeq) replaced.get(2).get(p))
190                 .getMappingFromS1(false);
191       }
192     }
193   }
194
195   /**
196    * Predict secondary structure for RNA and/or protein sequences and add as
197    * annotations
198    * 
199    * @param rnaSequences
200    * @param proteinSequences
201    */
202   protected void addSecondaryStructure(List<SequenceI> rnaSequences,
203           List<SequenceI> proteinSequences)
204   {
205     /*
206      * Currently using Annotate3D for RNA, but only if the 'use external
207      * prediction' flag is set
208      */
209     if (externalSecondaryStructure && rnaSequences.size() > 0)
210     {
211       try
212       {
213         processPdbFileWithAnnotate3d(rnaSequences);
214       } catch (Exception x)
215       {
216         System.err.println("Exceptions when dealing with RNA in pdb file");
217         x.printStackTrace();
218
219       }
220     }
221
222     /*
223      * Currently using JMol PDB parser for peptide
224      */
225     if (proteinSequences.size() > 0)
226     {
227       try
228       {
229         processWithJmolParser(proteinSequences);
230       } catch (Exception x)
231       {
232         System.err
233                 .println("Exceptions from Jmol when processing data in pdb file");
234         x.printStackTrace();
235       }
236     }
237   }
238
239   @SuppressWarnings({ "unchecked", "rawtypes" })
240   private void processWithJmolParser(List<SequenceI> prot)
241           throws Exception
242   {
243     try
244     {
245
246       Class cl = Class.forName("jalview.ext.jmol.JmolParser");
247       if (cl != null)
248       {
249         final Constructor constructor = cl
250                 .getConstructor(new Class[] { FileParse.class });
251         final Object[] args = new Object[] { new FileParse(getDataName(),
252                 type) };
253         Object jmf = constructor.newInstance(args);
254         AlignmentI al = new Alignment((SequenceI[]) cl.getMethod(
255                 "getSeqsAsArray", new Class[] {}).invoke(jmf));
256         cl.getMethod("addAnnotations", new Class[] { AlignmentI.class })
257                 .invoke(jmf, al);
258         for (SequenceI sq : al.getSequences())
259         {
260           if (sq.getDatasetSequence() != null)
261           {
262             sq.getDatasetSequence().getAllPDBEntries().clear();
263           }
264           else
265           {
266             sq.getAllPDBEntries().clear();
267           }
268         }
269         replaceAndUpdateChains(prot, al, AlignSeq.PEP, false);
270       }
271     } catch (ClassNotFoundException q)
272     {
273     }
274   }
275
276   public PDBChain findChain(String id) throws Exception
277   {
278     for (PDBChain chain : getChains())
279     {
280       if (chain.id.equalsIgnoreCase(id))
281       {
282         return chain;
283       }
284     }
285     throw new Exception("PDB chain not Found!");
286   }
287
288   public void makeResidueList()
289   {
290     for (PDBChain chain : getChains())
291     {
292       chain.makeResidueList(visibleChainAnnotation);
293     }
294   }
295
296   public void makeCaBondList()
297   {
298     for (PDBChain chain : getChains())
299     {
300       chain.makeCaBondList();
301     }
302   }
303
304   public void setChargeColours()
305   {
306     for (PDBChain chain : getChains())
307     {
308       chain.setChargeColours();
309     }
310   }
311
312   public void setColours(jalview.schemes.ColourSchemeI cs)
313   {
314     for (PDBChain chain : getChains())
315     {
316       chain.setChainColours(cs);
317     }
318   }
319
320   public void setChainColours()
321   {
322     int i = 0;
323     for (PDBChain chain : getChains())
324     {
325       chain.setChainColours(Color.getHSBColor(1.0f / i++, .4f, 1.0f));
326     }
327   }
328
329   public static boolean isRNA(SequenceI seq)
330   {
331     for (char c : seq.getSequence())
332     {
333       if ((c != 'A') && (c != 'C') && (c != 'G') && (c != 'U'))
334       {
335         return false;
336       }
337     }
338     return true;
339   }
340
341   /**
342    * make a friendly ID string.
343    * 
344    * @param dataName
345    * @return truncated dataName to after last '/'
346    */
347   protected String safeName(String dataName)
348   {
349     int p = 0;
350     while ((p = dataName.indexOf("/")) > -1 && p < dataName.length())
351     {
352       dataName = dataName.substring(p + 1);
353     }
354     return dataName;
355   }
356
357   public String getId()
358   {
359     return id;
360   }
361
362   public void setId(String id)
363   {
364     this.id = id;
365   }
366
367   public Vector<PDBChain> getChains()
368   {
369     return chains;
370   }
371
372   public void setChains(Vector<PDBChain> chains)
373   {
374     this.chains = chains;
375   }
376 }