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