Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve order of loading idfs for nxs files #815

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
7 changes: 5 additions & 2 deletions Code/Mantid/Framework/API/inc/MantidAPI/ExperimentInfo.h
Expand Up @@ -118,9 +118,10 @@ class MANTID_API_DLL ExperimentInfo {
/// Saves this experiment description to the open NeXus file
virtual void saveExperimentInfoNexus(::NeXus::File *file) const;
/// Loads an experiment description from the open NeXus file
virtual void loadExperimentInfoNexus(::NeXus::File *file, std::string &parameterStr);
virtual void loadExperimentInfoNexus(const std::string& nxFilename, ::NeXus::File *file, std::string &parameterStr);
/// Load the instrument from an open NeXus file.
virtual void loadInstrumentInfoNexus(::NeXus::File *file, std::string &parameterStr);
virtual void loadInstrumentInfoNexus(const std::string& nxFilename, ::NeXus::File *file, std::string &parameterStr);

/// Load the sample and log info from an open NeXus file.
virtual void loadSampleAndLogInfoNexus(::NeXus::File *file);
/// Populate the parameter map given a string
Expand Down Expand Up @@ -164,6 +165,8 @@ class MANTID_API_DLL ExperimentInfo {
const Geometry::XMLInstrumentParameter &paramInfo,
const Run &runData);

//Loads the xml from an instrument file with some basic error handling
std::string loadInstrumentXML(const std::string& filename);
/// Detector grouping information
det2group_map m_detgroups;
/// Mutex to protect against cow_ptr copying
Expand Down
104 changes: 48 additions & 56 deletions Code/Mantid/Framework/API/src/ExperimentInfo.cpp
Expand Up @@ -15,7 +15,6 @@
#include "MantidKernel/InstrumentInfo.h"
#include "MantidKernel/Property.h"
#include "MantidKernel/Strings.h"
#include "MantidKernel/TimeSeriesProperty.h"

#include <boost/algorithm/string.hpp>
#include <boost/make_shared.hpp>
Expand Down Expand Up @@ -929,110 +928,85 @@ void ExperimentInfo::loadSampleAndLogInfoNexus(::NeXus::File *file) {
//--------------------------------------------------------------------------------------------
/** Load the object from an open NeXus file.
* @param file :: open NeXus file
* @param nxFilename :: the filename of the nexus file
* @param[out] parameterStr :: special string for all the parameters.
* Feed that to ExperimentInfo::readParameterMap() after the
* instrument is done.
* @throws Exception::NotFoundError If instrument definition is not in the nexus
* file and cannot
* be loaded from the IDF.
*/
void ExperimentInfo::loadExperimentInfoNexus(::NeXus::File *file,
void ExperimentInfo::loadExperimentInfoNexus(const std::string& nxFilename,
::NeXus::File *file,
std::string &parameterStr) {
// load sample and log info
loadSampleAndLogInfoNexus(file);

loadInstrumentInfoNexus(file, parameterStr);
loadInstrumentInfoNexus(nxFilename, file, parameterStr);
}

//--------------------------------------------------------------------------------------------
/** Load the instrument from an open NeXus file.
* @param file :: open NeXus file
* @param nxFilename :: the filename of the nexus file
* @param[out] parameterStr :: special string for all the parameters.
* Feed that to ExperimentInfo::readParameterMap() after the
* instrument is done.
* @throws Exception::NotFoundError If instrument definition is not in the nexus
* file and cannot
* be loaded from the IDF.
*/
void ExperimentInfo::loadInstrumentInfoNexus(::NeXus::File *file,
void ExperimentInfo::loadInstrumentInfoNexus(const std::string& nxFilename,
::NeXus::File *file,
std::string &parameterStr) {
std::string instrumentName;
std::string instrumentXml;
std::string instrumentFilename;

// Try to get the instrument file
file->openGroup("instrument", "NXinstrument");
std::string instrumentName;
file->readData("name", instrumentName);

std::string instrumentXml;
try {
file->openGroup("instrument_xml", "NXnote");
file->readData("data", instrumentXml);
file->closeGroup();
} catch (NeXus::Exception &ex) {
// Just carry on - it might not be there (e.g. old-style processed files)
g_log.debug(ex.what());
}

// We first assume this is a new version file, but if the next step fails we
// assume its and old version file.
int version = 1;
try {
file->readData("instrument_source", instrumentFilename);
} catch (NeXus::Exception &) {
version = 0;
// In the old version 'processed' file, this was held at the top level (as
// was the parameter map)
file->closeGroup();
try {
file->readData("instrument_source", instrumentFilename);
} catch (NeXus::Exception &ex) {
// Just carry on - it might not be there (e.g. for SNS files)
g_log.debug(ex.what());
}
g_log.debug(std::string("Unable to load instrument_xml: ") + ex.what());
}

try {
file->openGroup("instrument_parameter_map", "NXnote");
file->readData("data", parameterStr);
file->closeGroup();
} catch (NeXus::Exception &ex) {
// Just carry on - it might not be there (e.g. for SNS files)
g_log.debug(ex.what());
g_log.debug(std::string("Unable to load instrument_parameter_map: ") + ex.what());
g_log.information("Parameter map entry missing from NeXus file. Continuing without it.");
}
// Close the instrument group
file->closeGroup();

if (version == 1) {
file->closeGroup();
}

instrumentFilename = Strings::strip(instrumentFilename);
instrumentXml = Strings::strip(instrumentXml);
instrumentName = Strings::strip(instrumentName);
if (instrumentXml.empty() && !instrumentName.empty()) {
// XML was not included or was empty.
// Use the instrument name to find the file
try {
std::string filename =
getInstrumentFilename(instrumentName, getWorkspaceStartDate());
// And now load the contents
instrumentFilename = filename;
instrumentXml = Strings::loadFile(filename);
} catch (std::exception &e) {
g_log.error() << "Error loading instrument IDF file for '"
<< instrumentName << "'.\n";
g_log.debug() << e.what() << std::endl;
throw;
}
} else {
if (!instrumentFilename.empty())
instrumentFilename = ConfigService::Instance().getInstrumentDirectory() +
"/" + instrumentFilename;
std::string instrumentFilename;
if (!instrumentXml.empty()) {
// instrument xml is being loaded from the nxs file, set the instrumentFilename
// to identify the Nexus file as the source of the data
instrumentFilename = nxFilename;
g_log.debug() << "Using instrument IDF XML text contained in nexus file.\n";
}
else
{
// XML was not included or was empty
// Use the instrument name to find the file
instrumentFilename =
getInstrumentFilename(instrumentName, getWorkspaceStartDate());
// And now load the contents
instrumentXml = loadInstrumentXML(instrumentFilename);
}

// ---------- Now parse that XML to make the instrument -------------------
if (!instrumentXml.empty() && !instrumentName.empty()) {
InstrumentDefinitionParser parser;
parser.initialize(instrumentFilename, instrumentName, instrumentXml);
InstrumentDefinitionParser parser(instrumentFilename, instrumentName, instrumentXml);

std::string instrumentNameMangled = parser.getMangledName();
Instrument_sptr instr;
// Check whether the instrument is already in the InstrumentDataService
Expand All @@ -1050,6 +1024,24 @@ void ExperimentInfo::loadInstrumentInfoNexus(::NeXus::File *file,
}
}

//-------------------------------------------------------------------------------------------------
/** Loads the contents of a file and returns the string
* The file is assumed to be an IDF, and already checked that
* the path is correct.
*
* @param filename :: the path to the file
*/
std::string ExperimentInfo::loadInstrumentXML(const std::string &filename) {
try {
return Strings::loadFile(filename);
} catch (std::exception &e) {
g_log.error() << "Error loading instrument IDF file: "
<< filename << ".\n";
g_log.debug() << e.what() << std::endl;
throw;
}
}

//-------------------------------------------------------------------------------------------------
/** Parse the result of ParameterMap.asString() into the ParameterMap
* of the current instrument. The instrument needs to have been loaded
Expand Down
2 changes: 1 addition & 1 deletion Code/Mantid/Framework/API/src/FileBackedExperimentInfo.cpp
Expand Up @@ -301,7 +301,7 @@ void FileBackedExperimentInfo::populateFromFile() const {

std::string parameterStr;
const_cast<FileBackedExperimentInfo *>(this)
->loadExperimentInfoNexus(&nxFile, parameterStr);
->loadExperimentInfoNexus(m_filename, &nxFile, parameterStr);
const_cast<FileBackedExperimentInfo *>(this)
->readParameterMap(parameterStr);
} catch (::NeXus::Exception &exc) {
Expand Down
19 changes: 10 additions & 9 deletions Code/Mantid/Framework/API/test/ExperimentInfoTest.h
Expand Up @@ -18,8 +18,6 @@
#include <boost/regex.hpp>
#include <Poco/DirectoryIterator.h>

#include <iomanip>
#include <iostream>
#include <set>

using namespace Mantid::API;
Expand Down Expand Up @@ -593,22 +591,23 @@ class ExperimentInfoTest : public CxxTest::TestSuite

void test_nexus()
{
std::string filename = "ExperimentInfoTest1.nxs";
NexusTestHelper th(true);
th.createFile("ExperimentInfoTest1.nxs");
th.createFile(filename);
ExperimentInfo ws;
boost::shared_ptr<Instrument> inst1(new Instrument());
inst1->setName("GEM");
inst1->setFilename("GEM_Definition.xml");
inst1->setXmlText("");
ws.setInstrument(inst1);

TS_ASSERT_THROWS_NOTHING( ws.saveExperimentInfoNexus(th.file); );

// ------------------------ Re-load the contents ----------------------
ExperimentInfo ws2;
std::string parameterStr;
th.reopenFile();
TS_ASSERT_THROWS_NOTHING( ws2.loadExperimentInfoNexus(th.file, parameterStr) );
TS_ASSERT_THROWS_NOTHING( ws2.loadExperimentInfoNexus(filename, th.file, parameterStr) );
Instrument_const_sptr inst = ws2.getInstrument();
TS_ASSERT_EQUALS( inst->getName(), "GEM" );
TS_ASSERT( inst->getFilename().find("GEM_Definition.xml",0) != std::string::npos );
Expand All @@ -618,8 +617,9 @@ class ExperimentInfoTest : public CxxTest::TestSuite

void test_nexus_empty_instrument()
{
std::string filename = "ExperimentInfoTest2.nxs";
NexusTestHelper th(true);
th.createFile("ExperimentInfoTest2.nxs");
th.createFile(filename);
ExperimentInfo ws;
boost::shared_ptr<Instrument> inst1(new Instrument());
inst1->setName("");
Expand All @@ -633,16 +633,17 @@ class ExperimentInfoTest : public CxxTest::TestSuite
ExperimentInfo ws2;
std::string parameterStr;
th.reopenFile();
TS_ASSERT_THROWS_NOTHING( ws2.loadExperimentInfoNexus(th.file, parameterStr) );
TS_ASSERT_THROWS_NOTHING( ws2.loadExperimentInfoNexus(filename, th.file, parameterStr) );
Instrument_const_sptr inst = ws2.getInstrument();
TS_ASSERT_EQUALS( inst->getName(), "" );
TS_ASSERT_EQUALS( parameterStr, "" );
}

void testNexus_W_matrix()
{
std::string filename = "ExperimentInfoWMatrixTest.nxs";
NexusTestHelper th(true);
th.createFile("ExperimentInfoWMatrixTest.nxs");
th.createFile(filename);
ExperimentInfo ei;

DblMatrix WTransf(3,3,true);
Expand All @@ -665,7 +666,7 @@ class ExperimentInfoTest : public CxxTest::TestSuite

ExperimentInfo other;
std::string InstrParameters;
TS_ASSERT_THROWS_NOTHING(other.loadExperimentInfoNexus(th.file,InstrParameters));
TS_ASSERT_THROWS_NOTHING(other.loadExperimentInfoNexus(filename, th.file,InstrParameters));

std::vector<double> wMatrRestored=other.run().getPropertyValueAsType<std::vector<double> >("W_MATRIX");

Expand Down
Expand Up @@ -36,7 +36,7 @@ class FileBackedExperimentInfoTest : public CxxTest::TestSuite {
::NeXus::File nxFile(m_filename, NXACC_READ);
nxFile.openGroup("mantid_workspace_1", "NXentry");
std::string paramString;
m_inMemoryExptInfo->loadExperimentInfoNexus(&nxFile, paramString);
m_inMemoryExptInfo->loadExperimentInfoNexus(m_filename, &nxFile, paramString);
m_inMemoryExptInfo->readParameterMap(paramString);
}

Expand All @@ -56,8 +56,6 @@ class FileBackedExperimentInfoTest : public CxxTest::TestSuite {

void test_getInstrument_populates_object() {
auto fileBacked = createTestObject();
auto fileBackedInstrument = fileBacked->getInstrument();
auto inMemoryInstrument = m_inMemoryExptInfo->getInstrument();

TS_ASSERT_EQUALS(fileBacked->constInstrumentParameters(),
m_inMemoryExptInfo->constInstrumentParameters());
Expand Down
53 changes: 3 additions & 50 deletions Code/Mantid/Framework/Algorithms/src/CreateDummyCalFile.cpp
Expand Up @@ -14,8 +14,6 @@
#include <Poco/DOM/DOMParser.h>
#include <Poco/DOM/Document.h>
#include <Poco/DOM/Element.h>
#include <Poco/File.h>
#include <Poco/Path.h>
#include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string/detail/classification.hpp>

Expand Down Expand Up @@ -63,55 +61,10 @@ void CreateDummyCalFile::exec() {

// Get some stuff from the input workspace
Instrument_const_sptr inst = inputW->getInstrument();
std::string instname = inst->getName();

// Check that the instrument is in store
// Get only the first 3 letters
std::string instshort = instname;
std::transform(instshort.begin(), instshort.end(), instshort.begin(),
toupper);
instshort = instshort + "_Definition.xml";
// Determine the search directory for XML instrument definition files (IDFs)
std::string directoryName =
Kernel::ConfigService::Instance().getInstrumentDirectory();

// Set up the DOM parser and parse xml file
DOMParser pParser;
Poco::AutoPtr<Document> pDoc;
try {
pDoc = pParser.parse(directoryName + instshort);
} catch (...) {
g_log.error("Unable to parse file " + m_filename);
throw Kernel::Exception::FileError("Unable to parse File:", m_filename);
}
// Get pointer to root element
Element *pRootElem = pDoc->documentElement();
if (!pRootElem->hasChildNodes()) {
g_log.error("XML file: " + m_filename + "contains no root element.");
throw Kernel::Exception::InstrumentDefinitionError(
"No root element in XML instrument file", m_filename);
}
if (!inst)
throw std::invalid_argument("The InputWorkspace does not have an instrument definition");

// Handle used in the singleton constructor for instrument file should append
// the value
// of the last-modified tag inside the file to determine if it is already in
// memory so that
// changes to the instrument file will cause file to be reloaded.
auto temp =
instshort +
pRootElem->getAttribute(
"last-modified"); // Generate the mangled name by hand (old-style)

// If instrument not in store, insult the user
if (!API::InstrumentDataService::Instance().doesExist(temp)) {
Mantid::Geometry::IDFObject idf(directoryName + instshort);
temp = idf.getMangledName(); // new style.
if (!API::InstrumentDataService::Instance().doesExist(temp)) {
g_log.error("Instrument " + instshort + " is not present in data store.");
throw std::runtime_error("Instrument " + instshort +
" is not present in data store.");
}
}
std::string instname = inst->getName();

// Get the names of groups
groups = instname;
Expand Down
Expand Up @@ -5,8 +5,6 @@
#include "MantidKernel/ConfigService.h"
#include "MantidKernel/BoundedValidator.h"
#include "MantidAPI/RegisterFileLoader.h"
#include <cmath>
#include <Poco/Path.h>

namespace Mantid {
namespace DataHandling {
Expand Down
5 changes: 5 additions & 0 deletions Code/Mantid/Framework/DataHandling/src/LoadEventNexus.cpp
Expand Up @@ -1771,13 +1771,18 @@ EventWorkspace_sptr LoadEventNexus::createEmptyEventWorkspace() {
file.openGroup(entry_name, "NXentry");

// get the title
try {
file.openData("title");
if (file.getInfo().type == ::NeXus::CHAR) {
string title = file.getStrData();
if (!title.empty())
WS->setTitle(title);
}
file.closeData();
} catch (std::exception&)
{
//don't set the title if the field is not loaded
}

// get the notes
try {
Expand Down