Skip to content

Commit

Permalink
Refs #5319: moved methods for algorithm history saving/loading
Browse files Browse the repository at this point in the history
to WorkspaceHistory, for code reuse
  • Loading branch information
Janik Zikovsky committed May 16, 2012
1 parent 2fd8100 commit 7eb9215
Show file tree
Hide file tree
Showing 8 changed files with 286 additions and 65 deletions.
2 changes: 2 additions & 0 deletions Code/Mantid/Framework/API/inc/MantidAPI/Algorithm.h
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,8 @@ class MANTID_API_DLL Algorithm : public IAlgorithm, public Kernel::PropertyManag
bool m_parallelException;
/// Reference to the logger class
Kernel::Logger& g_log;

friend class WorkspaceHistory; // Allow workspace history loading to adjust g_execCount
static size_t g_execCount; ///< Counter to keep track of algorithm execution order

// ------------------ For WorkspaceGroups ------------------------------------
Expand Down
9 changes: 9 additions & 0 deletions Code/Mantid/Framework/API/inc/MantidAPI/WorkspaceHistory.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@
//----------------------------------------------------------------------
#include "MantidAPI/AlgorithmHistory.h"
#include "MantidKernel/EnvironmentHistory.h"
#include "MantidNexusCPP/NeXusFile.hpp"
#include <boost/shared_ptr.hpp>
#include <ctime>
#include <list>
#include "MantidKernel/Logger.h"

namespace Mantid
{
Expand Down Expand Up @@ -78,6 +80,10 @@ class MANTID_API_DLL WorkspaceHistory
/// Pretty print the entire history
void printSelf(std::ostream&, const int indent = 0) const;

void saveNexus(::NeXus::File * file) const;
void loadNexus(::NeXus::File * file);


private:
/// Private, unimplemented copy assignment operator
WorkspaceHistory& operator=(const WorkspaceHistory& );
Expand All @@ -87,6 +93,9 @@ class MANTID_API_DLL WorkspaceHistory
/// The algorithms which have been called on the workspace
AlgorithmHistories m_algorithms;

/// Reference to the logger class
Kernel::Logger& g_log;

};

MANTID_API_DLL std::ostream& operator<<(std::ostream&, const WorkspaceHistory&);
Expand Down
225 changes: 223 additions & 2 deletions Code/Mantid/Framework/API/src/WorkspaceHistory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,22 @@
#include "MantidAPI/WorkspaceHistory.h"
#include "MantidAPI/AlgorithmHistory.h"
#include "MantidAPI/Algorithm.h"
#include "MantidKernel/EnvironmentHistory.h"
#include <boost/algorithm/string/split.hpp>
#include "Poco/DateTime.h"
#include <Poco/DateTimeParser.h>

using Mantid::Kernel::EnvironmentHistory;
using boost::algorithm::split;

namespace Mantid
{
namespace API
{

///Default Constructor
WorkspaceHistory::WorkspaceHistory() : m_environment(), m_algorithms()
WorkspaceHistory::WorkspaceHistory() : m_environment(), m_algorithms(),
g_log(Kernel::Logger::get("WorkspaceHistory"))
{}

/// Destructor
Expand All @@ -23,7 +31,8 @@ WorkspaceHistory::~WorkspaceHistory()
@param A :: WorkspaceHistory Item to copy
*/
WorkspaceHistory::WorkspaceHistory(const WorkspaceHistory& A) :
m_environment(A.m_environment), m_algorithms(A.m_algorithms)
m_environment(A.m_environment), m_algorithms(A.m_algorithms),
g_log(Kernel::Logger::get("WorkspaceHistory"))
{}

/// Returns a const reference to the algorithmHistory
Expand Down Expand Up @@ -145,6 +154,218 @@ void WorkspaceHistory::printSelf(std::ostream& os, const int indent)const
}
}

//------------------------------------------------------------------------------------------------
/** Saves all of the workspace history to a "process" field
* in an open NXS file.
* Code taken from NexusFileIO.cpp on May 14, 2012.
*
* @param file :: previously opened NXS file.
*/
void WorkspaceHistory::saveNexus(::NeXus::File * file) const
{
file->makeGroup("process", "NXprocess", true);
std::stringstream output,algorithmNumber;

// Environment history
EnvironmentHistory envHist;
output << envHist;
char buffer [25];
time_t now;
time(&now);
strftime (buffer,25,"%Y-%b-%d %H:%M:%S",localtime(&now));
file->makeGroup("MantidEnvironment", "NXNote", true);
file->writeData("author", "mantid");
file->openData("author");
file->putAttr("date", std::string(buffer));
file->closeData();
file->writeData("description", "Mantid Environment data");
file->writeData("data", output.str());
file->closeGroup();

// Algorithm History
typedef std::map <std::size_t,std::string> orderedHistMap;
orderedHistMap ordMap;
for(std::size_t i=0;i<this->size();i++)
{
std::stringstream algNumber,algData;
const API::AlgorithmHistory & entry = this->getAlgorithmHistory(i);
entry.printSelf(algData);

//get execute count
std::size_t nexecCount=entry.execCount();
//order by execute count
ordMap.insert(orderedHistMap::value_type(nexecCount,algData.str()));
}
int num=0;
std::map <std::size_t,std::string>::iterator m_Iter;
for (m_Iter=ordMap.begin( );m_Iter!=ordMap.end( );++m_Iter)
{
++num;
std::stringstream algNumber;
algNumber << "MantidAlgorithm_" << num;

file->makeGroup(algNumber.str(), "NXNote", true);
file->writeData("author", std::string("mantid"));
file->writeData("description", std::string("Mantid Algorithm data"));
file->writeData("data", m_Iter->second);
file->closeGroup();
}
file->closeGroup();
}

//-------------------------------------------------------------------------------------------------
/** If the first string contains exactly three words separated by spaces
* these words will be copied into each of the following strings that were passed
* @param[in] words3 a string with 3 words separated by spaces
* @param[out] w1 the first word in the input string
* @param[out] w2 the second word in the input string
* @param[out] w3 the third word in the input string
* @throw out_of_range if there aren't exaltly three strings in the word
*/
void getWordsInString(const std::string & words3, std::string & w1, std::string & w2, std::string & w3 )
{
Poco::StringTokenizer data(words3, " ", Poco::StringTokenizer::TOK_TRIM);
if (data.count() != 3)
throw std::out_of_range("Algorithm list line " + words3 + " is not of the correct format\n");

w1 = data[0];
w2 = data[1];
w3 = data[2];
}



//-------------------------------------------------------------------------------------------------
/** If the first string contains exactly four words separated by spaces
* these words will be copied into each of the following strings that were passed
* @param[in] words4 a string with 4 words separated by spaces
* @param[out] w1 the first word in the input string
* @param[out] w2 the second word in the input string
* @param[out] w3 the third word in the input string
* @param[out] w4 the fourth word in the input string
* @throw out_of_range if there aren't exaltly four strings in the word
*/
void getWordsInString(const std::string & words4, std::string & w1, std::string & w2, std::string & w3, std::string & w4)
{
Poco::StringTokenizer data(words4, " ", Poco::StringTokenizer::TOK_TRIM);
if (data.count() != 4)
throw std::out_of_range("Algorithm list line " + words4 + " is not of the correct format\n");

w1 = data[0];
w2 = data[1];
w3 = data[2];
w4 = data[3];
}


//------------------------------------------------------------------------------------------------
/** Opens a group called "process" and loads the workspace history from
* it.
*
* @param file :: previously opened NXS file.
*/
void WorkspaceHistory::loadNexus(::NeXus::File * file)
{
/// specifies the order that algorithm data is listed in workspaces' histories
enum AlgorithmHist
{
NAME = 0, //< algorithms name
EXEC_TIME = 1, //< when the algorithm was run
EXEC_DUR = 2, //< execution time for the algorithm
PARAMS = 3 //< the algorithm's parameters
};


file->openGroup("process", "NXprocess");
std::map<std::string, std::string> entries;
file->getEntries(entries);
// Entries should be sorted by name
for (auto it = entries.begin(); it != entries.end(); ++it)
{
std::string entryName = it->first;
if( entryName.find("MantidAlgorithm") != std::string::npos )
{
file->openGroup(entryName, "NXprocess");
std::string rawData;
file->readData("data", rawData);
file->closeData();
file->closeGroup();

// Split into separate lines
std::vector<std::string> info;
boost::split(info, rawData, boost::is_any_of("\n"));

const size_t nlines = info.size();
if( nlines < 4 )
{// ignore badly formed history entries
continue;
}

std::string algName, dummy, temp;
// get the name and version of the algorithm
getWordsInString(info[NAME], dummy, algName, temp);

//Chop of the v from the version string
size_t numStart = temp.find('v');
// this doesn't abort if the version string doesn't contain a v
numStart = numStart != 1 ? 1 : 0;
temp = std::string(temp.begin() + numStart, temp.end());
const int version = boost::lexical_cast<int>(temp);

//Get the execution date/time
std::string date, time;
getWordsInString(info[EXEC_TIME], dummy, dummy, date, time);
Poco::DateTime start_timedate;
//This is needed by the Poco parsing function
int tzdiff(-1);
if( !Poco::DateTimeParser::tryParse("%Y-%b-%d %H:%M:%S", date + " " + time, start_timedate, tzdiff))
{
g_log.warning() << "Error parsing start time in algorithm history entry." << "\n";
return;
}
//Get the duration
getWordsInString(info[EXEC_DUR], dummy, dummy, temp, dummy);
double dur = boost::lexical_cast<double>(temp);
if ( dur < 0.0 )
{
g_log.warning() << "Error parsing start time in algorithm history entry." << "\n";
return;
}
//Convert the timestamp to time_t to DateAndTime
Mantid::Kernel::DateAndTime utc_start;
utc_start.set_from_time_t( start_timedate.timestamp().epochTime() );
//Create the algorithm history
API::AlgorithmHistory alg_hist(algName, version, utc_start, dur,Algorithm::g_execCount);
// Simulate running an algorithm
++Algorithm::g_execCount;

//Add property information
for( size_t index = static_cast<size_t>(PARAMS)+1;index < nlines;++index )
{
const std::string line = info[index];
std::string::size_type colon = line.find(":");
std::string::size_type comma = line.find(",");
//Each colon has a space after it
std::string prop_name = line.substr(colon + 2, comma - colon - 2);
colon = line.find(":", comma);
comma = line.find(", Default?", colon);
std::string prop_value = line.substr(colon + 2, comma - colon - 2);
colon = line.find(":", comma);
comma = line.find(", Direction", colon);
std::string is_def = line.substr(colon + 2, comma - colon - 2);
colon = line.find(":", comma);
comma = line.find(",", colon);
std::string direction = line.substr(colon + 2, comma - colon - 2);
unsigned int direc(Mantid::Kernel::Direction::asEnum(direction));
alg_hist.addProperty(prop_name, prop_value, (is_def[0] == 'Y'), direc);
}
this->addHistory(alg_hist);
}
}
}


//------------------------------------------------------------------------------------------------
/** Prints a text representation
* @param os :: The ouput stream to write to
* @param WH :: The WorkspaceHistory to output
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,14 +71,6 @@ namespace Mantid
private:
/// Sets documentation strings for this algorithm
virtual void initDocs();
/// specifies the order that algorithm data is listed in workspaces' histories
enum AlgorithmHist
{
NAME = 0, //< algorithms name
EXEC_TIME = 1, //< when the algorithm was run
EXEC_DUR = 2, //< execution time for the algorithm
PARAMS = 3 //< the algorithm's parameters
};

/// Overwrites Algorithm method.
void init();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -324,7 +324,9 @@ namespace DataHandling
nexusFile->writeNexusTableWorkspace(tableWorkspace,"table_workspace");
} // finish table workspace specifics

nexusFile->writeNexusProcessedProcess(inputWorkspace);
// Switch to the Cpp API for the algorithm history
inputWorkspace->getHistory().saveNexus(cppFile);

nexusFile->closeNexusFile();

delete nexusFile;
Expand Down
3 changes: 0 additions & 3 deletions Code/Mantid/Framework/Nexus/inc/MantidNexus/NexusClasses.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,9 +79,6 @@ namespace Mantid
/// Default block size for reading and writing processed files
const int g_processed_blocksize = 8;

/// Formatting string for DateTime objects within the AlgorithmHistory objects
const std::string g_processed_datetime = std::string("%Y-%b-%d %H:%M:%S");

/** Nexus attributes. The type of each attribute is NX_CHAR
*/
class DLLExport NXAttributes
Expand Down
2 changes: 0 additions & 2 deletions Code/Mantid/Framework/Nexus/inc/MantidNexus/NexusFileIO.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,6 @@ namespace Mantid
/// read values and errors for spectra
int getSpectra(MantidVec& values, MantidVec& errors, const int& spectra) const;

/// write the algorithm and environment information
int writeNexusProcessedProcess(const API::Workspace_const_sptr& localworkspace) const;
/// write bin masking information
bool writeNexusBinMasking(API::MatrixWorkspace_const_sptr ws) const;

Expand Down

0 comments on commit 7eb9215

Please sign in to comment.