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    * @return last position in s1 for the last position in the chain
106    */
107   public void makeExactMapping(AlignSeq as, SequenceI s1)
108   {
109     int pdbpos = as.getSeq2Start() - 2;
110     int alignpos = s1.getStart() + as.getSeq1Start() - 3;
111
112     for (int i = 0; i < as.astr1.length(); i++)
113     {
114       if (as.astr1.charAt(i) != '-')
115       {
116         alignpos++;
117       }
118
119       if (as.astr2.charAt(i) != '-')
120       {
121         pdbpos++;
122       }
123
124       if (as.astr1.charAt(i) == as.astr2.charAt(i))
125       {
126         Residue res = (Residue) residues.elementAt(pdbpos);
127         Enumeration en = res.atoms.elements();
128         while (en.hasMoreElements())
129         {
130           Atom atom = (Atom) en.nextElement();
131           atom.alignmentMapping = alignpos;
132         }
133       }
134     }
135   }
136
137   /**
138    * copy over the RESNUM seqfeatures from the internal chain sequence to the
139    * mapped sequence
140    * 
141    * @param seq
142    * @param status
143    *          The Status of the transferred annotation
144    * @return the features added to sq (or its dataset)
145    */
146   public SequenceFeature[] transferRESNUMFeatures(SequenceI seq,
147           String status)
148   {
149     SequenceI sq = seq;
150     while (sq != null && sq.getDatasetSequence() != null)
151     {
152       sq = sq.getDatasetSequence();
153       if (sq == sequence)
154       {
155         return null;
156       }
157     }
158     /**
159      * Remove any existing features for this chain if they exist ?
160      * SequenceFeature[] seqsfeatures=seq.getSequenceFeatures(); int
161      * totfeat=seqsfeatures.length; // Remove any features for this exact chain
162      * ? for (int i=0; i<seqsfeatures.length; i++) { }
163      */
164     if (status == null)
165     {
166       status = PDBChain.IEASTATUS;
167     }
168     SequenceFeature[] features = sequence.getSequenceFeatures();
169     for (int i = 0; i < features.length; i++)
170     {
171       if (features[i].getFeatureGroup().equals(pdbid))
172       {
173         SequenceFeature tx = new SequenceFeature(features[i]);
174         tx.setBegin(1 + ((Atom) ((Residue) residues.elementAt(tx.getBegin()
175                 - offset)).atoms.elementAt(0)).alignmentMapping);
176         tx.setEnd(1 + ((Atom) ((Residue) residues.elementAt(tx.getEnd()
177                 - offset)).atoms.elementAt(0)).alignmentMapping);
178         tx.setStatus(status
179                 + ((tx.getStatus() == null || tx.getStatus().length() == 0) ? ""
180                         : ":" + tx.getStatus()));
181         if (tx.begin != 0 && tx.end != 0)
182           sq.addSequenceFeature(tx);
183       }
184     }
185     return features;
186   }
187
188   public void makeCaBondList()
189   {
190     boolean na = false;
191     int numNa = 0;
192     for (int i = 0; i < (residues.size() - 1); i++)
193     {
194       Residue tmpres = (Residue) residues.elementAt(i);
195       Residue tmpres2 = (Residue) residues.elementAt(i + 1);
196       Atom at1 = tmpres.findAtom("CA");
197       Atom at2 = tmpres2.findAtom("CA");
198       na = false;
199       if ((at1 == null) && (at2 == null))
200       {
201         na = true;
202         at1 = tmpres.findAtom("P");
203         at2 = tmpres2.findAtom("P");
204       }
205       if ((at1 != null) && (at2 != null))
206       {
207         if (at1.chain.equals(at2.chain))
208         {
209           if (na)
210           {
211             numNa++;
212           }
213           makeBond(at1, at2);
214         }
215       }
216       else
217       {
218         System.out.println("not found " + i);
219       }
220     }
221     if (numNa > 0 && ((numNa / residues.size()) > 0.99))
222     {
223       isNa = true;
224     }
225   }
226
227   public void makeBond(Atom at1, Atom at2)
228   {
229     float[] start = new float[3];
230     float[] end = new float[3];
231
232     start[0] = at1.x;
233     start[1] = at1.y;
234     start[2] = at1.z;
235
236     end[0] = at2.x;
237     end[1] = at2.y;
238     end[2] = at2.z;
239
240     bonds.addElement(new Bond(start, end, at1, at2));
241   }
242
243   public void makeResidueList()
244   {
245     int count = 0;
246     Object symbol;
247     boolean nucleotide = false;
248     StringBuffer seq = new StringBuffer();
249     Vector resFeatures = new Vector();
250     Vector resAnnotation = new Vector();
251     int i, iSize = atoms.size() - 1;
252     int resNumber = -1;
253     for (i = 0; i <= iSize; i++)
254     {
255       Atom tmp = (Atom) atoms.elementAt(i);
256       resNumber = tmp.resNumber;
257       int res = resNumber;
258
259       if (i == 0)
260       {
261         offset = resNumber;
262       }
263
264       Vector resAtoms = new Vector();
265       // Add atoms to a vector while the residue number
266       // remains the same as the first atom's resNumber (res)
267       while ((resNumber == res) && (i < atoms.size()))
268       {
269         resAtoms.addElement((Atom) atoms.elementAt(i));
270         i++;
271
272         if (i < atoms.size())
273         {
274           resNumber = ((Atom) atoms.elementAt(i)).resNumber;
275         }
276         else
277         {
278           resNumber++;
279         }
280       }
281
282       // We need this to keep in step with the outer for i = loop
283       i--;
284
285       // Make a new Residue object with the new atoms vector
286       residues.addElement(new Residue(resAtoms, resNumber - 1, count));
287
288       Residue tmpres = (Residue) residues.lastElement();
289       Atom tmpat = (Atom) tmpres.atoms.elementAt(0);
290       // Make A new SequenceFeature for the current residue numbering
291       SequenceFeature sf = new SequenceFeature("RESNUM", tmpat.resName
292               + ":" + tmpat.resNumIns + " " + pdbid + id, "", offset
293               + count, offset + count, pdbid);
294       // MCview.PDBChain.PDBFILEFEATURE);
295       resFeatures.addElement(sf);
296       resAnnotation.addElement(new Annotation(tmpat.tfactor));
297       // Keep totting up the sequence
298       if ((symbol = ResidueProperties.getAA3Hash().get(tmpat.resName)) == null)
299       {
300         String nucname = tmpat.resName.trim();
301         if (tmpat.name.equalsIgnoreCase("CA")
302                 || ResidueProperties.nucleotideIndex[nucname.charAt(0)] == -1)
303         {
304           seq.append("X");
305           // System.err.println("PDBReader:Null aa3Hash for " +
306           // tmpat.resName);
307         }
308         else
309         {
310           // nucleotide flag
311           nucleotide = true;
312           seq.append(nucname.charAt(0));
313         }
314       }
315       else
316       {
317         if (nucleotide)
318         {
319           System.err
320                   .println("Warning: mixed nucleotide and amino acid chain.. its gonna do bad things to you!");
321         }
322         seq.append(ResidueProperties.aa[((Integer) symbol).intValue()]);
323       }
324       count++;
325     }
326
327     if (id.length() < 1)
328     {
329       id = " ";
330     }
331     isNa = nucleotide;
332     sequence = new Sequence(id, seq.toString(), offset, resNumber - 1); // Note:
333     // resNumber-offset
334     // ~=
335     // seq.size()
336     // Add normalised feature scores to RESNUM indicating start/end of sequence
337     // sf.setScore(offset+count);
338
339     // System.out.println("PDB Sequence is :\nSequence = " + seq);
340     // System.out.println("No of residues = " + residues.size());
341     for (i = 0, iSize = resFeatures.size(); i < iSize; i++)
342     {
343       sequence.addSequenceFeature((SequenceFeature) resFeatures
344               .elementAt(i));
345       resFeatures.setElementAt(null, i);
346     }
347     Annotation[] annots = new Annotation[resAnnotation.size()];
348     float max = 0;
349     for (i = 0, iSize = annots.length; i < iSize; i++)
350     {
351       annots[i] = (Annotation) resAnnotation.elementAt(i);
352       if (annots[i].value > max)
353         max = annots[i].value;
354       resAnnotation.setElementAt(null, i);
355     }
356     AlignmentAnnotation tfactorann = new AlignmentAnnotation(
357             "PDB.TempFactor", "Temperature Factor for "
358                     + sequence.getName(), annots, 0, max,
359             AlignmentAnnotation.LINE_GRAPH);
360     tfactorann.setSequenceRef(sequence);
361     sequence.addAlignmentAnnotation(tfactorann);
362   }
363
364   public void setChargeColours()
365   {
366     for (int i = 0; i < bonds.size(); i++)
367     {
368       try
369       {
370         Bond b = (Bond) bonds.elementAt(i);
371
372         if (b.at1.resName.equalsIgnoreCase("ASP")
373                 || b.at1.resName.equalsIgnoreCase("GLU"))
374         {
375           b.startCol = Color.red;
376         }
377         else if (b.at1.resName.equalsIgnoreCase("LYS")
378                 || b.at1.resName.equalsIgnoreCase("ARG"))
379         {
380           b.startCol = Color.blue;
381         }
382         else if (b.at1.resName.equalsIgnoreCase("CYS"))
383         {
384           b.startCol = Color.yellow;
385         }
386         else
387         {
388           b.startCol = Color.lightGray;
389         }
390
391         if (b.at2.resName.equalsIgnoreCase("ASP")
392                 || b.at2.resName.equalsIgnoreCase("GLU"))
393         {
394           b.endCol = Color.red;
395         }
396         else if (b.at2.resName.equalsIgnoreCase("LYS")
397                 || b.at2.resName.equalsIgnoreCase("ARG"))
398         {
399           b.endCol = Color.blue;
400         }
401         else if (b.at2.resName.equalsIgnoreCase("CYS"))
402         {
403           b.endCol = Color.yellow;
404         }
405         else
406         {
407           b.endCol = Color.lightGray;
408         }
409       } catch (Exception e)
410       {
411         Bond b = (Bond) bonds.elementAt(i);
412         b.startCol = Color.gray;
413         b.endCol = Color.gray;
414       }
415     }
416   }
417
418   public void setChainColours(jalview.schemes.ColourSchemeI cs)
419   {
420     Bond b;
421     int index;
422     for (int i = 0; i < bonds.size(); i++)
423     {
424       try
425       {
426         b = (Bond) bonds.elementAt(i);
427
428         index = ((Integer) ResidueProperties.aa3Hash.get(b.at1.resName))
429                 .intValue();
430         b.startCol = cs.findColour(ResidueProperties.aa[index].charAt(0));
431
432         index = ((Integer) ResidueProperties.aa3Hash.get(b.at2.resName))
433                 .intValue();
434         b.endCol = cs.findColour(ResidueProperties.aa[index].charAt(0));
435
436       } catch (Exception e)
437       {
438         b = (Bond) bonds.elementAt(i);
439         b.startCol = Color.gray;
440         b.endCol = Color.gray;
441       }
442     }
443   }
444
445   public void setChainColours(Color col)
446   {
447     for (int i = 0; i < bonds.size(); i++)
448     {
449       Bond tmp = (Bond) bonds.elementAt(i);
450       tmp.startCol = col;
451       tmp.endCol = col;
452     }
453   }
454
455   public AlignmentAnnotation[] transferResidueAnnotation(SequenceI seq,
456           String status)
457   {
458     AlignmentAnnotation[] transferred = null;
459
460     return transferred;
461
462   }
463
464   /**
465    * copy any sequence annotation onto the sequence mapped using the provided
466    * StructureMapping
467    * 
468    * @param mapping
469    */
470   public void transferResidueAnnotation(StructureMapping mapping)
471   {
472     SequenceI sq = mapping.getSequence();
473     if (sq != null)
474     {
475       if (sequence != null && sequence.getAnnotation() != null)
476       {
477
478       }
479       float min = -1, max = 0;
480       Annotation[] an = new Annotation[sq.getEnd() - sq.getStart() + 1];
481       for (int i = sq.getStart(), j = sq.getEnd(), k = 0; i <= j; i++, k++)
482       {
483         int prn = mapping.getPDBResNum(k + 1);
484
485         an[k] = new Annotation((float) prn);
486         if (min == -1)
487         {
488           min = k;
489           max = k;
490         }
491         else
492         {
493           if (min > k)
494           {
495             min = k;
496           }
497           else if (max < k)
498           {
499             max = k;
500           }
501         }
502       }
503       sq.addAlignmentAnnotation(new AlignmentAnnotation("PDB.RESNUM",
504               "PDB Residue Numbering for " + this.pdbid + ":" + this.id,
505               an, (float) min, (float) max, AlignmentAnnotation.LINE_GRAPH));
506     }
507   }
508 }