The OutputManager
will handle opening and closing tree and parameter files, saving sampled trees to the tree file, saving sampled parameter values to the parameter file, and displaying output to the console.
Some changes/additions will need to be made to the Data
and Model
classes, but that will be postponed until after we’ve created the OutputManager
class.
Create a new file output_manager.hpp and replace the default contents with the following class declaration.
#pragma once
#include "data.hpp"
#include "tree_manip.hpp"
#include "model.hpp"
#include "xstrom.hpp"
#include <fstream>
namespace strom {
class OutputManager {
public:
typedef std::shared_ptr< OutputManager > SharedPtr;
OutputManager();
~OutputManager();
void setModel(Model::SharedPtr model) {_model = model;}
void setTreeManip(TreeManip::SharedPtr tm) {_tree_manip = tm;}
void openTreeFile(std::string filename, Data::SharedPtr data);
void openParameterFile(std::string filename, Model::SharedPtr model);
void closeTreeFile();
void closeParameterFile();
void outputConsole(std::string s);
void outputTree(unsigned iter, TreeManip::SharedPtr tm);
void outputParameters(unsigned iter, double lnL, double lnP, double TL, Model::SharedPtr model);
private:
TreeManip::SharedPtr _tree_manip;
Model::SharedPtr _model;
std::ofstream _treefile;
std::ofstream _parameterfile;
std::string _tree_file_name;
std::string _param_file_name;
};
// member function bodies go here
}
The constructor stores default names for the tree and parameter files, and the destructor is empty. (The output lines are provided but can remain commented out unless you need them at a later time.)
inline OutputManager::OutputManager() {
//std::cout << "Constructing an OutputManager" << std::endl;
_tree_file_name = "trees.t";
_param_file_name = "params.p";
}
inline OutputManager::~OutputManager() {
//std::cout << "Destroying an OutputManager" << std::endl;
}
These functions are responsible for opening and closing the file used to store trees sampled during the MCMC simulation. Note that some of the work in the openTreeFile
function is done by the Data
class: because the Data
object knows the taxon names, it can easily write out the taxa block for us, as well as the translate command in the trees block.
inline void OutputManager::openTreeFile(std::string filename, Data::SharedPtr data) {
assert(!_treefile.is_open());
_tree_file_name = filename;
_treefile.open(_tree_file_name.c_str());
if (!_treefile.is_open())
throw XStrom(boost::str(boost::format("Could not open tree file \"%s\"") % _tree_file_name));
_treefile << "#nexus\n\n";
_treefile << data->createTaxaBlock() << std::endl;
_treefile << "begin trees;\n";
_treefile << data->createTranslateStatement() << std::endl;
}
inline void OutputManager::closeTreeFile() {
assert(_treefile.is_open());
_treefile << "end;\n";
_treefile.close();
}
These functions are responsible for opening and closing the file used to store model parameters sampled during the MCMC simulation. The openParameterFile
function asks the supplied Model
object to provide a list of parameter names that it then uses for column headers when creating a new parameter file.
inline void OutputManager::openParameterFile(std::string filename, Model::SharedPtr model) {
assert(model);
assert(!_parameterfile.is_open());
_param_file_name = filename;
_parameterfile.open(_param_file_name.c_str());
if (!_parameterfile.is_open())
throw XStrom(boost::str(boost::format("Could not open parameter file \"%s\"") % _param_file_name));
_parameterfile << boost::str(boost::format("%s\t%s\t%s\t%s\t%s") % "iter" % "lnL" % "lnPr" % "TL" % model->paramNamesAsString("\t")) << std::endl;
}
inline void OutputManager::closeParameterFile() {
assert(_parameterfile.is_open());
_parameterfile.close();
}
These three functions are called to output messages to the user on the console, output sampled trees to the tree file, and output sampled parameters to the parameter file, respectively. The outputConsole
function currently just outputs the supplied message to the terminal (console), but could easily be modified to output the same message to both the console and to a file (we are not going to write that code in this tutorial, however). The outputTree
function asks the supplied TreeManip
object to provide the tree description that it then stores in the tree file. The outputParameters
function asks the supplied Model
object to provide the current values of all model parameters that it then stores in the parameters file.
inline void OutputManager::outputConsole(std::string s) {
std::cout << s << std::endl;
}
inline void OutputManager::outputTree(unsigned iter, TreeManip::SharedPtr tm) {
assert(_treefile.is_open());
assert(tm);
_treefile << boost::str(boost::format(" tree iter_%d = %s;") % iter % tm->makeNewick(5)) << std::endl;
}
inline void OutputManager::outputParameters(unsigned iter, double lnL, double lnP, double TL, Model::SharedPtr model) {
assert(model);
assert(_parameterfile.is_open());
_parameterfile << boost::str(boost::format("%d\t%.5f\t%.5f\t%.5f\t%s") % iter % lnL % lnP % TL % model->paramValuesAsString("\t")) << std::endl;
}