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