// NexusWriter.cpp #if defined(_WIN32) || defined(_WIN64) // C4290 - the compiler ignores exception specifications #pragma warning(disable: 4290) #endif #include #include "NexusWriter.hpp" namespace Cipres { namespace SequenceFormats { // NexusWriter NexusWriter::StandardDataBlock &NexusWriter::AddStandardDataBlock() throw(std::bad_alloc, std::runtime_error) { if(m_data_blocks.empty()) m_data_type = STANDARD; else if(m_data_type != STANDARD) throw std::runtime_error("mixed data type is not supported"); std::auto_ptr new_block(new StandardDataBlock(*this)); m_data_blocks.push_back(new_block.get()); return *new_block.release(); } NexusWriter::MolecularDataBlock &NexusWriter::AddDnaDataBlock() throw(std::bad_alloc, std::runtime_error) { if(m_data_blocks.empty()) m_data_type = DNA; else if(m_data_type != DNA) throw std::runtime_error("mixed data type is not supported"); std::auto_ptr new_block(new MolecularDataBlock(*this)); m_data_blocks.push_back(new_block.get()); return *new_block.release(); } NexusWriter::MolecularDataBlock &NexusWriter::AddProteinDataBlock() throw(std::bad_alloc, std::runtime_error) { if(m_data_blocks.empty()) m_data_type = PROTEIN; else if(m_data_type != PROTEIN) throw std::runtime_error("mixed data type is not supported"); std::auto_ptr new_block(new MolecularDataBlock(*this)); m_data_blocks.push_back(new_block.get()); return *new_block.release(); } NexusWriter::ContinuousDataBlock &NexusWriter::AddContinuousDataBlock() throw(std::bad_alloc, std::runtime_error) { if(m_data_blocks.empty()) m_data_type = CONTINUOUS; else if(m_data_type != CONTINUOUS) throw std::runtime_error("mixed data type is not supported"); std::auto_ptr new_block(new ContinuousDataBlock(*this)); m_data_blocks.push_back(new_block.get()); return *new_block.release(); } void NexusWriter::Write(std::ostream &output) const throw(std::bad_alloc, std::runtime_error, std::ios_base::failure) { if(m_taxa_by_name.empty()) throw std::runtime_error("no taxa"); output.exceptions(std::ios_base::badbit); output.write("#NEXUS\n[ Written by CIPRES ]\n", 29); if(!m_title.empty()) { output.put('['); output << m_title; output.write("]\n", 2); } WriteTaxaBlock(output); size_t num_chars = 0; for(DataBlockList::const_iterator i = m_data_blocks.begin() ; i != m_data_blocks.end() ; i++) num_chars += (*i)->MaxNumChars(); output.write("BEGIN CHARACTERS;\n DIMENSIONS NCHAR=", 37); output << num_chars; output.write(";\n FORMAT DATATYPE=", 20); if(m_data_type == DNA) output.write("DNA GAP=-", 9); else if(m_data_type == RNA) output.write("RNA GAP=-", 9); else if(m_data_type == NUCLEOTIDE) output.write("NUCLEOTIDE GAP=-", 16); else if(m_data_type == PROTEIN) output.write("PROTEIN GAP=-", 13); else if(m_data_type == CONTINUOUS) { output.precision(3); output.setf(std::ios::fixed); output.write("CONTINUOUS", 10); } else { assert(m_data_type == STANDARD); output.write("STANDARD GAP=- SYMBOLS=\"", 24); output << m_symbols.substr(4); output.put('"'); } output.write(";\n MATRIX", 10); if(m_data_blocks.size() == 1) m_data_blocks[0]->WriteCharBlock(output); else { size_t ordinal = 0; for(TaxonNameList::const_iterator i = m_taxa_by_ordinal.begin() ; i != m_taxa_by_ordinal.end() ; i++, ordinal++) { output.write("\n ", 5); output << *i; output.put(' '); for(DataBlockList::const_iterator j = m_data_blocks.begin() ; j != m_data_blocks.end() ; j++) { const DataBlock *block = *j; if(!block->WriteCharSequence(ordinal, output)) { size_t block_num_chars = block->MaxNumChars(); for(size_t k = 0 ; k < block_num_chars ; k++) output.put('?'); } } } } output.write(";\nEND;\n", 7); } size_t NexusWriter::AddTaxon(const std::string name) throw(std::bad_alloc) { size_t ordinal; TaxonOrdinalMap::const_iterator map_node(m_taxa_by_name.find(name)); if(map_node == m_taxa_by_name.end()) { ordinal = m_taxa_by_name.size(); m_taxa_by_name.insert(TaxonOrdinalMap::value_type(name, ordinal)); m_taxa_by_ordinal.push_back(name); } else ordinal = (*map_node).second; return ordinal; } void NexusWriter::WriteTaxaBlock(std::ostream &output) const throw(std::bad_alloc, std::ios_base::failure) { output.write("BEGIN TAXA;\n DIMENSIONS NTAX=", 30); output << m_taxa_by_ordinal.size(); output.write(";\n TAXLABELS", 13); for(TaxonNameList::const_iterator i = m_taxa_by_ordinal.begin() ; i != m_taxa_by_ordinal.end() ; i++) { output.put(' '); output << *i; } output.write(";\nEND;\n", 7); } // NexusWriter::StandardDataBlock NexusWriter::DiscreteTaxon &NexusWriter::StandardDataBlock::AddTaxon(const std::string name) throw(std::bad_alloc, std::runtime_error) { size_t ordinal = m_owner.AddTaxon(name); std::auto_ptr new_taxon(new DiscreteTaxon(ordinal, name)); std::pair result(m_taxa.insert(DiscreteTaxonMap::value_type(ordinal, new_taxon.get()))); if(!result.second) throw std::runtime_error("duplicate taxon name"); return *new_taxon.release(); } size_t NexusWriter::StandardDataBlock::MaxNumChars() const throw() { size_t max_num_chars = 0; for(DiscreteTaxonMap::const_iterator i = m_taxa.begin() ; i != m_taxa.end() ; i++) { size_t num_chars = (*i).second->m_num_chars; if(num_chars > max_num_chars) max_num_chars = num_chars; } return max_num_chars; } void NexusWriter::StandardDataBlock::WriteCharBlock(std::ostream &output) const throw(std::ios_base::failure) { for(DiscreteTaxonMap::const_iterator i = m_taxa.begin() ; i != m_taxa.end() ; i++) { const DiscreteTaxon *taxon = (*i).second; output.write("\n ", 5); output << taxon->m_name; output.put(' '); for(Taxon::DiscreteCharList::const_iterator j = taxon->m_characters.begin() ; j != taxon->m_characters.end() ; j++) output.put(m_owner.StateToSymbol(*j)); } } bool NexusWriter::StandardDataBlock::WriteCharSequence(size_t ordinal, std::ostream &output) const throw(std::ios_base::failure) { DiscreteTaxonMap::const_iterator map_node(m_taxa.find(ordinal)); if(map_node == m_taxa.end()) return false; const DiscreteTaxon *taxon = (*map_node).second; for(Taxon::DiscreteCharList::const_iterator i = taxon->m_characters.begin() ; i != taxon->m_characters.end() ; i++) output.put(m_owner.StateToSymbol(*i)); return true; } // NexusWriter::MolecularDataBlock NexusWriter::DiscreteTaxon &NexusWriter::MolecularDataBlock::AddTaxon(const std::string name) throw(std::bad_alloc, std::runtime_error) { size_t ordinal = m_owner.AddTaxon(name); std::auto_ptr new_taxon(new DiscreteTaxon(ordinal, name)); std::pair result(m_taxa.insert(DiscreteTaxonMap::value_type(ordinal, new_taxon.get()))); if(!result.second) throw std::runtime_error("duplicate taxon name"); return *new_taxon.release(); } size_t NexusWriter::MolecularDataBlock::MaxNumChars() const throw() { size_t max_num_chars = 0; for(DiscreteTaxonMap::const_iterator i = m_taxa.begin() ; i != m_taxa.end() ; i++) { size_t num_chars = (*i).second->m_num_chars; if(num_chars > max_num_chars) max_num_chars = num_chars; } return max_num_chars; } void NexusWriter::MolecularDataBlock::WriteCharBlock(std::ostream &output) const throw(std::ios_base::failure) { for(DiscreteTaxonMap::const_iterator i = m_taxa.begin() ; i != m_taxa.end() ; i++) { const DiscreteTaxon *taxon = (*i).second; output.write("\n ", 5); output << taxon->m_name; output.put(' '); for(Taxon::DiscreteCharList::const_iterator j = taxon->m_characters.begin() ; j != taxon->m_characters.end() ; j++) output.put(CodeToSymbol(*j)); } } bool NexusWriter::MolecularDataBlock::WriteCharSequence(size_t ordinal, std::ostream &output) const throw(std::ios_base::failure) { DiscreteTaxonMap::const_iterator map_node(m_taxa.find(ordinal)); if(map_node == m_taxa.end()) return false; const DiscreteTaxon *taxon = (*map_node).second; for(Taxon::DiscreteCharList::const_iterator i = taxon->m_characters.begin() ; i != taxon->m_characters.end() ; i++) output.put(CodeToSymbol(*i)); return true; } // NexusWriter::ContinuousDataBlock NexusWriter::ContinuousTaxon &NexusWriter::ContinuousDataBlock::AddTaxon(const std::string name) throw(std::bad_alloc, std::runtime_error) { size_t ordinal = m_owner.AddTaxon(name); std::auto_ptr new_taxon(new ContinuousTaxon(ordinal, name)); std::pair result(m_taxa.insert(ContinuousTaxonMap::value_type(ordinal, new_taxon.get()))); if(!result.second) throw std::runtime_error("duplicate taxon name"); return *new_taxon.release(); } size_t NexusWriter::ContinuousDataBlock::MaxNumChars() const throw() { size_t max_num_chars = 0; for(ContinuousTaxonMap::const_iterator i = m_taxa.begin() ; i != m_taxa.end() ; i++) { size_t num_chars = (*i).second->m_num_chars; if(num_chars > max_num_chars) max_num_chars = num_chars; } return max_num_chars; } void NexusWriter::ContinuousDataBlock::WriteCharBlock(std::ostream &output) const throw(std::ios_base::failure) { for(ContinuousTaxonMap::const_iterator i = m_taxa.begin() ; i != m_taxa.end() ; i++) { const ContinuousTaxon *taxon = (*i).second; output.write("\n ", 5); output << taxon->m_name; output.put(' '); for(Taxon::ContinuousCharList::const_iterator j = taxon->m_characters.begin() ; j != taxon->m_characters.end() ; j++) { float character = *j; if(character >= 0) output << character; else output.put('?'); output.put(' '); } } } bool NexusWriter::ContinuousDataBlock::WriteCharSequence(size_t ordinal, std::ostream &output) const throw(std::ios_base::failure) { ContinuousTaxonMap::const_iterator map_node(m_taxa.find(ordinal)); if(map_node == m_taxa.end()) return false; const ContinuousTaxon *taxon = (*map_node).second; for(Taxon::ContinuousCharList::const_iterator i = taxon->m_characters.begin() ; i != taxon->m_characters.end() ; i++) { float character = *i; if(character >= 0) output << character; else output.put('?'); output.put(' '); } return true; } } // namespace SequenceFormats } // namespace Cipres