3dd567e62b099b3d722863507aa88afaaab1562f
[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(MessageManager.getString("exception.outofmemory_loading_pdb_file"));
245     } catch (NumberFormatException ex)
246     {
247       if (line != null)
248       {
249         System.err.println("Couldn't read number from line:");
250         System.err.println(line);
251       }
252     }
253   }
254
255   private void processPdbFileWithJmol(ArrayList<SequenceI> prot)
256           throws Exception
257   {
258     try
259     {
260       Class cl = Class.forName("jalview.ext.jmol.PDBFileWithJmol");
261       if (cl != null)
262       {
263         Object jmf = cl.getConstructor(new Class[]
264         { FileParse.class }).newInstance(new Object[]
265         { new FileParse(getDataName(), type) });
266         Alignment al = new Alignment((SequenceI[]) cl.getMethod(
267                 "getSeqsAsArray", new Class[]
268                 {}).invoke(jmf));
269         cl.getMethod("addAnnotations", new Class[]
270         { Alignment.class }).invoke(jmf, al);
271         replaceMatchingSeqsWith(prot, al, AlignSeq.PEP);
272       }
273     } catch (ClassNotFoundException q)
274     {
275     }
276   }
277
278   private void processPdbFileWithAnnotate3d(ArrayList<SequenceI> rna)
279           throws Exception
280   {
281     // System.out.println("this is a PDB format and RNA sequence");
282     // note: we use reflection here so that the applet can compile and run
283     // without the HTTPClient bits and pieces needed for accessing Annotate3D
284     // web service
285     try
286     {
287       Class cl = Class.forName("jalview.ws.jws1.Annotate3D");
288       if (cl != null)
289       {
290         // TODO: use the PDB ID of the structure if one is available, to save
291         // bandwidth and avoid uploading the whole structure to the service
292         Object annotate3d = cl.getConstructor(new Class[]
293         {}).newInstance(new Object[]
294         {});
295         AlignmentI al = ((AlignmentI) cl.getMethod("getRNAMLFor",
296                 new Class[]
297                 { FileParse.class }).invoke(annotate3d, new Object[]
298         { new FileParse(getDataName(), type) }));
299         replaceMatchingSeqsWith(rna, al, AlignSeq.DNA);
300       }
301     } catch (ClassNotFoundException x)
302     {
303       // ignore classnotfounds - occurs in applet
304     }
305     ;
306   }
307
308   private void replaceMatchingSeqsWith(ArrayList<SequenceI> ochains,
309           AlignmentI al, String dnaOrProtein)
310   {
311     if (al != null && al.getHeight() > 0)
312     {
313       ArrayList<SequenceI> matches = new ArrayList<SequenceI>();
314       ArrayList<AlignSeq> aligns = new ArrayList<AlignSeq>();
315
316       for (SequenceI sq : ochains)
317       {
318         SequenceI bestm = null;
319         AlignSeq bestaseq = null;
320         int bestscore = 0;
321         for (SequenceI msq : al.getSequences())
322         {
323           AlignSeq aseq = AlignSeq.doGlobalNWAlignment(msq, sq,
324                   dnaOrProtein);
325           if (bestm == null || aseq.getMaxScore() > bestscore)
326           {
327             bestscore = aseq.getMaxScore();
328             bestaseq = aseq;
329             bestm = msq;
330           }
331         }
332         System.out.println("Best Score for " + (matches.size() + 1) + " :"
333                 + bestscore);
334         matches.add(bestm);
335         aligns.add(bestaseq);
336         al.deleteSequence(bestm);
337       }
338       for (int p = 0, pSize = seqs.size(); p < pSize; p++)
339       {
340         SequenceI sq, sp = seqs.get(p);
341         int q;
342         if ((q = ochains.indexOf(sp)) > -1)
343         {
344           seqs.set(p, sq = matches.get(q));
345           sq.setName(sp.getName());
346           sq.setDescription(sp.getDescription());
347           sq.transferAnnotation(sp, aligns.get(q).getMappingFromS1(false));
348           int inspos = -1;
349           for (int ap = 0; ap < annotations.size();)
350           {
351             if (((AlignmentAnnotation) annotations.get(ap)).sequenceRef == sp)
352             {
353               if (inspos == -1)
354               {
355                 inspos = ap;
356               }
357               annotations.remove(ap);
358             }
359             else
360             {
361               ap++;
362             }
363           }
364           if (sq.getAnnotation() != null)
365           {
366             annotations.addAll(inspos, Arrays.asList(sq.getAnnotation()));
367           }
368         }
369       }
370     }
371   }
372
373   /**
374    * make a friendly ID string.
375    * 
376    * @param dataName
377    * @return truncated dataName to after last '/'
378    */
379   private String safeName(String dataName)
380   {
381     int p = 0;
382     while ((p = dataName.indexOf("/")) > -1 && p < dataName.length())
383     {
384       dataName = dataName.substring(p + 1);
385     }
386     return dataName;
387   }
388
389   public void makeResidueList()
390   {
391     for (int i = 0; i < chains.size(); i++)
392     {
393       ((PDBChain) chains.elementAt(i)).makeResidueList();
394     }
395   }
396
397   public void makeCaBondList()
398   {
399     for (int i = 0; i < chains.size(); i++)
400     {
401       ((PDBChain) chains.elementAt(i)).makeCaBondList();
402     }
403   }
404
405   public PDBChain findChain(String id)
406   {
407     for (int i = 0; i < chains.size(); i++)
408     {
409       if (((PDBChain) chains.elementAt(i)).id.equals(id))
410       {
411         return (PDBChain) chains.elementAt(i);
412       }
413     }
414
415     return null;
416   }
417
418   public void setChargeColours()
419   {
420     for (int i = 0; i < chains.size(); i++)
421     {
422       ((PDBChain) chains.elementAt(i)).setChargeColours();
423     }
424   }
425
426   public void setColours(jalview.schemes.ColourSchemeI cs)
427   {
428     for (int i = 0; i < chains.size(); i++)
429     {
430       ((PDBChain) chains.elementAt(i)).setChainColours(cs);
431     }
432   }
433
434   public void setChainColours()
435   {
436     for (int i = 0; i < chains.size(); i++)
437     {
438       ((PDBChain) chains.elementAt(i)).setChainColours(Color.getHSBColor(
439               1.0f / (float) i, .4f, 1.0f));
440     }
441   }
442
443   public boolean isRNA(SequenceI seqs)
444   {
445     for (int i = 0; i < seqs.getLength(); i++)
446     {
447       if ((seqs.getCharAt(i) != 'A') && (seqs.getCharAt(i) != 'C')
448               && (seqs.getCharAt(i) != 'G') && (seqs.getCharAt(i) != 'U'))
449       {
450         return false;
451       }
452     }
453
454     return true;
455
456   }
457 }