/*
* Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
* Copyright (C) $$Year-Rel$$ The Jalview Authors
*
* This file is part of Jalview.
*
* Jalview is free software: you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation, either version 3
* of the License, or (at your option) any later version.
*
* Jalview is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Jalview. If not, see .
* The Jalview Authors are detailed in the 'AUTHORS' file.
*/
package jalview.workers;
import jalview.analysis.AAFrequency;
import jalview.api.AlignCalcWorkerI;
import jalview.api.AlignViewportI;
import jalview.api.AlignmentViewPanel;
import jalview.datamodel.AlignmentAnnotation;
import jalview.datamodel.AlignmentI;
import jalview.datamodel.Annotation;
import jalview.datamodel.SequenceI;
import jalview.schemes.ColourSchemeI;
import java.util.Hashtable;
public class ConsensusThread extends AlignCalcWorker implements
AlignCalcWorkerI
{
protected Hashtable[] hconsensus;
protected SequenceI[] aseqs;
@Override
public AlignCalcWorkerI getNewWorker() {
return new ConsensusThread(alignViewport, ap);
}
public ConsensusThread(AlignViewportI alignViewport,
AlignmentViewPanel alignPanel)
{
super(alignViewport, alignPanel);
}
/**
* The basic idea is that the state starts INIT, and then you can advance it as you
* wish to one or more LOOP states, and then to DONE.
*
* The entire operation is within a while loop so that Java need not exit.
*
* You can test for JavaScript using the field isJS.
*
* JSThread simply executes sleepAndReturn() at the end of these loops, returning
* TRUE if it is necessary to exit the thread (because this is JavaScript). In the
* case of Java, we are simply executing sleep(n), so we embed all this in
* while() loops.
*
*/
@Override
protected void run1(int state) {
while (!interrupted()) {
if (alignViewport.isClosed())
{
abortAndDestroy();
return;
}
try {
switch (state) {
case INIT:
if (calcMan.isPending(this))
return;
calcMan.notifyStart(this);
AlignmentAnnotation consensus = getConsensusAnnotation();
if (consensus == null || calcMan.isPending(this)) {
calcMan.workerComplete(this);
return;
}
state = LOOP_STANDBY;
break;
case LOOP_STANDBY:
while (!calcMan.notifyWorking(this)) {
if (ap != null) {
ap.paintAlignment(false);
}
try {
if (sleepAndReturn(200, state))
return;
} catch (InterruptedException e) {
state = DONE;
break;
}
}
if (alignViewport.isClosed()) {
abortAndDestroy();
state = DONE;
break;
}
alignment = alignViewport.getAlignment();
aWidth = -1;
if (alignment == null || (aWidth = alignment.getWidth()) < 0) {
state = DONE;
}
eraseConsensus(aWidth);
state = (initializeCalc() ? LOOP_CALCULATE : DONE);
break;
case LOOP_CALCULATE:
iFirst = iLast;
iLast = Math.min(iLast + nPer, aWidth);
if (iLast == iFirst) {
state = DONE;
} else {
computeConsensus();
if (sleepAndReturn(0, state))
return;
}
break;
case DONE:
finalizeCalc();
updateAlignment();
notifyDone();
return;
}
} catch (OutOfMemoryError error) {
calcMan.workerCannotRun(this);
ap.raiseOOMWarning("calculating consensus", error);
} catch (Throwable e) {
System.out.println("Error in ConsensusThread: " + e);
e.printStackTrace();
calcMan.workerComplete(this);
}
}
}
@SuppressWarnings("unchecked")
protected boolean initializeCalc() {
iLast = 0;
hconsensus = new Hashtable[aWidth];
aseqs = getSequences();
return true;
}
protected void computeConsensus() {
started = System.currentTimeMillis();
AAFrequency.calculate(aseqs, iFirst, iLast, hconsensus, true);
if (System.currentTimeMillis() - started < MS_MAX)
nPer *= 2;
}
protected void finalizeCalc() {
// BH: I was not sure about the exact placement of each of these steps
alignViewport.setSequenceConsensusHash(hconsensus);
}
protected void updateAlignment() {
setColourSchemeConsensus(hconsensus);
updateResultAnnotation(true);
}
/**
* Clear out any existing consensus annotations
*
* @param aWidth
* the width (number of columns) of the annotated alignment
*/
protected void eraseConsensus(int aWidth)
{
AlignmentAnnotation consensus = getConsensusAnnotation();
consensus.annotations = new Annotation[aWidth];
}
/**
* @return
*/
protected SequenceI[] getSequences()
{
return alignViewport.getAlignment().getSequencesArray();
}
/**
* @param hconsensus
*/
protected void setColourSchemeConsensus(Hashtable[] hconsensus)
{
ColourSchemeI globalColourScheme = alignViewport
.getGlobalColourScheme();
if (globalColourScheme != null)
{
globalColourScheme.setConsensus(hconsensus);
}
}
/**
* Get the Consensus annotation for the alignment
*
* @return
*/
protected AlignmentAnnotation getConsensusAnnotation()
{
return alignViewport.getAlignmentConsensusAnnotation();
}
/**
* update the consensus annotation from the sequence profile data using
* current visualization settings.
*/
@Override
public void updateAnnotation()
{
updateResultAnnotation(false);
}
public void updateResultAnnotation(boolean immediate)
{
AlignmentAnnotation consensus = getConsensusAnnotation();
Hashtable[] hconsensus = getViewportConsensus();
if (immediate || !calcMan.isWorking(this) && consensus != null
&& hconsensus != null)
{
deriveConsensus(consensus, hconsensus);
}
}
/**
* Convert the computed consensus data into the desired annotation for
* display.
*
* @param consensusAnnotation
* the annotation to be populated
* @param consensusData
* the computed consensus data
*/
protected void deriveConsensus(AlignmentAnnotation consensusAnnotation,
Hashtable[] consensusData)
{
long nseq = getSequences().length;
AAFrequency.completeConsensus(consensusAnnotation, consensusData, 0,
consensusData.length, alignViewport.isIgnoreGapsConsensus(),
alignViewport.isShowSequenceLogo(), nseq);
}
/**
* Get the consensus data stored on the viewport.
*
* @return
*/
protected Hashtable[] getViewportConsensus()
{
return alignViewport.getSequenceConsensusHash();
}
}