diff --git a/Code/Mantid/Framework/API/inc/MantidAPI/HistoryView.h b/Code/Mantid/Framework/API/inc/MantidAPI/HistoryView.h index 7eaf0947a50e5ce172aacb851e3294f03f4cba04..2873c1856c4cd33c9d5ed58b4e049545ddaecaa3 100644 --- a/Code/Mantid/Framework/API/inc/MantidAPI/HistoryView.h +++ b/Code/Mantid/Framework/API/inc/MantidAPI/HistoryView.h @@ -7,6 +7,7 @@ #include "MantidAPI/DllConfig.h" #include "MantidAPI/HistoryItem.h" #include "MantidAPI/WorkspaceHistory.h" +#include "MantidKernel/DateAndTime.h" #include <list> #include <vector> @@ -55,13 +56,14 @@ public: void unrollAll(); void roll(size_t index); void rollAll(); + void filterBetweenExecDate(Mantid::Kernel::DateAndTime start, Mantid::Kernel::DateAndTime end = Mantid::Kernel::DateAndTime::getCurrentTime()); const std::vector<HistoryItem> getAlgorithmsList() const; size_t size() const { return m_historyItems.size(); } private: void unroll(std::list<HistoryItem>::iterator it); void roll(std::list<HistoryItem>::iterator it); - + const WorkspaceHistory m_wsHist; std::list<HistoryItem> m_historyItems; }; diff --git a/Code/Mantid/Framework/API/src/HistoryView.cpp b/Code/Mantid/Framework/API/src/HistoryView.cpp index 1d8e8d09bfe1279823588f1d6478d3e445436bc1..13356e963bd8e1d664aaedf809707006c80d7f13 100644 --- a/Code/Mantid/Framework/API/src/HistoryView.cpp +++ b/Code/Mantid/Framework/API/src/HistoryView.cpp @@ -24,7 +24,7 @@ HistoryView::HistoryView(const WorkspaceHistory& wsHist) /** * Unroll an algorithm history to export its child algorithms. * - * This places each of the child algorithm histories into the + * This places each of the child algorithm histories into the * HistoryView object. The parent is retained as a marker so we can * "roll" the history back up if we want. This method does nothing if * the history object has no children @@ -43,13 +43,13 @@ void HistoryView::unroll(size_t index) auto it = m_historyItems.begin(); std::advance (it,index); - unroll(it); + unroll(it); } /** * Unroll an algorithm history to export its child algorithms. * - * This places each of the child algorithm histories into the + * This places each of the child algorithm histories into the * HistoryView object. The parent is retained as a marker so we can * "roll" the history back up if we want. This method does nothing if * the history object has no children @@ -62,15 +62,15 @@ void HistoryView::unroll(std::list<HistoryItem>::iterator it) const auto childHistories = history->getChildHistories(); if (!it->isUnrolled() && childHistories.size() > 0) - { + { //mark this record as being ignored by the script builder it->unrolled(true); - + ++it; //move iterator forward to insertion position //insert each of the records, in order, at this position for (auto childIter = childHistories.begin(); childIter != childHistories.end(); ++childIter) { - HistoryItem item(*childIter); + HistoryItem item(*childIter); m_historyItems.insert(it, item); } } @@ -125,8 +125,8 @@ void HistoryView::roll(size_t index) //advance to the item at the index auto it = m_historyItems.begin(); std::advance (it,index); - - roll(it); + + roll(it); } /** @@ -145,7 +145,7 @@ void HistoryView::roll(std::list<HistoryItem>::iterator it) // the number of records after this position const size_t numChildren = it->numberOfChildren(); if (it->isUnrolled() && numChildren > 0) - { + { //mark this record as not being ignored by the script builder it->unrolled(false); ++it; //move to first child @@ -153,7 +153,7 @@ void HistoryView::roll(std::list<HistoryItem>::iterator it) //remove each of the children from the list for (size_t i = 0; i < numChildren; ++i) { - //check if our children are unrolled and + //check if our children are unrolled and //roll them back up if so. if(it->isUnrolled()) { @@ -165,6 +165,31 @@ void HistoryView::roll(std::list<HistoryItem>::iterator it) } } +/** + * Filter the list of history items to remove any anlgorithms whos start + * time is outside of the given range. + * + * @param start Start of time range + * @param end End of time range + */ +void HistoryView::filterBetweenExecDate(Mantid::Kernel::DateAndTime start, Mantid::Kernel::DateAndTime end) +{ + for(auto it = m_historyItems.begin(); it != m_historyItems.end();) + { + Mantid::Kernel::DateAndTime algExecutionDate = it->getAlgorithmHistory()->executionDate(); + + // If the algorithm is outside of the time range, remove it and keep iterating + if(algExecutionDate < start || algExecutionDate > end) + { + it = m_historyItems.erase(it); + } + else + { + ++it; + } + } +} + /** * Get the list of History Items for this view. * diff --git a/Code/Mantid/Framework/API/src/WorkspaceHistory.cpp b/Code/Mantid/Framework/API/src/WorkspaceHistory.cpp index 0cc4528b5822d76986bad11360a70b21f53e907f..20ae8b904f75824b67d1e89fed9f34351f7d3b58 100644 --- a/Code/Mantid/Framework/API/src/WorkspaceHistory.cpp +++ b/Code/Mantid/Framework/API/src/WorkspaceHistory.cpp @@ -276,11 +276,11 @@ void WorkspaceHistory::loadNexus(::NeXus::File * file) } /** Load every algorithm history object at this point in the hierarchy. - * This method will recurse over every algorithm entry in the nexus file and + * This method will recurse over every algorithm entry in the nexus file and * load both the record and its children. - * + * * @param file :: The handle to the nexus file - * @param parent :: Pointer to the parent AlgorithmHistory object. If null then loaded histories are added to + * @param parent :: Pointer to the parent AlgorithmHistory object. If null then loaded histories are added to * the workspace history. */ void WorkspaceHistory::loadNestedHistory(::NeXus::File * file, AlgorithmHistory_sptr parent) @@ -293,9 +293,9 @@ void WorkspaceHistory::loadNestedHistory(::NeXus::File * file, AlgorithmHistory_ std::string rawData; file->openGroup(entryName, "NXnote"); file->readData("data", rawData); - + try - { + { AlgorithmHistory_sptr history = parseAlgorithmHistory(rawData); loadNestedHistory(file, history); if(parent) @@ -305,7 +305,7 @@ void WorkspaceHistory::loadNestedHistory(::NeXus::File * file, AlgorithmHistory_ else { //if not parent point is supplied, assume we're at the top - //and attach the history to the workspace + //and attach the history to the workspace this->addHistory(history); } } @@ -320,7 +320,7 @@ void WorkspaceHistory::loadNestedHistory(::NeXus::File * file, AlgorithmHistory_ } -/** Find all the algorithm entries at a particular point the the nexus file +/** Find all the algorithm entries at a particular point the the nexus file * @param file :: The handle to the nexus file * @returns set of integers. One for each algorithm at the level in the file. */ @@ -431,7 +431,7 @@ AlgorithmHistory_sptr WorkspaceHistory::parseAlgorithmHistory(const std::string& unsigned int direc(Mantid::Kernel::Direction::asEnum(direction)); alg_hist.addProperty(prop_name, prop_value, (is_def[0] == 'Y'), direc); } - + AlgorithmHistory_sptr history = boost::make_shared<AlgorithmHistory>(alg_hist); return history; } @@ -441,7 +441,7 @@ AlgorithmHistory_sptr WorkspaceHistory::parseAlgorithmHistory(const std::string& */ boost::shared_ptr<HistoryView> WorkspaceHistory::createView() const { - return boost::make_shared<HistoryView>(*this); + return boost::make_shared<HistoryView>(*this); } diff --git a/Code/Mantid/Framework/API/test/HistoryViewTest.h b/Code/Mantid/Framework/API/test/HistoryViewTest.h index b0947d9be7d1835b9513bd51fb75bb645f12533c..ff93c52b0a7ed1e9c47e78aeabe5463c956ec30e 100644 --- a/Code/Mantid/Framework/API/test/HistoryViewTest.h +++ b/Code/Mantid/Framework/API/test/HistoryViewTest.h @@ -7,6 +7,7 @@ using namespace Mantid::API; using namespace Mantid::Kernel; +using Mantid::Kernel::DateAndTime; class HistoryViewTest : public CxxTest::TestSuite @@ -25,45 +26,44 @@ class HistoryViewTest : public CxxTest::TestSuite void init() { - declareProperty("name","",Direction::Input); + declareProperty("name", "", Direction::Input); } + void exec() {} }; private: - AlgorithmHistory_sptr createFromTestAlg(const std::string& name ) - { + AlgorithmHistory_sptr createFromTestAlg(const std::string& name, DateAndTime execTime = DateAndTime::defaultTime()) + { testalg alg; alg.initialize(); alg.setPropertyValue("name", name); alg.execute(); - Mantid::Kernel::DateAndTime execTime = Mantid::Kernel::DateAndTime::defaultTime(); - AlgorithmHistory history(&alg, execTime, 14.0, m_execCount++); return boost::make_shared<AlgorithmHistory>(history); } - + public: HistoryViewTest() : m_wsHist(), m_execCount(0) { //create dummy history structure - auto alg1 = createFromTestAlg("alg1"); - auto child1 = createFromTestAlg("child1"); + auto alg1 = createFromTestAlg("alg1", DateAndTime(100, 0)); + auto child1 = createFromTestAlg("child1", DateAndTime(110, 0)); alg1->addChildHistory(child1); - - auto alg2 = createFromTestAlg("alg2"); - auto child2 = createFromTestAlg("child2"); - - auto subChild21 = createFromTestAlg("subChild21"); - auto subChild22 = createFromTestAlg("subChild22"); - + + auto alg2 = createFromTestAlg("alg2", DateAndTime(200, 0)); + auto child2 = createFromTestAlg("child2", DateAndTime(210, 0)); + + auto subChild21 = createFromTestAlg("subChild21", DateAndTime(211, 0)); + auto subChild22 = createFromTestAlg("subChild22", DateAndTime(212, 0)); + child2->addChildHistory(subChild21); child2->addChildHistory(subChild22); alg2->addChildHistory(child2); - - auto alg3 = createFromTestAlg("alg3"); + + auto alg3 = createFromTestAlg("alg3", DateAndTime(300, 0)); m_wsHist.addHistory(alg1); m_wsHist.addHistory(alg2); @@ -92,7 +92,6 @@ public: auto props = history->getProperties(); TS_ASSERT_EQUALS(props[0]->value(), "alg" + boost::lexical_cast<std::string>(i+1) ); } - } void test_Unroll_History() @@ -100,7 +99,7 @@ public: HistoryView view(m_wsHist); //unroll alg 2 TS_ASSERT_THROWS_NOTHING( view.unroll(0) ); - TS_ASSERT_EQUALS(view.size(), 4); + TS_ASSERT_EQUALS(view.size(), 4); auto items = view.getAlgorithmsList(); TS_ASSERT_EQUALS(items.size(), 4); @@ -110,7 +109,7 @@ public: { propNames[i] = items[i].getAlgorithmHistory()->getProperties()[0]->value(); } - + TS_ASSERT_EQUALS(propNames[0], "alg1") TS_ASSERT_EQUALS(propNames[1], "child1") TS_ASSERT_EQUALS(propNames[2], "alg2") @@ -124,7 +123,7 @@ public: //unroll alg 2 TS_ASSERT_THROWS_NOTHING( view.unroll(0) ); - + TS_ASSERT_EQUALS(view.size(), 4); auto items = view.getAlgorithmsList(); TS_ASSERT_EQUALS(items.size(), 4); @@ -134,7 +133,7 @@ public: { propNames[i] = items[i].getAlgorithmHistory()->getProperties()[0]->value(); } - + //check it unrolled properly TS_ASSERT_EQUALS(propNames[0], "alg1") TS_ASSERT_EQUALS(propNames[1], "child1") @@ -165,7 +164,7 @@ public: { //tests the case where we have multiple layers of history unrolled HistoryView view(m_wsHist); - + //unroll alg2 TS_ASSERT_THROWS_NOTHING( view.unroll(1) ); @@ -207,7 +206,7 @@ public: //now roll everything back up to the top level TS_ASSERT_THROWS_NOTHING( view.roll(1) ) - + TS_ASSERT_EQUALS(view.size(), 3); items = view.getAlgorithmsList(); TS_ASSERT_EQUALS(items.size(), 3); @@ -227,7 +226,7 @@ public: void test_Unroll_All() { HistoryView view(m_wsHist); - + TS_ASSERT_THROWS_NOTHING( view.unrollAll() ); TS_ASSERT_EQUALS(view.size(), 7); @@ -252,13 +251,13 @@ public: void test_Roll_All() { HistoryView view(m_wsHist); - + TS_ASSERT_THROWS_NOTHING( view.unrollAll() ); TS_ASSERT_EQUALS(view.size(), 7); auto items = view.getAlgorithmsList(); TS_ASSERT_EQUALS(items.size(), 7); - + std::vector<std::string> propNames(items.size()); for (size_t i=0;i<items.size();++i) { @@ -292,6 +291,62 @@ public: TS_ASSERT_THROWS_ANYTHING ( view.roll(3) ); } + void test_Filter_By_Exec_Time_Full_Range() + { + HistoryView view(m_wsHist); + + // Unroll to get all algorithms + TS_ASSERT_THROWS_NOTHING( view.unrollAll() ); + TS_ASSERT_EQUALS(view.size(), 7); + + // Filter by time with a start and end time + TS_ASSERT_THROWS_NOTHING( view.filterBetweenExecDate(DateAndTime(200, 0), DateAndTime(211, 0)) ); + TS_ASSERT_EQUALS(view.size(), 3); + + // Get algorithm list and compare results + auto items = view.getAlgorithmsList(); + TS_ASSERT_EQUALS(items.size(), 3); + + std::vector<std::string> propNames(items.size()); + for (size_t i=0;i<items.size();++i) + { + propNames[i] = items[i].getAlgorithmHistory()->getProperties()[0]->value(); + } + + TS_ASSERT_EQUALS(propNames[0], "alg2") + TS_ASSERT_EQUALS(propNames[1], "child2") + TS_ASSERT_EQUALS(propNames[2], "subChild21") + } + + void test_Filter_By_Exec_Time_Start_Only() + { + HistoryView view(m_wsHist); + + // Unroll to get all algorithms + TS_ASSERT_THROWS_NOTHING( view.unrollAll() ); + TS_ASSERT_EQUALS(view.size(), 7); + + // Filter by time with a start time only + TS_ASSERT_THROWS_NOTHING( view.filterBetweenExecDate(DateAndTime(200, 0)) ); + TS_ASSERT_EQUALS(view.size(), 5); + + // Get algorithm list and compare results + auto items = view.getAlgorithmsList(); + TS_ASSERT_EQUALS(items.size(), 5); + + std::vector<std::string> propNames(items.size()); + for (size_t i=0;i<items.size();++i) + { + propNames[i] = items[i].getAlgorithmHistory()->getProperties()[0]->value(); + } + + TS_ASSERT_EQUALS(propNames[0], "alg2") + TS_ASSERT_EQUALS(propNames[1], "child2") + TS_ASSERT_EQUALS(propNames[2], "subChild21") + TS_ASSERT_EQUALS(propNames[3], "subChild22") + TS_ASSERT_EQUALS(propNames[4], "alg3") + } + WorkspaceHistory m_wsHist; size_t m_execCount; diff --git a/Code/Mantid/Framework/Algorithms/src/GeneratePythonScript.cpp b/Code/Mantid/Framework/Algorithms/src/GeneratePythonScript.cpp index 475f479792d49dc587ef313c4b4d7655035e259d..a66d07d8684502fb934d98fa9b7075968084ea56 100644 --- a/Code/Mantid/Framework/Algorithms/src/GeneratePythonScript.cpp +++ b/Code/Mantid/Framework/Algorithms/src/GeneratePythonScript.cpp @@ -26,22 +26,25 @@ DECLARE_ALGORITHM(GeneratePythonScript) */ void GeneratePythonScript::init() { - declareProperty(new WorkspaceProperty<Workspace>("InputWorkspace","",Direction::Input), "An input workspace."); + declareProperty(new WorkspaceProperty<Workspace>("InputWorkspace", "", Direction::Input), "An input workspace."); std::vector<std::string> exts; exts.push_back(".py"); - declareProperty(new API::FileProperty("Filename","", API::FileProperty::OptionalSave, exts), + declareProperty(new API::FileProperty("Filename", "", API::FileProperty::OptionalSave, exts), "The name of the file into which the workspace history will be generated."); declareProperty("ScriptText", std::string(""), "Saves the history of the workspace to a variable.", Direction::Output); declareProperty("UnrollAll", false, "Unroll all algorithms to show just their child algorithms.", Direction::Input); + declareProperty("StartTimestamp", std::string(""), "The filter start time in the format YYYY-MM-DD HH:mm:ss", Direction::Input); + declareProperty("EndTimestamp", std::string(""), "The filter end time in the format YYYY-MM-DD HH:mm:ss", Direction::Input); + std::vector<std::string> saveVersions; saveVersions.push_back("Specify Old"); saveVersions.push_back("Specify All"); saveVersions.push_back("Specify None"); - declareProperty("SpecifyAlgorithmVersions","Specify Old",boost::make_shared<StringListValidator>(saveVersions), + declareProperty("SpecifyAlgorithmVersions", "Specify Old", boost::make_shared<StringListValidator>(saveVersions), "When to specify which algorithm version was used by Mantid."); } @@ -52,6 +55,8 @@ void GeneratePythonScript::exec() { const Workspace_const_sptr ws = getProperty("InputWorkspace"); const bool unrollAll = getProperty("UnrollAll"); + const std::string startTime = getProperty("StartTimestamp"); + const std::string endTime = getProperty("EndTimestamp"); const std::string saveVersions = getProperty("SpecifyAlgorithmVersions"); // Get the algorithm histories of the workspace. @@ -64,6 +69,20 @@ void GeneratePythonScript::exec() view->unrollAll(); } + // Need at least a start time to do time filter + if(startTime != "") + { + if(endTime == "") + { + // If no end time was given then filter up to now + view->filterBetweenExecDate(DateAndTime(startTime)); + } + else + { + view->filterBetweenExecDate(DateAndTime(startTime), DateAndTime(endTime)); + } + } + std::string versionSpecificity; if(saveVersions == "Specify Old") versionSpecificity = "old"; diff --git a/Code/Mantid/docs/source/algorithms/GeneratePythonScript-v1.rst b/Code/Mantid/docs/source/algorithms/GeneratePythonScript-v1.rst index ce804c7410ca66f6c1fffdc0e15272b52b66d7c5..a65f4d025222989453a7d1b712a66359d5deacc4 100644 --- a/Code/Mantid/docs/source/algorithms/GeneratePythonScript-v1.rst +++ b/Code/Mantid/docs/source/algorithms/GeneratePythonScript-v1.rst @@ -12,6 +12,14 @@ Description Retrieves the algorithm history of the workspace and saves it to a Python script file or Python variable. +A time range can be specified which will restrict the algorithms in +the scrit to those which were executed between the given times, +if no end time was specified then algorithms from the start time up +to the current time will be included in the generated script. + +Start and end times are given in ISO8601 format: YYYY-MM-DD HH:mm:ss, +for example 3:25 PM on July the 4th 2014 would be 2014-07-04 15:25:00. + Usage ----- @@ -53,6 +61,51 @@ Output: removeFiles(['myscript.py']) +**Example - generate a python script giving a range of start times:** + +.. testcode:: ExGeneratePythonScriptWithTimeRanges + + import time + + # Do some operations on the workspace with a pause between them + ws = CreateSampleWorkspace() + ws = CropWorkspace(ws, XMin=7828.162291, XMax=11980.906921) + time.sleep(2) + ws = Power(ws, Exponent=1.5) + ws = RenameWorkspace(ws, OutputWorkspace="MyTestWorkspace") + + # Get the execution time of the last algorithm and subtract 1 second + history = mtd['MyTestWorkspace'].getHistory() + last = history.getAlgorithmHistory(history.size() - 1) + from_time = last.executionDate() - int(1e9) + + # Generate a script with a given start time + script_text = GeneratePythonScript(ws, StartTimestamp=str(from_time)) + print script_text.strip() + +Output: + +.. testoutput:: ExGeneratePythonScriptWithTimeRanges + + ###################################################################### + #Python Script Generated by GeneratePythonScript Algorithm + ###################################################################### + Power(InputWorkspace='ws', OutputWorkspace='ws', Exponent=1.5) + RenameWorkspace(InputWorkspace='ws', OutputWorkspace='MyTestWorkspace') + +.. testcleanup:: ExGeneratePythonScriptWithTimeRanges + + import os + def removeFiles(files): + for ws in files: + try: + path = os.path.join(os.path.expanduser("~"), ws) + os.remove(path) + except: + pass + + removeFiles(['myscript.py']) + **Example - generate a python script and save it to file:**