Newer
Older
//---------------------------------------------------
// Includes
//---------------------------------------------------
#include "MantidAPI/FileProperty.h"
#include "MantidDataHandling/SaveOpenGenieAscii.h"
#include "MantidKernel/ListValidator.h"
#include "MantidKernel/Exception.h"
#include "MantidKernel/VisibleWhenProperty.h"
#include "MantidKernel/Property.h"
#include <exception>
#include <fstream>
#include <list>
#include <vector>
#include <Poco/File.h>
#include <Poco/Path.h>
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
namespace DatHandling {
using namespace Kernel;
using namespace Mantid::API;
// Register the algorithm into the AlgorithmFactory
DECLARE_ALGORITHM(SaveOpenGenieAscii)
/// Empty constructor
SaveOpenGenieAscii::SaveOpenGenieAscii() : Mantid::API::Algorithm() {}
//---------------------------------------------------
// Private member functions
//---------------------------------------------------
/**
* Initialise the algorithm
*/
void SaveOpenGenieAscii::init() {
declareProperty(
new API::WorkspaceProperty<>("InputWorkspace", "",
Kernel::Direction::Input),
"The name of the workspace containing the data you wish to save");
// Declare required parameters, filename with ext {.his} and input
// workspac
std::vector<std::string> his_exts;
his_exts.push_back(".his");
his_exts.push_back(".txt");
his_exts.push_back("");
declareProperty(
new API::FileProperty("Filename", "", API::FileProperty::Save, his_exts),
"The filename to use for the saved data");
declareProperty("IncludeHeader", true,
"Whether to include the header lines (default: true)");
std::vector<std::string> header(2);
header[0] = "ENGIN-X Format";
header[1] = "Basic Format";
declareProperty("OpenGenieFormat", "ENGIN-X Format",
boost::make_shared<Kernel::StringListValidator>(header),
"The format required to succesfully load the file to "
"OpenGnie: ENGIN-X Format (default)");
declareProperty(
"SpecNumberField", "",
"Spec number is a required field for ENGIN-X format of OpenGenie,"
"an example of spec number would be: 1201 - 1400");
setPropertySettings("SpecNumberField",
new VisibleWhenProperty("OpenGenieFormat", IS_EQUAL_TO,
"ENGIN-X Format"));
}
void SaveOpenGenieAscii::exec() {
// Process properties
// Retrieve the input workspace
/// Workspace
ws = getProperty("InputWorkspace");
int nSpectra = static_cast<int>(ws->getNumberHistograms());
int nBins = static_cast<int>(ws->blocksize());
// Retrieve the filename from the properties
std::string filename = getProperty("Filename");
// Output string variables
const std::string singleSpc = " ";
const std::string fourspc = " ";
// file
std::ofstream outfile(filename.c_str());
if (!outfile) {
g_log.error("Unable to create file: " + filename);
throw Exception::FileError("Unable to create file: ", filename);
}
if (nBins == 0 || nSpectra == 0)
throw std::runtime_error("Trying to save an empty workspace");
// Axis alphabets
const std::string Alpha[] = {"\"e\"", "\"x\"", "\"y\""};
// Get IncludeHeader property
const bool headers = getProperty("IncludeHeader");
// if true write file header
if (headers) {
writeFileHeader(outfile);
}
bool isHistogram = ws->isHistogramData();
Progress progress(this, 0, 1, nBins);
// writes out x, y, e to vector
std::string alpha;
for (int Num = 0; Num < 3; Num++) {
alpha = Alpha[Num];
axisToFile(alpha, singleSpc, fourspc, nBins, isHistogram);
// get all the sample in workspace
getSampleLogs(fourspc);
// add ntc sample log
addNtc(fourspc, nBins);
// Getting the format property
std::string formatType = getProperty("OpenGenieFormat");
if (formatType == "ENGIN-X Format") {
// Apply EnginX format if selected
applyEnginxFormat(fourspc);
} else {
std::stringstream msg;
msg << "Unrecognized format \"" << formatType << "\"";
throw std::runtime_error(msg.str());
}
// write out all samples in the vector
writeSampleLogs(outfile);
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
progress.report();
return;
}
// -----------------------------------------------------------------------------
/** generates the OpenGenie file header
* @param outfile :: File it will save it out to
*/
void SaveOpenGenieAscii::writeFileHeader(std::ofstream &outfile) {
const std::vector<Property *> &logData = ws->run().getLogData();
auto &log = logData;
// get total number of sample logs
auto samplenumber = (&log)->size();
samplenumber += 3; // x, y, e
outfile << "# Open Genie ASCII File #" << std::endl
<< "# label " << std::endl
<< "GXWorkspace" << std::endl
// number of entries
<< samplenumber << std::endl;
}
//------------------------------------------------------------------------------
/** generates the header for the axis which saves to file
* @param alpha :: onstant string Axis letter that is being used
* @param singleSpc :: Constant string for single space
* @param fourspc :: Constant string for four spaces
* @param nBins :: Number of bins
* @return A string of of the header for the x y and e
std::string SaveOpenGenieAscii::getAxisHeader(const std::string alpha,
const std::string singleSpc,
const std::string fourspc,
int nBins) {
std::string outStr = "";
const std::string GXR = "GXRealarray";
const std::string banknum = "1";
const std::string twospc = " ";
outStr += twospc + singleSpc + alpha + "\n";
outStr += fourspc + GXR + "\n";
outStr += fourspc + banknum + "\n";
outStr += fourspc + boost::lexical_cast<std::string>(nBins) + "\n";
}
//-----------------------------------------------------------------------------
/** Uses AxisHeader and WriteAxisValues to write in vector
* @param alpha :: Axis letter that is being used
* @param singleSpc :: Constant string for single space
* @param fourspc :: Constant string for four spaces
* @param nBins :: number of bins
* @param isHistogram :: If its a histogram
*/
void SaveOpenGenieAscii::axisToFile(const std::string alpha,
const std::string singleSpc,
const std::string fourspc, int nBins,
bool isHistogram) {
std::string out_str = getAxisHeader(alpha, singleSpc, fourspc, nBins);
for (int bin = 0; bin < nBins; bin++) {
if (isHistogram) // bin centres
{
if (bin == 0) {
out_str += fourspc;
}
auto axisStr = getAxisValues(alpha, bin, singleSpc);
out_str += axisStr;
if ((bin + 1) % 10 == 0 && bin != (nBins - 1)) {
out_str += "\n" + fourspc;
}
}
}
out_str += "\n";
}
//------------------------------------------------------------------------
/** Reads if alpha is e then reads the E values accordingly
* @param alpha :: Axis letter that is being used
* @param bin :: bin counter which goes through all the bin
* @param singleSpc :: Constant string for single space
* @return A string of either e, x or y
std::string SaveOpenGenieAscii::getAxisValues(std::string alpha, int bin,
const std::string singleSpc) {
std::string output = "";
if (alpha == "\"e\"") {
output += boost::lexical_cast<std::string>(ws->readE(0)[bin]) + singleSpc;
}
if (alpha == "\"x\"") {
output += boost::lexical_cast<std::string>(ws->readX(0)[bin]) + singleSpc;
}
if (alpha == "\"y\"") {
output += boost::lexical_cast<std::string>(ws->readY(0)[bin]) + singleSpc;
}
return output;
}
//-----------------------------------------------------------------------
/** Reads the sample logs and writes to vector
* @param fourspc :: Constant string for four spaces
*/
void SaveOpenGenieAscii::getSampleLogs(std::string fourspc) {
const std::vector<Property *> &logData = ws->run().getLogData();
for (auto log = logData.begin(); log != logData.end(); ++log) {
std::string name = (*log)->name();
std::string type = (*log)->type();
std::string value = (*log)->value();
if (type.std::string::find("vector") &&
type.std::string::find("double") != std::string::npos) {
auto tsp = ws->run().getTimeSeriesProperty<double>(name);
value = boost::lexical_cast<std::string>(tsp->timeAverageValue());
}
else if (type.std::string::find("vector") &&
type.std::string::find("int") != std::string::npos) {
auto tsp = ws->run().getTimeSeriesProperty<int>(name);
value = boost::lexical_cast<std::string>(tsp->timeAverageValue());
}
else if (type.std::string::find("vector") &&
type.std::string::find("bool") != std::string::npos) {
auto tsp = ws->run().getTimeSeriesProperty<bool>(name);
value = boost::lexical_cast<std::string>(tsp->timeAverageValue());
}
else if (type.std::string::find("vector") &&
type.std::string::find("char") != std::string::npos) {
auto tsp = ws->run().getTimeSeriesProperty<std::string>(name);
value = (tsp->lastValue());
}
if ((type.std::string::find("number") != std::string::npos) ||
(type.std::string::find("double") != std::string::npos) ||
(type.std::string::find("dbl list") != std::string::npos)) {
type = "Float";
}
else if ((type.std::string::find("TimeValueUnit<bool>") !=
std::string::npos) ||
(type.std::string::find("TimeValueUnit<int>") !=
std::string::npos)) {
type = "Integer";
}
else if (type.std::string::find("string") != std::string::npos) {
type = "String";
}
if (name == "run_number") {
name = "run_no";
value = "\"" + value + "\"";
}
if (name == "run_title") {
name = "title";
value = "\"" + value + "\"";
}
// if name != x y or e push str to vector; to avoid any duplication
if (name != "x" && name != "y" && name != "e") {
std::string outStr = (" \"" + name + "\"" + "\n" + fourspc + type +
"\n" + fourspc + value + "\n");
}
//------------------------------------------------------------------------------
/** Sorts the vector and writes outt he sample logs to file
* @param outfile :: File it will save it out to
*/
void SaveOpenGenieAscii::writeSampleLogs(std::ofstream &outfile) {
sort(logVector.begin(), logVector.end());
for (std::vector<std::string>::const_iterator i = logVector.begin();
i != logVector.end(); ++i) {
outfile << *i << ' ';
}
}
//------------------------------------------------------------------------------
/** Add ntc field (num of bins) required to run open genie
* @param fourspc :: Constant string for four spaces
* @param nBins :: Number of bins
*/
void SaveOpenGenieAscii::addNtc(const std::string fourspc, int nBins) {
std::string outStr = "";
std::string ntc = "ntc";
outStr += (" \"" + ntc + "\"" + "\n" + fourspc + "Integer" + "\n" + fourspc +
boost::lexical_cast<std::string>(nBins) + "\n");
logVector.push_back(outStr);
}
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
//------------------------------------------------------------------------------
/** Apply enginX format field which is required for OpenGenie
* @param fourspc :: Constant string for four spaces
*/
void SaveOpenGenieAscii::applyEnginxFormat(const std::string fourspc) {
std::string typeStr = "String";
// xunit & xlabel put in OpenGenie format
std::string xunits = "xunits";
std::string xlabel = "xlabel";
std::string xunitsVal = "\"Time-of-Flight (\\gms)\"";
auto xunitsOut = (" \"" + xunits + "\"" + "\n" + fourspc + typeStr + "\n" +
fourspc + xunitsVal + "\n");
auto xlabelOut = (" \"" + xlabel + "\"" + "\n" + fourspc + typeStr + "\n" +
fourspc + xunitsVal + "\n");
// yunit & ylabel put in OpenGenie format
std::string yunits = "yunits";
std::string ylabel = "ylabel";
std::string yunitsVal = "\"Neutron counts / \\gms\"";
// Assign it to a string
auto yunitsOut = (" \"" + yunits + "\"" + "\n" + fourspc + typeStr + "\n" +
fourspc + yunitsVal + "\n");
auto ylabelOut = (" \"" + ylabel + "\"" + "\n" + fourspc + typeStr + "\n" +
fourspc + yunitsVal + "\n");
// Get property SpecNumberField
std::string SpecNumberField = getProperty("SpecNumberField");
// while field is not empty
if (SpecNumberField != "") {
if (SpecNumberField.std::string::find("-") != std::string::npos) {
std::string specNum = "spec_no";
auto specNumOut = (" \"" + specNum + "\"" + "\n" + fourspc + typeStr +
"\n" + fourspc + "\"" + SpecNumberField + "\"" + "\n");
logVector.push_back(specNumOut);
} else {
std::string message =
"Invalid value of specNumVal = " + SpecNumberField +
" entered, please use the following format \"200 - 700\" ";
throw std::runtime_error(message);
}
}
// Push to vector
logVector.push_back(xunitsOut);
logVector.push_back(xlabelOut);
logVector.push_back(yunitsOut);
logVector.push_back(ylabelOut);
}
} // namespace DataHandling
} // namespace Mantid