JAL-654_dssp formatting and javadoc
[jalview.git] / src / MCview / PDBfile.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8.2)
3  * Copyright (C) 2014 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 MCview;
22
23 import java.io.*;
24 import java.util.*;
25
26 import java.awt.*;
27
28 import jalview.analysis.AlignSeq;
29 import jalview.datamodel.*;
30 import jalview.io.FileParse;
31 import jalview.util.MessageManager;
32
33 public class PDBfile extends jalview.io.AlignFile
34 {
35   public Vector chains;
36
37   public String id;
38
39   /**
40    * set to true to add chain alignment annotation as visible annotation.
41    */
42   boolean VisibleChainAnnotation = false;
43
44   public PDBfile(String inFile, String inType) throws IOException
45   {
46     super(inFile, inType);
47   }
48
49   public PDBfile(FileParse source) throws IOException
50   {
51     super(source);
52   }
53
54   public String print()
55   {
56     return null;
57   }
58
59   public void parse() throws IOException
60   {
61     // TODO set the filename sensibly - try using data source name.
62     id = safeName(getDataName());
63
64     chains = new Vector();
65     ArrayList<SequenceI> rna = new ArrayList<SequenceI>(), prot = new ArrayList<SequenceI>();
66     PDBChain tmpchain;
67     String line = null;
68     boolean modelFlag = false;
69     boolean terFlag = false;
70     String lastID = "";
71
72     int index = 0;
73     String atomnam = null;
74     try
75     {
76       while ((line = nextLine()) != null)
77       {
78         if (line.indexOf("HEADER") == 0)
79         {
80           if (line.length() > 62)
81           {
82             String tid;
83             if (line.length() > 67)
84             {
85               tid = line.substring(62, 67).trim();
86             }
87             else
88             {
89               tid = line.substring(62).trim();
90             }
91             if (tid.length() > 0)
92             {
93               id = tid;
94             }
95             continue;
96           }
97         }
98         // Were we to do anything with SEQRES - we start it here
99         if (line.indexOf("SEQRES") == 0)
100         {
101         }
102
103         if (line.indexOf("MODEL") == 0)
104         {
105           modelFlag = true;
106         }
107
108         if (line.indexOf("TER") == 0)
109         {
110           terFlag = true;
111         }
112
113         if (modelFlag && line.indexOf("ENDMDL") == 0)
114         {
115           break;
116         }
117         if (line.indexOf("ATOM") == 0
118                 || (line.indexOf("HETATM") == 0 && !terFlag))
119         {
120           terFlag = false;
121
122           // Jalview is only interested in CA bonds????
123           atomnam = line.substring(12, 15).trim();
124           if (!atomnam.equals("CA") && !atomnam.equals("P"))
125           {
126             continue;
127           }
128
129           Atom tmpatom = new Atom(line);
130           tmpchain = findChain(tmpatom.chain);
131           if (tmpchain != null)
132           {
133             if (tmpatom.resNumIns.trim().equals(lastID))
134             {
135               // phosphorylated protein - seen both CA and P..
136               continue;
137             }
138             tmpchain.atoms.addElement(tmpatom);
139           }
140           else
141           {
142             tmpchain = new PDBChain(id, tmpatom.chain);
143             chains.addElement(tmpchain);
144             tmpchain.atoms.addElement(tmpatom);
145           }
146           lastID = tmpatom.resNumIns.trim();
147         }
148         index++;
149       }
150
151       makeResidueList();
152       makeCaBondList();
153
154       if (id == null)
155       {
156         id = inFile.getName();
157       }
158       for (int i = 0; i < chains.size(); i++)
159       {
160         SequenceI dataset = ((PDBChain) chains.elementAt(i)).sequence;
161         dataset.setName(id + "|" + dataset.getName());
162         PDBEntry entry = new PDBEntry();
163         entry.setId(id);
164         entry.setProperty(new Hashtable());
165         if (((PDBChain) chains.elementAt(i)).id != null)
166         {
167           entry.getProperty().put("CHAIN",
168                   ((PDBChain) chains.elementAt(i)).id);
169         }
170         if (inFile != null)
171         {
172           entry.setFile(inFile.getAbsolutePath());
173         }
174         else
175         {
176           // TODO: decide if we should dump the datasource to disk
177           entry.setFile(getDataName());
178         }
179         dataset.addPDBId(entry);
180         SequenceI chainseq = dataset.deriveSequence(); // PDBChain objects
181         // maintain reference to
182         // dataset
183         seqs.addElement(chainseq);
184         if (isRNA(chainseq) == true)
185         {
186           rna.add(chainseq);
187         }
188         else
189         {
190           prot.add(chainseq);
191         }
192
193         AlignmentAnnotation[] chainannot = chainseq.getAnnotation();
194
195         if (chainannot != null)
196         {
197           for (int ai = 0; ai < chainannot.length; ai++)
198           {
199
200             chainannot[ai].visible = VisibleChainAnnotation;
201             annotations.addElement(chainannot[ai]);
202           }
203         }
204       }
205       if (rna.size() > 0)
206         try
207         {
208           processPdbFileWithAnnotate3d(rna);
209         } catch (Exception x)
210         {
211           System.err
212                   .println("Exceptions when dealing with RNA in pdb file");
213           x.printStackTrace();
214
215         }
216       ;
217       if (prot.size() > 0)
218         try
219         {
220           processPdbFileWithJmol(prot);
221         } catch (Exception x)
222         {
223           System.err
224                   .println("Exceptions when dealing with RNA in pdb file");
225           x.printStackTrace();
226
227         }
228       ;
229       if (prot.size() > 0)
230         try
231         {
232           processPdbFileWithJmol(prot);
233         } catch (Exception x)
234         {
235           System.err
236                   .println("Exceptions when dealing with RNA in pdb file");
237           x.printStackTrace();
238
239         }
240       ;
241     } catch (OutOfMemoryError er)
242     {
243       System.out.println("OUT OF MEMORY LOADING PDB FILE");
244       throw new IOException(
245               MessageManager
246                       .getString("exception.outofmemory_loading_pdb_file"));
247     } catch (NumberFormatException ex)
248     {
249       if (line != null)
250       {
251         System.err.println("Couldn't read number from line:");
252         System.err.println(line);
253       }
254     }
255   }
256
257   private void processPdbFileWithJmol(ArrayList<SequenceI> prot)
258           throws Exception
259   {
260     try
261     {
262       Class cl = Class.forName("jalview.ext.jmol.PDBFileWithJmol");
263       if (cl != null)
264       {
265         Object jmf = cl.getConstructor(new Class[]
266         { FileParse.class }).newInstance(new Object[]
267         { new FileParse(getDataName(), type) });
268         Alignment al = new Alignment((SequenceI[]) cl.getMethod(
269                 "getSeqsAsArray", new Class[]
270                 {}).invoke(jmf));
271         cl.getMethod("addAnnotations", new Class[]
272         { Alignment.class }).invoke(jmf, al);
273         replaceMatchingSeqsWith(prot, al, AlignSeq.PEP);
274       }
275     } catch (ClassNotFoundException q)
276     {
277     }
278   }
279
280   private void processPdbFileWithAnnotate3d(ArrayList<SequenceI> rna)
281           throws Exception
282   {
283     // System.out.println("this is a PDB format and RNA sequence");
284     // note: we use reflection here so that the applet can compile and run
285     // without the HTTPClient bits and pieces needed for accessing Annotate3D
286     // web service
287     try
288     {
289       Class cl = Class.forName("jalview.ws.jws1.Annotate3D");
290       if (cl != null)
291       {
292         // TODO: use the PDB ID of the structure if one is available, to save
293         // bandwidth and avoid uploading the whole structure to the service
294         Object annotate3d = cl.getConstructor(new Class[]
295         {}).newInstance(new Object[]
296         {});
297         AlignmentI al = ((AlignmentI) cl.getMethod("getRNAMLFor",
298                 new Class[]
299                 { FileParse.class }).invoke(annotate3d, new Object[]
300         { new FileParse(getDataName(), type) }));
301         replaceMatchingSeqsWith(rna, al, AlignSeq.DNA);
302       }
303     } catch (ClassNotFoundException x)
304     {
305       // ignore classnotfounds - occurs in applet
306     }
307     ;
308   }
309
310   /**
311    * matches ochains against al and populates seqs with the best match between
312    * each ochain and the set in al
313    * 
314    * @param ochains
315    * @param al
316    * @param dnaOrProtein
317    */
318   private void replaceMatchingSeqsWith(ArrayList<SequenceI> ochains,
319           AlignmentI al, String dnaOrProtein)
320   {
321     if (al != null && al.getHeight() > 0)
322     {
323       ArrayList<SequenceI> matches = new ArrayList<SequenceI>();
324       ArrayList<AlignSeq> aligns = new ArrayList<AlignSeq>();
325
326       for (SequenceI sq : ochains)
327       {
328         SequenceI bestm = null;
329         AlignSeq bestaseq = null;
330         int bestscore = 0;
331         for (SequenceI msq : al.getSequences())
332         {
333           AlignSeq aseq = AlignSeq.doGlobalNWAlignment(msq, sq,
334                   dnaOrProtein);
335           if (bestm == null || aseq.getMaxScore() > bestscore)
336           {
337             bestscore = aseq.getMaxScore();
338             bestaseq = aseq;
339             bestm = msq;
340           }
341         }
342         System.out.println("Best Score for " + (matches.size() + 1) + " :"
343                 + bestscore);
344         matches.add(bestm);
345         aligns.add(bestaseq);
346         al.deleteSequence(bestm);
347       }
348       for (int p = 0, pSize = seqs.size(); p < pSize; p++)
349       {
350         SequenceI sq, sp = seqs.get(p);
351         int q;
352         if ((q = ochains.indexOf(sp)) > -1)
353         {
354           seqs.set(p, sq = matches.get(q));
355           sq.setName(sp.getName());
356           sq.setDescription(sp.getDescription());
357           sq.transferAnnotation(sp, aligns.get(q).getMappingFromS1(false));
358           int inspos = -1;
359           for (int ap = 0; ap < annotations.size();)
360           {
361             if (((AlignmentAnnotation) annotations.get(ap)).sequenceRef == sp)
362             {
363               if (inspos == -1)
364               {
365                 inspos = ap;
366               }
367               annotations.remove(ap);
368             }
369             else
370             {
371               ap++;
372             }
373           }
374           if (sq.getAnnotation() != null)
375           {
376             annotations.addAll(inspos, Arrays.asList(sq.getAnnotation()));
377           }
378         }
379       }
380     }
381   }
382
383   /**
384    * make a friendly ID string.
385    * 
386    * @param dataName
387    * @return truncated dataName to after last '/'
388    */
389   private String safeName(String dataName)
390   {
391     int p = 0;
392     while ((p = dataName.indexOf("/")) > -1 && p < dataName.length())
393     {
394       dataName = dataName.substring(p + 1);
395     }
396     return dataName;
397   }
398
399   public void makeResidueList()
400   {
401     for (int i = 0; i < chains.size(); i++)
402     {
403       ((PDBChain) chains.elementAt(i)).makeResidueList();
404     }
405   }
406
407   public void makeCaBondList()
408   {
409     for (int i = 0; i < chains.size(); i++)
410     {
411       ((PDBChain) chains.elementAt(i)).makeCaBondList();
412     }
413   }
414
415   public PDBChain findChain(String id)
416   {
417     for (int i = 0; i < chains.size(); i++)
418     {
419       if (((PDBChain) chains.elementAt(i)).id.equals(id))
420       {
421         return (PDBChain) chains.elementAt(i);
422       }
423     }
424
425     return null;
426   }
427
428   public void setChargeColours()
429   {
430     for (int i = 0; i < chains.size(); i++)
431     {
432       ((PDBChain) chains.elementAt(i)).setChargeColours();
433     }
434   }
435
436   public void setColours(jalview.schemes.ColourSchemeI cs)
437   {
438     for (int i = 0; i < chains.size(); i++)
439     {
440       ((PDBChain) chains.elementAt(i)).setChainColours(cs);
441     }
442   }
443
444   public void setChainColours()
445   {
446     for (int i = 0; i < chains.size(); i++)
447     {
448       ((PDBChain) chains.elementAt(i)).setChainColours(Color.getHSBColor(
449               1.0f / (float) i, .4f, 1.0f));
450     }
451   }
452
453   public boolean isRNA(SequenceI seqs)
454   {
455     for (int i = 0; i < seqs.getLength(); i++)
456     {
457       if ((seqs.getCharAt(i) != 'A') && (seqs.getCharAt(i) != 'C')
458               && (seqs.getCharAt(i) != 'G') && (seqs.getCharAt(i) != 'U'))
459       {
460         return false;
461       }
462     }
463
464     return true;
465
466   }
467 }