// This file is part of BULL, a program for phylogenetic simulations
// most of the code was written by Mark T. Holder.
// This program is for internal use by the lab of Dr. Tandy Warnow only.
// Do not redistribute the code. It 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.
//
// Some of the code is from publically available source by Paul Lewis, Ziheng Yang,
// John Huelsenbeck, David Swofford , and others (as noted in the code).
// In fact the main structure of the program was created by modifying Paul Lewis'
// basiccmdline.cpp from his NCL
//
// This code was used in Mark's dissertation, some changes were made in order to
// get it to compile on gcc. It is possible that this porting introduced bugs (very
// little debugging has been done on UNIX platforms). I would suggest checking
// the simulator by generating data on trees with short branches, etc.
// This file is part of BULL, a program for phylogenetic simulations
// most of the code was written by Mark T. Holder.
// This program is for internal use by the lab of Dr. Tandy Warnow only.
// Do not redistribute the code. It 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.
//
// Some of the code is from publically available source by Paul Lewis, Ziheng Yang,
// John Huelsenbeck, David Swofford , and others (as noted in the code).
// In fact the main structure of the program was created by modifying Paul Lewis'
// basiccmdline.cpp from his NCL
//
// This code was used in Mark's dissertation, some changes were made in order to
// get it to compile on gcc. It is possible that this porting introduced bugs (very
// little debugging has been done on UNIX platforms). I would suggest checking
// the simulator by generating data on trees with short branches, etc.
#include "nexus_defs.hpp"
#include "xbull.hpp"
#include "nexus_token.hpp"
#include "nexus.hpp"
#include "taxa_block.hpp"
#include "string_extensions.hpp"
using std::endl;
/**
* @class TaxaBlock
* @file taxa_block.hpp
* @file taxablock.cpp
* @author Paul O. Lewis
* @copyright Copyright © 1999. All Rights Reserved.
* @variable ntax [int:private] number of taxa (set from NTAX specification)
* @variable taxonLabels [LabelList:private] storage for list of taxon labels
* @see LabelList
* @see Nexus
* @see NexusBlock
* @see NexusReader
* @see NexusToken
* @see XBull
*
* This class handles reading and storage for the Nexus block TAXA.
* It overrides the member functions Read and Reset, which are abstract
* virtual functions in the base class NexusBlock. The taxon names are
* stored in an array of strings (taxonLabels) that is accessible through
* the member functions GetTaxonLabel, AddTaxonLabel, ChangeTaxonLabel,
* and GetNumTaxonLabels.
*
*
Below is a table showing the correspondence between the elements of a
* TAXA block and the variables and member functions that can be used
* to access each piece of information stored.
*
*
*/
/**
* @constructor
*
* Default constructor. Initializes id to "TAXA" and ntax to 0.
*/
TaxaBlock::TaxaBlock() : ntax(0), NexusBlock()
{
id = "TAXA";
}
/**
* @destructor
*
* Flushes taxonLabels.
*/
TaxaBlock::~TaxaBlock()
{
taxonLabels.erase( taxonLabels.begin(), taxonLabels.end() );
}
/**
* @method Read [void:protected]
* @param token [NexusToken&] the token used to read from in
* @throws XBull
*
* This function provides the ability to read everything following the block name
* (which is read by the Nexus object) to the end or endblock statement.
* Characters are read from the input stream in. Overrides the
* abstract virtual function in the base class.
*/
void TaxaBlock::Read( NexusToken& token )
{
isEmpty = false;
token.GetNextToken(); // this should be the semicolon after the block name
if ( !token.Equals(";") ) {
errormsg = "Expecting ';' after TAXA block name, but found ";
errormsg += token.GetToken();
errormsg += " instead";
throw XBull( errormsg, token);
}
for (;;)
{
token.GetNextToken();
if ( token.Equals("DIMENSIONS") ) {
token.GetNextToken(); // this should be the NTAX keyword
if ( !token.Equals("NTAX") ) {
errormsg = "Expecting NTAX keyword, but found ";
errormsg += token.GetToken();
errormsg += " instead";
throw XBull( errormsg, token);
}
token.GetNextToken(); // this should be the equals sign
if ( !token.Equals("=") ) {
errormsg = "Expecting '=', but found ";
errormsg += token.GetToken();
errormsg += " instead";
throw XBull( errormsg, token);
}
token.GetNextToken(); // this should be the number of taxa
ntax = atoi( token.GetToken().c_str() );
if ( ntax <= 0 ) {
errormsg = "NTAX should be greater than zero (";
errormsg += token.GetToken();
errormsg += " was specified)";
throw XBull( errormsg, token);
}
token.GetNextToken(); // this should be the terminating semicolon
if ( !token.Equals(";") ) {
errormsg = "Expecting ';' to terminate DIMENSIONS command, but found ";
errormsg += token.GetToken();
errormsg += " instead";
throw XBull( errormsg, token);
}
}
else if ( token.Equals("TAXLABELS") ) {
if ( ntax <= 0 ) {
errormsg = "NTAX must be specified before TAXLABELS command";
throw XBull( errormsg, token);
}
for ( int i = 0; i < ntax; i++ ) {
token.GetNextToken();
taxonLabels.push_back( token.GetToken() );
}
token.GetNextToken(); // this should be terminating semicolon
if ( !token.Equals(";") ) {
errormsg = "Expecting ';' to terminate TAXLABELS command, but found ";
errormsg += token.GetToken();
errormsg += " instead";
throw XBull( errormsg, token);
}
}
else if ( token.Equals("END") ) {
// get the semicolon following END
token.GetNextToken();
if ( !token.Equals(";") ) {
errormsg = "Expecting ';' to terminate the END command, but found ";
errormsg += token.GetToken();
errormsg += " instead";
throw XBull( errormsg, token);
}
break;
}
else if ( token.Equals("ENDBLOCK") ) {
// get the semicolon following ENDBLOCK
token.GetNextToken();
if ( !token.Equals(";") ) {
errormsg = "Expecting ';' to terminate the ENDBLOCK command, but found ";
errormsg += token.GetToken();
errormsg += " instead";
throw XBull( errormsg, token);
}
break;
}
else {
SkippingCommand( token.GetToken() );
do {
token.GetNextToken();
} while ( !token.AtEOF() && !token.Equals(";") );
if ( token.AtEOF() ) {
errormsg = "Unexpected end of file encountered";
throw XBull( errormsg, token);
}
}
}
}
/**
* @method Report [void:public]
* @param out [ostream&] the output stream to which to write the report
*
* This function outputs a brief report of the contents of this taxa block.
* Overrides the abstract virtual function in the base class.
*/
void TaxaBlock::Report(std::ostream& out )
{
out << endl;
out << id << " block contains ";
if ( ntax == 0 ) {
out << "no taxa" << endl;
}
else if ( ntax == 1 )
out << "one taxon" << endl;
else
out << ntax << " taxa" << endl;
if ( ntax == 0 ) return;
for ( int k = 0; k < ntax; k++ )
out << '\t' << (k+1) << '\t' << taxonLabels[k] << endl;
}
/**
* @method Reset [void:protected]
*
* Flushes taxonLabels and sets ntax to 0 in preparation for reading a
* new TAXA block.
*/
void TaxaBlock::Reset()
{
isEmpty = true;
taxonLabels.erase( taxonLabels.begin(), taxonLabels.end() );
ntax = 0;
}
/**
* @method AddTaxonLabel [void:public]
* @param s [std::string] the taxon label to add
*
* Adds taxon label s to end of list of taxon labels and increments
* ntax by 1.
*/
void TaxaBlock::AddTaxonLabel( std::string s )
{
isEmpty = false;
taxonLabels.push_back(s);
ntax++;
}
/**
* @method ChangeTaxonLabel [void:public]
* @param i [int] the taxon label number to change
* @param s [std::string] the string used to replace label i
*
* Changes the label for taxon i to s.
*/
void TaxaBlock::ChangeTaxonLabel( int i, std::string s )
{
assert( i < (int)taxonLabels.size() );
taxonLabels[i] = s;
}
/**
* @method GetMaxTaxonLabelLength [char*:public]
*
* Returns the length of the longest taxon label stored. Useful for
* formatting purposes in outputting the data matrix (i.e., you want the
* left edge of the matrix to line up).
*/
int TaxaBlock::GetMaxTaxonLabelLength()
{
assert( ntax == (int)taxonLabels.size() );
int maxlen = 0;
for ( int i = 0; i < ntax; i++ ) {
int thislen = taxonLabels[i].size();
if ( thislen > maxlen )
maxlen = thislen;
}
return maxlen;
}
/**
* @method GetTaxonLabel [char*:public]
* @param i [int] the taxon label number to return
*
* Returns the label for taxon i.
*/
std::string TaxaBlock::GetTaxonLabel( int i )
{
assert( i < (int)taxonLabels.size() );
return taxonLabels[i];
}
/**
* @method IsAlreadyDefined [bool:public]
* @param s [std::string] the s to attempt to find in the taxonLabels list
*
* Calls IsAlreadyDefined function of taxonLabels, which returns 0
* if a taxon label equal to s is already stored in taxonLabels.
* Returns 0 if no taxon label equal to s can be found in the
* taxonLabels list.
*/
bool TaxaBlock::IsAlreadyDefined( std::string s )
{
LabelList::const_iterator iter = find( taxonLabels.begin(), taxonLabels.end(), s );
int taxonLabelFound = ( iter != taxonLabels.end() );
return taxonLabelFound;
}
/**
* @method FindTaxon [int:public]
* @param s [std::string] the string to attempt to find in the taxonLabels list
* @throws TaxaBlock::nosuchtaxon
*
* Returns index of taxon named s in taxonLabels list. If taxon named
* s cannot be found, or if there are no labels currently stored in
* the taxonLabels list, throws nosuchtaxon exception.
*/
int TaxaBlock::FindTaxon( std::string s )
{
int k = 0;
std::string localTax;
BlanksToUnderscores(s);
LabelList::const_iterator i;
for ( i = taxonLabels.begin(); i != taxonLabels.end(); ++i ) {
if ( *i == s ) break;
localTax=*i;
BlanksToUnderscores(localTax);
if ( localTax == s) break;
k++;
}
if ( i == taxonLabels.end() )
throw TaxaBlock::nosuchtaxon();
return k;
}
/**
* @method GetNumTaxonLabels [int:public]
*
* Returns number of taxon labels currently stored.
*/
int TaxaBlock::GetNumTaxonLabels()
{
return taxonLabels.size();
}
/**
* @method SetNtax [void:private]
* @param n [int] the number of taxa
*
* Sets ntax to n.
*/
void TaxaBlock::SetNtax( int n )
{
ntax = n;
}