diff --git a/Code/Mantid/DataHandling/inc/MantidDataHandling/LoadInstrumentHelper.h b/Code/Mantid/DataHandling/inc/MantidDataHandling/LoadInstrumentHelper.h index 645e805524929638038cdaa0c20cb94e1a5039d0..e0701e32317abbb5a100e3b5fc25945fa0287398 100644 --- a/Code/Mantid/DataHandling/inc/MantidDataHandling/LoadInstrumentHelper.h +++ b/Code/Mantid/DataHandling/inc/MantidDataHandling/LoadInstrumentHelper.h @@ -55,8 +55,12 @@ namespace Mantid /// Destructor virtual ~LoadInstrumentHelper() {} - /// Given an instrument name and a date return filename of appropriate IDF - std::string getIDF_Filename(std::string& IDFname, std::string date) {return std::string();} + /// For a given instrument name return IDF (identifier) that is valid for date + std::string getIDF_identifier(const std::string& idfName, const std::string& date); + + /// Return from an IDF the values of the valid-from and valid-to attributes + void getValidFromTo(const std::string& IDFfilename, std::string& outValidFrom, + std::string& outValidTo); private: diff --git a/Code/Mantid/DataHandling/src/LoadEventPreNeXus.cpp b/Code/Mantid/DataHandling/src/LoadEventPreNeXus.cpp index cffc1e040b690d7e752d3e166722bea5e96b2614..648a8bc58657e4c3ef31ab5d07e359f5e1741c37 100644 --- a/Code/Mantid/DataHandling/src/LoadEventPreNeXus.cpp +++ b/Code/Mantid/DataHandling/src/LoadEventPreNeXus.cpp @@ -273,7 +273,7 @@ void LoadEventPreNeXus::runLoadInstrument(const std::string &eventfilename, Matr pos = instrument.rfind("_", pos-1); // get rid of the run number instrument = instrument.substr(0, pos); - string filename = Mantid::Kernel::ConfigService::Instance().getInstrumentFilename(instrument); + string filename = Mantid::Kernel::ConfigService::Instance().getInstrumentFilename(instrument,""); if (filename.empty()) return; if (!Poco::File(filename).exists()) diff --git a/Code/Mantid/DataHandling/src/LoadInstrumentHelper.cpp b/Code/Mantid/DataHandling/src/LoadInstrumentHelper.cpp index bf3a14126b850d54524b8a300efd3a06d69c61cc..ded53ea69978cded1471621417a0e0deb809b680 100644 --- a/Code/Mantid/DataHandling/src/LoadInstrumentHelper.cpp +++ b/Code/Mantid/DataHandling/src/LoadInstrumentHelper.cpp @@ -31,6 +31,13 @@ #include "MantidKernel/ArrayProperty.h" #include <sstream> +#include "Poco/DirectoryIterator.h" +#include "Poco/RegularExpression.h" + +#include "Poco/SAX/SAXParser.h" +#include "Poco/SAX/ContentHandler.h" +#include "Poco/SAX/Attributes.h" + using Poco::XML::DOMParser; using Poco::XML::Document; using Poco::XML::Element; @@ -44,15 +51,166 @@ static bool VERBOSE = false; namespace Mantid { - namespace DataHandling +namespace DataHandling +{ +using namespace Kernel; +using namespace API; +using namespace Geometry; +using namespace Poco::XML; + +// used to terminate SAX process +class DummyException { +public: + std::string m_validFrom; + std::string m_validTo; + DummyException(std::string validFrom, std::string validTo) + : m_validFrom(validFrom), m_validTo(validTo) {} + + +}; + +// SAX content handler for grapping stuff quickly from IDF +class myContentHandler : public Poco::XML::ContentHandler +{ + virtual void startElement( + const XMLString & uri, + const XMLString & localName, + const XMLString & qname, + const Attributes & attrList + ) + { + //int a = 2; + //std::cout << localName << "\n"; + //for (int i = 0; i < attrList.getLength(); i++) + // std::cout << attrList.getValue(i) << "\n"; + + if ( localName == "instrument" ) + { + throw DummyException(static_cast<std::string>(attrList.getValue("","valid-from")), + static_cast<std::string>(attrList.getValue("","valid-to"))); + } + } + virtual void endElement( + const XMLString & uri, + const XMLString & localName, + const XMLString & qname + ) {} + virtual void startDocument() {} + virtual void endDocument() {} + virtual void characters( + const XMLChar ch[], + int start, + int length + ) {} + virtual void endPrefixMapping( + const XMLString & prefix + ) {} + virtual void ignorableWhitespace( + const XMLChar ch[], + int start, + int length + ) {} + virtual void processingInstruction( + const XMLString & target, + const XMLString & data + ) {} + virtual void setDocumentLocator( + const Locator * loc + ) {} + virtual void skippedEntity( + const XMLString & name + ) {} + virtual void startPrefixMapping( + const XMLString & prefix, + const XMLString & uri + ) {} +}; + + +/** Return from an IDF the values of the valid-from and valid-to attributes +* +* @param IDFname Full path of an IDF +* @param outValidFrom Used to return valid-from date +* @param outValidto Used to return valid-to date +*/ +void LoadInstrumentHelper::getValidFromTo(const std::string& IDFfilename, std::string& outValidFrom, + std::string& outValidTo) +{ + SAXParser pParser; + myContentHandler* conHand = new myContentHandler(); + pParser.setContentHandler(conHand); + + try + { + pParser.parse(IDFfilename); + } + catch(DummyException e) + { + outValidFrom = e.m_validFrom; + outValidTo = e.m_validTo; + } + catch(...) + { + // should return some sensible here + } +} + + +struct fromToEntry +{ + std::string identifier; + DateAndTime from; + DateAndTime to; +}; + +/// Given an instrument name and a date return filename of appropriate IDF +/** A given instrument may have multiple IDFs associated with it. This method return an +* identifier which identify a given IDF for a given instrument. An IDF filename is +* required to be of the form IDFname + _Definition + Identifier + .xml, the identifier +* then is the part of a filename that identifies the IDF valid at a given date. +* +* @param IDFname Instrument name ID e.g. GEM, TOPAS or BIOSANS +* @param date Date. E.g. date when raw files where collected +*/ +std::string LoadInstrumentHelper::getIDF_identifier(const std::string& idfName, const std::string& date) +{ + // Get the search directory for XML instrument definition files (IDFs) + std::string directoryName = Kernel::ConfigService::Instance().getInstrumentDirectory(); + // adjust IDFname to be consistent with names used in instrument search directory + std::string IDFname = Kernel::ConfigService::Instance().adjustIDFname(idfName); + + + Poco::RegularExpression regex(IDFname+"_Definition.*\\.xml", Poco::RegularExpression::RE_CASELESS ); + Poco::DirectoryIterator end_iter; + std::vector<fromToEntry> idfInstances; + DateAndTime d(date); + for ( Poco::DirectoryIterator dir_itr(directoryName); dir_itr != end_iter; ++dir_itr ) { + if ( !Poco::File(dir_itr->path() ).isFile() ) continue; + std::string l_filenamePart = Poco::Path(dir_itr->path()).getFileName(); - using namespace Kernel; - using namespace API; - using namespace Geometry; + if ( regex.match(l_filenamePart) ) + { + std::string validFrom, validTo; + getValidFromTo(dir_itr->path(), validFrom, validTo); + DateAndTime from(validFrom); + DateAndTime to(validTo); + if ( DateAndTime(validFrom) <= d && d <= DateAndTime(validTo) ) + { + size_t foundDefinition; + foundDefinition = l_filenamePart.find("_Definition"); + size_t foundXML; + foundXML = l_filenamePart.find(".xml"); + return l_filenamePart.substr(foundDefinition+11,foundXML-foundDefinition-11); + } + } + } + // should throw warning here: no IDF found with date: + return ""; +} - } // namespace DataHandling +} // namespace DataHandling } // namespace Mantid diff --git a/Code/Mantid/DataHandling/src/LoadPreNeXusMonitors.cpp b/Code/Mantid/DataHandling/src/LoadPreNeXusMonitors.cpp index e4711dee888f72ab2cad405007c070a17394a0d8..ce72dc4c7a3bb7b6459e0995d828bd975a88c524 100644 --- a/Code/Mantid/DataHandling/src/LoadPreNeXusMonitors.cpp +++ b/Code/Mantid/DataHandling/src/LoadPreNeXusMonitors.cpp @@ -242,7 +242,7 @@ void LoadPreNeXusMonitors::exec() void LoadPreNeXusMonitors::runLoadInstrument(const std::string &instrument, MatrixWorkspace_sptr localWorkspace) { - std::string filename = Mantid::Kernel::ConfigService::Instance().getInstrumentFilename(instrument); + std::string filename = Mantid::Kernel::ConfigService::Instance().getInstrumentFilename(instrument,""); if (filename.empty()) return; if (!Poco::File(filename).exists()) diff --git a/Code/Mantid/DataHandling/src/LoadRawHelper.cpp b/Code/Mantid/DataHandling/src/LoadRawHelper.cpp index ca7f59efca565ee27d05f48ecb549c122281a8ac..b264e8331a53e15915de2b0c5ed7aa67f51798c5 100644 --- a/Code/Mantid/DataHandling/src/LoadRawHelper.cpp +++ b/Code/Mantid/DataHandling/src/LoadRawHelper.cpp @@ -554,7 +554,7 @@ namespace Mantid if (i != std::string::npos) instrumentID.erase(i); - std::string fullPathIDF = Kernel::ConfigService::Instance().getInstrumentFilename(instrumentID); + std::string fullPathIDF = Kernel::ConfigService::Instance().getInstrumentFilename(instrumentID,""); IAlgorithm_sptr loadInst= createSubAlgorithm("LoadInstrument"); diff --git a/Code/Mantid/DataHandling/test/LoadInstrumentHelperTest.h b/Code/Mantid/DataHandling/test/LoadInstrumentHelperTest.h index b2c4a4db589944ebf5f7f4aa7a554a449531272c..0fc5b092dc7da04fb43d36e356dd9afc8e7f0b79 100644 --- a/Code/Mantid/DataHandling/test/LoadInstrumentHelperTest.h +++ b/Code/Mantid/DataHandling/test/LoadInstrumentHelperTest.h @@ -45,98 +45,7 @@ using namespace Mantid::DataObjects; using namespace Poco::XML; -class DummyException { -public: - std::string m_validFrom; - std::string m_validTo; - DummyException(std::string validFrom, std::string validTo) - : m_validFrom(validFrom), m_validTo(validTo) {} - - -}; - - -class myContentHandler : public Poco::XML::ContentHandler -{ - virtual void startElement( - const XMLString & uri, - const XMLString & localName, - const XMLString & qname, - const Attributes & attrList - ) - { - //int a = 2; - //std::cout << localName << "\n"; - //for (int i = 0; i < attrList.getLength(); i++) - // std::cout << attrList.getValue(i) << "\n"; - - if ( localName == "instrument" ) - { - throw DummyException(static_cast<std::string>(attrList.getValue("","valid-from")), - static_cast<std::string>(attrList.getValue("","valid-to"))); - } - } - virtual void endElement( - const XMLString & uri, - const XMLString & localName, - const XMLString & qname - ) {} - virtual void startDocument() {} - virtual void endDocument() {} - virtual void characters( - const XMLChar ch[], - int start, - int length - ) {} - virtual void endPrefixMapping( - const XMLString & prefix - ) {} - virtual void ignorableWhitespace( - const XMLChar ch[], - int start, - int length - ) {} - virtual void processingInstruction( - const XMLString & target, - const XMLString & data - ) {} - virtual void setDocumentLocator( - const Locator * loc - ) {} - virtual void skippedEntity( - const XMLString & name - ) {} - virtual void startPrefixMapping( - const XMLString & prefix, - const XMLString & uri - ) {} -}; - -void getValidFromTo(const std::string& filename, std::string& outValidFrom, - std::string& outValidTo) -{ - SAXParser pParser; - myContentHandler* conHand = new myContentHandler(); - pParser.setContentHandler(conHand); - - try - { - pParser.parse(filename); - } - catch(DummyException e) - { - outValidFrom = e.m_validFrom; - outValidTo = e.m_validTo; - //std::cout << "In getValidFromTo " << outValidFrom << " " << outValidTo << std::endl; - } - catch(...) - { - //g_log.error("Unable to parse file " + m_filename); - //throw Kernel::Exception::FileError("Unable to parse File:" , m_filename); - //std::cout << "\ndfgdsfgdsfgsdfgfdgdfgdfg\n"; - } -} struct fromToEntry { @@ -174,15 +83,12 @@ public: if ( regex.match(l_filenamePart) ) { std::string validFrom, validTo; - getValidFromTo(dir_itr->path(), validFrom, validTo); + helper.getValidFromTo(dir_itr->path(), validFrom, validTo); size_t found; found = l_filenamePart.find("_Definition"); - //std::cout << l_filenamePart.substr(0,found) << std::endl; - //std::cout << dir_itr->path() << std::endl; fromToEntry ft; ft.path = dir_itr->path(); - //std::cout << validFrom << " " << validTo << std::endl; ft.from.set_from_ISO8601_string(validFrom); ft.to.set_from_ISO8601_string(validTo); idfFiles.insert( std::pair<std::string,fromToEntry>(l_filenamePart.substr(0,found), @@ -216,18 +122,21 @@ public: { // some more intelligent stuff here later TS_ASSERT("dates in IDF overlap"=="0"); - //std::cout << "\nNot OK\n"; } } } } } - + } + + // + void testInstrumentHelperFunctions() + { + LoadInstrumentHelper helper; - //TS_ASSERT( !loader.isInitialized() ); - //loader.initialize(); - //TS_ASSERT( loader.isInitialized() ); + std::string boevs = helper.getIDF_identifier("BIOSANS", "2100-01-31 22:59:59"); + TS_ASSERT(boevs.empty()); } }; diff --git a/Code/Mantid/Kernel/inc/MantidKernel/ConfigService.h b/Code/Mantid/Kernel/inc/MantidKernel/ConfigService.h index 2d387c64be304aa2bf6996cb5c6d8cbecfaf17b3..187883f9df3c0763054c01e51067dc1b58d1e327 100644 --- a/Code/Mantid/Kernel/inc/MantidKernel/ConfigService.h +++ b/Code/Mantid/Kernel/inc/MantidKernel/ConfigService.h @@ -149,7 +149,12 @@ namespace Mantid /// Get the list of search paths const std::vector<std::string>& getDataSearchDirs() const; /// Gets the instrument geometry filename - const std::string getInstrumentFilename(const std::string& instrument) const; + const std::string getInstrumentFilename(const std::string& instrument, const std::string& identifier) const; + /// Get instrument search directory + const std::string getInstrumentDirectory() const; + /// Adjust instrument name to be consistent with names used for instruments in + /// instrument search directory + const std::string adjustIDFname(const std::string& instrumentName) const; /// Load facility information from instrumentDir/Facilities.xml file void updateFacilities(const std::string& fName = ""); diff --git a/Code/Mantid/Kernel/src/ConfigService.cpp b/Code/Mantid/Kernel/src/ConfigService.cpp index 07a9c1decf2ef38678ace1b00a068dd62f3faa1a..e7c76796c95b7682805598dd0fe835c18516f790 100644 --- a/Code/Mantid/Kernel/src/ConfigService.cpp +++ b/Code/Mantid/Kernel/src/ConfigService.cpp @@ -844,12 +844,61 @@ const std::vector<std::string>& ConfigServiceImpl::getDataSearchDirs() const return m_DataSearchDirs; } + +/** + * Adjust instrument name to be consistent with names used for instruments in + * instrument search directory, including adjusting instrument names to be upper case + */ +const std::string ConfigServiceImpl::adjustIDFname(const std::string& instrumentName) const +{ + // force instrument ID to upper case + std::string instrument; + instrument = instrumentName; + std::transform(instrument.begin(), instrument.end(), instrument.begin(), toupper); + + // hack to look for long name versions + if (instrument == "SEQ") + return "SEQUOIA"; + if (instrument == "PG3") + return "POWGEN"; + + return instrument; +} + + /** * Return the filename of the instrument geometry definition file. * @param instrumentName A string giving the instrument name + * @param identifier A given instrument may have multiple IDFs, this identifier identify which one * @returns A string containing the full qualified filename of the instrument file. */ -const std::string ConfigServiceImpl::getInstrumentFilename(const std::string& instrumentName) const +const std::string ConfigServiceImpl::getInstrumentFilename(const std::string& instrumentName, const std::string& identifier) const +{ + // force instrument ID to upper case + std::string instrument; + instrument = instrumentName; + std::transform(instrument.begin(), instrument.end(), instrument.begin(), toupper); + + // hack to look for long name versions + if (instrument == "SEQ") + return this->getInstrumentFilename("SEQUOIA", identifier); + if (instrument == "PG3") + return this->getInstrumentFilename("POWGEN", identifier); + + // Determine the search directory for XML instrument definition files (IDFs) + std::string directoryName = getInstrumentDirectory(); + + // force ID to upper case + return directoryName + "/" + instrument + "_Definition" + + identifier + ".xml"; +} + + +/** + * Return the search directory for XML instrument definition files (IDFs) + * @returns Full path of instrument search directory + */ +const std::string ConfigServiceImpl::getInstrumentDirectory() const { // Determine the search directory for XML instrument definition files (IDFs) std::string directoryName = getString("instrumentDefinition.directory"); @@ -860,25 +909,16 @@ const std::string ConfigServiceImpl::getInstrumentFilename(const std::string& in directoryName = Poco::Path(getBaseDir()).resolve("../Instrument").toString(); } - // force ID to upper case - std::string instrument; - instrument = instrumentName; - std::transform(instrument.begin(), instrument.end(), instrument.begin(), toupper); - std::string fullPathIDF = directoryName + "/" + instrument + "_Definition.xml"; - - // Special hack to look for long name versions - if (!Poco::File(fullPathIDF).exists()) + if ( !Poco::File(directoryName).isDirectory() ) { - if (instrument == "SEQ") - return this->getInstrumentFilename("SEQUOIA"); - if (instrument == "PG3") - return this->getInstrumentFilename("POWGEN"); - + g_log.error("Unable to locate instrument search directory at: " + directoryName); } - return fullPathIDF; + return directoryName; } + + /** * Load facility information from instrumentDir/Facilities.xml file if fName parameter * is not set diff --git a/Code/Mantid/Nexus/src/LoadNexusMonitors.cpp b/Code/Mantid/Nexus/src/LoadNexusMonitors.cpp index 3d53d73a9a8e24ed7e864ecb3944eb6de18139b3..97f22ba271a8fa3c13e82b11f5a772861135c32e 100644 --- a/Code/Mantid/Nexus/src/LoadNexusMonitors.cpp +++ b/Code/Mantid/Nexus/src/LoadNexusMonitors.cpp @@ -174,7 +174,7 @@ void LoadNexusMonitors::exec() void LoadNexusMonitors::runLoadInstrument(const std::string &instrument, API::MatrixWorkspace_sptr localWorkspace) { - std::string filename = Kernel::ConfigService::Instance().getInstrumentFilename(instrument); + std::string filename = Kernel::ConfigService::Instance().getInstrumentFilename(instrument,""); if (filename.empty()) { return; diff --git a/Code/Mantid/Nexus/src/LoadSNSEventNexus.cpp b/Code/Mantid/Nexus/src/LoadSNSEventNexus.cpp index 07be2c95a560cb9cf5b912417fa112b47b90f893..824a25eba9d36bc65428204c547251244b92e3ed 100644 --- a/Code/Mantid/Nexus/src/LoadSNSEventNexus.cpp +++ b/Code/Mantid/Nexus/src/LoadSNSEventNexus.cpp @@ -515,7 +515,7 @@ void LoadSNSEventNexus::runLoadInstrument(const std::string &nexusfilename, Matr nxfile.close(); // determine the instrument parameter file - string filename = Mantid::Kernel::ConfigService::Instance().getInstrumentFilename(instrument); + string filename = Mantid::Kernel::ConfigService::Instance().getInstrumentFilename(instrument,""); if (filename.empty()) { g_log.warning() << "Unable to determine geometry file for " << instrument << std::endl;