JAL-629 implementation of --tempfac options
[jalview.git] / src / jalview / io / StructureFile.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 jalview.io;
22
23 import java.awt.Color;
24 import java.io.IOException;
25 import java.lang.reflect.Constructor;
26 import java.util.List;
27 import java.util.Vector;
28
29 import jalview.analysis.AlignSeq;
30 import jalview.api.FeatureSettingsModelI;
31 import jalview.datamodel.Alignment;
32 import jalview.datamodel.AlignmentAnnotation;
33 import jalview.datamodel.AlignmentAnnotation.TFType;
34 import jalview.datamodel.AlignmentI;
35 import jalview.datamodel.DBRefEntry;
36 import jalview.datamodel.DBRefSource;
37 import jalview.datamodel.PDBEntry;
38 import jalview.datamodel.PDBEntry.Type;
39 import jalview.datamodel.SequenceI;
40 import jalview.structure.StructureImportSettings;
41 import mc_view.PDBChain;
42
43 public abstract class StructureFile extends AlignFile
44 {
45   private String id;
46
47   private PDBEntry.Type dbRefType;
48
49   /**
50    * set to true to add derived sequence annotations (temp factor read from
51    * file, or computed secondary structure) to the alignment
52    */
53   protected boolean visibleChainAnnotation = false;
54
55   /**
56    * Set true to predict secondary structure (using JMol for protein, Annotate3D
57    * for RNA)
58    */
59   protected boolean predictSecondaryStructure = false;
60
61   /**
62    * Set true (with predictSecondaryStructure=true) to predict secondary
63    * structure using an external service (currently Annotate3D for RNA only)
64    */
65   protected boolean externalSecondaryStructure = false;
66
67   private Vector<PDBChain> chains;
68
69   private boolean pdbIdAvailable;
70
71   public StructureFile(Object inFile, DataSourceType sourceType)
72           throws IOException
73   {
74     this(inFile, sourceType, null);
75   }
76
77   public StructureFile(Object inFile, DataSourceType sourceType,
78           AlignmentAnnotation.TFType tempfacType) throws IOException
79   {
80     super(inFile, sourceType, tempfacType);
81   }
82
83   public StructureFile(FileParse fp) throws IOException
84   {
85     super(fp);
86   }
87
88   public void addSettings(boolean addAlignmentAnnotations,
89           boolean predictSecondaryStructure, boolean externalSecStr)
90   {
91     this.visibleChainAnnotation = addAlignmentAnnotations;
92     this.predictSecondaryStructure = predictSecondaryStructure;
93     this.externalSecondaryStructure = externalSecStr;
94   }
95
96   public void xferSettings()
97   {
98     this.visibleChainAnnotation = StructureImportSettings
99             .isVisibleChainAnnotation();
100     this.predictSecondaryStructure = StructureImportSettings
101             .isProcessSecondaryStructure();
102     this.externalSecondaryStructure = StructureImportSettings
103             .isExternalSecondaryStructure();
104
105   }
106
107   public StructureFile(boolean parseImmediately, Object dataObject,
108           DataSourceType sourceType) throws IOException
109   {
110     super(parseImmediately, dataObject, sourceType);
111   }
112
113   public StructureFile(boolean a, FileParse fp) throws IOException
114   {
115     super(a, fp);
116   }
117
118   public StructureFile()
119   {
120   }
121
122   protected SequenceI postProcessChain(PDBChain chain)
123   {
124     SequenceI pdbSequence = chain.sequence;
125     pdbSequence.setName(getId() + "|" + pdbSequence.getName());
126     PDBEntry entry = new PDBEntry();
127     entry.setId(getId());
128     entry.setFakedPDBId(!isPPDBIdAvailable());
129     entry.setType(getStructureFileType());
130     if (chain.id != null)
131     {
132       entry.setChainCode(chain.id);
133     }
134     if (inFile != null)
135     {
136       entry.setFile(inFile.getAbsolutePath());
137     }
138     else
139     {
140       entry.setFile(getDataName());
141     }
142
143     DBRefEntry sourceDBRef = new DBRefEntry();
144     sourceDBRef.setAccessionId(getId());
145     sourceDBRef.setSource(DBRefSource.PDB);
146     // TODO: specify version for 'PDB' database ref if it is read from a file.
147     // TODO: decide if jalview.io should be creating primary refs!
148     sourceDBRef.setVersion("");
149     pdbSequence.addPDBId(entry);
150     pdbSequence.addDBRef(sourceDBRef);
151     SequenceI chainseq = pdbSequence;
152     seqs.addElement(chainseq);
153     AlignmentAnnotation[] chainannot = chainseq.getAnnotation();
154
155     if (chainannot != null && visibleChainAnnotation)
156     {
157       for (int ai = 0; ai < chainannot.length; ai++)
158       {
159         chainannot[ai].visible = visibleChainAnnotation;
160         annotations.addElement(chainannot[ai]);
161       }
162     }
163     return chainseq;
164   }
165
166   /**
167    * filetype of structure file - default is PDB
168    */
169   String structureFileType = PDBEntry.Type.PDB.toString();
170
171   protected void setStructureFileType(String structureFileType)
172   {
173     this.structureFileType = structureFileType;
174   }
175
176   /**
177    * filetype of last file processed
178    * 
179    * @return
180    */
181   public String getStructureFileType()
182   {
183     return structureFileType;
184   }
185
186   @SuppressWarnings({ "unchecked", "rawtypes" })
187   protected void processPdbFileWithAnnotate3d(List<SequenceI> rna)
188           throws Exception
189   {
190     // System.out.println("this is a PDB format and RNA sequence");
191     // note: we use reflection here so that the applet can compile and run
192     // without the HTTPClient bits and pieces needed for accessing Annotate3D
193     // web service
194     try
195     {
196       Class cl = Class.forName("jalview.ws.jws1.Annotate3D");
197       if (cl != null)
198       {
199         // TODO: use the PDB ID of the structure if one is available, to save
200         // bandwidth and avoid uploading the whole structure to the service
201         Object annotate3d = cl.getConstructor(new Class[] {})
202                 .newInstance(new Object[] {});
203         AlignmentI al = ((AlignmentI) cl
204                 .getMethod("getRNAMLFor", new Class[]
205                 { FileParse.class })
206                 .invoke(annotate3d, new Object[]
207                 { new FileParse(getDataName(), dataSourceType) }));
208         for (SequenceI sq : al.getSequences())
209         {
210           if (sq.getDatasetSequence() != null)
211           {
212             if (sq.getDatasetSequence().getAllPDBEntries() != null)
213             {
214               sq.getDatasetSequence().getAllPDBEntries().clear();
215             }
216           }
217           else
218           {
219             if (sq.getAllPDBEntries() != null)
220             {
221               sq.getAllPDBEntries().clear();
222             }
223           }
224         }
225         replaceAndUpdateChains(rna, al, AlignSeq.DNA, false);
226       }
227     } catch (ClassNotFoundException x)
228     {
229       // ignore classnotfounds - occurs in applet
230     }
231   }
232
233   @SuppressWarnings("unchecked")
234   protected void replaceAndUpdateChains(List<SequenceI> prot, AlignmentI al,
235           String pep, boolean b)
236   {
237     List<List<? extends Object>> replaced = AlignSeq
238             .replaceMatchingSeqsWith(seqs, annotations, prot, al, pep,
239                     false);
240     for (PDBChain ch : getChains())
241     {
242       int p = 0;
243       for (SequenceI sq : (List<SequenceI>) replaced.get(0))
244       {
245         p++;
246         if (sq == ch.sequence || sq.getDatasetSequence() == ch.sequence)
247         {
248           p = -p;
249           break;
250         }
251       }
252       if (p < 0)
253       {
254         p = -p - 1;
255         // set shadow entry for chains
256         ch.shadow = (SequenceI) replaced.get(1).get(p);
257         ch.shadowMap = ((AlignSeq) replaced.get(2).get(p))
258                 .getMappingFromS1(false);
259       }
260     }
261   }
262
263   /**
264    * Predict secondary structure for RNA and/or protein sequences and add as
265    * annotations
266    * 
267    * @param rnaSequences
268    * @param proteinSequences
269    */
270   protected void addSecondaryStructure(List<SequenceI> rnaSequences,
271           List<SequenceI> proteinSequences)
272   {
273     /*
274      * Currently using Annotate3D for RNA, but only if the 'use external
275      * prediction' flag is set
276      */
277     if (externalSecondaryStructure && rnaSequences.size() > 0)
278     {
279       try
280       {
281         processPdbFileWithAnnotate3d(rnaSequences);
282       } catch (Exception x)
283       {
284         System.err.println("Exceptions when dealing with RNA in pdb file");
285         x.printStackTrace();
286
287       }
288     }
289
290     /*
291      * Currently using JMol PDB parser for peptide
292      */
293     if (proteinSequences.size() > 0)
294     {
295       try
296       {
297         processWithJmolParser(proteinSequences);
298       } catch (Exception x)
299       {
300         System.err.println(
301                 "Exceptions from Jmol when processing data in pdb file");
302         x.printStackTrace();
303       }
304     }
305   }
306
307   @SuppressWarnings({ "unchecked", "rawtypes" })
308   private void processWithJmolParser(List<SequenceI> prot) throws Exception
309   {
310     try
311     {
312
313       Class cl = Class.forName("jalview.ext.jmol.JmolParser");
314       if (cl != null)
315       {
316         final Constructor constructor = cl
317                 .getConstructor(new Class[]
318                 { FileParse.class });
319         final Object[] args = new Object[] {
320             new FileParse(getDataName(), dataSourceType) };
321
322         StructureImportSettings.setShowSeqFeatures(false);
323         StructureImportSettings.setVisibleChainAnnotation(false);
324         StructureImportSettings
325                 .setProcessSecondaryStructure(predictSecondaryStructure);
326         StructureImportSettings
327                 .setExternalSecondaryStructure(externalSecondaryStructure);
328         Object jmf = constructor.newInstance(args);
329         AlignmentI al = new Alignment((SequenceI[]) cl
330                 .getMethod("getSeqsAsArray", new Class[] {}).invoke(jmf));
331         cl.getMethod("addAnnotations", new Class[] { AlignmentI.class })
332                 .invoke(jmf, al);
333         for (SequenceI sq : al.getSequences())
334         {
335           if (sq.getDatasetSequence() != null)
336           {
337             sq.getDatasetSequence().getAllPDBEntries().clear();
338           }
339           else
340           {
341             sq.getAllPDBEntries().clear();
342           }
343         }
344         replaceAndUpdateChains(prot, al, AlignSeq.PEP, false);
345       }
346     } catch (ClassNotFoundException q)
347     {
348     }
349     StructureImportSettings.setShowSeqFeatures(true);
350   }
351
352   /**
353    * Answers the first PDBChain found matching the given id, or null if none is
354    * found
355    * 
356    * @param id
357    * @return
358    */
359   public PDBChain findChain(String id)
360   {
361     for (PDBChain chain : getChains())
362     {
363       if (chain.id.equals(id))
364       {
365         return chain;
366       }
367     }
368     return null;
369   }
370
371   public void makeResidueList()
372   {
373     for (PDBChain chain : getChains())
374     {
375       chain.makeResidueList(visibleChainAnnotation);
376     }
377   }
378
379   public void makeCaBondList()
380   {
381     for (PDBChain chain : getChains())
382     {
383       chain.makeCaBondList();
384     }
385   }
386
387   public void setChargeColours()
388   {
389     for (PDBChain chain : getChains())
390     {
391       chain.setChargeColours();
392     }
393   }
394
395   public void setColours(jalview.schemes.ColourSchemeI cs)
396   {
397     for (PDBChain chain : getChains())
398     {
399       chain.setChainColours(cs);
400     }
401   }
402
403   public void setChainColours()
404   {
405     int i = 0;
406     for (PDBChain chain : getChains())
407     {
408       chain.setChainColours(Color.getHSBColor(1.0f / i++, .4f, 1.0f));
409     }
410   }
411
412   public static boolean isRNA(SequenceI seq)
413   {
414     int length = seq.getLength();
415     for (int i = 0; i < length; i++)
416     {
417       char c = seq.getCharAt(i);
418       if ((c != 'A') && (c != 'C') && (c != 'G') && (c != 'U'))
419       {
420         return false;
421       }
422     }
423     return true;
424   }
425
426   /**
427    * make a friendly ID string.
428    * 
429    * @param dataName
430    * @return truncated dataName to after last '/' and pruned .extension if
431    *         present
432    */
433   protected String safeName(String dataName)
434   {
435     int p = 0;
436     while ((p = dataName.indexOf("/")) > -1 && p < dataName.length())
437     {
438       dataName = dataName.substring(p + 1);
439     }
440     if (dataName.indexOf(".") > -1)
441     {
442       dataName = dataName.substring(0, dataName.lastIndexOf("."));
443     }
444     return dataName;
445   }
446
447   public String getId()
448   {
449     return id;
450   }
451
452   public void setId(String id)
453   {
454     this.id = id;
455   }
456
457   public Vector<PDBChain> getChains()
458   {
459     return chains;
460   }
461
462   public void setChains(Vector<PDBChain> chains)
463   {
464     this.chains = chains;
465   }
466
467   public Type getDbRefType()
468   {
469     return dbRefType;
470   }
471
472   public void setDbRefType(String dbRefType)
473   {
474     this.dbRefType = Type.getType(dbRefType);
475   }
476
477   public void setDbRefType(Type dbRefType)
478   {
479     this.dbRefType = dbRefType;
480   }
481
482   /**
483    * Returns a descriptor for suitable feature display settings with
484    * <ul>
485    * <li>ResNums or insertions features visible</li>
486    * <li>insertions features coloured red</li>
487    * <li>ResNum features coloured by label</li>
488    * <li>Insertions displayed above (on top of) ResNums</li>
489    * </ul>
490    */
491   @Override
492   public FeatureSettingsModelI getFeatureColourScheme()
493   {
494     return new PDBFeatureSettings();
495   }
496
497   /**
498    * Answers true if the structure file has a PDBId
499    * 
500    * @return
501    */
502   public boolean isPPDBIdAvailable()
503   {
504     return pdbIdAvailable;
505   }
506
507   public void setPDBIdAvailable(boolean pdbIdAvailable)
508   {
509     this.pdbIdAvailable = pdbIdAvailable;
510   }
511 }