// This file is part of BULL, a program for phylogenetic simulations // most of the code was written by Mark T. Holder. // 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. // 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. * *

* * * *
Nexus command * Nexus subcommand * Data Members * Member Functions *
DIMENSIONS * NTAX * int ntax * int GetNumTaxonLabels() *
TAXLABELS * LabelList taxonLabels * std::string GetTaxonLabel( int i ) *
int FindTaxon( std::string label ) *
int GetMaxTaxonLabelLength() *
*/ /** * @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; }