diff --git a/.clang-format b/.clang-format new file mode 100644 index 000000000000..5bead5f39dd3 --- /dev/null +++ b/.clang-format @@ -0,0 +1,2 @@ +BasedOnStyle: LLVM + diff --git a/Code/Mantid/Build/CMake/DarwinSetup.cmake b/Code/Mantid/Build/CMake/DarwinSetup.cmake index d26ddce540ee..6a6a88f3af7a 100644 --- a/Code/Mantid/Build/CMake/DarwinSetup.cmake +++ b/Code/Mantid/Build/CMake/DarwinSetup.cmake @@ -159,6 +159,8 @@ file ( GLOB THIRDPARTY_PYTHON_PACKAGES ${CMAKE_LIBRARY_PATH}/Python/* ) foreach ( PYPACKAGE ${THIRDPARTY_PYTHON_PACKAGES} ) if ( IS_DIRECTORY ${PYPACKAGE} ) install ( DIRECTORY ${PYPACKAGE} DESTINATION ${BIN_DIR} ) + else() + install ( FILES ${PYPACKAGE} DESTINATION ${BIN_DIR} ) endif() file ( COPY ${PYPACKAGE} DESTINATION ${PROJECT_BINARY_DIR}/bin ) endforeach( PYPACKAGE ) diff --git a/Code/Mantid/Framework/API/src/Algorithm.cpp b/Code/Mantid/Framework/API/src/Algorithm.cpp index ecf8ed2f07ba..f7cec91dc0fe 100644 --- a/Code/Mantid/Framework/API/src/Algorithm.cpp +++ b/Code/Mantid/Framework/API/src/Algorithm.cpp @@ -523,30 +523,55 @@ namespace Mantid } } + // ----- Check for processing groups ------------- + // default true so that it has the right value at the check below the catch block should checkGroups throw + bool callProcessGroups = true; + try + { + // Checking the input is a group. Throws if the sizes are wrong + callProcessGroups = this->checkGroups(); + } + catch(std::exception& ex) + { + getLogger().error() << "Error in execution of algorithm "<< this->name() << "\n" + << ex.what() << "\n"; + notificationCenter().postNotification(new ErrorNotification(this,ex.what())); + m_running = false; + if (m_isChildAlgorithm || m_runningAsync || m_rethrow) + { + m_runningAsync = false; + throw; + } + return false; + } + // ----- Perform validation of the whole set of properties ------------- - std::map errors = this->validateInputs(); - if (!errors.empty()) + if (!callProcessGroups) // for groups this is called on each workspace separately { - size_t numErrors = errors.size(); - // Log each issue - auto & errorLog = getLogger().error(); - auto & warnLog = getLogger().warning(); - for (auto it = errors.begin(); it != errors.end(); it++) + std::map errors = this->validateInputs(); + if (!errors.empty()) { - if (this->existsProperty(it->first)) - errorLog << "Invalid value for " << it->first << ": " << it->second << "\n"; - else + size_t numErrors = errors.size(); + // Log each issue + auto & errorLog = getLogger().error(); + auto & warnLog = getLogger().warning(); + for (auto it = errors.begin(); it != errors.end(); it++) { - numErrors -= 1; // don't count it as an error - warnLog << "validateInputs() references non-existant property \"" - << it->first << "\"\n"; + if (this->existsProperty(it->first)) + errorLog << "Invalid value for " << it->first << ": " << it->second << "\n"; + else + { + numErrors -= 1; // don't count it as an error + warnLog << "validateInputs() references non-existant property \"" + << it->first << "\"\n"; + } + } + // Throw because something was invalid + if (numErrors > 0) + { + notificationCenter().postNotification(new ErrorNotification(this,"Some invalid Properties found")); + throw std::runtime_error("Some invalid Properties found"); } - } - // Throw because something was invalid - if (numErrors > 0) - { - notificationCenter().postNotification(new ErrorNotification(this,"Some invalid Properties found")); - throw std::runtime_error("Some invalid Properties found"); } } @@ -562,50 +587,29 @@ namespace Mantid m_history = boost::make_shared(algHist); } - // ----- Check for processing groups ------------- - // default true so that it has the right value at the check below the catch block should checkGroups throw - bool callProcessGroups = true; - try - { - // Checking the input is a group. Throws if the sizes are wrong - callProcessGroups = this->checkGroups(); - if (callProcessGroups) - { - // This calls this->execute() again on each member of the group. - start_time = Mantid::Kernel::DateAndTime::getCurrentTime(); - // Start a timer - Timer timer; - // Call the concrete algorithm's exec method - const bool completed = processGroups(); - // Check for a cancellation request in case the concrete algorithm doesn't - interruption_point(); - // Get how long this algorithm took to run - const float duration = timer.elapsed(); - - if(completed) - { - // Log that execution has completed. - reportCompleted(duration, true/*indicat that this is for group processing*/); - } - return completed; - } - } - catch(std::exception& ex) + // ----- Process groups ------------- + // If checkGroups() threw an exception but there ARE group workspaces + // (means that the group sizes were incompatible) + if (callProcessGroups) { - getLogger().error() << "Error in execution of algorithm "<< this->name() << std::endl - << ex.what()<execute() again on each member of the group. + start_time = Mantid::Kernel::DateAndTime::getCurrentTime(); + // Start a timer + Timer timer; + // Call the concrete algorithm's exec method + const bool completed = processGroups(); + // Check for a cancellation request in case the concrete algorithm doesn't + interruption_point(); + // Get how long this algorithm took to run + const float duration = timer.elapsed(); + + if(completed) { - m_runningAsync = false; - throw; + // Log that execution has completed. + reportCompleted(duration, true/*indicat that this is for group processing*/); } + return completed; } - // If checkGroups() threw an exception but there ARE group workspaces - // (means that the group sizes were incompatible) - if (callProcessGroups) - return false; // Read or write locks every input/output workspace this->lockWorkspaces(); diff --git a/Code/Mantid/Framework/Algorithms/CMakeLists.txt b/Code/Mantid/Framework/Algorithms/CMakeLists.txt index a448a3324258..e292a623c7f8 100644 --- a/Code/Mantid/Framework/Algorithms/CMakeLists.txt +++ b/Code/Mantid/Framework/Algorithms/CMakeLists.txt @@ -54,6 +54,7 @@ set ( SRC_FILES src/CopyInstrumentParameters.cpp src/CopyLogs.cpp src/CopySample.cpp + src/CorelliCrossCorrelate.cpp src/CorrectFlightPaths.cpp src/CorrectKiKf.cpp src/CorrectToFile.cpp @@ -302,6 +303,7 @@ set ( INC_FILES inc/MantidAlgorithms/CopyInstrumentParameters.h inc/MantidAlgorithms/CopyLogs.h inc/MantidAlgorithms/CopySample.h + inc/MantidAlgorithms/CorelliCrossCorrelate.h inc/MantidAlgorithms/CorrectFlightPaths.h inc/MantidAlgorithms/CorrectKiKf.h inc/MantidAlgorithms/CorrectToFile.h @@ -562,6 +564,7 @@ set ( TEST_FILES CopyInstrumentParametersTest.h CopyLogsTest.h CopySampleTest.h + CorelliCrossCorrelateTest.h CorrectFlightPathsTest.h CorrectKiKfTest.h CorrectToFileTest.h diff --git a/Code/Mantid/Framework/Algorithms/inc/MantidAlgorithms/CorelliCrossCorrelate.h b/Code/Mantid/Framework/Algorithms/inc/MantidAlgorithms/CorelliCrossCorrelate.h new file mode 100644 index 000000000000..af9975c5aa99 --- /dev/null +++ b/Code/Mantid/Framework/Algorithms/inc/MantidAlgorithms/CorelliCrossCorrelate.h @@ -0,0 +1,59 @@ +#ifndef MANTID_ALGORITHMS_CORELLICROSSCORRELATE_H_ +#define MANTID_ALGORITHMS_CORELLICROSSCORRELATE_H_ + +#include "MantidKernel/System.h" +#include "MantidAPI/Algorithm.h" +#include "MantidDataObjects/EventWorkspace.h" + +namespace Mantid { +namespace Algorithms { + +/** CorelliCrossCorrelate : TODO: DESCRIPTION + + Copyright © 2014 ISIS Rutherford Appleton Laboratory & NScD Oak Ridge + National Laboratory + + This file is part of Mantid. + + Mantid is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + Mantid is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + File change history is stored at: + Code Documentation is available at: +*/ +class DLLExport CorelliCrossCorrelate : public API::Algorithm { +public: + CorelliCrossCorrelate(); + virtual ~CorelliCrossCorrelate(); + + virtual const std::string name() const { return "CorelliCrossCorrelate"; }; + virtual int version() const { return 1; }; + virtual const std::string category() const { return "Diffraction;Events"; }; + virtual const std::string summary() const { + return "Cross-correlation calculation for the elastic signal from Corelli."; + }; + +private: + std::map validateInputs(); + void init(); + void exec(); + + /// Input workspace + DataObjects::EventWorkspace_const_sptr inputWS; + DataObjects::EventWorkspace_sptr outputWS; +}; + +} // namespace Algorithms +} // namespace Mantid + +#endif /* MANTID_ALGORITHMS_CORELLICROSSCORRELATE_H_ */ diff --git a/Code/Mantid/Framework/Algorithms/src/CorelliCrossCorrelate.cpp b/Code/Mantid/Framework/Algorithms/src/CorelliCrossCorrelate.cpp new file mode 100644 index 000000000000..71ef6d998893 --- /dev/null +++ b/Code/Mantid/Framework/Algorithms/src/CorelliCrossCorrelate.cpp @@ -0,0 +1,280 @@ +#include "MantidAlgorithms/CorelliCrossCorrelate.h" +#include "MantidDataObjects/EventWorkspace.h" +#include "MantidAPI/WorkspaceValidators.h" +#include "MantidGeometry/IComponent.h" +#include "MantidKernel/MandatoryValidator.h" +#include "MantidKernel/TimeSeriesProperty.h" +#include "MantidGeometry/muParser_Silent.h" + +namespace Mantid { +namespace Algorithms { + +using namespace Kernel; +using namespace API; +using namespace Geometry; +using namespace DataObjects; + +// Register the algorithm into the AlgorithmFactory +DECLARE_ALGORITHM(CorelliCrossCorrelate) + +//---------------------------------------------------------------------------------------------- +/** Constructor + */ +CorelliCrossCorrelate::CorelliCrossCorrelate() {} + +//---------------------------------------------------------------------------------------------- +/** Destructor + */ +CorelliCrossCorrelate::~CorelliCrossCorrelate() {} + +//---------------------------------------------------------------------------------------------- +/** Initialize the algorithm's properties. + */ +void CorelliCrossCorrelate::init() { + auto wsValidator = boost::make_shared(); + wsValidator->add("TOF"); + wsValidator->add(); + + declareProperty(new WorkspaceProperty( + "InputWorkspace", "", Direction::Input, wsValidator), + "An input workspace."); + declareProperty(new WorkspaceProperty("OutputWorkspace", "", + Direction::Output), + "An output workspace."); + + declareProperty("TimingOffset", EMPTY_INT(), + boost::make_shared>(), + "Correlation chopper TDC timing offset in nanoseconds."); +} + +// Validate inputs workspace first. +std::map CorelliCrossCorrelate::validateInputs() { + std::map errors; + + inputWS = getProperty("InputWorkspace"); + + // check for null pointers - this is to protect against workspace groups + if (!inputWS) { + return errors; + } + + // This algorithm will only work for CORELLI, check for CORELLI. + if (inputWS->getInstrument()->getName() != "CORELLI") + errors["InputWorkspace"] = "This Algorithm will only work for Corelli."; + + // Must include the correlation-chopper in the IDF. + else if (!inputWS->getInstrument()->getComponentByName("correlation-chopper")) + errors["InputWorkspace"] = "Correlation chopper not found."; + + // The chopper must have a sequence parameter + else if (inputWS->getInstrument() + ->getComponentByName("correlation-chopper") + ->getStringParameter("sequence") + .empty()) + errors["InputWorkspace"] = + "Found the correlation chopper but no chopper sequence?"; + + // Check for the sample and source. + else if (!inputWS->getInstrument()->getSource() || + !inputWS->getInstrument()->getSample()) + errors["InputWorkspace"] = "Instrument not sufficiently defined: failed to " + "get source and/or sample"; + + // Must include the chopper4 TDCs. + else if (!inputWS->run().hasProperty("chopper4_TDC")) + errors["InputWorkspace"] = "Workspace is missing chopper4 TDCs."; + + // Check if input workspace is sorted. + else if (inputWS->getSortType() == UNSORTED) + errors["InputWorkspace"] = "The workspace needs to be a sorted."; + + // Check event type for pulse times + else if (inputWS->getEventType() == WEIGHTED_NOTIME) + errors["InputWorkspace"] = "This workspace has no pulse time information."; + + return errors; +} + +//---------------------------------------------------------------------------------------------- +/** Execute the algorithm. + */ +void CorelliCrossCorrelate::exec() { + inputWS = getProperty("InputWorkspace"); + outputWS = getProperty("OutputWorkspace"); + + if (outputWS != inputWS) { + // Make a brand new EventWorkspace + outputWS = boost::dynamic_pointer_cast( + API::WorkspaceFactory::Instance().create( + "EventWorkspace", inputWS->getNumberHistograms(), 2, 1)); + // Copy geometry over. + API::WorkspaceFactory::Instance().initializeFromParent(inputWS, outputWS, + false); + // You need to copy over the data as well. + outputWS->copyDataFrom((*inputWS)); + } + + // Read in chopper sequence from IDF. + // Chopper sequence, alternating between open and closed. If index%2==0 than + // absorbing else transparent. + IComponent_const_sptr chopper = + inputWS->getInstrument()->getComponentByName("correlation-chopper"); + std::vector chopperSequence = + chopper->getStringParameter("sequence"); + g_log.information("Found chopper sequence: " + chopperSequence[0]); + + std::vector chopperSequenceSplit; + boost::split(chopperSequenceSplit, chopperSequence[0], boost::is_space()); + + std::vector sequence; + sequence.resize(chopperSequenceSplit.size()); + sequence[0] = boost::lexical_cast(chopperSequenceSplit[0]); + + // Need the cumulative sum of the chopper sequence and total transparent + double totalOpen = 0; + for (unsigned int i = 1; i < chopperSequenceSplit.size(); i++) { + double seqAngle = boost::lexical_cast(chopperSequenceSplit[i]); + sequence[i] = sequence[i - 1] + seqAngle; + if (i % 2 == 1) + totalOpen += seqAngle; + } + + // Calculate the duty cycle and the event weights from the duty cycle. + double dutyCycle = totalOpen / sequence.back(); + float weightTransparent = static_cast(1.0 / dutyCycle); + float weightAbsorbing = static_cast(-1.0 / (1.0 - dutyCycle)); + g_log.information() << "dutyCycle = " << dutyCycle + << " weightTransparent = " << weightTransparent + << " weightAbsorbing = " << weightAbsorbing << "\n"; + + // Read in the TDC timings for the correlation chopper and apply the timing + // offset. + std::vector tdc = + dynamic_cast( + inputWS->run().getLogData("chopper4_TDC"))->timesAsVector(); + int offset_int = getProperty("TimingOffset"); + const int64_t offset = static_cast(offset_int); + for (unsigned long i = 0; i < tdc.size(); ++i) + tdc[i] += offset; + + // Determine period from TDC. + double period = static_cast(tdc[tdc.size() - 1].totalNanoseconds() - + tdc[1].totalNanoseconds()) / + double(tdc.size() - 2); + g_log.information() << "Frequency = " << 1e9 / period + << "Hz Period = " << period << "ns\n"; + + // Get the sample and source, calculate distances. + IComponent_const_sptr sample = inputWS->getInstrument()->getSample(); + const double distanceChopperToSource = + inputWS->getInstrument()->getSource()->getDistance(*chopper); + const double distanceSourceToSample = + inputWS->getInstrument()->getSource()->getDistance(*sample); + + // extract formula from instrument parameters + std::vector t0_formula = + inputWS->getInstrument()->getStringParameter("t0_formula"); + if (t0_formula.empty()) + throw Exception::InstrumentDefinitionError( + "Unable to retrieve t0_formula among instrument parameters"); + std::string formula = t0_formula[0]; + g_log.debug() << formula << "\n"; + + const double m_convfactor = 0.5e+12 * Mantid::PhysicalConstants::NeutronMass / + Mantid::PhysicalConstants::meV; + + // Do the cross correlation. + int64_t numHistograms = static_cast(inputWS->getNumberHistograms()); + g_log.notice("Start cross-correlation\n"); + API::Progress prog = API::Progress(this, 0.0, 1.0, numHistograms); + PARALLEL_FOR1(outputWS) + for (int64_t i = 0; i < numHistograms; ++i) { + PARALLEL_START_INTERUPT_REGION + + EventList *evlist = outputWS->getEventListPtr(i); + IDetector_const_sptr detector = inputWS->getDetector(i); + + switch (evlist->getEventType()) { + case TOF: + // Switch to weights if needed. + evlist->switchTo(WEIGHTED); + /* no break */ + // Fall through + case WEIGHTED: + break; + case WEIGHTED_NOTIME: + // Should never get here + throw std::runtime_error( + "This event list has no pulse time information."); + break; + } + + std::vector &events = evlist->getWeightedEvents(); + + // Skip if empty. + if (events.empty()) + continue; + + // Check for duplicate pulse problem in Corelli. + DateAndTime emptyTime; + if (events.back().pulseTime() == emptyTime) + throw std::runtime_error( + "Missing pulse times on events. This will not work."); + + // Scale for elastic scattering. + double distanceSourceToDetector = + distanceSourceToSample + detector->getDistance(*sample); + double tofScale = distanceChopperToSource / distanceSourceToDetector; + + double E1; + mu::Parser parser; + parser.DefineVar("incidentEnergy", + &E1); // associate variable E1 to this parser + parser.SetExpr(formula); + + uint64_t tdc_i = 0; + std::vector::iterator it; + for (it = events.begin(); it != events.end(); ++it) { + double tof = it->tof(); + E1 = m_convfactor * (distanceSourceToDetector / tof) * + (distanceSourceToDetector / tof); + double t0 = parser.Eval(); + + DateAndTime tofTime = + it->pulseTime() + + static_cast(((tof - t0) * tofScale + t0) * 1000.); + while (tdc_i != tdc.size() && tofTime > tdc[tdc_i]) + tdc_i += 1; + + double angle = 360. * + static_cast(tofTime.totalNanoseconds() - + tdc[tdc_i - 1].totalNanoseconds()) / + period; + + std::vector::iterator location; + location = std::lower_bound(sequence.begin(), sequence.end(), angle); + + if ((location - sequence.begin()) % 2 == 0) { + it->m_weight *= weightAbsorbing; + it->m_errorSquared *= weightAbsorbing * weightAbsorbing; + } else { + it->m_weight *= weightTransparent; + it->m_errorSquared *= weightTransparent * weightTransparent; + } + } + + // Warn if the tdc signal has stopped during the run + if ((events.back().pulseTime() + + static_cast(events.back().tof() * 1000.)) > + (tdc.back() + static_cast(period * 2))) + g_log.warning("Events occurred long after last TDC."); + + prog.report(); + PARALLEL_END_INTERUPT_REGION + } + PARALLEL_CHECK_INTERUPT_REGION + setProperty("OutputWorkspace", outputWS); +} + +} // namespace Algorithms +} // namespace Mantid diff --git a/Code/Mantid/Framework/Algorithms/src/EditInstrumentGeometry.cpp b/Code/Mantid/Framework/Algorithms/src/EditInstrumentGeometry.cpp index 58c88f2d4dec..5f5c4c974fe0 100644 --- a/Code/Mantid/Framework/Algorithms/src/EditInstrumentGeometry.cpp +++ b/Code/Mantid/Framework/Algorithms/src/EditInstrumentGeometry.cpp @@ -113,14 +113,28 @@ namespace Algorithms // everything depends on being parallel to the workspace # histo size_t numHist(0); + bool hasWorkspacePtr(false); { MatrixWorkspace_const_sptr workspace = getProperty("Workspace"); - numHist = workspace->getNumberHistograms(); + // this is to guard against WorkspaceGroups + // fallthrough is to skip workspace check and make sure + if (bool(workspace)) { + hasWorkspacePtr = true; + numHist = workspace->getNumberHistograms(); + } } std::string error; const std::vector specids = this->getProperty("SpectrumIDs"); + if (!hasWorkspacePtr) { + // use the number of spectra for the number of histograms + numHist = specids.size(); + // give up if it is empty + if (numHist == 0) { + return result; + } + } error = checkValues(specids, numHist); if (!error.empty()) result["SpectrumIDs"] = error; diff --git a/Code/Mantid/Framework/Algorithms/src/FilterByLogValue.cpp b/Code/Mantid/Framework/Algorithms/src/FilterByLogValue.cpp index 464673b57699..b2683a815f49 100644 --- a/Code/Mantid/Framework/Algorithms/src/FilterByLogValue.cpp +++ b/Code/Mantid/Framework/Algorithms/src/FilterByLogValue.cpp @@ -83,8 +83,13 @@ std::map FilterByLogValue::validateInputs() { std::map errors; - // Check that the log exists for the given input workspace + // check for null pointers - this is to protect against workspace groups EventWorkspace_const_sptr inputWS = this->getProperty("InputWorkspace"); + if (!inputWS) { + return errors; + } + + // Check that the log exists for the given input workspace std::string logname = getPropertyValue("LogName"); try { ITimeSeriesProperty * log = dynamic_cast( inputWS->run().getLogData(logname) ); diff --git a/Code/Mantid/Framework/Algorithms/src/PDFFourierTransform.cpp b/Code/Mantid/Framework/Algorithms/src/PDFFourierTransform.cpp index 43f2e2432b18..25daf3594db6 100644 --- a/Code/Mantid/Framework/Algorithms/src/PDFFourierTransform.cpp +++ b/Code/Mantid/Framework/Algorithms/src/PDFFourierTransform.cpp @@ -134,7 +134,12 @@ namespace Mantid if (Qmax <= Qmin) result["Qmax"] = "Must be greater than Qmin"; + // check for null pointers - this is to protect against workspace groups API::MatrixWorkspace_const_sptr inputWS = getProperty("InputWorkspace"); + if (!inputWS) { + return result; + } + if (inputWS->getNumberHistograms() != 1) { result["InputWorkspace"] = "Input workspace must have only one spectrum"; diff --git a/Code/Mantid/Framework/Algorithms/src/SumEventsByLogValue.cpp b/Code/Mantid/Framework/Algorithms/src/SumEventsByLogValue.cpp index 21335f0bf8ec..284fcff0fae0 100644 --- a/Code/Mantid/Framework/Algorithms/src/SumEventsByLogValue.cpp +++ b/Code/Mantid/Framework/Algorithms/src/SumEventsByLogValue.cpp @@ -48,7 +48,11 @@ namespace Algorithms { std::map errors; + // check for null pointers - this is to protect against workspace groups m_inputWorkspace = getProperty("InputWorkspace"); + if (!m_inputWorkspace) { + return errors; + } // This only works for unweighted events // TODO: Either turn this check into a proper validator or amend the algorithm to work for weighted events diff --git a/Code/Mantid/Framework/Algorithms/test/CorelliCrossCorrelateTest.h b/Code/Mantid/Framework/Algorithms/test/CorelliCrossCorrelateTest.h new file mode 100644 index 000000000000..b4c9bed5adb2 --- /dev/null +++ b/Code/Mantid/Framework/Algorithms/test/CorelliCrossCorrelateTest.h @@ -0,0 +1,103 @@ +#ifndef MANTID_ALGORITHMS_CORELLICROSSCORRELATETEST_H_ +#define MANTID_ALGORITHMS_CORELLICROSSCORRELATETEST_H_ + +#include + +#include "MantidAlgorithms/CorelliCrossCorrelate.h" +#include "MantidKernel/DateAndTime.h" +#include "MantidDataObjects/EventWorkspace.h" +#include "MantidKernel/TimeSeriesProperty.h" + +using Mantid::Algorithms::CorelliCrossCorrelate; +using namespace Mantid::API; +using namespace Mantid::DataObjects; +using namespace Mantid::Kernel; + +class CorelliCrossCorrelateTest : public CxxTest::TestSuite { +public: + // This pair of boilerplate methods prevent the suite being created statically + // This means the constructor isn't called when running other tests + static CorelliCrossCorrelateTest *createSuite() { + return new CorelliCrossCorrelateTest(); + } + static void destroySuite(CorelliCrossCorrelateTest *suite) { delete suite; } + + void test_Init() { + CorelliCrossCorrelate alg; + TS_ASSERT_THROWS_NOTHING(alg.initialize()) + TS_ASSERT(alg.isInitialized()) + } + + void test_exec() { + // Name of the output workspace. + std::string outWSName("CorelliCrossCorrelateTest_OutputWS"); + + IAlgorithm_sptr lei = + AlgorithmFactory::Instance().create("LoadEmptyInstrument", 1); + lei->initialize(); + lei->setPropertyValue("Filename", "CORELLI_Definition.xml"); + lei->setPropertyValue("OutputWorkspace", + "CorelliCrossCorrelateTest_OutputWS"); + lei->setPropertyValue("MakeEventWorkspace", "1"); + lei->execute(); + + EventWorkspace_sptr ws; + ws = AnalysisDataService::Instance().retrieveWS( + "CorelliCrossCorrelateTest_OutputWS"); + + DateAndTime startTime("2007-11-30T16:17:00"); + EventList *evlist = ws->getEventListPtr(0); + + // Add some events to the workspace. + evlist->addEventQuickly(TofEvent(10.0, startTime + 0.007)); + evlist->addEventQuickly(TofEvent(100.0, startTime + 0.012)); + evlist->addEventQuickly(TofEvent(1000.0, startTime + 0.012)); + evlist->addEventQuickly(TofEvent(10000.0, startTime + 0.012)); + evlist->addEventQuickly(TofEvent(1222.0, startTime + 0.03)); + + ws->getAxis(0)->setUnit("TOF"); + + ws->sortAll(PULSETIME_SORT, NULL); + + // Add some chopper TDCs to the workspace. + double period = 1 / 293.383; + auto tdc = new TimeSeriesProperty("chopper4_TDC"); + for (int i = 0; i < 10; i++) { + double tdcTime = i * period; + tdc->addValue(startTime + tdcTime, 1); + } + ws->mutableRun().addLogData(tdc); + + CorelliCrossCorrelate alg; + TS_ASSERT_THROWS_NOTHING(alg.initialize()) + TS_ASSERT(alg.isInitialized()) + TS_ASSERT_THROWS_NOTHING(alg.setPropertyValue( + "InputWorkspace", "CorelliCrossCorrelateTest_OutputWS")); + TS_ASSERT_THROWS_NOTHING(alg.setPropertyValue( + "OutputWorkspace", "CorelliCrossCorrelateTest_OutputWS")); + TS_ASSERT_THROWS_NOTHING(alg.setPropertyValue("TimingOffset", "20000")); + TS_ASSERT_THROWS_NOTHING(alg.execute();); + TS_ASSERT(alg.isExecuted()); + + // Retrieve the workspace from data service. + TS_ASSERT_THROWS_NOTHING( + ws = AnalysisDataService::Instance().retrieveWS( + "CorelliCrossCorrelateTest_OutputWS")); + TS_ASSERT(ws); + if (!ws) + return; + + std::vector &events = evlist->getWeightedEvents(); + + TS_ASSERT_DELTA(events[0].weight(), -1.99392, 0.00001) + TS_ASSERT_DELTA(events[1].weight(), -1.99392, 0.00001) + TS_ASSERT_DELTA(events[2].weight(), 2.00612, 0.00001) + TS_ASSERT_DELTA(events[3].weight(), -1.99392, 0.00001) + TS_ASSERT_DELTA(events[4].weight(), 2.00612, 0.00001) + + // Remove workspace from the data service. + AnalysisDataService::Instance().remove(outWSName); + } +}; + +#endif /* MANTID_ALGORITHMS_CORELLICROSSCORRELATETEST_H_ */ diff --git a/Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/LoadFullprofResolution.h b/Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/LoadFullprofResolution.h index 989812493da5..3ea47f5d2c50 100644 --- a/Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/LoadFullprofResolution.h +++ b/Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/LoadFullprofResolution.h @@ -55,6 +55,42 @@ namespace Mantid virtual const std::string summary() const {return "Load Fullprof's resolution (.irf) file to one or multiple TableWorkspace(s) and/or where this is supported." " See description section, translate fullprof resolution fitting parameter into Mantid equivalent fitting parameters.";} + /// Get row numbers of the parameters in the table workspace + static void getTableRowNumbers(const API::ITableWorkspace_sptr & tablews, std::map& parammap); + + /// Put parameters into a matrix workspace + static void putParametersIntoWorkspace( const API::Column_const_sptr, API::MatrixWorkspace_sptr ws, int profNumber, std::string & parameterXMLString); + + /// Add an Ikeda-Carpenter PV ALFBE parameter + static void addALFBEParameter(const API::Column_const_sptr, Poco::XML::Document* mDoc, Poco::XML::Element* parent, const std::string& paramName); + + /// Add set of Ikeda-Carpenter PV Sigma parameters + static void addSigmaParameters(const API::Column_const_sptr, Poco::XML::Document* mDoc, Poco::XML::Element* parent ); + + /// Add set of Ikeda-Carpenter PV Gamma parameters + static void addGammaParameters(const API::Column_const_sptr, Poco::XML::Document* mDoc, Poco::XML::Element* parent ); + + /// Add set of BackToBackExponential S parameters + static void addBBX_S_Parameters(const API::Column_const_sptr, Poco::XML::Document* mDoc, Poco::XML::Element* parent ); + + /// Add set of BackToBackExponential A parameters + static void addBBX_A_Parameters(const API::Column_const_sptr, Poco::XML::Document* mDoc, Poco::XML::Element* parent ); + + /// Add set of BackToBackExponential B parameters + static void addBBX_B_Parameters(const API::Column_const_sptr, Poco::XML::Document* mDoc, Poco::XML::Element* parent ); + + /// Get value for XML eq attribute for parameter + static std::string getXMLEqValue( const API::Column_const_sptr, const std::string& name ); + + /// Get value for XML eq attribute for squared parameter + static std::string getXMLSquaredEqValue( const API::Column_const_sptr column, const std::string& name ); + + // Translate a parameter name from as it appears in the table workspace to its name in the XML file + static std::string getXMLParameterName( const std::string& name ); + + /// Place to store the row numbers + static std::map m_rowNumbers; + private: /// Implement abstract Algorithm methods void init(); @@ -94,42 +130,6 @@ namespace Mantid /// Create Bank to Workspace Correspondence void createBankToWorkspaceMap ( const std::vector& banks, const std::vector& workspaces, std::map< int, size_t>& WorkpsaceOfBank ); - /// Put parameters into a matrix workspace - void putParametersIntoWorkspace( const API::Column_const_sptr, API::MatrixWorkspace_sptr ws, int profNumber); - - /// Add an Ikeda-Carpenter PV ALFBE parameter - void addALFBEParameter(const API::Column_const_sptr, Poco::XML::Document* mDoc, Poco::XML::Element* parent, const std::string& paramName); - - /// Add set of Ikeda-Carpenter PV Sigma parameters - void addSigmaParameters(const API::Column_const_sptr, Poco::XML::Document* mDoc, Poco::XML::Element* parent ); - - /// Add set of Ikeda-Carpenter PV Gamma parameters - void addGammaParameters(const API::Column_const_sptr, Poco::XML::Document* mDoc, Poco::XML::Element* parent ); - - /// Add set of BackToBackExponential S parameters - void addBBX_S_Parameters(const API::Column_const_sptr, Poco::XML::Document* mDoc, Poco::XML::Element* parent ); - - /// Add set of BackToBackExponential A parameters - void addBBX_A_Parameters(const API::Column_const_sptr, Poco::XML::Document* mDoc, Poco::XML::Element* parent ); - - /// Add set of BackToBackExponential B parameters - void addBBX_B_Parameters(const API::Column_const_sptr, Poco::XML::Document* mDoc, Poco::XML::Element* parent ); - - /// Get value for XML eq attribute for parameter - std::string getXMLEqValue( const API::Column_const_sptr, const std::string& name ); - - /// Get value for XML eq attribute for squared parameter - std::string getXMLSquaredEqValue( const API::Column_const_sptr column, const std::string& name ); - - // Translate a parameter name from as it appears in the table workspace to its name in the XML file - std::string getXMLParameterName( const std::string& name ); - - /// Get row numbers of the parameters in the table workspace - void getTableRowNumbers(const API::ITableWorkspace_sptr & tablews, std::map& parammap); - - /// Place to store the row numbers - std::map m_rowNumbers; - }; diff --git a/Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/SaveAscii2.h b/Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/SaveAscii2.h index dfacc3d56224..4e0dc838f1f5 100644 --- a/Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/SaveAscii2.h +++ b/Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/SaveAscii2.h @@ -57,9 +57,8 @@ namespace Mantid ~SaveAscii2() {} /// Algorithm's name for identification overriding a virtual method virtual const std::string name() const { return "SaveAscii"; } - ///Summary of algorithms purpose - virtual const std::string summary() const {return "Saves a 2D workspace to a ascii file.";} - + ///Summary of algorithms purpose + virtual const std::string summary() const {return "Saves a 2D workspace to a ascii file.";} /// Algorithm's version for identification overriding a virtual method virtual int version() const { return 2; } /// Algorithm's category for identification overriding a virtual method @@ -90,6 +89,7 @@ namespace Mantid bool m_writeDX; bool m_writeID; bool m_isHistogram; + bool m_isCommonBins; API::MatrixWorkspace_const_sptr m_ws; }; } // namespace DataHandling diff --git a/Code/Mantid/Framework/DataHandling/src/CreateChunkingFromInstrument.cpp b/Code/Mantid/Framework/DataHandling/src/CreateChunkingFromInstrument.cpp index 6ddd1217ede0..2a3a6deaac8e 100644 --- a/Code/Mantid/Framework/DataHandling/src/CreateChunkingFromInstrument.cpp +++ b/Code/Mantid/Framework/DataHandling/src/CreateChunkingFromInstrument.cpp @@ -139,14 +139,14 @@ namespace DataHandling // get the input paramters string filename = getPropertyValue(PARAM_IN_FILE); - MatrixWorkspace_sptr inWS = getProperty(PARAM_IN_WKSP); + string inWSname = getPropertyValue(PARAM_IN_WKSP); string instName = getPropertyValue(PARAM_INST_NAME); string instFilename = getPropertyValue(PARAM_INST_FILE); // count how many ways the input instrument was specified int numInst = 0; if (!filename.empty()) numInst++; - if (inWS) numInst++; + if (!inWSname.empty()) numInst++; if (!instName.empty()) numInst++; if (!instFilename.empty()) numInst++; diff --git a/Code/Mantid/Framework/DataHandling/src/LoadFullprofResolution.cpp b/Code/Mantid/Framework/DataHandling/src/LoadFullprofResolution.cpp index e33b5f0571f1..7ae2769db3ab 100644 --- a/Code/Mantid/Framework/DataHandling/src/LoadFullprofResolution.cpp +++ b/Code/Mantid/Framework/DataHandling/src/LoadFullprofResolution.cpp @@ -38,6 +38,8 @@ namespace DataHandling DECLARE_ALGORITHM(LoadFullprofResolution) + std::map LoadFullprofResolution::m_rowNumbers; + //---------------------------------------------------------------------------------------------- /** Constructor */ @@ -213,7 +215,7 @@ namespace DataHandling } else // Numbers match, so put parameters into workspaces. { - getTableRowNumbers( outTabWs, m_rowNumbers); + getTableRowNumbers( outTabWs, LoadFullprofResolution::m_rowNumbers); for (size_t i=0; i < vec_bankids.size(); ++i) { int bankId = vec_bankids[i]; @@ -222,7 +224,15 @@ namespace DataHandling auto workspace = boost::dynamic_pointer_cast(wsi); // Get column from table workspace API::Column_const_sptr OutTabColumn = outTabWs->getColumn( i+1 ); - putParametersIntoWorkspace( OutTabColumn, workspace, nProf ); + std::string parameterXMLString; + putParametersIntoWorkspace( OutTabColumn, workspace, nProf, parameterXMLString ); + + // Load the string into the workspace + Algorithm_sptr loadParamAlg = createChildAlgorithm("LoadParameterFile"); + loadParamAlg->setProperty("ParameterXML", parameterXMLString); + loadParamAlg->setProperty("Workspace", workspace); + loadParamAlg->execute(); + } } } @@ -835,7 +845,7 @@ namespace DataHandling * @param ws :: [input/output] the group workspace parameters are to be put in * @param nProf :: the PROF Number, which is used to determine fitting function for the parameters. */ - void LoadFullprofResolution::putParametersIntoWorkspace( API::Column_const_sptr column, API::MatrixWorkspace_sptr ws, int nProf) + void LoadFullprofResolution::putParametersIntoWorkspace( API::Column_const_sptr column, API::MatrixWorkspace_sptr ws, int nProf, std::string & parameterXMLString) { // Get instrument name from matrix workspace @@ -882,19 +892,13 @@ namespace DataHandling // Convert DOM XML document into string std::ostringstream outFile; writer.writeNode(outFile, mDoc); - std::string parameterXMLString = outFile.str(); + parameterXMLString = outFile.str(); // Useful code for testing upgrades commented out for production use //std::ofstream outfileDebug("C:/Temp/test4_fullprof.xml"); //outfileDebug << parameterXMLString; //outfileDebug.close(); - - // Load the string into the workspace - Algorithm_sptr loadParamAlg = createChildAlgorithm("LoadParameterFile"); - loadParamAlg->setProperty("ParameterXML", parameterXMLString); - loadParamAlg->setProperty("Workspace", ws); - loadParamAlg->execute(); } /* Add an Ikeda Carpenter PV ALFBE parameter to the XML document according to the table workspace @@ -1041,7 +1045,7 @@ namespace DataHandling */ std::string LoadFullprofResolution::getXMLEqValue( const API::Column_const_sptr column, const std::string& name ) { - size_t paramNumber = m_rowNumbers[name]; + size_t paramNumber = LoadFullprofResolution::m_rowNumbers[name]; //API::Column_const_sptr column = tablews->getColumn( columnIndex ); double eqValue = column->cell(paramNumber); return boost::lexical_cast(eqValue); @@ -1053,7 +1057,7 @@ namespace DataHandling */ std::string LoadFullprofResolution::getXMLSquaredEqValue( const API::Column_const_sptr column, const std::string& name ) { - size_t paramNumber = m_rowNumbers[name]; + size_t paramNumber = LoadFullprofResolution::m_rowNumbers[name]; //API::Column_const_sptr column = tablews->getColumn( columnIndex ); double eqValue = column->cell(paramNumber); return boost::lexical_cast(eqValue*eqValue); diff --git a/Code/Mantid/Framework/DataHandling/src/LoadGSS.cpp b/Code/Mantid/Framework/DataHandling/src/LoadGSS.cpp index 9e8b44f5853c..dc62761b30e2 100644 --- a/Code/Mantid/Framework/DataHandling/src/LoadGSS.cpp +++ b/Code/Mantid/Framework/DataHandling/src/LoadGSS.cpp @@ -337,17 +337,25 @@ namespace DataHandling } std::istringstream inputLine(currentLine, std::ios::in); - inputLine >> xValue >> yValue >> eValue; // It is different for the definition of X, Y, Z in SLOG and RALF format if (filetype == 'r') { // RALF + // LoadGSS produces overlapping columns for some datasets, due to std::setw + // For this reason we need to read the column values as string and then convert to double + std::string xString, yString, eString; + inputLine >> std::setw(11) >> xString >> std::setw(18) >> yString >> std::setw(18) >> eString; + xValue = boost::lexical_cast(xString); + yValue = boost::lexical_cast(yString); + eValue = boost::lexical_cast(eString); xValue = (2 * xValue) - xPrev; + } else if (filetype == 's') { // SLOG + inputLine >> xValue >> yValue >> eValue; if (calslogx0) { // calculation of x0 must use the x'[0] @@ -362,6 +370,11 @@ namespace DataHandling xValue = (2 * xValue) - xPrev; } + else + { + g_log.error() << "Unsupported GSAS File Type: " << filetype << "\n"; + throw Exception::FileError("Not a GSAS file", filename); + } if (multiplybybinwidth) { diff --git a/Code/Mantid/Framework/DataHandling/src/SaveAscii2.cpp b/Code/Mantid/Framework/DataHandling/src/SaveAscii2.cpp index f5d2bb8ee328..13b1a8908ce6 100644 --- a/Code/Mantid/Framework/DataHandling/src/SaveAscii2.cpp +++ b/Code/Mantid/Framework/DataHandling/src/SaveAscii2.cpp @@ -55,7 +55,7 @@ namespace Mantid "It is always written for workspaces with multiple spectra."); declareProperty("CommentIndicator", "#", "Character(s) to put in front of comment lines."); - + // For the ListValidator std::string spacers[6][2] = { {"CSV", ","}, {"Tab", "\t"}, {"Space", " "}, {"Colon", ":"}, {"SemiColon", ";"}, {"UserDefined", "UserDefined"} }; @@ -80,6 +80,7 @@ namespace Mantid declareProperty("AppendToFile", false, "If true, don't overwrite the file. Append to the end of it. "); + declareProperty("RaggedWorkspace", true, "If true, ensure that more than one xspectra is used. "); //in testing } /** @@ -92,6 +93,7 @@ namespace Mantid int nSpectra = static_cast(m_ws->getNumberHistograms()); m_nBins = static_cast(m_ws->blocksize()); m_isHistogram = m_ws->isHistogramData(); + m_isCommonBins = m_ws->isCommonBins(); //checking for ragged workspace m_writeID = getProperty("WriteSpectrumID"); if (nSpectra != 1) m_writeID = true; @@ -154,6 +156,7 @@ namespace Mantid idx.insert(i); } } + //figure out how to read in readX and have them be seperate lists // Add spectra list into the index list if (!spec_list.empty()) @@ -235,25 +238,31 @@ namespace Mantid @param spectraItr :: a set iterator pointing to a set of workspace IDs to be saved @param file :: the file writer object */ - void SaveAscii2::writeSpectra(const std::set::const_iterator & spectraItr, std::ofstream & file) + void SaveAscii2::writeSpectra(const std::set::const_iterator & spectraItr, std::ofstream & file) { auto spec = m_ws->getSpectrum(*spectraItr); auto specNo = spec->getSpectrumNo(); if (m_writeID) file << specNo << std::endl; - + for(int bin=0;binreadX(*spectraItr)[bin] + m_ws->readX(*spectraItr)[bin+1] )/2; + } - if (m_isHistogram) // bin centres + else if (m_isHistogram & m_isCommonBins) // bin centres, { - file << ( m_ws->readX(0)[bin] + m_ws->readX(0)[bin+1] )/2; + file << ( m_ws->readX(0)[bin] + m_ws->readX(0)[bin+1] )/2; } - else // data points + + else { file << m_ws->readX(0)[bin]; } file << m_sep; file << m_ws->readY(*spectraItr)[bin]; + file << m_sep; file << m_ws->readE(*spectraItr)[bin]; if (m_writeDX) @@ -277,7 +286,7 @@ namespace Mantid @param spectraIndex :: an integer relating to a workspace ID @param file :: the file writer object */ - void SaveAscii2::writeSpectra(const int & spectraIndex, std::ofstream & file) + void SaveAscii2::writeSpectra(const int & spectraIndex, std::ofstream & file) { auto spec = m_ws->getSpectrum(spectraIndex); auto specNo = spec->getSpectrumNo(); @@ -285,16 +294,21 @@ namespace Mantid for(int bin=0;binreadX(0)[bin] + m_ws->readX(0)[bin+1] )/2; } + else if (!m_isCommonBins) //checking for ragged workspace + { + file << ( m_ws->readX(spectraIndex)[bin] + m_ws->readX(spectraIndex)[bin+1] )/2; + } else // data points { file << m_ws->readX(0)[bin]; } file << m_sep; file << m_ws->readY(spectraIndex)[bin]; + file << m_sep; file << m_ws->readE(spectraIndex)[bin]; if (m_writeDX) diff --git a/Code/Mantid/Framework/DataHandling/src/SavePDFGui.cpp b/Code/Mantid/Framework/DataHandling/src/SavePDFGui.cpp index 6d3b6480f173..4e04a0b01da9 100644 --- a/Code/Mantid/Framework/DataHandling/src/SavePDFGui.cpp +++ b/Code/Mantid/Framework/DataHandling/src/SavePDFGui.cpp @@ -72,7 +72,12 @@ namespace DataHandling std::map SavePDFGui::validateInputs(){ std::map result; + // check for null pointers - this is to protect against workspace groups API::MatrixWorkspace_const_sptr inputWS = getProperty("InputWorkspace"); + if (!inputWS){ + return result; + } + const int nHist = static_cast (inputWS->getNumberHistograms()); if (nHist != 1) { diff --git a/Code/Mantid/Framework/DataHandling/src/SaveParameterFile.cpp b/Code/Mantid/Framework/DataHandling/src/SaveParameterFile.cpp index 4a3cdd2d150f..690eb5a44961 100644 --- a/Code/Mantid/Framework/DataHandling/src/SaveParameterFile.cpp +++ b/Code/Mantid/Framework/DataHandling/src/SaveParameterFile.cpp @@ -8,12 +8,6 @@ #include #include -#include -#include -#include -#include -#include - #include namespace Mantid @@ -84,22 +78,18 @@ namespace DataHandling const Instrument_const_sptr instrument = ws->getInstrument(); const ParameterMap_sptr params = instrument->getParameterMap(); - //Map of component ids to their respective XML Elements - std::map > compMap; - - //Set up the XML document - XML::AutoPtr xmlDoc = new XML::Document; - XML::AutoPtr rootElem = xmlDoc->createElement("parameter-file"); - rootElem->setAttribute("instrument", instrument->getName()); - rootElem->setAttribute("valid-from", instrument->getValidFromDate().toISO8601String()); - xmlDoc->appendChild(rootElem); + //maps components to a tuple of parameters' name, type, and value + std::map > > toSave; - //Vector of tuples: (componentid, paramname, paramtype, paramvalue) - std::vector > toSave; + //Set up a progress bar + Progress prog(this, 0.0, 0.3, params->size()); //Build a list of parameters to save; for(auto paramsIt = params->begin(); paramsIt != params->end(); ++paramsIt) { + if(prog.hasCancellationBeenRequested()) + break; + prog.report("Generating parameters"); const ComponentID cID = (*paramsIt).first; const std::string pName = (*paramsIt).second->name(); const std::string pType = (*paramsIt).second->type(); @@ -117,7 +107,22 @@ namespace DataHandling //If it isn't a position or rotation parameter, we can just add it to the list to save directly and move on. if(pName != "pos" && pName != "rot") { - toSave.push_back(boost::make_tuple(cID, pName, pType, pValue)); + if(pType == "fitting") + { + //With fitting parameters we do something special (i.e. silly) + //We create an entire XML element to be inserted into the output, instead of just giving a single fixed value + const FitParameter& fitParam = paramsIt->second->value(); + const std::string fpName = fitParam.getFunction() + ":" + fitParam.getName(); + std::stringstream fpValue; + fpValue << ""; + toSave[cID].push_back(boost::make_tuple(fpName, "fitting", fpValue.str())); + } + else + toSave[cID].push_back(boost::make_tuple(pName, pType, pValue)); } } @@ -127,10 +132,13 @@ namespace DataHandling { //Get all the components in the instrument instrument->getChildren(components, true); + prog.resetNumSteps((int64_t)components.size(), 0.3, 0.6); - auto progressSteps = std::distance(components.begin(), components.end()); for(auto cIt = components.begin(); cIt != components.end(); ++cIt) { + if(prog.hasCancellationBeenRequested()) + break; + prog.report("Generating location parameters"); const IComponent* comp = cIt->get(); const IComponent* baseComp = comp->getBaseComponent(); const ComponentID cID = const_cast(comp); @@ -141,33 +149,14 @@ namespace DataHandling const V3D absPos = comp->getPos(); const V3D posDiff = absPos - basePos; - bool savePos = true; + const double threshold = 0.0001; - const IComponent_const_sptr parent = comp->getParent(); - if(parent) - { - const V3D parBasePos = parent->getBaseComponent()->getPos(); - const V3D parAbsPos = parent->getPos(); - const V3D parPosDiff = parAbsPos - parBasePos; - const V3D parDiff = parPosDiff - posDiff; - - //If our parent's position offset is the same as ours (ignoring floating point errors - //then we won't bother saving our own position. - //if mag(diff) < mag(tolerance): - const double tolerance = 0.0001; - if(V3D::CompareMagnitude(parDiff, V3D(tolerance, tolerance, tolerance))) - savePos = false; - } - - if(savePos) - { - if(posDiff.X() != 0) - toSave.push_back(boost::make_tuple(cID, "x", "double", Strings::toString(absPos.X()))); - if(posDiff.Y() != 0) - toSave.push_back(boost::make_tuple(cID, "y", "double", Strings::toString(absPos.Y()))); - if(posDiff.Z() != 0) - toSave.push_back(boost::make_tuple(cID, "z", "double", Strings::toString(absPos.Z()))); - } + if(std::abs(posDiff.X()) > threshold) + toSave[cID].push_back(boost::make_tuple("x", "double", Strings::toString(absPos.X()))); + if(std::abs(posDiff.Y()) > threshold) + toSave[cID].push_back(boost::make_tuple("y", "double", Strings::toString(absPos.Y()))); + if(std::abs(posDiff.Z()) > threshold) + toSave[cID].push_back(boost::make_tuple("z", "double", Strings::toString(absPos.Z()))); //Check if the rotation has been changed by a parameter //If so, convert to Euler (XYZ order) and output each component that differs @@ -178,128 +167,62 @@ namespace DataHandling { //Euler rotation components are not independent so write them all out to be safe. std::vector absEuler = absRot.getEulerAngles("XYZ"); - toSave.push_back(boost::make_tuple(cID, "rotx", "double", Strings::toString(absEuler[0]))); - toSave.push_back(boost::make_tuple(cID, "roty", "double", Strings::toString(absEuler[1]))); - toSave.push_back(boost::make_tuple(cID, "rotz", "double", Strings::toString(absEuler[2]))); + toSave[cID].push_back(boost::make_tuple("rotx", "double", Strings::toString(absEuler[0]))); + toSave[cID].push_back(boost::make_tuple("roty", "double", Strings::toString(absEuler[1]))); + toSave[cID].push_back(boost::make_tuple("rotz", "double", Strings::toString(absEuler[2]))); } - - progress((double)std::distance(components.begin(), cIt) / (double)progressSteps * 0.3, "Identifying location parameters"); } } - auto progressSteps = std::distance(toSave.begin(), toSave.end()); - //Iterate through all the parameters we want to save and build an XML - //document out of them. - for(auto paramsIt = toSave.begin(); paramsIt != toSave.end(); ++paramsIt) - { + //Begin writing the XML manually + std::ofstream file(filename.c_str(), std::ofstream::trunc); + file << "\n"; + file << "getName() << "\""; + file << " valid-from=\"" << instrument->getValidFromDate().toISO8601String() << "\">\n"; - - //Component data - const ComponentID cID = boost::get<0>(*paramsIt); + prog.resetNumSteps((int64_t)toSave.size(), 0.6, 1.0); + //Iterate through all the parameters we want to save and build an XML document out of them. + for(auto compIt = toSave.begin(); compIt != toSave.end(); ++compIt) + { + if(prog.hasCancellationBeenRequested()) + break; + prog.report("Saving parameters"); + //Component data + const ComponentID cID = compIt->first; const std::string cFullName = cID->getFullName(); const IDetector* cDet = dynamic_cast(cID); const detid_t cDetID = (cDet) ? cDet->getID() : 0; - const std::string cDetIDStr = boost::lexical_cast(cDetID); - - //Parameter data - const std::string pName = boost::get<1>(*paramsIt); - const std::string pType = boost::get<2>(*paramsIt); - const std::string pValue = boost::get<3>(*paramsIt); - - //A component-link element - XML::AutoPtr compElem = 0; - - /* If an element already exists for a component with this name, re-use it. - * - * Why are we using an std::map and not simply traversing the DOM? Because - * the interface for doing that is painful and horrible to use, and this is - * probably faster (but negligably so in this case). - * - * And lastly, because Poco::XML::NodeList::length() segfaults. - */ - auto compIt = compMap.find(cID); - if(compIt != compMap.end()) - { - compElem = (*compIt).second; - } - //One doesn't already exist? Make a new one. - if(!compElem) + file << " \n"; + for(auto paramIt = compIt->second.begin(); paramIt != compIt->second.end(); ++paramIt) { - compElem = xmlDoc->createElement("component-link"); - rootElem->appendChild(compElem); - compMap[cID] = compElem; - } - - //Create the parameter element - XML::AutoPtr paramElem = xmlDoc->createElement("parameter"); - - //Set the attributes - compElem->setAttribute("name", cFullName); + const std::string pName = paramIt->get<0>(); + const std::string pType = paramIt->get<1>(); + const std::string pValue = paramIt->get<2>(); - //If there is a valid detector id, include it - if(cDetID > 0) - { - compElem->setAttribute("id", cDetIDStr); + //With fitting parameters, we're actually inserting an entire element, as constructed above + if(pType == "fitting") + { + file << " \n"; + file << " " << pValue << "\n"; + file << " \n"; + } + else + { + file << " \n"; + file << " \n"; + file << " \n"; + } } - - - if(pType == "fitting") - { - // We need some parameter information as function, formula, units, and result units - auto param = params->get(cID,pName,pType); - const Mantid::Geometry::FitParameter& fitParam = param->value(); - - // For fitting parameters we specify their type - paramElem->setAttribute("name", std::string(fitParam.getFunction()+":"+fitParam.getName())); - paramElem->setAttribute("type", pType); - - XML::AutoPtr formulaElem = xmlDoc->createElement("formula"); - formulaElem->setAttribute("eq", fitParam.getFormula()); - formulaElem->setAttribute("unit", fitParam.getFormulaUnit()); - formulaElem->setAttribute("result-unit", fitParam.getResultUnit()); - - //Insert the elements into the document - compElem->appendChild(paramElem); - paramElem->appendChild(formulaElem); - } - else - { - paramElem->setAttribute("name", pName); - - //For strings, we specify their type. - if(pType == "string") - { - paramElem->setAttribute("type", "string"); - } - XML::AutoPtr valueElem = xmlDoc->createElement("value"); - valueElem->setAttribute("val", pValue); - - //Insert the elements into the document - compElem->appendChild(paramElem); - paramElem->appendChild(valueElem); - } - - - progress((double)std::distance(toSave.begin(), paramsIt) / (double)progressSteps * 0.6 + 0.3, "Building XML graph"); + file << " \n"; } - progress(0.95, "Writing XML to file"); + file << "\n"; - //Output the XMl document to the given file. - XML::DOMWriter writer; - writer.setOptions(XML::XMLWriter::PRETTY_PRINT | XML::XMLWriter::WRITE_XML_DECLARATION); - std::ofstream file(filename.c_str(), std::ofstream::trunc); - try - { - writer.writeNode(file, xmlDoc); - } - catch(Poco::Exception &e) - { - g_log.error() << "Error serializing XML for SaveParameterFile: " << e.displayText() << std::endl; - } file.flush(); file.close(); - progress(1.0, "Done"); } } // namespace Algorithms diff --git a/Code/Mantid/Framework/DataHandling/test/SavePDFGuiTest.h b/Code/Mantid/Framework/DataHandling/test/SavePDFGuiTest.h index db962a619bbb..6782e6a6b153 100644 --- a/Code/Mantid/Framework/DataHandling/test/SavePDFGuiTest.h +++ b/Code/Mantid/Framework/DataHandling/test/SavePDFGuiTest.h @@ -5,6 +5,7 @@ #include #include +#include "MantidAPI/AlgorithmManager.h" #include "MantidDataHandling/SavePDFGui.h" #include "MantidDataHandling/LoadNexusProcessed.h" @@ -56,6 +57,16 @@ class SavePDFGuiTest : public CxxTest::TestSuite return n; } + bool loadWorkspace(const std::string &filename, const std::string wsName) + { + LoadNexusProcessed load; + load.initialize(); + load.setProperty("Filename", filename); + load.setProperty("OutputWorkspace", wsName); + load.execute(); + return load.isExecuted(); + } + void test_exec() { // name of workspace to create and save @@ -64,11 +75,7 @@ class SavePDFGuiTest : public CxxTest::TestSuite const std::string outFilename("SavePDFGuiTest_Output.gr"); // Load a file to save out - LoadNexusProcessed load; - load.initialize(); - load.setProperty("Filename", "nom_gr.nxs"); - load.setProperty("OutputWorkspace", wsName); - load.execute(); + TS_ASSERT(loadWorkspace("nom_gr.nxs", wsName)); // save the file SavePDFGui alg; @@ -91,6 +98,33 @@ class SavePDFGuiTest : public CxxTest::TestSuite outFile.remove(false); } + void test_exec_ws_group() + { + // Create a group + const std::string groupName("SavePDFGUIGroup"); + TS_ASSERT(loadWorkspace("nom_gr.nxs", groupName+"_1")); + TS_ASSERT(loadWorkspace("nom_gr.nxs", groupName+"_2")); + + auto grpAlg = AlgorithmManager::Instance().createUnmanaged("GroupWorkspaces"); + grpAlg->initialize(); + grpAlg->setPropertyValue("InputWorkspaces", groupName+"_1,"+groupName+"_2"); + grpAlg->setPropertyValue("OutputWorkspace", groupName); + grpAlg->execute(); + + // name of the output file + const std::string outFilename("SavePDFGUIGroup.gr"); + + // run the algorithm with a group + SavePDFGui alg; + TS_ASSERT_THROWS_NOTHING( alg.initialize() ); + TS_ASSERT_THROWS_NOTHING( alg.setPropertyValue("InputWorkspace", groupName) ); + TS_ASSERT_THROWS_NOTHING( alg.setPropertyValue("Filename","SavePDFGUIGroup.gr") ); + TS_ASSERT_THROWS_NOTHING( alg.execute() ); + TS_ASSERT( alg.isExecuted() ); + + // remove the workspace group + AnalysisDataService::Instance().deepRemoveGroup(groupName); + } }; diff --git a/Code/Mantid/Framework/Geometry/inc/MantidGeometry/Crystal/CompositeBraggScatterer.h b/Code/Mantid/Framework/Geometry/inc/MantidGeometry/Crystal/CompositeBraggScatterer.h index f7e9355d808f..192f8986c97a 100644 --- a/Code/Mantid/Framework/Geometry/inc/MantidGeometry/Crystal/CompositeBraggScatterer.h +++ b/Code/Mantid/Framework/Geometry/inc/MantidGeometry/Crystal/CompositeBraggScatterer.h @@ -1,4 +1,4 @@ -#ifndef MANTID_GEOMETRY_COMPOSITEBRAGGSCATTERER_H_ +#ifndef MANTID_GEOMETRY_COMPOSITEBRAGGSCATTERER_H_ #define MANTID_GEOMETRY_COMPOSITEBRAGGSCATTERER_H_ #include "MantidGeometry/DllConfig.h" @@ -79,7 +79,7 @@ class MANTID_GEOMETRY_DLL CompositeBraggScatterer : public BraggScatterer void removeScatterer(size_t i); StructureFactor calculateStructureFactor(const Kernel::V3D &hkl) const; - + protected: void afterPropertySet(const std::string &propertyName); void propagateProperty(const std::string &propertyName); @@ -91,9 +91,7 @@ class MANTID_GEOMETRY_DLL CompositeBraggScatterer : public BraggScatterer std::vector m_scatterers; }; +} +} - -} // namespace Geometry -} // namespace Mantid - -#endif /* MANTID_GEOMETRY_COMPOSITEBRAGGSCATTERER_H_ */ +#endif diff --git a/Code/Mantid/Framework/Kernel/src/NetworkProxyWin.cpp b/Code/Mantid/Framework/Kernel/src/NetworkProxyWin.cpp index 315e8eb6b0ea..eaab5392359d 100644 --- a/Code/Mantid/Framework/Kernel/src/NetworkProxyWin.cpp +++ b/Code/Mantid/Framework/Kernel/src/NetworkProxyWin.cpp @@ -2,6 +2,9 @@ #if defined(_WIN32) || defined(_WIN64) #include "MantidKernel/NetworkProxy.h" +// std +#include +// windows #include #include diff --git a/Code/Mantid/Framework/Kernel/src/ProgressBase.cpp b/Code/Mantid/Framework/Kernel/src/ProgressBase.cpp index afc3b4d5c080..b0da3a397808 100644 --- a/Code/Mantid/Framework/Kernel/src/ProgressBase.cpp +++ b/Code/Mantid/Framework/Kernel/src/ProgressBase.cpp @@ -174,6 +174,8 @@ namespace Kernel m_start = start; m_end = end; m_i = 0; + m_last_reported = 0; + m_timeElapsed->reset(); setNumSteps(nsteps); } diff --git a/Code/Mantid/MantidQt/CustomDialogs/src/LoadDialog.cpp b/Code/Mantid/MantidQt/CustomDialogs/src/LoadDialog.cpp index 6f92896ad552..ac4f0b602884 100644 --- a/Code/Mantid/MantidQt/CustomDialogs/src/LoadDialog.cpp +++ b/Code/Mantid/MantidQt/CustomDialogs/src/LoadDialog.cpp @@ -90,7 +90,7 @@ namespace MantidQt if( m_form.fileWidget->isValid() ) { if( m_form.fileWidget->getFilenames().size() == 1 ) - suggestion = QFileInfo(m_form.fileWidget->getFirstFilename()).baseName(); + suggestion = QFileInfo(m_form.fileWidget->getFirstFilename()).completeBaseName(); else suggestion = "MultiFiles"; } diff --git a/Code/Mantid/MantidQt/CustomInterfaces/CMakeLists.txt b/Code/Mantid/MantidQt/CustomInterfaces/CMakeLists.txt index 9a245f1e4e48..ac8a34bfda3f 100644 --- a/Code/Mantid/MantidQt/CustomInterfaces/CMakeLists.txt +++ b/Code/Mantid/MantidQt/CustomInterfaces/CMakeLists.txt @@ -25,6 +25,7 @@ set ( SRC_FILES src/IndirectMolDyn.cpp src/IndirectMoments.cpp src/IndirectNeutron.cpp + src/IndirectSassena.cpp src/IndirectSimulation.cpp src/IndirectSimulationTab.cpp src/IndirectSqw.cpp @@ -57,7 +58,10 @@ set ( SRC_FILES src/QtWorkspaceMementoModel.cpp src/Quasi.cpp src/RawFileMemento.cpp + src/ReflCatalogSearcher.cpp + src/ReflLegacyTransferStrategy.cpp src/ReflMainViewPresenter.cpp + src/ReflSearchModel.cpp src/ResNorm.cpp src/SANSAddFiles.cpp src/SANSDiagnostics.cpp @@ -103,6 +107,7 @@ set ( INC_FILES inc/MantidQtCustomInterfaces/IndirectMolDyn.h inc/MantidQtCustomInterfaces/IndirectMoments.h inc/MantidQtCustomInterfaces/IndirectNeutron.h + inc/MantidQtCustomInterfaces/IndirectSassena.h inc/MantidQtCustomInterfaces/IndirectSimulation.h inc/MantidQtCustomInterfaces/IndirectSimulationTab.h inc/MantidQtCustomInterfaces/IndirectSqw.h @@ -110,6 +115,7 @@ set ( INC_FILES inc/MantidQtCustomInterfaces/IndirectTransmission.h inc/MantidQtCustomInterfaces/IndirectTab.h inc/MantidQtCustomInterfaces/IReflPresenter.h + inc/MantidQtCustomInterfaces/IReflSearcher.h inc/MantidQtCustomInterfaces/JumpFit.h inc/MantidQtCustomInterfaces/MSDFit.h inc/MantidQtCustomInterfaces/MantidEV.h @@ -135,8 +141,12 @@ set ( INC_FILES inc/MantidQtCustomInterfaces/Muon/MuonAnalysisHelper.h inc/MantidQtCustomInterfaces/Muon/MuonAnalysisOptionTab.h inc/MantidQtCustomInterfaces/Muon/MuonAnalysisResultTableTab.h + inc/MantidQtCustomInterfaces/ReflCatalogSearcher.h + inc/MantidQtCustomInterfaces/ReflLegacyTransferStrategy.h inc/MantidQtCustomInterfaces/ReflMainView.h inc/MantidQtCustomInterfaces/ReflMainViewPresenter.h + inc/MantidQtCustomInterfaces/ReflSearchModel.h + inc/MantidQtCustomInterfaces/ReflTransferStrategy.h inc/MantidQtCustomInterfaces/QReflTableModel.h inc/MantidQtCustomInterfaces/QtReflMainView.h inc/MantidQtCustomInterfaces/QtReflOptionsDialog.h @@ -186,6 +196,7 @@ set ( MOC_FILES inc/MantidQtCustomInterfaces/Background.h inc/MantidQtCustomInterfaces/IndirectNeutron.h inc/MantidQtCustomInterfaces/IndirectMolDyn.h inc/MantidQtCustomInterfaces/IndirectMoments.h + inc/MantidQtCustomInterfaces/IndirectSassena.h inc/MantidQtCustomInterfaces/IndirectSimulation.h inc/MantidQtCustomInterfaces/IndirectSimulationTab.h inc/MantidQtCustomInterfaces/IndirectSqw.h @@ -209,6 +220,7 @@ set ( MOC_FILES inc/MantidQtCustomInterfaces/Background.h inc/MantidQtCustomInterfaces/Muon/MuonAnalysisHelper.h inc/MantidQtCustomInterfaces/Muon/MuonAnalysisOptionTab.h inc/MantidQtCustomInterfaces/Muon/MuonAnalysisResultTableTab.h + inc/MantidQtCustomInterfaces/ReflSearchModel.h inc/MantidQtCustomInterfaces/QReflTableModel.h inc/MantidQtCustomInterfaces/QtReflMainView.h inc/MantidQtCustomInterfaces/QtReflOptionsDialog.h @@ -234,6 +246,7 @@ set ( UI_FILES inc/MantidQtCustomInterfaces/CreateMDWorkspace.ui inc/MantidQtCustomInterfaces/IndirectLoadAscii.ui inc/MantidQtCustomInterfaces/IndirectNeutron.ui inc/MantidQtCustomInterfaces/IndirectMolDyn.ui + inc/MantidQtCustomInterfaces/IndirectSassena.ui inc/MantidQtCustomInterfaces/IndirectSimulation.ui inc/MantidQtCustomInterfaces/JumpFit.ui inc/MantidQtCustomInterfaces/Muon/ALCBaselineModellingView.ui @@ -264,6 +277,7 @@ set ( TEST_FILES IO_MuonGroupingTest.h MuonAnalysisHelperTest.h RawFileMementoTest.h + ReflLegacyTransferStrategyTest.h ReflMainViewPresenterTest.h WorkspaceInADSTest.h WorkspaceMementoTest.h diff --git a/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/IReflPresenter.h b/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/IReflPresenter.h index b3285e69101a..c7b71d8cd16b 100644 --- a/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/IReflPresenter.h +++ b/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/IReflPresenter.h @@ -59,6 +59,8 @@ namespace MantidQt CopySelectedFlag, CutSelectedFlag, PasteSelectedFlag, + SearchFlag, + TransferFlag, }; //Tell the presenter something happened diff --git a/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/IReflSearcher.h b/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/IReflSearcher.h new file mode 100644 index 000000000000..a9d1c8550449 --- /dev/null +++ b/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/IReflSearcher.h @@ -0,0 +1,45 @@ +#ifndef MANTID_CUSTOMINTERFACES_IREFLSEARCHER_H +#define MANTID_CUSTOMINTERFACES_IREFLSEARCHER_H + +#include + +#include "MantidQtCustomInterfaces/IReflPresenter.h" +#include "MantidAPI/ITableWorkspace.h" + +namespace MantidQt +{ + namespace CustomInterfaces + { + /** @class IReflSearcher + + IReflSearcher is an interface for search implementations used by IReflPresenter implementations. + + Copyright © 2011-14 ISIS Rutherford Appleton Laboratory & NScD Oak Ridge National Laboratory + + This file is part of Mantid. + + Mantid is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + Mantid is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + File change history is stored at: . + Code Documentation is available at: + */ + class IReflSearcher + { + public: + virtual ~IReflSearcher() {}; + virtual Mantid::API::ITableWorkspace_sptr search(const std::string& text, const std::string& instrument) = 0; + }; + } +} +#endif diff --git a/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/IndirectMolDyn.h b/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/IndirectMolDyn.h index 54e3ca5b83b8..000c1a164acd 100644 --- a/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/IndirectMolDyn.h +++ b/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/IndirectMolDyn.h @@ -15,10 +15,13 @@ namespace MantidQt public: IndirectMolDyn(QWidget * parent = 0); - // Inherited methods from IndirectForeignTab QString help() { return "IndirectMolDyn"; }; + + // Inherited methods from IndirectTab + void setup(); bool validate(); void run(); + /// Load default settings into the interface void loadSettings(const QSettings& settings); diff --git a/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/IndirectSassena.h b/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/IndirectSassena.h new file mode 100644 index 000000000000..dc373046b05a --- /dev/null +++ b/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/IndirectSassena.h @@ -0,0 +1,41 @@ +#ifndef MANTIDQTCUSTOMINTERFACES_INDIRECTSASSENA_H_ +#define MANTIDQTCUSTOMINTERFACES_INDIRECTSASSENA_H_ + +#include "ui_IndirectSassena.h" +#include "MantidQtCustomInterfaces/IndirectSimulationTab.h" + +namespace MantidQt +{ + namespace CustomInterfaces + { + class DLLExport IndirectSassena : public IndirectSimulationTab + { + Q_OBJECT + + public: + IndirectSassena(QWidget * parent = 0); + + QString help() { return "IndirectSassena"; }; + + void setup(); + bool validate(); + void run(); + + /// Load default settings into the interface + void loadSettings(const QSettings& settings); + + private slots: + /// Handle completion of the algorithm batch + void handleAlgorithmFinish(bool error); + + private: + /// The ui form + Ui::IndirectSassena m_uiForm; + /// Name of the output workspace group + QString m_outWsName; + + }; + } // namespace CustomInterfaces +} // namespace MantidQt + +#endif //MANTIDQTCUSTOMINTERFACES_INDIRECTSASSENA_H_ diff --git a/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/IndirectSassena.ui b/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/IndirectSassena.ui new file mode 100644 index 000000000000..db0f69caa544 --- /dev/null +++ b/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/IndirectSassena.ui @@ -0,0 +1,170 @@ + + + IndirectSassena + + + + 0 + 0 + 444 + 251 + + + + Form + + + + + + Input File + + + + 6 + + + + + + 0 + 0 + + + + + + + + .h5 + .hd5 + + + + + + + + Sample File: + + + + + + + + + + Options + + + + + + Time per Data Point: + + + + + + + <html><head/><body><p>The time in pico seconds between each consecutive data point.</p></body></html> + + + ps + + + 1000.000000000000000 + + + 1.000000000000000 + + + + + + + Sort by Q Vectors + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + 0 + 0 + + + + Output Options + + + + + + true + + + Plot Result + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Save Result + + + + + + + + + + + MantidQt::MantidWidgets::MWRunFiles + QWidget +
MantidQtMantidWidgets/MWRunFiles.h
+
+
+ + mwInputFile + sbTimeUnit + cbSortQ + chkPlot + chkSave + + + +
diff --git a/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/IndirectSimulation.h b/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/IndirectSimulation.h index e41c4934451e..3bffa70998b5 100644 --- a/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/IndirectSimulation.h +++ b/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/IndirectSimulation.h @@ -15,8 +15,8 @@ namespace MantidQt { namespace CustomInterfaces { - /** - This class defines the Indirect Simulation interface. It handles the creation of the interface window and + /** + This class defines the Indirect Simulation interface. It handles the creation of the interface window and handles the interaction between the child tabs on the window. @author Samuel Jackson, STFC @@ -39,7 +39,7 @@ namespace MantidQt along with this program. If not, see . File change history is stored at: - Code Documentation is available at: + Code Documentation is available at: */ class DLLExport IndirectSimulation : public MantidQt::API::UserSubWindow @@ -52,22 +52,22 @@ namespace MantidQt enum TabChoice { MOLDYN, + SASSENA, }; public: // public constructor, destructor and functions /// Default Constructor IndirectSimulation(QWidget *parent = 0); - ///Destructor + /// Destructor ~IndirectSimulation(); /// Interface name static std::string name() { return "Simulation"; } - // This interface's categories. + /// This interface's categories. static QString categoryInfo() { return "Indirect"; } + /// Setup tab UI virtual void initLayout(); private slots: - // Run the appropriate action depending based on the selected tab - /// Slot for clicking on the run button void runClicked(); /// Slot for clicking on the hlep button @@ -86,11 +86,12 @@ namespace MantidQt void handleDirectoryChange(Mantid::Kernel::ConfigValChangeNotification_ptr pNf); /// Map of tabs indexed by position on the window - std::map m_loadAsciiTabs; + std::map m_simulationTabs; /// Change Observer for ConfigService (monitors user directories) Poco::NObserver m_changeObserver; ///Main interface window Ui::IndirectSimulation m_uiForm; + }; } } diff --git a/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/IndirectSimulation.ui b/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/IndirectSimulation.ui index 9ec082cac946..0143af0267c7 100644 --- a/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/IndirectSimulation.ui +++ b/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/IndirectSimulation.ui @@ -31,6 +31,11 @@ MolDyn + + + Sassena + + diff --git a/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/IndirectSimulationTab.h b/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/IndirectSimulationTab.h index da6aae25aa45..2db3a71aa18b 100644 --- a/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/IndirectSimulationTab.h +++ b/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/IndirectSimulationTab.h @@ -1,8 +1,10 @@ #ifndef MANTID_CUSTOMINTERFACES_INDIRECTSIMULATIONTAB_H_ #define MANTID_CUSTOMINTERFACES_INDIRECTSIMULATIONTAB_H_ +#include "MantidAPI/AlgorithmManager.h" #include "MantidKernel/System.h" #include "MantidQtAPI/AlgorithmRunner.h" +#include "MantidQtCustomInterfaces/IndirectTab.h" #include #include @@ -14,10 +16,8 @@ namespace MantidQt This class defines a abstract base class for the different tabs of the Indirect Simulation interface. Any joint functionality shared between each of the tabs should be implemented here as well as defining shared member functions. - - @author Samuel Jackson, STFC - TODO: Make this inherit from IndirectTab (#10277) + @author Samuel Jackson, STFC Copyright © 2013 ISIS Rutherford Appleton Laboratory & NScD Oak Ridge National Laboratory @@ -40,7 +40,7 @@ namespace MantidQt Code Documentation is available at: */ - class DLLExport IndirectSimulationTab : public QWidget + class DLLExport IndirectSimulationTab : public IndirectTab { Q_OBJECT @@ -51,25 +51,9 @@ namespace MantidQt /// Returns a URL for the wiki help page for this interface QString tabHelpURL(); - /// Base methods implemented in derived classes virtual QString help() = 0; - virtual bool validate() = 0; - virtual void run() = 0; virtual void loadSettings(const QSettings& settings) = 0; - signals: - /// Send signal to parent window to execute python script - void executePythonScript(const QString& pyInput, bool output); - /// Send signal to parent window to show a message box to user - void showMessageBox(const QString& message); - - protected: - void runPythonScript(const QString& pyInput); - void runAlgorithm(const Mantid::API::IAlgorithm_sptr alg); - - private: - MantidQt::API::AlgorithmRunner m_algoRunner; - }; } // namespace CustomInterfaces } // namespace Mantid diff --git a/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/IndirectTab.h b/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/IndirectTab.h index 9e73bf40b269..327bcfbb2105 100644 --- a/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/IndirectTab.h +++ b/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/IndirectTab.h @@ -153,8 +153,8 @@ namespace CustomInterfaces signals: /// Send signal to parent window to show a message box to user void showMessageBox(const QString& message); - /// Send signal to parent window to execute python script - void runAsPythonScript(const QString& pyInput, bool output); + /// Run a python script + void runAsPythonScript(const QString & code, bool noOutput = false); protected: /// Overidden by child class. diff --git a/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/QtReflMainView.h b/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/QtReflMainView.h index 23e541383db2..5c180c9d9069 100644 --- a/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/QtReflMainView.h +++ b/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/QtReflMainView.h @@ -5,6 +5,7 @@ #include "MantidQtAPI/UserSubWindow.h" #include "MantidQtCustomInterfaces/ReflMainView.h" #include "MantidQtCustomInterfaces/IReflPresenter.h" +#include "MantidQtCustomInterfaces/ReflSearchModel.h" #include "MantidQtCustomInterfaces/QReflTableModel.h" #include #include @@ -51,6 +52,7 @@ namespace MantidQt //Connect the model virtual void showTable(QReflTableModel_sptr model); + virtual void showSearch(ReflSearchModel_sptr model); //Dialog/Prompt methods virtual std::string askUserString(const std::string& prompt, const std::string& title, const std::string& defaultValue); @@ -72,10 +74,12 @@ namespace MantidQt //Accessor methods virtual std::set getSelectedRows() const; + virtual std::set getSelectedSearchRows() const; virtual std::string getSearchInstrument() const; virtual std::string getProcessInstrument() const; virtual std::string getWorkspaceToOpen() const; virtual std::string getClipboard() const; + virtual std::string getSearchString() const; virtual boost::shared_ptr getPresenter() const; @@ -84,8 +88,9 @@ namespace MantidQt virtual void initLayout(); //the presenter boost::shared_ptr m_presenter; - //the model + //the models QReflTableModel_sptr m_model; + ReflSearchModel_sptr m_searchModel; //the interface Ui::reflMainWidget ui; //the workspace the user selected to open @@ -107,10 +112,13 @@ namespace MantidQt void on_actionPasteSelected_triggered(); void on_actionExpandSelection_triggered(); void on_actionOptionsDialog_triggered(); + void on_actionSearch_triggered(); + void on_actionTransfer_triggered(); void setModel(QString name); void tableUpdated(const QModelIndex& topLeft, const QModelIndex& bottomRight); void showContextMenu(const QPoint& pos); + void showSearchContextMenu(const QPoint& pos); }; diff --git a/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/ReflCatalogSearcher.h b/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/ReflCatalogSearcher.h new file mode 100644 index 000000000000..c00d2afd7956 --- /dev/null +++ b/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/ReflCatalogSearcher.h @@ -0,0 +1,42 @@ +#ifndef MANTID_CUSTOMINTERFACES_REFLCATALOGSEARCHER_H +#define MANTID_CUSTOMINTERFACES_REFLCATALOGSEARCHER_H + +#include "MantidQtCustomInterfaces/IReflSearcher.h" + +namespace MantidQt +{ + namespace CustomInterfaces + { + /** @class ReflCatalogSearcher + + ReflCatalogSearcher implements IReflSearcher to provide ICAT search functionality. + + Copyright © 2011-14 ISIS Rutherford Appleton Laboratory & NScD Oak Ridge National Laboratory + + This file is part of Mantid. + + Mantid is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + Mantid is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + File change history is stored at: . + Code Documentation is available at: + */ + class ReflCatalogSearcher : public IReflSearcher + { + public: + virtual ~ReflCatalogSearcher() {}; + Mantid::API::ITableWorkspace_sptr search(const std::string& text, const std::string& instrument); + }; + } +} +#endif diff --git a/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/ReflLegacyTransferStrategy.h b/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/ReflLegacyTransferStrategy.h new file mode 100644 index 000000000000..c3849db0bcad --- /dev/null +++ b/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/ReflLegacyTransferStrategy.h @@ -0,0 +1,42 @@ +#ifndef MANTID_CUSTOMINTERFACES_REFLLEGACYTRANSFERSTRATEGY_H +#define MANTID_CUSTOMINTERFACES_REFLLEGACYTRANSFERSTRATEGY_H + +#include "MantidKernel/System.h" +#include "MantidQtCustomInterfaces/ReflTransferStrategy.h" + +namespace MantidQt +{ + namespace CustomInterfaces + { + + /** ReflLegacyTransferStrategy : Replicates the old Reflectometry UI's transfer behaviour. + + Copyright © 2014 ISIS Rutherford Appleton Laboratory & NScD Oak Ridge National Laboratory + + This file is part of Mantid. + + Mantid is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + Mantid is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + File change history is stored at: + Code Documentation is available at: + */ + class DLLExport ReflLegacyTransferStrategy : public ReflTransferStrategy + { + public: + std::vector > transferRuns(const std::map& runRows); + }; + } +} + +#endif diff --git a/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/ReflMainView.h b/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/ReflMainView.h index a442a9eebf85..aa5bf8eb1bd9 100644 --- a/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/ReflMainView.h +++ b/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/ReflMainView.h @@ -3,6 +3,7 @@ #include "MantidKernel/System.h" #include "MantidQtCustomInterfaces/IReflPresenter.h" +#include "MantidQtCustomInterfaces/ReflSearchModel.h" #include "MantidQtCustomInterfaces/QReflTableModel.h" #include "MantidQtMantidWidgets/HintStrategy.h" @@ -43,6 +44,7 @@ namespace MantidQt //Connect the model virtual void showTable(QReflTableModel_sptr model) = 0; + virtual void showSearch(ReflSearchModel_sptr model) = 0; //Dialog/Prompt methods virtual std::string askUserString(const std::string& prompt, const std::string& title, const std::string& defaultValue) = 0; @@ -64,10 +66,12 @@ namespace MantidQt //Accessor methods virtual std::set getSelectedRows() const = 0; + virtual std::set getSelectedSearchRows() const = 0; virtual std::string getSearchInstrument() const = 0; virtual std::string getProcessInstrument() const = 0; virtual std::string getWorkspaceToOpen() const = 0; virtual std::string getClipboard() const = 0; + virtual std::string getSearchString() const = 0; virtual boost::shared_ptr getPresenter() const = 0; }; diff --git a/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/ReflMainViewPresenter.h b/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/ReflMainViewPresenter.h index d87822a8b85b..bbc04632bf7b 100644 --- a/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/ReflMainViewPresenter.h +++ b/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/ReflMainViewPresenter.h @@ -6,7 +6,9 @@ #include "MantidAPI/MatrixWorkspace.h" #include "MantidKernel/System.h" #include "MantidQtCustomInterfaces/IReflPresenter.h" +#include "MantidQtCustomInterfaces/IReflSearcher.h" #include "MantidQtCustomInterfaces/ReflMainView.h" +#include "MantidQtCustomInterfaces/ReflTransferStrategy.h" #include "MantidQtCustomInterfaces/QReflTableModel.h" #include @@ -43,7 +45,7 @@ namespace MantidQt class DLLExport ReflMainViewPresenter: public IReflPresenter { public: - ReflMainViewPresenter(ReflMainView* view); + ReflMainViewPresenter(ReflMainView* view, boost::shared_ptr searcher = boost::shared_ptr()); virtual ~ReflMainViewPresenter(); virtual void notify(IReflPresenter::Flag flag); virtual const std::map& options() const; @@ -53,8 +55,9 @@ namespace MantidQt protected: //the workspace the model is currently representing Mantid::API::ITableWorkspace_sptr m_ws; - //the model the table is currently representing + //the models QReflTableModel_sptr m_model; + ReflSearchModel_sptr m_searchModel; //the name of the workspace/table/model in the ADS, blank if unsaved std::string m_wsName; //the view we're managing @@ -63,6 +66,9 @@ namespace MantidQt bool m_tableDirty; //stores the user options for the presenter std::map m_options; + //the search implementation + boost::shared_ptr m_searcher; + boost::shared_ptr m_transferStrategy; //process selected rows virtual void process(); @@ -110,6 +116,9 @@ namespace MantidQt virtual void openTable(); virtual void saveTable(); virtual void saveTableAs(); + //searching + virtual void search(); + virtual void transfer(); //options void showOptionsDialog(); void initOptions(); diff --git a/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/ReflMainWidget.ui b/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/ReflMainWidget.ui index 5e71674b7306..e20468a1092e 100644 --- a/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/ReflMainWidget.ui +++ b/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/ReflMainWidget.ui @@ -90,10 +90,13 @@ Select the instrument to search with + + Specifies which instrument you're searching for data from. + - + 0 @@ -101,15 +104,15 @@ - RB Search: + Investigation Id: - textRB + textSearch - + 0 @@ -125,6 +128,9 @@ Investigation to search for + + Specifies the investigation id that you are searching for runs from. + Qt::ImhDigitsOnly @@ -144,6 +150,9 @@ Search + + Searches ICAT for runs from the given instrument with the given investigation id. + Search @@ -152,12 +161,21 @@ - - - Search results + + + Qt::CustomContextMenu - - false + + QAbstractItemView::ExtendedSelection + + + QAbstractItemView::SelectRows + + + 60 + + + 20 true @@ -165,19 +183,9 @@ false - - false + + 20 - - - Run # - - - - - Title - - @@ -196,18 +204,12 @@ - - - - 0 - 0 - - - - Add the selected run to the table - + - Add Run + Transfer + + + Qt::ToolButtonTextBesideIcon @@ -236,6 +238,7 @@ QToolBar{border: none;} + @@ -354,7 +357,7 @@ - Table + &Reflectometry @@ -374,7 +377,7 @@ - Row + &Edit @@ -540,14 +543,71 @@ Ctrl+X + + + + :/folder.png:/folder.png + + + Search + + + + + + :/append_drag_curves.png:/append_drag_curves.png + + + Transfer + + + Transfer the selected run(s) to the processing table. + + + Transfers the selected runs into the processing table. + + comboSearchInstrument - tableRuns + tableSearchResults viewTable - + + + buttonSearch + clicked() + actionSearch + trigger() + + + 217 + 143 + + + -1 + -1 + + + + + textSearch + returnPressed() + actionSearch + trigger() + + + 228 + 112 + + + -1 + -1 + + + + diff --git a/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/ReflSearchModel.h b/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/ReflSearchModel.h new file mode 100644 index 000000000000..9659554a59ab --- /dev/null +++ b/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/ReflSearchModel.h @@ -0,0 +1,67 @@ +#ifndef MANTID_CUSTOMINTERFACES_REFLSEARCHMODEL_H_ +#define MANTID_CUSTOMINTERFACES_REFLSEARCHMODEL_H_ + +#include "MantidAPI/ITableWorkspace.h" +#include +#include +#include +#include + +namespace MantidQt +{ + namespace CustomInterfaces + { + + /** ReflSearchModel : Provides a QAbstractTableModel for a Mantid ITableWorkspace of Reflectometry search results. + + Copyright © 2014 ISIS Rutherford Appleton Laboratory & NScD Oak Ridge National Laboratory + + This file is part of Mantid. + + Mantid is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + Mantid is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + File change history is stored at: + Code Documentation is available at: + */ + class ReflSearchModel : public QAbstractTableModel + { + Q_OBJECT + public: + ReflSearchModel(Mantid::API::ITableWorkspace_sptr tableWorkspace); + virtual ~ReflSearchModel(); + //row and column counts + int rowCount(const QModelIndex &parent = QModelIndex()) const; + int columnCount(const QModelIndex &parent = QModelIndex()) const; + //get data from a cell + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; + //get header data for the table + QVariant headerData(int section, Qt::Orientation orientation, int role) const; + //get flags for a cell + Qt::ItemFlags flags(const QModelIndex &index) const; + + protected: + //vector of the run numbers + std::vector m_runs; + + //maps each run number to its description + std::map m_descriptions; + }; + + /// Typedef for a shared pointer to \c ReflSearchModel + typedef boost::shared_ptr ReflSearchModel_sptr; + + } // namespace CustomInterfaces +} // namespace Mantid + +#endif /* MANTID_CUSTOMINTERFACES_REFLSEARCHMODEL_H_ */ diff --git a/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/ReflTransferStrategy.h b/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/ReflTransferStrategy.h new file mode 100644 index 000000000000..781d8b563f64 --- /dev/null +++ b/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/ReflTransferStrategy.h @@ -0,0 +1,49 @@ +#ifndef MANTID_CUSTOMINTERFACES_REFLTRANSFERSTRATEGY_H +#define MANTID_CUSTOMINTERFACES_REFLTRANSFERSTRATEGY_H + +#include +#include +#include + +namespace MantidQt +{ + namespace CustomInterfaces + { + + /** ReflTransferStrategy : Provides an stratgegy for transferring runs from search results to a format suitable for processing. + + Copyright © 2014 ISIS Rutherford Appleton Laboratory & NScD Oak Ridge National Laboratory + + This file is part of Mantid. + + Mantid is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + Mantid is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + File change history is stored at: + Code Documentation is available at: + */ + class ReflTransferStrategy + { + public: + virtual ~ReflTransferStrategy() {}; + + /** + * @param runRows : A map where the keys are the runs and the values the descriptions + * @returns A vector of maps where each map represents a row, with values for "runs", "theta", and "group" + */ + virtual std::vector > transferRuns(const std::map& runRows) = 0; + }; + } +} + +#endif diff --git a/Code/Mantid/MantidQt/CustomInterfaces/src/IndirectMolDyn.cpp b/Code/Mantid/MantidQt/CustomInterfaces/src/IndirectMolDyn.cpp index ffe02756868a..bc89ad7aa716 100644 --- a/Code/Mantid/MantidQt/CustomInterfaces/src/IndirectMolDyn.cpp +++ b/Code/Mantid/MantidQt/CustomInterfaces/src/IndirectMolDyn.cpp @@ -1,7 +1,5 @@ #include "MantidQtCustomInterfaces/IndirectMolDyn.h" -#include "MantidAPI/AlgorithmManager.h" - #include #include @@ -20,6 +18,10 @@ namespace MantidQt connect(m_uiForm.ckResolution, SIGNAL(toggled(bool)), m_uiForm.dsResolution, SLOT(setEnabled(bool))); } + void IndirectMolDyn::setup() + { + } + /** * Validate the form to check the program can be run * diff --git a/Code/Mantid/MantidQt/CustomInterfaces/src/IndirectSassena.cpp b/Code/Mantid/MantidQt/CustomInterfaces/src/IndirectSassena.cpp new file mode 100644 index 000000000000..457718358c6e --- /dev/null +++ b/Code/Mantid/MantidQt/CustomInterfaces/src/IndirectSassena.cpp @@ -0,0 +1,108 @@ +#include "MantidQtCustomInterfaces/IndirectSassena.h" + +#include +#include + +namespace MantidQt +{ + namespace CustomInterfaces + { + IndirectSassena::IndirectSassena(QWidget * parent) : + IndirectSimulationTab(parent) + { + m_uiForm.setupUi(parent); + connect(m_batchAlgoRunner, SIGNAL(batchComplete(bool)), this, SLOT(handleAlgorithmFinish(bool))); + } + + void IndirectSassena::setup() + { + } + + /** + * Validate the form to check the program can be run. + * + * @return Whether the form was valid + */ + bool IndirectSassena::validate() + { + // There is very little to actually be invalid here + // that was not already done via restrictions on input + return true; + } + + /** + * Configures and executes the LoadSassena algorithm. + */ + void IndirectSassena::run() + { + using namespace Mantid::API; + using MantidQt::API::BatchAlgorithmRunner; + + QString inputFileName = m_uiForm.mwInputFile->getFirstFilename(); + QFileInfo inputFileInfo(inputFileName); + m_outWsName = inputFileInfo.baseName(); + bool save = m_uiForm.chkSave->isChecked(); + + // If the workspace group already exists then remove it + if(AnalysisDataService::Instance().doesExist(m_outWsName.toStdString())) + AnalysisDataService::Instance().deepRemoveGroup(m_outWsName.toStdString()); + + IAlgorithm_sptr sassenaAlg = AlgorithmManager::Instance().create("LoadSassena"); + sassenaAlg->initialize(); + + sassenaAlg->setProperty("Filename", inputFileName.toStdString()); + sassenaAlg->setProperty("SortByQVectors", m_uiForm.cbSortQ->isChecked()); + sassenaAlg->setProperty("TimeUnit", m_uiForm.sbTimeUnit->value()); + sassenaAlg->setProperty("OutputWorkspace", m_outWsName.toStdString()); + + m_batchAlgoRunner->addAlgorithm(sassenaAlg); + + BatchAlgorithmRunner::AlgorithmRuntimeProps inputFromSassenaAlg; + inputFromSassenaAlg["InputWorkspace"] = m_outWsName.toStdString(); + + if(save) + { + QString saveFilename = m_outWsName + ".nxs"; + + IAlgorithm_sptr saveAlg = AlgorithmManager::Instance().create("SaveNexus"); + saveAlg->initialize(); + + saveAlg->setProperty("Filename", saveFilename.toStdString()); + + m_batchAlgoRunner->addAlgorithm(saveAlg, inputFromSassenaAlg); + } + + m_batchAlgoRunner->executeBatchAsync(); + } + + /** + * Handles completion of the algorithm batch. + * + * @param error If the batch was stopped due to error + */ + void IndirectSassena::handleAlgorithmFinish(bool error) + { + bool plot = m_uiForm.chkPlot->isChecked(); + + // Nothing to do if the algorithm failed or we do not want to plot + if(error || !plot) + return; + + // Plot the output workspace group + QString pyInput = "plotSpectrum('" + m_outWsName + "', 0)\n"; + emit runAsPythonScript(pyInput); + } + + /** + * Set the data selectors to use the default save directory + * when browsing for input files. + * + * @param settings :: The settings to loading into the interface + */ + void IndirectSassena::loadSettings(const QSettings& settings) + { + m_uiForm.mwInputFile->readSettings(settings.group()); + } + + } // namespace CustomInterfaces +} // namespace MantidQt diff --git a/Code/Mantid/MantidQt/CustomInterfaces/src/IndirectSimulation.cpp b/Code/Mantid/MantidQt/CustomInterfaces/src/IndirectSimulation.cpp index 9a62239a5252..649cdfa022b9 100644 --- a/Code/Mantid/MantidQt/CustomInterfaces/src/IndirectSimulation.cpp +++ b/Code/Mantid/MantidQt/CustomInterfaces/src/IndirectSimulation.cpp @@ -2,11 +2,12 @@ #include "MantidQtAPI/ManageUserDirectories.h" #include "MantidQtCustomInterfaces/IndirectSimulation.h" #include "MantidQtCustomInterfaces/IndirectMolDyn.h" +#include "MantidQtCustomInterfaces/IndirectSassena.h" #include #include -//Add this class to the list of specialised dialogs in this namespace +// Add this class to the list of specialised dialogs in this namespace namespace MantidQt { namespace CustomInterfaces @@ -20,30 +21,34 @@ using namespace MantidQt::CustomInterfaces; IndirectSimulation::IndirectSimulation(QWidget *parent) : UserSubWindow(parent), m_changeObserver(*this, &IndirectSimulation::handleDirectoryChange) { +} +IndirectSimulation::~IndirectSimulation() +{ } void IndirectSimulation::initLayout() { m_uiForm.setupUi(this); - + // Connect Poco Notification Observer Mantid::Kernel::ConfigService::Instance().addObserver(m_changeObserver); - //insert each tab into the interface on creation - m_loadAsciiTabs.insert(std::make_pair(MOLDYN, new IndirectMolDyn(m_uiForm.IndirectSimulationTabs->widget(MOLDYN)))); + // Insert each tab into the interface on creation + m_simulationTabs.insert(std::make_pair(MOLDYN, new IndirectMolDyn(m_uiForm.IndirectSimulationTabs->widget(MOLDYN)))); + m_simulationTabs.insert(std::make_pair(SASSENA, new IndirectSassena(m_uiForm.IndirectSimulationTabs->widget(SASSENA)))); - //Connect each tab to the actions available in this GUI + // Connect each tab to the actions available in this GUI std::map::iterator iter; - for (iter = m_loadAsciiTabs.begin(); iter != m_loadAsciiTabs.end(); ++iter) + for (iter = m_simulationTabs.begin(); iter != m_simulationTabs.end(); ++iter) { - connect(iter->second, SIGNAL(executePythonScript(const QString&, bool)), this, SIGNAL(runAsPythonScript(const QString&, bool))); + connect(iter->second, SIGNAL(runAsPythonScript(const QString&, bool)), this, SIGNAL(runAsPythonScript(const QString&, bool))); connect(iter->second, SIGNAL(showMessageBox(const QString&)), this, SLOT(showMessageBox(const QString&))); } loadSettings(); - //Connect statements for the buttons shared between all tabs on the Indirect Bayes interface + // Connect statements for the buttons shared between all tabs on the Indirect Bayes interface connect(m_uiForm.pbRun, SIGNAL(clicked()), this, SLOT(runClicked())); connect(m_uiForm.pbHelp, SIGNAL(clicked()), this, SLOT(helpClicked())); connect(m_uiForm.pbManageDirs, SIGNAL(clicked()), this, SLOT(manageUserDirectories())); @@ -88,7 +93,7 @@ void IndirectSimulation::loadSettings() settings.setValue("last_directory", saveDir); std::map::iterator iter; - for (iter = m_loadAsciiTabs.begin(); iter != m_loadAsciiTabs.end(); ++iter) + for (iter = m_simulationTabs.begin(); iter != m_simulationTabs.end(); ++iter) { iter->second->loadSettings(settings); } @@ -96,22 +101,17 @@ void IndirectSimulation::loadSettings() settings.endGroup(); } - /** * Slot to run the underlying algorithm code based on the currently selected * tab. - * + * * This method checks the tabs validate method is passing before calling * the run method. */ void IndirectSimulation::runClicked() { int tabIndex = m_uiForm.IndirectSimulationTabs->currentIndex(); - - if(m_loadAsciiTabs[tabIndex]->validate()) - { - m_loadAsciiTabs[tabIndex]->run(); - } + m_simulationTabs[tabIndex]->runTab(); } /** @@ -121,7 +121,7 @@ void IndirectSimulation::runClicked() void IndirectSimulation::helpClicked() { int tabIndex = m_uiForm.IndirectSimulationTabs->currentIndex(); - QString url = m_loadAsciiTabs[tabIndex]->tabHelpURL(); + QString url = m_simulationTabs[tabIndex]->tabHelpURL(); QDesktopServices::openUrl(QUrl(url)); } @@ -139,14 +139,10 @@ void IndirectSimulation::manageUserDirectories() /** * Slot to wrap the protected showInformationBox method defined * in UserSubWindow and provide access to composed tabs. - * + * * @param message :: The message to display in the message box */ void IndirectSimulation::showMessageBox(const QString& message) { showInformationBox(message); } - -IndirectSimulation::~IndirectSimulation() -{ -} diff --git a/Code/Mantid/MantidQt/CustomInterfaces/src/IndirectSimulationTab.cpp b/Code/Mantid/MantidQt/CustomInterfaces/src/IndirectSimulationTab.cpp index f76c10a40b0b..47d7cef49b87 100644 --- a/Code/Mantid/MantidQt/CustomInterfaces/src/IndirectSimulationTab.cpp +++ b/Code/Mantid/MantidQt/CustomInterfaces/src/IndirectSimulationTab.cpp @@ -11,8 +11,7 @@ namespace MantidQt //---------------------------------------------------------------------------------------------- /** Constructor */ - IndirectSimulationTab::IndirectSimulationTab(QWidget * parent) : QWidget(parent), - m_algoRunner(parent) + IndirectSimulationTab::IndirectSimulationTab(QWidget * parent) : IndirectTab(parent) { } @@ -25,33 +24,12 @@ namespace MantidQt /** * Method to build a URL to the appropriate page on the wiki for this tab. - * + * * @return The URL to the wiki page */ QString IndirectSimulationTab::tabHelpURL() - { - return "http://www.mantidproject.org/IndirectSimualtion:" + help(); - } - - /** - * Emits a signal to run a python script using the method in the parent - * UserSubWindow - * - * @param pyInput :: A string of python code to execute - */ - void IndirectSimulationTab::runPythonScript(const QString& pyInput) { - emit executePythonScript(pyInput, false); - } - - /** - * Runs an algorithm async from the UI thread. - * - * @param alg Configured algorithm to run - */ - void IndirectSimulationTab::runAlgorithm(const IAlgorithm_sptr alg) - { - m_algoRunner.startAlgorithm(alg); + return "http://www.mantidproject.org/IndirectSimualtion:" + help(); } } diff --git a/Code/Mantid/MantidQt/CustomInterfaces/src/QtReflMainView.cpp b/Code/Mantid/MantidQt/CustomInterfaces/src/QtReflMainView.cpp index 31db3c7987cb..ae0de1644182 100644 --- a/Code/Mantid/MantidQt/CustomInterfaces/src/QtReflMainView.cpp +++ b/Code/Mantid/MantidQt/CustomInterfaces/src/QtReflMainView.cpp @@ -37,16 +37,19 @@ namespace MantidQt ui.setupUi(this); ui.buttonProcess->setDefaultAction(ui.actionProcess); + ui.buttonTransfer->setDefaultAction(ui.actionTransfer); //Expand the process runs column at the expense of the search column ui.splitterTables->setStretchFactor(0, 0); ui.splitterTables->setStretchFactor(1, 1); - //Allow rows to be reordered + //Allow rows and columns to be reordered ui.viewTable->verticalHeader()->setMovable(true); + ui.viewTable->horizontalHeader()->setMovable(true); //Custom context menu for table connect(ui.viewTable, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(showContextMenu(const QPoint&))); + connect(ui.tableSearchResults, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(showSearchContextMenu(const QPoint&))); //Finally, create a presenter to do the thinking for us m_presenter = boost::shared_ptr(new ReflMainViewPresenter(this)); @@ -75,6 +78,17 @@ namespace MantidQt ui.viewTable->resizeColumnsToContents(); } + /** + Set a new model for search results + @param model : the model to be attached to the search results + */ + void QtReflMainView::showSearch(ReflSearchModel_sptr model) + { + m_searchModel = model; + ui.tableSearchResults->setModel(m_searchModel.get()); + ui.tableSearchResults->resizeColumnsToContents(); + } + /** Set the list of tables the user is offered to open @param tables : the names of the tables in the ADS @@ -208,6 +222,22 @@ namespace MantidQt m_presenter->notify(IReflPresenter::OptionsDialogFlag); } + /** + This slot notifies the presenter that the "search" button has been pressed + */ + void QtReflMainView::on_actionSearch_triggered() + { + m_presenter->notify(IReflPresenter::SearchFlag); + } + + /** + This slot notifies the presenter that the "transfer" button has been pressed + */ + void QtReflMainView::on_actionTransfer_triggered() + { + m_presenter->notify(IReflPresenter::TransferFlag); + } + /** This slot notifies the presenter that the table has been updated/changed by the user */ @@ -247,6 +277,21 @@ namespace MantidQt menu->popup(ui.viewTable->viewport()->mapToGlobal(pos)); } + /** + This slot is triggered when the user right clicks on the search results table + @param pos : The position of the right click within the table + */ + void QtReflMainView::showSearchContextMenu(const QPoint& pos) + { + if(!ui.tableSearchResults->indexAt(pos).isValid()) + return; + + //parent widget takes ownership of QMenu + QMenu* menu = new QMenu(this); + menu->addAction(ui.actionTransfer); + menu->popup(ui.tableSearchResults->viewport()->mapToGlobal(pos)); + } + /** Show an information dialog @param prompt : The prompt to appear on the dialog @@ -401,15 +446,35 @@ namespace MantidQt /** Get the indices of the highlighted rows - @returns a vector of unsigned ints contianing the highlighted row numbers + @returns a set of ints containing the highlighted row numbers */ std::set QtReflMainView::getSelectedRows() const { - auto selectedRows = ui.viewTable->selectionModel()->selectedRows(); std::set rows; - for(auto it = selectedRows.begin(); it != selectedRows.end(); ++it) - rows.insert(it->row()); + auto selectionModel = ui.viewTable->selectionModel(); + if(selectionModel) + { + auto selectedRows = selectionModel->selectedRows(); + for(auto it = selectedRows.begin(); it != selectedRows.end(); ++it) + rows.insert(it->row()); + } + return rows; + } + /** + Get the indices of the highlighted search result rows + @returns a set of ints containing the selected row numbers + */ + std::set QtReflMainView::getSelectedSearchRows() const + { + std::set rows; + auto selectionModel = ui.tableSearchResults->selectionModel(); + if(selectionModel) + { + auto selectedRows = selectionModel->selectedRows(); + for(auto it = selectedRows.begin(); it != selectedRows.end(); ++it) + rows.insert(it->row()); + } return rows; } @@ -440,5 +505,14 @@ namespace MantidQt return QApplication::clipboard()->text().toStdString(); } + /** + Get the string the user wants to search for. + @returns The search string + */ + std::string QtReflMainView::getSearchString() const + { + return ui.textSearch->text().toStdString(); + } + } // namespace CustomInterfaces } // namespace Mantid diff --git a/Code/Mantid/MantidQt/CustomInterfaces/src/ReflCatalogSearcher.cpp b/Code/Mantid/MantidQt/CustomInterfaces/src/ReflCatalogSearcher.cpp new file mode 100644 index 000000000000..b2600f66bb04 --- /dev/null +++ b/Code/Mantid/MantidQt/CustomInterfaces/src/ReflCatalogSearcher.cpp @@ -0,0 +1,69 @@ +#include "MantidQtCustomInterfaces/ReflCatalogSearcher.h" + +#include "MantidAPI/AlgorithmManager.h" +#include "MantidAPI/CatalogManager.h" + +using namespace Mantid::API; + +namespace MantidQt +{ + namespace CustomInterfaces + { + ITableWorkspace_sptr ReflCatalogSearcher::search(const std::string& text, const std::string& instrument) + { + auto sessions = CatalogManager::Instance().getActiveSessions(); + if(sessions.empty()) + throw std::runtime_error("You are not logged into any catalogs."); + + const std::string sessionId = sessions.front()->getSessionId(); + + auto algSearch = AlgorithmManager::Instance().create("CatalogGetDataFiles"); + algSearch->initialize(); + algSearch->setChild(true); + algSearch->setLogging(false); + algSearch->setProperty("Session", sessionId); + algSearch->setProperty("InvestigationId", text); + algSearch->setProperty("OutputWorkspace", "_ReflSearchResults"); + algSearch->execute(); + ITableWorkspace_sptr results = algSearch->getProperty("OutputWorkspace"); + + //Now, tidy up the data + std::set toRemove; + for(size_t i = 0; i < results->rowCount(); ++i) + { + std::string& run = results->String(i,0); + + //Too short to be more than ".raw" + if(run.size() < 5) + { + toRemove.insert(i); + } + //If this isn't the right instrument, remove it + else if(run.substr(0, instrument.size()) != instrument) + { + toRemove.insert(i); + } + //If it's not a raw file, remove it + else if(run.substr(run.size() - 4, 4) != ".raw") + { + toRemove.insert(i); + } + + //It's a valid run, so let's trim the instrument prefix and ".raw" suffix + run = run.substr(instrument.size(), run.size() - (instrument.size() + 4)); + + //Let's also get rid of any leading zeros + size_t numZeros = 0; + while(run[numZeros] == '0') + numZeros++; + run = run.substr(numZeros, run.size() - numZeros); + } + + //Sets are sorted so if we go from back to front we won't trip over ourselves + for(auto row = toRemove.rbegin(); row != toRemove.rend(); ++row) + results->removeRow(*row); + + return results; + } + } +} diff --git a/Code/Mantid/MantidQt/CustomInterfaces/src/ReflLegacyTransferStrategy.cpp b/Code/Mantid/MantidQt/CustomInterfaces/src/ReflLegacyTransferStrategy.cpp new file mode 100644 index 000000000000..58247c202622 --- /dev/null +++ b/Code/Mantid/MantidQt/CustomInterfaces/src/ReflLegacyTransferStrategy.cpp @@ -0,0 +1,78 @@ +#include "MantidQtCustomInterfaces/ReflLegacyTransferStrategy.h" + +#include +#include +#include + +namespace MantidQt +{ + namespace CustomInterfaces + { + std::vector > ReflLegacyTransferStrategy::transferRuns(const std::map& runRows) + { + /* + * If the descriptions are the same except for theta: same group, different rows. + * If the descriptions are the same including theta: same row with runs separated by '+' + * We always prefill theta if we can. + */ + + //maps descriptions to runs. Multiple runs are joined with '+' + std::map runsByDesc; + //Counter used to feed fresh group ids + int nextGroupId = 0; + //maps a description to a group. If descriptions only differ by theta, they'll share a group + std::map groupsByDesc; + //maps descriptions to the value of theta they contain + std::map thetaByDesc; + + //Iterate over the input and build the maps + for(auto rowIt = runRows.begin(); rowIt != runRows.end(); ++rowIt) + { + const std::string run = rowIt->first; + const std::string desc = rowIt->second; + std::string cleanDesc = desc; + + //See if theta is in the description + static boost::regex regexTheta("(?|th[:=](?[0-9.]+)|in (?[0-9.]+) theta)"); + boost::smatch matches; + if(boost::regex_search(desc, matches, regexTheta)) + { + //We have theta. Let's get a clean description + size_t matchOffset = matches.position("theta"); + const std::string theta = matches["theta"].str(); + const std::string descPreTheta = desc.substr(0, matchOffset); + const std::string descPostTheta = desc.substr(matchOffset + theta.length(), std::string::npos); + cleanDesc = descPreTheta + "?" + descPostTheta; + thetaByDesc[desc] = theta; + } + + //map the description to the run, making sure to join with a + if one already exists + const std::string prevRun = runsByDesc[desc]; + if(prevRun.empty()) + runsByDesc[desc] = run; + else + runsByDesc[desc] = prevRun + "+" + run; + + //If there isn't a group for this description (ignoring differences in theta) yet, make one + if(groupsByDesc[cleanDesc].empty()) + groupsByDesc[cleanDesc] = boost::lexical_cast(nextGroupId++); + + //Assign this description to the group it belongs to + groupsByDesc[desc] = groupsByDesc[cleanDesc]; + } + + //All the data we need is now properly organised, so we can quickly throw out the rows needed + std::vector > output; + for(auto run = runsByDesc.begin(); run != runsByDesc.end(); ++run) + { + std::map row; + row["runs"] = run->second; + row["theta"] = thetaByDesc[run->first]; + row["group"] = groupsByDesc[run->first]; + output.push_back(row); + } + std::sort(output.begin(), output.end()); + return output; + } + } +} diff --git a/Code/Mantid/MantidQt/CustomInterfaces/src/ReflMainViewPresenter.cpp b/Code/Mantid/MantidQt/CustomInterfaces/src/ReflMainViewPresenter.cpp index 774515f285da..c0f376f78baa 100644 --- a/Code/Mantid/MantidQt/CustomInterfaces/src/ReflMainViewPresenter.cpp +++ b/Code/Mantid/MantidQt/CustomInterfaces/src/ReflMainViewPresenter.cpp @@ -6,7 +6,10 @@ #include "MantidKernel/Strings.h" #include "MantidKernel/TimeSeriesProperty.h" #include "MantidKernel/Utils.h" +#include "MantidQtCustomInterfaces/ReflCatalogSearcher.h" +#include "MantidQtCustomInterfaces/ReflLegacyTransferStrategy.h" #include "MantidQtCustomInterfaces/ReflMainView.h" +#include "MantidQtCustomInterfaces/ReflSearchModel.h" #include "MantidQtCustomInterfaces/QReflTableModel.h" #include "MantidQtCustomInterfaces/QtReflOptionsDialog.h" #include "MantidQtMantidWidgets/AlgorithmHintStrategy.h" @@ -104,9 +107,11 @@ namespace MantidQt { namespace CustomInterfaces { - ReflMainViewPresenter::ReflMainViewPresenter(ReflMainView* view): + ReflMainViewPresenter::ReflMainViewPresenter(ReflMainView* view, boost::shared_ptr searcher): m_view(view), m_tableDirty(false), + m_searcher(searcher), + m_transferStrategy(new ReflLegacyTransferStrategy()), m_addObserver(*this, &ReflMainViewPresenter::handleAddEvent), m_remObserver(*this, &ReflMainViewPresenter::handleRemEvent), m_clearObserver(*this, &ReflMainViewPresenter::handleClearEvent), @@ -166,6 +171,10 @@ namespace MantidQt blacklist.insert("SecondTransmissionRun"); m_view->setOptionsHintStrategy(new AlgorithmHintStrategy(alg, blacklist)); + //If we don't have a searcher yet, use ReflCatalogSearcher + if(!m_searcher) + m_searcher.reset(new ReflCatalogSearcher()); + //Start with a blank table newTable(); } @@ -859,6 +868,8 @@ namespace MantidQt case IReflPresenter::CopySelectedFlag: copySelected(); break; case IReflPresenter::CutSelectedFlag: cutSelected(); break; case IReflPresenter::PasteSelectedFlag: pasteSelected(); break; + case IReflPresenter::SearchFlag: search(); break; + case IReflPresenter::TransferFlag: transfer(); break; } //Not having a 'default' case is deliberate. gcc issues a warning if there's a flag we aren't handling. } @@ -1130,6 +1141,61 @@ namespace MantidQt } } + /** Searches for runs that can be used */ + void ReflMainViewPresenter::search() + { + const std::string searchString = m_view->getSearchString(); + const std::string searchInstr = m_view->getSearchInstrument(); + + //Don't bother searching if they're not searching for anything + if(searchString.empty()) + return; + + try + { + auto results = m_searcher->search(searchString, searchInstr); + m_searchModel = ReflSearchModel_sptr(new ReflSearchModel(results)); + m_view->showSearch(m_searchModel); + } + catch(std::runtime_error& e) + { + m_view->giveUserCritical("Error running search:\n" + std::string(e.what()), "Search Failed"); + } + } + + /** Transfers the selected runs in the search results to the processing table */ + void ReflMainViewPresenter::transfer() + { + //Build the input for the transfer strategy + std::map runs; + auto selectedRows = m_view->getSelectedSearchRows(); + for(auto rowIt = selectedRows.begin(); rowIt != selectedRows.end(); ++rowIt) + { + const int row = *rowIt; + const std::string run = m_searchModel->data(m_searchModel->index(row, 0)).toString().toStdString(); + const std::string description = m_searchModel->data(m_searchModel->index(row, 1)).toString().toStdString(); + runs[run] = description; + } + + auto newRows = m_transferStrategy->transferRuns(runs); + + std::map groups; + for(auto rowIt = newRows.begin(); rowIt != newRows.end(); ++rowIt) + { + auto& row = *rowIt; + + if(groups.count(row["group"]) == 0) + groups[row["group"]] = getUnusedGroup(); + + const int rowIndex = m_model->rowCount(); + m_model->insertRow(rowIndex); + m_model->setData(m_model->index(rowIndex, COL_RUNS), QString::fromStdString(row["runs"])); + m_model->setData(m_model->index(rowIndex, COL_ANGLE), QString::fromStdString(row["theta"])); + m_model->setData(m_model->index(rowIndex, COL_SCALE), 1.0); + m_model->setData(m_model->index(rowIndex, COL_GROUP), groups[row["group"]]); + } + } + /** Shows the Refl Options dialog */ void ReflMainViewPresenter::showOptionsDialog() { diff --git a/Code/Mantid/MantidQt/CustomInterfaces/src/ReflSearchModel.cpp b/Code/Mantid/MantidQt/CustomInterfaces/src/ReflSearchModel.cpp new file mode 100644 index 000000000000..c95413cbb8fd --- /dev/null +++ b/Code/Mantid/MantidQt/CustomInterfaces/src/ReflSearchModel.cpp @@ -0,0 +1,116 @@ +#include "MantidQtCustomInterfaces/ReflSearchModel.h" +#include "MantidAPI/ITableWorkspace.h" +#include "MantidAPI/TableRow.h" + +namespace MantidQt +{ + namespace CustomInterfaces + { + using namespace Mantid::API; + + //---------------------------------------------------------------------------------------------- + /** Constructor + @param tableWorkspace : The table workspace to copy data from + */ + ReflSearchModel::ReflSearchModel(ITableWorkspace_sptr tableWorkspace) + { + //Copy the data from the input table workspace + for(size_t i = 0; i < tableWorkspace->rowCount(); ++i) + { + const std::string run = tableWorkspace->String(i,0); + const std::string description = tableWorkspace->String(i,6); + m_runs.push_back(run); + m_descriptions[run] = description; + } + + //By sorting the vector of runs, we sort the entire table + std::sort(m_runs.begin(), m_runs.end()); + } + + //---------------------------------------------------------------------------------------------- + /** Destructor + */ + ReflSearchModel::~ReflSearchModel() + { + } + + /** + @return the row count. + */ + int ReflSearchModel::rowCount(const QModelIndex &) const + { + return static_cast(m_runs.size()); + } + + /** + @return the number of columns in the model. + */ + int ReflSearchModel::columnCount(const QModelIndex &) const + { + return 2; + } + + /** + Overrident data method, allows consuming view to extract data for an index and role. + @param index : For which to extract the data + @param role : Role mode + */ + QVariant ReflSearchModel::data(const QModelIndex &index, int role) const + { + if(role != Qt::DisplayRole) + return QVariant(); + + const int colNumber = index.column(); + const int rowNumber = index.row(); + + if(rowNumber < 0 || rowNumber >= static_cast(m_runs.size())) + return QVariant(); + + const std::string run = m_runs[rowNumber]; + + if(colNumber == 0) + return QString::fromStdString(run); + + if(colNumber == 1) + return QString::fromStdString(m_descriptions.find(run)->second); + + return QVariant(); + } + + /** + Get the heading for a given section, orientation and role. + @param section : Column index + @param orientation : Heading orientation + @param role : Role mode of table. + @return HeaderData. + */ + QVariant ReflSearchModel::headerData(int section, Qt::Orientation orientation, int role) const + { + if(role != Qt::DisplayRole) + return QVariant(); + + if(orientation == Qt::Horizontal) + { + switch(section) + { + case 0: return "Run"; + case 1: return "Description"; + default: return ""; + } + } + return QVariant(); + } + + /** + Provide flags on an index by index basis + @param index: To generate a flag for. + */ + Qt::ItemFlags ReflSearchModel::flags(const QModelIndex &index) const + { + if(!index.isValid()) + return 0; + else + return Qt::ItemIsEnabled | Qt::ItemIsSelectable; + } + } // namespace CustomInterfaces +} // namespace Mantid diff --git a/Code/Mantid/MantidQt/CustomInterfaces/test/ReflLegacyTransferStrategyTest.h b/Code/Mantid/MantidQt/CustomInterfaces/test/ReflLegacyTransferStrategyTest.h new file mode 100644 index 000000000000..61ce4362ea8f --- /dev/null +++ b/Code/Mantid/MantidQt/CustomInterfaces/test/ReflLegacyTransferStrategyTest.h @@ -0,0 +1,182 @@ +#ifndef MANTID_CUSTOMINTERFACES_REFLLEGACYTRANSFERSTRATEGYTEST_H +#define MANTID_CUSTOMINTERFACES_REFLLEGACYTRANSFERSTRATEGYTEST_H + +#include +#include +#include +#include + +#include "MantidQtCustomInterfaces/ReflLegacyTransferStrategy.h" + +using namespace MantidQt::CustomInterfaces; + +class ReflLegacyTransferStrategyTest : public CxxTest::TestSuite +{ +public: + // This pair of boilerplate methods prevent the suite being created statically + // This means the constructor isn't called when running other tests + static ReflLegacyTransferStrategyTest *createSuite() { return new ReflLegacyTransferStrategyTest(); } + static void destroySuite( ReflLegacyTransferStrategyTest *suite ) { delete suite; } + + ReflLegacyTransferStrategyTest() + { + } + + void testBasicTransfer() + { + std::map input; + input["1234"] = "fictitious run on gold"; + input["1235"] = "fictitious run on silver"; + input["1236"] = "fictitious run on bronze"; + + std::vector > expected; + std::map expectedRow; + + expectedRow["runs"] = "1234"; + expectedRow["theta"] = ""; + expectedRow["group"] = "0"; + expected.push_back(expectedRow); + + expectedRow["runs"] = "1235"; + expectedRow["theta"] = ""; + expectedRow["group"] = "1"; + expected.push_back(expectedRow); + + expectedRow["runs"] = "1236"; + expectedRow["theta"] = ""; + expectedRow["group"] = "2"; + expected.push_back(expectedRow); + + ReflLegacyTransferStrategy strategy; + auto output = strategy.transferRuns(input); + + TS_ASSERT_EQUALS(output, expected); + } + + void testGroupedTransfer() + { + std::map input; + input["1233"] = "fictitious run on platinum"; + input["1234"] = "fictitious run on gold"; + input["1235"] = "fictitious run on gold"; + input["1236"] = "fictitious run on silver"; + + std::vector > expected; + std::map expectedRow; + + expectedRow["runs"] = "1233"; + expectedRow["theta"] = ""; + expectedRow["group"] = "0"; + expected.push_back(expectedRow); + + expectedRow["runs"] = "1234+1235"; + expectedRow["theta"] = ""; + expectedRow["group"] = "1"; + expected.push_back(expectedRow); + + expectedRow["runs"] = "1236"; + expectedRow["theta"] = ""; + expectedRow["group"] = "2"; + expected.push_back(expectedRow); + + ReflLegacyTransferStrategy strategy; + auto output = strategy.transferRuns(input); + + TS_ASSERT_EQUALS(output, expected); + } + + void testThetaExtraction() + { + std::map input; + input["1234"] = "fictitious run on gold"; + input["1235"] = "fictitious run on silver in 3.14 theta"; + input["1236"] = "fictitious run on bronze th=2.17"; + input["1237"] = "fictitious run on platinum th:1.23 and pH=12"; + + std::vector > expected; + std::map expectedRow; + + expectedRow["runs"] = "1234"; + expectedRow["theta"] = ""; + expectedRow["group"] = "0"; + expected.push_back(expectedRow); + + expectedRow["runs"] = "1235"; + expectedRow["theta"] = "3.14"; + expectedRow["group"] = "1"; + expected.push_back(expectedRow); + + expectedRow["runs"] = "1236"; + expectedRow["theta"] = "2.17"; + expectedRow["group"] = "2"; + expected.push_back(expectedRow); + + expectedRow["runs"] = "1237"; + expectedRow["theta"] = "1.23"; + expectedRow["group"] = "3"; + expected.push_back(expectedRow); + + ReflLegacyTransferStrategy strategy; + auto output = strategy.transferRuns(input); + + TS_ASSERT_EQUALS(output, expected); + } + + void testComplexExtraction() + { + std::map input; + input["1230"] = "fictitious run on gold"; + input["1231"] = "fictitious run on silver in 3.14 theta"; + input["1232"] = "fictitious run on silver in 3.14 theta"; + input["1233"] = "fictitious run on silver in 2.17 theta"; + input["1234"] = "fictitious run on bronze th=2.17"; + input["1235"] = "fictitious run on bronze th=1.23"; + input["1236"] = "fictitious run on platinum th:1.23 and pH=12"; + input["1237"] = "fictitious run on fool's gold"; + + std::vector > expected; + std::map expectedRow; + + expectedRow["runs"] = "1230"; + expectedRow["theta"] = ""; + expectedRow["group"] = "0"; + expected.push_back(expectedRow); + + expectedRow["runs"] = "1231+1232"; + expectedRow["theta"] = "3.14"; + expectedRow["group"] = "1"; + expected.push_back(expectedRow); + + expectedRow["runs"] = "1233"; + expectedRow["theta"] = "2.17"; + expectedRow["group"] = "1"; + expected.push_back(expectedRow); + + expectedRow["runs"] = "1234"; + expectedRow["theta"] = "2.17"; + expectedRow["group"] = "2"; + expected.push_back(expectedRow); + + expectedRow["runs"] = "1235"; + expectedRow["theta"] = "1.23"; + expectedRow["group"] = "2"; + expected.push_back(expectedRow); + + expectedRow["runs"] = "1236"; + expectedRow["theta"] = "1.23"; + expectedRow["group"] = "3"; + expected.push_back(expectedRow); + + expectedRow["runs"] = "1237"; + expectedRow["theta"] = ""; + expectedRow["group"] = "4"; + expected.push_back(expectedRow); + + ReflLegacyTransferStrategy strategy; + auto output = strategy.transferRuns(input); + + TS_ASSERT_EQUALS(output, expected); + } +}; + +#endif diff --git a/Code/Mantid/MantidQt/CustomInterfaces/test/ReflMainViewMockObjects.h b/Code/Mantid/MantidQt/CustomInterfaces/test/ReflMainViewMockObjects.h index c5948d24299a..5f2db3957a21 100644 --- a/Code/Mantid/MantidQt/CustomInterfaces/test/ReflMainViewMockObjects.h +++ b/Code/Mantid/MantidQt/CustomInterfaces/test/ReflMainViewMockObjects.h @@ -3,6 +3,7 @@ #include #include "MantidQtCustomInterfaces/ReflMainView.h" +#include "MantidQtCustomInterfaces/ReflSearchModel.h" #include "MantidQtCustomInterfaces/QReflTableModel.h" #include "MantidAPI/TableRow.h" @@ -37,18 +38,21 @@ class MockView : public ReflMainView MOCK_CONST_METHOD0(getWorkspaceToOpen, std::string()); MOCK_METHOD1(setSelection, void(const std::set& rows)); MOCK_CONST_METHOD0(getSelectedRows, std::set()); + MOCK_CONST_METHOD0(getSelectedSearchRows, std::set()); MOCK_METHOD1(setClipboard, void(const std::string& text)); MOCK_CONST_METHOD0(getClipboard, std::string()); + MOCK_CONST_METHOD0(getSearchString, std::string()); + MOCK_CONST_METHOD0(getSearchInstrument, std::string()); //Calls we don't care about virtual void showTable(QReflTableModel_sptr) {}; + virtual void showSearch(ReflSearchModel_sptr) {}; virtual void setOptionsHintStrategy(MantidQt::MantidWidgets::HintStrategy*) {}; virtual void setProgressRange(int,int) {}; virtual void setProgress(int) {}; virtual void setTableList(const std::set&) {}; virtual void setInstrumentList(const std::vector&, const std::string&) {}; virtual std::string getProcessInstrument() const {return "FAKE";} - virtual std::string getSearchInstrument() const {return "FAKE";} virtual boost::shared_ptr getPresenter() const {return boost::shared_ptr();} }; diff --git a/Code/Mantid/docs/source/algorithms/CorelliCrossCorrelate-v1.rst b/Code/Mantid/docs/source/algorithms/CorelliCrossCorrelate-v1.rst new file mode 100644 index 000000000000..44d77859cb3d --- /dev/null +++ b/Code/Mantid/docs/source/algorithms/CorelliCrossCorrelate-v1.rst @@ -0,0 +1,50 @@ + +.. algorithm:: + +.. summary:: + +.. alias:: + +.. properties:: + +Description +----------- + +The algorithm calculates the elastic signal for the Corelli diffractometer. This is done by calculating the cross-correlation with the correlation chopper. The correlation chopper modulates the incident neutron beam with a pseudo-random sequence. The calculated signal is applied the each event in the form of a weight. + +The algorithm requires the timing offset of the TDC signal from the correlation chopper to run. The timing offset is dependent on the frequency of the chopper and should not change if the frequency has not changed. + +Usage +----- +.. Try not to use files in your examples, + but if you cannot avoid it then the (small) files must be added to + autotestdata\UsageData and the following tag unindented + .. include:: ../usagedata-note.txt + +**Example - CorelliCrossCorrelate** + +.. testcode:: CorelliCrossCorrelateExample + + # Load a Corelli data file. + ws = Load('CORELLI_2100') + + # You will need to load the instrument if the one in the NeXus file doesn't contain the chopper sequence. + LoadInstrument(ws, MonitorList='-1,-2,-3', InstrumentName='CORELLI') + + # Run the cross-correlation. This is using a TDC timing offset of 56000ns. + wsOut = CorelliCrossCorrelate(ws,56000) + + print 'The detector 172305 has ' + str(ws.getEventList(172305).getNumberEvents()) + ' events.' + print 'The event weights before cross-correlation are ' + str(ws.getEventList(172305).getWeights()) + print 'The event weights after cross-correlation are ' + str(wsOut.getEventList(172305).getWeights()) + +Output: + +.. testoutput:: CorelliCrossCorrelateExample + + The detector 172305 has 3 events. + The event weights before cross-correlation are [ 1. 1. 1.] + The event weights after cross-correlation are [-1.99391854 2.00611877 2.00611877] + +.. categories:: + diff --git a/Code/Mantid/instrument/CORELLI_Definition.xml b/Code/Mantid/instrument/CORELLI_Definition.xml index 0961def41080..83b539b45c5d 100644 --- a/Code/Mantid/instrument/CORELLI_Definition.xml +++ b/Code/Mantid/instrument/CORELLI_Definition.xml @@ -15,7 +15,15 @@ - + + + + + + + + + @@ -31,6 +39,711 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -1342,7 +2055,7 @@ - + @@ -1604,7 +2317,7 @@ - + diff --git a/Code/Mantid/instrument/CORELLI_Parameters.xml b/Code/Mantid/instrument/CORELLI_Parameters.xml index ddf9701b1f49..e9cf3f940d4e 100644 --- a/Code/Mantid/instrument/CORELLI_Parameters.xml +++ b/Code/Mantid/instrument/CORELLI_Parameters.xml @@ -8,7 +8,12 @@ + + + + + + - diff --git a/Code/Mantid/instrument/CRISP_Parameters.xml b/Code/Mantid/instrument/CRISP_Parameters.xml index 8b05b80de698..785baa525ded 100644 --- a/Code/Mantid/instrument/CRISP_Parameters.xml +++ b/Code/Mantid/instrument/CRISP_Parameters.xml @@ -36,10 +36,14 @@ + + diff --git a/Code/Mantid/instrument/INTER_Parameters.xml b/Code/Mantid/instrument/INTER_Parameters.xml index 96216d6a8c2a..43671c19f03c 100644 --- a/Code/Mantid/instrument/INTER_Parameters.xml +++ b/Code/Mantid/instrument/INTER_Parameters.xml @@ -33,10 +33,14 @@ + + diff --git a/Code/Mantid/instrument/POLREF_Parameters.xml b/Code/Mantid/instrument/POLREF_Parameters.xml index fa461e5f257b..537b14c666c8 100644 --- a/Code/Mantid/instrument/POLREF_Parameters.xml +++ b/Code/Mantid/instrument/POLREF_Parameters.xml @@ -39,10 +39,14 @@ + + diff --git a/Code/Mantid/instrument/SURF_Parameters.xml b/Code/Mantid/instrument/SURF_Parameters.xml index 7b90a98646dc..6c443dcccd97 100644 --- a/Code/Mantid/instrument/SURF_Parameters.xml +++ b/Code/Mantid/instrument/SURF_Parameters.xml @@ -33,10 +33,14 @@ + + diff --git a/Code/Mantid/scripts/Interface/ui/reflectometer/refl_gui.py b/Code/Mantid/scripts/Interface/ui/reflectometer/refl_gui.py index 9159f11c0eef..ac2edbe01814 100644 --- a/Code/Mantid/scripts/Interface/ui/reflectometer/refl_gui.py +++ b/Code/Mantid/scripts/Interface/ui/reflectometer/refl_gui.py @@ -985,6 +985,8 @@ def _do_run(self, runno, row, which): if ',' in runno: runno = runno.split(',')[0] inst = wq.getInstrument() + #NOTE: In the new Refl UI, these adjustments to lmin/lmax are NOT made. This has been + #noted in the parameter files for INTER/CRIST/POLREF/SURF. lmin = inst.getNumberParameter('LambdaMin')[0] + 1 lmax = inst.getNumberParameter('LambdaMax')[0] - 2 qmin = 4 * math.pi / lmax * math.sin(th * math.pi / 180) diff --git a/Test/AutoTestData/UsageData/CORELLI_2100.nxs.h5 b/Test/AutoTestData/UsageData/CORELLI_2100.nxs.h5 new file mode 100644 index 000000000000..1f88e92abb90 Binary files /dev/null and b/Test/AutoTestData/UsageData/CORELLI_2100.nxs.h5 differ