JAL-1919 initial support for mmCIF using JMol API. Created an Abstract class - Struct...
[jalview.git] / src / MCview / PDBfile.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 MCview;
22
23 import jalview.analysis.AlignSeq;
24 import jalview.datamodel.Alignment;
25 import jalview.datamodel.AlignmentAnnotation;
26 import jalview.datamodel.AlignmentI;
27 import jalview.datamodel.SequenceI;
28 import jalview.io.FileParse;
29 import jalview.io.StructureFile;
30 import jalview.util.MessageManager;
31
32 import java.io.IOException;
33 import java.lang.reflect.Constructor;
34 import java.util.ArrayList;
35 import java.util.Hashtable;
36 import java.util.List;
37 import java.util.Vector;
38
39 public class PDBfile extends StructureFile
40 {
41   private static String CALC_ID_PREFIX = "JalviewPDB";
42
43   public PDBfile(boolean addAlignmentAnnotations,
44           boolean predictSecondaryStructure, boolean externalSecStr)
45   {
46     super();
47     this.visibleChainAnnotation = addAlignmentAnnotations;
48     this.predictSecondaryStructure = predictSecondaryStructure;
49     this.externalSecondaryStructure = externalSecStr;
50   }
51
52   public PDBfile(boolean addAlignmentAnnotations,
53           boolean predictSecondaryStructure, boolean externalSecStr,
54           String file, String protocol) throws IOException
55   {
56     super(false, file, protocol);
57     this.visibleChainAnnotation = addAlignmentAnnotations;
58     this.predictSecondaryStructure = predictSecondaryStructure;
59     this.externalSecondaryStructure = externalSecStr;
60     doParse();
61   }
62
63   public PDBfile(boolean addAlignmentAnnotations,
64           boolean predictSecondaryStructure, boolean externalSecStr,
65           FileParse source) throws IOException
66   {
67     super(false, source);
68     this.visibleChainAnnotation = addAlignmentAnnotations;
69     this.predictSecondaryStructure = predictSecondaryStructure;
70     this.externalSecondaryStructure = externalSecStr;
71     doParse();
72   }
73
74   @Override
75   public String print()
76   {
77     return null;
78   }
79
80   @Override
81   public void parse() throws IOException
82   {
83     // TODO set the filename sensibly - try using data source name.
84     setId(safeName(getDataName()));
85
86     setChains(new Vector<PDBChain>());
87     List<SequenceI> rna = new ArrayList<SequenceI>();
88     List<SequenceI> prot = new ArrayList<SequenceI>();
89     PDBChain tmpchain;
90     String line = null;
91     boolean modelFlag = false;
92     boolean terFlag = false;
93     String lastID = "";
94
95     int indexx = 0;
96     String atomnam = null;
97     try
98     {
99       while ((line = nextLine()) != null)
100       {
101         if (line.indexOf("HEADER") == 0)
102         {
103           if (line.length() > 62)
104           {
105             String tid;
106             if (line.length() > 67)
107             {
108               tid = line.substring(62, 67).trim();
109             }
110             else
111             {
112               tid = line.substring(62).trim();
113             }
114             if (tid.length() > 0)
115             {
116               setId(tid);
117             }
118             continue;
119           }
120         }
121         // Were we to do anything with SEQRES - we start it here
122         if (line.indexOf("SEQRES") == 0)
123         {
124         }
125
126         if (line.indexOf("MODEL") == 0)
127         {
128           modelFlag = true;
129         }
130
131         if (line.indexOf("TER") == 0)
132         {
133           terFlag = true;
134         }
135
136         if (modelFlag && line.indexOf("ENDMDL") == 0)
137         {
138           break;
139         }
140         if (line.indexOf("ATOM") == 0
141                 || (line.indexOf("HETATM") == 0 && !terFlag))
142         {
143           terFlag = false;
144
145           // Jalview is only interested in CA bonds????
146           atomnam = line.substring(12, 15).trim();
147           if (!atomnam.equals("CA") && !atomnam.equals("P"))
148           {
149             continue;
150           }
151
152           Atom tmpatom = new Atom(line);
153           try
154           {
155           tmpchain = findChain(tmpatom.chain);
156             if (tmpatom.resNumIns.trim().equals(lastID))
157             {
158               // phosphorylated protein - seen both CA and P..
159               continue;
160             }
161             tmpchain.atoms.addElement(tmpatom);
162           } catch (Exception e)
163           {
164             tmpchain = new PDBChain(getId(), tmpatom.chain);
165             getChains().add(tmpchain);
166             tmpchain.atoms.addElement(tmpatom);
167           }
168           lastID = tmpatom.resNumIns.trim();
169         }
170         index++;
171       }
172
173       makeResidueList();
174       makeCaBondList();
175
176       if (getId() == null)
177       {
178         setId(inFile.getName());
179       }
180       for (PDBChain chain : getChains())
181       {
182         SequenceI chainseq = postProcessChain(chain);
183         if (isRNA(chainseq))
184         {
185           rna.add(chainseq);
186         }
187         else
188         {
189           prot.add(chainseq);
190         }
191       }
192       if (predictSecondaryStructure)
193       {
194         predictSecondaryStructure(rna, prot);
195       }
196     } catch (OutOfMemoryError er)
197     {
198       System.out.println("OUT OF MEMORY LOADING PDB FILE");
199       throw new IOException(
200               MessageManager
201                       .getString("exception.outofmemory_loading_pdb_file"));
202     } catch (NumberFormatException ex)
203     {
204       if (line != null)
205       {
206         System.err.println("Couldn't read number from line:");
207         System.err.println(line);
208       }
209     }
210     markCalcIds();
211   }
212
213   /**
214    * Predict secondary structure for RNA and/or protein sequences and add as
215    * annotations
216    * 
217    * @param rnaSequences
218    * @param proteinSequences
219    */
220   protected void predictSecondaryStructure(List<SequenceI> rnaSequences,
221           List<SequenceI> proteinSequences)
222   {
223     /*
224      * Currently using Annotate3D for RNA, but only if the 'use external
225      * prediction' flag is set
226      */
227     if (externalSecondaryStructure && rnaSequences.size() > 0)
228     {
229       try
230       {
231         processPdbFileWithAnnotate3d(rnaSequences);
232       } catch (Exception x)
233       {
234         System.err.println("Exceptions when dealing with RNA in pdb file");
235         x.printStackTrace();
236
237       }
238     }
239
240     /*
241      * Currently using JMol PDB parser for peptide
242      */
243     if (proteinSequences.size() > 0)
244     {
245       try
246       {
247         processPdbFileWithJmol(proteinSequences);
248       } catch (Exception x)
249       {
250         System.err
251                 .println("Exceptions from Jmol when processing data in pdb file");
252         x.printStackTrace();
253       }
254     }
255   }
256
257   /**
258    * Process a parsed chain to construct and return a Sequence, and add it to
259    * the list of sequences parsed.
260    * 
261    * @param chain
262    * @return
263    */
264
265   public static boolean isCalcIdHandled(String calcId)
266   {
267     return calcId != null && (CALC_ID_PREFIX.equals(calcId));
268   }
269
270   public static boolean isCalcIdForFile(AlignmentAnnotation alan,
271           String pdbFile)
272   {
273     return alan.getCalcId() != null
274             && CALC_ID_PREFIX.equals(alan.getCalcId())
275             && pdbFile.equals(alan.getProperty("PDBID"));
276   }
277
278   public static String relocateCalcId(String calcId,
279           Hashtable<String, String> alreadyLoadedPDB) throws Exception
280   {
281     int s = CALC_ID_PREFIX.length(), end = calcId
282             .indexOf(CALC_ID_PREFIX, s);
283     String between = calcId.substring(s, end - 1);
284     return CALC_ID_PREFIX + alreadyLoadedPDB.get(between) + ":"
285             + calcId.substring(end);
286   }
287
288   private void markCalcIds()
289   {
290     for (SequenceI sq : seqs)
291     {
292       if (sq.getAnnotation() != null)
293       {
294         for (AlignmentAnnotation aa : sq.getAnnotation())
295         {
296           String oldId = aa.getCalcId();
297           if (oldId == null)
298           {
299             oldId = "";
300           }
301           aa.setCalcId(CALC_ID_PREFIX);
302           aa.setProperty("PDBID", getId());
303           aa.setProperty("oldCalcId", oldId);
304         }
305       }
306     }
307   }
308
309   private void processPdbFileWithJmol(List<SequenceI> prot)
310           throws Exception
311   {
312     try
313     {
314
315       Class cl = Class.forName("jalview.ext.jmol.JmolParser");
316       if (cl != null)
317       {
318         final Constructor constructor = cl
319                 .getConstructor(new Class[] { FileParse.class });
320         final Object[] args = new Object[] { new FileParse(getDataName(),
321                 type) };
322         Object jmf = constructor.newInstance(args);
323         AlignmentI al = new Alignment((SequenceI[]) cl.getMethod(
324                 "getSeqsAsArray", new Class[] {}).invoke(jmf));
325         cl.getMethod("addAnnotations", new Class[] { AlignmentI.class })
326                 .invoke(jmf, al);
327         for (SequenceI sq : al.getSequences())
328         {
329           if (sq.getDatasetSequence() != null)
330           {
331             sq.getDatasetSequence().getAllPDBEntries().clear();
332           }
333           else
334           {
335             sq.getAllPDBEntries().clear();
336           }
337         }
338         replaceAndUpdateChains(prot, al, AlignSeq.PEP, false);
339       }
340     } catch (ClassNotFoundException q)
341     {
342     }
343   }
344 }