/*
* ConvertAlignment.java
*
* Copyright (c) 2002-2015 Alexei Drummond, Andrew Rambaut and Marc Suchard
*
* This file is part of BEAST.
* See the NOTICE file distributed with this work for additional
* information regarding copyright ownership and licensing.
*
* BEAST is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* BEAST 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with BEAST; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*/
package dr.evolution.alignment;
import dr.evolution.datatype.*;
import dr.evolution.sequence.Sequence;
import dr.evolution.util.Taxon;
import java.util.*;
/**
* An alignment class that takes another alignment and converts it on the fly
* to a different dataType.
*
* @author Andrew Rambaut
* @author Alexei Drummond
*
* @version $Id: ConvertAlignment.java,v 1.29 2005/05/24 20:25:55 rambaut Exp $
*/
public class ConvertAlignment extends WrappedAlignment implements dr.util.XHTMLable
{
/**
* Constructor.
*/
public ConvertAlignment(DataType dataType) {
this(dataType, null, null);
}
/**
* Constructor.
*/
public ConvertAlignment(DataType dataType, CodonTable codonTable) {
this(dataType, codonTable, null);
}
/**
* Constructor.
*/
public ConvertAlignment(DataType dataType, Alignment alignment) {
this(dataType, null, alignment);
}
/**
* Constructor.
*/
public ConvertAlignment(DataType dataType, CodonTable codonTable, Alignment alignment) {
super(alignment);
setDataType(dataType);
setCodonTable(codonTable);
setAlignment(alignment);
}
/**
* Sets the CodonTable of this alignment.
*/
public void setCodonTable(CodonTable codonTable) {
this.codonTable = codonTable;
}
/**
* Sets the contained.
*/
public void setAlignment(Alignment alignment) {
if (dataType == null) {
dataType = alignment.getDataType();
}
this.alignment = alignment;
int newType = dataType.getType();
int originalType = alignment.getDataType().getType();
//TODO: this logic does not work for pibuss
if (originalType == DataType.NUCLEOTIDES) {
if (newType != DataType.CODONS && newType != DataType.AMINO_ACIDS) {
throw new RuntimeException("Incompatible alignment DataType for ConversionAlignment");
}
} else if (originalType == DataType.CODONS) {
if (!(newType == DataType.AMINO_ACIDS || newType == DataType.NUCLEOTIDES)) {
System.err.println("originalType = " + originalType);
System.err.println("newType = " + newType);
throw new RuntimeException("Incompatible alignment DataType for ConversionAlignment");
}
} else {
throw new RuntimeException("Incompatible alignment DataType for ConversionAlignment");
}//END: original type check
}
/**
* Sets the dataType of this alignment. This can be different from
* the dataTypes of the contained alignment - they will be translated
* as required.
*/
public void setDataType(DataType dataType) {
this.dataType = dataType;
}
/**
* @return the DataType of this siteList
*/
public DataType getDataType() {
return dataType;
}
/**
* @return number of sites
*/
public int getSiteCount() {
if (alignment == null) throw new RuntimeException("ConvertAlignment has no alignment");
int originalType = alignment.getDataType().getType();
int count = alignment.getSiteCount();
if (originalType == DataType.NUCLEOTIDES) {
count /= 3;
}
return count;
}
/**
* @return the sequence state at (taxon, site)
*/
public int getState(int taxonIndex, int siteIndex) {
if (alignment == null) throw new RuntimeException("ConvertAlignment has no alignment");
int newType = dataType.getType();
int originalType = alignment.getDataType().getType();
int state = 0;
if (originalType == DataType.NUCLEOTIDES) {
int siteIndex3 = siteIndex * 3;
int state1 = alignment.getState(taxonIndex, siteIndex3);
int state2 = alignment.getState(taxonIndex, siteIndex3 + 1);
int state3 = alignment.getState(taxonIndex, siteIndex3 + 2);
if (newType == DataType.CODONS) {
state = ((Codons)dataType).getState(state1, state2, state3);
} else { // newType == DataType.AMINO_ACIDS
state = codonTable.getAminoAcidState(((Codons)dataType).getCanonicalState(((Codons)dataType).getState(state1, state2, state3)));
}
} else if (originalType == DataType.CODONS) {
if (newType == DataType.AMINO_ACIDS) {
state = codonTable.getAminoAcidState(alignment.getState(taxonIndex, siteIndex));
} else { // newType == DataType.CODONS
String string = alignment.getAlignedSequenceString(taxonIndex);
state = Nucleotides.INSTANCE.getState(string.charAt(siteIndex));
}
}
return state;
}
public String toXHTML() {
String xhtml = "<p><em>Converted Alignment</em> data type = ";
xhtml += getDataType().getDescription();
xhtml += ", no. taxa = ";
xhtml += getTaxonCount();
xhtml += ", no. sites = ";
xhtml += getSiteCount();
xhtml += "</p>";
xhtml += "<pre>";
int length, maxLength = 0;
for (int i =0; i < getTaxonCount(); i++) {
length = getTaxonId(i).length();
if (length > maxLength)
maxLength = length;
}
int count, state;
int type = getDataType().getType();
for (int i = 0; i < getTaxonCount(); i++) {
length = getTaxonId(i).length();
xhtml += getTaxonId(i);
for (int j = length; j <= maxLength; j++)
xhtml += " ";
count = getSiteCount();
for (int j = 0; j < count; j++) {
state = getState(i, j);
if (type == DataType.CODONS)
xhtml += Codons.UNIVERSAL.getTriplet(state) + " ";
else
xhtml += AminoAcids.INSTANCE.getTriplet(state) + " ";
}
xhtml += "\n";
}
xhtml += "</pre>";
return xhtml;
}
private DataType dataType = null;
private CodonTable codonTable = null;
}