5385359c3d7df46ce7c0f98cf28420d7386d4d84
[jalview.git] / src / jalview / workers / InformationThread.java
1 package jalview.workers;
2
3 import jalview.analysis.AAFrequency;
4 import jalview.api.AlignViewportI;
5 import jalview.api.AlignmentViewPanel;
6 import jalview.datamodel.AlignmentAnnotation;
7 import jalview.datamodel.AlignmentI;
8 import jalview.datamodel.Annotation;
9 import jalview.datamodel.HiddenMarkovModel;
10 import jalview.datamodel.ProfilesI;
11 import jalview.datamodel.SequenceI;
12 import jalview.renderer.ResidueShaderI;
13
14 import java.util.List;
15
16 public class InformationThread extends AlignCalcWorker
17 {
18   public static final String HMM_CALC_ID = "HMM";
19
20   private float max = 0f;
21
22   /**
23    * Constructor for information thread.
24    * 
25    * @param alignViewport
26    * @param alignPanel
27    */
28   public InformationThread(AlignViewportI alignViewport,
29           AlignmentViewPanel alignPanel)
30   {
31     super(alignViewport, alignPanel);
32   }
33
34   @Override
35   public void run()
36   {
37     if (calcMan.isPending(this))
38     {
39       return;
40     }
41     calcMan.notifyStart(this);
42     // long started = System.currentTimeMillis();
43
44     List<AlignmentAnnotation> information = getInformationAnnotations();
45     try
46     {
47       if ((information == null) || calcMan.isPending(this))
48       {
49         calcMan.workerComplete(this);
50         return;
51       }
52       while (!calcMan.notifyWorking(this))
53       {
54         // System.err.println("Thread
55         // (Information"+Thread.currentThread().getName()+") Waiting around.");
56         try
57         {
58           if (ap != null)
59           {
60             ap.paintAlignment(false, false);
61           }
62           Thread.sleep(200);
63         } catch (Exception ex)
64         {
65           ex.printStackTrace();
66         }
67       }
68       if (alignViewport.isClosed())
69       {
70         abortAndDestroy();
71         return;
72       }
73       AlignmentI alignment = alignViewport.getAlignment();
74
75       int aWidth = -1;
76
77       if (alignment == null || (aWidth = alignment.getWidth()) < 0)
78       {
79         calcMan.workerComplete(this);
80         return;
81       }
82
83       eraseInformation(aWidth);
84       computeInformation(alignment);
85       updateResultAnnotation(true);
86
87       if (ap != null)
88       {
89         ap.paintAlignment(true, true);
90       }
91     } catch (OutOfMemoryError error)
92     {
93       calcMan.disableWorker(this);
94       ap.raiseOOMWarning("calculating information", error);
95     } finally
96     {
97       calcMan.workerComplete(this);
98     }
99   }
100
101   /**
102    * Clear out any existing information annotations
103    * 
104    * @param aWidth
105    *          the width (number of columns) of the annotated alignment
106    */
107   protected void eraseInformation(int aWidth)
108   {
109
110     List<AlignmentAnnotation> information = getInformationAnnotations();
111     for (AlignmentAnnotation info : information)
112     {
113       info.annotations = new Annotation[aWidth];
114     }
115   }
116
117   /**
118    * Computes the profiles from a HMM for an alignment.
119    * 
120    * @param alignment
121    */
122   protected void computeInformation(AlignmentI alignment)
123   {
124     int width = alignment.getWidth();
125     List<SequenceI> hmmSeqs = alignment.getHMMConsensusSequences();
126     int index = 0;
127
128     for (SequenceI seq : hmmSeqs)
129     {
130       HiddenMarkovModel hmm = seq.getHMM();
131       ProfilesI hinformation = AAFrequency.calculateHMMProfiles(hmm, width,
132               0, width, true, alignViewport.isIgnoreBelowBackground(),
133               alignViewport.isInfoLetterHeight());
134       alignViewport.setSequenceInformationHash(hinformation, index);
135       // setColourSchemeInformation(hinformation);
136       index++;
137     }
138   }
139
140   /**
141    * gets the sequences on the alignment on the viewport.
142    * 
143    * @return
144    */
145   protected SequenceI[] getSequences()
146   {
147     return alignViewport.getAlignment().getSequencesArray();
148   }
149
150   protected void setColourSchemeInformation(ProfilesI information)
151   {
152     ResidueShaderI cs = alignViewport.getResidueShading();
153     if (cs != null)
154     {
155       cs.setInformation(information);
156     }
157   }
158
159   /**
160    * Get the Information annotation for the alignment
161    * 
162    * @return
163    */
164   protected List<AlignmentAnnotation> getInformationAnnotations()
165   {
166     return alignViewport.getInformationAnnotations();
167   }
168
169   /**
170    * Get the Gap annotation for the alignment
171    * 
172    * @return
173    */
174   protected AlignmentAnnotation getGapAnnotation()
175   {
176     return alignViewport.getAlignmentGapAnnotation();
177   }
178
179   /**
180    * update the information annotation from the sequence profile data using
181    * current visualization settings.
182    */
183   @Override
184   public void updateAnnotation()
185   {
186     updateResultAnnotation(false);
187   }
188
189   /**
190    * Derives the information content for an information annotation.
191    * 
192    * @param immediate
193    */
194   public void updateResultAnnotation(boolean immediate)
195   {
196     List<AlignmentAnnotation> annots = getInformationAnnotations();
197     int index = 0;
198     for (AlignmentAnnotation information : annots)
199     {
200       ProfilesI hinformation = (ProfilesI) getSequenceInformation(index);
201       if (immediate || !calcMan.isWorking(this) && information != null
202               && hinformation != null)
203       {
204         deriveInformation(information, hinformation);
205       }
206       index++;
207     }
208   }
209
210   /**
211    * Convert the computed information data into the desired annotation for
212    * display.
213    * 
214    * @param informationAnnotation
215    *          the annotation to be populated
216    * @param hinformation
217    *          the computed information data
218    */
219   protected void deriveInformation(
220           AlignmentAnnotation informationAnnotation, ProfilesI hinformation)
221   {
222     long nseq = getSequences().length;
223     max = AAFrequency.completeInformation(informationAnnotation,
224             hinformation, hinformation.getStartColumn(),
225             hinformation.getEndColumn() + 1, nseq, max);
226   }
227
228   /**
229    * Get the information data stored on the viewport.
230    * 
231    * @return
232    */
233   protected Object getSequenceInformation(int index)
234   {
235     return alignViewport.getSequenceInformationHash(index);
236   }
237 }