Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #311 from mantidproject/feature/10766_save_tomo_co…
…nfig Add algorithm SaveSavuTomoConfig (save savu tomography reconstruction pipeline config)
- Loading branch information
Showing
5 changed files
with
518 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
88 changes: 88 additions & 0 deletions
88
Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/SaveSavuTomoConfig.h
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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
199
Code/Mantid/Framework/DataHandling/src/SaveSavuTomoConfig.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |
Oops, something went wrong.