diff --git a/Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/LoadIDFFromNexus.h b/Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/LoadIDFFromNexus.h index 44ea9f8826ae20b0fc0ac48585d6264ed84e0b4c..85a1f8df18a3e6fd84d7f710c4321de25a33ee48 100644 --- a/Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/LoadIDFFromNexus.h +++ b/Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/LoadIDFFromNexus.h @@ -89,6 +89,8 @@ private: void init(); /// Overwrites Algorithm method void exec(); + /// Load Parameter File specified by full pathname into given workspace, return success + bool loadParameterFile (const std::string& fullPathName, const API::MatrixWorkspace_sptr workspace ); }; } // namespace DataHandling diff --git a/Code/Mantid/Framework/DataHandling/src/LoadIDFFromNexus.cpp b/Code/Mantid/Framework/DataHandling/src/LoadIDFFromNexus.cpp index 3cb49bb1a53e46a0b5aa893f873e76f880a9132e..5b629a81cfd91775a091d266dfdd6157f743e844 100644 --- a/Code/Mantid/Framework/DataHandling/src/LoadIDFFromNexus.cpp +++ b/Code/Mantid/Framework/DataHandling/src/LoadIDFFromNexus.cpp @@ -54,6 +54,12 @@ void LoadIDFFromNexus::init() { "and 'mantid_workspace_1' for a processed nexus file. " "Only a one level path is curently supported", Direction::Input); + declareProperty("ParameterCorrectionFilePath", std::string(""), + "Full path name of Parameter Correction file. " + "This should only be used in a situation," + "where the default full file path is inconvenient.", + Direction::Input); + } /** Executes the algorithm. Reading in the file and creating and populating @@ -80,8 +86,11 @@ void LoadIDFFromNexus::exec() { localWorkspace->loadInstrumentInfoNexus(filename, &nxfile ); // Look for parameter correction file - std::string parameterCorrectionFile = getParameterCorrectionFile( localWorkspace->getInstrument()->getName() ); - g_log.notice() << "Parameter correction file: " << parameterCorrectionFile << "\n"; + std::string parameterCorrectionFile = getPropertyValue("ParameterCorrectionFilePath"); + if( parameterCorrectionFile == "") { + parameterCorrectionFile = getParameterCorrectionFile( localWorkspace->getInstrument()->getName() ); + } + g_log.debug() << "Parameter correction file: " << parameterCorrectionFile << "\n"; // Read parameter correction file, if found std::string correctionParameterFile = ""; @@ -90,11 +99,38 @@ void LoadIDFFromNexus::exec() { // Read parameter correction file // to find out which parameter file to use // and whether it is appended to default parameters. - readParameterCorrectionFile( parameterCorrectionFile, "2015-07-23 12:00:00", correctionParameterFile, append ); + g_log.notice() << "Using parameter correction file: " << parameterCorrectionFile << ".\n"; + readParameterCorrectionFile( parameterCorrectionFile, localWorkspace->getAvailableWorkspaceStartDate(), correctionParameterFile, append ); + } + + + // Load default parameters if either there is no correction parameter file or it is to be appended. + if( correctionParameterFile == "" || append ) { + LoadParameters( &nxfile, localWorkspace ); + } else { // Else clear the parameters + g_log.notice() << "Parameters to be replaced are cleared.\n"; + localWorkspace->getInstrument()->getParameterMap()->clear(); } - g_log.notice() << "Result of readParameterCorrectionFile: " << correctionParameterFile << " " << append << "\n"; - LoadParameters( &nxfile, localWorkspace ); + // Load parameters from correction parameter file, if it exists + if( correctionParameterFile != "") { + Poco::Path corrFilePath(parameterCorrectionFile); + g_log.debug() << "Correction file path: " << corrFilePath.toString() << "\n"; + Poco::Path corrDirPath = corrFilePath.parent(); + g_log.debug() << "Correction directory path: " << corrDirPath.toString() << "\n"; + Poco::Path corrParamFile( corrDirPath, correctionParameterFile ); + if(append) { + g_log.notice() << "Using correction parameter file: " << corrParamFile.toString() << " to append parameters.\n"; + } else { + g_log.notice() << "Using correction parameter file: " << corrParamFile.toString() << " to replace parameters.\n"; + } + bool ok = loadParameterFile( corrParamFile.toString(), localWorkspace ); + if(!ok) { + g_log.error() << "Unable to load parameter file " << corrParamFile.toString() << " specified in " << corrFilePath.toString() << ".\n"; + } + } else { + g_log.notice() << "No correction parameter file applies to the date for correection file.\n"; + } return; } @@ -137,12 +173,18 @@ void LoadIDFFromNexus::exec() { * @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 ) { + std::string& parameter_file, bool& append ) { // Set output arguments to default parameter_file = ""; append = false; + // Check the date. + if( date == ""){ + g_log.notice() << "No date is supplied for parameter correction file " << correction_file << ". Correction file is ignored.\n"; + return; + } + // Get contents of correction file const std::string xmlText = Kernel::Strings::loadFile(correction_file); @@ -166,6 +208,7 @@ void LoadIDFFromNexus::readParameterCorrectionFile( const std::string& correctio } // Convert date to Mantid object + g_log.notice() << "Date for correction file " << date << "\n"; DateAndTime externalDate( date ); // Examine the XML structure obtained by parsing @@ -219,24 +262,13 @@ void LoadIDFFromNexus::LoadParameters( ::NeXus::File *nxfile, const MatrixWorksp 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. "; - } + // Attempt to load specified file, if successful, use file and stop search. + if(loadParameterFile( paramFile, localWorkspace )) break; + } } else { // We do have parameters from the Nexus file g_log.notice() - << "Found Instrument parameter map entry in Nexus file, which is loaded" + << "Found Instrument parameter map entry in Nexus file, which is loaded.\n" << std::endl; // process parameterString into parameters in workspace localWorkspace->readParameterMap(parameterString); @@ -244,5 +276,26 @@ void LoadIDFFromNexus::LoadParameters( ::NeXus::File *nxfile, const MatrixWorksp } +// Private function to load parameter file specified by a full path name into given workspace, returning success. +bool LoadIDFFromNexus::loadParameterFile (const std::string& fullPathName, const MatrixWorkspace_sptr localWorkspace ) { + + try { + // load and also populate instrument parameters from this 'fallback' + // parameter file + Algorithm_sptr loadParamAlg = createChildAlgorithm("LoadParameterFile"); + loadParamAlg->setProperty("Filename", fullPathName); + loadParamAlg->setProperty("Workspace", localWorkspace); + loadParamAlg->execute(); + g_log.notice() << "Instrument parameter file: " << fullPathName + << " has been loaded.\n" << std::endl; + return true; // Success + } catch (std::runtime_error &) { + g_log.debug() << "Instrument parameter file: " << fullPathName + << " not found or un-parsable.\n"; + return false; // Failure + } +} + + } // namespace DataHandling } // namespace Mantid diff --git a/Code/Mantid/Framework/DataHandling/test/LoadIDFFromNexusTest.h b/Code/Mantid/Framework/DataHandling/test/LoadIDFFromNexusTest.h index de3acc33e991a8e6797dfee975b9dc4a3ae9accf..3e5905f233c4976a24c6b9d4ae97f33a013e1030 100644 --- a/Code/Mantid/Framework/DataHandling/test/LoadIDFFromNexusTest.h +++ b/Code/Mantid/Framework/DataHandling/test/LoadIDFFromNexusTest.h @@ -199,6 +199,160 @@ public: } + + void test_parameter_correction_file_append () { + + // We load a processed Nexus file with embedded parameters, which are corrected by + // a correction file created for this test. Append is set to true and tested. + + if ( !loader.isInitialized() ) loader.initialize(); + + //Create a workspace with some sample data and add a run with a start date + wsName = "LoadIDFFromNexusTestParameterCorrectionFileAppend"; + Workspace_sptr wsd = WorkspaceFactory::Instance().create("Workspace2D",1,1,1); + Workspace2D_sptr wsd2D = boost::dynamic_pointer_cast<Workspace2D>(wsd); + Run &runDetails = wsd2D->mutableRun(); + runDetails.addProperty("run_start", std::string("2015-08-01 12:00:00")); + + //Put this workspace in the data service + TS_ASSERT_THROWS_NOTHING(AnalysisDataService::Instance().add(wsName, wsd2D)); + + // Create correction file and a parameter file to which it refers + std::string cContents = + "<EmbeddedParameterCorrections name='XXX'>" + " <correction valid-from='2015-07-22 00:00:00' valid-to='2015-08-31 11:59:59' file='parameter_file_referred_to.xml' append='true'/>" + "</EmbeddedParameterCorrections>"; + std::string cFilename = "LOQ_parameter_correction_file_append_test.xml"; + ScopedFile cFile( cContents, cFilename); + std::string cFullFilename = cFile.getFileName(); + + std::string pContents = + "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + "<parameter-file instrument=\"LOQ\" valid-from=\"2002-02-26T09:30:00\">\n" + "\t<component-link name=\"LOQ\">\n" + "\t\t<parameter name=\"high-angle-detector-name\" type=\"string\">\n" + "\t\t\t<value val=\"HAB App\"/>\n" + "\t\t</parameter>\n" + "\t\t<parameter name=\"high-angle-detector-short-name\" type=\"string\">\n" + "\t\t\t<value val=\"HABA\"/>\n" + "\t\t</parameter>\n" + "\t</component-link>\n" + "</parameter-file>" + ; // Contents coverted to string by means of http://tomeko.net/online_tools/cpp_text_escape.php?lang=en + std::string pFilename = "parameter_file_referred_to.xml"; + ScopedFile pFile( pContents, pFilename); + std::string pFullFilename = pFile.getFileName(); + + // First we check that both scoped files are in the same directory, + // because the rest of the test relies on this. + Poco::Path cPath(cFullFilename); + Poco::Path pPath(pFullFilename); + TS_ASSERT_EQUALS(cPath.parent().toString(), pPath.parent().toString() ); + + // Set properties + loader.setPropertyValue("Workspace", wsName); + loader.setPropertyValue("Filename", "LOQ48127.nxs"); + loader.setPropertyValue("InstrumentParentPath","mantid_workspace_1"); + loader.setPropertyValue("ParameterCorrectionFilePath",cFullFilename); + inputFile = loader.getPropertyValue("Filename"); // get full pathname + + // Execute + TS_ASSERT_THROWS_NOTHING(loader.execute()); + TS_ASSERT( loader.isExecuted() ); + + // Get back the saved workspace + MatrixWorkspace_sptr output; + TS_ASSERT_THROWS_NOTHING(output = AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>(wsName)); + + // We now check a parameter that has been changed by this + const ParameterMap& paramMap = output->instrumentParameters(); + boost::shared_ptr<const Instrument> i = output->getInstrument(); + TS_ASSERT_EQUALS(paramMap.getString(i.get(), "high-angle-detector-name"), "HAB App"); + // If this gives "main-detector-bank" instead of "HAB", + // then the parementer file specified by the correction file has not been read and acted upon. + + // Also check a parameter from the embedded IDF to test the append + TS_ASSERT_EQUALS(paramMap.getString(i.get(), "low-angle-detector-name"), "main-detector-bank"); + + } + + void xtest_parameter_correction_file_replace () { // Disabled till fix of issue 13328. + + // We load a processed Nexus file with embedded parameters, which are corrected by + // a correction file created for this test. Append is set to false and tested + + if ( !loader.isInitialized() ) loader.initialize(); + + //Create a workspace with some sample data and add a run with a start date + wsName = "LoadIDFFromNexusTestParameterCorrectionFileReplace"; + Workspace_sptr wsd = WorkspaceFactory::Instance().create("Workspace2D",1,1,1); + Workspace2D_sptr wsd2D = boost::dynamic_pointer_cast<Workspace2D>(wsd); + Run &runDetails = wsd2D->mutableRun(); + runDetails.addProperty("run_start", std::string("2015-08-01 12:00:00")); + + //Put this workspace in the data service + TS_ASSERT_THROWS_NOTHING(AnalysisDataService::Instance().add(wsName, wsd2D)); + + // Create correction file and a parameter file to which it refers + std::string cContents = + "<EmbeddedParameterCorrections name='XXX'>" + " <correction valid-from='2015-07-22 00:00:00' valid-to='2015-08-31 11:59:59' file='parameter_file_referred_to.xml' append='false'/>" + "</EmbeddedParameterCorrections>"; + std::string cFilename = "LOQ_parameter_correction_file_replace_test.xml"; + ScopedFile cFile( cContents, cFilename); + std::string cFullFilename = cFile.getFileName(); + + std::string pContents = + "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + "<parameter-file instrument=\"LOQ\" valid-from=\"2002-02-26T09:30:00\">\n" + "\t<component-link name=\"LOQ\">\n" + "\t\t<parameter name=\"high-angle-detector-name\" type=\"string\">\n" + "\t\t\t<value val=\"HAB Rep\"/>\n" + "\t\t</parameter>\n" + "\t\t<parameter name=\"high-angle-detector-short-name\" type=\"string\">\n" + "\t\t\t<value val=\"HABR\"/>\n" + "\t\t</parameter>\n" + "\t</component-link>\n" + "</parameter-file>" + ; // Contents coverted to string by means of http://tomeko.net/online_tools/cpp_text_escape.php?lang=en + std::string pFilename = "parameter_file_referred_to.xml"; + ScopedFile pFile( pContents, pFilename); + std::string pFullFilename = pFile.getFileName(); + + // First we check that both scoped files are in the same directory, + // because the rest of the test relies on this. + Poco::Path cPath(cFullFilename); + Poco::Path pPath(pFullFilename); + TS_ASSERT_EQUALS(cPath.parent().toString(), pPath.parent().toString() ); + + // Set properties + loader.setPropertyValue("Workspace", wsName); + loader.setPropertyValue("Filename", "LOQ48127p.nxs"); + loader.setPropertyValue("InstrumentParentPath","mantid_workspace_1"); + loader.setPropertyValue("ParameterCorrectionFilePath",cFullFilename); + inputFile = loader.getPropertyValue("Filename"); // get full pathname + + // Execute + TS_ASSERT_THROWS_NOTHING(loader.execute()); + TS_ASSERT( loader.isExecuted() ); + + // Get back the saved workspace + MatrixWorkspace_sptr output; + TS_ASSERT_THROWS_NOTHING(output = AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>(wsName)); + + // We now check a parameter that has been changed by this + const ParameterMap& paramMap = output->instrumentParameters(); + boost::shared_ptr<const Instrument> i = output->getInstrument(); + TS_ASSERT_EQUALS(paramMap.getString(i.get(), "high-angle-detector-name"), "HAB Rep"); + // If this gives "main-detector-bank" instead of "HAB", + // then the parementer file specified by the correction file has not been read and acted upon. + + // Also check a parameter from the embedded IDF to test the append, which is false + TS_ASSERT_EQUALS(paramMap.getString(i.get(), "low-angle-detector-name"), ""); + + } + + void test_get_parameter_correction_file() { // We test the function the looks for a parameter correction file @@ -249,7 +403,6 @@ public: } - private: LoadIDFFromNexus loader; std::string inputFile; diff --git a/Code/Mantid/docs/source/algorithms/LoadIDFFromNexus-v1.rst b/Code/Mantid/docs/source/algorithms/LoadIDFFromNexus-v1.rst index c2c90b0b65ca33ee5b29c221a192aab71c6930e9..c34bccb57d62675bfaa59f44948821382d2e5ef8 100644 --- a/Code/Mantid/docs/source/algorithms/LoadIDFFromNexus-v1.rst +++ b/Code/Mantid/docs/source/algorithms/LoadIDFFromNexus-v1.rst @@ -11,12 +11,27 @@ Description Some Nexus files contain an instrument definition. This algorithm loads the instrument from this definition. You may need to tell this algorithm -where in the Nexus file to find the Instrument folder, which contains -the instrument definition. It also looks to see if it contains a separate -instrument parameter map. If yes this is loaded. If no, the algorithm will +where in the Nexus file to find the Instrument folder that contains +the instrument definition. + +It also looks to see if it contains a separate instrument parameter map. +If yes this is loaded. If no, the algorithm will attempt to load on paramter file on your disk from your instrument folder -with the name INST_Parameters.xml. Notification are displayed to information -what the algorithm does. +with the name INST_Parameters.xml. +This may be overriden by a parameter correction file, which can be +used to correct out of date embedded parameters. + +A parameter correction file contains a list of parameter files, +each with a non-overlapping date range and an append flag. +If a parameter correction file is found, +its list is compared to the workspace's run start date. +If this date occurs within one of the date ranges, the file with that date range +is used as the parameter file. +This parameter file must be in the same directory as the correction file. +If the append flag is true this parameter file is used in addition to any other parameters +that would be used, else it replaces the those parameters. + +Notifications are displayed to inform, what the algorithm is doing. Usage -----