diff --git a/Code/Mantid/Framework/API/inc/MantidAPI/ExperimentInfo.h b/Code/Mantid/Framework/API/inc/MantidAPI/ExperimentInfo.h index b2012724e47f..bd0d1c05f9db 100644 --- a/Code/Mantid/Framework/API/inc/MantidAPI/ExperimentInfo.h +++ b/Code/Mantid/Framework/API/inc/MantidAPI/ExperimentInfo.h @@ -121,6 +121,7 @@ class MANTID_API_DLL ExperimentInfo { virtual void loadExperimentInfoNexus(::NeXus::File *file, std::string ¶meterStr); /// Load the instrument from an open NeXus file. virtual void loadInstrumentInfoNexus(::NeXus::File *file, std::string ¶meterStr); + /// Load the sample and log info from an open NeXus file. virtual void loadSampleAndLogInfoNexus(::NeXus::File *file); /// Populate the parameter map given a string @@ -164,6 +165,8 @@ class MANTID_API_DLL ExperimentInfo { const Geometry::XMLInstrumentParameter ¶mInfo, 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 diff --git a/Code/Mantid/Framework/API/src/ExperimentInfo.cpp b/Code/Mantid/Framework/API/src/ExperimentInfo.cpp index d7a43ffc2ec1..a2d400489c0e 100644 --- a/Code/Mantid/Framework/API/src/ExperimentInfo.cpp +++ b/Code/Mantid/Framework/API/src/ExperimentInfo.cpp @@ -1006,32 +1006,27 @@ void ExperimentInfo::loadInstrumentInfoNexus(::NeXus::File *file, 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; + 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 = instrumentFilename; 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 + std::string filename = + getInstrumentFilename(instrumentName, getWorkspaceStartDate()); + // And now load the contents + instrumentFilename = filename; + 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 @@ -1049,6 +1044,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 diff --git a/Code/Mantid/Framework/DataHandling/src/LoadInstrument.cpp b/Code/Mantid/Framework/DataHandling/src/LoadInstrument.cpp index 673586cdad50..9a2fcf760b63 100644 --- a/Code/Mantid/Framework/DataHandling/src/LoadInstrument.cpp +++ b/Code/Mantid/Framework/DataHandling/src/LoadInstrument.cpp @@ -127,7 +127,7 @@ void LoadInstrument::exec() { const PropertyWithValue *xml = dynamic_cast *>(InstrumentXML); if (xml) { - parser.initialize(m_filename, m_instName, *xml); + parser = InstrumentDefinitionParser(m_filename, m_instName, *xml); } else { throw std::invalid_argument("The instrument XML passed cannot be " "casted to a standard string."); @@ -165,7 +165,7 @@ void LoadInstrument::exec() { m_instName = instrumentFile.substr(0, instrumentFile.find("_Def")); // Initialize the parser with the the XML text loaded from the IDF file - parser.initialize(m_filename, m_instName, Strings::loadFile(m_filename)); + parser = InstrumentDefinitionParser(m_filename, m_instName, Strings::loadFile(m_filename)); } // Find the mangled instrument name that includes the modified date diff --git a/Code/Mantid/Framework/DataHandling/src/LoadMcStas.cpp b/Code/Mantid/Framework/DataHandling/src/LoadMcStas.cpp index 26c18005d880..57a7a2146c5d 100644 --- a/Code/Mantid/Framework/DataHandling/src/LoadMcStas.cpp +++ b/Code/Mantid/Framework/DataHandling/src/LoadMcStas.cpp @@ -187,9 +187,8 @@ void LoadMcStas::readEventData( progInitial.report("Loading instrument"); - Geometry::InstrumentDefinitionParser parser; std::string instrumentName = "McStas"; - parser.initialize(filename, instrumentName, instrumentXML); + Geometry::InstrumentDefinitionParser parser(filename, instrumentName, instrumentXML); std::string instrumentNameMangled = parser.getMangledName(); // Check whether the instrument is already in the InstrumentDataService diff --git a/Code/Mantid/Framework/DataHandling/test/LoadNexusProcessedTest.h b/Code/Mantid/Framework/DataHandling/test/LoadNexusProcessedTest.h index c2b5c23bab10..7b24673a1269 100644 --- a/Code/Mantid/Framework/DataHandling/test/LoadNexusProcessedTest.h +++ b/Code/Mantid/Framework/DataHandling/test/LoadNexusProcessedTest.h @@ -829,8 +829,7 @@ class LoadNexusProcessedTest: public CxxTest::TestSuite // Loading a peaks workspace without a instrument from an IDF doesn't work ... const std::string filename = FileFinder::Instance().getFullPath( "IDFs_for_UNIT_TESTING/MINITOPAZ_Definition.xml"); - InstrumentDefinitionParser parser; - parser.initialize(filename, "MINITOPAZ", Strings::loadFile(filename)); + InstrumentDefinitionParser parser(filename, "MINITOPAZ", Strings::loadFile(filename)); auto instrument = parser.parseXML(NULL); peaksTestWS->populateInstrumentParameters(); peaksTestWS->setInstrument(instrument); @@ -872,8 +871,7 @@ class LoadNexusProcessedTest: public CxxTest::TestSuite // Loading a peaks workspace without a instrument from an IDF doesn't work ... const std::string filename = FileFinder::Instance().getFullPath( "IDFs_for_UNIT_TESTING/MINITOPAZ_Definition.xml"); - InstrumentDefinitionParser parser; - parser.initialize(filename, "MINITOPAZ", Strings::loadFile(filename)); + InstrumentDefinitionParser parser(filename, "MINITOPAZ", Strings::loadFile(filename)); auto instrument = parser.parseXML(NULL); peaksTestWS->populateInstrumentParameters(); peaksTestWS->setInstrument(instrument); diff --git a/Code/Mantid/Framework/Geometry/inc/MantidGeometry/Instrument/IDFObject.h b/Code/Mantid/Framework/Geometry/inc/MantidGeometry/Instrument/IDFObject.h index c50fb3e95035..e44f6b07c75f 100644 --- a/Code/Mantid/Framework/Geometry/inc/MantidGeometry/Instrument/IDFObject.h +++ b/Code/Mantid/Framework/Geometry/inc/MantidGeometry/Instrument/IDFObject.h @@ -5,7 +5,6 @@ #ifndef Q_MOC_RUN #include #endif -#include #include #include #include @@ -49,13 +48,11 @@ class DLLExport AbstractIDFObject { public: AbstractIDFObject() {} static const std::string expectedExtension(); - virtual const Poco::Path &getParentDirectory() const = 0; + virtual const Poco::Path getParentDirectory() const = 0; virtual const Poco::Path &getFileFullPath() const = 0; virtual const std::string &getFileFullPathStr() const = 0; virtual std::string getFileNameOnly() const = 0; virtual std::string getExtension() const = 0; - virtual Poco::Timestamp getLastModified() const = 0; - virtual std::string getFormattedLastModified() const = 0; virtual std::string getMangledName() const = 0; virtual bool exists() const = 0; virtual ~AbstractIDFObject(){}; @@ -71,13 +68,11 @@ class DLLExport AbstractIDFObject { class DLLExport IDFObject : public AbstractIDFObject { public: IDFObject(const std::string &fileName); - virtual const Poco::Path &getParentDirectory() const; + virtual const Poco::Path getParentDirectory() const; virtual const Poco::Path &getFileFullPath() const; virtual const std::string &getFileFullPathStr() const; virtual std::string getFileNameOnly() const; virtual std::string getExtension() const; - virtual Poco::Timestamp getLastModified() const; - virtual std::string getFormattedLastModified() const; virtual std::string getMangledName() const; virtual bool exists() const; virtual ~IDFObject(); @@ -101,7 +96,7 @@ class DLLExport NullIDFObject : public AbstractIDFObject { public: NullIDFObject() : m_emptyResponse("") {} - virtual const Poco::Path &getParentDirectory() const { + virtual const Poco::Path getParentDirectory() const { throw std::runtime_error("Not implemented on NullIDFObject"); } virtual const Poco::Path &getFileFullPath() const { @@ -112,12 +107,6 @@ class DLLExport NullIDFObject : public AbstractIDFObject { } virtual std::string getFileNameOnly() const { return m_emptyResponse; } virtual std::string getExtension() const { return m_emptyResponse; } - virtual Poco::Timestamp getLastModified() const { - throw std::runtime_error("Not implemented on NullIDFObject"); - } - virtual std::string getFormattedLastModified() const { - throw std::runtime_error("Not implemented on NullIDFObject"); - } virtual std::string getMangledName() const { throw std::runtime_error("Not implemented on NullIDFObject"); } diff --git a/Code/Mantid/Framework/Geometry/inc/MantidGeometry/Instrument/InstrumentDefinitionParser.h b/Code/Mantid/Framework/Geometry/inc/MantidGeometry/Instrument/InstrumentDefinitionParser.h index 3a6a4edb1445..1ee83c18075c 100644 --- a/Code/Mantid/Framework/Geometry/inc/MantidGeometry/Instrument/InstrumentDefinitionParser.h +++ b/Code/Mantid/Framework/Geometry/inc/MantidGeometry/Instrument/InstrumentDefinitionParser.h @@ -58,26 +58,22 @@ class Object; class DLLExport InstrumentDefinitionParser { public: InstrumentDefinitionParser(); + InstrumentDefinitionParser(const std::string &filename, const std::string &instName, + const std::string &xmlText); + InstrumentDefinitionParser(const IDFObject_const_sptr xmlFile, + const IDFObject_const_sptr expectedCacheFile, + const std::string& instName, const std::string& xmlText); ~InstrumentDefinitionParser(); /// Caching enum CachingOption { NoneApplied, - ReadAdjacent, + ReadGeomCache, ReadFallBack, - WroteCacheAdjacent, + WroteGeomCache, WroteCacheTemp }; - /// Set up parser - void initialize(const std::string &filename, const std::string &instName, - const std::string &xmlText); - - /// Set up parser. - void initialize(IDFObject_const_sptr xmlFile, - IDFObject_const_sptr expectedCacheFile, - const std::string &instName, const std::string &xmlText); - /// Parse XML contents boost::shared_ptr parseXML(Kernel::ProgressBase *prog); @@ -104,7 +100,19 @@ class DLLExport InstrumentDefinitionParser { /// Getter the the applied caching option. CachingOption getAppliedCachingOption() const; + ///creates a vtp filename from a given xml filename + const std::string createVTPFileName(); + private: + ///shared Constructor logic + void initialise(const std::string &filename, + const std::string &instName, + const std::string &xmlText, + const std::string &vtpFilename); + + ///lazy loads the document and returns a pointer + Poco::AutoPtr getDocument(); + /// Set location (position) of comp as specified in XML location element void setLocation(Geometry::IComponent *comp, const Poco::XML::Element *pElem, const double angleConvertConst, @@ -210,7 +218,7 @@ class DLLExport InstrumentDefinitionParser { /// notation for a sequence of \ elements. /// This method return this sequence as a xml string std::string convertLocationsElement(const Poco::XML::Element *pElem); - + public: // for testing /// return absolute position of point which is set relative to the /// coordinate system of the input component @@ -218,14 +226,12 @@ class DLLExport InstrumentDefinitionParser { Kernel::V3D); private: - /// Checks if the proposed cache file can be read from. - bool canUseProposedCacheFile(IDFObject_const_sptr cache) const; - /// Reads from a cache file. void applyCache(IDFObject_const_sptr cacheToApply); /// Write out a cache file. - CachingOption writeAndApplyCache(IDFObject_const_sptr usedCache); + CachingOption writeAndApplyCache(IDFObject_const_sptr firstChoiceCache, + IDFObject_const_sptr usedCache); /// This method returns the parent appended which its child components and /// also name of type of the last child component @@ -259,10 +265,8 @@ class DLLExport InstrumentDefinitionParser { /// Name of the instrument std::string m_instName; - /// XML document loaded - Poco::AutoPtr pDoc; - /// Root element of the parsed XML - Poco::XML::Element *pRootElem; + /// XML document is lazy loaded + Poco::AutoPtr m_pDoc; /** Holds all the xml elements that have a \ child element. * Added purely for the purpose of computing speed and is used in diff --git a/Code/Mantid/Framework/Geometry/src/Instrument/IDFObject.cpp b/Code/Mantid/Framework/Geometry/src/Instrument/IDFObject.cpp index 35e8dd10d470..150a84be6b9c 100644 --- a/Code/Mantid/Framework/Geometry/src/Instrument/IDFObject.cpp +++ b/Code/Mantid/Framework/Geometry/src/Instrument/IDFObject.cpp @@ -33,7 +33,7 @@ IDFObject::~IDFObject() {} Gets the parent directory of the file. @return Parent directory path. */ -const Poco::Path &IDFObject::getParentDirectory() const { +const Poco::Path IDFObject::getParentDirectory() const { return m_cacheParentDirectory; } @@ -67,23 +67,6 @@ std::string IDFObject::getExtension() const { return "." + ext; } -/** -Gets the last modified timestamp of the file. -@return last modified timestamp. -*/ -Poco::Timestamp IDFObject::getLastModified() const { - return m_defFile.getLastModified(); -} - -/** -Gets a formatted string of the last modified timestamp. -@return timestamp as a formatted string. -*/ -std::string IDFObject::getFormattedLastModified() const { - return Poco::DateTimeFormatter::format(this->getLastModified(), - "%Y-%d-%mT%H:%M:%S"); -} - /** Gets the idf file as a mangled name. @return the idf file as a mangled name. diff --git a/Code/Mantid/Framework/Geometry/src/Instrument/InstrumentDefinitionParser.cpp b/Code/Mantid/Framework/Geometry/src/Instrument/InstrumentDefinitionParser.cpp index 7a1242493c94..2f96e19d3986 100644 --- a/Code/Mantid/Framework/Geometry/src/Instrument/InstrumentDefinitionParser.cpp +++ b/Code/Mantid/Framework/Geometry/src/Instrument/InstrumentDefinitionParser.cpp @@ -17,6 +17,7 @@ #include "MantidKernel/UnitFactory.h" #include "MantidKernel/Strings.h" +#include #include #include #include @@ -29,7 +30,6 @@ #include #include -#include using namespace Mantid; using namespace Mantid::Kernel; @@ -47,126 +47,162 @@ namespace { // initialize the static logger Kernel::Logger g_log("InstrumentDefinitionParser"); } - -//---------------------------------------------------------------------------------------------- -/** Constructor + //---------------------------------------------------------------------------------------------- +/** Default Constructor - not very functional in this state */ -InstrumentDefinitionParser::InstrumentDefinitionParser() - : m_xmlFile(boost::make_shared()), - m_cacheFile(boost::make_shared()), pDoc(NULL), - pRootElem(NULL), m_hasParameterElement_beenSet(false), + InstrumentDefinitionParser::InstrumentDefinitionParser(): + m_xmlFile(boost::make_shared()), + m_cacheFile(boost::make_shared()), m_pDoc(NULL), + m_hasParameterElement_beenSet(false), m_haveDefaultFacing(false), m_deltaOffsets(false), m_angleConvertConst(1.0), m_indirectPositions(false), - m_cachingOption(NoneApplied) {} - -//---------------------------------------------------------------------------------------------- -/** Destructor - */ -InstrumentDefinitionParser::~InstrumentDefinitionParser() {} - + m_cachingOption(NoneApplied) + { + initialise("","","",""); + } //---------------------------------------------------------------------------------------------- -/** Initialize the XML parser based on an IDF xml file path. - * - * Note that this convenience initialize method actually translates the inputs - *into the other initialize method. - * +/** Constructor * @param filename :: IDF .xml path (full). This is needed mostly to find the *instrument geometry cache. * @param instName :: name of the instrument * @param xmlText :: XML contents of IDF */ -void InstrumentDefinitionParser::initialize(const std::string &filename, - const std::string &instName, - const std::string &xmlText) { - IDFObject_const_sptr xmlFile = boost::make_shared(filename); - // Use the filename to construct the cachefile name so that there is a 1:1 map - // between a definition file & cache - std::string idfExt = xmlFile->getExtension(); - std::string vtpFilename = filename; - static const char *vtpExt = ".vtp"; - if (idfExt.empty()) { - vtpFilename += vtpExt; - } else { - boost::replace_last(vtpFilename, idfExt, vtpExt); - } - IDFObject_const_sptr vtpFile = - boost::make_shared(vtpFilename); - - this->initialize(xmlFile, vtpFile, instName, xmlText); +InstrumentDefinitionParser::InstrumentDefinitionParser(const std::string &filename, + const std::string &instName, + const std::string &xmlText) + : m_xmlFile(boost::make_shared()), + m_cacheFile(boost::make_shared()), m_pDoc(NULL), + m_hasParameterElement_beenSet(false), + m_haveDefaultFacing(false), m_deltaOffsets(false), + m_angleConvertConst(1.0), m_indirectPositions(false), + m_cachingOption(NoneApplied) +{ + initialise(filename,instName,xmlText,""); } //---------------------------------------------------------------------------------------------- -/** Initialize the XML parser based on an IDF xml and cached vtp file objects. +/** Construct the XML parser based on an IDF xml and cached vtp file objects. * * @param xmlFile :: The xml file, here wrapped in a IDFObject * @param expectedCacheFile :: Expected vtp cache file * @param instName :: Instrument name * @param xmlText :: XML contents of IDF */ -void InstrumentDefinitionParser::initialize( +InstrumentDefinitionParser::InstrumentDefinitionParser ( const IDFObject_const_sptr xmlFile, - const IDFObject_const_sptr expectedCacheFile, const std::string &instName, - const std::string &xmlText) { + const IDFObject_const_sptr expectedCacheFile, + const std::string &instName, + const std::string &xmlText) + : m_xmlFile(boost::make_shared()), + m_cacheFile(boost::make_shared()), m_pDoc(NULL), + m_hasParameterElement_beenSet(false), + m_haveDefaultFacing(false), m_deltaOffsets(false), + m_angleConvertConst(1.0), m_indirectPositions(false), + m_cachingOption(NoneApplied) +{ + initialise(xmlFile->getFileFullPathStr(),instName,xmlText,expectedCacheFile->getFileFullPathStr()); + m_cacheFile = expectedCacheFile; +} + + //---------------------------------------------------------------------------------------------- +/** Initialise method used in Constructor + * @param filename :: IDF .xml path (full). This is needed mostly to find the + *instrument geometry cache. + * @param instName :: name of the instrument + * @param xmlText :: XML contents of IDF + * @param vtpFilename :: the path to the vtp file if you want to override the default + */ +void InstrumentDefinitionParser::initialise(const std::string &filename, + const std::string &instName, + const std::string &xmlText, + const std::string &vtpFilename) +{ + + IDFObject_const_sptr xmlFile = boost::make_shared(filename); + // Handle the parameters - const std::string filename = xmlFile->getFileFullPathStr(); m_instName = instName; m_xmlFile = xmlFile; - m_cacheFile = expectedCacheFile; - - // Set up the DOM parser and parse xml file - DOMParser pParser; - try { - pDoc = pParser.parseString(xmlText); - } catch (Poco::Exception &exc) { - throw Kernel::Exception::FileError( - exc.displayText() + ". Unable to parse XML", filename); - } catch (...) { - throw Kernel::Exception::FileError("Unable to parse XML", filename); - } - // Get pointer to root element - pRootElem = pDoc->documentElement(); - if (!pRootElem->hasChildNodes()) { - g_log.error("XML file: " + filename + "contains no root element."); - throw Kernel::Exception::InstrumentDefinitionError( - "No root element in XML instrument file", filename); - } - + // Create our new instrument // We don't want the instrument name taken out of the XML file itself, it // should come from the filename (or the property) m_instrument = boost::make_shared(m_instName); - + // Save the XML file path and contents m_instrument->setFilename(filename); m_instrument->setXmlText(xmlText); + + // Use the filename to construct the cachefile name so that there is a 1:1 map + // between a definition file & cache + if (vtpFilename.empty()) { + m_cacheFile = boost::make_shared(createVTPFileName()); + } + else + { + m_cacheFile = boost::make_shared(vtpFilename); + } + } +//---------------------------------------------------------------------------------------------- +/** Destructor + */ +InstrumentDefinitionParser::~InstrumentDefinitionParser() {} //---------------------------------------------------------------------------------------------- /** * 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 + * file sha-1 checksum to determine if it is already in *memory so that * changes to the instrument file will cause file to be reloaded. * - * @return a mangled name combining the filename and the "last-modified" + * @return a mangled name combining the filename and the checksum *attribute of the XML contents * */ std::string InstrumentDefinitionParser::getMangledName() { - // Use the file in preference if possible. - if (this->m_xmlFile->exists()) { - return m_xmlFile->getMangledName(); - } + std::string retVal = ""; + //use the xml in preference if available auto xml = Poco::trim(m_instrument->getXmlText()); if (!(xml.empty())) { std::string checksum = Kernel::ChecksumHelper::sha1FromString(xml); - return m_instName + checksum; - } else { - throw std::runtime_error( - "Call InstrumentDefinitionParser::initialize() before getMangledName."); + retVal = m_instName + checksum; + } + else if (this->m_xmlFile->exists()) {// Use the file + retVal = m_xmlFile->getMangledName(); + } + + return retVal; + +} + +//---------------------------------------------------------------------------------------------- +/** Lazy loads the document and returns a autopointer + * + * @return an autopointer to the xml document + */ +Poco::AutoPtr InstrumentDefinitionParser::getDocument() +{ + if (!m_pDoc) { + //instantiate if not created + if (m_instrument->getXmlText().empty()) + { + throw std::invalid_argument("Instrument XML string is empty"); + } + // Set up the DOM parser and parse xml file + DOMParser pParser; + try { + m_pDoc = pParser.parseString(m_instrument->getXmlText()); + } catch (Poco::Exception &exc) { + throw std::invalid_argument( + exc.displayText() + ". Unable to parse XML"); + } catch (...) { + throw std::invalid_argument("Unable to parse XML"); + } } + return m_pDoc; } //---------------------------------------------------------------------------------------------- @@ -178,9 +214,16 @@ std::string InstrumentDefinitionParser::getMangledName() { */ Instrument_sptr InstrumentDefinitionParser::parseXML(Kernel::ProgressBase *prog) { - if (!pDoc) - throw std::runtime_error( - "Call InstrumentDefinitionParser::initialize() before parseXML."); + auto pDoc = getDocument(); + + // Get pointer to root element + Poco::XML::Element * pRootElem = pDoc->documentElement(); + + if (!pRootElem->hasChildNodes()) { + g_log.error("Instrument XML contains no root element."); + throw Kernel::Exception::InstrumentDefinitionError( + "No root element in XML instrument"); + } setValidityRange(pRootElem); readDefaults(pRootElem->getChildElement("defaults")); @@ -508,7 +551,8 @@ void InstrumentDefinitionParser::saveDOM_Tree(std::string &outFilename) { Poco::XML::DOMWriter writer; writer.setNewLine("\n"); writer.setOptions(Poco::XML::XMLWriter::PRETTY_PRINT); - + + auto pDoc = getDocument(); std::ofstream outFile(outFilename.c_str()); writer.writeNode(outFile, pDoc); outFile.close(); @@ -951,8 +995,7 @@ void InstrumentDefinitionParser::readDefaults(Poco::XML::Element *defaults) { Handedness handedness = s_handedness.compare("right") == 0 ? Right : Left; // Overwrite the default reference frame. - m_instrument->setReferenceFrame(boost::shared_ptr( - new ReferenceFrame(pointingUp, alongBeam, handedness, s_origin))); + m_instrument->setReferenceFrame(boost::make_shared(pointingUp, alongBeam, handedness, s_origin)); } } @@ -1294,7 +1337,7 @@ void InstrumentDefinitionParser::appendLeaf(Geometry::ICompAssembly *parent, boost::dynamic_pointer_cast((*xColumn)[y]); if (detector) { // Make default facing for the pixel - Geometry::IComponent *comp = (Geometry::IComponent *)detector.get(); + Geometry::IComponent *comp = static_cast(detector.get()); if (m_haveDefaultFacing) makeXYplaneFaceComponent(comp, m_defaultFacing); // Mark it as a detector (add to the instrument cache) @@ -2069,7 +2112,7 @@ void InstrumentDefinitionParser::setComponentLinks( unsigned long numberLinks = pNL_link->length(); if (progress) - progress->resetNumSteps((int64_t)numberLinks, 0.0, 0.95); + progress->resetNumSteps(static_cast(numberLinks), 0.0, 0.95); Node *curNode = pRootElem->firstChild(); while (curNode) { @@ -2092,7 +2135,7 @@ void InstrumentDefinitionParser::setComponentLinks( int detid; std::stringstream(id) >> detid; boost::shared_ptr detector = - instrument->getDetector((detid_t)detid); + instrument->getDetector(static_cast(detid)); // If we didn't find anything with the detector id, explain why to the // user, and throw an exception. @@ -2160,17 +2203,6 @@ void InstrumentDefinitionParser::setComponentLinks( } } -/** -Check that the cache file does actually exist and that it was modified last -after the last modification to the xml def file. i.e. the vtp file contains the -most recent set of changes. -@param cacheCandiate : candiate cache file object to use the the geometries. -*/ -bool InstrumentDefinitionParser::canUseProposedCacheFile( - IDFObject_const_sptr cacheCandiate) const { - return m_xmlFile->exists() && cacheCandiate->exists() && - (m_xmlFile->getLastModified() < cacheCandiate->getLastModified()); -} /** Apply the cache. @@ -2194,19 +2226,18 @@ Write the cache file from the IDF file and apply it. @param fallBackCache : File location for a fallback cache if required. */ InstrumentDefinitionParser::CachingOption -InstrumentDefinitionParser::writeAndApplyCache( +InstrumentDefinitionParser::writeAndApplyCache(IDFObject_const_sptr firstChoiceCache, IDFObject_const_sptr fallBackCache) { - IDFObject_const_sptr usedCache = m_cacheFile; - InstrumentDefinitionParser::CachingOption cachingOption = WroteCacheAdjacent; + IDFObject_const_sptr usedCache = firstChoiceCache; + auto cachingOption = WroteGeomCache; g_log.information("Geometry cache is not available"); try { - Poco::File dir = m_xmlFile->getParentDirectory(); - if (!m_xmlFile->exists() || dir.path().empty() || !dir.exists() || - !dir.canWrite()) { + Poco::File dir = usedCache->getParentDirectory(); + if (dir.path().empty() || !dir.exists() || !dir.canWrite()) { usedCache = fallBackCache; cachingOption = WroteCacheTemp; - g_log.information() << "Instrument directory is read only, writing cache " + g_log.information() << "Geometrycache directory is read only, writing cache " "to system temp.\n"; } } catch (Poco::FileNotFoundException &) { @@ -2239,17 +2270,17 @@ InstrumentDefinitionParser::setupGeometryCache() { // directory. IDFObject_const_sptr fallBackCache = boost::make_shared( Poco::Path(ConfigService::Instance().getTempDir()) - .append(m_instName + ".vtp") + .append(this->getMangledName()+".vtp") .toString()); CachingOption cachingOption = NoneApplied; - if (canUseProposedCacheFile(m_cacheFile)) { + if (m_cacheFile->exists()) { applyCache(m_cacheFile); - cachingOption = ReadAdjacent; - } else if (canUseProposedCacheFile(fallBackCache)) { + cachingOption = ReadGeomCache; + } else if (fallBackCache->exists()) { applyCache(fallBackCache); cachingOption = ReadFallBack; } else { - cachingOption = writeAndApplyCache(fallBackCache); + cachingOption = writeAndApplyCache(m_cacheFile,fallBackCache); } return cachingOption; } @@ -2668,6 +2699,24 @@ std::string InstrumentDefinitionParser::convertLocationsElement( return xml.str(); } + /** Generates a vtp filename from a xml filename + * + * @return The vtp filename + * + */ +const std::string InstrumentDefinitionParser::createVTPFileName() +{ + std::string retVal; + std::string filename = getMangledName(); + if (!filename.empty()) { + Poco::Path path(ConfigService::Instance().getVTPFileDirectory()); + path.makeDirectory(); + path.append(filename + ".vtp"); + retVal = path.toString(); + } + return retVal; +} + /** Return a subelement of an XML element, but also checks that there exist *exactly one entry * of this subelement. diff --git a/Code/Mantid/Framework/Geometry/test/IDFObjectTest.h b/Code/Mantid/Framework/Geometry/test/IDFObjectTest.h index ff93226299f6..2070ba2183c0 100644 --- a/Code/Mantid/Framework/Geometry/test/IDFObjectTest.h +++ b/Code/Mantid/Framework/Geometry/test/IDFObjectTest.h @@ -80,24 +80,6 @@ class IDFObjectTest : public CxxTest::TestSuite TS_ASSERT_EQUALS(filenameonly, obj.getFileNameOnly()); } - void testGetModifiedTimestamp() - { - const std::string filename = ConfigService::Instance().getInstrumentDirectory() + "/IDFs_for_UNIT_TESTING/IDF_for_UNIT_TESTING.xml"; - Poco::File file(filename); - - IDFObject obj(filename); - TS_ASSERT_EQUALS(file.getLastModified(), obj.getLastModified()); - } - - void testGetFormattedModifiedTimestamp() - { - const std::string filename = ConfigService::Instance().getInstrumentDirectory() + "/IDFs_for_UNIT_TESTING/IDF_for_UNIT_TESTING.xml"; - Poco::File file(filename); - - IDFObject obj(filename); - TS_ASSERT_EQUALS(Poco::DateTimeFormatter::format(file.getLastModified(), "%Y-%d-%mT%H:%M:%S"), obj.getFormattedLastModified()); - } - void testGetMangledName() { const std::string filename = ConfigService::Instance().getInstrumentDirectory() + "/IDFs_for_UNIT_TESTING/IDF_for_UNIT_TESTING.xml"; diff --git a/Code/Mantid/Framework/Geometry/test/InstrumentDefinitionParserTest.h b/Code/Mantid/Framework/Geometry/test/InstrumentDefinitionParserTest.h index e938bf680146..3499e9919cc8 100644 --- a/Code/Mantid/Framework/Geometry/test/InstrumentDefinitionParserTest.h +++ b/Code/Mantid/Framework/Geometry/test/InstrumentDefinitionParserTest.h @@ -3,6 +3,7 @@ #include #include "MantidGeometry/Instrument/InstrumentDefinitionParser.h" +#include "MantidKernel/ChecksumHelper.h" #include "MantidKernel/ConfigService.h" #include "MantidKernel/Strings.h" #include "MantidGeometry/Instrument/RectangularDetector.h" @@ -10,7 +11,6 @@ #include "MantidTestHelpers/ScopedFileHelper.h" #include -#include #include using namespace Mantid; @@ -29,12 +29,20 @@ class InstrumentDefinitionParserTest : public CxxTest::TestSuite { public: MockIDFObject(const std::string fileName) : Mantid::Geometry::IDFObject(fileName){} - MOCK_CONST_METHOD0(getLastModified, Poco::Timestamp()); MOCK_CONST_METHOD0(exists, bool()); }; + /// Mock Type to act as IDF files. + class MockIDFObjectWithParentDirectory : public Mantid::Geometry::IDFObject + { + public: + MockIDFObjectWithParentDirectory(const std::string fileName) : Mantid::Geometry::IDFObject(fileName){} + MOCK_CONST_METHOD0(exists, bool()); + MOCK_CONST_METHOD0(getParentDirectory, const Poco::Path()); + }; + /** - Helper type to pass around related IDF enviroment information in a collection. + Helper type to pass around related IDF environment information in a collection. */ struct IDFEnvironment { @@ -56,7 +64,6 @@ class InstrumentDefinitionParserTest : public CxxTest::TestSuite { const std::string instrument_name = "MinimalForTesting"; const std::string idf_filename = instrument_name + "_Definition.xml"; - const std::string vtp_filename= instrument_name + ".vtp"; const std::string idf_file_contents = "" "" "" @@ -76,17 +83,17 @@ class InstrumentDefinitionParserTest : public CxxTest::TestSuite "" ""; + //expected name + const std::string vtp_filename = instrument_name + ChecksumHelper::sha1FromString(Strings::strip(idf_file_contents)) + ".vtp"; const std::string vtp_file_contents=""; - + const std::string instrument_dir = ConfigService::Instance().getInstrumentDirectory() + "/IDFs_for_UNIT_TESTING/"; - - ScopedFile idf(idf_file_contents, idf_filename, instrument_dir); - ScopedFile vtp(vtp_file_contents, vtp_filename, instrument_dir); // Put the vtp file adjacent to the idf. - - if(!put_vtp_next_to_IDF) - { - vtp = ScopedFile(vtp_file_contents, vtp_filename); // Overwrite to put vtp file in the temp dir + std::string vtp_dir = ConfigService::Instance().getVTPFileDirectory(); + if (!put_vtp_next_to_IDF) { + vtp_dir= ConfigService::Instance().getTempDir(); } + ScopedFile idf(idf_file_contents, idf_filename, instrument_dir); + ScopedFile vtp(vtp_file_contents, vtp_filename, vtp_dir); return IDFEnvironment(idf, vtp, idf_file_contents, instrument_name); @@ -114,8 +121,7 @@ class InstrumentDefinitionParserTest : public CxxTest::TestSuite boost::shared_ptr i; // Parse the XML - InstrumentDefinitionParser parser; - TS_ASSERT_THROWS_NOTHING( parser.initialize(filename, "For Unit Testing", xmlText); ); + InstrumentDefinitionParser parser(filename, "For Unit Testing", xmlText); TS_ASSERT_THROWS_NOTHING( i = parser.parseXML(NULL); ); // Extract the reference frame object @@ -136,8 +142,10 @@ class InstrumentDefinitionParserTest : public CxxTest::TestSuite std::string xmlText = Strings::loadFile(filename); boost::shared_ptr i; + InstrumentDefinitionParser parser(filename, "For Unit Testing", xmlText); + // Parse the XML (remove old vtp file if it exists) - std::string vtpFilename = filenameNoExt + ".vtp"; + std::string vtpFilename = parser.createVTPFileName(); try { Poco::File vtpFile(vtpFilename); @@ -145,10 +153,7 @@ class InstrumentDefinitionParserTest : public CxxTest::TestSuite } catch(Poco::FileNotFoundException&) {} - InstrumentDefinitionParser parser; - TS_ASSERT_THROWS_NOTHING( parser.initialize(filename, "For Unit Testing", xmlText); ); TS_ASSERT_THROWS_NOTHING( i = parser.parseXML(NULL); ); - try { Poco::File vtpFile(vtpFilename); @@ -433,8 +438,7 @@ class InstrumentDefinitionParserTest : public CxxTest::TestSuite boost::shared_ptr i; // Parse the XML - InstrumentDefinitionParser parser; - TS_ASSERT_THROWS_NOTHING( parser.initialize(filename, "For Unit Testing2", xmlText); ); + InstrumentDefinitionParser parser(filename, "For Unit Testing2", xmlText); TS_ASSERT_THROWS_NOTHING( i = parser.parseXML(NULL); ); boost::shared_ptr ptrDetShape = i->getDetector(1100); @@ -478,8 +482,7 @@ class InstrumentDefinitionParserTest : public CxxTest::TestSuite boost::shared_ptr i; // Parse the XML - InstrumentDefinitionParser parser; - TS_ASSERT_THROWS_NOTHING( parser.initialize(filename, "RectangularUnitTest", xmlText); ); + InstrumentDefinitionParser parser(filename, "RectangularUnitTest", xmlText); TS_ASSERT_THROWS_NOTHING( i = parser.parseXML(NULL); ); // Now the XY detector in bank1 @@ -533,8 +536,7 @@ class InstrumentDefinitionParserTest : public CxxTest::TestSuite boost::shared_ptr i; // Parse the XML - InstrumentDefinitionParser parser; - TS_ASSERT_THROWS_NOTHING( parser.initialize(filename, "AdjustTest", xmlText); ); + InstrumentDefinitionParser parser(filename, "AdjustTest", xmlText); TS_ASSERT_THROWS_NOTHING( i = parser.parseXML(NULL); ); // None rotated cuboid @@ -614,73 +616,19 @@ class InstrumentDefinitionParserTest : public CxxTest::TestSuite TS_ASSERT_EQUALS(InstrumentDefinitionParser::NoneApplied, parser.getAppliedCachingOption()); } - void testUseAdjacentCacheFile() + void testCreateVTPFilename() { IDFEnvironment instrumentEnv = create_idf_and_vtp_pair(); - const std::string idfFileName = instrumentEnv._idf.getFileName(); - const std::string cacheFileName = instrumentEnv._vtp.getFileName(); - - MockIDFObject* mockIDF = new MockIDFObject(idfFileName); - MockIDFObject* mockCache = new MockIDFObject(cacheFileName); - - EXPECT_CALL(*mockIDF, exists()).WillRepeatedly(Return(true)); - EXPECT_CALL(*mockCache, exists()).WillRepeatedly(Return(true)); - - const Poco::Timestamp smallerTime = 0; - const Poco::Timestamp largerTime = smallerTime + 1; - - EXPECT_CALL(*mockIDF, getLastModified()).WillOnce(Return(smallerTime)); - EXPECT_CALL(*mockCache, getLastModified()).WillOnce(Return(largerTime)); // Mock expectation set such that Cache file modified created most recently, so SHOULD be used. - - IDFObject_const_sptr idf(mockIDF); - IDFObject_const_sptr cache(mockCache); - - InstrumentDefinitionParser parser; + const std::string instrumentName = instrumentEnv._instName; const std::string xmlText = Strings::loadFile(idfFileName); - const std::string instrumentName = "UseAjacentCache"; - parser.initialize(idf, cache, instrumentEnv._instName, instrumentEnv._xmlText); - TS_ASSERT_THROWS_NOTHING(parser.parseXML(NULL)); - - TS_ASSERT_EQUALS(InstrumentDefinitionParser::ReadAdjacent, parser.getAppliedCachingOption()); // Check that the adjacent cache file was used. - TS_ASSERT(Mock::VerifyAndClearExpectations(mockIDF)); - TS_ASSERT(Mock::VerifyAndClearExpectations(mockCache)); - } + InstrumentDefinitionParser parser(idfFileName,instrumentName,xmlText); - void testWriteAdjacentCacheFileIfCacheIsOutOfDate() - { - IDFEnvironment instrumentEnv = create_idf_and_vtp_pair(); - - const std::string idfFileName = instrumentEnv._idf.getFileName(); - const std::string cacheFileName = instrumentEnv._vtp.getFileName(); - - MockIDFObject* mockIDF = new MockIDFObject(idfFileName); - MockIDFObject* mockCache = new MockIDFObject(cacheFileName); - - EXPECT_CALL(*mockIDF, exists()).WillRepeatedly(Return(true)); - EXPECT_CALL(*mockCache, exists()).WillRepeatedly(Return(true)); - - const Poco::Timestamp smallerTime = 0; - const Poco::Timestamp largerTime = smallerTime + 1; - - EXPECT_CALL(*mockIDF, getLastModified()).WillRepeatedly(Return(largerTime)); // Mock expectation set up so that IDF will appear newer than cache file. - EXPECT_CALL(*mockCache, getLastModified()).WillRepeatedly(Return(smallerTime)); - - IDFObject_const_sptr idf(mockIDF); - IDFObject_const_sptr cache(mockCache); - - InstrumentDefinitionParser parser; - parser.initialize(idf, cache, instrumentEnv._instName, instrumentEnv._xmlText); - TS_ASSERT_THROWS_NOTHING(parser.parseXML(NULL)); - - TS_ASSERT_EQUALS(InstrumentDefinitionParser::WroteCacheAdjacent, parser.getAppliedCachingOption()); // Check that the adjacent cache file was used. - TS_ASSERT(Mock::VerifyAndClearExpectations(mockIDF)); - TS_ASSERT(Mock::VerifyAndClearExpectations(mockCache)); + TS_ASSERT_EQUALS(instrumentEnv._vtp.getFileName(), parser.createVTPFileName()); } - + void testReadFromCacheInTempDirectory() { - const time_t tAtStart = 0; // create an early timestamp for use later. const bool put_vtp_in_instrument_directory = false; IDFEnvironment instrumentEnv = create_idf_and_vtp_pair(put_vtp_in_instrument_directory); @@ -691,24 +639,35 @@ class InstrumentDefinitionParserTest : public CxxTest::TestSuite MockIDFObject* mockCache = new MockIDFObject(cacheFileName); EXPECT_CALL(*mockIDF, exists()).WillRepeatedly(Return(true)); - EXPECT_CALL(*mockCache, exists()).WillRepeatedly(Return(false)); // Mock expectation set such that adjacent Cache file does not exist, so should not be used. + EXPECT_CALL(*mockCache, exists()).WillRepeatedly(Return(false)); // Mock expectation set such that geometry Cache file does not exist, so should not be used. - EXPECT_CALL(*mockIDF, getLastModified()).WillOnce(Return(tAtStart)); IDFObject_const_sptr idf(mockIDF); IDFObject_const_sptr cache(mockCache); - InstrumentDefinitionParser parser; + InstrumentDefinitionParser parser(idf, cache, instrumentEnv._instName, instrumentEnv._xmlText); - parser.initialize(idf, cache, instrumentEnv._instName, instrumentEnv._xmlText); TS_ASSERT_THROWS_NOTHING(parser.parseXML(NULL)); - TS_ASSERT_EQUALS(InstrumentDefinitionParser::ReadFallBack, parser.getAppliedCachingOption()); // Check that the adjacent cache file was used. + TS_ASSERT_EQUALS(InstrumentDefinitionParser::ReadFallBack, parser.getAppliedCachingOption()); // Check that the geometry cache file was used. TS_ASSERT(Mock::VerifyAndClearExpectations(mockIDF)); TS_ASSERT(Mock::VerifyAndClearExpectations(mockCache)); } - void testWriteAdjacentCacheFileIfCacheDoestExist() + void RemoveFallbackVTPFile(InstrumentDefinitionParser& parser) + { + Poco::Path vtpPath(parser.createVTPFileName()); + Poco::Path fallbackPath(ConfigService::Instance().getTempDir()); + fallbackPath.makeDirectory(); + fallbackPath.setFileName(vtpPath.getFileName()); + std::string fp = fallbackPath.toString(); + Poco::File fallbackFile(fallbackPath.toString()); + if (fallbackFile.exists()) { + fallbackFile.remove(); + } + } + + void testWriteCacheFileIfCacheDoestExist() { IDFEnvironment instrumentEnv = create_idf_and_vtp_pair(); @@ -718,18 +677,22 @@ class InstrumentDefinitionParserTest : public CxxTest::TestSuite MockIDFObject* mockIDF = new MockIDFObject(idfFileName); MockIDFObject* mockCache = new MockIDFObject(cacheFileName); + //make sure the fallback location for the geometry file is deleted + + EXPECT_CALL(*mockIDF, exists()).WillRepeatedly(Return(true)); EXPECT_CALL(*mockCache, exists()).WillRepeatedly(Return(false)); // Mock expectation set such that Cache file does not exist, so should not be used. IDFObject_const_sptr idf(mockIDF); IDFObject_const_sptr cache(mockCache); - InstrumentDefinitionParser parser; - - parser.initialize(idf, cache, instrumentEnv._instName, instrumentEnv._xmlText); - TS_ASSERT_THROWS_NOTHING(parser.parseXML(NULL)); + //remove the fallback file if it exists + InstrumentDefinitionParser parser(idf, cache, instrumentEnv._instName, instrumentEnv._xmlText); + RemoveFallbackVTPFile(parser); - TS_ASSERT_EQUALS(InstrumentDefinitionParser::WroteCacheAdjacent, parser.getAppliedCachingOption()); // Check that the adjacent cache file was used. + TS_ASSERT_THROWS_NOTHING(parser.parseXML(NULL)); + + TS_ASSERT_EQUALS(InstrumentDefinitionParser::WroteGeomCache, parser.getAppliedCachingOption()); // Check that the geometry cache file was used. TS_ASSERT(Mock::VerifyAndClearExpectations(mockIDF)); TS_ASSERT(Mock::VerifyAndClearExpectations(mockCache)); } @@ -746,16 +709,17 @@ class InstrumentDefinitionParserTest : public CxxTest::TestSuite const std::string cacheFileName = instrumentEnv._vtp.getFileName(); // We do provide a cache file, but this shouldn't be used. MockIDFObject* mockIDF = new MockIDFObject(idfFileName); - MockIDFObject* mockCache = new MockIDFObject(cacheFileName); + MockIDFObjectWithParentDirectory* mockCache = new MockIDFObjectWithParentDirectory(cacheFileName); EXPECT_CALL(*mockIDF, exists()).WillRepeatedly(Return(false)); // IDF set not to exist. - EXPECT_CALL(*mockCache, exists()).WillRepeatedly(Return(true)); // Mock expectation set such that Cache file does exist, but should not be used.. + EXPECT_CALL(*mockCache, exists()).WillRepeatedly(Return(false)); // Mock expectation set such that Cache file does not exist, and location is inaccessible. + EXPECT_CALL(*mockCache, getParentDirectory()).WillRepeatedly(Return(Poco::Path("this does not exist"))); IDFObject_const_sptr idf(mockIDF); IDFObject_const_sptr cache(mockCache); - InstrumentDefinitionParser parser; - parser.initialize(idf, cache, instrumentEnv._instName, instrumentEnv._xmlText); + InstrumentDefinitionParser parser(idf, cache, instrumentEnv._instName, instrumentEnv._xmlText); + TS_ASSERT_THROWS_NOTHING(parser.parseXML(NULL)); TS_ASSERT_EQUALS(InstrumentDefinitionParser::WroteCacheTemp, parser.getAppliedCachingOption()); // Check that the TEMP cache file was used. @@ -797,8 +761,7 @@ class InstrumentDefinitionParserTest : public CxxTest::TestSuite ScopedFile idfFile = createIDFFileObject(idfFilename, idfFileContents); - InstrumentDefinitionParser parser; - TS_ASSERT_THROWS_NOTHING( parser.initialize(idfFilename, "For Unit Testing", idfFileContents); ); + InstrumentDefinitionParser parser(idfFilename, "For Unit Testing", idfFileContents); std::string errorMsg(""); try @@ -827,8 +790,7 @@ class InstrumentDefinitionParserTest : public CxxTest::TestSuite boost::replace_first(contents, "%LOCATIONS%", locations); boost::replace_first(contents, "%NUM_DETECTORS%", boost::lexical_cast(numDetectors)); - InstrumentDefinitionParser parser; - parser.initialize(filename, "LocationsTestInstrument", contents); + InstrumentDefinitionParser parser(filename, "LocationsTestInstrument", contents); Instrument_sptr instr; @@ -996,8 +958,7 @@ void testLoadingAndParsing() } catch(Poco::FileNotFoundException&) {} - InstrumentDefinitionParser parser; - TS_ASSERT_THROWS_NOTHING( parser.initialize(filename, "For Unit Testing", xmlText); ); + InstrumentDefinitionParser parser(filename, "For Unit Testing", xmlText); TS_ASSERT_THROWS_NOTHING( i = parser.parseXML(NULL); ); // Remove it for clean test @@ -1017,3 +978,4 @@ void testLoadingAndParsing() #endif /* MANTID_GEOMETRY_INSTRUMENTDEFINITIONPARSERTEST_H_ */ + diff --git a/Code/Mantid/Framework/Kernel/inc/MantidKernel/ConfigService.h b/Code/Mantid/Framework/Kernel/inc/MantidKernel/ConfigService.h index 5f218e2a1dc0..ed1da6ad340e 100644 --- a/Code/Mantid/Framework/Kernel/inc/MantidKernel/ConfigService.h +++ b/Code/Mantid/Framework/Kernel/inc/MantidKernel/ConfigService.h @@ -206,6 +206,8 @@ class MANTID_KERNEL_DLL ConfigServiceImpl { const std::vector &getInstrumentDirectories() const; /// Get instrument search directory const std::string getInstrumentDirectory() const; + ///get the vtp file directory + const std::string getVTPFileDirectory(); //@} /// Load facility information from instrumentDir/Facilities.xml file diff --git a/Code/Mantid/Framework/Kernel/src/ConfigService.cpp b/Code/Mantid/Framework/Kernel/src/ConfigService.cpp index 4ff60619ab8f..e309fbd9c54f 100644 --- a/Code/Mantid/Framework/Kernel/src/ConfigService.cpp +++ b/Code/Mantid/Framework/Kernel/src/ConfigService.cpp @@ -187,14 +187,6 @@ ConfigServiceImpl::ConfigServiceImpl() } } - // Assert that the appdata and the instrument subdirectory exists - std::string appDataDir = getAppDataDir(); - Poco::Path path(appDataDir); - path.pushDirectory("instrument"); - Poco::File file(path); - // createdirectories will fail gracefully if it is already present - file.createDirectories(); - // Fill the list of possible relative path keys that may require conversion to // absolute paths m_ConfigPaths.insert( @@ -203,6 +195,7 @@ ConfigServiceImpl::ConfigServiceImpl() m_ConfigPaths.insert(std::make_pair("pvplugins.directory", true)); m_ConfigPaths.insert(std::make_pair("mantidqt.plugins.directory", true)); m_ConfigPaths.insert(std::make_pair("instrumentDefinition.directory", true)); + m_ConfigPaths.insert(std::make_pair("instrumentDefinition.vtpDirectory", true)); m_ConfigPaths.insert(std::make_pair("groupingFiles.directory", true)); m_ConfigPaths.insert(std::make_pair("maskFiles.directory", true)); m_ConfigPaths.insert(std::make_pair("colormaps.directory", true)); @@ -253,6 +246,16 @@ ConfigServiceImpl::ConfigServiceImpl() #ifndef MPI_BUILD // There is no logging to file by default in MPI build g_log.information() << "Logging to: " << m_logFilePath << std::endl; #endif + + // Assert that the appdata and the instrument subdirectory exists + std::string appDataDir = getAppDataDir(); + Poco::Path path(appDataDir); + path.pushDirectory("instrument"); + Poco::File file(path); + // createdirectories will fail gracefully if it is already present + file.createDirectories(); + Poco::File vtpDir(getVTPFileDirectory()); + vtpDir.createDirectories(); } /** Private Destructor @@ -1669,7 +1672,24 @@ ConfigServiceImpl::getInstrumentDirectories() const { const std::string ConfigServiceImpl::getInstrumentDirectory() const { return m_InstrumentDirs[m_InstrumentDirs.size() - 1]; } - +/** + * Return the search directory for vtp files + * @returns a path + */ +const std::string ConfigServiceImpl::getVTPFileDirectory() { + // Determine the search directory for XML instrument definition files (IDFs) + std::string directoryName = getString("instrumentDefinition.vtpDirectory"); + + if (directoryName.empty()) + { + Poco::Path path(getAppDataDir()); + path.makeDirectory(); + path.pushDirectory("instrument"); + path.pushDirectory("geometryCache"); + directoryName = path.toString(); + } + return directoryName; +} /** * Fills the internal cache of instrument definition directories */ diff --git a/Code/Mantid/Framework/TestHelpers/src/MDEventsTestHelper.cpp b/Code/Mantid/Framework/TestHelpers/src/MDEventsTestHelper.cpp index 9a8941ae9d41..ac738ae22134 100644 --- a/Code/Mantid/Framework/TestHelpers/src/MDEventsTestHelper.cpp +++ b/Code/Mantid/Framework/TestHelpers/src/MDEventsTestHelper.cpp @@ -69,8 +69,7 @@ createDiffractionEventWorkspace(int numEvents, int numPixels, int numBins) { // --------- Load the instrument ----------- const std::string filename = FileFinder::Instance().getFullPath( "IDFs_for_UNIT_TESTING/MINITOPAZ_Definition.xml"); - InstrumentDefinitionParser parser; - parser.initialize(filename, "MINITOPAZ", Strings::loadFile(filename)); + InstrumentDefinitionParser parser(filename, "MINITOPAZ", Strings::loadFile(filename)); auto instrument = parser.parseXML(NULL); retVal->populateInstrumentParameters(); retVal->setInstrument(instrument);