Skip to content

Commit

Permalink
Merge pull request #311 from mantidproject/feature/10766_save_tomo_co…
Browse files Browse the repository at this point in the history
…nfig

Add algorithm SaveSavuTomoConfig (save savu tomography reconstruction pipeline config)
  • Loading branch information
raquelalvarezbanos committed Feb 27, 2015
2 parents daf9984 + 099adbc commit cbc7d62
Show file tree
Hide file tree
Showing 5 changed files with 518 additions and 0 deletions.
3 changes: 3 additions & 0 deletions Code/Mantid/Framework/DataHandling/CMakeLists.txt
Expand Up @@ -141,6 +141,7 @@ set ( SRC_FILES
src/SaveReflCustomAscii.cpp
src/SaveReflTBL.cpp
src/SaveReflThreeColumnAscii.cpp
src/SaveSavuTomoConfig.cpp
src/SaveSPE.cpp
src/SaveToSNSHistogramNexus.cpp
src/SaveVTK.cpp
Expand Down Expand Up @@ -288,6 +289,7 @@ set ( INC_FILES
inc/MantidDataHandling/SaveReflCustomAscii.h
inc/MantidDataHandling/SaveReflTBL.h
inc/MantidDataHandling/SaveReflThreeColumnAscii.h
inc/MantidDataHandling/SaveSavuTomoConfig.h
inc/MantidDataHandling/SaveSPE.h
inc/MantidDataHandling/SaveToSNSHistogramNexus.h
inc/MantidDataHandling/SaveVTK.h
Expand Down Expand Up @@ -430,6 +432,7 @@ set ( TEST_FILES
SaveReflCustomAsciiTest.h
SaveReflTBLTest.h
SaveReflThreeColumnAsciiTest.h
SaveSavuTomoConfigTest.h
SaveSPETest.h
SaveToSNSHistogramNexusTest.h
SetSampleMaterialTest.h
Expand Down
@@ -0,0 +1,88 @@
#ifndef MANTID_DATAHANDLING_SAVESAVUTOMOCONFIG_H_
#define MANTID_DATAHANDLING_SAVESAVUTOMOCONFIG_H_

//---------------------------------------------------
// Includes
//---------------------------------------------------
#include "MantidAPI/Algorithm.h"
#include "MantidAPI/ITableWorkspace.h"

namespace Mantid {
namespace DataHandling {

/**
* Saves a configuration for a tomographic reconstruction into a
* NeXus/HDF5 file.
*
* Operates on table workspaces, with each row representing a plugin
* definition to add.
*
* Columns:4: id/params/name/cite
*
* Copyright © 2014-2015 ISIS Rutherford Appleton Laboratory,
* NScD Oak Ridge National Laboratory & European Spallation Source
*
* This file is part of Mantid.
*
* Mantid is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* Mantid 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. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* File change history is stored at: <https://github.com/mantidproject/mantid>
* Code Documentation is available at: <http://doxygen.mantidproject.org>
*/

class DLLExport SaveSavuTomoConfig : public API::Algorithm {
public:
SaveSavuTomoConfig();
/// Virtual dtor
virtual ~SaveSavuTomoConfig() {}

/// Algorithm's name for identification overriding a virtual method
virtual const std::string name() const { return "SaveSavuTomoConfig"; }

/// Summary of algorithms purpose
virtual const std::string summary() const {
return "Writes a configuration file for a tomographic reconstruction job.";
}

/// Algorithm's version
virtual int version() const { return (1); }

/// Algorithm's category for identification
virtual const std::string category() const {
return "DataHandling\\Tomography;"; }

private:
/// Initialisation code
void init();
/// Execution code : Single workspace
void exec();

/// basic check on a table workspace properties
bool tableLooksGenuine(const API::ITableWorkspace_sptr &tws);

/// get table workspaces (checking the workspace names given)
std::vector<API::ITableWorkspace_sptr> checkTables(
const std::vector<std::string> &workspaces);
/// write savu tomo config file
void saveFile(const std::string fname,
const std::vector<API::ITableWorkspace_sptr> &wss);

// Number of info entries to read from the input table workspaces
unsigned int m_pluginInfoCount;
};

} // namespace DataHandling
} // namespace Mantid

#endif // MANTID_DATAHANDLING_SAVESAVUTOMOCONFIG_H_
199 changes: 199 additions & 0 deletions Code/Mantid/Framework/DataHandling/src/SaveSavuTomoConfig.cpp
@@ -0,0 +1,199 @@
#include "MantidAPI/FileProperty.h"
#include "MantidDataHandling/SaveSavuTomoConfig.h"
#include "MantidKernel/ArrayProperty.h"
#include "MantidKernel/MandatoryValidator.h"

#include <nexus/NeXusFile.hpp>
#include <Poco/File.h>

namespace Mantid {
namespace DataHandling {
// Register the algorithm into the algorithm factory
DECLARE_ALGORITHM(SaveSavuTomoConfig)

using namespace Kernel;
using namespace API;

SaveSavuTomoConfig::SaveSavuTomoConfig() : API::Algorithm(), m_pluginInfoCount(4)
{ }

/**
* Initialise the algorithm
*/
void SaveSavuTomoConfig::init() {
// Get a list of table workspaces which contain the plugin information
declareProperty(
new ArrayProperty<std::string>("InputWorkspaces",
boost::make_shared<MandatoryValidator<std::vector<std::string>>>()),
"The names of the table workspaces containing plugin information.");

declareProperty(new API::FileProperty("Filename", "", FileProperty::Save,
std::vector<std::string>(1, ".nxs")),
"The name of the tomographic config file to write, as a full "
"or relative path. This will overwrite existing files.");
}

/**
* Execute the algorithm
*/
void SaveSavuTomoConfig::exec() {
// Prepare properties for writing to file
std::string fileName = getPropertyValue("Filename");

progress(0, "Checking workspace (tables)...");

std::vector<ITableWorkspace_sptr> wss = checkTables(getProperty("InputWorkspaces"));

try {
saveFile(fileName, wss);
} catch (std::exception &e) {
g_log.error() << "Failed to save savu tomography reconstruction parameterization "
"file, error description: " << e.what() << std::endl;
return;
}

progress(0, "File saved.");
}

/**
* Do a basic check that the table seems to be what we need to save a
* savu configuration file.
*
* @param tws Table workspace that should contain plugin/processing
* steps information (a savu configuration)
*
* @return True if the table passed seems to be a savu configuration table
*/
bool SaveSavuTomoConfig::tableLooksGenuine(const ITableWorkspace_sptr &tws) {
// note that more columns might be added in the relatively near future
if (!(tws->columnCount() >= m_pluginInfoCount))
return false;

std::vector<std::string> names = tws->getColumnNames();
return ( 4 <= names.size() &&
"ID" == names[0] &&
"Parameters" == names[1] &&
"Name" == names[2] &&
"Cite" == names[3]);
}

/**
* Check that the list of workspace names identifies table workspaces
* with (approximately) the expected information (4 columns), and
* return the corresponding (table) workspace objects.
*
* @param workspaces Table workspace names that should contain plugin/processing
* steps information
*
* @return Table workspaces retrieved from the ADS, corresponding to
* the names passed
*/
std::vector<ITableWorkspace_sptr> SaveSavuTomoConfig::checkTables(
const std::vector<std::string> &workspaces) {
std::vector<ITableWorkspace_sptr> wss;
for (auto it = workspaces.begin(); it != workspaces.end(); ++it) {
if (AnalysisDataService::Instance().doesExist(*it)) {
ITableWorkspace_sptr table =
AnalysisDataService::Instance().retrieveWS<ITableWorkspace>(*it);
// Check it's valid. Very permissive check for the time being
if (table && tableLooksGenuine(table)) {
wss.push_back(table);
} else {
throw std::runtime_error("Invalid workspace provided: " +
*it + ". This algorithm requires a table "
"workspace with correct savu plugin/ "
"pipeline process information.");
}
} else {
throw std::runtime_error(
"One or more specified table workspaces don't exist. I could not "
"find this one: " + *it);
}
}
return wss;
}

/**
* Check that the list of workspace names identifies table workspaces
* with (approximately) the expected information (4 columns), and
* return the corresponding (table) workspace objects.
*
* @param fname Destination file name (can be ammended if needed and that
* will be logged)
* @param wss Table workspaces that apparently contain plugin/processing
* steps information
*/
void SaveSavuTomoConfig::saveFile(const std::string fname,
const std::vector<ITableWorkspace_sptr> &wss) {
// Ensure it has a .nxs extension
std::string fileName = fname;
if (!boost::ends_with(fileName, ".nxs")) {
const std::string ext = ".nxs";
g_log.notice() << "Adding extension '" << ext << "' to the output "
"file name given (it is a NeXus file). " << std::endl;
fileName = fileName + ".nxs";
}

// If file exists, delete it.
Poco::File f(fileName);
if (f.exists()) {
g_log.notice() << "Overwriting existing file: '" << fileName << "'" <<
std::endl;
f.remove();
} else {
g_log.notice() << "Creating file: '" << fileName << ";" << std::endl;
}

// Create the file handle
NXhandle fileHandle;
NXstatus status = NXopen(fileName.c_str(), NXACC_CREATE5, &fileHandle);

if (status == NX_ERROR)
throw std::runtime_error("Unable to create file.");

NeXus::File nxFile(fileHandle);

std::string topLevelEntry = "entry";
nxFile.makeGroup(topLevelEntry, "NXentry", true);

const std::string processingEntry = "processing";
nxFile.makeGroup(processingEntry, "NXprocess", true);

// Iterate through all plugin entries (number sub groups 0....n-1)
size_t procCount = 0;
for (size_t i = 0; i < wss.size(); ++i) {
// Concatenate table contents, putting pipeline processing steps in the same sequence
// as they come in the seq of table workspaces
ITableWorkspace_sptr w = wss[i];
for (size_t ti =0; ti < w->rowCount(); ++ti) {
// Column info order is [ID / Params {as json string} / name {description} /
// citation info]
std::string id = w->cell<std::string>(ti, 0);
std::string params = w->cell<std::string>(ti, 1);
std::string name = w->cell<std::string>(ti, 2);
std::string cite = w->cell<std::string>(ti, 3);

// but in the file it goes as: data (params), id, name
nxFile.makeGroup(boost::lexical_cast<std::string>(procCount++), "NXnote", true);
nxFile.writeData("data", params);
nxFile.writeData("id", id);
nxFile.writeData("name", name);
// Ignore citation information for now. Format not fixed yet.
// nxFile.writeData("cite", cite);
nxFile.closeGroup(); // close NXnote
}
}

nxFile.closeGroup(); // processing NXprocess

// This seems to be required for certain extensions that can be appended
// to these files. Not fixed for now.
nxFile.makeGroup("intermediate", "NXcollection", false);

nxFile.closeGroup(); // Top level entry (NXentry)

nxFile.close();
}

} // namespace DataHandling
} // namespace Mantid

0 comments on commit cbc7d62

Please sign in to comment.