Newer
Older
//----------------------------------------------------------------------
// Includes
//----------------------------------------------------------------------
#include "MantidDataHandling/LoadIDFFromNexus.h"
#include "MantidKernel/ConfigService.h"
#include "MantidAPI/FileProperty.h"
#include <Poco/Path.h>
#include <Poco/File.h>
#include <Poco/DOM/Document.h>
#include <Poco/DOM/DOMParser.h>
#include <Poco/DOM/Element.h>
using Poco::XML::DOMParser;
using Poco::XML::Document;
using Poco::XML::Element;
namespace Mantid {
namespace DataHandling {
DECLARE_ALGORITHM(LoadIDFFromNexus)
using namespace Kernel;
using namespace API;
using Geometry::Instrument;
/// Empty default constructor
LoadIDFFromNexus::LoadIDFFromNexus() {}
/// Initialisation method.
void LoadIDFFromNexus::init() {
// When used as a Child Algorithm the workspace name is not used - hence the
// "Anonymous" to satisfy the validator
new WorkspaceProperty<MatrixWorkspace>("Workspace", "Anonymous",
Direction::InOut),
"The name of the workspace in which to attach the imported instrument");
std::vector<std::string> exts;
exts.push_back(".nxs");
exts.push_back(".nxs.h5");
declareProperty(
new FileProperty("Filename", "", FileProperty::Load, exts),
"The name (including its full or relative path) of the Nexus file to "
"attempt to load the instrument from.");
declareProperty("InstrumentParentPath", std::string(""),
"Path name within the Nexus tree of the folder containing "
Federico Montesino Pouzols
committed
"the instrument folder. "
"For example it is 'raw_data_1' for an ISIS raw Nexus file "
Federico Montesino Pouzols
committed
"and 'mantid_workspace_1' for a processed nexus file. "
"Only a one level path is curently supported",
Direction::Input);
}
/** Executes the algorithm. Reading in the file and creating and populating
* the output workspace
*
* @throw FileError Thrown if unable to parse XML file
*/
// Retrieve the filename from the properties
const std::string filename = getPropertyValue("Filename");
// Get the input workspace
const MatrixWorkspace_sptr localWorkspace = getProperty("Workspace");
// Get the instrument path
std::string instrumentParentPath = getPropertyValue("InstrumentParentPath");
// Get the instrument group in the Nexus file
::NeXus::File nxfile(filename);
// Assume one level in instrument path
nxfile.openPath(instrumentParentPath);
// Take instrument info from nexus file.
localWorkspace->loadInstrumentInfoNexus(filename, &nxfile );
// Look for parameter correction file
std::string parameterCorrectionFile = getParameterCorrectionFile( localWorkspace->getInstrument()->getName() );
g_log.debug() << "Parameter correction file: " << parameterCorrectionFile;
LoadParameters( &nxfile, localWorkspace );
/* Gets the full pathname of the parameter correction file, if it exists
* @param instName :: short name of instrument as it appears in IDF filename etc.
* @returns full path name of correction file if found else ""
*/
std::string LoadIDFFromNexus::getParameterCorrectionFile( const std::string& instName ) {
std::vector<std::string> directoryNames =
ConfigService::Instance().getInstrumentDirectories();
for (auto instDirs_itr = directoryNames.begin();
instDirs_itr != directoryNames.end(); ++instDirs_itr) {
// This will iterate around the directories from user ->etc ->install, and
// find the first appropriate file
Poco::Path iPath( *instDirs_itr,"embedded_instrument_corrections"); // Go to correction file subfolder
// First see if the directory exists
Poco::File ipDir(iPath);
if( ipDir.exists() && ipDir.isDirectory() ) {
iPath.append(instName + "_Parameter_Corrections.xml"); // Append file name to pathname
Poco::File ipFile(iPath);
if( ipFile.exists() && ipFile.isFile())
{
return ipFile.path(); // Return first found
}
} // Directory
} // Loop
return ""; // No file found
}
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
/* Reads the parameter correction file and if a correction is needed output the parameterfile needed
* and whether it is to be appended.
* @param correction_file :: path nsame of correction file as returned by getParameterCorrectionFile()
* @param date :: IS8601 date string applicable
* @param parameter_file :: output parameter file to use or "" if none
* @param append :: output whether the parameters from parameter_file should be appended.
*
* @throw FileError Thrown if unable to parse XML file
*/
void LoadIDFFromNexus::readParameterCorrectionFile( const std::string& correction_file, const std::string& date,
std::string parameter_file, bool append ) {
// Get contents of correction file
const std::string xmlText = Kernel::Strings::loadFile(correction_file);
// Set up the DOM parser and parse xml file
DOMParser pParser;
Document* pDoc;
try {
pDoc = pParser.parseString(xmlText);
} catch (Poco::Exception &exc) {
throw Kernel::Exception::FileError(
exc.displayText() + ". Unable to parse parameter correction file:", correction_file);
} catch (...) {
throw Kernel::Exception::FileError("Unable to parse parameter correction file:", correction_file);
}
// Get pointer to root element
Element* pRootElem = pDoc->documentElement();
if (!pRootElem->hasChildNodes()) {
g_log.error("Parameter correction file: " + correction_file + "contains no XML root element.");
throw Kernel::Exception::InstrumentDefinitionError(
"No root element in XML parameter correction file", correction_file);
}
}
/** Loads the parameters from the Nexus file if possible, else from a parameter file
* into the specified workspace
* @param nxfile :: open NeXus file
* @param localWorkspace :: workspace into which loading occurs
*
* @throw FileError Thrown if unable to parse XML file
*/
void LoadIDFFromNexus::LoadParameters( ::NeXus::File *nxfile, const MatrixWorkspace_sptr localWorkspace ) {
std::string parameterString;
// First attempt to load parameters from nexus file.
nxfile->openGroup("instrument", "NXinstrument");
localWorkspace->loadInstrumentParametersNexus( nxfile, parameterString );
// loadInstrumentParametersNexus does not populate any instrument params
// so we do it here.
localWorkspace->populateInstrumentParameters();
// No parameters have been found in Nexus file, so we look for them in a parameter file.
std::vector<std::string> directoryNames =
ConfigService::Instance().getInstrumentDirectories();
const std::string instrumentName =
localWorkspace->getInstrument()->getName();
for (auto instDirs_itr = directoryNames.begin();
instDirs_itr != directoryNames.end(); ++instDirs_itr) {
// This will iterate around the directories from user ->etc ->install, and
std::string directoryName = *instDirs_itr;
const std::string paramFile =
directoryName + instrumentName + "_Parameters.xml";
try {
// load and also populate instrument parameters from this 'fallback'
// parameter file
Algorithm_sptr loadParamAlg = createChildAlgorithm("LoadParameterFile");
loadParamAlg->setProperty("Filename", paramFile);
loadParamAlg->setProperty("Workspace", localWorkspace);
loadParamAlg->execute();
g_log.notice() << "Instrument parameter file: " << paramFile
<< " has been loaded" << std::endl;
break; // stop at the first one
} catch (std::runtime_error &) {
g_log.debug() << "Instrument parameter file: " << paramFile
<< " not found or un-parsable. ";
} else { // We do have parameters from the Nexus file
g_log.notice()
<< "Found Instrument parameter map entry in Nexus file, which is loaded"
<< std::endl;
// process parameterString into parameters in workspace
localWorkspace->readParameterMap(parameterString);
}
}
} // namespace DataHandling
} // namespace Mantid