javadoc
[jalview.git] / src / MCview / PDBChain.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer (Version 2.6)
3  * Copyright (C) 2010 J Procter, AM Waterhouse, G Barton, M Clamp, S Searle
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 of the License, or (at your option) any later version.
10  * 
11  * Jalview is distributed in the hope that it will be useful, but 
12  * WITHOUT ANY WARRANTY; without even the implied warranty 
13  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
14  * PURPOSE.  See the GNU General Public License for more details.
15  * 
16  * You should have received a copy of the GNU General Public License along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
17  */
18 package MCview;
19
20 import java.util.*;
21
22 import java.awt.*;
23
24 import jalview.analysis.*;
25 import jalview.datamodel.*;
26 import jalview.schemes.*;
27 import jalview.structure.StructureMapping;
28
29 public class PDBChain
30 {
31   /**
32    * SequenceFeature group for PDB File features added to sequences
33    */
34   private static final String PDBFILEFEATURE = "PDBFile";
35
36   private static final String IEASTATUS = "IEA:jalview";
37
38   public String id;
39
40   public Vector bonds = new Vector();
41
42   public Vector atoms = new Vector();
43
44   public Vector residues = new Vector();
45
46   public int offset;
47
48   public Sequence sequence;
49
50   public boolean isNa = false;
51
52   public boolean isVisible = true;
53
54   public int pdbstart = 0;
55
56   public int pdbend = 0;
57
58   public int seqstart = 0;
59
60   public int seqend = 0;
61
62   public String pdbid = "";
63
64   public PDBChain(String pdbid, String id)
65   {
66     this.pdbid = pdbid.toLowerCase();
67     this.id = id;
68   }
69
70   /**
71    * character used to write newlines
72    */
73   protected String newline = System.getProperty("line.separator");
74
75   public void setNewlineString(String nl)
76   {
77     newline = nl;
78   }
79
80   public String getNewlineString()
81   {
82     return newline;
83   }
84
85   public String print()
86   {
87     String tmp = "";
88
89     for (int i = 0; i < bonds.size(); i++)
90     {
91       tmp = tmp + ((Bond) bonds.elementAt(i)).at1.resName + " "
92               + ((Bond) bonds.elementAt(i)).at1.resNumber + " " + offset
93               + newline;
94     }
95
96     return tmp;
97   }
98
99   /**
100    * Annotate the residues with their corresponding positions in s1 using the
101    * alignment in as
102    * 
103    * @param as
104    * @param s1
105    */
106   public void makeExactMapping(AlignSeq as, SequenceI s1)
107   {
108     int pdbpos = as.getSeq2Start() - 2;
109     int alignpos = s1.getStart() + as.getSeq1Start() - 3;
110
111     for (int i = 0; i < as.astr1.length(); i++)
112     {
113       if (as.astr1.charAt(i) != '-')
114       {
115         alignpos++;
116       }
117
118       if (as.astr2.charAt(i) != '-')
119       {
120         pdbpos++;
121       }
122
123       if (as.astr1.charAt(i) == as.astr2.charAt(i))
124       {
125         Residue res = (Residue) residues.elementAt(pdbpos);
126         Enumeration en = res.atoms.elements();
127         while (en.hasMoreElements())
128         {
129           Atom atom = (Atom) en.nextElement();
130           atom.alignmentMapping = alignpos;
131         }
132       }
133     }
134   }
135
136   /**
137    * copy over the RESNUM seqfeatures from the internal chain sequence to the
138    * mapped sequence
139    * 
140    * @param seq
141    * @param status
142    *          The Status of the transferred annotation
143    * @return the features added to sq (or its dataset)
144    */
145   public SequenceFeature[] transferRESNUMFeatures(SequenceI seq,
146           String status)
147   {
148     SequenceI sq = seq;
149     while (sq != null && sq.getDatasetSequence() != null)
150     {
151       sq = sq.getDatasetSequence();
152       if (sq == sequence)
153       {
154         return null;
155       }
156     }
157     /**
158      * Remove any existing features for this chain if they exist ?
159      * SequenceFeature[] seqsfeatures=seq.getSequenceFeatures(); int
160      * totfeat=seqsfeatures.length; // Remove any features for this exact chain
161      * ? for (int i=0; i<seqsfeatures.length; i++) { }
162      */
163     if (status == null)
164     {
165       status = PDBChain.IEASTATUS;
166     }
167     SequenceFeature[] features = sequence.getSequenceFeatures();
168     for (int i = 0; i < features.length; i++)
169     {
170       if (features[i].getFeatureGroup().equals(pdbid))
171       {
172         SequenceFeature tx = new SequenceFeature(features[i]);
173         tx.setBegin(1 + ((Atom) ((Residue) residues.elementAt(tx.getBegin()
174                 - offset)).atoms.elementAt(0)).alignmentMapping);
175         tx.setEnd(1 + ((Atom) ((Residue) residues.elementAt(tx.getEnd()
176                 - offset)).atoms.elementAt(0)).alignmentMapping);
177         tx.setStatus(status
178                 + ((tx.getStatus() == null || tx.getStatus().length() == 0) ? ""
179                         : ":" + tx.getStatus()));
180         if (tx.begin != 0 && tx.end != 0)
181           sq.addSequenceFeature(tx);
182       }
183     }
184     return features;
185   }
186
187   public void makeCaBondList()
188   {
189     boolean na = false;
190     int numNa = 0;
191     for (int i = 0; i < (residues.size() - 1); i++)
192     {
193       Residue tmpres = (Residue) residues.elementAt(i);
194       Residue tmpres2 = (Residue) residues.elementAt(i + 1);
195       Atom at1 = tmpres.findAtom("CA");
196       Atom at2 = tmpres2.findAtom("CA");
197       na = false;
198       if ((at1 == null) && (at2 == null))
199       {
200         na = true;
201         at1 = tmpres.findAtom("P");
202         at2 = tmpres2.findAtom("P");
203       }
204       if ((at1 != null) && (at2 != null))
205       {
206         if (at1.chain.equals(at2.chain))
207         {
208           if (na)
209           {
210             numNa++;
211           }
212           makeBond(at1, at2);
213         }
214       }
215       else
216       {
217         System.out.println("not found " + i);
218       }
219     }
220     if (numNa > 0 && ((numNa / residues.size()) > 0.99))
221     {
222       isNa = true;
223     }
224   }
225
226   public void makeBond(Atom at1, Atom at2)
227   {
228     float[] start = new float[3];
229     float[] end = new float[3];
230
231     start[0] = at1.x;
232     start[1] = at1.y;
233     start[2] = at1.z;
234
235     end[0] = at2.x;
236     end[1] = at2.y;
237     end[2] = at2.z;
238
239     bonds.addElement(new Bond(start, end, at1, at2));
240   }
241
242   public void makeResidueList()
243   {
244     int count = 0;
245     Object symbol;
246     boolean nucleotide = false;
247     StringBuffer seq = new StringBuffer();
248     Vector resFeatures = new Vector();
249     Vector resAnnotation = new Vector();
250     int i, iSize = atoms.size() - 1;
251     int resNumber = -1;
252     for (i = 0; i <= iSize; i++)
253     {
254       Atom tmp = (Atom) atoms.elementAt(i);
255       resNumber = tmp.resNumber;
256       int res = resNumber;
257
258       if (i == 0)
259       {
260         offset = resNumber;
261       }
262
263       Vector resAtoms = new Vector();
264       // Add atoms to a vector while the residue number
265       // remains the same as the first atom's resNumber (res)
266       while ((resNumber == res) && (i < atoms.size()))
267       {
268         resAtoms.addElement((Atom) atoms.elementAt(i));
269         i++;
270
271         if (i < atoms.size())
272         {
273           resNumber = ((Atom) atoms.elementAt(i)).resNumber;
274         }
275         else
276         {
277           resNumber++;
278         }
279       }
280
281       // We need this to keep in step with the outer for i = loop
282       i--;
283
284       // Make a new Residue object with the new atoms vector
285       residues.addElement(new Residue(resAtoms, resNumber - 1, count));
286
287       Residue tmpres = (Residue) residues.lastElement();
288       Atom tmpat = (Atom) tmpres.atoms.elementAt(0);
289       // Make A new SequenceFeature for the current residue numbering
290       SequenceFeature sf = new SequenceFeature("RESNUM", tmpat.resName
291               + ":" + tmpat.resNumIns + " " + pdbid + id, "", offset
292               + count, offset + count, pdbid);
293       // MCview.PDBChain.PDBFILEFEATURE);
294       resFeatures.addElement(sf);
295       resAnnotation.addElement(new Annotation(tmpat.tfactor));
296       // Keep totting up the sequence
297       if ((symbol = ResidueProperties.getAA3Hash().get(tmpat.resName)) == null)
298       {
299         String nucname = tmpat.resName.trim();
300         if (tmpat.name.equalsIgnoreCase("CA")
301                 || ResidueProperties.nucleotideIndex[nucname.charAt(0)] == -1)
302         {
303           seq.append("X");
304           // System.err.println("PDBReader:Null aa3Hash for " +
305           // tmpat.resName);
306         }
307         else
308         {
309           // nucleotide flag
310           nucleotide = true;
311           seq.append(nucname.charAt(0));
312         }
313       }
314       else
315       {
316         if (nucleotide)
317         {
318           System.err
319                   .println("Warning: mixed nucleotide and amino acid chain.. its gonna do bad things to you!");
320         }
321         seq.append(ResidueProperties.aa[((Integer) symbol).intValue()]);
322       }
323       count++;
324     }
325
326     if (id.length() < 1)
327     {
328       id = " ";
329     }
330     isNa = nucleotide;
331     sequence = new Sequence(id, seq.toString(), offset, resNumber - 1); // Note:
332     // resNumber-offset
333     // ~=
334     // seq.size()
335     // Add normalised feature scores to RESNUM indicating start/end of sequence
336     // sf.setScore(offset+count);
337
338     // System.out.println("PDB Sequence is :\nSequence = " + seq);
339     // System.out.println("No of residues = " + residues.size());
340     for (i = 0, iSize = resFeatures.size(); i < iSize; i++)
341     {
342       sequence.addSequenceFeature((SequenceFeature) resFeatures
343               .elementAt(i));
344       resFeatures.setElementAt(null, i);
345     }
346     Annotation[] annots = new Annotation[resAnnotation.size()];
347     float max = 0;
348     for (i = 0, iSize = annots.length; i < iSize; i++)
349     {
350       annots[i] = (Annotation) resAnnotation.elementAt(i);
351       if (annots[i].value > max)
352         max = annots[i].value;
353       resAnnotation.setElementAt(null, i);
354     }
355     AlignmentAnnotation tfactorann = new AlignmentAnnotation(
356             "PDB.TempFactor", "Temperature Factor for "
357                     + sequence.getName(), annots, 0, max,
358             AlignmentAnnotation.LINE_GRAPH);
359     tfactorann.setSequenceRef(sequence);
360     sequence.addAlignmentAnnotation(tfactorann);
361   }
362
363   public void setChargeColours()
364   {
365     for (int i = 0; i < bonds.size(); i++)
366     {
367       try
368       {
369         Bond b = (Bond) bonds.elementAt(i);
370
371         if (b.at1.resName.equalsIgnoreCase("ASP")
372                 || b.at1.resName.equalsIgnoreCase("GLU"))
373         {
374           b.startCol = Color.red;
375         }
376         else if (b.at1.resName.equalsIgnoreCase("LYS")
377                 || b.at1.resName.equalsIgnoreCase("ARG"))
378         {
379           b.startCol = Color.blue;
380         }
381         else if (b.at1.resName.equalsIgnoreCase("CYS"))
382         {
383           b.startCol = Color.yellow;
384         }
385         else
386         {
387           b.startCol = Color.lightGray;
388         }
389
390         if (b.at2.resName.equalsIgnoreCase("ASP")
391                 || b.at2.resName.equalsIgnoreCase("GLU"))
392         {
393           b.endCol = Color.red;
394         }
395         else if (b.at2.resName.equalsIgnoreCase("LYS")
396                 || b.at2.resName.equalsIgnoreCase("ARG"))
397         {
398           b.endCol = Color.blue;
399         }
400         else if (b.at2.resName.equalsIgnoreCase("CYS"))
401         {
402           b.endCol = Color.yellow;
403         }
404         else
405         {
406           b.endCol = Color.lightGray;
407         }
408       } catch (Exception e)
409       {
410         Bond b = (Bond) bonds.elementAt(i);
411         b.startCol = Color.gray;
412         b.endCol = Color.gray;
413       }
414     }
415   }
416
417   public void setChainColours(jalview.schemes.ColourSchemeI cs)
418   {
419     Bond b;
420     int index;
421     for (int i = 0; i < bonds.size(); i++)
422     {
423       try
424       {
425         b = (Bond) bonds.elementAt(i);
426
427         index = ((Integer) ResidueProperties.aa3Hash.get(b.at1.resName))
428                 .intValue();
429         b.startCol = cs.findColour(ResidueProperties.aa[index].charAt(0));
430
431         index = ((Integer) ResidueProperties.aa3Hash.get(b.at2.resName))
432                 .intValue();
433         b.endCol = cs.findColour(ResidueProperties.aa[index].charAt(0));
434
435       } catch (Exception e)
436       {
437         b = (Bond) bonds.elementAt(i);
438         b.startCol = Color.gray;
439         b.endCol = Color.gray;
440       }
441     }
442   }
443
444   public void setChainColours(Color col)
445   {
446     for (int i = 0; i < bonds.size(); i++)
447     {
448       Bond tmp = (Bond) bonds.elementAt(i);
449       tmp.startCol = col;
450       tmp.endCol = col;
451     }
452   }
453
454   public AlignmentAnnotation[] transferResidueAnnotation(SequenceI seq,
455           String status)
456   {
457     AlignmentAnnotation[] transferred = null;
458
459     return transferred;
460
461   }
462
463   /**
464    * copy any sequence annotation onto the sequence mapped using the provided
465    * StructureMapping
466    * 
467    * @param mapping
468    */
469   public void transferResidueAnnotation(StructureMapping mapping)
470   {
471     SequenceI sq = mapping.getSequence();
472     if (sq != null)
473     {
474       if (sequence != null && sequence.getAnnotation() != null)
475       {
476
477       }
478       float min = -1, max = 0;
479       Annotation[] an = new Annotation[sq.getEnd() - sq.getStart() + 1];
480       for (int i = sq.getStart(), j = sq.getEnd(), k = 0; i <= j; i++, k++)
481       {
482         int prn = mapping.getPDBResNum(k + 1);
483
484         an[k] = new Annotation((float) prn);
485         if (min == -1)
486         {
487           min = k;
488           max = k;
489         }
490         else
491         {
492           if (min > k)
493           {
494             min = k;
495           }
496           else if (max < k)
497           {
498             max = k;
499           }
500         }
501       }
502       sq.addAlignmentAnnotation(new AlignmentAnnotation("PDB.RESNUM",
503               "PDB Residue Numbering for " + this.pdbid + ":" + this.id,
504               an, (float) min, (float) max, AlignmentAnnotation.LINE_GRAPH));
505     }
506   }
507 }