diff --git a/Code/Mantid/Framework/API/inc/MantidAPI/Axis.h b/Code/Mantid/Framework/API/inc/MantidAPI/Axis.h index b72e9bef5d574e2a30713dbcd25349a43b1ea325..6784b7fd2393120181a07f9b8ad867c19efac4b7 100644 --- a/Code/Mantid/Framework/API/inc/MantidAPI/Axis.h +++ b/Code/Mantid/Framework/API/inc/MantidAPI/Axis.h @@ -61,7 +61,7 @@ public: Kernel::Unit_sptr& unit(); /// Set the unit on the Axis - virtual void setUnit(const std::string & unit); + virtual const Kernel::Unit_sptr& setUnit(const std::string & unitName); /// Returns true is the axis is a Spectra axis virtual bool isSpectra() const{return false;} diff --git a/Code/Mantid/Framework/API/inc/MantidAPI/CoordTransform.h b/Code/Mantid/Framework/API/inc/MantidAPI/CoordTransform.h index 62fddac4d8bb9abb2ee624431c14b0596867d25c..ea5c2d5b9f204b6cf355467e2e12a3fb2266de00 100644 --- a/Code/Mantid/Framework/API/inc/MantidAPI/CoordTransform.h +++ b/Code/Mantid/Framework/API/inc/MantidAPI/CoordTransform.h @@ -34,6 +34,7 @@ namespace API virtual std::string toXMLString() const = 0; virtual void apply(const coord_t * inputVector, coord_t * outVector) const = 0; virtual CoordTransform * clone() const = 0; + virtual std::string id() const = 0; /// Wrapper for VMD Mantid::Kernel::VMD applyVMD(const Mantid::Kernel::VMD & inputVector) const; diff --git a/Code/Mantid/Framework/API/inc/MantidAPI/NullCoordTransform.h b/Code/Mantid/Framework/API/inc/MantidAPI/NullCoordTransform.h index a81c51a4fe7e23c432b2dc3784ef59be95f0c7b4..ba556ad977d2b9be743623ad2775d6238e1c6fe8 100644 --- a/Code/Mantid/Framework/API/inc/MantidAPI/NullCoordTransform.h +++ b/Code/Mantid/Framework/API/inc/MantidAPI/NullCoordTransform.h @@ -20,6 +20,7 @@ namespace Mantid NullCoordTransform(size_t ndims=3); virtual ~NullCoordTransform(); std::string toXMLString() const; + std::string id() const; void apply(const Mantid::coord_t * inputVector, Mantid::coord_t * outVector) const; virtual CoordTransform * clone() const; diff --git a/Code/Mantid/Framework/API/inc/MantidAPI/ScriptRepository.h b/Code/Mantid/Framework/API/inc/MantidAPI/ScriptRepository.h index 847b2cd83a2b57d3a99b4ea747ef4660d84479c7..968898b08ab952677379491ebb3bba34b5a7dd4f 100644 --- a/Code/Mantid/Framework/API/inc/MantidAPI/ScriptRepository.h +++ b/Code/Mantid/Framework/API/inc/MantidAPI/ScriptRepository.h @@ -471,10 +471,7 @@ They will work as was expected for folders @ref folders-sec. it it necessary that it identifies who was responsible for changing the file. - @param description is an optional argument, because, as - explained at @ref script-description-sec it may be already inside the - file. But, if the description is given, it will be inserted to the local - file (if it is a script) or to the README file inside the folder. + @param email An string that identifies the email of the author. @exception ScriptRepoException may be triggered for an attempt to publish an @@ -486,7 +483,7 @@ They will work as was expected for folders @ref folders-sec. */ virtual void upload(const std::string & file_path, const std::string & comment, const std::string & author, - const std::string & description = std::string()) = 0; + const std::string & email) = 0; /** Define the file patterns that will not be listed in listFiles. This is important to force the ScriptRepository to not list hidden files, diff --git a/Code/Mantid/Framework/API/src/Axis.cpp b/Code/Mantid/Framework/API/src/Axis.cpp index 7af21d6ac6c55953ba106e36dfebe3b13b64b0f1..e359642bb7bea112878766414a9f5525fd842a7f 100644 --- a/Code/Mantid/Framework/API/src/Axis.cpp +++ b/Code/Mantid/Framework/API/src/Axis.cpp @@ -59,11 +59,13 @@ Kernel::Unit_sptr& Axis::unit() } /** * Sets the Unit that is in use on this axis. -* @param unit :: name of the unit as known to the UnitFactory +* @param unitName :: name of the unit as known to the UnitFactory +* @returns The new unit instance */ -void Axis::setUnit(const std::string & unit) +const Kernel::Unit_sptr& Axis::setUnit(const std::string & unitName) { - m_unit = Mantid::Kernel::UnitFactory::Instance().create(unit); + m_unit = Mantid::Kernel::UnitFactory::Instance().create(unitName); + return unit(); } /** diff --git a/Code/Mantid/Framework/API/src/LogManager.cpp b/Code/Mantid/Framework/API/src/LogManager.cpp index 5252201a069f1352bf656fdd6d39e6a8656387e7..9bd21775a9762022fd41c82c3c21255857ac6315 100644 --- a/Code/Mantid/Framework/API/src/LogManager.cpp +++ b/Code/Mantid/Framework/API/src/LogManager.cpp @@ -458,6 +458,12 @@ Kernel::Logger& LogManager::g_log = Kernel::Logger::get("LogManager"); INSTANTIATE(uint32_t); INSTANTIATE(std::string); INSTANTIATE(bool); + + template MANTID_API_DLL uint16_t LogManager::getPropertyValueAsType(const std::string &) const; + template MANTID_API_DLL std::vector<double> LogManager::getPropertyValueAsType(const std::string &) const; + template MANTID_API_DLL std::vector<size_t> LogManager::getPropertyValueAsType(const std::string &) const; + template MANTID_API_DLL std::vector<int> LogManager::getPropertyValueAsType(const std::string &) const; + template MANTID_API_DLL std::vector<long> LogManager::getPropertyValueAsType(const std::string &) const; /** @endcond */ } //API namespace diff --git a/Code/Mantid/Framework/API/src/NullCoordTransform.cpp b/Code/Mantid/Framework/API/src/NullCoordTransform.cpp index fcdea182635ecb9aba25b08abde13e6e495fe08b..415bd5b144c4c83cef53bd152f438534e57c4dde 100644 --- a/Code/Mantid/Framework/API/src/NullCoordTransform.cpp +++ b/Code/Mantid/Framework/API/src/NullCoordTransform.cpp @@ -32,6 +32,15 @@ namespace Mantid throw std::runtime_error("Not Implemented"); } + /** + * Coordinate transform id + * @return the type of coordinate transform + */ + std::string NullCoordTransform::id() const + { + return "NullCoordTransform"; + } + /** Apply the transformation. @param inputVector : pointer to the input vector diff --git a/Code/Mantid/Framework/API/test/ExperimentInfoTest.h b/Code/Mantid/Framework/API/test/ExperimentInfoTest.h index 28aaff9059051ae47d5c88e2180ef149f12bb154..eeab798a5748d6b371e158394b39ca375cfd6333 100644 --- a/Code/Mantid/Framework/API/test/ExperimentInfoTest.h +++ b/Code/Mantid/Framework/API/test/ExperimentInfoTest.h @@ -10,6 +10,7 @@ #include "MantidKernel/DateAndTime.h" #include "MantidKernel/NexusTestHelper.h" #include "MantidKernel/SingletonHolder.h" +#include "MantidKernel/Matrix.h" #include "MantidTestHelpers/ComponentCreationHelper.h" @@ -628,6 +629,43 @@ public: TS_ASSERT_EQUALS( parameterStr, "" ); } + void testNexus_W_matrix() + { + NexusTestHelper th(true); + th.createFile("ExperimentInfoWMatrixTest.nxs"); + ExperimentInfo ei; + + DblMatrix WTransf(3,3,true); + // let's add some tricky stuff to w-transf + WTransf[0][1]=0.5; + WTransf[0][2]=2.5; + WTransf[1][0]=10.5; + WTransf[1][2]=12.5; + WTransf[2][0]=20.5; + WTransf[2][1]=21.5; + + auto wTrVector = WTransf.getVector(); + + // this occurs in ConvertToMD, copy methadata + ei.mutableRun().addProperty("W_MATRIX",wTrVector,true); + + TS_ASSERT_THROWS_NOTHING(ei.saveExperimentInfoNexus(th.file)); + + th.reopenFile(); + + ExperimentInfo other; + std::string InstrParameters; + TS_ASSERT_THROWS_NOTHING(other.loadExperimentInfoNexus(th.file,InstrParameters)); + + std::vector<double> wMatrRestored=other.run().getPropertyValueAsType<std::vector<double> >("W_MATRIX"); + + for(int i=0;i<9;i++) + { + TS_ASSERT_DELTA(wTrVector[i],wMatrRestored[i],1.e-9); + } + + } + private: void addInstrumentWithParameter(ExperimentInfo & expt, const std::string & name, const std::string & value) diff --git a/Code/Mantid/Framework/Algorithms/CMakeLists.txt b/Code/Mantid/Framework/Algorithms/CMakeLists.txt index bcc5c5f73dda2af20632cb80e8d8d05c65f935bb..0eecf79a5accd2754f2368c3d51c28ed3cad7e54 100644 --- a/Code/Mantid/Framework/Algorithms/CMakeLists.txt +++ b/Code/Mantid/Framework/Algorithms/CMakeLists.txt @@ -478,6 +478,7 @@ set ( TEST_FILES ConvertToMatrixWorkspaceTest.h ConvertToPointDataTest.h ConvertUnitsTest.h + CopyInstrumentParametersTest.h CopySampleTest.h CorrectFlightPathsTest.h CorrectKiKfTest.h diff --git a/Code/Mantid/Framework/Algorithms/inc/MantidAlgorithms/GenerateEventsFilter.h b/Code/Mantid/Framework/Algorithms/inc/MantidAlgorithms/GenerateEventsFilter.h index e592d7ad890330592c4d8bdcfa30aa25a5782111..84ec3ba4d14a073123fe9d948350a336f0c5281e 100644 --- a/Code/Mantid/Framework/Algorithms/inc/MantidAlgorithms/GenerateEventsFilter.h +++ b/Code/Mantid/Framework/Algorithms/inc/MantidAlgorithms/GenerateEventsFilter.h @@ -61,7 +61,7 @@ namespace Algorithms class DLLExport GenerateEventsFilter : public API::Algorithm { public: - GenerateEventsFilter(); + explicit GenerateEventsFilter(); virtual ~GenerateEventsFilter(); /// Algorithm's name for identification overriding a virtual method @@ -83,34 +83,51 @@ namespace Algorithms void setFilterByTimeOnly(); void setFilterByLogValue(std::string logname); - void processSingleValueFilter(Kernel::TimeSeriesProperty<double>* mlog, double minvalue, double maxvalue, + void processSingleValueFilter(double minvalue, double maxvalue, bool filterincrease, bool filterdecrease); - void processMultipleValueFilters(Kernel::TimeSeriesProperty<double>* mlog, double minvalue, double maxvalue, + void processMultipleValueFilters(double minvalue, double maxvalue, bool filterincrease, bool filterdecrease); - void makeFilterByValue(Kernel::TimeSeriesProperty<double>* mlog, - Kernel::TimeSplitterType& split, double min, double max, double TimeTolerance, bool centre, + void makeFilterByValue(Kernel::TimeSplitterType& split, double min, double max, double TimeTolerance, bool centre, bool filterIncrease, bool filterDecrease, Kernel::DateAndTime startTime, Kernel::DateAndTime stopTime, int wsindex); - void makeMultipleFiltersByValues(Kernel::TimeSeriesProperty<double>* mlog, - Kernel::TimeSplitterType& split, std::map<size_t, int> indexwsindexmap, std::vector<double> logvalueranges, + void makeMultipleFiltersByValues(Kernel::TimeSplitterType& split, std::map<size_t, int> indexwsindexmap, std::vector<double> logvalueranges, bool centre, bool filterIncrease, bool filterDecrease, Kernel::DateAndTime startTime, Kernel::DateAndTime stopTime); + void processIntegerValueFilter(Kernel::TimeSplitterType &splitters, int minvalue, int maxvalue, + bool filterIncrease, bool filterDecrease, Kernel::DateAndTime runend); + size_t searchValue(std::vector<double> sorteddata, double value); - DataObjects::EventWorkspace_const_sptr mEventWS; - API::ISplittersWorkspace_sptr mSplitters; - API::ITableWorkspace_sptr mFilterInfoWS; + DataObjects::EventWorkspace_const_sptr m_dataWS; + API::ISplittersWorkspace_sptr m_splitWS; + API::ITableWorkspace_sptr m_filterInfoWS; Kernel::DateAndTime mStartTime; Kernel::DateAndTime mStopTime; - double m_convertfactor; + double m_timeUnitConvertFactor; + + Kernel::TimeSeriesProperty<double>* m_dblLog; + Kernel::TimeSeriesProperty<int>* m_intLog; + + bool m_logAtCentre; + double m_logTimeTolerance; }; + /** Generate a new time splitter and add to a list of splitters + */ + void make_splitter(Kernel::DateAndTime start, Kernel::DateAndTime stop, int group, Kernel::time_duration tolerance, + Kernel::TimeSplitterType& splitters) + { + Kernel::SplittingInterval newsplit(start - tolerance, stop - tolerance, group); + splitters.push_back(newsplit); + + return; + } } // namespace Algorithms } // namespace Mantid diff --git a/Code/Mantid/Framework/Algorithms/src/GenerateEventsFilter.cpp b/Code/Mantid/Framework/Algorithms/src/GenerateEventsFilter.cpp index 5e4d199849b3817babde19b0262ae40f3646173a..e6bcecf5c1e76852df3d9d524f494d177b48ae31 100644 --- a/Code/Mantid/Framework/Algorithms/src/GenerateEventsFilter.cpp +++ b/Code/Mantid/Framework/Algorithms/src/GenerateEventsFilter.cpp @@ -47,6 +47,8 @@ using namespace Mantid; using namespace Mantid::Kernel; using namespace Mantid::API; +using namespace std; + namespace Mantid { namespace Algorithms @@ -72,13 +74,12 @@ namespace Algorithms this->setWikiSummary("Generate one or a set of event filters according to time or specified log's value."); } - /* - * Define input + //---------------------------------------------------------------------------------------------- + /** Declare input */ void GenerateEventsFilter::init() { - - // 0. Input/Output Workspaces + // 1. Input/Output Workspaces declareProperty( new API::WorkspaceProperty<DataObjects::EventWorkspace>("InputWorkspace", "Anonymous", Direction::Input), "An input event workspace" ); @@ -91,7 +92,7 @@ namespace Algorithms Direction::Output), "Optional output for the information of each splitter workspace index"); - // 1. Time + // 2. Time (general) declareProperty("StartTime", "0.0", "The start time, in (a) seconds, (b) nanoseconds or (c) percentage of total run time\n" "since the start of the run. OR (d) absolute time. \n" @@ -102,6 +103,7 @@ namespace Algorithms "since the start of the run. OR (d) absolute time. \n" "Events at or after this time are filtered out."); + // 3. Filter by time (only) declareProperty("TimeInterval", -1.0, "Length of the time splices if filtered in time only."); @@ -114,7 +116,7 @@ namespace Algorithms "The unit can be second or nanosecond from run start time." "They can also be defined as percentage of total run time."); - // 2. Log value + // 4. Filter by log value (only) declareProperty("LogName", "", "Name of the sample log to use to filter.\n" "For example, the pulse charge is recorded in 'ProtonCharge'."); @@ -138,24 +140,20 @@ namespace Algorithms declareProperty("TimeTolerance", 0.0, "Tolerance in time for the event times to keep. It is used in the case to filter by single value."); - declareProperty("LogBoundary", "centre", - "How to treat log values as being measured in the centre of time."); + vector<string> logboundoptions; + logboundoptions.push_back("Centre"); + logboundoptions.push_back("other"); + auto logvalidator = boost::make_shared<StringListValidator>(logboundoptions); + declareProperty("LogBoundary", "Centre", logvalidator, + "How to treat log values as being measured in the centre of time."); declareProperty("LogValueTolerance", EMPTY_DBL(), "Tolerance of the log value to be included in filter. It is used in the case to filter by multiple values."); - /* removed due to SNS hardware - std::vector<std::string> logvalueoptions; - logvalueoptions.push_back("StepFunction"); - logvalueoptions.push_back("LinearInterpolation"); - declareProperty("LogValueInterpolation", "StepFunction", boost::make_shared<Kernel::StringListValidator>(logvalueoptions), - "How to treat the changing log value in multiple-value filtering."); - */ - declareProperty("LogValueTimeSections", 1, "In one log value interval, it can be further divided into sections in even time slice."); - // Output workspaces' title and name + // 5. Output workspaces' title and name declareProperty("TitleOfSplitters", "", "Title of output splitters workspace and information workspace."); @@ -169,8 +167,8 @@ namespace Algorithms void GenerateEventsFilter::exec() { // 1. Get general input and output - mEventWS = this->getProperty("InputWorkspace"); - if (!mEventWS) + m_dataWS = this->getProperty("InputWorkspace"); + if (!m_dataWS) { std::stringstream errss; errss << "GenerateEventsFilter does not get input workspace as an EventWorkspace."; @@ -179,11 +177,12 @@ namespace Algorithms } else { - g_log.debug() << "DB9441 GenerateEventsFilter() Input Event WS = " << mEventWS->getName() - << ", Events = " << mEventWS->getNumberEvents() << std::endl; + g_log.debug() << "DB9441 GenerateEventsFilter() Input Event WS = " << m_dataWS->getName() + << ", Events = " << m_dataWS->getNumberEvents() << std::endl; } - Kernel::DateAndTime runstart(mEventWS->run().getProperty("run_start")->value()); + Kernel::DateAndTime runstart = m_dataWS->run().startTime(); + // (m_dataWS->run().getProperty("run_start")->value()); g_log.debug() << "DB9441 Run Start = " << runstart << " / " << runstart.totalNanoseconds() << std::endl; @@ -195,15 +194,15 @@ namespace Algorithms } // Output Splitters workspace - mSplitters = boost::shared_ptr<DataObjects::SplittersWorkspace>(new DataObjects::SplittersWorkspace()); - mSplitters->setTitle(title); + m_splitWS = boost::shared_ptr<DataObjects::SplittersWorkspace>(new DataObjects::SplittersWorkspace()); + m_splitWS->setTitle(title); // mFilterInfoWS = boost::shared_ptr<DataObjects::TableWorkspace>(new DataObjects::TableWorkspace); - mFilterInfoWS = API::WorkspaceFactory::Instance().createTable("TableWorkspace"); - mFilterInfoWS->setTitle(title); + m_filterInfoWS = API::WorkspaceFactory::Instance().createTable("TableWorkspace"); + m_filterInfoWS->setTitle(title); - mFilterInfoWS->addColumn("int", "workspacegroup"); - mFilterInfoWS->addColumn("str", "title"); + m_filterInfoWS->addColumn("int", "workspacegroup"); + m_filterInfoWS->addColumn("str", "title"); // 2. Get Time processInputTime(runstart); @@ -224,14 +223,15 @@ namespace Algorithms setFilterByLogValue(logname); } - this->setProperty("OutputWorkspace", mSplitters); - this->setProperty("InformationWorkspace", mFilterInfoWS); + this->setProperty("OutputWorkspace", m_splitWS); + this->setProperty("InformationWorkspace", m_filterInfoWS); return; } - /* - * Process the input for time. A smart but complicated default rule + //---------------------------------------------------------------------------------------------- + /** Process the input for time. A smart but complicated default rule + * @param runstarttime :: run start time in sample log */ void GenerateEventsFilter::processInputTime(Kernel::DateAndTime runstarttime) { @@ -269,27 +269,27 @@ namespace Algorithms // 2. Find maximum time by proton charge // FIXME Use this simple method may miss the events in the last pulse Kernel::TimeSeriesProperty<double>* protonchargelog = - dynamic_cast<Kernel::TimeSeriesProperty<double> *>(mEventWS->run().getProperty("proton_charge")); + dynamic_cast<Kernel::TimeSeriesProperty<double> *>(m_dataWS->run().getProperty("proton_charge")); Kernel::DateAndTime runend = protonchargelog->lastTime(); // 3. Set up time-convert unit - m_convertfactor = 1.0; + m_timeUnitConvertFactor = 1.0; if (timeunit.compare("Seconds") == 0) { // a) In unit of seconds - m_convertfactor = 1.0E9; + m_timeUnitConvertFactor = 1.0E9; } else if (timeunit.compare("Nanoseconds") == 0) { // b) In unit of nano-seconds - m_convertfactor = 1.0; + m_timeUnitConvertFactor = 1.0; } else if (timeunit.compare("Percent") == 0) { // c) In unit of percent of total run time int64_t runtime_ns = runend.totalNanoseconds()-runstarttime.totalNanoseconds(); double runtimed_ns = static_cast<double>(runtime_ns); - m_convertfactor = 0.01*runtimed_ns; + m_timeUnitConvertFactor = 0.01*runtimed_ns; } else { @@ -299,7 +299,7 @@ namespace Algorithms } // 4. Process second round - int64_t t0_ns = runstarttime.totalNanoseconds() + static_cast<int64_t>(inpt0*m_convertfactor); + int64_t t0_ns = runstarttime.totalNanoseconds() + static_cast<int64_t>(inpt0*m_timeUnitConvertFactor); Kernel::DateAndTime tmpt0(t0_ns); mStartTime = tmpt0; @@ -309,19 +309,19 @@ namespace Algorithms } else { - int64_t tf_ns = runstarttime.totalNanoseconds()+static_cast<int64_t>(inptf*m_convertfactor); + int64_t tf_ns = runstarttime.totalNanoseconds()+static_cast<int64_t>(inptf*m_timeUnitConvertFactor); Kernel::DateAndTime tmptf(tf_ns); mStopTime = tmptf; } } - g_log.debug() << "DB8147 StartTime = " << mStartTime << ", StopTime = " << mStopTime << std::endl; + g_log.information() << "Filter: StartTime = " << mStartTime << ", StopTime = " << mStopTime << std::endl; return; } - /* - * Set splitters by time value / interval only + //---------------------------------------------------------------------------------------------- + /** Set splitters by time value / interval only */ void GenerateEventsFilter::setFilterByTimeOnly() { @@ -336,9 +336,9 @@ namespace Algorithms int wsindex = 0; // 1. Default and thus just one interval Kernel::SplittingInterval ti(mStartTime, mStopTime, 0); - mSplitters->addSplitter(ti); + m_splitWS->addSplitter(ti); - API::TableRow row = mFilterInfoWS->appendRow(); + API::TableRow row = m_filterInfoWS->appendRow(); std::stringstream ss; ss << "Time Interval From " << mStartTime << " to " << mStopTime; row << wsindex << ss.str(); @@ -346,7 +346,7 @@ namespace Algorithms else { // 2. Use N time interval - int64_t deltatime_ns = static_cast<int64_t>(timeinterval*m_convertfactor); + int64_t deltatime_ns = static_cast<int64_t>(timeinterval*m_timeUnitConvertFactor); int64_t curtime_ns = mStartTime.totalNanoseconds(); int wsindex = 0; @@ -361,10 +361,10 @@ namespace Algorithms Kernel::DateAndTime t0(curtime_ns); Kernel::DateAndTime tf(nexttime_ns); Kernel::SplittingInterval spiv(t0, tf, wsindex); - mSplitters->addSplitter(spiv); + m_splitWS->addSplitter(spiv); // c) Information - API::TableRow row = mFilterInfoWS->appendRow(); + API::TableRow row = m_filterInfoWS->appendRow(); std::stringstream ss; ss << "Time Interval From " << t0 << " to " << tf; row << wsindex << ss.str(); @@ -392,42 +392,34 @@ namespace Algorithms //---------------------------------------------------------------------------------------------- /** Generate filters by log values. + * @param logname :: name of the log to filter with */ void GenerateEventsFilter::setFilterByLogValue(std::string logname) { - // 1. Process inputs - Kernel::TimeSeriesProperty<double>* mLog = - dynamic_cast<Kernel::TimeSeriesProperty<double>* >(mEventWS->run().getProperty(logname)); - if (!mLog) + // 1. Get hold on sample log to filter with + m_dblLog = dynamic_cast<TimeSeriesProperty<double>* >(m_dataWS->run().getProperty(logname)); + m_intLog = dynamic_cast<TimeSeriesProperty<int>* > (m_dataWS->run().getProperty(logname)); + if (!m_dblLog && !m_intLog) { - g_log.error() << "Log " << logname << " does not exist or is not TimeSeriesProperty in double." << std::endl; - throw std::invalid_argument("User specified log is not correct"); + stringstream errmsg; + errmsg << "Log " << logname << " does not exist or is not TimeSeriesProperty in double or integer."; + g_log.error(errmsg.str()); + throw runtime_error(errmsg.str()); } - // a) Clear duplicate value - mLog->eliminateDuplicates(); + // Clear duplicate value + if (m_dblLog) + m_dblLog->eliminateDuplicates(); + else + m_intLog->eliminateDuplicates(); + // 2. Process input properties related to filter with log value double minvalue = this->getProperty("MinimumLogValue"); double maxvalue = this->getProperty("MaximumLogValue"); double deltaValue = this->getProperty("LogValueInterval"); - if (minvalue == EMPTY_DBL()) - { - minvalue = mLog->minValue(); - } - if (maxvalue == EMPTY_DBL()) - { - maxvalue = mLog->maxValue(); - } - - if (minvalue > maxvalue) - { - g_log.error() << "Error: Input minimum log value " << minvalue << - " is larger than maximum log value " << maxvalue << std::endl; - throw std::invalid_argument("Input minimum value is larger than maximum value"); - } - - std::string filterdirection = this->getProperty("FilterLogValueByChangingDirection"); + // 3. Log value change direction + std::string filterdirection = getProperty("FilterLogValueByChangingDirection"); bool filterIncrease; bool filterDecrease; if (filterdirection.compare("Both") == 0) @@ -452,52 +444,122 @@ namespace Algorithms toProcessSingleValueFilter = true; } - // 2. Generate filters - if (toProcessSingleValueFilter) + // 4. Log boundary + string logboundary = getProperty("LogBoundary"); + if (logboundary.compare("Centre")) + m_logAtCentre = true; + else + m_logAtCentre = false; + + m_logTimeTolerance = getProperty("TimeTolerance"); + + // 5. Generate filters + if (m_dblLog) { - // a) Generate a filter for a single log value - processSingleValueFilter(mLog, minvalue, maxvalue, filterIncrease, filterDecrease); + // Process min/max + if (minvalue == EMPTY_DBL()) + { + minvalue = m_dblLog->minValue(); + } + if (maxvalue == EMPTY_DBL()) + { + maxvalue = m_dblLog->maxValue(); + } + + if (minvalue > maxvalue) + { + stringstream errmsg; + errmsg << "Fatal Error: Input minimum log value " << minvalue + << " is larger than maximum log value " << maxvalue; + g_log.error(errmsg.str()); + throw runtime_error(errmsg.str()); + } + + // Filter double value log + if (toProcessSingleValueFilter) + { + // a) Generate a filter for a single log value + processSingleValueFilter(minvalue, maxvalue, filterIncrease, filterDecrease); + } + else + { + // b) Generate filters for a series of log value + processMultipleValueFilters(minvalue, maxvalue, filterIncrease, filterDecrease); + } } else { - // b) Generate filters for a series of log value - processMultipleValueFilters(mLog, minvalue, maxvalue, filterIncrease, filterDecrease); + // Filter integer log + int minvaluei, maxvaluei; + if (minvalue == EMPTY_DBL()) + minvaluei = m_intLog->minValue(); + else + minvaluei = static_cast<int>(minvalue+0.5); + + if (maxvalue == EMPTY_DBL()) + maxvaluei = m_intLog->maxValue(); + else + maxvaluei = static_cast<int>(maxvalue+0.5); + + if (minvalue > maxvalue) + { + stringstream errmsg; + errmsg << "Fatal Error: Input minimum log value " << minvalue + << " is larger than maximum log value " << maxvalue; + g_log.error(errmsg.str()); + throw runtime_error(errmsg.str()); + } + + TimeSplitterType splitters; + DateAndTime runendtime = m_dataWS->run().endTime(); + processIntegerValueFilter(splitters, minvaluei, maxvaluei, filterIncrease, filterDecrease, runendtime); + + size_t numsplits = splitters.size(); + for (size_t i = 0; i < numsplits; ++i) + { + SplittingInterval split = splitters[i]; + m_splitWS->addSplitter(split); + } } + return; } //---------------------------------------------------------------------------------------------- /** Generate filters by single log value + * @param minvalue :: minimum value of the allowed log value; + * @param maxvalue :: maximum value of the allowed log value; + * @param filterincrease :: if true, log value in the increasing curve should be included; + * @param filterdecrease :: if true, log value in the decreasing curve should be included; */ - void GenerateEventsFilter::processSingleValueFilter(Kernel::TimeSeriesProperty<double>* mlog, - double minvalue, double maxvalue, + void GenerateEventsFilter::processSingleValueFilter(double minvalue, double maxvalue, bool filterincrease, bool filterdecrease) { // 1. Validity & value double timetolerance = this->getProperty("TimeTolerance"); - int64_t timetolerance_ns = static_cast<int64_t>(timetolerance*m_convertfactor); + int64_t timetolerance_ns = static_cast<int64_t>(timetolerance*m_timeUnitConvertFactor); std::string logboundary = this->getProperty("LogBoundary"); - std::transform(logboundary.begin(), logboundary.end(), logboundary.begin(), tolower); + transform(logboundary.begin(), logboundary.end(), logboundary.begin(), ::tolower); // 2. Generate filter std::vector<Kernel::SplittingInterval> splitters; int wsindex = 0; - makeFilterByValue(mlog, splitters, minvalue, maxvalue, static_cast<double>(timetolerance_ns)*1.0E-9, + makeFilterByValue(splitters, minvalue, maxvalue, static_cast<double>(timetolerance_ns)*1.0E-9, logboundary.compare("centre")==0, filterincrease, filterdecrease, mStartTime, mStopTime, wsindex); // 3. Add to output for (size_t isp = 0; isp < splitters.size(); isp ++) { - mSplitters->addSplitter(splitters[isp]); + m_splitWS->addSplitter(splitters[isp]); } // 4. Add information - API::TableRow row = mFilterInfoWS->appendRow(); + API::TableRow row = m_filterInfoWS->appendRow(); std::stringstream ss; - ss << "Log " << mlog->name() << " From " << minvalue << " To " << maxvalue << " Value-change-direction "; + ss << "Log " << m_dblLog->name() << " From " << minvalue << " To " << maxvalue << " Value-change-direction "; if (filterincrease && filterdecrease) { ss << " both "; @@ -517,10 +579,14 @@ namespace Algorithms //---------------------------------------------------------------------------------------------- /** Generate filters from multiple values + * @param minvalue :: minimum value of the allowed log value; + * @param maxvalue :: maximum value of the allowed log value; + * @param filterincrease :: if true, log value in the increasing curve should be included; + * @param filterdecrease :: if true, log value in the decreasing curve should be included; */ - void GenerateEventsFilter::processMultipleValueFilters(Kernel::TimeSeriesProperty<double>* mlog, double minvalue, - double maxvalue, - bool filterincrease, bool filterdecrease) + void GenerateEventsFilter::processMultipleValueFilters(double minvalue, double maxvalue, + bool filterincrease, + bool filterdecrease) { // 1. Read more input double valueinterval = this->getProperty("LogValueInterval"); @@ -552,7 +618,7 @@ namespace Algorithms // Workgroup information std::stringstream ss; - ss << "Log " << mlog->name() << " From " << lowbound << " To " << upbound << " Value-change-direction "; + ss << "Log " << m_dblLog->name() << " From " << lowbound << " To " << upbound << " Value-change-direction "; if (filterincrease && filterdecrease) { ss << " both "; @@ -565,7 +631,7 @@ namespace Algorithms { ss << " decrease"; }; - API::TableRow newrow = mFilterInfoWS->appendRow(); + API::TableRow newrow = m_filterInfoWS->appendRow(); newrow << wsindex << ss.str(); curvalue += valueinterval; @@ -581,28 +647,28 @@ namespace Algorithms double upperboundinterval0 = logvalueranges[1]; double lowerboundlastinterval = logvalueranges[logvalueranges.size()-2]; - double minlogvalue = mlog->minValue(); - double maxlogvalue = mlog->maxValue(); + double minlogvalue = m_dblLog->minValue(); + double maxlogvalue = m_dblLog->maxValue(); if (minlogvalue > upperboundinterval0 || maxlogvalue < lowerboundlastinterval) { g_log.warning() << "User specifies log interval from " << minvalue-valuetolerance << " to " << maxvalue-valuetolerance << " with interval size = " << valueinterval - << "; Log " << mlog->name() << " has range " << minlogvalue << " to " << maxlogvalue + << "; Log " << m_dblLog->name() << " has range " << minlogvalue << " to " << maxlogvalue << ". Therefore some workgroup index may not have any splitter." << std::endl; } // 3. Call Kernel::TimeSplitterType splitters; std::string logboundary = this->getProperty("LogBoundary"); - transform(logboundary.begin(), logboundary.end(), logboundary.begin(), tolower); + transform(logboundary.begin(), logboundary.end(), logboundary.begin(), ::tolower); - makeMultipleFiltersByValues(mlog, splitters, indexwsindexmap, logvalueranges, + makeMultipleFiltersByValues(splitters, indexwsindexmap, logvalueranges, logboundary.compare("centre") == 0, filterincrease, filterdecrease, mStartTime, mStopTime); // 4. Put to SplittersWorkspace for (size_t i = 0; i < splitters.size(); i ++) - mSplitters->addSplitter(splitters[i]); + m_splitWS->addSplitter(splitters[i]); return; } @@ -614,7 +680,6 @@ namespace Algorithms * SINGLE log values >= min and < max. Creates SplittingInterval's where * times match the log values, and going to index==0. * - * @param mlog :: Log. * @param filterIncrease :: As log value increase, and within (min, max), include this range in the filter. * @param filterDecrease :: As log value increase, and within (min, max), include this range in the filter. * @param startTime :: Start time. @@ -626,13 +691,12 @@ namespace Algorithms * @param TimeTolerance :: Offset added to times in seconds. * @param centre :: Whether the log value time is considered centred or at the beginning. */ - void GenerateEventsFilter::makeFilterByValue(Kernel::TimeSeriesProperty<double>* mlog, - Kernel::TimeSplitterType& split, double min, double max, double TimeTolerance, bool centre, - bool filterIncrease, bool filterDecrease, Kernel::DateAndTime startTime, Kernel::DateAndTime stopTime, - int wsindex) + void GenerateEventsFilter::makeFilterByValue(TimeSplitterType &split, + double min, double max, double TimeTolerance, bool centre, bool filterIncrease, + bool filterDecrease, DateAndTime startTime, Kernel::DateAndTime stopTime, int wsindex) { // 1. Do nothing if the log is empty. - if (mlog->size() == 0) + if (m_dblLog->size() == 0) { g_log.warning() << "There is no entry in this property " << this->name() << std::endl; return; @@ -648,12 +712,12 @@ namespace Algorithms size_t progslot = 0; - for (int i = 0; i < mlog->size(); i ++) + for (int i = 0; i < m_dblLog->size(); i ++) { lastTime = t; //The new entry - t = mlog->nthTime(i); - double val = mlog->nthValue(i); + t = m_dblLog->nthTime(i); + double val = m_dblLog->nthValue(i); // A good value? if (filterIncrease && filterDecrease) @@ -666,14 +730,14 @@ namespace Algorithms if (i == 0) isGood = false; else - isGood = ((val >= min) && (val < max)) && t >= startTime && t <= stopTime && val-mlog->nthValue(i-1) > 0; + isGood = ((val >= min) && (val < max)) && t >= startTime && t <= stopTime && val-m_dblLog->nthValue(i-1) > 0; } else if (filterDecrease) { if (i == 0) isGood = false; else - isGood = ((val >= min) && (val < max)) && t >= startTime && t <= stopTime && val-mlog->nthValue(i-1) < 0; + isGood = ((val >= min) && (val < max)) && t >= startTime && t <= stopTime && val-m_dblLog->nthValue(i-1) < 0; } else { @@ -708,28 +772,6 @@ namespace Algorithms } split.push_back( SplittingInterval(start, stop, wsindex) ); - /* - if (numgood == 1) - { - //There was only one point with the value. Use the last time, - the tolerance, as the end time - if (centre) - { - stop = t-tol; - // stop = lastTime - tol; - } - else - { - stop = t; - } - split.push_back( SplittingInterval(start, stop, wsindex) ); - } - else - { - //At least 2 good values. Save the end time - XXX XXX - } - */ - //Reset the number of good ones, for next time numgood = 0; } @@ -737,7 +779,7 @@ namespace Algorithms } // Progress bar.. - size_t tmpslot = i*90/mlog->size(); + size_t tmpslot = i*90/m_dblLog->size(); if (tmpslot > progslot) { progslot = tmpslot; @@ -766,7 +808,6 @@ namespace Algorithms * SINGLE log values >= min and < max. Creates SplittingInterval's where * times match the log values, and going to index==0. * - * @param mlog :: Log. * @param split :: Splitter that will be filled. * @param indexwsindexmap :: Index. * @param logvalueranges :: A vector of double. Each 2i and 2i+1 pair is one individual log value range. @@ -776,9 +817,10 @@ namespace Algorithms * @param startTime :: Start time. * @param stopTime :: Stop time. */ - void GenerateEventsFilter::makeMultipleFiltersByValues(Kernel::TimeSeriesProperty<double>* mlog, - Kernel::TimeSplitterType& split, std::map<size_t, int> indexwsindexmap, std::vector<double> logvalueranges, - bool centre, bool filterIncrease, bool filterDecrease, Kernel::DateAndTime startTime, Kernel::DateAndTime stopTime) + void GenerateEventsFilter::makeMultipleFiltersByValues(TimeSplitterType& split, map<size_t, int> indexwsindexmap, + vector<double> logvalueranges, + bool centre, bool filterIncrease, bool filterDecrease, + DateAndTime startTime, DateAndTime stopTime) { // 0. Set up double timetolerance = 0.0; @@ -789,9 +831,9 @@ namespace Algorithms time_duration tol = DateAndTime::durationFromSeconds( timetolerance ); // 1. Do nothing if the log is empty. - if (mlog->size() == 0) + if (m_dblLog->size() == 0) { - g_log.warning() << "There is no entry in this property " << mlog->name() << std::endl; + g_log.warning() << "There is no entry in this property " << m_dblLog->name() << std::endl; return; } @@ -804,7 +846,7 @@ namespace Algorithms double currValue = 0.0; size_t progslot = 0; - int logsize = mlog->size(); + int logsize = m_dblLog->size(); for (int i = 0; i < logsize; i ++) { @@ -814,8 +856,8 @@ namespace Algorithms bool completehalf = false; bool newsplitter = false; - currTime = mlog->nthTime(i); - currValue = mlog->nthValue(i); + currTime = m_dblLog->nthTime(i); + currValue = m_dblLog->nthValue(i); // b) Filter out by time and direction (optional) bool intime = false; @@ -855,7 +897,7 @@ namespace Algorithms { // Filter out one direction int direction = 0; - if ( mlog->nthValue(i)-mlog->nthValue(i-1) > 0) + if ( m_dblLog->nthValue(i)-m_dblLog->nthValue(i-1) > 0) direction = 1; else direction = -1; @@ -1005,7 +1047,7 @@ namespace Algorithms // f) Progress // Progress bar.. - size_t tmpslot = i*90/mlog->size(); + size_t tmpslot = i*90/m_dblLog->size(); if (tmpslot > progslot) { progslot = tmpslot; @@ -1020,6 +1062,161 @@ namespace Algorithms return; } + //----------------------------------------------------------------------------------------------- + /** Generate filters for an integer log + * @param minvalue :: minimum allowed log value + * @param maxvalue :: maximum allowed log value + * @param filterIncrease :: include log value increasing period; + * @param filterDecrease :: include log value decreasing period + */ + void GenerateEventsFilter::processIntegerValueFilter(TimeSplitterType& splitters, int minvalue, int maxvalue, + bool filterIncrease, bool filterDecrease, DateAndTime runend) + { + // 1. Determine the filter mode + int delta = 0; + double singlemode; + if (minvalue == maxvalue) + { + singlemode = true; + } + else + { + double deltadbl = getProperty("LogValueInterval"); + delta = static_cast<int>(deltadbl+0.5); + if (delta <= 0) + throw runtime_error("LogValueInterval cannot be 0 or negative for integer log."); + singlemode = false; + } + + // 2. Search along log to generate splitters + size_t numlogentries = m_intLog->size(); + vector<DateAndTime> times = m_intLog->timesAsVector(); + vector<int> values = m_intLog->valuesAsVector(); + + time_duration timetol = DateAndTime::durationFromSeconds( m_logTimeTolerance*m_timeUnitConvertFactor*1.0E-9); + + DateAndTime splitstarttime(0); + int pregroup = -1; + + g_log.debug() << "[DB] Number of log entries = " << numlogentries << ".\n"; + + for (size_t i = 0; i < numlogentries; ++i) + { + int currvalue = values[i]; + int currgroup = -1; + + // a) Determine allowed and group + if (currvalue > maxvalue || currvalue < minvalue) + { + // Log value is out of range + g_log.debug() << "[DB] Entry[" << i << "] = " << currvalue << ": out of range. " << ".\n"; + } + else if ((i == 0) || (i >= 1 && ((filterIncrease && values[i] >= values[i-1]) || + (filterDecrease && values[i] <= values[i])))) + { + // First entry (regardless direction) and other entries considering change of value + if (singlemode) + { + currgroup = 0; + } + else + { + currgroup = (currvalue-minvalue)/delta; + } + g_log.debug() << "[DB] Entry[" << i << "] = " << currvalue << ": belong to group " + << currgroup << ".\n"; + } + + // b) Consider to make a splitter + bool statuschanged; + if (pregroup >= 0 && currgroup < 0) + { + // i. previous log is in allowed region. but this one is not. create a splitter + if (splitstarttime.totalNanoseconds() == 0) + throw runtime_error("Programming logic error."); + make_splitter(splitstarttime, times[i], pregroup, timetol, splitters); + + splitstarttime = DateAndTime(0); + statuschanged = true; + } + else if (pregroup < 0 && currgroup >= 0) + { + // ii. previous log is not allowed, but this one is. this is the start of a new splitter + splitstarttime = times[i]; + statuschanged = true; + } + else if (currgroup >= 0 && pregroup != currgroup) + { + // iii. migrated to a new region + if (splitstarttime.totalNanoseconds() == 0) + throw runtime_error("Programming logic error (1)."); + make_splitter(splitstarttime, times[i], pregroup, timetol, splitters); + + splitstarttime = times[i]; + statuschanged = true; + } + else + { + // iv. no need to do anything + statuschanged = false; + } + + // c) Update + if (statuschanged) + pregroup = currgroup; + } + + // 3. Create the last splitter if existing + if (pregroup >= 0) + { + // Last entry is in an allowed region. + if (splitstarttime.totalNanoseconds() == 0) + throw runtime_error("Programming logic error (1)."); + make_splitter(splitstarttime, runend, pregroup, timetol, splitters); + } + + // 4. Write to the information workspace + if (singlemode) + { + TableRow newrow = m_filterInfoWS->appendRow(); + stringstream message; + message << m_intLog->name() << " = " << minvalue; + newrow << 0 << message.str(); + } + else + { + int logvalue = minvalue; + int wsindex = 0; + while (logvalue <= maxvalue) + { + stringstream message; + if (logvalue + delta - 1 > logvalue) + message << m_intLog->name() << " = [" << logvalue << ", " << logvalue+delta-1 << "]"; + else + message << m_intLog->name() << " = " << logvalue ; + + message << ". Value change direction: "; + if (filterIncrease && filterDecrease) + message << "Both."; + else if (filterIncrease) + message << "Increasing. "; + else if (filterDecrease) + message << "Decreasing. "; + + TableRow newrow = m_filterInfoWS->appendRow(); + newrow << wsindex << message.str(); + + ++ wsindex; + logvalue += delta; + } + } + + g_log.notice() << "[DB] Number of splitters = " << splitters.size() + << ", Number of split info = " << m_filterInfoWS->rowCount() << ".\n"; + + return; + } + //---------------------------------------------------------------------------------------------- /** Do a binary search in the following list diff --git a/Code/Mantid/Framework/Algorithms/test/CopyInstrumentParametersTest.h b/Code/Mantid/Framework/Algorithms/test/CopyInstrumentParametersTest.h new file mode 100644 index 0000000000000000000000000000000000000000..5501d5ddf10df740b699429046c6308500d93412 --- /dev/null +++ b/Code/Mantid/Framework/Algorithms/test/CopyInstrumentParametersTest.h @@ -0,0 +1,131 @@ +#ifndef COPYINSTRUMENTPARAMETERSTEST_H_ +#define COPYINSTRUMENTPARAMETERSTEST_H_ + +#include <cxxtest/TestSuite.h> + +#include "MantidDataHandling/LoadInstrument.h" +#include "MantidAPI/IAlgorithm.h" +#include "MantidAlgorithms/CopyInstrumentParameters.h" +#include "MantidAPI/Workspace.h" +#include "MantidDataObjects/Workspace2D.h" +#include "MantidAPI/MatrixWorkspace.h" +#include "MantidAPI/WorkspaceFactory.h" +#include "WorkspaceCreationHelperTest.h" +#include "MantidAPI/AnalysisDataService.h" +#include "MantidAPI/ITableWorkspace.h" +#include "MantidAPI/TableRow.h" +#include "MantidKernel/V3D.h" +#include "MantidGeometry/Instrument.h" +#include "MantidGeometry/Instrument/Component.h" +#include "MantidDataHandling/LoadEmptyInstrument.h" +#include "MantidGeometry/Instrument/ComponentHelper.h" +#include <stdexcept> + +using namespace Mantid::Algorithms; +using namespace Mantid::API; +using namespace Mantid::Kernel; +using namespace Mantid::DataObjects; +using Mantid::Geometry::IDetector_const_sptr; +using Mantid::Geometry::IComponent_const_sptr; +using namespace Geometry::ComponentHelper; + +class CopyInstrumentParametersTest : public CxxTest::TestSuite +{ +public: + + void testName() + { + TS_ASSERT_EQUALS( copyInstParam.name(), "CopyInstrumentParameters" ) + } + + void testInit() + { + copyInstParam.initialize(); + TS_ASSERT( copyInstParam.isInitialized() ) + } + + void testExec() + { + // Create input workspace with paremeterised instrument and put into data store + MatrixWorkspace_sptr ws1 = WorkspaceCreationHelper::create2DWorkspaceWithFullInstrument(3, 10, true); + const std::string wsName1("CopyInstParamWs1"); + AnalysisDataServiceImpl & dataStore = AnalysisDataService::Instance(); + dataStore.add(wsName1, ws1); + /// Create output workspace with the same base instrument and put into data store + MatrixWorkspace_sptr ws2 = WorkspaceFactory::Instance().create( ws1 ); + const std::string wsName2("CopyInstParamWs2"); + dataStore.add(wsName2, ws2); + + // Set properties + TS_ASSERT_THROWS_NOTHING(copyInstParam.setPropertyValue("InputWorkspace", wsName1 )); + TS_ASSERT_THROWS_NOTHING(copyInstParam.setPropertyValue("OutputWorkspace", wsName2 )); + // Get instrument of input workspace and move some detectors + Geometry::ParameterMap *pmap; + pmap = &(ws1->instrumentParameters()); + Geometry::Instrument_const_sptr instrument = ws1->getInstrument(); + IComponent_const_sptr det1 =instrument->getDetector(1); + Geometry::ComponentHelper::moveComponent(*det1, *pmap, V3D(6.0,0.0,0.7), Absolute ); + IComponent_const_sptr det2 =instrument->getDetector(2); + Geometry::ComponentHelper::moveComponent(*det2, *pmap, V3D(6.0,0.1,0.7), Absolute ); + + // Verify that a detector moved in the input workspace has not yet been moved in the output workspace + IDetector_const_sptr deto = ws2->getDetector(0); + V3D newPos = deto->getPos(); + TS_ASSERT_DELTA( newPos.X() , 5.0, 0.0001); + + // Execute Algorithm + TS_ASSERT_THROWS_NOTHING(copyInstParam.execute()); + TS_ASSERT( copyInstParam.isExecuted() ); + + // Verify that the detectors in the output workspace have been moved as in the input workspace before execution + IDetector_const_sptr deto1 = ws2->getDetector(0); + int id1 = deto1->getID(); + V3D newPos1 = deto1->getPos(); + TS_ASSERT_EQUALS( id1, 1); + TS_ASSERT_DELTA( newPos1.X() , 6.0, 0.0001); + TS_ASSERT_DELTA( newPos1.Y() , 0.0, 0.0001); + TS_ASSERT_DELTA( newPos1.Z() , 0.7, 0.0001); + IDetector_const_sptr deto2 = ws2->getDetector(1); + int id2 = deto2->getID(); + V3D newPos2 = deto2->getPos(); + TS_ASSERT_EQUALS( id2, 2); + TS_ASSERT_DELTA( newPos2.X() , 6.0, 0.0001); + TS_ASSERT_DELTA( newPos2.Y() , 0.1, 0.0001); + TS_ASSERT_DELTA( newPos2.Z() , 0.7, 0.0001); + + dataStore.remove(wsName1); + dataStore.remove(wsName2); + } + + void testDifferent_BaseInstrument_Throws() + { + // Create input workspace with parameterised instrument and put into data store + MatrixWorkspace_sptr ws1 = WorkspaceCreationHelper::create2DWorkspaceWithFullInstrument(3, 10, true); + const std::string wsName1("CopyInstParamWs1"); + AnalysisDataServiceImpl & dataStore = AnalysisDataService::Instance(); + dataStore.add(wsName1, ws1); + // Create output workspace with another parameterised instrument and put into data store + MatrixWorkspace_sptr ws2 = WorkspaceCreationHelper::create2DWorkspaceWithFullInstrument(3, 10, true); + const std::string wsName2("CopyInstParamWs2"); + dataStore.add(wsName2, ws2); + + // Set properties + TS_ASSERT_THROWS_NOTHING(copyInstParam.setPropertyValue("InputWorkspace", wsName1 )); + TS_ASSERT_THROWS_NOTHING(copyInstParam.setPropertyValue("OutputWorkspace", wsName2 )); + + // Execute Algorithm, should throw invalid argument exception + copyInstParam.setRethrows(true); + TS_ASSERT_THROWS(copyInstParam.execute(), std::invalid_argument); + TS_ASSERT( !copyInstParam.isExecuted() ); + + dataStore.remove(wsName1); + dataStore.remove(wsName2); + } + +private: + CopyInstrumentParameters copyInstParam; + + +}; + +#endif /*COPYINSTRUMENTPARAMETERSTEST_H_*/ diff --git a/Code/Mantid/Framework/Algorithms/test/GenerateEventsFilterTest.h b/Code/Mantid/Framework/Algorithms/test/GenerateEventsFilterTest.h index c053d707eafc2fd831387d8d3d1281480f0afd6a..5e25cce6fc665f07c044c487cdbd109f400beca7 100644 --- a/Code/Mantid/Framework/Algorithms/test/GenerateEventsFilterTest.h +++ b/Code/Mantid/Framework/Algorithms/test/GenerateEventsFilterTest.h @@ -31,6 +31,8 @@ using namespace Mantid; using namespace Mantid::Algorithms; using namespace Mantid::API; +using namespace Mantid::DataObjects; +using namespace Mantid::Kernel; using namespace std; @@ -52,8 +54,8 @@ public: return; } - /* - * Test generation of splitters by time + //---------------------------------------------------------------------------------------------- + /** Test generation of splitters by time */ void test_genTime1Interval() { @@ -113,8 +115,8 @@ public: return; } - /* - * Test generation of splitters by time + //---------------------------------------------------------------------------------------------- + /** Test generation of splitters by time * (1) Multiple time interval * (2) Default start time and stop time */ @@ -180,8 +182,8 @@ public: return; } - /* - * Generate filter by log value in simple way + //---------------------------------------------------------------------------------------------- + /** Generate filter by log value in simple way * (1) No time tolerance * (2) Just one */ @@ -238,9 +240,8 @@ public: return; } - - /* - * Generate filter by log values in increasing + //---------------------------------------------------------------------------------------------- + /** Generate filter by log values in increasing * (1) No time tolerance * (2) Just one */ @@ -297,9 +298,70 @@ public: } + //---------------------------------------------------------------------------------------------- + /** Test to generate a set of filters against an integer log + */ + void test_genFilterByIntegerLog() + { + // 1. Create input + DataObjects::EventWorkspace_sptr eventWS = createEventWorkspace2(); + AnalysisDataService::Instance().addOrReplace("TestEventData2", eventWS); + + // 2. Init and set property + GenerateEventsFilter alg; + alg.initialize(); + + TS_ASSERT_THROWS_NOTHING(alg.setProperty("InputWorkspace", "TestEventData2")); + TS_ASSERT_THROWS_NOTHING(alg.setProperty("OutputWorkspace", "IntLogSplitter")); + TS_ASSERT_THROWS_NOTHING(alg.setProperty("InformationWorkspace", "IntLogInformation")); + TS_ASSERT_THROWS_NOTHING(alg.setProperty("LogName", "DummyIntLog")); + TS_ASSERT_THROWS_NOTHING(alg.setProperty("MinimumLogValue", static_cast<double>(1))); + TS_ASSERT_THROWS_NOTHING(alg.setProperty("MaximumLogValue", static_cast<double>(10))); + TS_ASSERT_THROWS_NOTHING(alg.setProperty("LogValueInterval", static_cast<double>(1))); + TS_ASSERT_THROWS_NOTHING(alg.setProperty("UnitOfTime", "Seconds")); + TS_ASSERT_THROWS_NOTHING(alg.setProperty("FilterLogValueByChangingDirection", "Both")); + TS_ASSERT_THROWS_NOTHING(alg.setProperty("TimeTolerance", 0.05)); + TS_ASSERT_THROWS_NOTHING(alg.setProperty("LogBoundary", "Centre")); + + // 3. Running and get result + TS_ASSERT_THROWS_NOTHING(alg.execute()); + TS_ASSERT(alg.isExecuted()); + + // 4. Retrieve output workspaces + SplittersWorkspace_sptr splittersws = boost::dynamic_pointer_cast<SplittersWorkspace>( + AnalysisDataService::Instance().retrieve("IntLogSplitter")); + TS_ASSERT(splittersws); + + TableWorkspace_const_sptr infows = boost::dynamic_pointer_cast<TableWorkspace>( + AnalysisDataService::Instance().retrieve("IntLogInformation")); + TS_ASSERT(infows); + + // 5. Check output workspace + size_t numsplitters = 10; + TS_ASSERT_EQUALS(splittersws->getNumberSplitters(), numsplitters); + size_t numoutputs = 10; + TS_ASSERT_EQUALS(infows->rowCount(), numoutputs); + + int64_t factor = static_cast<int64_t>(1.0E9+0.5); + + Kernel::SplittingInterval s0 = splittersws->getSplitter(0); + TS_ASSERT_EQUALS(s0.start().totalNanoseconds(), 11*factor-5*factor/100); + TS_ASSERT_EQUALS(s0.index(), 0); + + Kernel::SplittingInterval s9 = splittersws->getSplitter(9); + // TS_ASSERT_EQUALS(s14.start(), 3000924990); + // TS_ASSERT_EQUALS(s14.stop(), 3000974990); + TS_ASSERT_EQUALS(s9.index(), 9); + + // 6. Clean + AnalysisDataService::Instance().remove("TestEventData2"); + AnalysisDataService::Instance().remove("IntLogSplitter"); + AnalysisDataService::Instance().remove("IntLogInformation"); + } + - /* - * Create an EventWorkspace including + //---------------------------------------------------------------------------------------------- + /** Create an EventWorkspace including * (1) proton charge log from * (2) test log in sin function with time */ @@ -362,8 +424,92 @@ public: return eventws; } + //---------------------------------------------------------------------------------------------- + /** Create an EventWorkspace containing an integer log + * 1. Run start = 10 (s) + * 2. Run end = 22 (s) + * 3. Pulse = 0.5 (s) + * 4. Log change = 1 (s) + */ + EventWorkspace_sptr createEventWorkspace2() + { + using namespace WorkspaceCreationHelper; + + // 1. Empty workspace + EventWorkspace_sptr eventws = + WorkspaceCreationHelper::createEventWorkspaceWithFullInstrument(2, 2, true); + + // 2. Run star time + int64_t factor = static_cast<int64_t>(1.0E9+0.5); + int64_t runstarttime_ns = 10*factor; + int64_t runstoptime_ns = 22*factor; + int64_t pulsetime_ns = 5*factor/10; + int64_t logduration_ns = 1*factor; + + Kernel::DateAndTime runstarttime(runstarttime_ns); + eventws->mutableRun().addProperty("run_start", runstarttime.toISO8601String()); + Kernel::DateAndTime runendtime(runstoptime_ns); + eventws->mutableRun().addProperty("run_end", runendtime.toISO8601String()); + + // 3. Proton charge log + Kernel::TimeSeriesProperty<double> *protonchargelog = + new Kernel::TimeSeriesProperty<double>("proton_charge"); + int64_t curtime_ns = runstarttime_ns; + while (curtime_ns <= runstoptime_ns) + { + Kernel::DateAndTime curtime(curtime_ns); + protonchargelog->addValue(curtime, 1.0); + curtime_ns += pulsetime_ns; + } + eventws->mutableRun().addProperty(protonchargelog, true); + + // 4. Integer log + TimeSeriesProperty<int> *dummyintlog = new TimeSeriesProperty<int>("DummyIntLog"); + + int logstep = 1; + int logvalue = 0; + // double period = static_cast<double>(pulsetime_ns); + curtime_ns = runstarttime_ns; + while (curtime_ns < runstoptime_ns) + { + Kernel::DateAndTime curtime(curtime_ns); + dummyintlog->addValue(curtime, logvalue); + + curtime_ns += logduration_ns; + logvalue += logstep; + } + eventws->mutableRun().addProperty(dummyintlog, true); + + return eventws; + } }; #endif /* MANTID_ALGORITHMS_GENERATEEVENTSFILTERTEST_H_ */ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Code/Mantid/Framework/Crystal/inc/MantidCrystal/MaskPeaksWorkspace.h b/Code/Mantid/Framework/Crystal/inc/MantidCrystal/MaskPeaksWorkspace.h index 223af86e045909c6ff291cb2251efbd2e05c4c6f..19baacd471aa727acf65dfc861c1d4785cbe93e2 100644 --- a/Code/Mantid/Framework/Crystal/inc/MantidCrystal/MaskPeaksWorkspace.h +++ b/Code/Mantid/Framework/Crystal/inc/MantidCrystal/MaskPeaksWorkspace.h @@ -53,14 +53,15 @@ public: virtual const std::string category() const { return "Crystal"; } private: - DataObjects::EventWorkspace_sptr inputW; ///< A pointer to the input workspace + API::MatrixWorkspace_sptr inputW; ///< A pointer to the input workspace API::MatrixWorkspace_sptr outputW; ///< A pointer to the output workspace // Overridden Algorithm methods void init(); void exec(); - std::size_t getWkspIndex(detid2index_map * pixel_to_wi, Geometry::RectangularDetector_const_sptr det, + std::size_t getWkspIndex(detid2index_map * pixel_to_wi, Geometry::IComponent_const_sptr comp, const int x, const int y); void getTofRange(double &tofMin, double &tofMax, const double tofPeak, const MantidVec& tof); + int findPixelID(std::string bankName, int col, int row); /// Read in all the input parameters void retrieveProperties(); diff --git a/Code/Mantid/Framework/Crystal/src/MaskPeaksWorkspace.cpp b/Code/Mantid/Framework/Crystal/src/MaskPeaksWorkspace.cpp index 13221346548e939d7488790794dcfea024f39e40..37461da068c1427f8a15448b6252b4cfcbd248b6 100644 --- a/Code/Mantid/Framework/Crystal/src/MaskPeaksWorkspace.cpp +++ b/Code/Mantid/Framework/Crystal/src/MaskPeaksWorkspace.cpp @@ -1,7 +1,7 @@ /*WIKI* -Mask pixels in an EventWorkspace close to peak positions from a PeaksWorkspace. -Peaks could come from ISAW diamond stripping routine for SNAP data. Only works on EventWorkspaces and for instruments with RectangularDetector's. +Mask pixels in an Workspace close to peak positions from a PeaksWorkspace. +Peaks could come from ISAW diamond stripping routine for SNAP data. Only works on Workspaces and for instruments with RectangularDetector's. *WIKI*/ //---------------------------------------------------------------------- @@ -37,6 +37,7 @@ namespace Mantid using namespace Kernel; using namespace API; using namespace DataObjects; + using namespace Geometry; using std::string; @@ -54,16 +55,16 @@ namespace Mantid void MaskPeaksWorkspace::init() { - declareProperty(new WorkspaceProperty<EventWorkspace>("InputWorkspace", "", Direction::Input), + declareProperty(new WorkspaceProperty<MatrixWorkspace>("InputWorkspace", "", Direction::Input), "A workspace containing one or more rectangular area detectors. Each spectrum needs to correspond to only one pixelID (e.g. no grouping or previous calls to SumNeighbours)."); declareProperty(new WorkspaceProperty<PeaksWorkspace>("InPeaksWorkspace", "", Direction::Input), "The name of the workspace that will be created. Can replace the input workspace."); - declareProperty("XMin", -2, "Minimum of X (col) Range to mask peak"); - declareProperty("XMax", 2, "Maximum of X (col) Range to mask peak"); - declareProperty("YMin", -2, "Minimum of Y (row) Range to mask peak"); - declareProperty("YMax", 2, "Maximum of Y (row) Range to mask peak"); - declareProperty("TOFMin", EMPTY_DBL(), "Minimum TOF relative to peak's center TOF."); - declareProperty("TOFMax", EMPTY_DBL(), "Maximum TOF relative to peak's center TOF."); + declareProperty("XMin", -2, "Minimum of X (col) Range to mask peak relative to peak's center"); + declareProperty("XMax", 2, "Maximum of X (col) Range to mask peak relative to peak's center"); + declareProperty("YMin", -2, "Minimum of Y (row) Range to mask peak relative to peak's center"); + declareProperty("YMax", 2, "Maximum of Y (row) Range to mask peak relative to peak's center"); + declareProperty("TOFMin", EMPTY_DBL(), "Optional(all TOF if not specified): Minimum TOF relative to peak's center TOF."); + declareProperty("TOFMax", EMPTY_DBL(), "Optional(all TOF if not specified): Maximum TOF relative to peak's center TOF."); } /** Executes the algorithm @@ -79,7 +80,7 @@ namespace Mantid peaksW = AnalysisDataService::Instance().retrieveWS<PeaksWorkspace>(getProperty("InPeaksWorkspace")); //To get the workspace index from the detector ID - detid2index_map * pixel_to_wi = inputW->getDetectorIDToWorkspaceIndexMap(true); + detid2index_map * pixel_to_wi = inputW->getDetectorIDToWorkspaceIndexMap(false); //Get some stuff from the input workspace Geometry::Instrument_const_sptr inst = inputW->getInstrument(); if (!inst) @@ -94,37 +95,36 @@ namespace Mantid // Loop over peaks const std::vector<Peak> & peaks = peaksW->getPeaks(); - for ( auto peak = peaks.begin(); peak != peaks.end(); ++peak ) + PARALLEL_FOR3(inputW,peaksW,tablews) + for (int i=0; i < static_cast<int>(peaks.size()); i++) { + PARALLEL_START_INTERUPT_REGION + Peak peak = peaks[i]; // get the peak location on the detector - double col = peak->getCol(); - double row = peak->getRow(); + double col = peak.getCol(); + double row = peak.getRow(); int xPeak = int(col+0.5)-1; int yPeak = int(row+0.5)-1; g_log.debug() << "Generating information for peak at x=" << xPeak << " y=" << yPeak << "\n"; // the detector component for the peak will have all pixels that we mask - const string bankName = peak->getBankName(); + const string bankName = peak.getBankName(); + if(bankName.compare("None") == 0) continue; Geometry::IComponent_const_sptr comp = inst->getComponentByName(bankName); if (!comp) { - throw std::invalid_argument("Component "+bankName+" does not exist in instrument"); - } - Geometry::RectangularDetector_const_sptr det - = boost::dynamic_pointer_cast<const Geometry::RectangularDetector>(comp); - if (!det) - { - throw std::invalid_argument("Component "+bankName+" is not a rectangular detector"); + continue; + g_log.debug() << "Component "+bankName+" does not exist in instrument\n"; } // determine the range in time-of-flight double x0; double xf; bool tofRangeSet(false); - if(xPeak < det->xpixels() && xPeak >= 0 && yPeak < det->ypixels() && yPeak >= 0) + size_t wi = this->getWkspIndex(pixel_to_wi, comp, xPeak, yPeak); + if (wi != static_cast<size_t>(EMPTY_INT())) { // scope limit the workspace index - size_t wi = this->getWkspIndex(pixel_to_wi, det, xPeak, yPeak); - this->getTofRange(x0, xf, peak->getTOF(), inputW->readX(wi)); + this->getTofRange(x0, xf, peak.getTOF(), inputW->readX(wi)); tofRangeSet = true; } @@ -134,15 +134,13 @@ namespace Mantid { for (int iy=m_yMin; iy <= m_yMax; iy++) { - std::cout << "in inner loop " << xPeak+ix << ", " << yPeak+iy << std::endl; //Find the pixel ID at that XY position on the rectangular detector - if(xPeak+ix >= det->xpixels() || xPeak+ix < 0)continue; - if(yPeak+iy >= det->ypixels() || yPeak+iy < 0)continue; - spectra.insert(this->getWkspIndex(pixel_to_wi, det, xPeak+ix, yPeak+iy)); + size_t wj = this->getWkspIndex(pixel_to_wi, comp, xPeak+ix, yPeak+iy); + if (wj == static_cast<size_t>(EMPTY_INT())) continue; + spectra.insert(wj); if (!tofRangeSet) { // scope limit the workspace index - size_t wi = this->getWkspIndex(pixel_to_wi, det, xPeak+ix, yPeak+iy); - this->getTofRange(x0, xf, peak->getTOF(), inputW->readX(wi)); + this->getTofRange(x0, xf, peak.getTOF(), inputW->readX(wj)); tofRangeSet = true; } } @@ -152,22 +150,24 @@ namespace Mantid if (!tofRangeSet) { g_log.warning() << "Failed to set time-of-flight range for peak (x=" << xPeak - << ", y=" << yPeak << ", tof=" << peak->getTOF() << ")\n"; + << ", y=" << yPeak << ", tof=" << peak.getTOF() << ")\n"; } else if (spectra.empty()) { g_log.warning() << "Failed to find spectra for peak (x=" << xPeak - << ", y=" << yPeak << ", tof=" << peak->getTOF() << ")\n"; + << ", y=" << yPeak << ", tof=" << peak.getTOF() << ")\n"; continue; } else + PARALLEL_CRITICAL(tablews) { // append to the table workspace API::TableRow newrow = tablews->appendRow(); newrow << x0 << xf << Kernel::Strings::toString(spectra); } + PARALLEL_END_INTERUPT_REGION } // end loop over peaks - + PARALLEL_CHECK_INTERUPT_REGION // Mask bins API::IAlgorithm_sptr maskbinstb = this->createChildAlgorithm("MaskBinsFromTable", 0.5, 1.0, true); @@ -211,28 +211,52 @@ namespace Mantid } } - size_t MaskPeaksWorkspace::getWkspIndex(detid2index_map *pixel_to_wi, Geometry::RectangularDetector_const_sptr det, + size_t MaskPeaksWorkspace::getWkspIndex(detid2index_map *pixel_to_wi, Geometry::IComponent_const_sptr comp, const int x, const int y) { - if ( (x >= det->xpixels()) || (x < 0) // this check is unnecessary as callers are doing it too - || (y >= det->ypixels()) || (y < 0)) // but just to make debugging easier + Geometry::RectangularDetector_const_sptr det + = boost::dynamic_pointer_cast<const Geometry::RectangularDetector>(comp); + if(det) { - std::stringstream msg; - msg << "Failed to find workspace index for x=" << x << " y=" << y - << "(max x=" << det->xpixels() << ", max y=" << det->ypixels() << ")"; - throw std::runtime_error(msg.str()); - } + if(x >= det->xpixels() || x < 0 || y >= det->ypixels() || y < 0) return EMPTY_INT(); + if ( (x >= det->xpixels()) || (x < 0) // this check is unnecessary as callers are doing it too + || (y >= det->ypixels()) || (y < 0)) // but just to make debugging easier + { + std::stringstream msg; + msg << "Failed to find workspace index for x=" << x << " y=" << y + << "(max x=" << det->xpixels() << ", max y=" << det->ypixels() << ")"; + throw std::runtime_error(msg.str()); + } - int pixelID = det->getAtXY(x,y)->getID(); + int pixelID = det->getAtXY(x,y)->getID(); - //Find the corresponding workspace index, if any - if (pixel_to_wi->find(pixelID) == pixel_to_wi->end()) + //Find the corresponding workspace index, if any + if (pixel_to_wi->find(pixelID) == pixel_to_wi->end()) + { + std::stringstream msg; + msg << "Failed to find workspace index for x=" << x << " y=" << y; + throw std::runtime_error(msg.str()); + } + return (*pixel_to_wi)[pixelID]; + } + else { - std::stringstream msg; - msg << "Failed to find workspace index for x=" << x << " y=" << y; - throw std::runtime_error(msg.str()); + std::vector<Geometry::IComponent_const_sptr> children; + boost::shared_ptr<const Geometry::ICompAssembly> asmb = boost::dynamic_pointer_cast<const Geometry::ICompAssembly>(comp); + asmb->getChildren(children, false); + boost::shared_ptr<const Geometry::ICompAssembly> asmb2 = boost::dynamic_pointer_cast<const Geometry::ICompAssembly>(children[0]); + std::vector<Geometry::IComponent_const_sptr> grandchildren; + asmb2->getChildren(grandchildren,false); + int NROWS = static_cast<int>(grandchildren.size()); + int NCOLS = static_cast<int>(children.size()); + // Wish pixels and tubes start at 1 not 0 + if(x-1 >= NCOLS || x-1 < 0 || y-1 >= NROWS || y-1 < 0) return EMPTY_INT(); + std::string bankName = comp->getName(); + detid2index_map::const_iterator it = pixel_to_wi->find(findPixelID(bankName, x, y)); + if ( it == pixel_to_wi->end() ) return EMPTY_INT(); + return (it->second); } - return (*pixel_to_wi)[pixelID]; + return EMPTY_INT(); } /** @@ -254,6 +278,31 @@ namespace Mantid tofMax = tofPeak + m_tofMax; } } + int MaskPeaksWorkspace::findPixelID(std::string bankName, int col, int row) + { + Geometry::Instrument_const_sptr Iptr = inputW->getInstrument(); + boost::shared_ptr<const IComponent> parent = Iptr->getComponentByName(bankName); + if (parent->type().compare("RectangularDetector") == 0) + { + boost::shared_ptr<const RectangularDetector> RDet = boost::shared_dynamic_cast< + const RectangularDetector>(parent); - } // namespace Crystal + boost::shared_ptr<Detector> pixel = RDet->getAtXY(col, row); + return pixel->getID(); + } + else + { + std::string bankName0 = bankName; + //Only works for WISH + bankName0.erase(0,4); + std::ostringstream pixelString; + pixelString << Iptr->getName() << "/" << bankName0 << "/" <<bankName + << "/tube" << std::setw(3) << std::setfill('0')<< col + << "/pixel" << std::setw(4) << std::setfill('0')<< row; + boost::shared_ptr<const Geometry::IComponent> component = Iptr->getComponentByName(pixelString.str()); + boost::shared_ptr<const Detector> pixel = boost::dynamic_pointer_cast<const Detector>(component); + return pixel->getID(); + } + } +} // namespace Crystal } // namespace Mantid diff --git a/Code/Mantid/Framework/DataHandling/CMakeLists.txt b/Code/Mantid/Framework/DataHandling/CMakeLists.txt index 568d513d07228afc41640edcb9c73f8569aafc8c..3958a443a1f393c3d3d6442b1608e46345c35b4c 100644 --- a/Code/Mantid/Framework/DataHandling/CMakeLists.txt +++ b/Code/Mantid/Framework/DataHandling/CMakeLists.txt @@ -281,7 +281,7 @@ set ( INC_FILES ) set ( TEST_FILES - #LoadDAETest.h + LoadDAETest.h #LoadSNSNexusTest.h # TODO has no active tests in it #Needs fixing to not rely on network. SNSLiveEventDataListenerTest.h ADARAPacketTest.h diff --git a/Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/LoadDAE.h b/Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/LoadDAE.h index a6f007cec1563b5a98b601607ef97cd0cfd37d2e..957e8a9725374d3872ae67491ae39444e5004726 100644 --- a/Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/LoadDAE.h +++ b/Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/LoadDAE.h @@ -8,6 +8,7 @@ #include "MantidDataObjects/Workspace2D.h" #include <climits> #include "MantidAPI/WorkspaceGroup.h" +#include "MantidAPI/DeprecatedAlgorithm.h" //---------------------------------------------------------------------- // Forward declaration @@ -64,7 +65,7 @@ namespace Mantid File change history is stored at: <https://github.com/mantidproject/mantid>. Code Documentation is available at: <http://doxygen.mantidproject.org> */ - class DLLExport LoadDAE : public API::Algorithm + class DLLExport LoadDAE : public API::Algorithm, public API::DeprecatedAlgorithm { public: /// Default constructor @@ -76,7 +77,7 @@ namespace Mantid /// Algorithm's version for identification overriding a virtual method virtual int version() const { return 1; } /// Algorithm's category for identification overriding a virtual method - virtual const std::string category() const { return "DataHandling\\DataAcquisition"; } + virtual const std::string category() const { return "Deprecated"; } /// Personal wrapper for sqrt to allow msvs to compile static double dblSqrt(double in); diff --git a/Code/Mantid/Framework/DataHandling/src/LoadDAE.cpp b/Code/Mantid/Framework/DataHandling/src/LoadDAE.cpp index f294cd1f79d4d9b2e37c0344b31e1a83b9509003..ebc8b9a41c1a21c93cc4f74e930abc88237cf4fe 100644 --- a/Code/Mantid/Framework/DataHandling/src/LoadDAE.cpp +++ b/Code/Mantid/Framework/DataHandling/src/LoadDAE.cpp @@ -60,7 +60,10 @@ namespace Mantid LoadDAE::LoadDAE() : Algorithm(), m_daename(""), m_numberOfSpectra(0), m_numberOfPeriods(0), m_list(false), m_interval(false), m_spec_list(), m_spec_min(0), m_spec_max(Mantid::EMPTY_INT()),m_firstRun(true) - {} + { + this->useAlgorithm("StartLiveData"); + this->deprecatedDate("2013-04-22"); + } /// load data from the DAE diff --git a/Code/Mantid/Framework/DataHandling/src/LoadEventNexus.cpp b/Code/Mantid/Framework/DataHandling/src/LoadEventNexus.cpp index 179cbe15911340d6a08361b5055c928cd18d8df2..b3357c27784c25870ae8637296663a31c118cb58 100644 --- a/Code/Mantid/Framework/DataHandling/src/LoadEventNexus.cpp +++ b/Code/Mantid/Framework/DataHandling/src/LoadEventNexus.cpp @@ -2,7 +2,7 @@ The LoadEventNeXus algorithm loads data from an EventNexus file into an [[EventWorkspace]]. The default histogram bin boundaries consist of a single bin able to hold all events (in all pixels), and will have their [[units]] set to time-of-flight. Since it is an [[EventWorkspace]], it can be rebinned to finer bins with no loss of data. -Sample logs, such as motor positions or e.g. temperature vs time, are also loaded using the [[LoadLogsFromSNSNexus]] child algorithm. +Sample logs, such as motor positions or e.g. temperature vs time, are also loaded using the [[LoadNexusLogs]] child algorithm. === Optional properties === @@ -1938,90 +1938,90 @@ BankPulseTimes * LoadEventNexus::runLoadNexusLogs(const std::string &nexusfilena */ void LoadEventNexus::deleteBanks(API::MatrixWorkspace_sptr workspace, std::vector<std::string> bankNames) { - Instrument_sptr inst = boost::const_pointer_cast<Instrument>(workspace->getInstrument()->baseInstrument()); - //Build a list of Rectangular Detectors - std::vector<boost::shared_ptr<RectangularDetector> > detList; - for (int i=0; i < inst->nelements(); i++) - { - boost::shared_ptr<RectangularDetector> det; - boost::shared_ptr<ICompAssembly> assem; - boost::shared_ptr<ICompAssembly> assem2; - - det = boost::dynamic_pointer_cast<RectangularDetector>( (*inst)[i] ); - if (det) - { - detList.push_back(det); - } - else - { - //Also, look in the first sub-level for RectangularDetectors (e.g. PG3). - // We are not doing a full recursive search since that will be very long for lots of pixels. - assem = boost::dynamic_pointer_cast<ICompAssembly>( (*inst)[i] ); - if (assem) - { - for (int j=0; j < assem->nelements(); j++) - { - det = boost::dynamic_pointer_cast<RectangularDetector>( (*assem)[j] ); - if (det) - { - detList.push_back(det); - - } - else - { - //Also, look in the second sub-level for RectangularDetectors (e.g. PG3). - // We are not doing a full recursive search since that will be very long for lots of pixels. - assem2 = boost::dynamic_pointer_cast<ICompAssembly>( (*assem)[j] ); - if (assem2) - { - for (int k=0; k < assem2->nelements(); k++) - { - det = boost::dynamic_pointer_cast<RectangularDetector>( (*assem2)[k] ); - if (det) - { - detList.push_back(det); - } - } - } - } - } - } - } - } + Instrument_sptr inst = boost::const_pointer_cast<Instrument>(workspace->getInstrument()->baseInstrument()); + //Build a list of Rectangular Detectors + std::vector<boost::shared_ptr<RectangularDetector> > detList; + for (int i=0; i < inst->nelements(); i++) + { + boost::shared_ptr<RectangularDetector> det; + boost::shared_ptr<ICompAssembly> assem; + boost::shared_ptr<ICompAssembly> assem2; + + det = boost::dynamic_pointer_cast<RectangularDetector>( (*inst)[i] ); + if (det) + { + detList.push_back(det); + } + else + { + //Also, look in the first sub-level for RectangularDetectors (e.g. PG3). + // We are not doing a full recursive search since that will be very long for lots of pixels. + assem = boost::dynamic_pointer_cast<ICompAssembly>( (*inst)[i] ); + if (assem) + { + for (int j=0; j < assem->nelements(); j++) + { + det = boost::dynamic_pointer_cast<RectangularDetector>( (*assem)[j] ); + if (det) + { + detList.push_back(det); + + } + else + { + //Also, look in the second sub-level for RectangularDetectors (e.g. PG3). + // We are not doing a full recursive search since that will be very long for lots of pixels. + assem2 = boost::dynamic_pointer_cast<ICompAssembly>( (*assem)[j] ); + if (assem2) + { + for (int k=0; k < assem2->nelements(); k++) + { + det = boost::dynamic_pointer_cast<RectangularDetector>( (*assem2)[k] ); + if (det) + { + detList.push_back(det); + } + } + } + } + } + } + } + } if (detList.size() == 0) return; - for (int i = 0; i<static_cast<int>(detList.size()); i++) - { - bool keep = false; - boost::shared_ptr<RectangularDetector> det = detList[i]; - std::string det_name = det->getName(); - for (int j = 0; j<static_cast<int>(bankNames.size()); j++) - { - size_t pos = bankNames[j].find("_events"); - if(det_name.compare(bankNames[j].substr(0,pos)) == 0) keep = true; - if(keep) break; - } - if (!keep) - { - boost::shared_ptr<const IComponent> parent = inst->getComponentByName(det_name); - std::vector<Geometry::IComponent_const_sptr> children; - boost::shared_ptr<const Geometry::ICompAssembly> asmb = boost::dynamic_pointer_cast<const Geometry::ICompAssembly>(parent); - asmb->getChildren(children, false); - for (int col = 0; col<static_cast<int>(children.size()); col++) - { - boost::shared_ptr<const Geometry::ICompAssembly> asmb2 = boost::dynamic_pointer_cast<const Geometry::ICompAssembly>(children[col]); - std::vector<Geometry::IComponent_const_sptr> grandchildren; - asmb2->getChildren(grandchildren,false); - - for (int row = 0; row<static_cast<int>(grandchildren.size()); row++) - { - Detector* d = dynamic_cast<Detector*>(const_cast<IComponent*>(grandchildren[row].get())); - inst->removeDetector(d); - } - } - IComponent* comp = dynamic_cast<IComponent*>(detList[i].get()); - inst->remove(comp); - } - } + for (int i = 0; i<static_cast<int>(detList.size()); i++) + { + bool keep = false; + boost::shared_ptr<RectangularDetector> det = detList[i]; + std::string det_name = det->getName(); + for (int j = 0; j<static_cast<int>(bankNames.size()); j++) + { + size_t pos = bankNames[j].find("_events"); + if(det_name.compare(bankNames[j].substr(0,pos)) == 0) keep = true; + if(keep) break; + } + if (!keep) + { + boost::shared_ptr<const IComponent> parent = inst->getComponentByName(det_name); + std::vector<Geometry::IComponent_const_sptr> children; + boost::shared_ptr<const Geometry::ICompAssembly> asmb = boost::dynamic_pointer_cast<const Geometry::ICompAssembly>(parent); + asmb->getChildren(children, false); + for (int col = 0; col<static_cast<int>(children.size()); col++) + { + boost::shared_ptr<const Geometry::ICompAssembly> asmb2 = boost::dynamic_pointer_cast<const Geometry::ICompAssembly>(children[col]); + std::vector<Geometry::IComponent_const_sptr> grandchildren; + asmb2->getChildren(grandchildren,false); + + for (int row = 0; row<static_cast<int>(grandchildren.size()); row++) + { + Detector* d = dynamic_cast<Detector*>(const_cast<IComponent*>(grandchildren[row].get())); + inst->removeDetector(d); + } + } + IComponent* comp = dynamic_cast<IComponent*>(detList[i].get()); + inst->remove(comp); + } + } return; } //----------------------------------------------------------------------------- diff --git a/Code/Mantid/Framework/DataHandling/test/LoadDAETest.h b/Code/Mantid/Framework/DataHandling/test/LoadDAETest.h index fe5bba2740ae3e20d0f68444e2d045f41bebe923..ef7884d632b0c4007671cdbbef048d18c5e6da3c 100644 --- a/Code/Mantid/Framework/DataHandling/test/LoadDAETest.h +++ b/Code/Mantid/Framework/DataHandling/test/LoadDAETest.h @@ -4,193 +4,30 @@ #include <cxxtest/TestSuite.h> #include "MantidDataHandling/LoadDAE.h" -#include "MantidAPI/WorkspaceFactory.h" -#include "MantidDataObjects/ManagedWorkspace2D.h" -#include "MantidAPI/AnalysisDataService.h" -#include "MantidAPI/FrameworkManager.h" -#include "MantidKernel/ConfigService.h" -#include "MantidKernel/TimeSeriesProperty.h" -#ifdef _WIN32 -#include <winsock2.h> -#else -#include <netdb.h> -#include <arpa/inet.h> -#endif - -using namespace Mantid::API; -using namespace Mantid::Kernel; using namespace Mantid::DataHandling; -using namespace Mantid::DataObjects; class LoadDAETest : public CxxTest::TestSuite { -private: - // Function to determine whether we're running test at RAL or not - // because it won't work anywhere else - bool atRAL() - { - char ac[80]; - if (gethostname(ac, sizeof(ac)) == -1) { - // On failure assume outside of RAL - return 0; - } - - struct hostent *phe = gethostbyname(ac); - if (phe == 0) { - // On failure assume outside of RAL - return 0; - } - - for (int i = 0; phe->h_addr_list[i] != 0; ++i) { - struct in_addr addr; - memcpy(&addr, phe->h_addr_list[i], sizeof(struct in_addr)); - const std::string ip(inet_ntoa(addr)); - if (ip.find("130.246")==0) return 1; // Yes, we're at RAL! - } - - return 0; - } - public: static LoadDAETest *createSuite() { return new LoadDAETest(); } static void destroySuite(LoadDAETest *suite) { delete suite; } - LoadDAETest() - { - // Hostname of computer with DAE to connect to - m_inputDAE="ndw714.isis.cclrc.ac.uk"; - //m_inputDAE="isis53147.nd.rl.ac.uk"; - } - void testInit() { - TS_ASSERT_THROWS_NOTHING( m_loader.initialize()); - TS_ASSERT( m_loader.isInitialized() ); + LoadDAE loader; + TS_ASSERT_THROWS_NOTHING( loader.initialize()); + TS_ASSERT( loader.isInitialized() ); } - void testExec() + void testDeprecated() { - -#ifdef _WIN32 - WSADATA wsaData; - WSAStartup(MAKEWORD(2,2), &wsaData); -#endif - - if ( !m_loader.isInitialized() ) m_loader.initialize(); - - // Set inputs - TS_ASSERT_THROWS_NOTHING(m_loader.setPropertyValue("DAEname", m_inputDAE)); - TS_ASSERT_THROWS_NOTHING(m_loader.setPropertyValue("SpectrumMin", "1")); - TS_ASSERT_THROWS_NOTHING(m_loader.setPropertyValue("SpectrumMax", "2")); - - m_outputSpace = "DAEouter"; - TS_ASSERT_THROWS_NOTHING(m_loader.setPropertyValue("OutputWorkspace", m_outputSpace)); - - std::string result; - TS_ASSERT_THROWS_NOTHING( result = m_loader.getPropertyValue("DAEname") ); - TS_ASSERT( ! result.compare(m_inputDAE)); - - // Only do the rest if the test is being run on a machine at RAL, - // because it will fail if you're anywhere else - // (can't reach the machine where the DAE instance is running) - if ( atRAL() ) - { - - TS_ASSERT_THROWS_NOTHING(m_loader.execute()); - TS_ASSERT_EQUALS( m_loader.isExecuted(),true); - - // Get back the saved workspace - Workspace_sptr output; - TS_ASSERT_THROWS_NOTHING(output = AnalysisDataService::Instance().retrieve(m_outputSpace)); - if (output != 0) - { - Workspace2D_sptr output2D = boost::dynamic_pointer_cast<Workspace2D>(output); - - // As we are checking a live DAE, we cannot be sure what we will see - // as setup will change with experiments. All we can do is test - // things that must always be true irrespective of setup - - // check number of spectra returned - TS_ASSERT_EQUALS( output2D->getNumberHistograms(), 2); - - // Check two X vectors are the same - TS_ASSERT( (output2D->dataX(0)) == (output2D->dataX(1)) ); - - // Check two Y arrays have the same number of elements - TS_ASSERT_EQUALS( output2D->dataY(0).size(), output2D->dataY(1).size() ); - - // Check the unit has been set correctly - TS_ASSERT_EQUALS( output2D->getAxis(0)->unit()->unitID(), "TOF" ); - TS_ASSERT( ! output2D-> isDistribution() ); - } - } + LoadDAE loader; + TS_ASSERT( dynamic_cast<Mantid::API::DeprecatedAlgorithm*>(&loader) ); + TS_ASSERT_EQUALS(loader.deprecationMsg(&loader), "LoadDAE is deprecated (on 2013-04-22). Use StartLiveData instead."); } -// void testExecMultiPeriod() -// { -// -//#ifdef _WIN32 -// WSADATA wsaData; -// WSAStartup(MAKEWORD(2,2), &wsaData); -//#endif -// -// if ( !m_loader.isInitialized() ) m_loader.initialize(); -// -// // Should fail because mandatory parameter has not been set -// // TS_ASSERT_THROWS(m_loader.execute(),std::runtime_error); -// -// m_inputDAE="ndxcrisp"; -// // Set inputs -// m_loader.setPropertyValue("DAEname", m_inputDAE); -// m_loader.setPropertyValue("SpectrumMin", "1"); -// m_loader.setPropertyValue("SpectrumMax", "2"); -// -// m_outputSpace = "DAEouter"; -// m_loader.setPropertyValue("OutputWorkspace", m_outputSpace); -// -// std::string result; -// TS_ASSERT_THROWS_NOTHING( result = m_loader.getPropertyValue("DAEname") ) -// TS_ASSERT( ! result.compare(m_inputDAE)); -// -// TS_ASSERT_THROWS_NOTHING(m_loader.execute()); -// TS_ASSERT_EQUALS( m_loader.isExecuted(),true); -// -// WorkspaceGroup_sptr outgrp; -// TS_ASSERT_THROWS_NOTHING(outgrp =boost::dynamic_pointer_cast<WorkspaceGroup> (AnalysisDataService::Instance().retrieve(m_outputSpace))); -// // Get back the saved workspace -// Workspace_sptr output; -// TS_ASSERT_THROWS_NOTHING(output = AnalysisDataService::Instance().retrieve(m_outputSpace+"_1")); -// if (output != 0) -// { -// Workspace2D_sptr output2D = boost::dynamic_pointer_cast<Workspace2D>(output); -// -// // As we are checking a live DAE, we cannot be sure what we will see -// // as setup will change with experiments. All we can do is test -// // things that must always be true irrespective of setup -// -// // check number of spectra returned -// TS_ASSERT_EQUALS( output2D->getNumberHistograms(), 4); -// -// // Check two X vectors are the same -// TS_ASSERT( (output2D->dataX(0)) == (output2D->dataX(1)) ); -// -// // Check two Y arrays have the same number of elements -// TS_ASSERT_EQUALS( output2D->dataY(0).size(), output2D->dataY(1).size() ); -// -// // Check the unit has been set correctly -// TS_ASSERT_EQUALS( output2D->getAxis(0)->unit()->unitID(), "TOF" ) -// TS_ASSERT( ! output2D-> isDistribution() ) -// } -// Workspace_sptr output2; -// TS_ASSERT_THROWS_NOTHING(output2 = AnalysisDataService::Instance().retrieve(m_outputSpace+"_2")); -// } - -private: - LoadDAE m_loader; - std::string m_inputDAE; - std::string m_outputSpace; }; #endif /*LOADDAETEST_H_*/ diff --git a/Code/Mantid/Framework/Kernel/CMakeLists.txt b/Code/Mantid/Framework/Kernel/CMakeLists.txt index 96d3beb6fe4c7b778ca3466009d408e7d721d9e1..b766f298a4782b8885ca566591d05c1cd194c27e 100644 --- a/Code/Mantid/Framework/Kernel/CMakeLists.txt +++ b/Code/Mantid/Framework/Kernel/CMakeLists.txt @@ -383,6 +383,7 @@ set ( PYTHONALG_DIRS "${MANTID_ROOT}/Framework/PythonAPI/PythonAlgorithms;${MANT set ( PYTHONPLUGIN_DIRS "${MANTID_ROOT}/Framework/PythonAPI/PythonAlgorithms;${MANTID_ROOT}/Framework/PythonInterface/plugins" ) set ( DATADIRS ${MANTID_ROOT}/../../Test/AutoTestData;${MANTID_ROOT}/instrument ) set ( COLORMAPS_FOLDER ${MANTID_ROOT}/Installers/colormaps/ ) +SET ( MANTIDPUBLISHER "http://upload.mantidproject.org/scriptrepository/payload/publish_debug" ) # Construct script paths. set ( MANTID_SCRIPTS ${MANTID_ROOT}/scripts ) @@ -456,6 +457,7 @@ set ( PLUGINS ${MANTID_ROOT}/plugins ) set ( PYTHONALG_DIRS ${PLUGINS}/PythonAlgs ) # deprecated set ( PYTHONPLUGIN_DIRS ${PLUGINS}/python ) set ( DATADIRS "" ) +SET ( MANTIDPUBLISHER "http://upload.mantidproject.org/scriptrepository/payload/publish" ) # Construct script paths by replacing the old MANTID_ROOT with the new one. # Unfortunately string (REGEX REPLACE ... )removes the semi-colons so we have to do this in a loop. diff --git a/Code/Mantid/Framework/Kernel/inc/MantidKernel/FacilityInfo.h b/Code/Mantid/Framework/Kernel/inc/MantidKernel/FacilityInfo.h index 56b1cdd7fc1b227196565e1b9f7c4589caa4a45a..a1ff88242718a1853abe7c417d858da958a21b8e 100644 --- a/Code/Mantid/Framework/Kernel/inc/MantidKernel/FacilityInfo.h +++ b/Code/Mantid/Framework/Kernel/inc/MantidKernel/FacilityInfo.h @@ -82,8 +82,6 @@ public: std::vector<InstrumentInfo> instruments(const std::string& tech) const; /// Returns instruments with given name const InstrumentInfo & instrument(std::string iName = "") const; - /// Returns the proxy string related to ScriptRepository settings for its installation. - const std::string & getHTTPProxy() const {return m_HTTPProxy;} private: void fillZeroPadding(const Poco::XML::Element* elem); @@ -94,7 +92,6 @@ private: void fillCatalogName(const Poco::XML::Element* elem); void fillInstruments(const Poco::XML::Element* elem); void fillLiveListener(const Poco::XML::Element* elem); - void fillHTTPProxy(const Poco::XML::Element* elem); /// Add new extension void addExtension(const std::string& ext); @@ -108,7 +105,6 @@ private: std::vector<InstrumentInfo> m_instruments; ///< list of instruments of this facility std::string m_catalogName; ///< name of the catalog system of this facility std::string m_liveListener; ///< name of the default live listener - std::string m_HTTPProxy; ///< name of the default httpProxy static Logger& g_log; ///< logger }; diff --git a/Code/Mantid/Framework/Kernel/src/FacilityInfo.cpp b/Code/Mantid/Framework/Kernel/src/FacilityInfo.cpp index 10e43961db873c4a947da0cad5e3599d1411231a..d7261f5761831c3b15510954ae482643c46456d8 100644 --- a/Code/Mantid/Framework/Kernel/src/FacilityInfo.cpp +++ b/Code/Mantid/Framework/Kernel/src/FacilityInfo.cpp @@ -28,8 +28,7 @@ Logger& FacilityInfo::g_log(Logger::get("FacilityInfo")); */ FacilityInfo::FacilityInfo(const Poco::XML::Element* elem) : m_name(elem->getAttribute("name")), m_zeroPadding(0), m_delimiter(), m_extensions(), - m_soapEndPoint(), m_archiveSearch(), m_instruments(), m_catalogName(), m_liveListener(), - m_HTTPProxy() + m_soapEndPoint(), m_archiveSearch(), m_instruments(), m_catalogName(), m_liveListener() { if (m_name.empty()) { @@ -45,7 +44,6 @@ FacilityInfo::FacilityInfo(const Poco::XML::Element* elem) : fillArchiveNames(elem); fillCatalogName(elem); fillLiveListener(elem); - fillHTTPProxy(elem); fillInstruments(elem); // Make sure this is last as it picks up some defaults that are set above } @@ -203,18 +201,6 @@ void FacilityInfo::fillLiveListener(const Poco::XML::Element* elem) } } -/// Called from constructor to fill HTTP proxy name -void FacilityInfo::fillHTTPProxy(const Poco::XML::Element* elem) -{ - // Get the first HTTP proxy element (will be NULL if there's none) - Element * proxy = elem->getChildElement("httpproxy"); - if ( proxy ) - { - // Get the name of the HTTP proxy - empty string will be returned if missing - m_HTTPProxy = proxy->getAttribute("url"); - } -} - /** * Returns instrument with given name * @param iName Instrument name diff --git a/Code/Mantid/Framework/Kernel/test/FacilitiesTest.h b/Code/Mantid/Framework/Kernel/test/FacilitiesTest.h index d1e8e2cebb8800af6c69902d1f4814713008dbd2..731f6bef95584f00907729694a90924bfd0d8345 100644 --- a/Code/Mantid/Framework/Kernel/test/FacilitiesTest.h +++ b/Code/Mantid/Framework/Kernel/test/FacilitiesTest.h @@ -76,7 +76,6 @@ public: TS_ASSERT_EQUALS( fac->extensions()[0],".xyz" ); TS_ASSERT_EQUALS( fac->preferredExtension(), ".xyz" ); TS_ASSERT( fac->getSoapEndPoint().empty() ); - TS_ASSERT( fac->getHTTPProxy().empty() ); TS_ASSERT( fac->catalogName().empty() ); TS_ASSERT( fac->archiveSearch().empty() ); TS_ASSERT( fac->liveListener().empty() ); diff --git a/Code/Mantid/Framework/MDAlgorithms/inc/MantidMDAlgorithms/ConvertToMD.h b/Code/Mantid/Framework/MDAlgorithms/inc/MantidMDAlgorithms/ConvertToMD.h index 9c0fcd8f17e3b0d6e2d3b7edc44a4fd7ad35e890..f87af0838d8256dad499f0e9054297f4c229c519 100644 --- a/Code/Mantid/Framework/MDAlgorithms/inc/MantidMDAlgorithms/ConvertToMD.h +++ b/Code/Mantid/Framework/MDAlgorithms/inc/MantidMDAlgorithms/ConvertToMD.h @@ -68,19 +68,20 @@ namespace MDAlgorithms void exec(); /// Sets documentation strings for this algorithm virtual void initDocs(); - /// the pointer to class which keeps output MD workspace and is responsible for adding data to N-dimensional workspace; - boost::shared_ptr<MDEvents::MDEventWSWrapper> m_OutWSWrapper; /// progress reporter boost::scoped_ptr<API::Progress > m_Progress; - /// pointer to the class, which does the particular conversion - boost::shared_ptr<MDEvents::ConvToMDBase> m_Convertor; /// logger -> to provide logging, for MD dataset file operations static Mantid::Kernel::Logger& g_Log; //------------------------------------------------------------------------------------------------------------------------------------------ protected: //for testing, otherwise private: + /// the pointer to class which keeps output MD workspace and is responsible for adding data to N-dimensional workspace; + boost::shared_ptr<MDEvents::MDEventWSWrapper> m_OutWSWrapper; /// pointer to the input workspace; Mantid::API::MatrixWorkspace_sptr m_InWS2D; + /// pointer to the class, which does the particular conversion + boost::shared_ptr<MDEvents::ConvToMDBase> m_Convertor; + static Mantid::Kernel::Logger & getLogger(); @@ -92,8 +93,8 @@ namespace MDAlgorithms bool buildTargetWSDescription(API::IMDEventWorkspace_sptr spws,const std::string &Q_mod_req,const std::string &dEModeRequested,const std::vector<std::string> &other_dim_names, const std::string &convert_to_,MDEvents::MDWSDescription &targWSDescr); - /// Store metadata - void copyMetaData(API::IMDEventWorkspace_sptr mdEventWS) const; + /// Store metadata and set some methadata, needed for plugin to run on the target workspace description + void copyMetaData(API::IMDEventWorkspace_sptr mdEventWS,MDEvents::MDWSDescription &targWSDescr) const; // DataObjects::TableWorkspace_const_sptr preprocessDetectorsPositions( Mantid::API::MatrixWorkspace_const_sptr InWS2D,const std::string &dEModeRequested,bool updateMasks); diff --git a/Code/Mantid/Framework/MDAlgorithms/inc/MantidMDAlgorithms/LoadMD.h b/Code/Mantid/Framework/MDAlgorithms/inc/MantidMDAlgorithms/LoadMD.h index 538f8d41784544af017c7efc316547b5c1dc5ef8..e2cb4b745a6526dc49e2546289d6ff458616740e 100644 --- a/Code/Mantid/Framework/MDAlgorithms/inc/MantidMDAlgorithms/LoadMD.h +++ b/Code/Mantid/Framework/MDAlgorithms/inc/MantidMDAlgorithms/LoadMD.h @@ -74,6 +74,11 @@ namespace MDAlgorithms void loadDimensions(); + /// Load all the affine matricies + void loadAffineMatricies(API::IMDWorkspace_sptr ws); + /// Load a given affine matrix + API::CoordTransform *loadAffineMatrix(std::string entry_name); + /// Open file handle ::NeXus::File * file; diff --git a/Code/Mantid/Framework/MDAlgorithms/inc/MantidMDAlgorithms/SaveMD.h b/Code/Mantid/Framework/MDAlgorithms/inc/MantidMDAlgorithms/SaveMD.h index 483fdcfbf95ad7c2b77baa0c1878f2a09825c896..292b1dd7be324c43d18b34dae653d55b1527dd5b 100644 --- a/Code/Mantid/Framework/MDAlgorithms/inc/MantidMDAlgorithms/SaveMD.h +++ b/Code/Mantid/Framework/MDAlgorithms/inc/MantidMDAlgorithms/SaveMD.h @@ -7,6 +7,7 @@ namespace Mantid { + namespace MDAlgorithms { @@ -63,6 +64,17 @@ namespace MDAlgorithms /// Save the MDHistoWorkspace. void doSaveHisto(Mantid::MDEvents::MDHistoWorkspace_sptr ws); + /// Save all the affine matricies + void saveAffineTransformMatricies(::NeXus::File * const file, + API::IMDWorkspace_const_sptr ws); + /// Save a given affine matrix + void saveAffineTransformMatrix(::NeXus::File * const file, + API::CoordTransform *transform, + std::string entry_name); + /// Save a generic matrix + template<typename T> + void saveMatrix(::NeXus::File * const file, std::string name, + Kernel::Matrix<T> &m, ::NeXus::NXnumtype type, std::string tag=""); }; diff --git a/Code/Mantid/Framework/MDAlgorithms/src/ConvertToMD.cpp b/Code/Mantid/Framework/MDAlgorithms/src/ConvertToMD.cpp index 22e20215dd5959a2190d86337c4d7d9966b72ea4..429025b89acc51a928cdf62d19fcaad1bb8cb0c8 100644 --- a/Code/Mantid/Framework/MDAlgorithms/src/ConvertToMD.cpp +++ b/Code/Mantid/Framework/MDAlgorithms/src/ConvertToMD.cpp @@ -370,7 +370,9 @@ void ConvertToMD::exec() else // setup existing MD workspace as workspace target. m_OutWSWrapper->setMDWS(spws); - // preprocess detectors; + // copy the necessary methadata and get the unique number, that identifies the run, the source workspace came from. + copyMetaData(spws,targWSDescr); + // preprocess detectors; targWSDescr.m_PreprDetTable = this->preprocessDetectorsPositions(m_InWS2D,dEModReq,getProperty("UpdateMasks")); @@ -386,7 +388,7 @@ void ConvertToMD::exec() g_log.information()<<" conversion started\n"; m_Convertor->runConversion(m_Progress.get()); - copyMetaData(spws); + //JOB COMPLETED: setProperty("OutputWorkspace", boost::dynamic_pointer_cast<IMDEventWorkspace>(spws)); @@ -400,12 +402,24 @@ void ConvertToMD::exec() /** * Copy over the metadata from the input matrix workspace to output MDEventWorkspace * @param mdEventWS :: The output MDEventWorkspace + * @param targWSDescr :: The descrition of the target workspace, used in the algorithm + * + * @return :: the number of experiment info added from the current MD workspace */ -void ConvertToMD::copyMetaData(API::IMDEventWorkspace_sptr mdEventWS) const +void ConvertToMD::copyMetaData(API::IMDEventWorkspace_sptr mdEventWS, MDEvents::MDWSDescription &targWSDescr) const { + // Copy ExperimentInfo (instrument, run, sample) to the output WS + API::ExperimentInfo_sptr ei(m_InWS2D->cloneExperimentInfo()); + + ei->mutableRun().addProperty("RUBW_MATRIX",targWSDescr.m_Wtransf.getVector(),true); + ei->mutableRun().addProperty("W_MATRIX",targWSDescr.getPropertyValueAsType<std::vector<double> >("W_MATRIX"),true); + + uint16_t runIndex = mdEventWS->addExperimentInfo(ei); + const MantidVec & binBoundaries = m_InWS2D->readX(0); auto mapping = m_InWS2D->spectraMap().createIDGroupsMap(); + uint16_t nexpts = mdEventWS->getNumExperimentInfo(); for(uint16_t i = 0; i < nexpts; ++i) { @@ -413,6 +427,10 @@ void ConvertToMD::copyMetaData(API::IMDEventWorkspace_sptr mdEventWS) const expt->mutableRun().storeHistogramBinBoundaries(binBoundaries); expt->cacheDetectorGroupings(*mapping); } + + // and add it to the target workspace description for further usage as identifier for the workspaces, which come from this run. + targWSDescr.addProperty("RUN_INDEX",runIndex,true); + } /** Constructor */ diff --git a/Code/Mantid/Framework/MDAlgorithms/src/LoadMD.cpp b/Code/Mantid/Framework/MDAlgorithms/src/LoadMD.cpp index d4bf79c5f50c4270bee84ad47ee32cbee0b7594f..3c032951e077c79858b32e5b0261bf76138de67a 100644 --- a/Code/Mantid/Framework/MDAlgorithms/src/LoadMD.cpp +++ b/Code/Mantid/Framework/MDAlgorithms/src/LoadMD.cpp @@ -35,6 +35,7 @@ and used by other algorithms, they should not be needed in daily use. #include "MantidMDEvents/MDBoxFlatTree.h" #include "MantidMDEvents/MDHistoWorkspace.h" #include "MantidMDEvents/BoxControllerNeXusIO.h" +#include "MantidMDEvents/CoordTransformAffine.h" #include <nexus/NeXusException.hpp> #include <boost/algorithm/string.hpp> #include <vector> @@ -165,10 +166,74 @@ namespace Mantid + //---------------------------------------------------------------------------------------------- + /** Load the ExperimentInfo blocks, if any, in the NXS file + * + * @param ws :: MDEventWorkspace/MDHisto to load + */ + void LoadMD::loadExperimentInfos(boost::shared_ptr<Mantid::API::MultipleExperimentInfos> ws) + { + // First, find how many experimentX blocks there are + std::map<std::string,std::string> entries; + file->getEntries(entries); + std::map<std::string,std::string>::iterator it = entries.begin(); + std::vector<bool> hasExperimentBlock; + uint16_t numExperimentInfo = 0; + for (; it != entries.end(); ++it) + { + std::string name = it->first; + if (boost::starts_with(name, "experiment")) + { + try + { + uint16_t num = boost::lexical_cast<uint16_t>(name.substr(10, name.size()-10)); + if (num+1 > numExperimentInfo) + { + numExperimentInfo = uint16_t(num+uint16_t(1)); + hasExperimentBlock.resize(numExperimentInfo, false); + hasExperimentBlock[num] = true; + } + } + catch (boost::bad_lexical_cast &) + { /* ignore */ } + } + } + + // Now go through in order, loading and adding + for (uint16_t i=0; i < numExperimentInfo; i++) + { + std::string groupName = "experiment" + Strings::toString(i); + if (!numExperimentInfo) + { + g_log.warning() << "NXS file is missing a ExperimentInfo block " << groupName << ". Workspace will be missing ExperimentInfo." << std::endl; + break; + } + file->openGroup(groupName, "NXgroup"); + ExperimentInfo_sptr ei(new ExperimentInfo); + std::string parameterStr; + try + { + // Get the sample, logs, instrument + ei->loadExperimentInfoNexus(file, parameterStr); + // Now do the parameter map + ei->readParameterMap(parameterStr); + // And set it in the workspace. + ws->addExperimentInfo(ei); + } + catch (std::exception & e) + { + g_log.information("Error loading section '" + groupName + "' of nxs file."); + g_log.information(e.what()); + } + file->closeGroup(); + } + + } + - ////---------------------------------------------------------------------------------------------- - ///** Execute the algorithm. - //*/ + //---------------------------------------------------------------------------------------------- + /** Execute the algorithm. + */ void LoadMD::exec() { m_filename = getPropertyValue("Filename"); @@ -254,10 +319,10 @@ namespace Mantid std::vector<int> size(1, static_cast<int>(ws->getNPoints())); file->getSlab(data, start, size); file->closeData(); - } + } //---------------------------------------------------------------------------------------------- - /** Perform loading for a MDHistoWorkspace. + /** Perform loading for a MDHistoWorkspace. * The entry should be open already. */ void LoadMD::loadHisto() @@ -271,6 +336,8 @@ namespace Mantid // Load the WorkspaceHistory "process" ws->history().loadNexus(file); + this->loadAffineMatricies(boost::dynamic_pointer_cast<IMDWorkspace>(ws)); + // Load each data slab this->loadSlab("signal", ws->getSignalArray(), ws, ::NeXus::FLOAT64); this->loadSlab("errors_squared", ws->getErrorSquaredArray(), ws, ::NeXus::FLOAT64); @@ -316,12 +383,12 @@ namespace Mantid template<typename MDE, size_t nd> void LoadMD::doLoad(typename MDEventWorkspace<MDE, nd>::sptr ws) { - // // Are we using the file back end? + // Are we using the file back end? bool FileBackEnd = getProperty("FileBackEnd"); bool BoxStructureOnly = getProperty("BoxStructureOnly"); if (FileBackEnd && BoxStructureOnly) - throw std::invalid_argument("Both BoxStructureOnly and FileBackEnd were set to TRUE: this is not possible."); + throw std::invalid_argument("Both BoxStructureOnly and FileBackEnd were set to TRUE: this is not possible."); CPUTimer tim; Progress * prog = new Progress(this, 0.0, 1.0, 100); @@ -334,6 +401,8 @@ namespace Mantid // Load the WorkspaceHistory "process" ws->history().loadNexus(file); + this->loadAffineMatricies(boost::dynamic_pointer_cast<IMDWorkspace>(ws)); + file->closeGroup(); file->close(); // Add each of the dimension @@ -363,6 +432,7 @@ namespace Mantid // boxes have been already made file-backed when restoring the boxTree; // How much memory for the cache? { + // TODO: Clean up, only a write buffer now double mb = getProperty("Memory"); // Defaults have changed, defauld disk buffer size should be 10 data chunks TODO: find optimal, 100 may be better. @@ -392,6 +462,8 @@ namespace Mantid for (size_t i=0; i<numBoxes; i++) { prog->report(); + MDBox<MDE,nd> * box = dynamic_cast<MDBox<MDE,nd> *>(boxTree[i]); + if(!box)continue; if(BoxEventIndex[2*i+1]>0) // Load in memory NOT using the file as the back-end, boxTree[i]->loadAndAddFrom(loader.get(),BoxEventIndex[2*i],static_cast<size_t>(BoxEventIndex[2*i+1])); @@ -413,10 +485,69 @@ namespace Mantid //TODO:if(!FileBackEnd)ws->refreshCache(); ws->refreshCache(); g_log.debug() << tim << " to refreshCache(). " << ws->getNPoints() << " points after refresh." << std::endl; + g_log.debug() << tim << " to finish up." << std::endl; delete prog; } + /** + * Load all of the affine matricies from the file, create the + * appropriate coordinate transform and set those on the workspace. + * @param ws : workspace to set the coordinate transforms on + */ + void LoadMD::loadAffineMatricies(IMDWorkspace_sptr ws) + { + std::map<std::string, std::string> entries; + file->getEntries(entries); + + if (entries.find("transform_to_orig") != entries.end()) + { + CoordTransform *transform = this->loadAffineMatrix("transform_to_orig"); + ws->setTransformToOriginal(transform); + } + if (entries.find("transform_from_orig") != entries.end()) + { + CoordTransform *transform = this->loadAffineMatrix("transform_from_orig"); + ws->setTransformFromOriginal(transform); + } + } + + /** + * Do that actual loading and manipulating of the read data to create + * the affine matrix and then the appropriate transformation. This is + * currently limited to CoordTransformAffine transforms. + * @param entry_name : the entry point in the NeXus file to read + * @return the coordinate transform object + */ + CoordTransform *LoadMD::loadAffineMatrix(std::string entry_name) + { + file->openData(entry_name); + std::vector<coord_t> vec; + file->getData<coord_t>(vec); + std::string type; + int inD; + int outD; + file->getAttr("type", type); + file->getAttr<int>("rows", outD); + file->getAttr<int>("columns", inD); + file->closeData(); + // Adjust dimensions + inD--; + outD--; + Matrix<coord_t> mat(vec); + CoordTransform *transform = NULL; + if ("CoordTransformAffine" == type) + { + CoordTransformAffine *affine = new CoordTransformAffine(inD, outD); + affine->setMatrix(mat); + transform = affine; + } + else + { + g_log.notice("Do not know how to process coordinate transform " + type); + } + return transform; + } } // namespace Mantid } // namespace MDEvents diff --git a/Code/Mantid/Framework/MDAlgorithms/src/SaveMD.cpp b/Code/Mantid/Framework/MDAlgorithms/src/SaveMD.cpp index 1545df45bc686058c46177e9456ed98cb5745fbe..0d25f5e775ecf7ecb06372a0e01129ffdba3b77f 100644 --- a/Code/Mantid/Framework/MDAlgorithms/src/SaveMD.cpp +++ b/Code/Mantid/Framework/MDAlgorithms/src/SaveMD.cpp @@ -9,8 +9,10 @@ If you specify UpdateFileBackEnd, then any changes (e.g. events added using the *WIKI*/ +#include "MantidAPI/CoordTransform.h" #include "MantidAPI/FileProperty.h" #include "MantidAPI/IMDEventWorkspace.h" +#include "MantidKernel/Matrix.h" #include "MantidKernel/System.h" #include "MantidMDEvents/MDBoxIterator.h" #include "MantidMDEvents/MDEventFactory.h" @@ -118,17 +120,17 @@ namespace MDAlgorithms if(!wsIsFileBacked) { // Erase the file if it exists - Poco::File oldFile(filename); - if (oldFile.exists()) - oldFile.remove(); + Poco::File oldFile(filename); + if (oldFile.exists()) + oldFile.remove(); } Progress * prog = new Progress(this, 0.0, 0.05,1); if(update) // workspace has its own file and ignores any changes to the algorithm parameters { - if(!ws->isFileBacked()) - throw std::runtime_error(" attemtp to update non-file backed workspace"); - filename = bc->getFileIO()->getFileName(); + if(!ws->isFileBacked()) + throw std::runtime_error(" attemtp to update non-file backed workspace"); + filename = bc->getFileIO()->getFileName(); } //----------------------------------------------------------------------------------------------------- @@ -138,86 +140,89 @@ namespace MDAlgorithms MDBoxFlatTree::saveExperimentInfos(file.get(),ws); if(!update) - { - // Save the algorithm history under "process" - ws->getHistory().saveNexus(file.get()); - - // Save some info as attributes. (Note: need to use attributes, not data sets because those cannot be resized). - file->putAttr("definition", ws->id()); - file->putAttr("title", ws->getTitle() ); - // Save each dimension, as their XML representation - for (size_t d=0; d<nd; d++) - { - std::ostringstream mess; - mess << "dimension" << d; - file->putAttr( mess.str(), ws->getDimension(d)->toXMLString() ); - } + { + // Save the algorithm history under "process" + ws->getHistory().saveNexus(file.get()); + + // Write out the affine matrices + this->saveAffineTransformMatricies(file.get(), + boost::dynamic_pointer_cast<const IMDWorkspace>(ws)); + + // Save some info as attributes. (Note: need to use attributes, not data sets because those cannot be resized). + file->putAttr("definition", ws->id()); + file->putAttr("title", ws->getTitle() ); + // Save each dimension, as their XML representation + for (size_t d=0; d<nd; d++) + { + std::ostringstream mess; + mess << "dimension" << d; + file->putAttr( mess.str(), ws->getDimension(d)->toXMLString() ); + } } file->closeGroup(); file->close(); - - MDBoxFlatTree BoxFlatStruct; + MDBoxFlatTree BoxFlatStruct; //----------------------------------------------------------------------------------------------------- if(update) // the workspace is already file backed; We not usually use this mode but want to leave it for compartibility { - // remove all boxes from the DiskBuffer. DB will calculate boxes positions on HDD. - bc->getFileIO()->flushCache(); - // flatten the box structure; this will remember boxes file positions in the box structure - BoxFlatStruct.initFlatStructure(ws,filename); + // remove all boxes from the DiskBuffer. DB will calculate boxes positions on HDD. + bc->getFileIO()->flushCache(); + // flatten the box structure; this will remember boxes file positions in the box structure + BoxFlatStruct.initFlatStructure(ws,filename); } else // not file backed; { - // the boxes file positions are unknown and we need to calculate it. - BoxFlatStruct.initFlatStructure(ws,filename); - // create saver class - auto Saver = boost::shared_ptr<API::IBoxControllerIO>(new MDEvents::BoxControllerNeXusIO(bc.get())); - Saver->setDataType(sizeof(coord_t),MDE::getTypeName()); - if(MakeFileBacked) + // the boxes file positions are unknown and we need to calculate it. + BoxFlatStruct.initFlatStructure(ws,filename); + // create saver class + auto Saver = boost::shared_ptr<API::IBoxControllerIO>(new MDEvents::BoxControllerNeXusIO(bc.get())); + Saver->setDataType(sizeof(coord_t),MDE::getTypeName()); + if(MakeFileBacked) + { + // store saver with box controller + bc->setFileBacked(Saver,filename); + // get access to boxes array + std::vector<API::IMDNode *> &boxes = BoxFlatStruct.getBoxes(); + // calculate the position of the boxes on file, indicating to make them saveable and that the boxes were not saved. + BoxFlatStruct.setBoxesFilePositions(true); + prog->resetNumSteps(boxes.size(),0.06,0.90); + for(size_t i=0;i<boxes.size();i++) { - // store saver with box controller - bc->setFileBacked(Saver,filename); - // get access to boxes array - std::vector<API::IMDNode *> &boxes = BoxFlatStruct.getBoxes(); - // calculate the position of the boxes on file, indicating to make them saveable and that the boxes were not saved. - BoxFlatStruct.setBoxesFilePositions(true); - prog->resetNumSteps(boxes.size(),0.06,0.90); - for(size_t i=0;i<boxes.size();i++) - { - auto saveableTag = boxes[i]->getISaveable(); - if(saveableTag) // only boxes can be saveable - { - // do not spend time on empty boxes - if(boxes[i]->getDataInMemorySize()==0)continue; - // save boxes directly using the boxes file postion, precalculated in boxFlatStructure. - saveableTag->save(); - // remove boxes data from memory. This will actually correctly set the tag indicatin that data were not loaded. - saveableTag->clearDataFromMemory(); - // put boxes into write buffer wich will save them when necessary - //Saver->toWrite(saveTag); - prog->report("Saving Box"); - } - } - // remove everything from diskBuffer; (not sure if it really necessary but just in case , should not make any harm) - Saver->flushCache(); - // drop NeXus on HDD (not sure if it really necessary but just in case ) - Saver->flushData(); + auto saveableTag = boxes[i]->getISaveable(); + if(saveableTag) // only boxes can be saveable + { + // do not spend time on empty boxes + if(boxes[i]->getDataInMemorySize()==0)continue; + // save boxes directly using the boxes file postion, precalculated in boxFlatStructure. + saveableTag->save(); + // remove boxes data from memory. This will actually correctly set the tag indicatin that data were not loaded. + saveableTag->clearDataFromMemory(); + // put boxes into write buffer wich will save them when necessary + //Saver->toWrite(saveTag); + prog->report("Saving Box"); + } } - else // just save data, and finish with it + // remove everything from diskBuffer; (not sure if it really necessary but just in case , should not make any harm) + Saver->flushCache(); + // drop NeXus on HDD (not sure if it really necessary but just in case ) + Saver->flushData(); + } + else // just save data, and finish with it + { + Saver->openFile(filename,"w"); + BoxFlatStruct.setBoxesFilePositions(false); + std::vector<API::IMDNode *> &boxes = BoxFlatStruct.getBoxes(); + std::vector<uint64_t> &eventIndex = BoxFlatStruct.getEventIndex(); + prog->resetNumSteps(boxes.size(),0.06,0.90); + for(size_t i=0;i<boxes.size();i++) { - Saver->openFile(filename,"w"); - BoxFlatStruct.setBoxesFilePositions(false); - std::vector<API::IMDNode *> &boxes = BoxFlatStruct.getBoxes(); - std::vector<uint64_t> &eventIndex = BoxFlatStruct.getEventIndex(); - prog->resetNumSteps(boxes.size(),0.06,0.90); - for(size_t i=0;i<boxes.size();i++) - { - if(eventIndex[2*i+1]==0)continue; - boxes[i]->saveAt(Saver.get(),eventIndex[2*i]); - prog->report("Saving Box"); - } - Saver->closeFile(); + if(eventIndex[2*i+1]==0)continue; + boxes[i]->saveAt(Saver.get(),eventIndex[2*i]); + prog->report("Saving Box"); } + Saver->closeFile(); + } } @@ -225,12 +230,13 @@ namespace MDAlgorithms // OK, we've filled these big arrays of data representing flat box structrre. Save them. progress(0.91, "Writing Box Data"); prog->resetNumSteps(8, 0.92, 1.00); + //Save box structure; BoxFlatStruct.saveBoxStructure(filename); delete prog; - ws->setFileNeedsUpdating(false); + ws->setFileNeedsUpdating(false); } @@ -284,6 +290,9 @@ namespace MDAlgorithms file->putAttr( mess.str(), ws->getDimension(d)->toXMLString() ); } + // Write out the affine matrices + this->saveAffineTransformMatricies(file, boost::dynamic_pointer_cast<const IMDWorkspace>(ws)); + // Check that the typedef has not been changed. The NeXus types would need changing if it does! assert(sizeof(signal_t) == sizeof(double)); @@ -314,7 +323,7 @@ namespace MDAlgorithms } -// + //---------------------------------------------------------------------------------------------- /** Execute the algorithm. */ @@ -337,6 +346,79 @@ namespace MDAlgorithms throw std::runtime_error("SaveMD can only save MDEventWorkspaces and MDHistoWorkspaces.\nPlease use SaveNexus or another algorithm appropriate for this workspace type."); } + /** + * Save the affine matricies to both directional conversions to the + * data. + * @param file : pointer to the NeXus file + * @param ws : workspace to get matrix from + */ + void SaveMD::saveAffineTransformMatricies(::NeXus::File *const file, + IMDWorkspace_const_sptr ws) + { + try { + this->saveAffineTransformMatrix(file, + ws->getTransformToOriginal(), + "transform_to_orig"); + } + catch (std::runtime_error &) + { + // Do nothing + } + try { + this->saveAffineTransformMatrix(file, + ws->getTransformFromOriginal(), + "transform_from_orig"); + } + catch (std::runtime_error &) + { + // Do nothing + } + } + + /** + * Extract and save the requested affine matrix. + * @param file : pointer to the NeXus file + * @param transform : the object to extract the affine matrix from + * @param entry_name : the tag in the NeXus file to save under + */ + void SaveMD::saveAffineTransformMatrix(::NeXus::File *const file, + CoordTransform *transform, + std::string entry_name) + { + Matrix<coord_t> matrix = transform->makeAffineMatrix(); + g_log.debug() << "TRFM: " << matrix.str() << std::endl; + this->saveMatrix<coord_t>(file, entry_name, matrix, + ::NeXus::FLOAT32, transform->id()); + } + + + /** + * Save routine for a generic matrix + * @param file : pointer to the NeXus file + * @param name : the tag in the NeXus file to save under + * @param m : matrix to save + * @param type : NXnumtype for the matrix data + * @param tag : id for an affine matrix conversion + */ + template<typename T> + void SaveMD::saveMatrix(::NeXus::File *const file, std::string name, + Matrix<T> &m, ::NeXus::NXnumtype type, std::string tag) + { + std::vector<T> v = m.getVector(); + // Number of data points + int nPoints = static_cast<int>(v.size()); + + file->makeData(name, type, nPoints, true); + // Need a pointer + file->putData(&v[0]); + if (!tag.empty()) + { + file->putAttr("type", tag); + file->putAttr("rows", static_cast<int>(m.numRows())); + file->putAttr("columns", static_cast<int>(m.numCols())); + } + file->closeData(); + } } // namespace Mantid diff --git a/Code/Mantid/Framework/MDAlgorithms/test/ConvertToMDComponentsTest.h b/Code/Mantid/Framework/MDAlgorithms/test/ConvertToMDComponentsTest.h index 520603e65ede51a013dd7ab95a77b88b9002cd0d..3d695740829106ca7716870a6d2a85977f1cb63a 100644 --- a/Code/Mantid/Framework/MDAlgorithms/test/ConvertToMDComponentsTest.h +++ b/Code/Mantid/Framework/MDAlgorithms/test/ConvertToMDComponentsTest.h @@ -13,6 +13,7 @@ #include "MantidTestHelpers/WorkspaceCreationHelper.h" #include "MantidKernel/UnitFactory.h" #include "MantidKernel/LibraryWrapper.h" +#include "MantidMDEvents/MDWSTransform.h" #include <cxxtest/TestSuite.h> #include <iomanip> #include <iostream> @@ -33,13 +34,28 @@ public: } void setSourceWS(Mantid::API::MatrixWorkspace_sptr InWS2D) { - m_InWS2D = InWS2D; + this->m_InWS2D = InWS2D; + // and create the class, which will deal with the target workspace + if(!this->m_OutWSWrapper) this->m_OutWSWrapper = boost::shared_ptr<MDEvents::MDEventWSWrapper>(new MDEvents::MDEventWSWrapper()); } Convert2MDComponentsTestHelper() { ConvertToMD::initialize(); } + bool buildTargetWSDescription(API::IMDEventWorkspace_sptr spws,const std::string &Q_mod_req,const std::string &dEModeRequested,const std::vector<std::string> &other_dim_names, + const std::string &convert_to_,MDEvents::MDWSDescription &targWSDescr) + { + return ConvertToMD::buildTargetWSDescription(spws,Q_mod_req,dEModeRequested,other_dim_names,convert_to_,targWSDescr); + } + void copyMetaData(API::IMDEventWorkspace_sptr mdEventWS,MDEvents::MDWSDescription &targWSDescr) const + { + ConvertToMD::copyMetaData(mdEventWS,targWSDescr); + } + API::IMDEventWorkspace_sptr createNewMDWorkspace(const MDEvents::MDWSDescription &NewMDWSDescription) + { + return ConvertToMD::createNewMDWorkspace(NewMDWSDescription); + } }; @@ -184,7 +200,58 @@ void testCalcDECol() } +void testCopyMethadata() +{ + Mantid::API::MatrixWorkspace_sptr ws2Dp = AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>("testWSProcessed"); + + API::IMDEventWorkspace_sptr spws; + // create testing part of the algorithm + Convert2MDComponentsTestHelper subAlgo; + // set source workspace as it would be used by the algorithm iteslt; + subAlgo.setSourceWS(ws2Dp); + // and min-max values (they are still needed by the algorithm) + subAlgo.setPropertyValue("MinValues","-10"); + subAlgo.setPropertyValue("MaxValues","10"); + + bool createNewTargetWs(false); + std::vector<std::string> Q_modes = MDEvents::MDTransfFactory::Instance().getKeys(); + std::string dE_mode = Kernel::DeltaEMode().asString(Kernel::DeltaEMode::Elastic); + MDWSTransform QScl; + std::vector<std::string> QScales = QScl.getQScalings(); + + MDEvents::MDWSDescription targWSDescr; + TS_ASSERT_THROWS_NOTHING(createNewTargetWs=subAlgo.buildTargetWSDescription(spws,Q_modes[0],dE_mode,std::vector<std::string>(),QScales[CnvrtToMD::NoScaling],targWSDescr)); + TSM_ASSERT("as spws is null pointer, this should request creating new workspace ",createNewTargetWs) + + TS_ASSERT_THROWS_NOTHING(spws = subAlgo.createNewMDWorkspace(targWSDescr)); + TS_ASSERT(spws); + if(!spws)return; + + // copy the necessary methadata and get the unique number, that identifies the run, the source workspace came from. + TS_ASSERT_THROWS_NOTHING(subAlgo.copyMetaData(spws,targWSDescr)); + + uint16_t runIndex(1000); + TS_ASSERT_THROWS_NOTHING(runIndex=targWSDescr.getPropertyValueAsType<uint16_t>("RUN_INDEX")); + TS_ASSERT_EQUALS(0,runIndex); + + // target workspace has W-matrix, which should be unit matrix + TS_ASSERT(spws->getExperimentInfo(0)->run().hasProperty("W_MATRIX")); + // it also has transformation matrix + TS_ASSERT(spws->getExperimentInfo(0)->run().hasProperty("RUBW_MATRIX")); + + if(!spws->getExperimentInfo(0)->run().hasProperty("W_MATRIX"))return; + + Kernel::DblMatrix UnitMatr(3,3,true); + std::vector<double> libWMatr; + + TS_ASSERT_THROWS_NOTHING(libWMatr=spws->getExperimentInfo(0)->run().getPropertyValueAsType<std::vector<double> >("W_MATRIX")); + + Kernel::DblMatrix wMatr(libWMatr); + TSM_ASSERT("We have not set up anything so it should be unit matrix",wMatr.equals(UnitMatr)); + + +} ConvertToMDComponentsTest() diff --git a/Code/Mantid/Framework/MDAlgorithms/test/ConvertToMDTest.h b/Code/Mantid/Framework/MDAlgorithms/test/ConvertToMDTest.h index e72ea4761be31baedbf818eef1a71234636a66e1..fdbd0255b5cb9be2f683b56b02b4084510dc51a5 100644 --- a/Code/Mantid/Framework/MDAlgorithms/test/ConvertToMDTest.h +++ b/Code/Mantid/Framework/MDAlgorithms/test/ConvertToMDTest.h @@ -268,155 +268,154 @@ static void destroySuite(ConvertToMDTestPerformance * suite) { delete suite; } void test_EventNoUnitsConv() { - TS_WARN("Disabled untill meged with #6852"); - - //NumericAxis *pAxis0 = new NumericAxis(2); - //pAxis0->setUnit("DeltaE"); - //inWsEv->replaceAxis(0,pAxis0); - - //MDWSDescription WSD; - //std::vector<double> min(4,-1e+30),max(4,1e+30); - //WSD.setMinMax(min,max); - - //WSD.buildFromMatrixWS(inWsEv,"Q3D","Indirect"); - - //WSD.m_PreprDetTable =pDetLoc_events; - //WSD.m_RotMatrix = Rot; - //// this one comes from ticket #6852 and would not exist in clear branch. - //WSD.addProperty("RUN_INDEX",10,true); - - //// create new target MD workspace - //pTargWS->releaseWorkspace(); - //pTargWS->createEmptyMDWS(WSD); - - //ConvToMDSelector AlgoSelector; - //pConvMethods = AlgoSelector.convSelector(inWsEv); - //TS_ASSERT_THROWS_NOTHING(pConvMethods->initialize(WSD,pTargWS)); - - //pMockAlgorithm->resetProgress(numHist); - ////Clock.elapsedCPU(); - //std::time (&start); - //TS_ASSERT_THROWS_NOTHING(pConvMethods->runConversion(pMockAlgorithm->getProgress())); - //std::time (&end); - //double sec = std::difftime (end,start); - //TS_WARN("Time to complete: <EventWSType,Q3D,Indir,ConvertNo,CrystType>: "+boost::lexical_cast<std::string>(sec)+" sec"); + + + NumericAxis *pAxis0 = new NumericAxis(2); + pAxis0->setUnit("DeltaE"); + inWsEv->replaceAxis(0,pAxis0); + + MDWSDescription WSD; + std::vector<double> min(4,-1e+30),max(4,1e+30); + WSD.setMinMax(min,max); + + WSD.buildFromMatrixWS(inWsEv,"Q3D","Indirect"); + + WSD.m_PreprDetTable =pDetLoc_events; + WSD.m_RotMatrix = Rot; + // this one comes from ticket #6852 and would not exist in clear branch. + WSD.addProperty("RUN_INDEX",static_cast<uint16_t>(10),true); + + // create new target MD workspace + pTargWS->releaseWorkspace(); + pTargWS->createEmptyMDWS(WSD); + + ConvToMDSelector AlgoSelector; + pConvMethods = AlgoSelector.convSelector(inWsEv); + TS_ASSERT_THROWS_NOTHING(pConvMethods->initialize(WSD,pTargWS)); + + pMockAlgorithm->resetProgress(numHist); + //Clock.elapsedCPU(); + std::time (&start); + TS_ASSERT_THROWS_NOTHING(pConvMethods->runConversion(pMockAlgorithm->getProgress())); + std::time (&end); + double sec = std::difftime (end,start); + TS_WARN("Time to complete: <EventWSType,Q3D,Indir,ConvertNo,CrystType>: "+boost::lexical_cast<std::string>(sec)+" sec"); } void test_EventFromTOFConv() { - TS_WARN("Disabled untill meged with #6852"); + - //NumericAxis *pAxis0 = new NumericAxis(2); - //pAxis0->setUnit("TOF"); - //inWsEv->replaceAxis(0,pAxis0); + NumericAxis *pAxis0 = new NumericAxis(2); + pAxis0->setUnit("TOF"); + inWsEv->replaceAxis(0,pAxis0); - //MDWSDescription WSD; - //std::vector<double> min(4,-1e+30),max(4,1e+30); - //WSD.setMinMax(min,max); - //WSD.buildFromMatrixWS(inWsEv,"Q3D","Indirect"); - - //WSD.m_PreprDetTable =pDetLoc_events; - //WSD.m_RotMatrix = Rot; - //// this one comes from ticket #6852 and would not exist in clear branch. - //WSD.addProperty("RUN_INDEX",10,true); - - //// create new target MD workspace - //pTargWS->releaseWorkspace(); - //pTargWS->createEmptyMDWS(WSD); - - - //ConvToMDSelector AlgoSelector; - //pConvMethods = AlgoSelector.convSelector(inWsEv); - //pConvMethods->initialize(WSD,pTargWS); - - //pMockAlgorithm->resetProgress(numHist); - ////Clock.elapsedCPU(); - //std::time (&start); - //TS_ASSERT_THROWS_NOTHING(pConvMethods->runConversion(pMockAlgorithm->getProgress())); - //std::time (&end); - //double sec = std::difftime (end,start); - ////float sec = Clock.elapsedCPU(); - //TS_WARN("Time to complete: <EventWSType,Q3D,Indir,ConvFromTOF,CrystType>: "+boost::lexical_cast<std::string>(sec)+" sec"); + MDWSDescription WSD; + std::vector<double> min(4,-1e+30),max(4,1e+30); + WSD.setMinMax(min,max); + WSD.buildFromMatrixWS(inWsEv,"Q3D","Indirect"); + + WSD.m_PreprDetTable =pDetLoc_events; + WSD.m_RotMatrix = Rot; + // this one comes from ticket #6852 and would not exist in clear branch. + WSD.addProperty("RUN_INDEX",static_cast<uint16_t>(10),true); + + // create new target MD workspace + pTargWS->releaseWorkspace(); + pTargWS->createEmptyMDWS(WSD); + + + ConvToMDSelector AlgoSelector; + pConvMethods = AlgoSelector.convSelector(inWsEv); + pConvMethods->initialize(WSD,pTargWS); + + pMockAlgorithm->resetProgress(numHist); + //Clock.elapsedCPU(); + std::time (&start); + TS_ASSERT_THROWS_NOTHING(pConvMethods->runConversion(pMockAlgorithm->getProgress())); + std::time (&end); + double sec = std::difftime (end,start); + //float sec = Clock.elapsedCPU(); + TS_WARN("Time to complete: <EventWSType,Q3D,Indir,ConvFromTOF,CrystType>: "+boost::lexical_cast<std::string>(sec)+" sec"); } void test_HistoFromTOFConv() { - TS_WARN("Disabled untill meged with #6852"); - //NumericAxis *pAxis0 = new NumericAxis(2); - //pAxis0->setUnit("TOF"); - //inWs2D->replaceAxis(0,pAxis0); + NumericAxis *pAxis0 = new NumericAxis(2); + pAxis0->setUnit("TOF"); + inWs2D->replaceAxis(0,pAxis0); - //MDWSDescription WSD; - //std::vector<double> min(4,-1e+30),max(4,1e+30); - //WSD.setMinMax(min,max); + MDWSDescription WSD; + std::vector<double> min(4,-1e+30),max(4,1e+30); + WSD.setMinMax(min,max); - //WSD.buildFromMatrixWS(inWs2D,"Q3D","Indirect"); + WSD.buildFromMatrixWS(inWs2D,"Q3D","Indirect"); - //WSD.m_PreprDetTable =pDetLoc_histo; - //WSD.m_RotMatrix = Rot; - //// this one comes from ticket #6852 and would not exist in clear branch. - //WSD.addProperty("RUN_INDEX",10,true); + WSD.m_PreprDetTable =pDetLoc_histo; + WSD.m_RotMatrix = Rot; + // this one comes from ticket #6852 and would not exist in clear branch. + WSD.addProperty("RUN_INDEX",static_cast<uint16_t>(10),true); - //// create new target MD workspace - //pTargWS->releaseWorkspace(); - //pTargWS->createEmptyMDWS(WSD); + // create new target MD workspace + pTargWS->releaseWorkspace(); + pTargWS->createEmptyMDWS(WSD); - //pTargWS->createEmptyMDWS(WSD); + pTargWS->createEmptyMDWS(WSD); - //ConvToMDSelector AlgoSelector; - //pConvMethods = AlgoSelector.convSelector(inWs2D); - //pConvMethods->initialize(WSD,pTargWS); + ConvToMDSelector AlgoSelector; + pConvMethods = AlgoSelector.convSelector(inWs2D); + pConvMethods->initialize(WSD,pTargWS); - //pMockAlgorithm->resetProgress(numHist); - ////Clock.elapsedCPU(); - //std::time (&start); - //TS_ASSERT_THROWS_NOTHING(pConvMethods->runConversion(pMockAlgorithm->getProgress())); - //std::time (&end); - //double sec = std::difftime (end,start); + pMockAlgorithm->resetProgress(numHist); + //Clock.elapsedCPU(); + std::time (&start); + TS_ASSERT_THROWS_NOTHING(pConvMethods->runConversion(pMockAlgorithm->getProgress())); + std::time (&end); + double sec = std::difftime (end,start); - //TS_WARN("Time to complete: <Ws2DHistoType,Q3D,Indir,ConvFromTOF,CrystType>: "+boost::lexical_cast<std::string>(sec)+" sec"); + TS_WARN("Time to complete: <Ws2DHistoType,Q3D,Indir,ConvFromTOF,CrystType>: "+boost::lexical_cast<std::string>(sec)+" sec"); } void test_HistoNoUnitsConv() { - TS_WARN("Disabled untill meged with #6852"); + - //NumericAxis *pAxis0 = new NumericAxis(2); - //pAxis0->setUnit("DeltaE"); - //inWs2D->replaceAxis(0,pAxis0); + NumericAxis *pAxis0 = new NumericAxis(2); + pAxis0->setUnit("DeltaE"); + inWs2D->replaceAxis(0,pAxis0); - //MDWSDescription WSD; - //std::vector<double> min(4,-1e+30),max(4,1e+30); - //WSD.setMinMax(min,max); + MDWSDescription WSD; + std::vector<double> min(4,-1e+30),max(4,1e+30); + WSD.setMinMax(min,max); - //WSD.buildFromMatrixWS(inWs2D,"Q3D","Indirect"); + WSD.buildFromMatrixWS(inWs2D,"Q3D","Indirect"); - //WSD.m_PreprDetTable =pDetLoc_histo; - //WSD.m_RotMatrix = Rot; - //// this one comes from ticket #6852 and would not exist in clear branch. - //WSD.addProperty("RUN_INDEX",10,true); + WSD.m_PreprDetTable =pDetLoc_histo; + WSD.m_RotMatrix = Rot; + // this one comes from ticket #6852 and would not exist in clear branch. + WSD.addProperty("RUN_INDEX",static_cast<uint16_t>(10),true); - //// create new target MD workspace - //pTargWS->releaseWorkspace(); - //pTargWS->createEmptyMDWS(WSD); + // create new target MD workspace + pTargWS->releaseWorkspace(); + pTargWS->createEmptyMDWS(WSD); - //pTargWS->createEmptyMDWS(WSD); + pTargWS->createEmptyMDWS(WSD); - //ConvToMDSelector AlgoSelector; - //pConvMethods = AlgoSelector.convSelector(inWs2D); - //pConvMethods->initialize(WSD,pTargWS); + ConvToMDSelector AlgoSelector; + pConvMethods = AlgoSelector.convSelector(inWs2D); + pConvMethods->initialize(WSD,pTargWS); - //pMockAlgorithm->resetProgress(numHist); - ////Clock.elapsedCPU(); - //std::time (&start); - //TS_ASSERT_THROWS_NOTHING(pConvMethods->runConversion(pMockAlgorithm->getProgress())); - //std::time (&end); - //double sec = std::difftime (end,start); + pMockAlgorithm->resetProgress(numHist); + //Clock.elapsedCPU(); + std::time (&start); + TS_ASSERT_THROWS_NOTHING(pConvMethods->runConversion(pMockAlgorithm->getProgress())); + std::time (&end); + double sec = std::difftime (end,start); - //TS_WARN("Time to complete: <Ws2DHistoType,Q3D,Indir,ConvertNo,CrystType>: "+boost::lexical_cast<std::string>(sec)+" sec"); + TS_WARN("Time to complete: <Ws2DHistoType,Q3D,Indir,ConvertNo,CrystType>: "+boost::lexical_cast<std::string>(sec)+" sec"); } diff --git a/Code/Mantid/Framework/MDAlgorithms/test/LoadMDTest.h b/Code/Mantid/Framework/MDAlgorithms/test/LoadMDTest.h index c21e96173b7ba8d5f19e002a53e5e9540b64179e..5a0fc5f9ed7eacc90dca5b1a734a954490866ba7 100644 --- a/Code/Mantid/Framework/MDAlgorithms/test/LoadMDTest.h +++ b/Code/Mantid/Framework/MDAlgorithms/test/LoadMDTest.h @@ -567,6 +567,57 @@ public: AnalysisDataService::Instance().remove("OutputWorkspace"); } + void test_loadAffine() + { + std::string filename("SaveMDAffineTest.nxs"); + // Make a 4D MDEventWorkspace + MDEventWorkspace4Lean::sptr ws = MDEventsTestHelper::makeMDEW<4>(10, 0.0, 10.0, 2); + AnalysisDataService::Instance().addOrReplace("SaveMDAffineTest_ws", ws); + + // Bin data to get affine matrix + BinMD balg; + balg.initialize(); + balg.setProperty("InputWorkspace", "SaveMDAffineTest_ws"); + balg.setProperty("OutputWorkspace", "SaveMDAffineTestHisto_ws"); + balg.setProperty("AlignedDim0", "Axis2,0,10,10"); + balg.setProperty("AlignedDim1", "Axis0,0,10,5"); + balg.setProperty("AlignedDim2", "Axis1,0,10,5"); + balg.setProperty("AlignedDim3", "Axis3,0,10,2"); + balg.execute(); + + SaveMD alg; + alg.initialize(); + alg.setPropertyValue("InputWorkspace", "SaveMDAffineTestHisto_ws"); + alg.setPropertyValue("Filename", filename); + alg.setProperty("MakeFileBacked","0"); + alg.execute(); + TS_ASSERT( alg.isExecuted() ); + + LoadMD loadAlg; + loadAlg.initialize(); + loadAlg.isInitialized(); + loadAlg.setPropertyValue("Filename", filename); + loadAlg.setProperty("FileBackEnd", false); + loadAlg.setPropertyValue("OutputWorkspace", "reloaded_affine"); + loadAlg.execute(); + TS_ASSERT( loadAlg.isExecuted() ); + + // Check the affine matrix over at a couple of locations + MDHistoWorkspace_sptr newWS = AnalysisDataService::Instance().retrieveWS<MDHistoWorkspace>("reloaded_affine"); + Matrix<coord_t> affMat = newWS->getTransformToOriginal()->makeAffineMatrix(); + TS_ASSERT_EQUALS( affMat[0][1], 1.0 ); + TS_ASSERT_EQUALS( affMat[2][0], 1.0 ); + + if (Poco::File(filename).exists()) + { + Poco::File(filename).remove(); + } + + AnalysisDataService::Instance().remove("SaveMDAffineTest_ws"); + AnalysisDataService::Instance().remove("SaveMDAffineTestHisto_ws"); + AnalysisDataService::Instance().remove("OutputWorkspace"); + } + }; #endif /* MANTID_MDEVENTS_LOADMDEWTEST_H_ */ diff --git a/Code/Mantid/Framework/MDAlgorithms/test/SaveMDTest.h b/Code/Mantid/Framework/MDAlgorithms/test/SaveMDTest.h index b256c611c6b8eb461ad8b3cf0088393df3fa5e83..1c90b386e9e2b04c39a3da8d80733d6bd55014a7 100644 --- a/Code/Mantid/Framework/MDAlgorithms/test/SaveMDTest.h +++ b/Code/Mantid/Framework/MDAlgorithms/test/SaveMDTest.h @@ -4,6 +4,7 @@ #include "MantidKernel/System.h" #include "MantidKernel/Timer.h" #include "MantidMDEvents/MDEventFactory.h" +#include "MantidMDAlgorithms/BinMD.h" #include "MantidMDAlgorithms/SaveMD.h" #include "MantidTestHelpers/MDEventsTestHelper.h" #include "MantidAPI/FrameworkManager.h" @@ -208,6 +209,39 @@ public: } + void test_saveAffine() + { + std::string filename("MDAffineSaveTest.nxs"); + // Make a 4D MDEventWorkspace + MDEventWorkspace4Lean::sptr ws = MDEventsTestHelper::makeMDEW<4>(10, 0.0, 10.0, 2); + AnalysisDataService::Instance().addOrReplace("SaveMDTest_ws", ws); + + // Bin data to get affine matrix + BinMD balg; + balg.initialize(); + balg.setProperty("InputWorkspace", "SaveMDTest_ws"); + balg.setProperty("OutputWorkspace", "SaveMDTestHisto_ws"); + balg.setProperty("AlignedDim0", "Axis2,0,10,10"); + balg.setProperty("AlignedDim1", "Axis0,0,10,5"); + balg.setProperty("AlignedDim2", "Axis1,0,10,5"); + balg.setProperty("AlignedDim3", "Axis3,0,10,2"); + balg.execute(); + + SaveMD alg; + TS_ASSERT_THROWS_NOTHING( alg.initialize() ) + TS_ASSERT( alg.isInitialized() ) + TS_ASSERT_THROWS_NOTHING( alg.setPropertyValue("InputWorkspace", "SaveMDTestHisto_ws") ); + TS_ASSERT_THROWS_NOTHING( alg.setPropertyValue("Filename", filename) ); + TS_ASSERT_THROWS_NOTHING( alg.setProperty("MakeFileBacked","0") ); + alg.execute(); + TS_ASSERT( alg.isExecuted() ); + + ws->clearFileBacked(false); + if (Poco::File(filename).exists()) + { + Poco::File(filename).remove(); + } + } /** Run SaveMD with the MDHistoWorkspace */ void doTestHisto(MDHistoWorkspace_sptr ws) diff --git a/Code/Mantid/Framework/MDEvents/inc/MantidMDEvents/CoordTransformAffine.h b/Code/Mantid/Framework/MDEvents/inc/MantidMDEvents/CoordTransformAffine.h index d0a9243da8328833b22ba14bc7f38e058c594e62..69725cbca68a1aefe6b5f11f55b0be62f41ac258 100644 --- a/Code/Mantid/Framework/MDEvents/inc/MantidMDEvents/CoordTransformAffine.h +++ b/Code/Mantid/Framework/MDEvents/inc/MantidMDEvents/CoordTransformAffine.h @@ -37,6 +37,7 @@ namespace MDEvents virtual CoordTransform * clone() const; virtual ~CoordTransformAffine(); virtual std::string toXMLString() const; + virtual std::string id() const; void addTranslation(const coord_t * translationVector); const Mantid::Kernel::Matrix<coord_t> & getMatrix() const; Mantid::Kernel::Matrix<coord_t> makeAffineMatrix() const; diff --git a/Code/Mantid/Framework/MDEvents/inc/MantidMDEvents/CoordTransformAligned.h b/Code/Mantid/Framework/MDEvents/inc/MantidMDEvents/CoordTransformAligned.h index d3cf482d3a0981a7ea249e082f17a3356839a07e..0e1161ae807fc33e6b612667eb513f9663ec52bf 100644 --- a/Code/Mantid/Framework/MDEvents/inc/MantidMDEvents/CoordTransformAligned.h +++ b/Code/Mantid/Framework/MDEvents/inc/MantidMDEvents/CoordTransformAligned.h @@ -64,6 +64,7 @@ namespace MDEvents virtual ~CoordTransformAligned(); std::string toXMLString() const; + std::string id() const; void apply(const coord_t * inputVector, coord_t * outVector) const; Mantid::Kernel::Matrix<coord_t> makeAffineMatrix() const; diff --git a/Code/Mantid/Framework/MDEvents/inc/MantidMDEvents/CoordTransformDistance.h b/Code/Mantid/Framework/MDEvents/inc/MantidMDEvents/CoordTransformDistance.h index 89d9d5a29244772f18f23631827da9e91e6dc1d8..d969b047154e05d4ad73573e235c791ab279ce2a 100644 --- a/Code/Mantid/Framework/MDEvents/inc/MantidMDEvents/CoordTransformDistance.h +++ b/Code/Mantid/Framework/MDEvents/inc/MantidMDEvents/CoordTransformDistance.h @@ -37,6 +37,7 @@ namespace MDEvents virtual CoordTransform * clone() const; virtual ~CoordTransformDistance(); virtual std::string toXMLString() const; + virtual std::string id() const; void apply(const coord_t * inputVector, coord_t * outVector) const; diff --git a/Code/Mantid/Framework/MDEvents/inc/MantidMDEvents/MDWSDescription.h b/Code/Mantid/Framework/MDEvents/inc/MantidMDEvents/MDWSDescription.h index a6d7979245aa20b9577f8668f8477ff7d92b50d2..4c6fc8af3c4d21ceacfc3817e99d6851d7c006aa 100644 --- a/Code/Mantid/Framework/MDEvents/inc/MantidMDEvents/MDWSDescription.h +++ b/Code/Mantid/Framework/MDEvents/inc/MantidMDEvents/MDWSDescription.h @@ -11,8 +11,8 @@ #include "MantidMDEvents/MDEvent.h" #include "MantidMDEvents/ConvToMDPreprocDet.h" -//#include "MantidMDEvents/MDTransfDEHelper.h" #include "MantidDataObjects/TableWorkspace.h" +#include "MantidAPI/LogManager.h" namespace Mantid @@ -56,7 +56,7 @@ namespace MDEvents /// helper class describes the properties of target MD workspace, which should be obtained as the result of conversion algorithm. -class DLLExport MDWSDescription : public Kernel::PropertyManager + class DLLExport MDWSDescription : public API::LogManager { public: // for the time being /// the string which describes ChildAlgorithm, used to convert source ws to target MD ws. At the moment, it coinsides with Q-mode @@ -156,6 +156,7 @@ protected: // until MDWSDesctiptionDepricatedExist //********************* internal helpers /// helper function to resize all vectors, responsible for MD dimensions in one go void resizeDimDescriptions(unsigned int Dims,size_t nBins=10); + private: /// Coordinate system. Mantid::API::SpecialCoordinateSystem m_coordinateSystem; diff --git a/Code/Mantid/Framework/MDEvents/src/ConvToMDBase.cpp b/Code/Mantid/Framework/MDEvents/src/ConvToMDBase.cpp index 6406cae75ee55f26bbb11bdfd5e94cf5fc701742..f4c0dbab3001c22e17db3d8658d2bbad16f97092 100644 --- a/Code/Mantid/Framework/MDEvents/src/ConvToMDBase.cpp +++ b/Code/Mantid/Framework/MDEvents/src/ConvToMDBase.cpp @@ -33,10 +33,9 @@ namespace Mantid // set up output MD workspace wrapper m_OutWSWrapper = inWSWrapper; - - // Copy ExperimentInfo (instrument, run, sample) to the output WS - API::ExperimentInfo_sptr ei(m_InWS2D->cloneExperimentInfo()); - m_RunIndex = m_OutWSWrapper->pWorkspace()->addExperimentInfo(ei); + // get the index which identify the run the source workspace came from. + // This index will mark the workspace' events for diffetent worksapces to combine + m_RunIndex = WSD.getPropertyValueAsType<uint16_t>("RUN_INDEX"); m_NDims = m_OutWSWrapper->nDimensions(); // allocate space for single MDEvent coordinates diff --git a/Code/Mantid/Framework/MDEvents/src/CoordTransformAffine.cpp b/Code/Mantid/Framework/MDEvents/src/CoordTransformAffine.cpp index af724579ce4916cf8f8bf27caf06325c26f6746a..67dcd7383e9db1189487c392f31baf610cdf61d1 100644 --- a/Code/Mantid/Framework/MDEvents/src/CoordTransformAffine.cpp +++ b/Code/Mantid/Framework/MDEvents/src/CoordTransformAffine.cpp @@ -267,6 +267,14 @@ namespace MDEvents return formattedXMLString; } + /** + * Coordinate transform id + * @return the type of coordinate transform + */ + std::string CoordTransformAffine::id() const + { + return "CoordTransformAffine"; + } //---------------------------------------------------------------------------------------------- /** Combine two transformations into a single affine transformations diff --git a/Code/Mantid/Framework/MDEvents/src/CoordTransformAligned.cpp b/Code/Mantid/Framework/MDEvents/src/CoordTransformAligned.cpp index 210580588ea1a1709114aabadd1f5c333a3559f3..a29269ca2e1742555f3d1e2ead5d16bab417764d 100644 --- a/Code/Mantid/Framework/MDEvents/src/CoordTransformAligned.cpp +++ b/Code/Mantid/Framework/MDEvents/src/CoordTransformAligned.cpp @@ -183,6 +183,14 @@ namespace MDEvents return formattedXMLString; } + /** + * Coordinate transform id + * @return the type of coordinate transform + */ + std::string CoordTransformAligned::id() const + { + return "CoordTransformAligned"; + } } // namespace Mantid } // namespace MDEvents diff --git a/Code/Mantid/Framework/MDEvents/src/CoordTransformDistance.cpp b/Code/Mantid/Framework/MDEvents/src/CoordTransformDistance.cpp index 398786fc001e31d2a316a41c2813f1140a9cec32..5671395593c2295165ba4d6ade032ecb98d6372b 100644 --- a/Code/Mantid/Framework/MDEvents/src/CoordTransformDistance.cpp +++ b/Code/Mantid/Framework/MDEvents/src/CoordTransformDistance.cpp @@ -133,6 +133,15 @@ namespace MDEvents return formattedXMLString; } + /** + * Coordinate transform id + * @return the type of coordinate transform + */ + std::string CoordTransformDistance::id() const + { + return "CoordTransformDistance"; + } + } // namespace Mantid } // namespace MDEvents diff --git a/Code/Mantid/Framework/MDEvents/src/MDWSTransform.cpp b/Code/Mantid/Framework/MDEvents/src/MDWSTransform.cpp index 17458ad61caea6a5dc40bd1d3a28fd2780ae3660..d459d9fb0333eea7bea7f70552cc0e5290a7e998 100644 --- a/Code/Mantid/Framework/MDEvents/src/MDWSTransform.cpp +++ b/Code/Mantid/Framework/MDEvents/src/MDWSTransform.cpp @@ -198,7 +198,7 @@ Kernel::DblMatrix MDWSTransform::buildQTrahsf(MDEvents::MDWSDescription &TargWSD default: throw(std::invalid_argument("unrecognized conversion mode")); } - + TargWSDescription.addProperty("W_MATRIX",Wmat.getVector(),true); return Transf*Scale*Wmat; } diff --git a/Code/Mantid/Framework/Properties/Mantid.properties.template b/Code/Mantid/Framework/Properties/Mantid.properties.template index ab9edf72aa619386b9d7e4c4099c8d7edf432797..a629dd29127e5bafcb85de1d5ff48f673d3820d2 100644 --- a/Code/Mantid/Framework/Properties/Mantid.properties.template +++ b/Code/Mantid/Framework/Properties/Mantid.properties.template @@ -200,11 +200,11 @@ algorithms.categories.hidden=Workflow\\Inelastic\\UsesPropertyManager;Workflow\\ # ScriptRepository Properties: -# Url for the WebServer that support the upload of the files that the users want to share (not in usage) -UploaderWebServer = +# Url for the WebServer that support the upload of the files that the users want to share +UploaderWebServer = @MANTIDPUBLISHER@ # Local system path for the script repository. ScriptLocalRepository = # Url for the remote script repository. -ScriptRepository = http://download.mantidproject.org/master_builds/ +ScriptRepository = http://download.mantidproject.org/scriptrepository/ # Pattern given to ScriptRepository that is used to hide entries from repository to the users. It is a csv string separated with ';' ScriptRepositoryIgnore = *pyc; diff --git a/Code/Mantid/Framework/PythonAPI/src/api_exports.cpp b/Code/Mantid/Framework/PythonAPI/src/api_exports.cpp index aec78f1d7bb0bdb4680bb7627bd7f3fc8692b23f..32d26cdb9ca854a0c05647e3ec8d837e07b809e2 100644 --- a/Code/Mantid/Framework/PythonAPI/src/api_exports.cpp +++ b/Code/Mantid/Framework/PythonAPI/src/api_exports.cpp @@ -813,7 +813,8 @@ void export_dataitem() .def("isText", & API::Axis::isText) .def("label", & API::Axis::label) .def("getUnit", (const Mantid::Kernel::Unit_sptr & (Mantid::API::Axis::*)() const) &API::Axis::unit, return_value_policy<copy_const_reference>() ) - .def("setUnit", & API::Axis::setUnit) + .def("setUnit", & API::Axis::setUnit, + return_value_policy<copy_const_reference>()) .def("getValue", & API::NumericAxis::getValue) ; diff --git a/Code/Mantid/Framework/PythonInterface/mantid/api/src/Exports/Axis.cpp b/Code/Mantid/Framework/PythonInterface/mantid/api/src/Exports/Axis.cpp index 82b49b046a037f25e610f87b6dacb89e66c05a38..53e50346978a89023902a800f236560911e691a3 100644 --- a/Code/Mantid/Framework/PythonInterface/mantid/api/src/Exports/Axis.cpp +++ b/Code/Mantid/Framework/PythonInterface/mantid/api/src/Exports/Axis.cpp @@ -98,7 +98,8 @@ void export_Axis() .def("getValue", &Axis::getValue, Axis_getValue(args("index", "vertical_index"), "Returns the value at the given point on the Axis. The vertical axis index [default=0]")) .def("extractValues", &extractAxisValues, "Return a numpy array of the axis values") - .def("setUnit", & Axis::setUnit, "Set the unit for this axis") + .def("setUnit", & Axis::setUnit, return_value_policy<copy_const_reference>(), + "Set the unit for this axis by name.") .def("setValue", &Axis::setValue, "Set a value at the given index") .def("getMin", &Axis::getMin, "Get min value specified on the axis") .def("getMax", &Axis::getMax, "Get max value specified on the axis") diff --git a/Code/Mantid/Framework/PythonInterface/mantid/kernel/CMakeLists.txt b/Code/Mantid/Framework/PythonInterface/mantid/kernel/CMakeLists.txt index d8ca3d48dbfca33e9da6b0de96efee2bb6e0a665..f99bf353b2f7f2c60c24f83c8cf26208ea497678 100644 --- a/Code/Mantid/Framework/PythonInterface/mantid/kernel/CMakeLists.txt +++ b/Code/Mantid/Framework/PythonInterface/mantid/kernel/CMakeLists.txt @@ -20,6 +20,7 @@ set ( EXPORT_FILES src/Exports/StlContainers.cpp src/Exports/Logger.cpp src/Exports/Unit.cpp + src/Exports/Units.cpp src/Exports/BoundedValidator.cpp src/Exports/TimeSeriesProperty.cpp src/Exports/FilteredTimeSeriesProperty.cpp @@ -174,4 +175,4 @@ endif() install ( FILES ${PY_FILES} DESTINATION ${BIN_DIR}/mantid/kernel ) # packagesetup.py that will overwrite the ones from the built target install ( FILES ${CMAKE_CURRENT_BINARY_DIR}/${PACKAGESETUP_PY}.install.py DESTINATION - ${BIN_DIR}/mantid/kernel RENAME ${PACKAGESETUP_PY}.py ) \ No newline at end of file + ${BIN_DIR}/mantid/kernel RENAME ${PACKAGESETUP_PY}.py ) diff --git a/Code/Mantid/Framework/PythonInterface/mantid/kernel/src/Exports/UnitFactory.cpp b/Code/Mantid/Framework/PythonInterface/mantid/kernel/src/Exports/UnitFactory.cpp index 9b9046baa84e4ada9e77719977da395b8733d4e4..bd0850258e48776cbdd8b281d18e539e14a6debf 100644 --- a/Code/Mantid/Framework/PythonInterface/mantid/kernel/src/Exports/UnitFactory.cpp +++ b/Code/Mantid/Framework/PythonInterface/mantid/kernel/src/Exports/UnitFactory.cpp @@ -1,4 +1,5 @@ #include "MantidKernel/UnitFactory.h" +#include "MantidKernel/Unit.h" #include "MantidPythonInterface/kernel/Policies/VectorToNumpy.h" @@ -14,6 +15,8 @@ using namespace boost::python; void export_UnitFactory() { class_<UnitFactoryImpl, boost::noncopyable>("UnitFactoryImpl", no_init) + .def("create", &UnitFactoryImpl::create, "Creates a named unit if it exists in the factory") + .def("getKeys", &UnitFactoryImpl::getKeys, return_value_policy<Policies::VectorToNumpy>(), "Returns a list of units available from the factory") diff --git a/Code/Mantid/Framework/PythonInterface/mantid/kernel/src/Exports/Units.cpp b/Code/Mantid/Framework/PythonInterface/mantid/kernel/src/Exports/Units.cpp new file mode 100644 index 0000000000000000000000000000000000000000..17fe520efe9788be48fe01cc1a5042e031d54479 --- /dev/null +++ b/Code/Mantid/Framework/PythonInterface/mantid/kernel/src/Exports/Units.cpp @@ -0,0 +1,20 @@ +#include "MantidKernel/Unit.h" + +#include <boost/python/class.hpp> + +using Mantid::Kernel::Unit; +using namespace Mantid::Kernel::Units; +using namespace boost::python; + +// We only export the concrete unit classes that +// have additional functionality over the base class + +void export_Label() +{ + class_<Label, bases<Unit>, boost::noncopyable>("Label", no_init) + .def("setLabel", (void (Label::*)(const std::string &,const std::string &))&Label::setLabel, + (arg("caption"),arg("label")), "Set the caption (e.g.Temperature) & label (K) on the unit") + ; + +} + diff --git a/Code/Mantid/Framework/PythonInterface/plugins/algorithms/SNSPowderReduction.py b/Code/Mantid/Framework/PythonInterface/plugins/algorithms/SNSPowderReduction.py index acdd7cb027539a901ba9a2af5d5eba3d4c4955af..7d7f02a754463db829bac46b923563d0e9cc22b5 100644 --- a/Code/Mantid/Framework/PythonInterface/plugins/algorithms/SNSPowderReduction.py +++ b/Code/Mantid/Framework/PythonInterface/plugins/algorithms/SNSPowderReduction.py @@ -607,7 +607,7 @@ class SNSPowderReduction(PythonAlgorithm): print "[DB1050-1] Unable to get events of %s. Error message: %s" % (str(wksp), str(e)) if HAVE_MPI: - msg = "MPI Task = %s ;" %s (str(mpi.world.rank)) + msg = "MPI Task = %s ;" % (str(mpi.world.rank)) try: msg += "Number Events = ", wksp.getNumberEvents() except Exception as e: diff --git a/Code/Mantid/Framework/PythonInterface/test/python/mantid/api/AxisTest.py b/Code/Mantid/Framework/PythonInterface/test/python/mantid/api/AxisTest.py index bf2964aedd860ca1abfb2067387392d1835a5679..65d135871c4044ef8101792cfc6f6771a859c459 100644 --- a/Code/Mantid/Framework/PythonInterface/test/python/mantid/api/AxisTest.py +++ b/Code/Mantid/Framework/PythonInterface/test/python/mantid/api/AxisTest.py @@ -1,6 +1,6 @@ import unittest from testhelpers import run_algorithm -from mantid.api import NumericAxis, TextAxis +from mantid.api import NumericAxis, TextAxis, mtd import numpy as np class AxisTest(unittest.TestCase): @@ -9,13 +9,14 @@ class AxisTest(unittest.TestCase): def setUp(self): if self.__class__._test_ws is None: - alg = run_algorithm("Load", Filename="LOQ48127.raw", SpectrumMax=3, child=True) + alg = run_algorithm('CreateWorkspace', DataX=datY,DataY=datY,DataE=datY,NSpec=3, + child=True) self.__class__._test_ws = alg.getProperty("OutputWorkspace").value def test_constructor_methods_return_the_correct_type(self): self.assertTrue(isinstance(NumericAxis.create(2),NumericAxis)) self.assertTrue(isinstance(TextAxis.create(2),TextAxis)) - + def test_axis_meta_data(self): yAxis = self._test_ws.getAxis(1) self.assertTrue(isinstance(yAxis, SpectraAxis)) @@ -30,6 +31,23 @@ class AxisTest(unittest.TestCase): self.assertEquals(xunit.unitID(), "TOF") self.assertEquals(xunit.caption(), "Time-of-flight") self.assertEquals(xunit.label(), "microsecond") + + def test_axis_unit_can_be_replaced(self): + datY=np.arange(100) + ns=3 + alg = run_algorithm('CreateWorkspace', DataX=datY,DataY=datY,DataE=datY,NSpec=ns, + VerticalAxisUnit="Label", VerticalAxisValues=taxis, child=True) + ws = alg.getPropertyValue("OutputWorkspace") + + ws.getAxis(0).setUnit("Label").setLabel("Time", "ns") + ws.getAxis(1).setUnit("Label").setLabel("Temperature", "K") + + unitx = ws.getAxis(0).getUnit() + unity = ws.getAxis(1).getUnit() + self.assertEquals("Time",unitx.caption()) + self.assertEquals("ns",unitx.label()) + self.assertEquals("Temperature",unity.caption()) + self.assertEquals("K",unity.label()) def test_value_axis(self): yAxis = self._test_ws.getAxis(1) @@ -46,7 +64,8 @@ class AxisTest(unittest.TestCase): def test_extract_string_axis_values_to_list(self): data = [1.,2.,3.] axis_values = ["a","b","c"] - alg = run_algorithm("CreateWorkspace", DataX=data, DataY=data, NSpec=3,VerticalAxisUnit="Text",VerticalAxisValues=axis_values,child=True) + alg = run_algorithm("CreateWorkspace", DataX=data, DataY=data, NSpec=3, + VerticalAxisUnit="Text",VerticalAxisValues=axis_values,child=True) workspace = alg.getProperty("OutputWorkspace").value txtAxis = workspace.getAxis(1) self.assertTrue(txtAxis.isText()) @@ -54,4 +73,4 @@ class AxisTest(unittest.TestCase): self.assertTrue(isinstance(values, list)) for index, value in enumerate(values): self.assertEquals(value, axis_values[index]) - \ No newline at end of file + diff --git a/Code/Mantid/Framework/PythonInterface/test/python/mantid/kernel/CMakeLists.txt b/Code/Mantid/Framework/PythonInterface/test/python/mantid/kernel/CMakeLists.txt index 9048ccb36195ca2a93977a53d262d7b756c68598..910c2d392132e22810cb74c4c466b2d613c7355f 100644 --- a/Code/Mantid/Framework/PythonInterface/test/python/mantid/kernel/CMakeLists.txt +++ b/Code/Mantid/Framework/PythonInterface/test/python/mantid/kernel/CMakeLists.txt @@ -25,6 +25,7 @@ set ( TEST_PY_FILES QuatTest.py UnitConversionTest.py UnitFactoryTest.py + UnitsTest.py V3DTest.py ) diff --git a/Code/Mantid/Framework/PythonInterface/test/python/mantid/kernel/UnitFactoryTest.py b/Code/Mantid/Framework/PythonInterface/test/python/mantid/kernel/UnitFactoryTest.py index cc5db6043cdd00f853625d2f1f66980eb026bec2..7d4834abfc059561d12422cac8e880443ed5f207 100644 --- a/Code/Mantid/Framework/PythonInterface/test/python/mantid/kernel/UnitFactoryTest.py +++ b/Code/Mantid/Framework/PythonInterface/test/python/mantid/kernel/UnitFactoryTest.py @@ -1,10 +1,18 @@ import unittest -from mantid import UnitFactory, UnitFactoryImpl +from mantid.kernel import UnitFactory, UnitFactoryImpl, Unit class UnitFactoryTest(unittest.TestCase): def test_alias_is_of_type_UnitFactoryImpl(self): self.assertTrue(isinstance(UnitFactory, UnitFactoryImpl)) + + def test_known_unit_can_be_created(self): + energy = UnitFactory.create("Energy") + self.assertTrue(isinstance(energy, Unit)) + + def test_unknown_unit_raises_error(self): + self.assertRaises(RuntimeError, UnitFactory.create, + "NotAUnit") def test_keys_returns_a_non_empty_python_list_of_unit_keys(self): known_units = UnitFactory.getKeys() diff --git a/Code/Mantid/Framework/PythonInterface/test/python/mantid/kernel/UnitsTest.py b/Code/Mantid/Framework/PythonInterface/test/python/mantid/kernel/UnitsTest.py new file mode 100644 index 0000000000000000000000000000000000000000..c2b72d8743d5772ebe2ba3ea7129b11c0474e18e --- /dev/null +++ b/Code/Mantid/Framework/PythonInterface/test/python/mantid/kernel/UnitsTest.py @@ -0,0 +1,15 @@ +import unittest +from mantid.kernel import UnitFactory, Unit, Label + +class UnitsTest(unittest.TestCase): + + def test_Label_is_returned_from_Factory(self): + label_unit = UnitFactory.Instance().create("Label") + self.assertTrue(isinstance(label_unit, Unit)) + self.assertTrue(isinstance(label_unit, Label)) + label_unit.setLabel("Temperature", "K") + self.assertEquals("Temperature", label_unit.caption()) + self.assertEquals("K", label_unit.label()) + +if __name__ == '__main__': + unittest.main() diff --git a/Code/Mantid/Framework/ScriptRepository/inc/MantidScriptRepository/ScriptRepositoryImpl.h b/Code/Mantid/Framework/ScriptRepository/inc/MantidScriptRepository/ScriptRepositoryImpl.h index c0f5d8e4fff9cff5026fc3809f4d8a8d8b5e43df..f20983fcd9f4b46b86543ffadcab1c52414758be 100644 --- a/Code/Mantid/Framework/ScriptRepository/inc/MantidScriptRepository/ScriptRepositoryImpl.h +++ b/Code/Mantid/Framework/ScriptRepository/inc/MantidScriptRepository/ScriptRepositoryImpl.h @@ -99,7 +99,7 @@ namespace API{ void upload(const std::string & file_path, const std::string & comment, const std::string & author, - const std::string & description = std::string()); + const std::string & email); /* Return true if there is a local repository installed*/ bool isValid(void); @@ -135,6 +135,8 @@ namespace API{ std::string local_repository; /// URL for the remote repository, usually: std::string remote_url; + /// URL for the upload + std::string remote_upload; private: diff --git a/Code/Mantid/Framework/ScriptRepository/src/ScriptRepositoryImpl.cpp b/Code/Mantid/Framework/ScriptRepository/src/ScriptRepositoryImpl.cpp index d78ab5d86ebbae1ce93ecacb24965333f2562e42..79290bda08d5aec3e3c55071ed81233d783ec70b 100644 --- a/Code/Mantid/Framework/ScriptRepository/src/ScriptRepositoryImpl.cpp +++ b/Code/Mantid/Framework/ScriptRepository/src/ScriptRepositoryImpl.cpp @@ -18,6 +18,9 @@ using Mantid::Kernel::ConfigServiceImpl; #include <Poco/Exception.h> #include <Poco/Net/HTTPResponse.h> #include <Poco/Net/NetException.h> +#include <Poco/Net/HTMLForm.h> +#include "Poco/Net/FilePartSource.h" + // Visual Studion compains with the inclusion of Poco/FileStream // disabling this warning. @@ -46,17 +49,11 @@ using Mantid::Kernel::ConfigServiceImpl; using boost::property_tree::ptree; -const std::string SCRIPTREPPATH = "scripts_repo/"; - namespace Mantid { namespace API { - static void notImplemented(){ - throw ScriptRepoException("This method is not implemented yet"); - }; - static ScriptRepoException pocoException(const std::string & info, Poco::Exception & ex){ std::stringstream ss; @@ -112,10 +109,11 @@ namespace API { // get the local path and the remote path std::string loc, rem; + ConfigServiceImpl & config = ConfigService::Instance(); + remote_upload = config.getString("UploaderWebServer"); if (local_rep.empty() || remote.empty()){ - ConfigServiceImpl & config = ConfigService::Instance(); loc = config.getString("ScriptLocalRepository"); - rem = config.getString("ScriptRepository"); + rem = config.getString("ScriptRepository"); }else{ local_repository = local_rep; remote_url = remote; @@ -265,7 +263,7 @@ namespace API // install the two files inside the given folder // download the repository json - doDownloadFile(std::string(remote_url).append("/repository.json"), + doDownloadFile(std::string(remote_url).append("repository.json"), rep_json_file); g_log.debug() << "ScriptRepository downloaded repository information" << std::endl; // creation of the instance of local_json file @@ -442,7 +440,7 @@ namespace API st |= LOC; // the file is remote_changed if the date of the pub_date file is // diferent from the local downloaded pubdate. - if (entry.pub_date != entry.downloaded_pubdate) + if (entry.pub_date > entry.downloaded_pubdate) st |= REMO; @@ -616,7 +614,7 @@ namespace API return; // download the file - std::string url_path = std::string(remote_url).append(SCRIPTREPPATH).append(file_path); + std::string url_path = std::string(remote_url).append(file_path); Poco::TemporaryFile tmpFile; doDownloadFile(url_path, tmpFile.path()); @@ -693,20 +691,131 @@ namespace API } /** - @todo Describe - + * Uploads one file to the ScriptRepository web server, pushing, indirectly, to the + * git repository. It will send in a POST method, the file and the following fields: + * - author : Will identify the author of the change + * - email: Will identify the email of the author + * - comment: Description of the nature of the file or of the update + * + * It will them upload to the URL pointed to UploaderWebServer. It will them receive a json file + * with some usefull information about the success or failure of the attempt to upload. + * In failure, it will be converted to an appropriated ScriptRepoException. */ void ScriptRepositoryImpl::upload(const std::string & file_path, const std::string & comment, const std::string & author, - const std::string & description) + const std::string & email) { - UNUSED_ARG(file_path); - UNUSED_ARG(comment); - UNUSED_ARG(author); - UNUSED_ARG(description); - notImplemented(); + using namespace Poco::Net; + try{ + g_log.notice() << "ScriptRepository uploading " << file_path << " ..." << std::endl; + Poco::URI uri(remote_upload); + std::string path(uri.getPathAndQuery()); + HTTPClientSession session(uri.getHost(), uri.getPort()); + HTTPRequest req(HTTPRequest::HTTP_POST, path, + HTTPMessage::HTTP_1_0); + HTMLForm form(HTMLForm::ENCODING_MULTIPART); + + // add the fields author, email and comment + form.add("author",author); + form.add("mail", email); + form.add("comment",comment); + + // deal with the folder + std::string relative_path = convertPath(file_path); + std::string absolute_path = local_repository + relative_path; + std::string folder = "./"; + size_t pos = relative_path.rfind('/'); + if (pos != std::string::npos) + folder += std::string(relative_path.begin(), relative_path.begin() + pos); + if (folder[folder.size()-1] != '/') + folder += "/"; + g_log.information() << "Uploading to folder: " << folder << std::endl; + form.add("path",folder); + + // inserting the file + FilePartSource * m_file = new FilePartSource(absolute_path); + form.addPart("file",m_file); + form.prepareSubmit(req); + + // get the size of everything + std::stringstream sst; + form.write(sst); + // move back to the begining of the file + m_file->stream().clear(); + m_file->stream().seekg(0,std::ios::beg); + // set the size + req.setContentLength((int)sst.str().size()); + + std::ostream& ostr = session.sendRequest(req); + // send the request. + ostr << sst.str(); + + HTTPResponse response; + std::istream & rs = session.receiveResponse(response); + + g_log.information() << "ScriptRepository upload status: " + << response.getStatus() << " " << response.getReason() << std::endl; + std::stringstream answer; + { // remove the status message from the end of the reply, in order not to get exception from the read_json parser + std::stringstream server_reply; + std::string server_reply_str; + Poco::StreamCopier::copyStream(rs, server_reply); + server_reply_str= server_reply.str(); + size_t pos = server_reply_str.rfind("}"); + if (pos != std::string::npos) + answer << std::string(server_reply_str.begin() , server_reply_str.begin() + pos + 1); + else + answer << server_reply_str; + } + g_log.debug() << "Form Output: " << answer.str() << std::endl; + + std::string info; + std::string detail; + std::string published_date; + + ptree pt; + try{ + read_json(answer, pt); + info = pt.get<std::string>("message",""); + detail = pt.get<std::string>("detail",""); + published_date = pt.get<std::string>("pub_date",""); + std::string cmd = pt.get<std::string>("shell",""); + if (!cmd.empty()) + detail.append("\nFrom Command: ").append(cmd); + + }catch (boost::property_tree::json_parser_error & ex){ + throw ScriptRepoException("Bad answer from the Server", + ex.what()); + } + + if (info == "success"){ + g_log.notice() << "ScriptRepository:" << file_path << " uploaded!"<< std::endl; + + // update the file + RepositoryEntry & entry = repo.at(file_path); + { + Poco::File local(absolute_path); + entry.downloaded_date = DateAndTime(Poco::DateTimeFormatter::format(local.getLastModified(), + timeformat)); + // update the pub_date and downloaded_pubdate with the pub_date given by the upload. + // this ensures that the status will be correctly defined. + if (!published_date.empty()) + entry.pub_date = DateAndTime(published_date); + entry.downloaded_pubdate = entry.pub_date; + entry.status = BOTH_UNCHANGED; + } + g_log.information() << "ScriptRepository update local json " << std::endl; + updateLocalJson(file_path, entry); ///FIXME: performance! + + + }else + throw ScriptRepoException(info, detail); + + }catch(Poco::Exception & ex){ + throw ScriptRepoException(ex.displayText(), ex.className()); + } } /** The ScriptRepositoryImpl is set to be valid when the local repository path @@ -733,7 +842,7 @@ namespace API f.moveTo(backup); } try{ - doDownloadFile(std::string(remote_url).append("/repository.json"), + doDownloadFile(std::string(remote_url).append("repository.json"), rep_json_file); }catch(...){ // restore file @@ -851,10 +960,11 @@ namespace API Poco::URI uri(url_file); std::string path(uri.getPathAndQuery()); if (path.empty()) path = "/"; - std::string given_path = std::string(path.begin()+28, path.end());// remove the "/master_builds/scripts_repo/" from the path + std::string given_path = std::string(path.begin()+18, path.end());// remove the "/scriptrepository/" from the path //Configure Poco HTTP Client Session try{ Poco::Net::HTTPClientSession session(uri.getHost(), uri.getPort()); + session.setTimeout(Poco::Timespan(2,0));// 2 secconds Poco::Net::HTTPRequest request(Poco::Net::HTTPRequest::HTTP_GET, path, Poco::Net::HTTPMessage::HTTP_1_1); Poco::Net::HTTPResponse response; @@ -1056,8 +1166,12 @@ namespace API // array.push_back(std::make_pair("auto_update",entry.auto_update))); local_json.push_back( std::pair<std::string, boost::property_tree::basic_ptree<std::string,std::string> >(path,array) ); }else{ - local_json.put(std::string(path).append(".downloaded_pubdate"), - entry.downloaded_pubdate.toFormattedString()); + local_json.put( + boost::property_tree::ptree::path_type( std::string(path).append("!downloaded_pubdate"), '!'), + entry.downloaded_pubdate.toFormattedString().c_str()); + local_json.put( + boost::property_tree::ptree::path_type( std::string(path).append("!downloaded_date"), '!'), + entry.downloaded_date.toFormattedString().c_str()); } //g_log.debug() << "Update LOCAL JSON FILE" << std::endl; #if defined(_WIN32) || defined(_WIN64) diff --git a/Code/Mantid/MantidPlot/CMakeLists.txt b/Code/Mantid/MantidPlot/CMakeLists.txt index e6acb18a6b089d15335cf9f8098eaa663f06cf8c..e9d022d192817c63784430e80e66c3fa841eabef 100644 --- a/Code/Mantid/MantidPlot/CMakeLists.txt +++ b/Code/Mantid/MantidPlot/CMakeLists.txt @@ -901,6 +901,7 @@ add_subdirectory( docs ) # List of .py files than must be run WITHIN MantidPlot. set ( MANTIDPLOT_TEST_PY_FILES MantidPlotAlgorithmDialogTest.py + MantidPlotInstrumentViewTest.py MantidPlotSliceViewerTest.py MantidPlot1DPlotTest.py MantidPlotProxiesTest.py diff --git a/Code/Mantid/MantidPlot/mantidplot.py b/Code/Mantid/MantidPlot/mantidplot.py index eecafdfcfddf47ce42fc0c6b379d1e61e5ce55de..a5c8831440ddc2065e7fa51c913e8febbbdf13e2 100644 --- a/Code/Mantid/MantidPlot/mantidplot.py +++ b/Code/Mantid/MantidPlot/mantidplot.py @@ -17,8 +17,9 @@ import os import time # Import into the global namespace qti classes that: -# (a) don't need a proxy & (b) can be constructed from python -from _qti import PlotSymbol, ImageSymbol, ArrowMarker, ImageMarker +# (a) don't need a proxy & (b) can be constructed from python or (c) have enumerations within them +from _qti import (PlotSymbol, ImageSymbol, ArrowMarker, ImageMarker, + GraphOptions, InstrumentWindow, InstrumentWindowPickTab, InstrumentWindowMaskTab) # Make the ApplicationWindow instance accessible from the mantidplot namespace from _qti import app @@ -446,17 +447,20 @@ def getMantidMatrix(name): """Get a handle to the named Mantid matrix""" return new_proxy(proxies.MantidMatrix, _qti.app.mantidUI.getMantidMatrix, name) -def getInstrumentView(name, tab=-1): +def getInstrumentView(name, tab=InstrumentWindow.RENDER): """Create an instrument view window based on the given workspace. Args: name: The name of the workspace. - tab: The index of the tab to display initially. + tab: The index of the tab to display initially, (default=InstrumentWindow.RENDER) Returns: A handle to the created instrument view widget. """ - return new_proxy(proxies.MDIWindow, _qti.app.mantidUI.getInstrumentView, name,tab) + ads = _get_analysis_data_service() + if name not in ads: + raise ValueError("Workspace %s does not exist" % name) + return new_proxy(proxies.InstrumentWindow, _qti.app.mantidUI.getInstrumentView, name, tab) def importMatrixWorkspace(name, firstIndex=None, lastIndex=None, showDialog=False, visible=False): """Create a MantidMatrix object from the named workspace. diff --git a/Code/Mantid/MantidPlot/mantidplotpy/proxies.py b/Code/Mantid/MantidPlot/mantidplotpy/proxies.py index 51912424c3a4bc41ce52dffb9d3d2da99a810363..eebc64f417a687bf1bf309b4716ea002aa693659 100644 --- a/Code/Mantid/MantidPlot/mantidplotpy/proxies.py +++ b/Code/Mantid/MantidPlot/mantidplotpy/proxies.py @@ -527,6 +527,73 @@ class MantidMatrix(MDIWindow): """ return new_proxy(Graph, self._getHeldObject().plotGraph2D, type) +#----------------------------------------------------------------------------- +class InstrumentWindow(MDIWindow): + """Proxy for the instrument window + """ + + def __init__(self, toproxy): + """Creates a proxy object around an instrument window + + Args: + toproxy: The raw C object to proxy + """ + QtProxyObject.__init__(self, toproxy) + + def getTab(self, name_or_tab): + """Retrieve a handle to the given tab + + Args: + name_or_index: A string containing the title or tab type + + Returns: + A handle to a tab widget + """ + handle = new_proxy(QtProxyObject, self._getHeldObject().getTab, name_or_tab) + if handle is None: + raise ValueError("Invalid tab title '%s'" % str(name_or_tab)) + return handle + + # ----- Deprecated functions ----- + def changeColormap(self, filename=None): + import warnings + warnings.warn("InstrumentWindow.changeColormap has been deprecated. Use the render tab method instead.") + callable = QtProxyObject.__getattr__(self, "changeColormap") + if filename is None: + callable() + else: + callable(filename) + + def setColorMapMinValue(self, value): + import warnings + warnings.warn("InstrumentWindow.setColorMapMinValue has been deprecated. Use the render tab setMinValue method instead.") + QtProxyObject.__getattr__(self, "setColorMapMinValue")(value) + + def setColorMapMaxValue(self, value): + import warnings + warnings.warn("InstrumentWindow.setColorMapMaxValue has been deprecated. Use the render tab setMaxValue method instead.") + QtProxyObject.__getattr__(self, "setColorMapMaxValue")(value) + + def setColorMapRange(self, minvalue, maxvalue): + import warnings + warnings.warn("InstrumentWindow.setColorMapRange has been deprecated. Use the render tab setRange method instead.") + QtProxyObject.__getattr__(self, "setColorMapRange")(minvalue,maxvalue) + + def setScaleType(self, scale_type): + import warnings + warnings.warn("InstrumentWindow.setScaleType has been deprecated. Use the render tab setScaleType method instead.") + QtProxyObject.__getattr__(self, "setScaleType")(scale_type) + + def setViewType(self, view_type): + import warnings + warnings.warn("InstrumentWindow.setViewType has been deprecated. Use the render tab setSurfaceType method instead.") + QtProxyObject.__getattr__(self, "setViewType")(view_type) + + def selectComponent(self, name): + import warnings + warnings.warn("InstrumentWindow.selectComponent has been deprecated. Use the tree tab selectComponentByName method instead.") + QtProxyObject.__getattr__(self, "selectComponent")(name) + #----------------------------------------------------------------------------- class SliceViewerWindowProxy(QtProxyObject): """Proxy for a C++ SliceViewerWindow object. diff --git a/Code/Mantid/MantidPlot/src/Mantid/InstrumentWidget/InstrumentActor.cpp b/Code/Mantid/MantidPlot/src/Mantid/InstrumentWidget/InstrumentActor.cpp index ac03e821bacb8f7434f188bdc36710e12334f9c3..5beb2c4a50969359492d7f83866d76e2ff45c39c 100644 --- a/Code/Mantid/MantidPlot/src/Mantid/InstrumentWidget/InstrumentActor.cpp +++ b/Code/Mantid/MantidPlot/src/Mantid/InstrumentWidget/InstrumentActor.cpp @@ -215,12 +215,20 @@ IMaskWorkspace_sptr InstrumentActor::getMaskWorkspaceIfExists() const void InstrumentActor::applyMaskWorkspace() { if ( !m_maskWorkspace ) return; - Mantid::API::IAlgorithm * alg = Mantid::API::FrameworkManager::Instance().createAlgorithm("MaskDetectors",-1); - alg->setPropertyValue( "Workspace", getWorkspace()->name() ); - alg->setProperty( "MaskedWorkspace", m_maskWorkspace ); - alg->execute(); - // After the algorithm finishes the InstrumentWindow catches the after-replace notification - // and updates this instrument actor. + try + { + Mantid::API::IAlgorithm * alg = Mantid::API::FrameworkManager::Instance().createAlgorithm("MaskDetectors",-1); + alg->setPropertyValue( "Workspace", getWorkspace()->name() ); + alg->setProperty( "MaskedWorkspace", m_maskWorkspace ); + alg->execute(); + // After the algorithm finishes the InstrumentWindow catches the after-replace notification + // and updates this instrument actor. + } + catch(...) + { + QMessageBox::warning(NULL,"MantidPlot - Warning","An error accured when applying the mask.","OK"); + } + clearMaskWorkspace(); } /** @@ -621,15 +629,15 @@ void InstrumentActor::setAutoscaling(bool on) void InstrumentActor::initMaskHelper() const { if ( m_maskWorkspace ) return; - // extract the mask (if any) from the data to the mask workspace - const std::string maskName = "__InstrumentActor_MaskWorkspace"; - Mantid::API::IAlgorithm * alg = Mantid::API::FrameworkManager::Instance().createAlgorithm("ExtractMask",-1); - alg->setPropertyValue( "InputWorkspace", getWorkspace()->name() ); - alg->setPropertyValue( "OutputWorkspace", maskName ); - alg->execute(); - try { + // extract the mask (if any) from the data to the mask workspace + const std::string maskName = "__InstrumentActor_MaskWorkspace"; + Mantid::API::IAlgorithm * alg = Mantid::API::FrameworkManager::Instance().createAlgorithm("ExtractMask",-1); + alg->setPropertyValue( "InputWorkspace", getWorkspace()->name() ); + alg->setPropertyValue( "OutputWorkspace", maskName ); + alg->execute(); + m_maskWorkspace = boost::dynamic_pointer_cast<Mantid::API::MatrixWorkspace>(Mantid::API::AnalysisDataService::Instance().retrieve(maskName)); Mantid::API::AnalysisDataService::Instance().remove( maskName ); } diff --git a/Code/Mantid/MantidPlot/src/Mantid/InstrumentWidget/InstrumentWindow.cpp b/Code/Mantid/MantidPlot/src/Mantid/InstrumentWidget/InstrumentWindow.cpp index bce9beee83537b120e922c4e8161770ff37544cd..2ed736f0ba377bd198014468605a06576c671347 100644 --- a/Code/Mantid/MantidPlot/src/Mantid/InstrumentWidget/InstrumentWindow.cpp +++ b/Code/Mantid/MantidPlot/src/Mantid/InstrumentWidget/InstrumentWindow.cpp @@ -231,11 +231,38 @@ void InstrumentWindow::selectTab(int tab) } /** - * Return the currently displayed tab. + * Returns the named tab or the current tab if none supplied + * @param title Optional title of a tab (default="") */ -InstrumentWindowTab *InstrumentWindow::getTab()const +InstrumentWindowTab *InstrumentWindow::getTab(const QString & title)const { - return static_cast<InstrumentWindowTab*>(mControlsTab->currentWidget()); + QWidget *tab(NULL); + if(title.isEmpty()) tab = mControlsTab->currentWidget(); + else + { + for(int i = 0; i < mControlsTab->count(); ++i) + { + if(mControlsTab->tabText(i) == title) + { + tab = mControlsTab->widget(i); + break; + } + } + } + + if(tab) return qobject_cast<InstrumentWindowTab*>(tab); + else return NULL; +} + +/** + * @param tab An enumeration for the tab to select + * @returns A pointer to the requested tab + */ +InstrumentWindowTab * InstrumentWindow::getTab(const Tab tab) const +{ + QWidget *widget = mControlsTab->widget(static_cast<int>(tab)); + if(widget) return qobject_cast<InstrumentWindowTab*>(widget); + else return NULL; } /** @@ -628,39 +655,53 @@ void InstrumentWindow::pickBackgroundColor() setBackgroundColor(color); } -void InstrumentWindow::saveImage() +/** + * Saves the current image buffer as a png file. + * @param filename Optional filename. Empty string raises a save dialog + */ +void InstrumentWindow::saveImage(QString filename) { + QString defaultExt = ".png"; QList<QByteArray> formats = QImageWriter::supportedImageFormats(); - QListIterator<QByteArray> itr(formats); - QString filter(""); - while( itr.hasNext() ) + if(filename.isEmpty()) { - filter += "*." + itr.next(); - if( itr.hasNext() ) + QListIterator<QByteArray> itr(formats); + QString filter(""); + while( itr.hasNext() ) { - filter += ";;"; + filter += "*." + itr.next(); + if( itr.hasNext() ) + { + filter += ";;"; + } } - } - QString selectedFilter = "*.png"; - QString filename = getSaveFileName("Save image ...", filter, &selectedFilter); + QString selectedFilter = "*" + defaultExt; + filename = getSaveFileName("Save image ...", filter, &selectedFilter); - // If its empty, they cancelled the dialog - if( filename.isEmpty() ) return; + // If its empty, they cancelled the dialog + if( filename.isEmpty() ) return; + } QFileInfo finfo(filename); - QString ext = finfo.completeSuffix(); + if( ext.isEmpty() ) { - filename += selectedFilter.section("*", 1); + filename += defaultExt; ext = QFileInfo(filename).completeSuffix(); } else { - QStringList extlist = filter.split(";;"); - if( !extlist.contains("*." + ext) ) + if( !formats.contains(ext.toAscii()) ) { - QMessageBox::warning(this, "MantidPlot", "Unsupported file extension, please use one from the supported list."); + QString msg("Unsupported file extension. Choose one of the following: "); + QListIterator<QByteArray> itr(formats); + while( itr.hasNext() ) + { + msg += itr.next() + ", "; + } + msg.chop(2);// Remove last space and comma + QMessageBox::warning(this, "MantidPlot", msg); return; } } @@ -983,20 +1024,7 @@ void InstrumentWindow::dropEvent( QDropEvent* e ) if (text.startsWith("Workspace::")) { QStringList wsName = text.split("::"); - Mantid::API::IPeaksWorkspace_sptr pws = boost::dynamic_pointer_cast<Mantid::API::IPeaksWorkspace>( - Mantid::API::AnalysisDataService::Instance().retrieve(wsName[1].toStdString())); - auto surface = boost::dynamic_pointer_cast<UnwrappedSurface>( getSurface() ); - if (pws && surface) - { - surface->setPeaksWorkspace(pws); - updateInstrumentView(); - e->accept(); - return; - } - else if (pws && !surface) - { - QMessageBox::warning(this,"MantidPlot - Warning","Please change to an unwrapped view to see peak labels."); - } + if(this->overlay(wsName[1])) e->accept(); } e->ignore(); } @@ -1046,6 +1074,30 @@ void InstrumentWindow::setColorMapAutoscaling(bool on) updateInstrumentView(); } +/** + * Overlay a workspace with the given name + * @param wsName The name of a workspace in the ADS + * @returns True if the overlay was successful, false otherwise + */ +bool InstrumentWindow::overlay(const QString & wsName) +{ + using namespace Mantid::API; + auto pws = boost::dynamic_pointer_cast<IPeaksWorkspace>(AnalysisDataService::Instance().retrieve(wsName.toStdString())); + auto surface = boost::dynamic_pointer_cast<UnwrappedSurface>( getSurface() ); + bool success(false); + if (pws && surface) + { + surface->setPeaksWorkspace(pws); + updateInstrumentView(); + success = true; + } + else if (pws && !surface) + { + QMessageBox::warning(this,"MantidPlot - Warning","Please change to an unwrapped view to see peak labels."); + } + return success; +} + /** * Remove all peak overlays from the instrument display. */ @@ -1224,17 +1276,10 @@ void InstrumentWindow::enableOpenGL( bool on ) /// Private slot to toggle between the GL and simple instrument display widgets void InstrumentWindow::enableGL( bool on ) { - m_useOpenGL = on; - if ( m_surfaceType == FULL3D ) - { - // always OpenGL in 3D - selectOpenGLDisplay( true ); - } - else - { - // select the display - selectOpenGLDisplay( on ); - } + if ( m_surfaceType == FULL3D ) m_useOpenGL = true; // always OpenGL in 3D + else m_useOpenGL = on; + + selectOpenGLDisplay(m_useOpenGL); } /// True if the GL instrument display is currently on diff --git a/Code/Mantid/MantidPlot/src/Mantid/InstrumentWidget/InstrumentWindow.h b/Code/Mantid/MantidPlot/src/Mantid/InstrumentWidget/InstrumentWindow.h index 9dde5ddc70da9f56372f3483354095da3fe9ab30..be9f36b9bed213aef3e0a5e670e7bca97aeb5f6b 100644 --- a/Code/Mantid/MantidPlot/src/Mantid/InstrumentWidget/InstrumentWindow.h +++ b/Code/Mantid/MantidPlot/src/Mantid/InstrumentWidget/InstrumentWindow.h @@ -51,7 +51,10 @@ class QSettings; \date September 2008 \version 1.0 - This is a QT widget for the controls and display of instrument geometry + This is a QT widget for the controls and display of instrument geometry. + The user documentation can be found at http://www.mantidproject.org/MantidPlot:_Instrument_View + and needs to be updated whenever the instrument view functionality changes. + */ class InstrumentWindow : public MdiSubWindow, public MantidQt::API::WorkspaceObserver, public Mantid::API::AlgorithmObserver { @@ -91,7 +94,8 @@ public: bool blocked()const{return m_blocked;} void selectTab(int tab); void selectTab(Tab tab){selectTab(int(tab));} - InstrumentWindowTab *getTab()const; + InstrumentWindowTab *getTab(const QString & title="") const; + InstrumentWindowTab *getTab(const Tab tab) const; /// Get a filename for saving QString getSaveFileName(const QString& title, const QString& filters, QString* selectedFilter = NULL); @@ -133,23 +137,26 @@ public slots: void executeAlgorithm(Mantid::API::IAlgorithm_sptr); void setupColorMap(); - void changeColormap(const QString & filename = ""); - void changeScaleType(int); - void changeColorMapMinValue(double minValue); - void changeColorMapMaxValue(double maxValue); - void changeColorMapRange(double minValue, double maxValue); + + void changeColormap(const QString & filename = ""); // Deprecated + void changeScaleType(int);// Deprecated + void changeColorMapMinValue(double minValue); // Deprecated + void changeColorMapMaxValue(double maxValue); // Deprecated + void changeColorMapRange(double minValue, double maxValue); // Deprecated void setIntegrationRange(double,double); void setBinRange(double,double); - void setColorMapAutoscaling(bool); + void setColorMapAutoscaling(bool); // Deprecated void setViewDirection(const QString&); void pickBackgroundColor(); - void saveImage(); + void saveImage(QString filename); void setInfoText(const QString&); void set3DAxesState(bool); void setSurfaceType(int); void setWireframe(bool); + /// Overlay a workspace with the given name + bool overlay(const QString & wsName); void clearPeakOverlays(); void setPeakLabelPrecision(int n); void setShowPeakRowFlag(bool on); diff --git a/Code/Mantid/MantidPlot/src/Mantid/InstrumentWidget/InstrumentWindowMaskTab.cpp b/Code/Mantid/MantidPlot/src/Mantid/InstrumentWidget/InstrumentWindowMaskTab.cpp index e922c4097834694baa56aa92942157da52730c9e..3fc0b19ac6b94e2373af0f86156bb7819bfdd49a 100644 --- a/Code/Mantid/MantidPlot/src/Mantid/InstrumentWidget/InstrumentWindowMaskTab.cpp +++ b/Code/Mantid/MantidPlot/src/Mantid/InstrumentWidget/InstrumentWindowMaskTab.cpp @@ -47,6 +47,7 @@ #include <QToolTip> #include <QTemporaryFile> #include <QGroupBox> +#include <QCheckBox> #include "MantidQtAPI/FileDialogHandler.h" @@ -147,13 +148,13 @@ m_userEditing(true) // Create property browser - /* Create property managers: they create, own properties, get and set values */ + /* Create property managers: they create, own properties, get and set values */ m_groupManager = new QtGroupPropertyManager(this); m_doubleManager = new QtDoublePropertyManager(this); connect(m_doubleManager,SIGNAL(propertyChanged(QtProperty*)),this,SLOT(doubleChanged(QtProperty*))); - /* Create editors and assign them to the managers */ + /* Create editors and assign them to the managers */ DoubleEditorFactory *doubleEditorFactory = new DoubleEditorFactory(this); @@ -164,14 +165,22 @@ m_userEditing(true) // Algorithm buttons - m_apply = new QPushButton("Apply Mask(s) to Workspace(data)"); + m_apply = new QPushButton("Apply to Data"); m_apply->setToolTip("Apply current mask to the data workspace. Cannot be reverted."); connect(m_apply,SIGNAL(clicked()),this,SLOT(applyMask())); + m_apply_to_view = new QPushButton("Apply to View"); + m_apply_to_view->setToolTip("Apply current mask to the view."); + connect(m_apply_to_view,SIGNAL(clicked()),this,SLOT(applyMaskToView())); + m_clear_all = new QPushButton("Clear All"); m_clear_all->setToolTip("Clear all masking that have not been applied to the data."); connect(m_clear_all,SIGNAL(clicked()),this,SLOT(clearMask())); + m_savegroupdet = new QCheckBox("Grouped Detectors"); + m_savegroupdet->setToolTip("If checked, then save masked with grouped detectors. "); + m_savegroupdet->setChecked(false); + m_save_as_workspace_exclude = new QAction("As Mask to workspace",this); m_save_as_workspace_exclude->setToolTip("Save current mask to mask workspace."); connect(m_save_as_workspace_exclude,SIGNAL(activated()),this,SLOT(saveMaskToWorkspace())); @@ -213,7 +222,7 @@ m_userEditing(true) connect(m_sum_to_workspace,SIGNAL(activated()),this,SLOT(sumDetsToWorkspace())); // Save button and its menus - m_saveButton = new QPushButton("Save"); + m_saveButton = new QPushButton("Apply and Save"); m_saveButton->setToolTip("Save current masking/grouping to a file or a workspace."); m_saveMask = new QMenu(this); @@ -237,26 +246,77 @@ m_userEditing(true) m_saveGroup->addAction(m_save_group_file_exclude); connect(m_saveGroup,SIGNAL(hovered(QAction*)),this,SLOT(showSaveMenuTooltip(QAction*))); - + QGroupBox *box = new QGroupBox("View"); QGridLayout* buttons = new QGridLayout(); - buttons->addWidget(m_apply,0,0,1,2); + buttons->addWidget(m_apply_to_view,0,0,1,2); buttons->addWidget(m_saveButton,1,0); buttons->addWidget(m_clear_all,1,1); - - layout->addLayout(buttons); + buttons->addWidget(m_savegroupdet, 2, 0, 1, 2); + + box->setLayout(buttons); + layout->addWidget(box); + + box = new QGroupBox("Workspace"); + buttons = new QGridLayout(); + buttons->addWidget(m_apply,0,0); + box->setLayout(buttons); + layout->addWidget(box); } +/** + * Initialize the tab when new projection surface is created. + */ void InstrumentWindowMaskTab::initSurface() { connect(m_instrWindow->getSurface().get(),SIGNAL(shapeCreated()),this,SLOT(shapeCreated())); connect(m_instrWindow->getSurface().get(),SIGNAL(shapeSelected()),this,SLOT(shapeSelected())); connect(m_instrWindow->getSurface().get(),SIGNAL(shapesDeselected()),this,SLOT(shapesDeselected())); connect(m_instrWindow->getSurface().get(),SIGNAL(shapeChanged()),this,SLOT(shapeChanged())); - enableApply(); - enableClear(); + connect(m_instrWindow->getSurface().get(),SIGNAL(shapesCleared()),this,SLOT(shapesCleared())); + enableApplyButtons(); } +/** + * Selects between masking/grouping + * @param mode The required mode, @see Mode + */ +void InstrumentWindowMaskTab::setMode(Mode mode) +{ + switch(mode) + { + case Mask: toggleMaskGroup(true); + break; + case Group: toggleMaskGroup(false); + break; + default: throw std::invalid_argument("Invalid Mask tab mode. Use Mask/Group."); + }; + + +} + +void InstrumentWindowMaskTab::selectTool(Activity tool) +{ + switch(tool) + { + case Move: m_move->setChecked(true); + break; + case Select: m_pointer->setChecked(true); + break; + case DrawEllipse: m_ellipse->setChecked(true); + break; + case DrawRectangle: m_rectangle->setChecked(true); + break; + case DrawEllipticalRing: m_ring_ellipse->setChecked(true); + break; + case DrawRectangularRing: m_ring_rectangle->setChecked(true); + break; + default: throw std::invalid_argument("Invalid tool type."); + } + setActivity(); +} + + /** * Set tab's activity based on the currently selected tool button. */ @@ -282,42 +342,53 @@ void InstrumentWindowMaskTab::setActivity() } else if (m_rectangle->isChecked()) { - m_activity = DrawEllipse; + m_activity = DrawRectangle; m_instrWindow->getSurface()->startCreatingShape2D("rectangle",borderColor,fillColor); m_instrWindow->getSurface()->setInteractionMode(ProjectionSurface::DrawMode); } else if (m_ring_ellipse->isChecked()) { - m_activity = DrawEllipse; + m_activity = DrawEllipticalRing; m_instrWindow->getSurface()->startCreatingShape2D("ring ellipse",borderColor,fillColor); m_instrWindow->getSurface()->setInteractionMode(ProjectionSurface::DrawMode); } else if (m_ring_rectangle->isChecked()) { - m_activity = DrawEllipse; + m_activity = DrawRectangularRing; m_instrWindow->getSurface()->startCreatingShape2D("ring rectangle",borderColor,fillColor); m_instrWindow->getSurface()->setInteractionMode(ProjectionSurface::DrawMode); } m_instrWindow->updateInfoText(); } +/** + * Slot responding on creation of a new masking shape. + */ void InstrumentWindowMaskTab::shapeCreated() { setSelectActivity(); - enableApply(); - enableClear(); + enableApplyButtons(); } +/** + * Slot responding on selection of a new masking shape. + */ void InstrumentWindowMaskTab::shapeSelected() { setProperties(); } +/** + * Slot responding on deselecting all masking shapes. + */ void InstrumentWindowMaskTab::shapesDeselected() { clearProperties(); } +/** + * Slot responding on a change of a masking shape. + */ void InstrumentWindowMaskTab::shapeChanged() { if (!m_left) return; // check that everything is ok @@ -343,6 +414,14 @@ void InstrumentWindowMaskTab::shapeChanged() m_userEditing = true; } +/** + * Slot responding on removing all masking shapes. + */ +void InstrumentWindowMaskTab::shapesCleared() +{ + enableApplyButtons(); +} + /** * Removes the mask shapes from the screen. */ @@ -355,8 +434,7 @@ void InstrumentWindowMaskTab::showEvent (QShowEvent *) { setActivity(); m_instrWindow->setMouseTracking(true); - enableApply(); - enableClear(); + enableApplyButtons(); m_instrWindow->updateInstrumentView(true); } @@ -456,11 +534,19 @@ void InstrumentWindowMaskTab::applyMask() storeMask(); QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); m_instrWindow->getInstrumentActor()->applyMaskWorkspace(); - enableApply(); - enableClear(); + enableApplyButtons(); QApplication::restoreOverrideCursor(); } +/** + * Apply the constructed mask to the view only. + */ +void InstrumentWindowMaskTab::applyMaskToView() +{ + storeMask(); + enableApplyButtons(); +} + /** * Remove all masking that has not been applied to the data workspace. */ @@ -469,8 +555,7 @@ void InstrumentWindowMaskTab::clearMask() clearShapes(); m_instrWindow->getInstrumentActor()->clearMaskWorkspace(); m_instrWindow->updateInstrumentView(); - enableApply(); - enableClear(); + enableApplyButtons(); } /** @@ -619,14 +704,21 @@ void InstrumentWindowMaskTab::showSaveMenuTooltip(QAction *action) */ void InstrumentWindowMaskTab::toggleMaskGroup(bool maskOn) { - enableApply(); + m_masking_on->blockSignals(true); + m_masking_on->setChecked(maskOn); + m_grouping_on->setChecked(!maskOn); + m_masking_on->blockSignals(false); + + enableApplyButtons(); if ( maskOn ) { m_saveButton->setMenu(m_saveMask); + m_saveButton->setText("Apply and Save"); } else { m_saveButton->setMenu(m_saveGroup); + m_saveButton->setText("Save"); } m_instrWindow->getSurface()->changeBorderColor(getShapeBorderColor()); m_instrWindow->updateInstrumentView(); @@ -640,13 +732,11 @@ void InstrumentWindowMaskTab::toggleMaskGroup(bool maskOn) void InstrumentWindowMaskTab::saveMaskingToWorkspace(bool invertMask) { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); - // Make sure we have stored the Mask in the helper MaskWorkspace storeMask(); - setSelectActivity(); createMaskWorkspace(invertMask, false); - + enableApplyButtons(); QApplication::restoreOverrideCursor(); } @@ -671,14 +761,19 @@ void InstrumentWindowMaskTab::saveMaskingToFile(bool invertMask) if (!fileName.isEmpty()) { + // Check option "GroupedDetectors" + bool groupeddetectors = m_savegroupdet->isChecked(); + + // Call "SaveMask()" Mantid::API::IAlgorithm_sptr alg = Mantid::API::AlgorithmManager::Instance().create("SaveMask",-1); alg->setProperty("InputWorkspace",boost::dynamic_pointer_cast<Mantid::API::Workspace>(outputWS)); alg->setPropertyValue("OutputFile",fileName.toStdString()); - alg->setProperty("GroupedDetectors",true); + alg->setProperty("GroupedDetectors", groupeddetectors); alg->execute(); } Mantid::API::AnalysisDataService::Instance().remove( outputWS->name() ); } + enableApplyButtons(); QApplication::restoreOverrideCursor(); } @@ -700,9 +795,6 @@ void InstrumentWindowMaskTab::saveMaskingToCalFile(bool invertMask) { clearShapes(); QString fileName = m_instrWindow->getSaveFileName("Select location and name for the mask file", "cal files (*.cal)"); - - std::cerr << "File " << fileName.toStdString() << std::endl; - if (!fileName.isEmpty()) { Mantid::API::IAlgorithm_sptr alg = Mantid::API::AlgorithmManager::Instance().create("MaskWorkspaceToCalFile",-1); @@ -713,6 +805,7 @@ void InstrumentWindowMaskTab::saveMaskingToCalFile(bool invertMask) } Mantid::API::AnalysisDataService::Instance().remove( outputWS->name() ); } + enableApplyButtons(); QApplication::restoreOverrideCursor(); } @@ -745,31 +838,26 @@ std::string InstrumentWindowMaskTab::generateMaskWorkspaceName(bool temp) const /** * Sets the m_hasMaskToApply flag and - * enables/disables the Apply button. + * enables/disables the apply and clear buttons. */ -void InstrumentWindowMaskTab::enableApply() +void InstrumentWindowMaskTab::enableApplyButtons() { + bool hasMaskShapes = m_instrWindow->getSurface()->hasMasks(); + bool hasMaskWorkspace = m_instrWindow->getInstrumentActor()->hasMaskWorkspace(); + bool hasMask = hasMaskShapes || hasMaskWorkspace; if ( isMasking() ) { - bool hasMasks = m_instrWindow->getSurface()->hasMasks(); - m_hasMaskToApply = hasMasks; - m_apply->setEnabled(hasMasks); + m_hasMaskToApply = hasMask; + m_apply->setEnabled(hasMask); + m_apply_to_view->setEnabled(hasMaskShapes); } else { m_apply->setEnabled(false); + m_apply_to_view->setEnabled(false); } -} - -/** - * Enables/disables the ClearAll button. - */ -void InstrumentWindowMaskTab::enableClear() -{ - m_clear_all->setEnabled( - m_instrWindow->getSurface()->hasMasks() - || m_instrWindow->getInstrumentActor()->hasMaskWorkspace() - ); + m_saveButton->setEnabled(hasMask); + m_clear_all->setEnabled(hasMask); } /** @@ -824,6 +912,7 @@ void InstrumentWindowMaskTab::storeMask() m_instrWindow->updateInstrumentView(); // to refresh the pick image QList<int> dets; + // get detectors covered by the shapes m_instrWindow->getSurface()->getMaskedDetectors(dets); if (!dets.isEmpty()) { @@ -834,11 +923,21 @@ void InstrumentWindowMaskTab::storeMask() } if ( !detList.empty() ) { - m_instrWindow->getInstrumentActor()->getMaskWorkspace()->setMasked( detList ); - m_instrWindow->getInstrumentActor()->update(); - m_instrWindow->updateInstrumentDetectors(); + // try to mask each detector separatly and ignore any failure + for(auto det = detList.begin(); det != detList.end(); ++det) + { + try + { + m_instrWindow->getInstrumentActor()->getMaskWorkspace()->setMasked( *det ); + } + catch(...){} + } + // update detector colours + m_instrWindow->getInstrumentActor()->update(); + m_instrWindow->updateInstrumentDetectors(); } } + // remove masking shapes clearShapes(); QApplication::restoreOverrideCursor(); } diff --git a/Code/Mantid/MantidPlot/src/Mantid/InstrumentWidget/InstrumentWindowMaskTab.h b/Code/Mantid/MantidPlot/src/Mantid/InstrumentWidget/InstrumentWindowMaskTab.h index 665653b37d2b55c95978c3881dc977cd39e179bc..6ba2d70d556a9bca57fb4c558765e48306031412 100644 --- a/Code/Mantid/MantidPlot/src/Mantid/InstrumentWidget/InstrumentWindowMaskTab.h +++ b/Code/Mantid/MantidPlot/src/Mantid/InstrumentWidget/InstrumentWindowMaskTab.h @@ -51,9 +51,14 @@ class InstrumentWindowMaskTab: public InstrumentWindowTab { Q_OBJECT public: - enum Activity {Move = 0, Select = 1, DrawEllipse}; + enum Mode {Mask, Group}; + enum Activity {Move,Select,DrawEllipse,DrawRectangle,DrawEllipticalRing,DrawRectangularRing}; + InstrumentWindowMaskTab(InstrumentWindow* instrWindow); void initSurface(); + void setMode(Mode mode); + void selectTool(Activity tool); + signals: void executeAlgorithm(const QString&, const QString&); protected slots: @@ -62,8 +67,10 @@ protected slots: void shapeSelected(); void shapesDeselected(); void shapeChanged(); + void shapesCleared(); void clearShapes(); void applyMask(); + void applyMaskToView(); void storeMask(); void clearMask(); void saveInvertedMaskToWorkspace(); @@ -90,8 +97,7 @@ protected: void saveMaskingToFile(bool invertMask = false); void saveMaskingToCalFile(bool invertMask = false); std::string generateMaskWorkspaceName(bool temp = false) const; - void enableApply(); - void enableClear(); + void enableApplyButtons(); void setSelectActivity(); /// True if in masking mode, flase if in grouping. bool isMasking() const; @@ -119,8 +125,11 @@ protected: QPushButton* m_ring_rectangle; QPushButton* m_apply; + QPushButton* m_apply_to_view; QPushButton* m_clear_all; QPushButton* m_saveButton; + QCheckBox* m_savegroupdet; + QMenu* m_saveMask; QAction* m_save_as_workspace_include; diff --git a/Code/Mantid/MantidPlot/src/Mantid/InstrumentWidget/InstrumentWindowPickTab.cpp b/Code/Mantid/MantidPlot/src/Mantid/InstrumentWidget/InstrumentWindowPickTab.cpp index 1a8c6c1097c2bb3c979c43239a456006fa844514..b2b281f00fda64779cebb490bb1decbc8d05d38a 100644 --- a/Code/Mantid/MantidPlot/src/Mantid/InstrumentWidget/InstrumentWindowPickTab.cpp +++ b/Code/Mantid/MantidPlot/src/Mantid/InstrumentWidget/InstrumentWindowPickTab.cpp @@ -1223,6 +1223,30 @@ bool InstrumentWindowPickTab::addToDisplayContextMenu(QMenu &context) const return res; } +/** + * Select a tool on the tab + * @param tool One of the enumerated tool types, @see ToolType + */ +void InstrumentWindowPickTab::selectTool(const ToolType tool) +{ + switch(tool) + { + case Zoom: m_zoom->setChecked(true); + break; + case PixelSelect: m_one->setChecked(true); + break; + case TubeSelect: m_tube->setChecked(true); + break; + case PeakSelect: m_peak->setChecked(true); + break; + case PeakErase: m_peakSelect->setChecked(true); + break; + default: throw std::invalid_argument("Invalid tool type."); + } + setSelectionType(); +} + + void InstrumentWindowPickTab::singleDetectorTouched(int detid) { if (canUpdateTouchedDetector()) diff --git a/Code/Mantid/MantidPlot/src/Mantid/InstrumentWidget/InstrumentWindowPickTab.h b/Code/Mantid/MantidPlot/src/Mantid/InstrumentWidget/InstrumentWindowPickTab.h index 33ec2226777b860033685b2d238804b4ff2b807f..a3ba9312c7ba3cb2c827a80d203956bdb5963458 100644 --- a/Code/Mantid/MantidPlot/src/Mantid/InstrumentWidget/InstrumentWindowPickTab.h +++ b/Code/Mantid/MantidPlot/src/Mantid/InstrumentWidget/InstrumentWindowPickTab.h @@ -43,7 +43,9 @@ public: /// SelectPeak: click on a peak marker or draw a rubber-band selector to select peak /// markers. Selected peaks can be deleted by pressing the Delete key. enum SelectionType {Single=0,AddPeak,ErasePeak,SingleDetectorSelection,Tube}; + enum ToolType {Zoom,PixelSelect,TubeSelect,PeakSelect,PeakErase}; enum TubeXUnits {DETECTOR_ID = 0,LENGTH,PHI,NUMBER_OF_UNITS}; + InstrumentWindowPickTab(InstrumentWindow* instrWindow); void updatePick(int detid); bool canUpdateTouchedDetector()const; @@ -53,6 +55,7 @@ public: void saveSettings(QSettings& settings) const; void loadSettings(const QSettings& settings); bool addToDisplayContextMenu(QMenu&) const; + void selectTool(const ToolType tool); public slots: void setTubeXUnits(int units); diff --git a/Code/Mantid/MantidPlot/src/Mantid/InstrumentWidget/InstrumentWindowRenderTab.cpp b/Code/Mantid/MantidPlot/src/Mantid/InstrumentWidget/InstrumentWindowRenderTab.cpp index 155ca0f22abc24f068670353b1afcc13bd44857d..54397d67471429f8f722bc60095257f9b7dde0df 100644 --- a/Code/Mantid/MantidPlot/src/Mantid/InstrumentWidget/InstrumentWindowRenderTab.cpp +++ b/Code/Mantid/MantidPlot/src/Mantid/InstrumentWidget/InstrumentWindowRenderTab.cpp @@ -51,14 +51,14 @@ InstrumentWindowTab(instrWindow) // Save image control mSaveImage = new QPushButton(tr("Save image")); mSaveImage->setToolTip("Save the instrument image to a file"); - connect(mSaveImage, SIGNAL(clicked()), m_instrWindow, SLOT(saveImage())); + connect(mSaveImage, SIGNAL(clicked()), this, SLOT(saveImage())); // Setup Display Setting menu QPushButton* displaySettings = new QPushButton("Display Settings",this); QMenu* displaySettingsMenu = new QMenu(this); connect(displaySettingsMenu, SIGNAL(aboutToShow()),this,SLOT(displaySettingsAboutToshow())); m_colorMap = new QAction("Color Map",this); - connect(m_colorMap,SIGNAL(triggered()),this,SLOT(changeColormap())); + connect(m_colorMap,SIGNAL(triggered()),this,SLOT(changeColorMap())); m_backgroundColor = new QAction("Background Color",this); connect(m_backgroundColor,SIGNAL(triggered()),m_instrWindow,SLOT(pickBackgroundColor())); m_lighting = new QAction("Lighting",this); @@ -86,7 +86,7 @@ InstrumentWindowTab(instrWindow) bool useOpenGL = setting == "ON"; m_instrWindow->enableGL( useOpenGL ); m_GLView->setChecked( useOpenGL ); - connect(m_GLView, SIGNAL( toggled(bool) ), m_instrWindow, SLOT( enableGL(bool) )); + connect(m_GLView, SIGNAL( toggled(bool) ), this, SLOT( enableGL(bool) )); displaySettingsMenu->addAction(m_colorMap); displaySettingsMenu->addAction(m_backgroundColor); @@ -210,7 +210,7 @@ void InstrumentWindowRenderTab::setupColorBarScaling(const MantidColorMap& cmap, /** * Change color map button slot. This provides the file dialog box to select colormap or sets it directly a string is provided */ -void InstrumentWindowRenderTab::changeColormap(const QString &filename) +void InstrumentWindowRenderTab::changeColorMap(const QString &filename) { m_instrWindow->changeColormap(filename); } @@ -334,6 +334,20 @@ void InstrumentWindowRenderTab::displayDetectorsOnly(bool yes) m_displayDetectorsOnly->blockSignals(false); } +/** + * Toggle use of OpenGL + * + * @param on :: True of false for on and off. + */ +void InstrumentWindowRenderTab::enableGL(bool on) +{ + m_instrWindow->enableGL(on); + m_GLView->blockSignals(true); + m_GLView->setChecked(m_instrWindow->isGLEnabled()); + m_GLView->blockSignals(false); +} + + void InstrumentWindowRenderTab::showEvent (QShowEvent *) { auto surface = getSurface(); @@ -357,6 +371,21 @@ void InstrumentWindowRenderTab::flipUnwrappedView(bool on) if (!surface) return; surface->setFlippedView(on); m_instrWindow->updateInstrumentView(); + // Sync checkbox + m_flipCheckBox->blockSignals(true); + m_flipCheckBox->setChecked(on); + m_flipCheckBox->blockSignals(false); + +} + +/** + * Saves the current image buffer to the given file. An empty string raises a dialog + * for finding the file + * @param filename Optional full path of the saved image + */ +void InstrumentWindowRenderTab::saveImage(QString filename) +{ + m_instrWindow->saveImage(filename); } /** @@ -466,6 +495,10 @@ void InstrumentWindowRenderTab::displaySettingsAboutToshow() */ void InstrumentWindowRenderTab::setSurfaceType(int index) { + m_renderMode->blockSignals(true); + m_renderMode->setCurrentIndex( index ); + m_renderMode->blockSignals(false); + m_instrWindow->setSurfaceType( index ); showResetView( index ); showFlipControl( index ); diff --git a/Code/Mantid/MantidPlot/src/Mantid/InstrumentWidget/InstrumentWindowRenderTab.h b/Code/Mantid/MantidPlot/src/Mantid/InstrumentWidget/InstrumentWindowRenderTab.h index bb32cd5d79ec2fcbf8daf5badadeb903a0be1508..4618868106f90cc3017bfea013176b4560969dab 100644 --- a/Code/Mantid/MantidPlot/src/Mantid/InstrumentWidget/InstrumentWindowRenderTab.h +++ b/Code/Mantid/MantidPlot/src/Mantid/InstrumentWidget/InstrumentWindowRenderTab.h @@ -47,17 +47,20 @@ public slots: void setRange(double minValue, double maxValue, bool apply = true); void showAxes(bool on); void displayDetectorsOnly(bool yes); + void enableGL(bool on); void setColorMapAutoscaling(bool); + void changeColorMap(const QString & filename = ""); + void setSurfaceType(int); + void flipUnwrappedView(bool); + void saveImage(QString filename = ""); private slots: - void changeColormap(const QString & filename = ""); + void showResetView(int); void showFlipControl(int); - void flipUnwrappedView(bool); /// Called before the display setting menu opens. Filters out menu options. void displaySettingsAboutToshow(); - /// Change the type of the surface - void setSurfaceType(int); + /// Change the type of the surfac void surfaceTypeChanged(int); void colorMapChanged(); void scaleTypeChanged(int); diff --git a/Code/Mantid/MantidPlot/src/Mantid/InstrumentWidget/ProjectionSurface.cpp b/Code/Mantid/MantidPlot/src/Mantid/InstrumentWidget/ProjectionSurface.cpp index c705a951913b385fd653741abc037f4a564eeea9..df3df8f36bf31436139dfc99a6b18f74f5143504 100644 --- a/Code/Mantid/MantidPlot/src/Mantid/InstrumentWidget/ProjectionSurface.cpp +++ b/Code/Mantid/MantidPlot/src/Mantid/InstrumentWidget/ProjectionSurface.cpp @@ -45,10 +45,11 @@ ProjectionSurface::ProjectionSurface(const InstrumentActor* rootActor,const Mant m_redrawPicking(true) { connect(rootActor,SIGNAL(colorMapChanged()),this,SLOT(colorMapChanged())); - connect(&m_maskShapes,SIGNAL(shapeCreated()),this,SLOT(catchShapeCreated())); - connect(&m_maskShapes,SIGNAL(shapeSelected()),this,SLOT(catchShapeSelected())); - connect(&m_maskShapes,SIGNAL(shapesDeselected()),this,SLOT(catchShapesDeselected())); - connect(&m_maskShapes,SIGNAL(shapeChanged()),this,SLOT(catchShapeChanged())); + connect(&m_maskShapes,SIGNAL(shapeCreated()),this,SIGNAL(shapeCreated())); + connect(&m_maskShapes,SIGNAL(shapeSelected()),this,SIGNAL(shapeSelected())); + connect(&m_maskShapes,SIGNAL(shapesDeselected()),this,SIGNAL(shapesDeselected())); + connect(&m_maskShapes,SIGNAL(shapeChanged()),this,SIGNAL(shapeChanged())); + connect(&m_maskShapes,SIGNAL(cleared()),this,SIGNAL(shapesCleared())); // create and connect the pick input controller InputControllerPick* pickController = new InputControllerPick(this); @@ -585,26 +586,6 @@ void ProjectionSurface::startCreatingShape2D(const QString& type,const QColor& b emit signalToStartCreatingShape2D(type,borderColor,fillColor); } -void ProjectionSurface::catchShapeCreated() -{ - emit shapeCreated(); -} - -void ProjectionSurface::catchShapeSelected() -{ - emit shapeSelected(); -} - -void ProjectionSurface::catchShapesDeselected() -{ - emit shapesDeselected(); -} - -void ProjectionSurface::catchShapeChanged() -{ - emit shapeChanged(); -} - /** * Return a combined list of peak parkers from all overlays * @param detID :: The detector ID of interest diff --git a/Code/Mantid/MantidPlot/src/Mantid/InstrumentWidget/ProjectionSurface.h b/Code/Mantid/MantidPlot/src/Mantid/InstrumentWidget/ProjectionSurface.h index 0274e5410392ff9a961ecf3f28f23ba493c4ca88..e3ad67718dfd8711cee95172a7a5dccb89394a44 100644 --- a/Code/Mantid/MantidPlot/src/Mantid/InstrumentWidget/ProjectionSurface.h +++ b/Code/Mantid/MantidPlot/src/Mantid/InstrumentWidget/ProjectionSurface.h @@ -198,6 +198,7 @@ signals: void shapeSelected(); void shapesDeselected(); void shapeChanged(); + void shapesCleared(); // peaks void peaksWorkspaceAdded(); @@ -218,10 +219,6 @@ protected slots: void erasePeaks(const QRect& rect); void colorMapChanged(); - void catchShapeCreated(); - void catchShapeSelected(); - void catchShapesDeselected(); - void catchShapeChanged(); protected: diff --git a/Code/Mantid/MantidPlot/src/Mantid/InstrumentWidget/Shape2DCollection.cpp b/Code/Mantid/MantidPlot/src/Mantid/InstrumentWidget/Shape2DCollection.cpp index fb486cb76878cb1b2aabd576c475403a8c106b56..d239fdf0c22d6381b7a41ae0075b507413767e4b 100644 --- a/Code/Mantid/MantidPlot/src/Mantid/InstrumentWidget/Shape2DCollection.cpp +++ b/Code/Mantid/MantidPlot/src/Mantid/InstrumentWidget/Shape2DCollection.cpp @@ -105,6 +105,10 @@ void Shape2DCollection::removeShape(Shape2D* shape) m_shapes.removeOne(shape); delete shape; } + if (m_shapes.isEmpty()) + { + emit cleared(); + } } /** @@ -121,6 +125,10 @@ void Shape2DCollection::removeShapes(const QList<Shape2D*>& shapeList) } removeShape( shape ); } + if (m_shapes.isEmpty()) + { + emit cleared(); + } } /** @@ -130,19 +138,6 @@ void Shape2DCollection::setWindow(const RectF &surface,const QRect& viewport) co m_viewport = viewport; m_surfaceRect = surface; m_surfaceRect.findTransform( m_transform, viewport ); - -// std::cerr << "surface:" << std::endl; -// std::cerr << surface.x0() << ' ' << surface.y0() << ' ' << surface.width() << ' ' << surface.height() << std::endl; -// std::cerr << "Viewport:" << std::endl; -// std::cerr << viewport.x() << ' ' << viewport.y() << ' ' << viewport.width() << ' ' << viewport.height() << std::endl; -// std::cerr << "Transform:" << std::endl; -// std::cerr << m_transform.m11() << ' ' -// << m_transform.m12() << ' ' -// << m_transform.m22() << ' ' -// << m_transform.m31() << ' ' -// << m_transform.m32() << ' ' -// << m_transform.m33() << ' ' -// << std::endl; } void Shape2DCollection::refit() diff --git a/Code/Mantid/MantidPlot/src/Mantid/InstrumentWidget/Shape2DCollection.h b/Code/Mantid/MantidPlot/src/Mantid/InstrumentWidget/Shape2DCollection.h index f72f5db05dac198bdb3994d14dc4cf4bfe241b2f..2c97513987d66d8934239d40239efaa99c352f30 100644 --- a/Code/Mantid/MantidPlot/src/Mantid/InstrumentWidget/Shape2DCollection.h +++ b/Code/Mantid/MantidPlot/src/Mantid/InstrumentWidget/Shape2DCollection.h @@ -80,6 +80,7 @@ signals: void shapeSelected(); void shapesDeselected(); void shapeChanged(); + void cleared(); public slots: void addShape(const QString& type,int x,int y,const QColor& borderColor,const QColor& fillColor); diff --git a/Code/Mantid/MantidPlot/src/Mantid/MantidDock.cpp b/Code/Mantid/MantidPlot/src/Mantid/MantidDock.cpp index 0a52878011aa3acb8d3436590beb389af98beb03..7f01a322e0e38cc5984dfb30000d03da04ff07c7 100644 --- a/Code/Mantid/MantidPlot/src/Mantid/MantidDock.cpp +++ b/Code/Mantid/MantidPlot/src/Mantid/MantidDock.cpp @@ -89,15 +89,15 @@ QDockWidget(tr("Workspaces"),parent), m_mantidUI(mui), m_known_groups(), m_rerun m_loadMenu = new QMenu(this); QAction* loadFileAction = new QAction("File",this); - QAction *loadDAEAction = new QAction("from DAE",this); + QAction *liveDataAction = new QAction("Live Data",this); m_loadMapper = new QSignalMapper(this); - m_loadMapper->setMapping(loadDAEAction,"LoadDAE"); + m_loadMapper->setMapping(liveDataAction,"StartLiveData"); m_loadMapper->setMapping(loadFileAction,"Load"); - connect(loadDAEAction,SIGNAL(activated()), m_loadMapper, SLOT(map())); + connect(liveDataAction,SIGNAL(activated()), m_loadMapper, SLOT(map())); connect(loadFileAction,SIGNAL(activated()),m_loadMapper,SLOT(map())); connect(m_loadMapper, SIGNAL(mapped(const QString &)), m_mantidUI, SLOT(executeAlgorithm(const QString&))); m_loadMenu->addAction(loadFileAction); - m_loadMenu->addAction(loadDAEAction); + m_loadMenu->addAction(liveDataAction); m_loadButton->setMenu(m_loadMenu); // SET UP SORT diff --git a/Code/Mantid/MantidPlot/src/qti.sip b/Code/Mantid/MantidPlot/src/qti.sip index a317b00acd1c75b89b644ea257cbdfd18df3fa19..79c181933fbcf9b2ca2cf9fe827b84a917808bb4 100644 --- a/Code/Mantid/MantidPlot/src/qti.sip +++ b/Code/Mantid/MantidPlot/src/qti.sip @@ -1272,25 +1272,306 @@ private: MantidMatrix(const MantidMatrix&); }; +class InstrumentWindowTab: QFrame +{ +%TypeHeaderCode +#include "src/Mantid/InstrumentWidget/InstrumentWindowTab.h" +%End +private: + InstrumentWindowTab(const InstrumentWindowTab &); +}; + class InstrumentWindow: MdiSubWindow { %TypeHeaderCode #include "src/Mantid/InstrumentWidget/InstrumentWindow.h" %End + +%Docstring + +InstrumentWindow +================ + + The InstrumentWindow contains functionality for exploring + a 3D model of an instrument. It is a tabbed widget offering + rendering, picking, masking and grouping functions. There is + also a tree view of the instrument hierarchy. + + For further help see the functions defined on each of the following + - InstrumentWindowRenderTab + - InstrumentWindowPickTab + - InstrumentWindowMaskTab +%End + public: - void changeColormap() /PyName = changeColorMap/; - void changeColormap(const QString & file) /PyName = changeColorMap/; + enum SurfaceType { FULL3D, CYLINDRICAL_X, CYLINDRICAL_Y, CYLINDRICAL_Z, + SPHERICAL_X, SPHERICAL_Y, SPHERICAL_Z, + RENDERMODE_SIZE }; + enum Tab { RENDER, PICK, MASK, TREE }; + + + InstrumentWindowTab * getTab(const QString & title) const; +%Docstring + Returns a handler to the requested tab + + Args: + title The full title of a tab in the window + + Returns: + a pointer to the requested tab widget +%End + + InstrumentWindowTab * getTab(const Tab tab) const; +%Docstring + Returns a handler to the requested tab + + Args: + tab One of the Tab enumeration types: + InstrumentWindow.RENDER,InstrumentWindow.PICK, + InstrumentWindow.MASK,InstrumentWindow.TREE + + Returns: + a pointer to the requested tab widget +%End + + void setBinRange(double min_value, double max_value); +%Docstring + Updates the integration range over which the colours + are calculated + + Args: + min_value The minimum value over which the data is integrated + max_value The maximum value over which the data is integrated +%End + + bool overlay(const QString & wsName); +%Docstring + Overlays a workspace onto an unwrapped surface on the instrument view. + Raises a dialog box if the current surface is not unwrapped. + + Args: + wsName The name of the workspace + + Returns: + A boolean indicating if the overlay was successful or not +%End + + // -- Deprecated in favour of specific tab functions -- + // Deprecation is done in mantidplot.py module rather than using + // sip /Deprecated/annotation so that the message can be customised + void changeColormap(); + void changeColormap(const QString & file); void setColorMapMinValue(double); void setColorMapMaxValue(double); void setColorMapRange(double, double); - void setBinRange(double, double);// /PyName = setBinRange/; void selectComponent(const QString &); void setScaleType(GraphOptions::ScaleType); void setViewType(const QString &); + private: +InstrumentWindow(); InstrumentWindow(const InstrumentWindow &); }; +class InstrumentWindowRenderTab: InstrumentWindowTab +{ +%TypeHeaderCode +#include "src/Mantid/InstrumentWidget/InstrumentWindowRenderTab.h" +%End + +public: + + GraphOptions::ScaleType getScaleType() const; +%Docstring + Returns the current scale type. 0=Linear, 1=Log10 +%End + + void setScaleType(GraphOptions::ScaleType type); +%Docstring + Set the scale type for the colour bar. + + Args: + type The new type Options are: GraphOptions.Linear, GraphOptions.Log10 +%End + + void setAxis(const QString& axisName); +%Docstring + Set the current viewing axis by name. + + Args: + axisName The name of a view in a string: X+,X-,Y+,Y-,Z+,Z- +%End + + void setMinValue(double value, bool apply = true); +%Docstring + Set the minimum value for the colour scale + + Args: + value The new value for the minimum +%End + + void setMaxValue(double value, bool apply = true); +%Docstring + Set the maximum value for the colour scale + + Args: + value The new value for the maximum +%End + + void setRange(double minValue, double maxValue, bool apply = true); +%Docstring + Set the range of the colour bar + + Args: + minValue The new value for the minimum + maxValue The new value for the maximum +%End + + void showAxes(bool on); +%Docstring + Set the axes on/off + + Args: + on True/False indicating whether the axes are visible +%End + + void setColorMapAutoscaling(bool on); +%Docstring + Set whether the colour scale should auto scale when the data is updated + + Args: + on True/False indicating whether auto scaling is active +%End + + void displayDetectorsOnly(bool yes); +%Docstring + Set whether only detectors should be shown. + + Args: + yes True/False indicating whether only detectors are shown +%End + + void enableGL(bool on); +%Docstring + Toggle the use of OpenGL. This can only be used for the unwrapped views. + + Args: + on True/False indicating whether OpenGL should be used. +%End + + void changeColorMap(const QString & filename = ""); +%Docstring + Change the color map for the given one. If blank then a dialog is raised + + Args: + filename A filename giving the full path to a color map file +%End + + void setSurfaceType(int type); +%Docstring + Set the surface type of the current window. + + Args: + type A known suface type: FULL3D, CYLINDRICAL_X, CYLINDRICAL_Y, + CYLINDRICAL_Z,SPHERICAL_X, SPHERICAL_Y, + SPHERICAL_Z +%End + + void flipUnwrappedView(bool on); +%Docstring + Set whether an unwrapped view is flipped + + Args: + on True/False indicatingif to flip the view +%End + + void saveImage(QString filename = ""); +%Docstring + Save the current display buffer to an image file. The format is chosen by the filename extension and must + be one of .bmp,.jpeg,.jpeg,.png,.ppm,.tiff,.xbm,.xpm + + Args: + filename The filename for the saved image. An empty string raises a dialog box. +%End + +private: + InstrumentWindowRenderTab(); + InstrumentWindowRenderTab(const InstrumentWindowRenderTab &); +}; + +class InstrumentWindowPickTab: InstrumentWindowTab +{ +%TypeHeaderCode +#include "src/Mantid/InstrumentWidget/InstrumentWindowPickTab.h" +%End + +public: + enum ToolType {Zoom, PixelSelect, TubeSelect, PeakSelect, PeakErase}; + + void selectTool(const ToolType tool); +%Docstring + Select the active tool. + + Args: + tool One of InstrumentWindowPickTab.{Zoom, PixelSelect, TubeSelect, PeakSelect, PeakErase} +%End + +private: + InstrumentWindowPickTab(); + InstrumentWindowPickTab(const InstrumentWindowPickTab &); +}; + +class InstrumentWindowMaskTab: InstrumentWindowTab +{ +%TypeHeaderCode +#include "src/Mantid/InstrumentWidget/InstrumentWindowMaskTab.h" +%End + +public: + enum Mode {Mask, Group}; + enum Activity {Move,Select,DrawEllipse,DrawRectangle,DrawEllipticalRing,DrawRectangularRing}; + + void setMode(Mode mode); +%Docstring + Set the mode to either group/mask + + Args: + mode One of the Mode enumerations InstrumentWindowMaskTab.{Mask, Group} +%End + + void selectTool(Activity tool); +%Docstring + Set the mode to either group/mask + + Args: + tool One of the Activity enumerations InstrumentWindowMaskTab.{Move,Select,DrawEllipse,DrawRectangle,DrawEllipticalRing,DrawRectangularRing} +%End + +private: + InstrumentWindowMaskTab(); + InstrumentWindowMaskTab(const InstrumentWindowMaskTab &); +}; + +class InstrumentWindowTreeTab: InstrumentWindowTab +{ +%TypeHeaderCode +#include "src/Mantid/InstrumentWidget/InstrumentWindowTreeTab.h" +%End + +public: + void selectComponentByName(const QString& name); +%Docstring + Sets the tree tab to center the view on the named component + + Args: + name The name of a component in the instrument +%End + +private: + InstrumentWindowTreeTab(); + InstrumentWindowTreeTab(const InstrumentWindowTreeTab &); +}; + class MantidUI: QObject { %TypeHeaderCode @@ -1316,7 +1597,7 @@ public: InstrumentWindow* getInstrumentView(const QString &, int tab = -1); %MethodCode sipRes = sipCpp->getInstrumentView(*a0,a1); - sipRes->hide(); + if(sipRes) sipRes->hide(); %End MantidMatrix* importMatrixWorkspace(const QString&,int = -1, int = -1, bool = false, bool = false); Table* createTableFromSpectraList(const QString& tableName, const QString& workspaceName, diff --git a/Code/Mantid/MantidPlot/test/MantidPlotInstrumentViewTest.py b/Code/Mantid/MantidPlot/test/MantidPlotInstrumentViewTest.py new file mode 100644 index 0000000000000000000000000000000000000000..494737cd32d0ce57f76e7535b37edf5030779328 --- /dev/null +++ b/Code/Mantid/MantidPlot/test/MantidPlotInstrumentViewTest.py @@ -0,0 +1,74 @@ +""" +Test the interaction with the instrument view. +Assertion that things work is difficult so mosts +test will just that things don't crash. +""" +import mantidplottests +from mantidplottests import * +import time +import numpy as np +from PyQt4 import QtGui, QtCore + +# ===== Test workspace ====== +X1 = np.linspace(0,10, 100) +Y1 = 1000*(np.sin(X1)**2) + X1*10 +X1 = np.append(X1, 10.1) + +X2 = np.linspace(2,12, 100) +Y2 = 500*(np.cos(X2/2.)**2) + 20 +X2 = np.append(X2, 12.10) + +X = np.append(X1, X2) +Y = np.append(Y1, Y2) +E = np.sqrt(Y) + +CreateWorkspace(OutputWorkspace="loq_inst", DataX=list(X), DataY=list(Y), + DataE=list(E), NSpec=2, UnitX="TOF", YUnitLabel="Counts", + WorkspaceTitle="Faked data Workspace") +LoadInstrument(Workspace="loq_inst", InstrumentName="LOQ") +INST_WIN = getInstrumentView("loq_inst") + +class MantidPlotInstrumentViewTest(unittest.TestCase): + + def test_invalid_tab_title_raises_exception(self): + self.assertRaises(ValueError, INST_WIN.getTab, "wont see this tab") + + def test_get_tab_can_use_title_index_or_enum(self): + render_tab = INST_WIN.getTab("Render") + self.assertTrue(render_tab is not None) + render_tab = INST_WIN.getTab(InstrumentWindow.RENDER) + self.assertTrue(render_tab is not None) + render_tab = INST_WIN.getTab(0) + self.assertTrue(render_tab is not None) + + def test_integration_range_can_be_changed(self): + INST_WIN.setBinRange(5,10) + + def test_scale_type_can_be_changed(self): + render_tab = INST_WIN.getTab("Render") + current_scale = render_tab.getScaleType() + self.assertTrue(isinstance(current_scale, GraphOptions.ScaleType)) + render_tab.setScaleType(GraphOptions.Log10) + + def test_colour_range_can_be_changed(self): + render_tab = INST_WIN.getTab("Render") + render_tab.setMinValue(1.25) + render_tab.setMaxValue(1.75) + render_tab.setRange(1.35,1.85) + + def test_display_options(self): + render_tab = INST_WIN.getTab("Render") + render_tab.showAxes(True) + render_tab.displayDetectorsOnly(True) + render_tab.setColorMapAutoscaling(False) + render_tab.setSurfaceType(0) + render_tab.setAxis("Y-") + render_tab.flipUnwrappedView(True) + + def test_closing_window_invalidates_reference(self): + inst = getInstrumentView("loq_inst") + inst.close() + self.assertTrue(inst._getHeldObject() is None) + +# Run the unit tests +mantidplottests.runTests(MantidPlotInstrumentViewTest) diff --git a/Code/Mantid/MantidQt/API/src/RepoModel.cpp b/Code/Mantid/MantidQt/API/src/RepoModel.cpp index 525e4d6feb9d030ae510773230eb2aa67662a318..00f7917e9e1a60a052b2b55ee2e9622ed8c89262 100644 --- a/Code/Mantid/MantidQt/API/src/RepoModel.cpp +++ b/Code/Mantid/MantidQt/API/src/RepoModel.cpp @@ -366,7 +366,6 @@ bool RepoModel::setData(const QModelIndex & index, const QVariant & value, } QWidget * father = qobject_cast<QWidget*>(QObject::parent()); - if (repo_ptr->fileInfo(path).directory){ QMessageBox::information(father, "Not Supported", diff --git a/Code/Mantid/instrument/Facilities.xml b/Code/Mantid/instrument/Facilities.xml index e5f3fd626c72e116b7805d3f8e67c067918b468e..3125b7b45a30691c6c9ee81a6e7e894b9c0e60ca 100644 --- a/Code/Mantid/instrument/Facilities.xml +++ b/Code/Mantid/instrument/Facilities.xml @@ -9,9 +9,6 @@ <catalog name="ICat3Catalog"> </catalog> - <httpproxy url="http://wwwcache.rl.ac.uk:8080"> - </httpproxy> - <soapEndPoint url="https://facilities01.esc.rl.ac.uk:443/ICATService/ICAT"> </soapEndPoint>