diff --git a/Framework/API/CMakeLists.txt b/Framework/API/CMakeLists.txt index 145eab698ac87c6cea2183ae505b719c9c7e4adf..fc99054b2507868a7143f0ab4e97defffcc23fb8 100644 --- a/Framework/API/CMakeLists.txt +++ b/Framework/API/CMakeLists.txt @@ -100,6 +100,7 @@ set ( SRC_FILES src/MultipleExperimentInfos.cpp src/MultipleFileProperty.cpp src/NearestNeighbourInfo.cpp + src/NearestNeighbours.cpp src/NotebookBuilder.cpp src/NotebookWriter.cpp src/NullCoordTransform.cpp @@ -285,6 +286,7 @@ set ( INC_FILES inc/MantidAPI/MultipleExperimentInfos.h inc/MantidAPI/MultipleFileProperty.h inc/MantidAPI/NearestNeighbourInfo.h + inc/MantidAPI/NearestNeighbours.h inc/MantidAPI/NotebookBuilder.h inc/MantidAPI/NotebookWriter.h inc/MantidAPI/NullCoordTransform.h @@ -399,6 +401,7 @@ set ( TEST_FILES MultipleExperimentInfosTest.h MultipleFilePropertyTest.h NearestNeighbourInfoTest.h + NearestNeighboursTest.h NotebookBuilderTest.h NotebookWriterTest.h NumericAxisTest.h diff --git a/Framework/API/inc/MantidAPI/DetectorInfo.h b/Framework/API/inc/MantidAPI/DetectorInfo.h index 7f2482e92c6042ebadd56824a089eb90fb00dd61..e25b4a23897b093e7672ed0962d1b214351729fb 100644 --- a/Framework/API/inc/MantidAPI/DetectorInfo.h +++ b/Framework/API/inc/MantidAPI/DetectorInfo.h @@ -63,6 +63,8 @@ public: DetectorInfo(boost::shared_ptr<const Geometry::Instrument> instrument, Geometry::ParameterMap *pmap = nullptr); + size_t size() const; + bool isMonitor(const size_t index) const; bool isMasked(const size_t index) const; double l2(const size_t index) const; @@ -71,6 +73,9 @@ public: Kernel::V3D position(const size_t index) const; Kernel::Quat rotation(const size_t index) const; + void setMasked(const size_t index, bool masked); + void clearMaskFlags(); + void setPosition(const size_t index, const Kernel::V3D &position); void setRotation(const size_t index, const Kernel::Quat &rotation); diff --git a/Framework/API/inc/MantidAPI/FunctionDomain1D.h b/Framework/API/inc/MantidAPI/FunctionDomain1D.h index 8db1c56b83cb02be26097677633f0b41dd02521d..b1482e0b667f87ea67dff99034c4478c115283ff 100644 --- a/Framework/API/inc/MantidAPI/FunctionDomain1D.h +++ b/Framework/API/inc/MantidAPI/FunctionDomain1D.h @@ -59,11 +59,15 @@ public: const double *getPointerAt(size_t i) const { return m_data + i; } /// Convert to a vector std::vector<double> toVector() const; + /// Set a peak redius to pass to peak functions. + void setPeakRadius(int radius); + /// Get the peak radius. + int getPeakRadius() const; protected: /// Protected constructor, shouldn't be created directly. Use /// FunctionDomain1DView instead. - FunctionDomain1D(const double *x, size_t n) : m_data(x), m_n(n) {} + FunctionDomain1D(const double *x, size_t n); /// Reset the pointer and size of the domain void resetData(const double *x, size_t n) { m_data = x; @@ -71,8 +75,12 @@ protected: } private: - const double *m_data; ///< pointer to the start of the domain data - size_t m_n; ///< size of the data + /// pointer to the start of the domain data + const double *m_data; + /// size of the data + size_t m_n; + /// A peak radius that IPeakFunctions should use + int m_peakRadius; }; /** diff --git a/Framework/API/inc/MantidAPI/FunctionValues.h b/Framework/API/inc/MantidAPI/FunctionValues.h index 115645a16a40f4694f739504fdf497b25a77bfbe..de5cbba735743be3297cdbff926b3ff9be951b04 100644 --- a/Framework/API/inc/MantidAPI/FunctionValues.h +++ b/Framework/API/inc/MantidAPI/FunctionValues.h @@ -112,11 +112,12 @@ protected: /// buffer /// @param to :: Pointer to the buffer, it must be large enough void multiply(double *to) const; - - std::vector<double> m_calculated; ///< buffer for calculated values - std::vector<double> m_data; ///< buffer for fit data - std::vector<double> - m_weights; ///< buffer for fitting weights (reciprocal errors) + /// buffer for calculated values + std::vector<double> m_calculated; + /// buffer for fit data + std::vector<double> m_data; + /// buffer for fitting weights (reciprocal errors) + std::vector<double> m_weights; }; /// typedef for a shared pointer diff --git a/Framework/API/inc/MantidAPI/IFunction1D.h b/Framework/API/inc/MantidAPI/IFunction1D.h index a84af386955e4be6786aff59123697df2afcc19d..e4fb9302f2543e26a71c4d50fbe8cfecb338b0a8 100644 --- a/Framework/API/inc/MantidAPI/IFunction1D.h +++ b/Framework/API/inc/MantidAPI/IFunction1D.h @@ -62,11 +62,11 @@ public: void function(const FunctionDomain &domain, FunctionValues &values) const override; + void functionDeriv(const FunctionDomain &domain, Jacobian &jacobian) override; + virtual void derivative(const FunctionDomain &domain, FunctionValues &values, const size_t order = 1) const; - void functionDeriv(const FunctionDomain &domain, Jacobian &jacobian) override; - /// Function you want to fit to. virtual void function1D(double *out, const double *xValues, const size_t nData) const = 0; diff --git a/Framework/API/inc/MantidAPI/IPeakFunction.h b/Framework/API/inc/MantidAPI/IPeakFunction.h index c5725c8ce59a44609f1e3f76f6a3d93872a23e2f..3636919b41686ed772c00792659cea37e199d881 100644 --- a/Framework/API/inc/MantidAPI/IPeakFunction.h +++ b/Framework/API/inc/MantidAPI/IPeakFunction.h @@ -39,6 +39,10 @@ class MANTID_API_DLL IPeakFunction : public IFunctionWithLocation { public: /// Constructor IPeakFunction(); + + void function(const FunctionDomain &domain, + FunctionValues &values) const override; + /// Returns the peak FWHM virtual double fwhm() const = 0; @@ -57,8 +61,11 @@ public: /// General implementation of the method for all peaks. void functionDeriv1D(Jacobian *out, const double *xValues, const size_t nData) override; - /// Set new peak radius - static void setPeakRadius(const int &r = 5); + + /// Get the interval on which the peak has all its values above a certain + /// level + virtual std::pair<double, double> + getDomainInterval(double level = DEFAULT_SEARCH_LEVEL) const; /// Function evaluation method to be implemented in the inherited classes virtual void functionLocal(double *out, const double *xValues, @@ -83,10 +90,14 @@ public: "Generic intensity fixing isn't implemented for this function."); } -protected: +private: + /// Set new peak radius + void setPeakRadius(int r) const; /// Defines the area around the centre where the peak values are to be /// calculated (in FWHM). - static int s_peakRadius; + mutable int m_peakRadius; + /// The default level for searching a domain interval (getDomainInterval()) + static constexpr double DEFAULT_SEARCH_LEVEL = 1e-5; }; typedef boost::shared_ptr<IPeakFunction> IPeakFunction_sptr; diff --git a/Framework/API/inc/MantidAPI/MatrixWorkspace.h b/Framework/API/inc/MantidAPI/MatrixWorkspace.h index 7a21ee3440626068b9d32f7371257140c3334e2d..06569527eb9d8fb7a498387671103e479e603c93 100644 --- a/Framework/API/inc/MantidAPI/MatrixWorkspace.h +++ b/Framework/API/inc/MantidAPI/MatrixWorkspace.h @@ -424,9 +424,6 @@ public: bool isDistribution() const; void setDistribution(bool newValue); - /// Mask a given workspace index, setting the data and error values to zero - void maskWorkspaceIndex(const std::size_t index); - // Methods to set and access masked bins void maskBin(const size_t &workspaceIndex, const size_t &binIndex, const double &weight = 1.0); diff --git a/Framework/API/inc/MantidAPI/NearestNeighbourInfo.h b/Framework/API/inc/MantidAPI/NearestNeighbourInfo.h index b184b9e7fff58d67b493084c8d4f3d9ab2ba2e0c..894c8c43e130d3a1b806f36936245fb558966757 100644 --- a/Framework/API/inc/MantidAPI/NearestNeighbourInfo.h +++ b/Framework/API/inc/MantidAPI/NearestNeighbourInfo.h @@ -2,12 +2,20 @@ #define MANTID_API_NEARESTNEIGHBOURINFO_H_ #include "MantidAPI/DllConfig.h" -#include "MantidGeometry/Instrument/NearestNeighbours.h" +#include "MantidGeometry/IDTypes.h" +#include "MantidKernel/V3D.h" + +#include <memory> +#include <map> namespace Mantid { +namespace Geometry { +class IDetector; +} namespace API { class MatrixWorkspace; +class NearestNeighbours; /** NearestNeighbourInfo provides easy access to nearest-neighbour information for a workspace. @@ -38,6 +46,7 @@ public: NearestNeighbourInfo(const MatrixWorkspace &workspace, const bool ignoreMaskedDetectors, const int nNeighbours = 8); + ~NearestNeighbourInfo(); std::map<specnum_t, Kernel::V3D> getNeighbours(const Geometry::IDetector *comp, @@ -48,7 +57,7 @@ public: private: const MatrixWorkspace &m_workspace; - Geometry::NearestNeighbours m_nearestNeighbours; + std::unique_ptr<NearestNeighbours> m_nearestNeighbours; }; } // namespace API diff --git a/Framework/Geometry/inc/MantidGeometry/Instrument/NearestNeighbours.h b/Framework/API/inc/MantidAPI/NearestNeighbours.h similarity index 74% rename from Framework/Geometry/inc/MantidGeometry/Instrument/NearestNeighbours.h rename to Framework/API/inc/MantidAPI/NearestNeighbours.h index 3527a025c4da602a638d75c605b427878eca720a..cbe5525b5624ae76218e498894b212283735bacf 100644 --- a/Framework/Geometry/inc/MantidGeometry/Instrument/NearestNeighbours.h +++ b/Framework/API/inc/MantidAPI/NearestNeighbours.h @@ -1,7 +1,7 @@ #ifndef MANTID_GEOMETRY_INSTRUMENT_NEARESTNEIGHBOURS #define MANTID_GEOMETRY_INSTRUMENT_NEARESTNEIGHBOURS -#include "MantidGeometry/DllConfig.h" +#include "MantidAPI/DllConfig.h" #include "MantidGeometry/IDTypes.h" #include "MantidKernel/V3D.h" // Boost graphing @@ -13,14 +13,14 @@ namespace Mantid { namespace Geometry { - class Instrument; class IDetector; - -typedef std::unordered_map<specnum_t, std::set<detid_t>> - ISpectrumDetectorMapping; - +} +namespace API { +class SpectrumInfo; /** + * This class is not intended for direct use. Use NearestNeighbourInfo instead! + * * This class is used to find the nearest neighbours of a detector in the * instrument geometry. This class can be queried through calls to the * getNeighbours() function on a Detector object. @@ -58,17 +58,10 @@ typedef std::unordered_map<specnum_t, std::set<detid_t>> * File change history is stored at: <https://github.com/mantidproject/mantid> * Code Documentation is available at: <http://doxygen.mantidproject.org> */ -class MANTID_GEOMETRY_DLL NearestNeighbours { +class MANTID_API_DLL NearestNeighbours { public: - /// Constructor with an instrument and a spectra map - NearestNeighbours(boost::shared_ptr<const Instrument> instrument, - const ISpectrumDetectorMapping &spectraMap, - bool ignoreMaskedDetectors = false); - - /// Constructor with an instrument and a spectra map and number of neighbours - NearestNeighbours(int nNeighbours, - boost::shared_ptr<const Instrument> instrument, - const ISpectrumDetectorMapping &spectraMap, + NearestNeighbours(int nNeighbours, const SpectrumInfo &spectrumInfo, + std::vector<specnum_t> spectrumNumbers, bool ignoreMaskedDetectors = false); // Neighbouring spectra by radius @@ -79,17 +72,14 @@ public: std::map<specnum_t, Mantid::Kernel::V3D> neighbours(specnum_t spectrum) const; protected: - /// Get the spectra associated with all in the instrument - std::map<specnum_t, boost::shared_ptr<const IDetector>> - getSpectraDetectors(boost::shared_ptr<const Instrument> instrument, - const ISpectrumDetectorMapping &spectraMap); - - /// A pointer the the instrument - boost::shared_ptr<const Instrument> m_instrument; - /// A reference to the spectra map - const ISpectrumDetectorMapping &m_spectraMap; + std::vector<size_t> getSpectraDetectors(); private: + /// A reference to the SpectrumInfo + const SpectrumInfo &m_spectrumInfo; + /// Vector of spectrum numbers + const std::vector<specnum_t> m_spectrumNumbers; + /// typedef for Graph object used to hold the calculated information typedef boost::adjacency_list< boost::vecS, boost::vecS, boost::directedS, @@ -127,14 +117,7 @@ private: bool m_bIgnoreMaskedDetectors; }; -/// Typedef for shared pointer to the NearestNeighbours class -typedef boost::shared_ptr<Mantid::Geometry::NearestNeighbours> - NearestNeighbours_sptr; -/// Typedef for constant shared pointer to the NearestNeighbours class -typedef boost::shared_ptr<const Mantid::Geometry::NearestNeighbours> - NearestNeighbours_const_sptr; - -} // namespace Geometry +} // namespace API } // namespace Mantid #endif diff --git a/Framework/API/inc/MantidAPI/PrecompiledHeader.h b/Framework/API/inc/MantidAPI/PrecompiledHeader.h index fa64968355765c1e9b938ac562bed81e326ccdc9..4869d894bee622cffb880d4809900bf0d5a8e614 100644 --- a/Framework/API/inc/MantidAPI/PrecompiledHeader.h +++ b/Framework/API/inc/MantidAPI/PrecompiledHeader.h @@ -14,7 +14,6 @@ #include "MantidGeometry/IComponent.h" #include "MantidGeometry/IDetector.h" #include "MantidGeometry/Instrument.h" -#include "MantidGeometry/Instrument/NearestNeighbours.h" // STL #include <vector> diff --git a/Framework/API/inc/MantidAPI/SpectrumInfo.h b/Framework/API/inc/MantidAPI/SpectrumInfo.h index aed89ecc1015d66abad4250982c34e0301b14669..f6e24356c95a6ffb08e90da269f7d8eaa56367e1 100644 --- a/Framework/API/inc/MantidAPI/SpectrumInfo.h +++ b/Framework/API/inc/MantidAPI/SpectrumInfo.h @@ -72,6 +72,8 @@ public: bool hasDetectors(const size_t index) const; bool hasUniqueDetector(const size_t index) const; + void setMasked(const size_t index, bool masked); + // This is likely to be deprecated/removed with the introduction of // Instrument-2.0: The concept of detector groups will probably be dropped so // returning a single detector for a spectrum will not be possible anymore. diff --git a/Framework/API/src/ADSValidator.cpp b/Framework/API/src/ADSValidator.cpp index f65fa6980997e00d5629aaed92cadaea44bdbe8a..ad8f0d8f8d0bea0bfa6f8e061a0d44031fa06cf0 100644 --- a/Framework/API/src/ADSValidator.cpp +++ b/Framework/API/src/ADSValidator.cpp @@ -3,6 +3,7 @@ #include "MantidKernel/StringTokenizer.h" #include "MantidAPI/AnalysisDataService.h" #include <boost/make_shared.hpp> +#include <sstream> namespace Mantid { namespace API { diff --git a/Framework/API/src/AnalysisDataService.cpp b/Framework/API/src/AnalysisDataService.cpp index d88362663d687c9f0c9dceb79e8d59498760b0d5..61350e192a94f657a9fb15f9b0ffab6fed0e255d 100644 --- a/Framework/API/src/AnalysisDataService.cpp +++ b/Framework/API/src/AnalysisDataService.cpp @@ -1,5 +1,6 @@ #include "MantidAPI/AnalysisDataService.h" #include "MantidAPI/WorkspaceGroup.h" +#include <sstream> namespace Mantid { namespace API { diff --git a/Framework/API/src/DataProcessorAlgorithm.cpp b/Framework/API/src/DataProcessorAlgorithm.cpp index aaafb7ead939b200a967eae837dd21243e37bd47..67389704fb71804c8784f36883a7c8c13de1008b 100644 --- a/Framework/API/src/DataProcessorAlgorithm.cpp +++ b/Framework/API/src/DataProcessorAlgorithm.cpp @@ -236,8 +236,8 @@ Workspace_sptr DataProcessorAlgorithm::assemble(Workspace_sptr partialWS) { Workspace_sptr DataProcessorAlgorithm::assemble(const std::string &partialWSName, const std::string &outputWSName) { - std::string threadOutput = partialWSName; #ifdef MPI_BUILD + std::string threadOutput = partialWSName; Workspace_sptr partialWS = AnalysisDataService::Instance().retrieve(partialWSName); IAlgorithm_sptr gatherAlg = createChildAlgorithm("GatherWorkspaces"); @@ -252,6 +252,8 @@ DataProcessorAlgorithm::assemble(const std::string &partialWSName, threadOutput = outputWSName; #else UNUSED_ARG(outputWSName) + const std::string &threadOutput = partialWSName; + #endif Workspace_sptr outputWS = AnalysisDataService::Instance().retrieve(threadOutput); diff --git a/Framework/API/src/DetectorInfo.cpp b/Framework/API/src/DetectorInfo.cpp index 90a4ea42ac6bf384ae97a471187d81d0a5fc67ee..8e43e78acd058783073fa0c9ae62f095344dceab 100644 --- a/Framework/API/src/DetectorInfo.cpp +++ b/Framework/API/src/DetectorInfo.cpp @@ -32,6 +32,10 @@ DetectorInfo::DetectorInfo( m_detIDToIndex[m_detectorIDs[i]] = i; } +/// Returns the size of the DetectorInfo, i.e., the number of detectors in the +/// instrument. +size_t DetectorInfo::size() const { return m_detectorIDs.size(); } + /// Returns true if the detector is a monitor. bool DetectorInfo::isMonitor(const size_t index) const { return getDetector(index).isMonitor(); @@ -93,6 +97,17 @@ Kernel::Quat DetectorInfo::rotation(const size_t index) const { return getDetector(index).getRotation(); } +/// Set the mask flag of the detector with given index. +void DetectorInfo::setMasked(const size_t index, bool masked) { + m_pmap->addBool(&getDetector(index), "masked", masked); +} + +/** Sets all mask flags to false (unmasked). + * + * This method was introduced to help with refactoring and may be removed in the + *future. */ +void DetectorInfo::clearMaskFlags() { m_pmap->clearParametersByName("masked"); } + /// Set the absolute position of the detector with given index. void DetectorInfo::setPosition(const size_t index, const Kernel::V3D &position) { diff --git a/Framework/API/src/FileFinder.cpp b/Framework/API/src/FileFinder.cpp index a9b808e4915382c2a9bb94d01aab57f77112157d..5e6f1f8d668f249a9344a670f41ae0163bb87779 100644 --- a/Framework/API/src/FileFinder.cpp +++ b/Framework/API/src/FileFinder.cpp @@ -134,9 +134,8 @@ std::string FileFinderImpl::getFullPath(const std::string &filename, if (fName.find("*") != std::string::npos) { #endif Poco::Path path(searchPath, fName); - Poco::Path pathPattern(path); std::set<std::string> files; - Kernel::Glob::glob(pathPattern, files, m_globOption); + Kernel::Glob::glob(path, files, m_globOption); if (!files.empty()) { Poco::File matchPath(*files.begin()); if (ignoreDirs && matchPath.isDirectory()) { diff --git a/Framework/API/src/FunctionDomain1D.cpp b/Framework/API/src/FunctionDomain1D.cpp index 36c1871078133f84248007f8106e62fdf35ca0d1..68ea72ce43fd83c81b9ed2e38aea68e41d6c717f 100644 --- a/Framework/API/src/FunctionDomain1D.cpp +++ b/Framework/API/src/FunctionDomain1D.cpp @@ -6,6 +6,10 @@ namespace Mantid { namespace API { +/// The constructor +FunctionDomain1D::FunctionDomain1D(const double *x, size_t n) + : m_data(x), m_n(n), m_peakRadius(0) {} + /// Convert to a vector std::vector<double> FunctionDomain1D::toVector() const { std::vector<double> res; @@ -15,6 +19,17 @@ std::vector<double> FunctionDomain1D::toVector() const { return res; } +/** + * Set a peak redius to pass to peak functions. + * @param radius :: New radius value. + */ +void FunctionDomain1D::setPeakRadius(int radius) { m_peakRadius = radius; } + +/** + * Get the peak radius. + */ +int FunctionDomain1D::getPeakRadius() const { return m_peakRadius; } + /** * Create a domain from a vector. * @param xvalues :: Vector with function arguments to be copied from. diff --git a/Framework/API/src/IFunction.cpp b/Framework/API/src/IFunction.cpp index 119b7c04cc74762665b0e1e48f72675ae030e7d3..0496959f6c96281b51815d6e2325e3d750455cf5 100644 --- a/Framework/API/src/IFunction.cpp +++ b/Framework/API/src/IFunction.cpp @@ -138,6 +138,7 @@ void IFunction::addTies(const std::string &ties, bool isDefault) { } } } + applyTies(); } /** Removes the tie off a parameter. The parameter becomes active diff --git a/Framework/API/src/IPeakFunction.cpp b/Framework/API/src/IPeakFunction.cpp index 63d4f9b66ce2fd173c72825e0d2ea1627330946e..99541fecf29ceac2357ea28ad76a78bb78057ae3 100644 --- a/Framework/API/src/IPeakFunction.cpp +++ b/Framework/API/src/IPeakFunction.cpp @@ -7,15 +7,17 @@ #include "MantidAPI/PeakFunctionIntegrator.h" #include "MantidAPI/FunctionParameterDecorator.h" #include "MantidKernel/Exception.h" -#include "MantidKernel/ConfigService.h" #include <boost/lexical_cast.hpp> #include <boost/make_shared.hpp> #include <cmath> +#include <limits> namespace Mantid { namespace API { +namespace { + /** A Jacobian for individual functions */ class PartialJacobian1 : public Jacobian { @@ -78,21 +80,24 @@ protected: std::vector<double> m_J; }; -/// Default value for the peak radius -int IPeakFunction::s_peakRadius = 5; +/// Tolerance for determining the smallest significant value on the peak +const double PEAK_TOLERANCE = 1e-14; +/// "Infinite" value for the peak radius +const int MAX_PEAK_RADIUS = std::numeric_limits<int>::max(); + +} // namespace /** - * Constructor. Sets peak radius to the value of curvefitting.peakRadius - * property + * Constructor. */ -IPeakFunction::IPeakFunction() { - int peakRadius; - if (Kernel::ConfigService::Instance().getValue("curvefitting.peakRadius", - peakRadius)) { - if (peakRadius != s_peakRadius) { - setPeakRadius(peakRadius); - } - } +IPeakFunction::IPeakFunction() : m_peakRadius(MAX_PEAK_RADIUS) {} + +void IPeakFunction::function(const FunctionDomain &domain, + FunctionValues &values) const { + auto peakRadius = + dynamic_cast<const FunctionDomain1D &>(domain).getPeakRadius(); + setPeakRadius(peakRadius); + IFunction1D::function(domain, values); } /** @@ -108,7 +113,7 @@ IPeakFunction::IPeakFunction() { void IPeakFunction::function1D(double *out, const double *xValues, const size_t nData) const { double c = this->centre(); - double dx = fabs(s_peakRadius * this->fwhm()); + double dx = fabs(m_peakRadius * this->fwhm()); int i0 = -1; int n = 0; for (size_t i = 0; i < nData; ++i) { @@ -139,7 +144,7 @@ void IPeakFunction::function1D(double *out, const double *xValues, void IPeakFunction::functionDeriv1D(Jacobian *out, const double *xValues, const size_t nData) { double c = this->centre(); - double dx = fabs(s_peakRadius * this->fwhm()); + double dx = fabs(m_peakRadius * this->fwhm()); int i0 = -1; int n = 0; for (size_t i = 0; i < nData; ++i) { @@ -159,23 +164,22 @@ void IPeakFunction::functionDeriv1D(Jacobian *out, const double *xValues, this->functionDerivLocal(&J, xValues + i0, n); } -void IPeakFunction::setPeakRadius(const int &r) { +void IPeakFunction::setPeakRadius(int r) const { if (r > 0) { - s_peakRadius = r; - std::string setting = std::to_string(r); - Kernel::ConfigService::Instance().setString("curvefitting.peakRadius", - setting); + m_peakRadius = r; + } else if (r == 0) { + m_peakRadius = MAX_PEAK_RADIUS; } } /// Returns the integral intensity of the peak function, using the peak radius /// to determine integration borders. double IPeakFunction::intensity() const { - double x0 = centre(); - double dx = fabs(s_peakRadius * fwhm()); + auto interval = getDomainInterval(); PeakFunctionIntegrator integrator; - IntegrationResult result = integrator.integrate(*this, x0 - dx, x0 + dx); + IntegrationResult result = + integrator.integrate(*this, interval.first, interval.second); if (!result.success) { return 0.0; @@ -226,5 +230,40 @@ std::string IPeakFunction::getCentreParameterName() const { return parameterName(jacobian.maxParam(0)); } +/// Get the interval on which the peak has all its values above a certain +/// level. All values outside the interval are below that level. +/// @param level :: A fraction of the peak height. +/// @return A pair of doubles giving the bounds of the interval. +std::pair<double, double> IPeakFunction::getDomainInterval(double level) const { + if (level < PEAK_TOLERANCE) { + level = PEAK_TOLERANCE; + } + double left = 0.0; + double right = 0.0; + auto h = height(); + auto w = fwhm(); + auto c = centre(); + if (h == 0.0 || w == 0.0 || level >= 1.0) { + return std::make_pair(c, c); + } + + auto findBound = [this, c, h, level](double dx) { + for (size_t i = 0; i < 100; ++i) { + double x = c + dx; + double y = 0.0; + this->functionLocal(&y, &x, 1); + if (fabs(y / h) < level) { + return x; + } + dx *= 2; + } + return c + dx; + }; + + left = findBound(-w); + right = findBound(w); + return std::make_pair(left, right); +} + } // namespace API } // namespace Mantid diff --git a/Framework/API/src/ImplicitFunctionParserFactory.cpp b/Framework/API/src/ImplicitFunctionParserFactory.cpp index 9a13f894941560ad6e748903857b93a2fa91e4ef..14e1ab5afd4977a6c9b397a19295fa1e9c31d3aa 100644 --- a/Framework/API/src/ImplicitFunctionParserFactory.cpp +++ b/Framework/API/src/ImplicitFunctionParserFactory.cpp @@ -18,7 +18,7 @@ ImplicitFunctionParserFactoryImpl::create(const std::string &xmlString) const { ImplicitFunctionParser * ImplicitFunctionParserFactoryImpl::createImplicitFunctionParserFromXML( Poco::XML::Element *functionElement) const { - std::string name = functionElement->localName(); + const std::string &name = functionElement->localName(); if (name != "Function") { throw std::runtime_error( "Root node must be a Funtion element. Unable to determine parsers."); diff --git a/Framework/API/src/MatrixWorkspace.cpp b/Framework/API/src/MatrixWorkspace.cpp index 47464de1d8e15cada60073a780d6b127d2fdbc6a..70b3c253737a003a857cfb72bad867a8f0efe049 100644 --- a/Framework/API/src/MatrixWorkspace.cpp +++ b/Framework/API/src/MatrixWorkspace.cpp @@ -896,35 +896,6 @@ bool MatrixWorkspace::isCommonBins() const { return m_isCommonBinsFlag; } -/** -* Mask a given workspace index, setting the data and error values to zero -* @param index :: The index within the workspace to mask -*/ -void MatrixWorkspace::maskWorkspaceIndex(const std::size_t index) { - if (index >= this->getNumberHistograms()) { - throw Kernel::Exception::IndexError( - index, this->getNumberHistograms(), - "MatrixWorkspace::maskWorkspaceIndex,index"); - } - - auto &spec = this->getSpectrum(index); - - // Virtual method clears the spectrum as appropriate - spec.clearData(); - - const auto dets = spec.getDetectorIDs(); - for (auto detId : dets) { - try { - if (const Geometry::Detector *det = - dynamic_cast<const Geometry::Detector *>( - sptr_instrument->getDetector(detId).get())) { - m_parmap->addBool(det, "masked", true); // Thread-safe method - } - } catch (Kernel::Exception::NotFoundError &) { - } - } -} - /** Called by the algorithm MaskBins to mask a single bin for the first time, * algorithms that later propagate the * the mask from an input to the output should call flagMasked() instead. Here diff --git a/Framework/API/src/NearestNeighbourInfo.cpp b/Framework/API/src/NearestNeighbourInfo.cpp index ab6832c24f4ba4ab8ff38daeff670c549119939c..7612bddd1e6a909f9af5e9dfe101c98d240b3f6a 100644 --- a/Framework/API/src/NearestNeighbourInfo.cpp +++ b/Framework/API/src/NearestNeighbourInfo.cpp @@ -1,6 +1,7 @@ #include "MantidAPI/NearestNeighbourInfo.h" +#include "MantidAPI/NearestNeighbours.h" #include "MantidAPI/MatrixWorkspace.h" -#include "MantidAPI/SpectrumDetectorMapping.h" +#include "MantidKernel/make_unique.h" namespace Mantid { namespace API { @@ -15,10 +16,18 @@ namespace API { NearestNeighbourInfo::NearestNeighbourInfo(const MatrixWorkspace &workspace, const bool ignoreMaskedDetectors, const int nNeighbours) - : m_workspace(workspace), - m_nearestNeighbours(nNeighbours, workspace.getInstrument(), - SpectrumDetectorMapping(&workspace).getMapping(), - ignoreMaskedDetectors) {} + : m_workspace(workspace) { + std::vector<specnum_t> spectrumNumbers; + for (size_t i = 0; i < m_workspace.getNumberHistograms(); ++i) + spectrumNumbers.push_back(m_workspace.getSpectrum(i).getSpectrumNo()); + + m_nearestNeighbours = Kernel::make_unique<NearestNeighbours>( + nNeighbours, workspace.spectrumInfo(), std::move(spectrumNumbers), + ignoreMaskedDetectors); +} + +// Defined as default in source for forward declaration with std::unique_ptr. +NearestNeighbourInfo::~NearestNeighbourInfo() = default; /** Queries the NearestNeighbours object for the selected detector. * NOTE! getNeighbours(spectrumNumber, radius) is MUCH faster. @@ -39,7 +48,7 @@ NearestNeighbourInfo::getNeighbours(const Geometry::IDetector *comp, "detector", comp->getID()); } - return m_nearestNeighbours.neighboursInRadius(spectra[0], radius); + return m_nearestNeighbours->neighboursInRadius(spectra[0], radius); } /** Queries the NearestNeighbours object for the selected spectrum number. @@ -50,7 +59,7 @@ NearestNeighbourInfo::getNeighbours(const Geometry::IDetector *comp, */ std::map<specnum_t, Kernel::V3D> NearestNeighbourInfo::getNeighbours(specnum_t spec, const double radius) const { - return m_nearestNeighbours.neighboursInRadius(spec, radius); + return m_nearestNeighbours->neighboursInRadius(spec, radius); } /** Queries the NearestNeighbours object for the selected spectrum number. @@ -60,7 +69,7 @@ NearestNeighbourInfo::getNeighbours(specnum_t spec, const double radius) const { */ std::map<specnum_t, Kernel::V3D> NearestNeighbourInfo::getNeighboursExact(specnum_t spec) const { - return m_nearestNeighbours.neighbours(spec); + return m_nearestNeighbours->neighbours(spec); } } // namespace API diff --git a/Framework/Geometry/src/Instrument/NearestNeighbours.cpp b/Framework/API/src/NearestNeighbours.cpp similarity index 71% rename from Framework/Geometry/src/Instrument/NearestNeighbours.cpp rename to Framework/API/src/NearestNeighbours.cpp index 5fdff4da49128e36da1778d299b4db7d53f128f9..9f094269ade399b5944cac26ba3f19f0ada12663 100644 --- a/Framework/Geometry/src/Instrument/NearestNeighbours.cpp +++ b/Framework/API/src/NearestNeighbours.cpp @@ -1,4 +1,5 @@ -#include "MantidGeometry/Instrument/NearestNeighbours.h" +#include "MantidAPI/NearestNeighbours.h" +#include "MantidAPI/SpectrumInfo.h" #include "MantidGeometry/Instrument.h" #include "MantidGeometry/Instrument/DetectorGroup.h" #include "MantidGeometry/Objects/BoundingBox.h" @@ -8,38 +9,27 @@ #include "MantidKernel/Timer.h" namespace Mantid { -namespace Geometry { +using namespace Geometry; +namespace API { using Mantid::detid_t; using Kernel::V3D; -/** -*Constructor -*@param instrument :: A shared pointer to Instrument object -*@param spectraMap :: A reference to the spectra-detector mapping -*@param ignoreMaskedDetectors :: flag indicating that masked detectors should be -* ignored. -*/ -NearestNeighbours::NearestNeighbours( - boost::shared_ptr<const Instrument> instrument, - const ISpectrumDetectorMapping &spectraMap, bool ignoreMaskedDetectors) - : m_instrument(instrument), m_spectraMap(spectraMap), m_noNeighbours(8), - m_cutoff(-DBL_MAX), m_radius(0), - m_bIgnoreMaskedDetectors(ignoreMaskedDetectors) { - this->build(m_noNeighbours); -} - /** * Constructor * @param nNeighbours :: Number of neighbours to use - * @param instrument :: A shared pointer to Instrument object - * @param spectraMap :: A reference to the spectra-detector mapping + * @param spectrumInfo :: Reference to the SpectrumInfo of the underlying + * workspace + * @param spectrumNumbers :: Vector of spectrum numbers, defining the ordering + * of spectra * @param ignoreMaskedDetectors :: flag indicating that masked detectors should * be ignored. */ -NearestNeighbours::NearestNeighbours( - int nNeighbours, boost::shared_ptr<const Instrument> instrument, - const ISpectrumDetectorMapping &spectraMap, bool ignoreMaskedDetectors) - : m_instrument(instrument), m_spectraMap(spectraMap), +NearestNeighbours::NearestNeighbours(int nNeighbours, + const SpectrumInfo &spectrumInfo, + std::vector<specnum_t> spectrumNumbers, + bool ignoreMaskedDetectors) + : m_spectrumInfo(spectrumInfo), + m_spectrumNumbers(std::move(spectrumNumbers)), m_noNeighbours(nNeighbours), m_cutoff(-DBL_MAX), m_radius(0), m_bIgnoreMaskedDetectors(ignoreMaskedDetectors) { this->build(m_noNeighbours); @@ -120,14 +110,13 @@ NearestNeighbours::neighboursInRadius(const specnum_t spectrum, * the graph */ void NearestNeighbours::build(const int noNeighbours) { - std::map<specnum_t, IDetector_const_sptr> spectraDets = - getSpectraDetectors(m_instrument, m_spectraMap); - if (spectraDets.empty()) { + const auto indices = getSpectraDetectors(); + if (indices.empty()) { throw std::runtime_error( "NearestNeighbours::build - Cannot find any spectra"); } const int nspectra = - static_cast<int>(spectraDets.size()); // ANN only deals with integers + static_cast<int>(indices.size()); // ANN only deals with integers if (noNeighbours >= nspectra) { throw std::invalid_argument( "NearestNeighbours::build - Invalid number of neighbours"); @@ -141,18 +130,16 @@ void NearestNeighbours::build(const int noNeighbours) { BoundingBox bbox; // Base the scaling on the first detector, should be adequate but we can look // at this - IDetector_const_sptr firstDet = (*spectraDets.begin()).second; - firstDet->getBoundingBox(bbox); + const auto &firstDet = m_spectrumInfo.detector(indices.front()); + firstDet.getBoundingBox(bbox); m_scale = V3D(bbox.width()); ANNpointArray dataPoints = annAllocPts(nspectra, 3); MapIV pointNoToVertex; - std::map<specnum_t, IDetector_const_sptr>::const_iterator detIt; int pointNo = 0; - for (detIt = spectraDets.begin(); detIt != spectraDets.end(); ++detIt) { - IDetector_const_sptr detector = detIt->second; - const specnum_t spectrum = detIt->first; - V3D pos = detector->getPos() / m_scale; + for (const auto i : indices) { + const specnum_t spectrum = m_spectrumNumbers[i]; + V3D pos = m_spectrumInfo.position(i) / m_scale; dataPoints[pointNo][0] = pos.X(); dataPoints[pointNo][1] = pos.Y(); dataPoints[pointNo][2] = pos.Z(); @@ -168,7 +155,7 @@ void NearestNeighbours::build(const int noNeighbours) { auto nnIndexList = new ANNidx[m_noNeighbours]; auto nnDistList = new ANNdist[m_noNeighbours]; - for (detIt = spectraDets.begin(); detIt != spectraDets.end(); ++detIt) { + for (const auto idx : indices) { ANNpoint scaledPos = dataPoints[pointNo]; annTree->annkSearch(scaledPos, // Point to search nearest neighbours of m_noNeighbours, // Number of neighbours to find (8) @@ -186,8 +173,8 @@ void NearestNeighbours::build(const int noNeighbours) { m_scale; V3D distance = neighbour - realPos; double separation = distance.norm(); - boost::add_edge(m_specToVertex[detIt->first], // from - pointNoToVertex[index], // to + boost::add_edge(m_specToVertex[m_spectrumNumbers[idx]], // from + pointNoToVertex[index], // to distance, m_graph); if (separation > m_cutoff) { m_cutoff = separation; @@ -236,30 +223,17 @@ NearestNeighbours::defaultNeighbours(const specnum_t spectrum) const { } } -/** - * Get the list of detectors associated with a spectra - * @param instrument :: A pointer to the instrument - * @param spectraMap :: A reference to the spectra map - * @returns A map of spectra number to detector pointer - */ -std::map<specnum_t, IDetector_const_sptr> -NearestNeighbours::getSpectraDetectors( - boost::shared_ptr<const Instrument> instrument, - const ISpectrumDetectorMapping &spectraMap) { - std::map<specnum_t, IDetector_const_sptr> spectra; - if (spectraMap.empty()) - return spectra; - auto cend = spectraMap.cend(); - for (auto citr = spectraMap.cbegin(); citr != cend; ++citr) { - const std::vector<detid_t> detIDs(citr->second.begin(), citr->second.end()); - IDetector_const_sptr det = instrument->getDetectorG(detIDs); +/// Returns the list of valid spectrum indices +std::vector<size_t> NearestNeighbours::getSpectraDetectors() { + std::vector<size_t> indices; + for (size_t i = 0; i < m_spectrumNumbers.size(); ++i) { // Always ignore monitors and ignore masked detectors if requested. - bool heedMasking = m_bIgnoreMaskedDetectors && det->isMasked(); - if (!det->isMonitor() && !heedMasking) { - spectra.emplace(citr->first, det); + bool heedMasking = m_bIgnoreMaskedDetectors && m_spectrumInfo.isMasked(i); + if (!m_spectrumInfo.isMonitor(i) && !heedMasking) { + indices.push_back(i); } } - return spectra; + return indices; } } } diff --git a/Framework/API/src/Progress.cpp b/Framework/API/src/Progress.cpp index 9e6964bced0cd05c97282e08a3cd7031b27ee9bf..03a976199c1686b9aa22fb051b60d3692805f396 100644 --- a/Framework/API/src/Progress.cpp +++ b/Framework/API/src/Progress.cpp @@ -53,8 +53,8 @@ void Progress::doReport(const std::string &msg) { p = m_end; if (!m_alg) return; - - m_alg->progress(p, msg, this->getEstimatedTime(), + // progress must be between 0 and 1 + m_alg->progress(p / (m_end - m_start), msg, this->getEstimatedTime(), this->m_notifyStepPrecision); m_alg->interruption_point(); } diff --git a/Framework/API/src/Run.cpp b/Framework/API/src/Run.cpp index edf9dedfd7a3a25c7d7707aa4747916d037333e0..cba9f55cf7458af81edb42dcd4855b30ad00e715 100644 --- a/Framework/API/src/Run.cpp +++ b/Framework/API/src/Run.cpp @@ -197,7 +197,7 @@ void Run::integrateProtonCharge(const std::string &logname) const { if (log) { const std::vector<double> logValues = log->valuesAsVector(); double total = std::accumulate(logValues.begin(), logValues.end(), 0.0); - std::string unit = log->units(); + const std::string &unit = log->units(); // Do we need to take account of a unit if (unit.find("picoCoulomb") != std::string::npos) { /// Conversion factor between picoColumbs and microAmp*hours diff --git a/Framework/API/src/SpectrumInfo.cpp b/Framework/API/src/SpectrumInfo.cpp index d6cf7474fe4646a3414d5344d2a2cbe8975648c7..364021f9a925bec0e43b50f7fd98dca5a5efdf6e 100644 --- a/Framework/API/src/SpectrumInfo.cpp +++ b/Framework/API/src/SpectrumInfo.cpp @@ -132,6 +132,17 @@ bool SpectrumInfo::hasUniqueDetector(const size_t index) const { return count == 1; } +/** Set the mask flag of the spectrum with given index. + * + * Currently this simply sets the mask flags for the underlying detectors. */ +void SpectrumInfo::setMasked(const size_t index, bool masked) { + for (const auto &det : getDetectorVector(index)) { + const auto detIndex = m_detectorInfo.indexOf(det->getID()); + m_detectorInfo.setCachedDetector(detIndex, det); + m_mutableDetectorInfo->setMasked(detIndex, masked); + } +} + /// Return a const reference to the detector or detector group of the spectrum /// with given index. const Geometry::IDetector &SpectrumInfo::detector(const size_t index) const { diff --git a/Framework/API/test/DetectorInfoTest.h b/Framework/API/test/DetectorInfoTest.h index acdf52c7b2b7815027b7d1221cb6e080fc7b2925..3db5b7b73385689fdf3c02fe776c05f42acece22 100644 --- a/Framework/API/test/DetectorInfoTest.h +++ b/Framework/API/test/DetectorInfoTest.h @@ -44,6 +44,8 @@ public: numberOfBins - 1); } + void test_size() { TS_ASSERT_EQUALS(m_workspace.detectorInfo().size(), 5); } + void test_sourcePosition() { TS_ASSERT_EQUALS(m_workspace.detectorInfo().sourcePosition(), V3D(0.0, 0.0, -20.0)); @@ -177,6 +179,20 @@ public: TS_ASSERT_EQUALS(detectorInfo.rotation(4), Quat(1.0, 0.0, 0.0, 0.0)); } + void test_setMasked() { + auto &detectorInfo = m_workspace.mutableDetectorInfo(); + TS_ASSERT_EQUALS(detectorInfo.isMasked(0), true); + detectorInfo.setMasked(0, false); + TS_ASSERT_EQUALS(detectorInfo.isMasked(0), false); + detectorInfo.setMasked(0, true); + TS_ASSERT_EQUALS(detectorInfo.isMasked(0), true); + // Make sure no other detectors are affected + TS_ASSERT_EQUALS(detectorInfo.isMasked(1), false); + TS_ASSERT_EQUALS(detectorInfo.isMasked(2), false); + TS_ASSERT_EQUALS(detectorInfo.isMasked(3), true); + TS_ASSERT_EQUALS(detectorInfo.isMasked(4), false); + } + void test_setRotation() { V3D e3{0, 0, 1}; Quat r3(90.0, e3); diff --git a/Framework/API/test/MatrixWorkspaceTest.h b/Framework/API/test/MatrixWorkspaceTest.h index 2700b470276ace129d6914aa90d177b5a6a4523a..00bde365b1cc136eab9a8006d75c5d360cf8bf8a 100644 --- a/Framework/API/test/MatrixWorkspaceTest.h +++ b/Framework/API/test/MatrixWorkspaceTest.h @@ -263,8 +263,10 @@ public: } // Mask a spectra - workspace->maskWorkspaceIndex(1); - workspace->maskWorkspaceIndex(2); + workspace->getSpectrum(1).clearData(); + workspace->getSpectrum(2).clearData(); + workspace->mutableSpectrumInfo().setMasked(1, true); + workspace->mutableSpectrumInfo().setMasked(2, true); for (int i = 0; i < numHist; ++i) { double expectedValue(0.0); @@ -292,8 +294,10 @@ public: // Workspace has 3 spectra, each 1 in length const int numHist(3); auto workspace = makeWorkspaceWithDetectors(numHist, 1); - workspace->maskWorkspaceIndex(1); - workspace->maskWorkspaceIndex(2); + workspace->getSpectrum(1).clearData(); + workspace->getSpectrum(2).clearData(); + workspace->mutableSpectrumInfo().setMasked(1, true); + workspace->mutableSpectrumInfo().setMasked(2, true); const auto &spectrumInfo = workspace->spectrumInfo(); for (int i = 0; i < numHist; ++i) { @@ -523,55 +527,6 @@ public: TS_ASSERT_THROWS_NOTHING(ws->saveSpectraMapNexus(th.file, spec);); } - /** Properly, this tests a method on Instrument, not MatrixWorkspace, but they - * are related. - */ - void test_isDetectorMasked() { - auto ws = makeWorkspaceWithDetectors(100, 10); - Instrument_const_sptr inst = ws->getInstrument(); - // Make sure the instrument is parametrized so that the test is thorough - TS_ASSERT(inst->isParametrized()); - TS_ASSERT(!inst->isDetectorMasked(1)); - TS_ASSERT(!inst->isDetectorMasked(19)); - // Mask then check that it returns as masked - TS_ASSERT(ws->getSpectrum(19).hasDetectorID(19)); - ws->maskWorkspaceIndex(19); - TS_ASSERT(inst->isDetectorMasked(19)); - } - - /** Check if any of a list of detectors are masked */ - void test_isDetectorMasked_onASet() { - auto ws = makeWorkspaceWithDetectors(100, 10); - Instrument_const_sptr inst = ws->getInstrument(); - // Make sure the instrument is parametrized so that the test is thorough - TS_ASSERT(inst->isParametrized()); - - // Mask detector IDs 8 and 9 - ws->maskWorkspaceIndex(8); - ws->maskWorkspaceIndex(9); - - std::set<detid_t> dets; - TSM_ASSERT("No detector IDs = not masked", !inst->isDetectorMasked(dets)); - dets.insert(6); - TSM_ASSERT("Detector is not masked", !inst->isDetectorMasked(dets)); - dets.insert(7); - TSM_ASSERT("Detectors are not masked", !inst->isDetectorMasked(dets)); - dets.insert(8); - TSM_ASSERT("If any detector is not masked, return false", - !inst->isDetectorMasked(dets)); - // Start again - dets.clear(); - dets.insert(8); - TSM_ASSERT("If all detectors are not masked, return true", - inst->isDetectorMasked(dets)); - dets.insert(9); - TSM_ASSERT("If all detectors are not masked, return true", - inst->isDetectorMasked(dets)); - dets.insert(10); - TSM_ASSERT("If any detector is not masked, return false", - !inst->isDetectorMasked(dets)); - } - void test_hasGroupedDetectors() { auto ws = makeWorkspaceWithDetectors(5, 1); TS_ASSERT_EQUALS(ws->hasGroupedDetectors(), false); diff --git a/Framework/API/test/NearestNeighbourInfoTest.h b/Framework/API/test/NearestNeighbourInfoTest.h index b53ca21b5e256e3bc255f4a5e39224655ab6191b..f8fa58c3e4d72ae8275216a845528f2a378fe4d9 100644 --- a/Framework/API/test/NearestNeighbourInfoTest.h +++ b/Framework/API/test/NearestNeighbourInfoTest.h @@ -6,6 +6,7 @@ #include "MantidTestHelpers/FakeObjects.h" #include "MantidTestHelpers/InstrumentCreationHelper.h" #include "MantidAPI/NearestNeighbourInfo.h" +#include "MantidAPI/SpectrumInfo.h" using Mantid::API::NearestNeighbourInfo; @@ -23,7 +24,8 @@ public: InstrumentCreationHelper::addFullInstrumentToWorkspace(workspace, false, false, ""); workspace.rebuildSpectraMapping(); - workspace.maskWorkspaceIndex(0); + workspace.getSpectrum(0).clearData(); + workspace.mutableSpectrumInfo().setMasked(0, true); } void test_construct() { diff --git a/Framework/Geometry/test/NearestNeighboursTest.h b/Framework/API/test/NearestNeighboursTest.h similarity index 55% rename from Framework/Geometry/test/NearestNeighboursTest.h rename to Framework/API/test/NearestNeighboursTest.h index a5609c0933186f6c67b8752e0a388b674fc42a27..0369aaacabbf069c5fff98582b8e0df241163e7e 100644 --- a/Framework/Geometry/test/NearestNeighboursTest.h +++ b/Framework/API/test/NearestNeighboursTest.h @@ -1,71 +1,78 @@ #ifndef MANTID_TEST_GEOMETRY_NEARESTNEIGHBOURS #define MANTID_TEST_GEOMETRY_NEARESTNEIGHBOURS +#include "MantidAPI/NearestNeighbours.h" +#include "MantidAPI/SpectrumInfo.h" #include "MantidGeometry/IDetector.h" #include "MantidGeometry/Instrument/Detector.h" #include "MantidGeometry/Instrument.h" -#include "MantidGeometry/Instrument/NearestNeighbours.h" #include "MantidGeometry/Instrument/ParameterMap.h" #include "MantidGeometry/Instrument/RectangularDetector.h" #include "MantidGeometry/Objects/BoundingBox.h" #include "MantidTestHelpers/ComponentCreationHelper.h" +#include "MantidTestHelpers/FakeObjects.h" #include <cxxtest/TestSuite.h> #include <map> using namespace Mantid; using namespace Mantid::Geometry; +using namespace Mantid::API; using Mantid::Kernel::V3D; /** * Everything must be in one test or the instrument/detector list goes AWOL. */ +namespace { +boost::shared_ptr<MatrixWorkspace> makeWorkspace(const specnum_t start, + const specnum_t end) { + auto ws = boost::make_shared<WorkspaceTester>(); + ws->initialize(end - start + 1, 2, 1); + for (specnum_t i = start; i <= end; ++i) { + ws->getSpectrum(i - start).setSpectrumNo(i); + ws->getSpectrum(i - start).setDetectorID(i); + } + return ws; +} + +std::vector<specnum_t> getSpectrumNumbers(const MatrixWorkspace &workspace) { + std::vector<specnum_t> spectrumNumbers; + for (size_t i = 0; i < workspace.getNumberHistograms(); ++i) + spectrumNumbers.push_back(workspace.getSpectrum(i).getSpectrumNo()); + return spectrumNumbers; +} +} + //===================================================================================== // Functional tests //===================================================================================== class NearestNeighboursTest : public CxxTest::TestSuite { -public: - static ISpectrumDetectorMapping - buildSpectrumDetectorMapping(const specnum_t start, const specnum_t end) { - std::unordered_map<specnum_t, std::set<detid_t>> map; - for (specnum_t i = start; i <= end; ++i) { - map[i].insert(i); - } - return map; - } - private: /// Helper type giving access to protected methods. Makes testing of NN /// internals possible. - class ExposedNearestNeighbours : public Mantid::Geometry::NearestNeighbours { + class ExposedNearestNeighbours : public Mantid::API::NearestNeighbours { public: - ExposedNearestNeighbours(boost::shared_ptr<const Instrument> instrument, - const ISpectrumDetectorMapping &spectraMap, + ExposedNearestNeighbours(const SpectrumInfo &spectrumInfo, + const std::vector<specnum_t> spectrumNumbers, bool ignoreMasked = false) - : NearestNeighbours(instrument, spectraMap, ignoreMasked) {} + : NearestNeighbours(8, spectrumInfo, spectrumNumbers, ignoreMasked) {} // Direct access to intermdiate spectra detectors - std::map<specnum_t, IDetector_const_sptr> getSpectraDetectors() { - return NearestNeighbours::getSpectraDetectors(m_instrument, m_spectraMap); + std::vector<size_t> getSpectraDetectors() { + return NearestNeighbours::getSpectraDetectors(); } }; public: void doTestWithNeighbourNumbers(int actualNeighboursNumber, int expectedNeighboursNumber) { - // Create Instrument and make it Parameterised - Instrument_sptr instrument = boost::dynamic_pointer_cast<Instrument>( + const auto ws = makeWorkspace(1, 18); + ws->setInstrument( ComponentCreationHelper::createTestInstrumentCylindrical(2)); - const ISpectrumDetectorMapping spectramap = - buildSpectrumDetectorMapping(1, 18); - TS_ASSERT_EQUALS(spectramap.size(), 18); - // Default parameter map. - ParameterMap_sptr pmap(new ParameterMap()); - // Parameterized instrument - Instrument_sptr m_instrument(new Instrument(instrument, pmap)); // Create the NearestNeighbours object directly. - NearestNeighbours nn(actualNeighboursNumber, m_instrument, spectramap); + NearestNeighbours nn(actualNeighboursNumber, ws->spectrumInfo(), + getSpectrumNumbers(*ws)); // Check distances calculated in NearestNeighbours compare with those using // getDistance on component @@ -76,22 +83,15 @@ public: } void testNeighbourFindingWithRadius() { - // Create Instrument and make it Parameterised - Instrument_sptr instrument = boost::dynamic_pointer_cast<Instrument>( + const auto ws = makeWorkspace(1, 18); + ws->setInstrument( ComponentCreationHelper::createTestInstrumentCylindrical(2)); - const ISpectrumDetectorMapping spectramap = - buildSpectrumDetectorMapping(1, 18); - TS_ASSERT_EQUALS(spectramap.size(), 18); - // Default parameter map. - ParameterMap_sptr pmap(new ParameterMap()); - // Parameterized instrument - Instrument_sptr m_instrument(new Instrument(instrument, pmap)); // Create the NearestNeighbours object directly. - NearestNeighbours nn(m_instrument, spectramap); + NearestNeighbours nn(8, ws->spectrumInfo(), getSpectrumNumbers(*ws)); detid2det_map m_detectors; - m_instrument->getDetectors(m_detectors); + ws->getInstrument()->getDetectors(m_detectors); // Need scaling vector since changes to NN ( 22/12/10 ) Mantid::Geometry::BoundingBox bbox = Mantid::Geometry::BoundingBox(); @@ -102,8 +102,6 @@ public: (bbox.zMax() - bbox.zMin())); // Check instrument was created to our expectations - ParameterMap_sptr p_map; - TS_ASSERT_THROWS_NOTHING(p_map = m_instrument->getParameterMap()); TS_ASSERT_EQUALS(m_detectors.size(), 18); // Check distances calculated in NearestNeighbours compare with those using @@ -140,21 +138,15 @@ public: // Let's try it with a rectangular detector. void testNeighbours_RectangularDetector() { + const auto ws = makeWorkspace(256, 767); // 2 Rectangular detectors, 16x16 - Instrument_sptr instrument = boost::dynamic_pointer_cast<Instrument>( + ws->setInstrument( ComponentCreationHelper::createTestInstrumentRectangular(2, 16)); - // Test fails without a parameter map. - const ISpectrumDetectorMapping spectramap = - buildSpectrumDetectorMapping(256, 767); - // Default parameter map. - ParameterMap_sptr pmap(new ParameterMap()); - // Parameterized instrument - Instrument_sptr m_instrument(new Instrument(instrument, pmap)); - // Create the NearestNeighbours object directly. - NearestNeighbours nn(m_instrument, spectramap); + NearestNeighbours nn(8, ws->spectrumInfo(), getSpectrumNumbers(*ws)); + const auto &m_instrument = ws->getInstrument(); // Correct # of detectors TS_ASSERT_EQUALS(m_instrument->getDetectorIDs().size(), 512); @@ -177,34 +169,21 @@ public: } void testIgnoreAndApplyMasking() { - Instrument_sptr instrument = boost::dynamic_pointer_cast<Instrument>( + const auto ws = makeWorkspace(1, 18); + ws->setInstrument( ComponentCreationHelper::createTestInstrumentCylindrical(2)); - const ISpectrumDetectorMapping spectramap = - buildSpectrumDetectorMapping(1, 18); - - // Default parameter map. - ParameterMap_sptr pmap(new ParameterMap()); - - // Mask the first 5 detectors - for (Mantid::specnum_t i = 1; i < 3; i++) { - if (const Geometry::ComponentID det = - instrument->getDetector(*spectramap.at(i).begin()) - ->getComponentID()) { - pmap->addBool(det, "masked", true); - } - } - // Parameterized instrument - Instrument_sptr m_instrument(new Instrument(instrument, pmap)); - - IDetector_const_sptr det = - m_instrument->getDetector(*spectramap.at(1).begin()); + // Mask the first 2 detectors + auto &spectrumInfo = ws->mutableSpectrumInfo(); + spectrumInfo.setMasked(0, true); + spectrumInfo.setMasked(1, true); // Create the NearestNeighbours object directly. Ignore any masking. - ExposedNearestNeighbours ignoreMaskedNN(m_instrument, spectramap, true); + ExposedNearestNeighbours ignoreMaskedNN(ws->spectrumInfo(), + getSpectrumNumbers(*ws), true); // Create the NearestNeighbours object directly. Account for any masking. - ExposedNearestNeighbours accountForMaskedNN(m_instrument, spectramap, - false); + ExposedNearestNeighbours accountForMaskedNN(ws->spectrumInfo(), + getSpectrumNumbers(*ws), false); size_t sizeWithoutMasked = ignoreMaskedNN.getSpectraDetectors().size(); size_t sizeWithMasked = accountForMaskedNN.getSpectraDetectors().size(); @@ -225,52 +204,27 @@ class NearestNeighboursTestPerformance : public CxxTest::TestSuite { public: void testUsingRadius() { - Instrument_sptr instrument = boost::dynamic_pointer_cast<Instrument>( + const auto ws = makeWorkspace(1, 18); + ws->setInstrument( ComponentCreationHelper::createTestInstrumentCylindrical(2)); - const ISpectrumDetectorMapping spectramap = - NearestNeighboursTest::buildSpectrumDetectorMapping(1, 18); - // Default parameter map. - ParameterMap_sptr pmap(new ParameterMap()); - // Parameterized instrument - Instrument_sptr m_instrument(new Instrument(instrument, pmap)); // Create the NearestNeighbours object directly. - NearestNeighbours nn(m_instrument, spectramap); + NearestNeighbours nn(8, ws->spectrumInfo(), getSpectrumNumbers(*ws)); for (size_t i = 0; i < 2000; i++) { nn.neighboursInRadius(1, 5.0); } } - void testUsingDefault() { - Instrument_sptr instrument = boost::dynamic_pointer_cast<Instrument>( - ComponentCreationHelper::createTestInstrumentCylindrical(2)); - const ISpectrumDetectorMapping spectramap = - NearestNeighboursTest::buildSpectrumDetectorMapping(1, 18); - // Default parameter map. - ParameterMap_sptr pmap(new ParameterMap()); - // Parameterized instrument - Instrument_sptr m_instrument(new Instrument(instrument, pmap)); - - // Create the NearestNeighbours object directly. - NearestNeighbours nn(m_instrument, spectramap); - for (size_t i = 0; i < 2000; i++) { - nn.neighboursInRadius(1, 0.0); - } - } - void testUsingNumberOfNeighbours() { - Instrument_sptr instrument = boost::dynamic_pointer_cast<Instrument>( + const auto ws = makeWorkspace(1, 18); + ws->setInstrument( ComponentCreationHelper::createTestInstrumentCylindrical(2)); - const ISpectrumDetectorMapping spectramap = - NearestNeighboursTest::buildSpectrumDetectorMapping(1, 18); - // Default parameter map. - ParameterMap_sptr pmap(new ParameterMap()); - // Parameterized instrument - Instrument_sptr m_instrument(new Instrument(instrument, pmap)); // Create the NearestNeighbours object directly. + const auto &spectrumInfo = ws->spectrumInfo(); + const auto spectrumNumbers = getSpectrumNumbers(*ws); for (size_t i = 0; i < 2000; i++) { - NearestNeighbours nn(8, m_instrument, spectramap); + NearestNeighbours nn(8, spectrumInfo, spectrumNumbers); nn.neighbours(1); } } diff --git a/Framework/API/test/SpectrumInfoTest.h b/Framework/API/test/SpectrumInfoTest.h index d606a635a7b71c5cc4003f3417422f67d0de04dd..28331380e91cdf242502ae75322318ddf9716ca0 100644 --- a/Framework/API/test/SpectrumInfoTest.h +++ b/Framework/API/test/SpectrumInfoTest.h @@ -16,6 +16,14 @@ using namespace Mantid::Geometry; using namespace Mantid::API; using namespace Mantid::Kernel; +namespace { +constexpr size_t GroupOfDets2And3 = 0; +constexpr size_t GroupOfDets1And2 = 1; +constexpr size_t GroupOfDets1And4 = 2; +constexpr size_t GroupOfDets4And5 = 3; +constexpr size_t GroupOfAllDets = 4; +} + class SpectrumInfoTest : public CxxTest::TestSuite { public: // This pair of boilerplate methods prevent the suite being created statically @@ -31,11 +39,15 @@ public: numberOfBins); // Workspace has 5 detectors, 1 and 4 are masked, 4 and 5 are monitors. - m_grouped.getSpectrum(0).setDetectorIDs({2, 3}); // no mask - m_grouped.getSpectrum(1).setDetectorIDs({1, 2}); // partial mask - m_grouped.getSpectrum(2).setDetectorIDs({1, 4}); // masked, partial monitor - m_grouped.getSpectrum(3).setDetectorIDs({4, 5}); // full monitor - m_grouped.getSpectrum(4).setDetectorIDs({1, 2, 3, 4, 5}); // everything + m_grouped.getSpectrum(GroupOfDets2And3).setDetectorIDs({2, 3}); // no mask + m_grouped.getSpectrum(GroupOfDets1And2) + .setDetectorIDs({1, 2}); // partial mask + m_grouped.getSpectrum(GroupOfDets1And4) + .setDetectorIDs({1, 4}); // masked, partial monitor + m_grouped.getSpectrum(GroupOfDets4And5) + .setDetectorIDs({4, 5}); // full monitor + m_grouped.getSpectrum(GroupOfAllDets) + .setDetectorIDs({1, 2, 3, 4, 5}); // everything } void test_constructor() { @@ -73,11 +85,11 @@ public: // This is adopting the old definition from DetectorGroup: Spectra with at // least one non-monitor detector are not monitors. Actually it might make // more sense to forbid such a grouping. - TS_ASSERT_EQUALS(spectrumInfo.isMonitor(0), false); - TS_ASSERT_EQUALS(spectrumInfo.isMonitor(1), false); - TS_ASSERT_EQUALS(spectrumInfo.isMonitor(2), false); - TS_ASSERT_EQUALS(spectrumInfo.isMonitor(3), true); - TS_ASSERT_EQUALS(spectrumInfo.isMonitor(4), false); + TS_ASSERT_EQUALS(spectrumInfo.isMonitor(GroupOfDets2And3), false); + TS_ASSERT_EQUALS(spectrumInfo.isMonitor(GroupOfDets1And2), false); + TS_ASSERT_EQUALS(spectrumInfo.isMonitor(GroupOfDets1And4), false); + TS_ASSERT_EQUALS(spectrumInfo.isMonitor(GroupOfDets4And5), true); + TS_ASSERT_EQUALS(spectrumInfo.isMonitor(GroupOfAllDets), false); } void test_isMasked() { @@ -91,11 +103,11 @@ public: void test_grouped_isMasked() { const auto &spectrumInfo = m_grouped.spectrumInfo(); - TS_ASSERT_EQUALS(spectrumInfo.isMasked(0), false); - TS_ASSERT_EQUALS(spectrumInfo.isMasked(1), false); - TS_ASSERT_EQUALS(spectrumInfo.isMasked(2), true); - TS_ASSERT_EQUALS(spectrumInfo.isMasked(3), false); - TS_ASSERT_EQUALS(spectrumInfo.isMasked(4), false); + TS_ASSERT_EQUALS(spectrumInfo.isMasked(GroupOfDets2And3), false); + TS_ASSERT_EQUALS(spectrumInfo.isMasked(GroupOfDets1And2), false); + TS_ASSERT_EQUALS(spectrumInfo.isMasked(GroupOfDets1And4), true); + TS_ASSERT_EQUALS(spectrumInfo.isMasked(GroupOfDets4And5), false); + TS_ASSERT_EQUALS(spectrumInfo.isMasked(GroupOfAllDets), false); } void test_isMasked_unthreaded() { @@ -132,9 +144,9 @@ public: const auto &spectrumInfo = m_grouped.spectrumInfo(); double x2 = 5.0 * 5.0; double y2 = 2.0 * 2.0 * 0.05 * 0.05; - TS_ASSERT_EQUALS(spectrumInfo.l2(0), + TS_ASSERT_EQUALS(spectrumInfo.l2(GroupOfDets2And3), (sqrt(x2 + 0 * 0 * y2) + sqrt(x2 + 1 * 1 * y2)) / 2.0); - TS_ASSERT_EQUALS(spectrumInfo.l2(1), + TS_ASSERT_EQUALS(spectrumInfo.l2(GroupOfDets1And2), (sqrt(x2 + 0 * 0 * y2) + sqrt(x2 + 1 * 1 * y2)) / 2.0); // Other lengths are not sensible since the detectors include monitors } @@ -165,8 +177,10 @@ public: void test_grouped_twoTheta() { const auto &spectrumInfo = m_grouped.spectrumInfo(); - TS_ASSERT_DELTA(spectrumInfo.twoTheta(0), 0.0199973 / 2.0, 1e-6); - TS_ASSERT_DELTA(spectrumInfo.twoTheta(1), 0.0199973 / 2.0, 1e-6); + TS_ASSERT_DELTA(spectrumInfo.twoTheta(GroupOfDets2And3), 0.0199973 / 2.0, + 1e-6); + TS_ASSERT_DELTA(spectrumInfo.twoTheta(GroupOfDets1And2), 0.0199973 / 2.0, + 1e-6); // Other theta values are not sensible since the detectors include monitors } @@ -183,8 +197,8 @@ public: // removed at some point. void test_grouped_twoThetaLegacy() { const auto &spectrumInfo = m_grouped.spectrumInfo(); - auto det = m_grouped.getDetector(1); - TS_ASSERT_EQUALS(spectrumInfo.twoTheta(1), + auto det = m_grouped.getDetector(GroupOfDets1And2); + TS_ASSERT_EQUALS(spectrumInfo.twoTheta(GroupOfDets1And2), m_grouped.detectorTwoTheta(*det)); } @@ -200,8 +214,10 @@ public: void test_grouped_signedTwoTheta() { const auto &spectrumInfo = m_grouped.spectrumInfo(); - TS_ASSERT_DELTA(spectrumInfo.signedTwoTheta(0), 0.0199973 / 2.0, 1e-6); - TS_ASSERT_DELTA(spectrumInfo.signedTwoTheta(1), -0.0199973 / 2.0, 1e-6); + TS_ASSERT_DELTA(spectrumInfo.signedTwoTheta(GroupOfDets2And3), + 0.0199973 / 2.0, 1e-6); + TS_ASSERT_DELTA(spectrumInfo.signedTwoTheta(GroupOfDets1And2), + -0.0199973 / 2.0, 1e-6); // Other theta values are not sensible since the detectors include monitors } @@ -218,8 +234,8 @@ public: // be removed at some point. void test_grouped_signedTwoThetaLegacy() { const auto &spectrumInfo = m_grouped.spectrumInfo(); - auto det = m_grouped.getDetector(1); - TS_ASSERT_EQUALS(spectrumInfo.signedTwoTheta(1), + auto det = m_grouped.getDetector(GroupOfDets1And2); + TS_ASSERT_EQUALS(spectrumInfo.signedTwoTheta(GroupOfDets1And2), m_grouped.detectorSignedTwoTheta(*det)); } @@ -234,18 +250,21 @@ public: void test_grouped_position() { const auto &spectrumInfo = m_grouped.spectrumInfo(); - TS_ASSERT_EQUALS(spectrumInfo.position(0), V3D(0.0, 0.1 / 2.0, 5.0)); - TS_ASSERT_EQUALS(spectrumInfo.position(1), V3D(0.0, -0.1 / 2.0, 5.0)); + TS_ASSERT_EQUALS(spectrumInfo.position(GroupOfDets2And3), + V3D(0.0, 0.1 / 2.0, 5.0)); + TS_ASSERT_EQUALS(spectrumInfo.position(GroupOfDets1And2), + V3D(0.0, -0.1 / 2.0, 5.0)); // Other positions are not sensible since the detectors include monitors } void test_grouped_position_tracks_changes() { auto &detectorInfo = m_grouped.mutableDetectorInfo(); const auto &spectrumInfo = m_grouped.spectrumInfo(); - const auto oldPos = spectrumInfo.position(0); + const auto oldPos = detectorInfo.position(1); // Change Y pos from 0.0 to -0.1 detectorInfo.setPosition(1, V3D(0.0, -0.1, 5.0)); - TS_ASSERT_EQUALS(spectrumInfo.position(0), V3D(0.0, 0.0, 5.0)); + TS_ASSERT_EQUALS(spectrumInfo.position(GroupOfDets2And3), + V3D(0.0, 0.0, 5.0)); TS_ASSERT_DELTA(spectrumInfo.twoTheta(0), 0.0199973, 1e-6); // Restore old position detectorInfo.setPosition(1, oldPos); @@ -273,11 +292,11 @@ public: void test_grouped_hasDetectors() { const auto &spectrumInfo = m_grouped.spectrumInfo(); - TS_ASSERT(spectrumInfo.hasDetectors(0)); - TS_ASSERT(spectrumInfo.hasDetectors(1)); - TS_ASSERT(spectrumInfo.hasDetectors(2)); - TS_ASSERT(spectrumInfo.hasDetectors(3)); - TS_ASSERT(spectrumInfo.hasDetectors(4)); + TS_ASSERT(spectrumInfo.hasDetectors(GroupOfDets2And3)); + TS_ASSERT(spectrumInfo.hasDetectors(GroupOfDets1And2)); + TS_ASSERT(spectrumInfo.hasDetectors(GroupOfDets1And4)); + TS_ASSERT(spectrumInfo.hasDetectors(GroupOfDets4And5)); + TS_ASSERT(spectrumInfo.hasDetectors(GroupOfAllDets)); } void test_hasDetectors_ignores_bad_IDs() { @@ -311,11 +330,11 @@ public: void test_grouped_hasUniqueDetector() { const auto &spectrumInfo = m_grouped.spectrumInfo(); - TS_ASSERT(!spectrumInfo.hasUniqueDetector(0)); - TS_ASSERT(!spectrumInfo.hasUniqueDetector(1)); - TS_ASSERT(!spectrumInfo.hasUniqueDetector(2)); - TS_ASSERT(!spectrumInfo.hasUniqueDetector(3)); - TS_ASSERT(!spectrumInfo.hasUniqueDetector(4)); + TS_ASSERT(!spectrumInfo.hasUniqueDetector(GroupOfDets2And3)); + TS_ASSERT(!spectrumInfo.hasUniqueDetector(GroupOfDets1And2)); + TS_ASSERT(!spectrumInfo.hasUniqueDetector(GroupOfDets1And4)); + TS_ASSERT(!spectrumInfo.hasUniqueDetector(GroupOfDets4And5)); + TS_ASSERT(!spectrumInfo.hasUniqueDetector(GroupOfAllDets)); } void test_hasUniqueDetector_ignores_bad_IDs() { @@ -327,6 +346,62 @@ public: m_workspace.getSpectrum(1).setDetectorID(2); } + void test_setMasked() { + auto &spectrumInfo = m_workspace.mutableSpectrumInfo(); + TS_ASSERT_EQUALS(spectrumInfo.isMasked(0), true); + spectrumInfo.setMasked(0, false); + TS_ASSERT_EQUALS(spectrumInfo.isMasked(0), false); + spectrumInfo.setMasked(0, true); + TS_ASSERT_EQUALS(spectrumInfo.isMasked(0), true); + // Make sure no other detectors are affected + TS_ASSERT_EQUALS(spectrumInfo.isMasked(1), false); + TS_ASSERT_EQUALS(spectrumInfo.isMasked(2), false); + TS_ASSERT_EQUALS(spectrumInfo.isMasked(3), true); + TS_ASSERT_EQUALS(spectrumInfo.isMasked(4), false); + } + + void test_grouped_setMasked() { + auto &spectrumInfo = m_grouped.mutableSpectrumInfo(); + spectrumInfo.setMasked(GroupOfAllDets, false); + // 4 includes all detectors so all other spectra are affected + TS_ASSERT_EQUALS(spectrumInfo.isMasked(GroupOfDets2And3), false); + TS_ASSERT_EQUALS(spectrumInfo.isMasked(GroupOfDets1And2), false); + TS_ASSERT_EQUALS(spectrumInfo.isMasked(GroupOfDets1And4), false); + TS_ASSERT_EQUALS(spectrumInfo.isMasked(GroupOfDets4And5), false); + TS_ASSERT_EQUALS(spectrumInfo.isMasked(GroupOfAllDets), false); + spectrumInfo.setMasked(GroupOfDets2And3, true); + // Partial masking => false + TS_ASSERT_EQUALS(spectrumInfo.isMasked(GroupOfDets2And3), true); + TS_ASSERT_EQUALS(spectrumInfo.isMasked(GroupOfDets1And2), false); + TS_ASSERT_EQUALS(spectrumInfo.isMasked(GroupOfDets1And4), false); + TS_ASSERT_EQUALS(spectrumInfo.isMasked(GroupOfDets4And5), false); + TS_ASSERT_EQUALS(spectrumInfo.isMasked(GroupOfAllDets), false); + // Restore initial state + spectrumInfo.setMasked(GroupOfAllDets, false); + spectrumInfo.setMasked(GroupOfDets1And4, true); + } + + void test_grouped_setMasked_reverse_case() { + auto &spectrumInfo = m_grouped.mutableSpectrumInfo(); + spectrumInfo.setMasked(GroupOfAllDets, true); + // 4 includes all detectors so all other spectra are affected + TS_ASSERT_EQUALS(spectrumInfo.isMasked(GroupOfDets2And3), true); + TS_ASSERT_EQUALS(spectrumInfo.isMasked(GroupOfDets1And2), true); + TS_ASSERT_EQUALS(spectrumInfo.isMasked(GroupOfDets1And4), true); + TS_ASSERT_EQUALS(spectrumInfo.isMasked(GroupOfDets4And5), true); + TS_ASSERT_EQUALS(spectrumInfo.isMasked(GroupOfAllDets), true); + spectrumInfo.setMasked(GroupOfDets2And3, false); + // Partial masking => false + TS_ASSERT_EQUALS(spectrumInfo.isMasked(GroupOfDets2And3), false); + TS_ASSERT_EQUALS(spectrumInfo.isMasked(GroupOfDets1And2), false); + TS_ASSERT_EQUALS(spectrumInfo.isMasked(GroupOfDets1And4), true); + TS_ASSERT_EQUALS(spectrumInfo.isMasked(GroupOfDets4And5), true); + TS_ASSERT_EQUALS(spectrumInfo.isMasked(GroupOfAllDets), false); + // Restore initial state + spectrumInfo.setMasked(GroupOfAllDets, false); + spectrumInfo.setMasked(GroupOfDets1And4, true); + } + void test_detector() { const auto &spectrumInfo = m_workspace.spectrumInfo(); TS_ASSERT_THROWS_NOTHING(spectrumInfo.detector(0)); @@ -352,15 +427,16 @@ private: ws->initialize(numSpectra, 1, 1); auto inst = boost::make_shared<Instrument>("TestInstrument"); ws->setInstrument(inst); - auto &pmap = ws->instrumentParameters(); for (size_t i = 0; i < ws->getNumberHistograms(); ++i) { auto det = new Detector("pixel", static_cast<detid_t>(i), inst.get()); inst->add(det); inst->markAsDetector(det); ws->getSpectrum(i).addDetectorID(static_cast<detid_t>(i)); - if (i % 2 == 0) - pmap.addBool(det->getComponentID(), "masked", true); } + auto &detectorInfo = ws->mutableDetectorInfo(); + for (size_t i = 0; i < ws->getNumberHistograms(); ++i) + if (i % 2 == 0) + detectorInfo.setMasked(i, true); return std::move(ws); } @@ -376,13 +452,9 @@ private: ws, includeMonitors, startYNegative, instrumentName); std::set<int64_t> toMask{0, 3}; - ParameterMap &pmap = ws.instrumentParameters(); - for (size_t i = 0; i < ws.getNumberHistograms(); ++i) { - if (toMask.find(i) != toMask.end()) { - IDetector_const_sptr det = ws.getDetector(i); - pmap.addBool(det.get(), "masked", true); - } - } + auto &detectorInfo = ws.mutableDetectorInfo(); + for (const auto &i : toMask) + detectorInfo.setMasked(i, true); return ws; } }; diff --git a/Framework/Algorithms/inc/MantidAlgorithms/BinaryOperation.h b/Framework/Algorithms/inc/MantidAlgorithms/BinaryOperation.h index eb54c236338b94b24a586366dd62da420f9d74a4..4c2a6908c231b4ee191e1b140c13885995dde8cb 100644 --- a/Framework/Algorithms/inc/MantidAlgorithms/BinaryOperation.h +++ b/Framework/Algorithms/inc/MantidAlgorithms/BinaryOperation.h @@ -108,14 +108,11 @@ protected: checkSizeCompatibility(const API::MatrixWorkspace_const_sptr lhs, const API::MatrixWorkspace_const_sptr rhs) const; - /// Checks if the spectra at the given index of either input workspace is - /// masked. If so then the output spectra has zeroed data - /// and is also masked. The function returns true if further processing is not - /// required on the spectra. virtual bool propagateSpectraMask(const API::SpectrumInfo &lhsSpectrumInfo, const API::SpectrumInfo &rhsSpectrumInfo, const int64_t index, - API::MatrixWorkspace &out); + API::MatrixWorkspace &out, + API::SpectrumInfo &outSpectrumInfo); /** Carries out the binary operation on a single spectrum, with another *spectrum as the right-hand operand. diff --git a/Framework/Algorithms/inc/MantidAlgorithms/InterpolationOption.h b/Framework/Algorithms/inc/MantidAlgorithms/InterpolationOption.h index 7d8617863726bf8aa69a33c3c5e449cd394a5441..fcc79d49f8128ae4b592cc2b97ce7fb384737e80 100644 --- a/Framework/Algorithms/inc/MantidAlgorithms/InterpolationOption.h +++ b/Framework/Algorithms/inc/MantidAlgorithms/InterpolationOption.h @@ -3,6 +3,7 @@ #include "MantidAlgorithms/DllConfig.h" #include <memory> +#include <string> namespace Mantid { namespace HistogramData { diff --git a/Framework/Algorithms/inc/MantidAlgorithms/SumSpectra.h b/Framework/Algorithms/inc/MantidAlgorithms/SumSpectra.h index c05ada0cf5a0aa76410efde2ef38c854458ffcc8..e7a400f89d8bf819c04a151bcff8fa69bd5a4f8d 100644 --- a/Framework/Algorithms/inc/MantidAlgorithms/SumSpectra.h +++ b/Framework/Algorithms/inc/MantidAlgorithms/SumSpectra.h @@ -34,7 +34,7 @@ namespace Algorithms { @author Nick Draper, Tessella Support Services plc @date 22/01/2009 - Copyright © 2007-2010 ISIS Rutherford Appleton Laboratory, NScD Oak + Copyright © 2007-2016 ISIS Rutherford Appleton Laboratory, NScD Oak Ridge National Laboratory & European Spallation Source This file is part of Mantid. @@ -80,8 +80,7 @@ private: API::Progress &progress, size_t &numSpectra, size_t &numMasked, size_t &numZeros); /// Handle logic for Workspace2D workspaces - void doWorkspace2D(API::MatrixWorkspace_const_sptr localworkspace, - API::ISpectrum &outSpec, API::Progress &progress, + void doWorkspace2D(API::ISpectrum &outSpec, API::Progress &progress, size_t &numSpectra, size_t &numMasked, size_t &numZeros); // Overridden Algorithm methods @@ -91,6 +90,9 @@ private: std::set<int> &indices); specnum_t getOutputSpecNo(API::MatrixWorkspace_const_sptr localworkspace); + API::MatrixWorkspace_sptr + replaceSpecialValues(API::MatrixWorkspace_sptr inputWs); + /// The output spectrum number specnum_t m_outSpecNum; /// The spectrum to start the integration from @@ -99,14 +101,16 @@ private: int m_maxWsInd; /// Set true to keep monitors bool m_keepMonitors; + /// Set true to remove special values before processing + bool m_replaceSpecialValues; /// numberOfSpectra in the input int m_numberOfSpectra; /// Blocksize of the input workspace int m_yLength; - /// Set of indicies to sum + /// Set of indices to sum std::set<int> m_indices; - // if calculateing additional workspace with specially weighted averages is + // if calculating additional workspace with specially weighted averages is // necessary bool m_calculateWeightedSum; }; diff --git a/Framework/Algorithms/src/BinaryOperation.cpp b/Framework/Algorithms/src/BinaryOperation.cpp index 21212515f8e167bdc8c48e8b9c723278b2715c06..40b4a3d5eb7af18eb7436e534abf147bda5fbb90 100644 --- a/Framework/Algorithms/src/BinaryOperation.cpp +++ b/Framework/Algorithms/src/BinaryOperation.cpp @@ -437,13 +437,15 @@ std::string BinaryOperation::checkSizeCompatibility( * @param rhsSpectrumInfo :: The RHS spectrum info object * @param index :: The workspace index to check * @param out :: A pointer to the output workspace + * @param outSpectrumInfo :: The spectrum info object of `out` * @returns True if further processing is not required on the spectra, false if * the binary operation should be performed. */ bool BinaryOperation::propagateSpectraMask(const SpectrumInfo &lhsSpectrumInfo, const SpectrumInfo &rhsSpectrumInfo, const int64_t index, - API::MatrixWorkspace &out) { + MatrixWorkspace &out, + SpectrumInfo &outSpectrumInfo) { bool continueOp(true); if ((lhsSpectrumInfo.hasDetectors(index) && @@ -451,7 +453,8 @@ bool BinaryOperation::propagateSpectraMask(const SpectrumInfo &lhsSpectrumInfo, (rhsSpectrumInfo.hasDetectors(index) && rhsSpectrumInfo.isMasked(index))) { continueOp = false; - out.maskWorkspaceIndex(index); + out.getSpectrum(index).clearData(); + outSpectrumInfo.setMasked(index, true); } return continueOp; } @@ -517,6 +520,7 @@ void BinaryOperation::doSingleColumn() { // value from each m_rhs 'spectrum' // and then calling the virtual function const int64_t numHists = m_lhs->getNumberHistograms(); + auto &outSpectrumInfo = m_out->mutableSpectrumInfo(); auto &lhsSpectrumInfo = m_lhs->spectrumInfo(); auto &rhsSpectrumInfo = m_rhs->spectrumInfo(); if (m_eout) { @@ -528,7 +532,8 @@ void BinaryOperation::doSingleColumn() { const double rhsE = m_rhs->readE(i)[0]; // m_out->setX(i, m_lhs->refX(i)); //unnecessary - that was copied before. - if (propagateSpectraMask(lhsSpectrumInfo, rhsSpectrumInfo, i, *m_out)) { + if (propagateSpectraMask(lhsSpectrumInfo, rhsSpectrumInfo, i, *m_out, + outSpectrumInfo)) { performEventBinaryOperation(m_eout->getSpectrum(i), rhsY, rhsE); } m_progress->report(this->name()); @@ -544,7 +549,8 @@ void BinaryOperation::doSingleColumn() { const double rhsE = m_rhs->readE(i)[0]; m_out->setX(i, m_lhs->refX(i)); - if (propagateSpectraMask(lhsSpectrumInfo, rhsSpectrumInfo, i, *m_out)) { + if (propagateSpectraMask(lhsSpectrumInfo, rhsSpectrumInfo, i, *m_out, + outSpectrumInfo)) { // Get reference to output vectors here to break any sharing outside the // function call below // where the order of argument evaluation is not guaranteed (if it's @@ -668,6 +674,7 @@ void BinaryOperation::do2D(bool mismatchedSpectra) { // TODO: Check if this works for event workspaces... propagateBinMasks(m_rhs, m_out); + auto &outSpectrumInfo = m_out->mutableSpectrumInfo(); auto &lhsSpectrumInfo = m_lhs->spectrumInfo(); auto &rhsSpectrumInfo = m_rhs->spectrumInfo(); @@ -690,8 +697,8 @@ void BinaryOperation::do2D(bool mismatchedSpectra) { continue; } else { // Check for masking except when mismatched sizes - if (!propagateSpectraMask(lhsSpectrumInfo, rhsSpectrumInfo, i, - *m_out)) + if (!propagateSpectraMask(lhsSpectrumInfo, rhsSpectrumInfo, i, *m_out, + outSpectrumInfo)) continue; } // Reach here? Do the division @@ -723,8 +730,8 @@ void BinaryOperation::do2D(bool mismatchedSpectra) { continue; } else { // Check for masking except when mismatched sizes - if (!propagateSpectraMask(lhsSpectrumInfo, rhsSpectrumInfo, i, - *m_out)) + if (!propagateSpectraMask(lhsSpectrumInfo, rhsSpectrumInfo, i, *m_out, + outSpectrumInfo)) continue; } @@ -762,7 +769,8 @@ void BinaryOperation::do2D(bool mismatchedSpectra) { continue; } else { // Check for masking except when mismatched sizes - if (!propagateSpectraMask(lhsSpectrumInfo, rhsSpectrumInfo, i, *m_out)) + if (!propagateSpectraMask(lhsSpectrumInfo, rhsSpectrumInfo, i, *m_out, + outSpectrumInfo)) continue; } // Reach here? Do the division diff --git a/Framework/Algorithms/src/CalculateEfficiency.cpp b/Framework/Algorithms/src/CalculateEfficiency.cpp index 65a086e197f0e222b282df61b3601b58b349da3c..4f4a2fb67d5347fd3085ca622e19b2ca71dbc479 100644 --- a/Framework/Algorithms/src/CalculateEfficiency.cpp +++ b/Framework/Algorithms/src/CalculateEfficiency.cpp @@ -311,8 +311,11 @@ void CalculateEfficiency::maskComponent(MatrixWorkspace &ws, } } auto indexList = ws.getIndicesFromDetectorIDs(detectorList); - for (const auto &idx : indexList) - ws.maskWorkspaceIndex(idx); + auto &spectrumInfo = ws.mutableSpectrumInfo(); + for (const auto &idx : indexList) { + ws.getSpectrum(idx).clearData(); + spectrumInfo.setMasked(idx, true); + } } catch (std::exception &) { g_log.warning("Expecting the component " + componentName + " to be a CompAssembly, e.g., a bank. Component not masked!"); diff --git a/Framework/Algorithms/src/ClearMaskFlag.cpp b/Framework/Algorithms/src/ClearMaskFlag.cpp index dfa7f3a53e68d50b6c096d9c49fbb7d33b5fdf46..4e9c7fcba0bc913cd5129834133e180db52fad51 100644 --- a/Framework/Algorithms/src/ClearMaskFlag.cpp +++ b/Framework/Algorithms/src/ClearMaskFlag.cpp @@ -1,9 +1,8 @@ #include "MantidAlgorithms/ClearMaskFlag.h" +#include "MantidAPI/DetectorInfo.h" #include "MantidAPI/MatrixWorkspace.h" -#include "MantidGeometry/Instrument/ParameterMap.h" -#include "MantidGeometry/Instrument/Detector.h" -#include "MantidGeometry/Instrument/Component.h" +#include "MantidGeometry/IDetector.h" #include "MantidGeometry/Instrument.h" namespace Mantid { @@ -16,7 +15,6 @@ using Kernel::Direction; // Register the algorithm into the AlgorithmFactory DECLARE_ALGORITHM(ClearMaskFlag) -//---------------------------------------------------------------------------------------------- /// Algorithm's name for identification. @see Algorithm::name const std::string ClearMaskFlag::name() const { return "ClearMaskFlag"; } @@ -28,7 +26,6 @@ const std::string ClearMaskFlag::category() const { return "Transforms\\Masking"; } -//---------------------------------------------------------------------------------------------- /** Initialize the algorithm's properties. */ void ClearMaskFlag::init() { @@ -41,28 +38,22 @@ void ClearMaskFlag::init() { "the whole instrument."); } -//---------------------------------------------------------------------------------------------- /** Execute the algorithm. */ void ClearMaskFlag::exec() { MatrixWorkspace_sptr ws = getProperty("Workspace"); std::string componentName = getPropertyValue("ComponentName"); - - // Clear the mask flags - Geometry::ParameterMap &pmap = ws->instrumentParameters(); + auto &detectorInfo = ws->mutableDetectorInfo(); if (!componentName.empty()) { - auto instrument = ws->getInstrument(); - auto component = instrument->getComponentByName(componentName); - boost::shared_ptr<const Geometry::ICompAssembly> componentAssembly = - boost::dynamic_pointer_cast<const Geometry::ICompAssembly>(component); - std::vector<Geometry::IComponent_const_sptr> children; - componentAssembly->getChildren(children, true); - for (auto det : children) { - pmap.addBool(det.get(), "masked", false); + std::vector<IDetector_const_sptr> detectors; + ws->getInstrument()->getDetectorsInBank(detectors, componentName); + for (const auto &det : detectors) { + auto index = detectorInfo.indexOf(det->getID()); + detectorInfo.setMasked(index, false); } } else { - pmap.clearParametersByName("masked"); + detectorInfo.clearMaskFlags(); } } diff --git a/Framework/Algorithms/src/ConvertAxisByFormula.cpp b/Framework/Algorithms/src/ConvertAxisByFormula.cpp index 5941af7807e84f817f720ee98027f19a5d52d29c..ada62fb7d4e67eb951a6db5656442b4f7a2f0481 100644 --- a/Framework/Algorithms/src/ConvertAxisByFormula.cpp +++ b/Framework/Algorithms/src/ConvertAxisByFormula.cpp @@ -178,7 +178,7 @@ void ConvertAxisByFormula::exec() { if ((isRaggedBins) || (isGeometryRequired)) { // ragged bins or geometry used - we have to calculate for every spectra size_t numberOfSpectra_i = outputWs->getNumberHistograms(); - const auto &spectrumInfo = outputWs->spectrumInfo(); + auto &spectrumInfo = outputWs->mutableSpectrumInfo(); size_t failedDetectorCount = 0; Progress prog(this, 0.6, 1.0, numberOfSpectra_i); @@ -192,7 +192,8 @@ void ConvertAxisByFormula::exec() { // both handled the same way { // could not find the geometry info for this spectra - outputWs->maskWorkspaceIndex(i); + outputWs->getSpectrum(i).clearData(); + spectrumInfo.setMasked(i, true); failedDetectorCount++; } prog.report(); diff --git a/Framework/Algorithms/src/ConvertUnits.cpp b/Framework/Algorithms/src/ConvertUnits.cpp index 47cac08c4a46ba48e122dfdd74e4389d87d4af8d..95af11ae5422a6e5692963428ee50045b650220b 100644 --- a/Framework/Algorithms/src/ConvertUnits.cpp +++ b/Framework/Algorithms/src/ConvertUnits.cpp @@ -543,7 +543,7 @@ ConvertUnits::convertViaTOF(Kernel::Unit_const_sptr fromUnit, boost::dynamic_pointer_cast<EventWorkspace>(outputWS); assert(static_cast<bool>(eventWS) == m_inputEvents); // Sanity check - const auto &outSpectrumInfo = outputWS->spectrumInfo(); + auto &outSpectrumInfo = outputWS->mutableSpectrumInfo(); // Loop over the histograms (detector spectra) for (int64_t i = 0; i < numberOfSpectra_i; ++i) { double efixed = efixedProp; @@ -581,7 +581,9 @@ ConvertUnits::convertViaTOF(Kernel::Unit_const_sptr fromUnit, // detectors, this call is // the same as just zeroing out the data (calling clearData on the // spectrum) - outputWS->maskWorkspaceIndex(i); + outputWS->getSpectrum(i).clearData(); + if (outSpectrumInfo.hasDetectors(i)) + outSpectrumInfo.setMasked(i, true); } prog.report("Convert to " + m_outputUnit->unitID()); diff --git a/Framework/Algorithms/src/ConvertUnitsUsingDetectorTable.cpp b/Framework/Algorithms/src/ConvertUnitsUsingDetectorTable.cpp index 9906fb3a512a4d65e02ca9485a32508cb45d996c..06a58c53fcc156abac792cc1a3c0da8385bffae1 100644 --- a/Framework/Algorithms/src/ConvertUnitsUsingDetectorTable.cpp +++ b/Framework/Algorithms/src/ConvertUnitsUsingDetectorTable.cpp @@ -4,6 +4,7 @@ #include "MantidDataObjects/TableWorkspace.h" #include "MantidAPI/WorkspaceUnitValidator.h" #include "MantidAPI/HistogramValidator.h" +#include "MantidAPI/SpectrumInfo.h" #include "MantidGeometry/IDetector.h" #include "MantidKernel/CompositeValidator.h" #include "MantidKernel/ListValidator.h" @@ -174,6 +175,8 @@ MatrixWorkspace_sptr ConvertUnitsUsingDetectorTable::convertViaTOF( boost::dynamic_pointer_cast<EventWorkspace>(outputWS); assert(static_cast<bool>(eventWS) == m_inputEvents); // Sanity check + auto &spectrumInfo = outputWS->mutableSpectrumInfo(); + // TODO: Check why this parallel stuff breaks // Loop over the histograms (detector spectra) // PARALLEL_FOR_IF(Kernel::threadSafe(*outputWS)) @@ -248,7 +251,9 @@ MatrixWorkspace_sptr ConvertUnitsUsingDetectorTable::convertViaTOF( } else { // Not found failedDetectorCount++; - outputWS->maskWorkspaceIndex(wsid); + outputWS->getSpectrum(wsid).clearData(); + if (spectrumInfo.hasDetectors(wsid)) + spectrumInfo.setMasked(wsid, true); } } catch (Exception::NotFoundError &) { @@ -258,7 +263,7 @@ MatrixWorkspace_sptr ConvertUnitsUsingDetectorTable::convertViaTOF( // detectors, this call is // the same as just zeroing out the data (calling clearData on the // spectrum) - outputWS->maskWorkspaceIndex(i); + outputWS->getSpectrum(i).clearData(); } prog.report("Convert to " + m_outputUnit->unitID()); diff --git a/Framework/Algorithms/src/CreateGroupingWorkspace.cpp b/Framework/Algorithms/src/CreateGroupingWorkspace.cpp index 5abcdff721f5232a02fcfb099412c06f3e88e225..3c2cbe2ab2f1b5808a45b8b8bfe04e43524ff0f3 100644 --- a/Framework/Algorithms/src/CreateGroupingWorkspace.cpp +++ b/Framework/Algorithms/src/CreateGroupingWorkspace.cpp @@ -71,11 +71,13 @@ void CreateGroupingWorkspace::init() { "Use / or , to separate multiple groups. " "If empty, then an empty GroupingWorkspace will be created."); - std::vector<std::string> grouping{"", "All", "Group", "Column", "bank"}; + std::vector<std::string> grouping{"", "All", "Group", "2_4Grouping", "Column", + "bank"}; declareProperty( "GroupDetectorsBy", "", boost::make_shared<StringListValidator>(grouping), "Only used if GroupNames is empty: All detectors as one group, Groups " - "(East,West for SNAP), Columns for SNAP, detector banks"); + "(Group or East,West for SNAP), 2_4Grouping (SNAP), Columns, detector " + "banks"); declareProperty("MaxRecursionDepth", 5, "Number of levels to search into the instrument (default=5)"); @@ -355,12 +357,23 @@ void CreateGroupingWorkspace::exec() { inst = tempWS->getInstrument(); } + // Validation for 2_4Grouping input used only for SNAP + if (inst->getName().compare("SNAP") != 0 && + grouping.compare("2_4Grouping") == 0) { + const std::string message("2_4Grouping only works for SNAP."); + g_log.error(message); + throw std::invalid_argument(message); + } + if (GroupNames.empty() && OldCalFilename.empty()) { if (grouping.compare("All") == 0) { GroupNames = inst->getName(); } else if (inst->getName().compare("SNAP") == 0 && grouping.compare("Group") == 0) { GroupNames = "East,West"; + } else if (inst->getName().compare("SNAP") == 0 && + grouping.compare("2_4Grouping") == 0) { + GroupNames = "Column1,Column2,Column3,Column4,Column5,Column6,"; } else { sortnames = true; GroupNames = ""; @@ -392,9 +405,20 @@ void CreateGroupingWorkspace::exec() { Progress prog(this, 0.2, 1.0, outWS->getNumberHistograms()); // Make the grouping one of three ways: - if (!GroupNames.empty()) + if (!GroupNames.empty()) { detIDtoGroup = makeGroupingByNames(GroupNames, inst, prog, sortnames); - else if (!OldCalFilename.empty()) + if (grouping.compare("2_4Grouping") == 0) { + std::map<detid_t, int>::const_iterator it_end = detIDtoGroup.end(); + std::map<detid_t, int>::const_iterator it; + for (it = detIDtoGroup.begin(); it != it_end; ++it) { + if (it->second < 5) + detIDtoGroup[it->first] = 1; + else + detIDtoGroup[it->first] = 2; + } + } + + } else if (!OldCalFilename.empty()) detIDtoGroup = readGroupingFile(OldCalFilename, prog); else if ((numGroups > 0) && !componentName.empty()) detIDtoGroup = diff --git a/Framework/Algorithms/src/DetectorDiagnostic.cpp b/Framework/Algorithms/src/DetectorDiagnostic.cpp index dbb315c6bfb33b7ac14cbbbe97676f9e383caabb..7ddf392551b294aefd488a92f5b0987480e81dbb 100644 --- a/Framework/Algorithms/src/DetectorDiagnostic.cpp +++ b/Framework/Algorithms/src/DetectorDiagnostic.cpp @@ -1,7 +1,5 @@ -//-------------------------------------------------------------------------- -// Includes -//-------------------------------------------------------------------------- #include "MantidAlgorithms/DetectorDiagnostic.h" +#include "MantidAPI/SpectrumInfo.h" #include "MantidAPI/WorkspaceFactory.h" #include "MantidDataObjects/EventWorkspaceHelpers.h" #include "MantidDataObjects/MaskWorkspace.h" @@ -608,29 +606,26 @@ std::vector<double> DetectorDiagnostic::calculateMedian( std::vector<double> medianvec; g_log.debug("Calculating the median count rate of the spectra"); + bool checkForMask = false; + Geometry::Instrument_const_sptr instrument = input.getInstrument(); + if (instrument != nullptr) { + checkForMask = ((instrument->getSource() != nullptr) && + (instrument->getSample() != nullptr)); + } + const auto &spectrumInfo = input.spectrumInfo(); + for (const auto &hists : indexmap) { std::vector<double> medianInput; const int nhists = static_cast<int>(hists.size()); // The maximum possible length is that of workspace length medianInput.reserve(nhists); - bool checkForMask = false; - Geometry::Instrument_const_sptr instrument = input.getInstrument(); - if (instrument != nullptr) { - checkForMask = ((instrument->getSource() != nullptr) && - (instrument->getSample() != nullptr)); - } - PARALLEL_FOR_IF(Kernel::threadSafe(input)) for (int i = 0; i < nhists; ++i) { // NOLINT PARALLEL_START_INTERUPT_REGION - if (checkForMask) { - const std::set<detid_t> &detids = - input.getSpectrum(hists[i]).getDetectorIDs(); - if (instrument->isDetectorMasked(detids)) - continue; - if (instrument->isMonitor(detids)) + if (checkForMask && spectrumInfo.hasDetectors(hists[i])) { + if (spectrumInfo.isMasked(hists[i]) || spectrumInfo.isMonitor(hists[i])) continue; } diff --git a/Framework/Algorithms/src/DiffractionFocussing2.cpp b/Framework/Algorithms/src/DiffractionFocussing2.cpp index 16f90e20fd8d1121b648fd4f3f79d1d07d620366..9d0cd8f42e073a0ea68e50528e97d02139bc0e36 100644 --- a/Framework/Algorithms/src/DiffractionFocussing2.cpp +++ b/Framework/Algorithms/src/DiffractionFocussing2.cpp @@ -6,6 +6,7 @@ #include "MantidAPI/MatrixWorkspace.h" #include "MantidAPI/RawCountValidator.h" #include "MantidAPI/SpectraAxis.h" +#include "MantidAPI/SpectrumInfo.h" #include "MantidAPI/WorkspaceFactory.h" #include "MantidDataObjects/EventWorkspace.h" #include "MantidDataObjects/GroupingWorkspace.h" @@ -559,6 +560,7 @@ void DiffractionFocussing2::determineRebinParameters() { checkForMask = ((instrument->getSource() != nullptr) && (instrument->getSample() != nullptr)); } + const auto &spectrumInfo = m_matrixInputW->spectrumInfo(); groupAtWorkspaceIndex.resize(nHist); for (int wi = 0; wi < nHist; @@ -569,10 +571,8 @@ void DiffractionFocussing2::determineRebinParameters() { if (group == -1) continue; - // the spectrum is the real thing we want to work with - const auto &spec = m_matrixInputW->getSpectrum(wi); if (checkForMask) { - if (instrument->isDetectorMasked(spec.getDetectorIDs())) { + if (spectrumInfo.isMasked(wi)) { groupAtWorkspaceIndex[wi] = -1; continue; } @@ -586,7 +586,7 @@ void DiffractionFocussing2::determineRebinParameters() { } const double min = (gpit->second).first; const double max = (gpit->second).second; - auto &X = spec.x(); + auto &X = m_matrixInputW->x(wi); double temp = X.front(); if (temp < (min)) // New Xmin found (gpit->second).first = temp; diff --git a/Framework/Algorithms/src/ExtractMask.cpp b/Framework/Algorithms/src/ExtractMask.cpp index 4c735bd8db9d69a8b84378a4f35949a62ba7db90..bd2a694cd77f5ecfedc4e0db4381031a9769946d 100644 --- a/Framework/Algorithms/src/ExtractMask.cpp +++ b/Framework/Algorithms/src/ExtractMask.cpp @@ -80,10 +80,6 @@ void ExtractMask::exec() { } PARALLEL_CHECK_INTERUPT_REGION - // Clear all the "masked" bits on the output masked workspace - Geometry::ParameterMap &pmap = maskWS->instrumentParameters(); - pmap.clearParametersByName("masked"); - g_log.information() << maskWS->getNumberMasked() << " spectra are masked\n"; g_log.information() << detectorList.size() << " detectors are masked\n"; setProperty("OutputWorkspace", maskWS); diff --git a/Framework/Algorithms/src/GetDetOffsetsMultiPeaks.cpp b/Framework/Algorithms/src/GetDetOffsetsMultiPeaks.cpp index 9f4f0beb3356eaf24905c8d998f1e7bad3a5e277..62e6f045441106f0d8ad7c4a4807b4f4f2a36693 100644 --- a/Framework/Algorithms/src/GetDetOffsetsMultiPeaks.cpp +++ b/Framework/Algorithms/src/GetDetOffsetsMultiPeaks.cpp @@ -7,6 +7,7 @@ #include "MantidAPI/IPeakFunction.h" #include "MantidAPI/IBackgroundFunction.h" #include "MantidAPI/TableRow.h" +#include "MantidAPI/SpectrumInfo.h" #include "MantidAPI/WorkspaceFactory.h" #include "MantidAPI/WorkspaceUnitValidator.h" #include "MantidDataObjects/EventWorkspace.h" @@ -475,6 +476,7 @@ void GetDetOffsetsMultiPeaks::calculateDetectorsOffsets() { // Fit all the spectra with a gaussian Progress prog(this, 0, 1.0, nspec); + auto &spectrumInfo = m_maskWS->mutableSpectrumInfo(); // cppcheck-suppress syntaxError PRAGMA_OMP(parallel for schedule(dynamic, 1) ) for (int wi = 0; wi < nspec; ++wi) { @@ -509,7 +511,8 @@ void GetDetOffsetsMultiPeaks::calculateDetectorsOffsets() { const size_t workspaceIndex = mapEntry->second; if (offsetresult.mask > 0.9) { // Being masked - m_maskWS->maskWorkspaceIndex(workspaceIndex); + m_maskWS->getSpectrum(workspaceIndex).clearData(); + spectrumInfo.setMasked(workspaceIndex, true); m_maskWS->mutableY(workspaceIndex)[0] = offsetresult.mask; } else { // Using the detector diff --git a/Framework/Algorithms/src/GetDetectorOffsets.cpp b/Framework/Algorithms/src/GetDetectorOffsets.cpp index 5ce99a549b31ded3c5c9594601522212aa645330..e7cdc66de35303c94659427317c17ef8f6693543 100644 --- a/Framework/Algorithms/src/GetDetectorOffsets.cpp +++ b/Framework/Algorithms/src/GetDetectorOffsets.cpp @@ -3,6 +3,7 @@ #include "MantidAPI/FileProperty.h" #include "MantidAPI/FunctionFactory.h" #include "MantidAPI/IPeakFunction.h" +#include "MantidAPI/SpectrumInfo.h" #include "MantidAPI/WorkspaceUnitValidator.h" #include "MantidDataObjects/MaskWorkspace.h" #include "MantidDataObjects/OffsetsWorkspace.h" @@ -108,6 +109,7 @@ void GetDetectorOffsets::exec() { // Fit all the spectra with a gaussian Progress prog(this, 0, 1.0, nspec); + auto &spectrumInfo = maskWS->mutableSpectrumInfo(); PARALLEL_FOR_IF(Kernel::threadSafe(*inputW)) for (int wi = 0; wi < nspec; ++wi) { PARALLEL_START_INTERUPT_REGION @@ -134,7 +136,8 @@ void GetDetectorOffsets::exec() { const size_t workspaceIndex = mapEntry->second; if (mask == 1.) { // Being masked - maskWS->maskWorkspaceIndex(workspaceIndex); + maskWS->getSpectrum(workspaceIndex).clearData(); + spectrumInfo.setMasked(workspaceIndex, true); maskWS->mutableY(workspaceIndex)[0] = mask; } else { // Using the detector diff --git a/Framework/Algorithms/src/He3TubeEfficiency.cpp b/Framework/Algorithms/src/He3TubeEfficiency.cpp index 4ada8afdb2379ac750d6ccd18e77dfa9399155dd..3acdde5862ddce38dcaf2b704511e6c9dd571721 100644 --- a/Framework/Algorithms/src/He3TubeEfficiency.cpp +++ b/Framework/Algorithms/src/He3TubeEfficiency.cpp @@ -2,6 +2,7 @@ #include "MantidAPI/Axis.h" #include "MantidAPI/HistogramValidator.h" #include "MantidAPI/InstrumentValidator.h" +#include "MantidAPI/SpectrumInfo.h" #include "MantidAPI/WorkspaceUnitValidator.h" #include "MantidAPI/WorkspaceFactory.h" #include "MantidDataObjects/EventWorkspace.h" @@ -423,6 +424,7 @@ void He3TubeEfficiency::execEvent() { boost::dynamic_pointer_cast<DataObjects::EventWorkspace>(matrixOutputWS); std::size_t numHistograms = outputWS->getNumberHistograms(); + auto &spectrumInfo = outputWS->mutableSpectrumInfo(); this->progress = new API::Progress(this, 0.0, 1.0, numHistograms); PARALLEL_FOR_IF(Kernel::threadSafe(*outputWS)) for (int i = 0; i < static_cast<int>(numHistograms); ++i) { @@ -440,7 +442,8 @@ void He3TubeEfficiency::execEvent() { // Parameters are bad so skip correction PARALLEL_CRITICAL(deteff_invalid) { this->spectraSkipped.push_back(outputWS->getAxis(1)->spectraNo(i)); - outputWS->maskWorkspaceIndex(i); + outputWS->getSpectrum(i).clearData(); + spectrumInfo.setMasked(i, true); } } diff --git a/Framework/Algorithms/src/MedianDetectorTest.cpp b/Framework/Algorithms/src/MedianDetectorTest.cpp index 8844f32e172146c517f6e2be5ffcba795eda476d..3d20253d46ce421b4b5146327732f2d70758b851 100644 --- a/Framework/Algorithms/src/MedianDetectorTest.cpp +++ b/Framework/Algorithms/src/MedianDetectorTest.cpp @@ -1,5 +1,6 @@ #include "MantidAlgorithms/MedianDetectorTest.h" #include "MantidAPI/HistogramValidator.h" +#include "MantidAPI/SpectrumInfo.h" #include "MantidKernel/BoundedValidator.h" #include <cmath> @@ -246,6 +247,7 @@ int MedianDetectorTest::maskOutliers( checkForMask = ((instrument->getSource() != nullptr) && (instrument->getSample() != nullptr)); } + auto &spectrumInfo = countsWS->mutableSpectrumInfo(); for (size_t i = 0; i < indexmap.size(); ++i) { std::vector<size_t> &hists = indexmap[i]; @@ -255,17 +257,19 @@ int MedianDetectorTest::maskOutliers( for (int j = 0; j < static_cast<int>(hists.size()); ++j) { // NOLINT const double value = countsWS->y(hists[j])[0]; if ((value == 0.) && checkForMask) { - const auto &detids = countsWS->getSpectrum(hists[j]).getDetectorIDs(); - if (instrument->isDetectorMasked(detids)) { + if (spectrumInfo.hasDetectors(hists[j]) && + spectrumInfo.isMasked(hists[j])) { numFailed -= 1; // it was already masked } } if ((value < out_lo * median) && (value > 0.0)) { - countsWS->maskWorkspaceIndex(hists[j]); + countsWS->getSpectrum(hists[j]).clearData(); + spectrumInfo.setMasked(hists[j], true); PARALLEL_ATOMIC ++numFailed; } else if (value > out_hi * median) { - countsWS->maskWorkspaceIndex(hists[j]); + countsWS->getSpectrum(hists[j]).clearData(); + spectrumInfo.setMasked(hists[j], true); PARALLEL_ATOMIC ++numFailed; } @@ -313,6 +317,7 @@ int MedianDetectorTest::doDetectorTests( checkForMask = ((instrument->getSource() != nullptr) && (instrument->getSample() != nullptr)); } + const auto &spectrumInfo = countsWS->spectrumInfo(); PARALLEL_FOR_IF(Kernel::threadSafe(*countsWS, *maskWS)) for (int j = 0; j < static_cast<int>(indexmap.size()); ++j) { @@ -331,14 +336,12 @@ int MedianDetectorTest::doDetectorTests( numSpec)); } - if (checkForMask) { - const auto &detids = - countsWS->getSpectrum(hists.at(i)).getDetectorIDs(); - if (instrument->isDetectorMasked(detids)) { + if (checkForMask && spectrumInfo.hasDetectors(hists.at(i))) { + if (spectrumInfo.isMasked(hists.at(i))) { maskWS->mutableY(hists.at(i))[0] = deadValue; continue; } - if (instrument->isMonitor(detids)) { + if (spectrumInfo.isMonitor(hists.at(i))) { // Don't include in calculation but don't mask it continue; } diff --git a/Framework/Algorithms/src/Qxy.cpp b/Framework/Algorithms/src/Qxy.cpp index 42d8cc3181becfd31991e61c044d7c0fbd8caa71..5a711f89b1e70fa66024d32bd1de66fa1cd932b3 100644 --- a/Framework/Algorithms/src/Qxy.cpp +++ b/Framework/Algorithms/src/Qxy.cpp @@ -1,5 +1,6 @@ #include "MantidAlgorithms/Qxy.h" #include "MantidAPI/BinEdgeAxis.h" +#include "MantidAPI/DetectorInfo.h" #include "MantidAPI/HistogramValidator.h" #include "MantidAPI/InstrumentValidator.h" #include "MantidAPI/SpectrumInfo.h" @@ -362,10 +363,8 @@ Qxy::setUpOutputWorkspace(API::MatrixWorkspace_const_sptr inputWorkspace) { MatrixWorkspace_sptr outputWorkspace = WorkspaceFactory::Instance().create( inputWorkspace, bins - 1, bins, bins - 1); // ... but clear the masking from the parameter map as we don't want to carry - // that over since this is essentially - // a 2D rebin - ParameterMap &pmap = outputWorkspace->instrumentParameters(); - pmap.clearParametersByName("masked"); + // that over since this is essentially a 2D rebin + outputWorkspace->mutableDetectorInfo().clearMaskFlags(); // Create a numeric axis to replace the vertical one Axis *verticalAxis = new BinEdgeAxis(bins); diff --git a/Framework/Algorithms/src/Stitch1DMany.cpp b/Framework/Algorithms/src/Stitch1DMany.cpp index 041768ed7f26531995e8b78313e1a26a013c6f57..482b4c769eb05fd71c71d9632cf54a9d7ec0c14e 100644 --- a/Framework/Algorithms/src/Stitch1DMany.cpp +++ b/Framework/Algorithms/src/Stitch1DMany.cpp @@ -136,13 +136,6 @@ std::map<std::string, std::string> Stitch1DMany::validateInputs() { if (m_params.empty()) errors["Params"] = "At least one parameter must be given."; - if (!m_scaleRHSWorkspace) { - // Flip these around for processing - std::reverse(m_inputWorkspaces.begin(), m_inputWorkspaces.end()); - std::reverse(m_startOverlaps.begin(), m_startOverlaps.end()); - std::reverse(m_endOverlaps.begin(), m_endOverlaps.end()); - } - m_scaleFactors.clear(); m_outputWorkspace.reset(); diff --git a/Framework/Algorithms/src/SumSpectra.cpp b/Framework/Algorithms/src/SumSpectra.cpp index 95c16d6ba4c91dd4cde6d92a6bac836651be185f..4ca13b070ea8b2c9ace2dc3f3c12dbc0fde5a39f 100644 --- a/Framework/Algorithms/src/SumSpectra.cpp +++ b/Framework/Algorithms/src/SumSpectra.cpp @@ -20,7 +20,8 @@ using namespace DataObjects; SumSpectra::SumSpectra() : API::Algorithm(), m_outSpecNum(0), m_minWsInd(0), m_maxWsInd(0), - m_keepMonitors(false), m_numberOfSpectra(0), m_yLength(0), m_indices(), + m_keepMonitors(false), m_replaceSpecialValues(false), + m_numberOfSpectra(0), m_yLength(0), m_indices(), m_calculateWeightedSum(false) {} /** Initialisation method. @@ -68,6 +69,10 @@ void SumSpectra::init() { "values with zero error are dropped from the summation. To " "estimate the number of dropped values see the " "description. "); + + declareProperty("RemoveSpecialValues", false, + "If enabled floating point special values such as NaN or Inf" + " are removed before the spectra are summed."); } /** Executes the algorithm @@ -80,6 +85,7 @@ void SumSpectra::exec() { const std::vector<int> indices_list = getProperty("ListOfWorkspaceIndices"); m_keepMonitors = getProperty("IncludeMonitors"); + m_replaceSpecialValues = getProperty("RemoveSpecialValues"); // Get the input workspace MatrixWorkspace_const_sptr localworkspace = getProperty("InputWorkspace"); @@ -140,7 +146,7 @@ void SumSpectra::exec() { size_t numMasked(0); // total number of the masked and skipped spectra size_t numZeros(0); // number of spectra which have 0 value in the first // column (used in special cases of evaluating how good - // Puasonian statistics is) + // Poissonian statistics is) Progress progress(this, 0, 1, this->m_indices.size()); @@ -158,8 +164,7 @@ void SumSpectra::exec() { this->doRebinnedOutput(outputWorkspace, progress, numSpectra, numMasked, numZeros); } else { - this->doWorkspace2D(localworkspace, outSpec, progress, numSpectra, - numMasked, numZeros); + this->doWorkspace2D(outSpec, progress, numSpectra, numMasked, numZeros); } // Pointer to sqrt function @@ -211,9 +216,33 @@ SumSpectra::getOutputSpecNo(MatrixWorkspace_const_sptr localworkspace) { return specId; } +/** + * Calls an algorithm to replace special values within the workspace + * such as NaN or Inf to 0. + * @param inputWs The workspace to process + * @return The workspace with special floating point values set to 0 + */ +API::MatrixWorkspace_sptr +SumSpectra::replaceSpecialValues(API::MatrixWorkspace_sptr inputWs) { + if (!m_replaceSpecialValues) { + // Skip any additional processing + return inputWs; + } + + IAlgorithm_sptr alg = this->createChildAlgorithm("ReplaceSpecialValues"); + alg->setProperty<MatrixWorkspace_sptr>("InputWorkspace", inputWs); + std::string outName = "_" + inputWs->getName() + "_clean"; + alg->setProperty("OutputWorkspace", outName); + alg->setProperty("NaNValue", 0.0); + alg->setProperty("NaNError", 0.0); + alg->setProperty("InfinityValue", 0.0); + alg->setProperty("InfinityError", 0.0); + alg->executeAsChildAlg(); + return alg->getProperty("OutputWorkspace"); +} + /** * This function deals with the logic necessary for summing a Workspace2D. - * @param localworkspace The input workspace for summing. * @param outSpec The spectrum for the summed output. * @param progress The progress indicator. * @param numSpectra The number of spectra contributed to the sum. @@ -222,69 +251,73 @@ SumSpectra::getOutputSpecNo(MatrixWorkspace_const_sptr localworkspace) { * @param numZeros The number of zero bins in histogram workspace or empty * spectra for event workspace. */ -void SumSpectra::doWorkspace2D(MatrixWorkspace_const_sptr localworkspace, - ISpectrum &outSpec, Progress &progress, +void SumSpectra::doWorkspace2D(ISpectrum &outSpec, Progress &progress, size_t &numSpectra, size_t &numMasked, size_t &numZeros) { // Get references to the output workspaces's data vectors - auto &YSum = outSpec.mutableY(); - auto &YError = outSpec.mutableE(); + auto &OutputYSum = outSpec.mutableY(); + auto &OutputYError = outSpec.mutableE(); std::vector<double> Weight; std::vector<size_t> nZeros; if (m_calculateWeightedSum) { - Weight.assign(YSum.size(), 0); - nZeros.assign(YSum.size(), 0); + Weight.assign(OutputYSum.size(), 0); + nZeros.assign(OutputYSum.size(), 0); } numSpectra = 0; numMasked = 0; numZeros = 0; + MatrixWorkspace_sptr in_ws = getProperty("InputWorkspace"); + // Clean workspace of any NANs or Inf values + auto localworkspace = replaceSpecialValues(in_ws); const auto &spectrumInfo = localworkspace->spectrumInfo(); // Loop over spectra - for (const auto i : this->m_indices) { + for (const auto wsIndex : this->m_indices) { // Don't go outside the range. - if ((i >= this->m_numberOfSpectra) || (i < 0)) { - g_log.error() << "Invalid index " << i + if ((wsIndex >= this->m_numberOfSpectra) || (wsIndex < 0)) { + g_log.error() << "Invalid index " << wsIndex << " was specified. Sum was aborted.\n"; break; } - if (spectrumInfo.hasDetectors(i)) { + if (spectrumInfo.hasDetectors(wsIndex)) { // Skip monitors, if the property is set to do so - if (!m_keepMonitors && spectrumInfo.isMonitor(i)) + if (!m_keepMonitors && spectrumInfo.isMonitor(wsIndex)) continue; // Skip masked detectors - if (spectrumInfo.isMasked(i)) { + if (spectrumInfo.isMasked(wsIndex)) { numMasked++; continue; } } numSpectra++; + const auto &YValues = localworkspace->y(wsIndex); + const auto &YErrors = localworkspace->e(wsIndex); + // Retrieve the spectrum into a vector - const auto &YValues = localworkspace->y(i); - const auto &YErrors = localworkspace->e(i); - if (m_calculateWeightedSum) { - for (int k = 0; k < this->m_yLength; ++k) { - if (YErrors[k] != 0) { - double errsq = YErrors[k] * YErrors[k]; - YError[k] += errsq; - Weight[k] += 1. / errsq; - YSum[k] += YValues[k] / errsq; + + for (int i = 0; i < m_yLength; ++i) { + if (m_calculateWeightedSum) { + if (std::isnormal(YErrors[i])) { + const double errsq = YErrors[i] * YErrors[i]; + OutputYError[i] += errsq; + Weight[i] += 1. / errsq; + OutputYSum[i] += YValues[i] / errsq; } else { - nZeros[k]++; + nZeros[i]++; } - } - } else { - for (int k = 0; k < this->m_yLength; ++k) { - YSum[k] += YValues[k]; - YError[k] += YErrors[k] * YErrors[k]; + + } else { + OutputYSum[i] += YValues[i]; + OutputYError[i] += YErrors[i] * YErrors[i]; } } // Map all the detectors onto the spectrum of the output - outSpec.addDetectorIDs(localworkspace->getSpectrum(i).getDetectorIDs()); + outSpec.addDetectorIDs( + localworkspace->getSpectrum(wsIndex).getDetectorIDs()); progress.report(); } @@ -293,7 +326,7 @@ void SumSpectra::doWorkspace2D(MatrixWorkspace_const_sptr localworkspace, numZeros = 0; for (size_t i = 0; i < Weight.size(); i++) { if (numSpectra > nZeros[i]) - YSum[i] *= double(numSpectra - nZeros[i]) / Weight[i]; + OutputYSum[i] *= double(numSpectra - nZeros[i]) / Weight[i]; if (nZeros[i] != 0) numZeros += nZeros[i]; } @@ -312,21 +345,12 @@ void SumSpectra::doRebinnedOutput(MatrixWorkspace_sptr outputWorkspace, Progress &progress, size_t &numSpectra, size_t &numMasked, size_t &numZeros) { // Get a copy of the input workspace - MatrixWorkspace_sptr temp = getProperty("InputWorkspace"); + MatrixWorkspace_sptr in_ws = getProperty("InputWorkspace"); // First, we need to clean the input workspace for nan's and inf's in order // to treat the data correctly later. This will create a new private // workspace that will be retrieved as mutable. - IAlgorithm_sptr alg = this->createChildAlgorithm("ReplaceSpecialValues"); - alg->setProperty<MatrixWorkspace_sptr>("InputWorkspace", temp); - std::string outName = "_" + temp->getName() + "_clean"; - alg->setProperty("OutputWorkspace", outName); - alg->setProperty("NaNValue", 0.0); - alg->setProperty("NaNError", 0.0); - alg->setProperty("InfinityValue", 0.0); - alg->setProperty("InfinityError", 0.0); - alg->executeAsChildAlg(); - MatrixWorkspace_sptr localworkspace = alg->getProperty("OutputWorkspace"); + auto localworkspace = replaceSpecialValues(in_ws); // Transform to real workspace types RebinnedOutput_sptr inWS = diff --git a/Framework/Algorithms/src/WorkspaceJoiners.cpp b/Framework/Algorithms/src/WorkspaceJoiners.cpp index b4f5e7d01617ff2c000eaf8934f908c166212f65..df772064ebd2e57e665a643b7e656febf458e174 100644 --- a/Framework/Algorithms/src/WorkspaceJoiners.cpp +++ b/Framework/Algorithms/src/WorkspaceJoiners.cpp @@ -76,6 +76,7 @@ WorkspaceJoiners::execWS2D(API::MatrixWorkspace_const_sptr ws1, // For second loop we use the offset from the first const int64_t &nhist2 = ws2->getNumberHistograms(); const auto &spectrumInfo = ws2->spectrumInfo(); + auto &outSpectrumInfo = output->mutableSpectrumInfo(); PARALLEL_FOR_IF(Kernel::threadSafe(*ws2, *output)) for (int64_t j = 0; j < nhist2; ++j) { PARALLEL_START_INTERUPT_REGION @@ -95,8 +96,10 @@ WorkspaceJoiners::execWS2D(API::MatrixWorkspace_const_sptr ws1, } } // Propagate spectrum masking - if (spectrumInfo.hasDetectors(j) && spectrumInfo.isMasked(j)) - output->maskWorkspaceIndex(nhist1 + j); + if (spectrumInfo.hasDetectors(j) && spectrumInfo.isMasked(j)) { + output->getSpectrum(nhist1 + j).clearData(); + outSpectrumInfo.setMasked(nhist1 + j, true); + } m_progress->report(); PARALLEL_END_INTERUPT_REGION @@ -137,6 +140,7 @@ MatrixWorkspace_sptr WorkspaceJoiners::execEvent() { // For second loop we use the offset from the first const int64_t &nhist2 = event_ws2->getNumberHistograms(); const auto &spectrumInfo = event_ws2->spectrumInfo(); + auto &outSpectrumInfo = output->mutableSpectrumInfo(); for (int64_t j = 0; j < nhist2; ++j) { // This is the workspace index at which we assign in the output int64_t output_wi = j + nhist1; @@ -144,8 +148,10 @@ MatrixWorkspace_sptr WorkspaceJoiners::execEvent() { // Propagate spectrum masking. First workspace will have been done by the // factory - if (spectrumInfo.hasDetectors(j) && spectrumInfo.isMasked(j)) - output->maskWorkspaceIndex(output_wi); + if (spectrumInfo.hasDetectors(j) && spectrumInfo.isMasked(j)) { + output->getSpectrum(output_wi).clearData(); + outSpectrumInfo.setMasked(output_wi, true); + } m_progress->report(); } diff --git a/Framework/Algorithms/test/AppendSpectraTest.h b/Framework/Algorithms/test/AppendSpectraTest.h index 2cd534ad39cbd6be6b7270ffeb851682777c4977..9620482c5ef629e005b5df3d146212210d402ecb 100644 --- a/Framework/Algorithms/test/AppendSpectraTest.h +++ b/Framework/Algorithms/test/AppendSpectraTest.h @@ -4,6 +4,7 @@ #include "MantidAPI/AnalysisDataService.h" #include "MantidAPI/Axis.h" #include "MantidAPI/FrameworkManager.h" +#include "MantidAPI/SpectrumInfo.h" #include "MantidAlgorithms/AppendSpectra.h" #include "MantidDataHandling/LoadRaw3.h" #include "MantidKernel/TimeSeriesProperty.h" @@ -66,8 +67,10 @@ public: // Mask a spectrum and check it is carried over const size_t maskTop(5), maskBottom(10); - in1->maskWorkspaceIndex(maskTop); - in2->maskWorkspaceIndex(maskBottom); + in1->getSpectrum(maskTop).clearData(); + in2->getSpectrum(maskBottom).clearData(); + in1->mutableSpectrumInfo().setMasked(maskTop, true); + in2->mutableSpectrumInfo().setMasked(maskBottom, true); // Now it should succeed TS_ASSERT_THROWS_NOTHING(alg.setPropertyValue("InputWorkspace1", "top")); diff --git a/Framework/Algorithms/test/ClearMaskFlagTest.h b/Framework/Algorithms/test/ClearMaskFlagTest.h index 33cc62cf37924e5efaae15a1a31ec0f50e24ab5f..91afa209f332d6a04ee56463401054745eb4d617 100644 --- a/Framework/Algorithms/test/ClearMaskFlagTest.h +++ b/Framework/Algorithms/test/ClearMaskFlagTest.h @@ -5,6 +5,7 @@ #include "MantidHistogramData/LinearGenerator.h" #include "MantidAlgorithms/ClearMaskFlag.h" #include "MantidAPI/AnalysisDataService.h" +#include "MantidAPI/DetectorInfo.h" #include "MantidAPI/WorkspaceFactory.h" #include "MantidDataObjects/Workspace2D.h" #include "MantidGeometry/Instrument.h" @@ -58,9 +59,9 @@ public: space2D->setInstrument(instr); // set the mask on a bunch of spectra - Mantid::Geometry::ParameterMap &pmap = space2D->instrumentParameters(); + auto &detectorInfo = space2D->mutableDetectorInfo(); for (int j = 0; j < nummask; ++j) { - pmap.addBool(instr->getDetector(j)->getComponentID(), "masked", true); + detectorInfo.setMasked(j, true); } // register the workspace in the data service @@ -85,9 +86,9 @@ public: return; // check the results - Instrument_const_sptr out_instr = ws->getInstrument(); + const auto &resultDetInfo = ws->detectorInfo(); for (int j = 0; j < numspec; ++j) { - TS_ASSERT(!out_instr->isDetectorMasked(j)); + TS_ASSERT(!resultDetInfo.isMasked(j)); } // remove workspace from the data service. diff --git a/Framework/Algorithms/test/ConjoinWorkspacesTest.h b/Framework/Algorithms/test/ConjoinWorkspacesTest.h index 01e9a2f88dad1b75096bd08dbc0a9ce67c488bf7..fd096e7d1bb777dd655cc30255a857558654adde 100644 --- a/Framework/Algorithms/test/ConjoinWorkspacesTest.h +++ b/Framework/Algorithms/test/ConjoinWorkspacesTest.h @@ -5,6 +5,7 @@ #include "MantidAlgorithms/ConjoinWorkspaces.h" #include "MantidAPI/Axis.h" +#include "MantidAPI/SpectrumInfo.h" #include "MantidAPI/WorkspaceHistory.h" #include "MantidDataHandling/LoadRaw3.h" #include "MantidTestHelpers/WorkspaceCreationHelper.h" @@ -74,8 +75,10 @@ public: // Mask a spectrum and check it is carried over const size_t maskTop(5), maskBottom(10); - in1->maskWorkspaceIndex(maskTop); - in2->maskWorkspaceIndex(maskBottom); + in1->getSpectrum(maskTop).clearData(); + in2->getSpectrum(maskBottom).clearData(); + in1->mutableSpectrumInfo().setMasked(maskTop, true); + in2->mutableSpectrumInfo().setMasked(maskBottom, true); // Check it fails if properties haven't been set TS_ASSERT_THROWS(conj.execute(), std::runtime_error); diff --git a/Framework/Algorithms/test/IntegrateByComponentTest.h b/Framework/Algorithms/test/IntegrateByComponentTest.h index 0ca35f182b98f72259c39cb5382e26f7dd15a674..c39d35bd33f223f7d525ded08e14fd35bf60ec08 100644 --- a/Framework/Algorithms/test/IntegrateByComponentTest.h +++ b/Framework/Algorithms/test/IntegrateByComponentTest.h @@ -3,6 +3,7 @@ #include <cxxtest/TestSuite.h> +#include "MantidAPI/DetectorInfo.h" #include "MantidAlgorithms/IntegrateByComponent.h" #include "MantidDataObjects/Workspace2D.h" #include "MantidGeometry/Instrument/ParameterMap.h" @@ -244,12 +245,11 @@ private: ws2D->setInstrument( ComponentCreationHelper::createTestInstrumentRectangular(3, 2, 0)); - Mantid::Geometry::ParameterMap &pmap = ws2D->instrumentParameters(); + auto &detectorInfo = ws2D->mutableDetectorInfo(); for (int i = 0; i < nSpectra; i++) { ws2D->getSpectrum(i).setDetectorID(i + 4); if (mask && (i % 4 == 0)) { - Mantid::Geometry::IDetector_const_sptr det = ws2D->getDetector(i); - pmap.addBool(det.get(), "masked", true); + detectorInfo.setMasked(i, true); } } diff --git a/Framework/Algorithms/test/MedianDetectorTestTest.h b/Framework/Algorithms/test/MedianDetectorTestTest.h index 01666e3928ab782fc1a1a05cc380f48ec83ea72f..5419d0bdc53846af5cc370e05149241972d6a020 100644 --- a/Framework/Algorithms/test/MedianDetectorTestTest.h +++ b/Framework/Algorithms/test/MedianDetectorTestTest.h @@ -9,10 +9,10 @@ #include "MantidKernel/UnitFactory.h" #include "MantidAPI/AnalysisDataService.h" #include "MantidAPI/Axis.h" +#include "MantidAPI/SpectrumInfo.h" #include "MantidAPI/WorkspaceFactory.h" #include "MantidDataObjects/Workspace2D.h" #include "MantidDataHandling/LoadInstrument.h" -//#include "MantidDataHandling/LoadEmptyInstrument.h" #include <boost/shared_ptr.hpp> #include <boost/lexical_cast.hpp> #include <Poco/File.h> @@ -71,7 +71,6 @@ public: input = AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>(m_IWSName); TS_ASSERT(input); - // TS_ASSERT(input->getInstrument()->isDetectorMasked(input->getSpectrum(THEMASKED).getDetectorIDs())); MatrixWorkspace_sptr outputMat = boost::dynamic_pointer_cast<MatrixWorkspace>(output); @@ -233,7 +232,8 @@ public: m_2DWS->getAxis(0)->unit() = UnitFactory::Instance().create("TOF"); // mask the detector - m_2DWS->maskWorkspaceIndex(THEMASKED); + m_2DWS->getSpectrum(THEMASKED).clearData(); + m_2DWS->mutableSpectrumInfo().setMasked(THEMASKED, true); } private: diff --git a/Framework/Algorithms/test/SolidAngleTest.h b/Framework/Algorithms/test/SolidAngleTest.h index 59f25b6b638872e111539a05b34a951696c78df2..a2fe7fb1bcf1f935d5de6ab9777d4882ef187f26 100644 --- a/Framework/Algorithms/test/SolidAngleTest.h +++ b/Framework/Algorithms/test/SolidAngleTest.h @@ -10,6 +10,7 @@ #include "MantidKernel/UnitFactory.h" #include "MantidAPI/AnalysisDataService.h" #include "MantidAPI/Axis.h" +#include "MantidAPI/SpectrumInfo.h" #include "MantidAPI/WorkspaceFactory.h" #include "MantidDataObjects/Workspace2D.h" #include "MantidDataHandling/LoadInstrument.h" @@ -61,9 +62,7 @@ public: space2D->getAxis(0)->unit() = UnitFactory::Instance().create("TOF"); // Mark one detector dead to test that it leads to zero solid angle - IDetector_const_sptr det143 = space2D->getDetector(143); - ParameterMap &pmap = space2D->instrumentParameters(); - pmap.addBool(det143.get(), "masked", true); + space2D->mutableSpectrumInfo().setMasked(143, true); } void testInit() { diff --git a/Framework/Algorithms/test/Stitch1DManyTest.h b/Framework/Algorithms/test/Stitch1DManyTest.h index da6d9db7acfd20555cc8c7908e6129d152f60cbe..50a0d6095dc6ed3ed33714eab3b5a589a6b35476 100644 --- a/Framework/Algorithms/test/Stitch1DManyTest.h +++ b/Framework/Algorithms/test/Stitch1DManyTest.h @@ -52,12 +52,12 @@ private: MatrixWorkspace_sptr ws = WorkspaceFactory::Instance().create("Workspace2D", 2, nbins + 1, nbins); - ws->dataX(0) = xData1; - ws->dataX(1) = xData2; - ws->dataY(0) = yData1; - ws->dataY(1) = yData2; - ws->dataE(0) = eData1; - ws->dataE(1) = eData2; + ws->mutableX(0) = xData1; + ws->mutableX(1) = xData2; + ws->mutableY(0) = yData1; + ws->mutableY(1) = yData2; + ws->mutableE(0) = eData1; + ws->mutableE(1) = eData2; ws->getAxis(0)->unit() = UnitFactory::Instance().create("Wavelength"); return ws; @@ -188,18 +188,18 @@ public: auto stitched = boost::dynamic_pointer_cast<MatrixWorkspace>(outws); TS_ASSERT_EQUALS(stitched->getNumberHistograms(), 2); TS_ASSERT_EQUALS(stitched->blocksize(), 17); - TS_ASSERT_DELTA(stitched->readY(0)[0], 1, 0.00001); - TS_ASSERT_DELTA(stitched->readY(0)[9], 1, 0.00001); - TS_ASSERT_DELTA(stitched->readY(0)[16], 1, 0.00001); - TS_ASSERT_DELTA(stitched->readY(1)[0], 2, 0.00001); - TS_ASSERT_DELTA(stitched->readY(1)[9], 2, 0.00001); - TS_ASSERT_DELTA(stitched->readY(1)[16], 2, 0.00001); - TS_ASSERT_DELTA(stitched->readE(0)[0], 1, 0.00001); - TS_ASSERT_DELTA(stitched->readE(0)[9], 0.77919, 0.00001); - TS_ASSERT_DELTA(stitched->readE(0)[16], 1.24316, 0.00001); - TS_ASSERT_DELTA(stitched->readE(1)[0], 1.41421, 0.00001); - TS_ASSERT_DELTA(stitched->readE(1)[9], 1.10982, 0.00001); - TS_ASSERT_DELTA(stitched->readE(1)[16], 1.79063, 0.00001); + TS_ASSERT_DELTA(stitched->y(0)[0], 1, 0.00001); + TS_ASSERT_DELTA(stitched->y(0)[9], 1, 0.00001); + TS_ASSERT_DELTA(stitched->y(0)[16], 1, 0.00001); + TS_ASSERT_DELTA(stitched->y(1)[0], 2, 0.00001); + TS_ASSERT_DELTA(stitched->y(1)[9], 2, 0.00001); + TS_ASSERT_DELTA(stitched->y(1)[16], 2, 0.00001); + TS_ASSERT_DELTA(stitched->e(0)[0], 1, 0.00001); + TS_ASSERT_DELTA(stitched->e(0)[9], 0.77919, 0.00001); + TS_ASSERT_DELTA(stitched->e(0)[16], 1.24316, 0.00001); + TS_ASSERT_DELTA(stitched->e(1)[0], 1.41421, 0.00001); + TS_ASSERT_DELTA(stitched->e(1)[9], 1.10982, 0.00001); + TS_ASSERT_DELTA(stitched->e(1)[16], 1.79063, 0.00001); // Test out sclae factors std::vector<double> scales = alg.getProperty("OutScaleFactors"); @@ -222,8 +222,8 @@ public: alg2.execute(); MatrixWorkspace_sptr stitched2 = alg2.getProperty("OutputWorkspace"); TS_ASSERT_EQUALS(stitched->readX(0), stitched2->readX(0)); - TS_ASSERT_EQUALS(stitched->readY(0), stitched2->readY(0)); - TS_ASSERT_EQUALS(stitched->readE(0), stitched2->readE(0)); + TS_ASSERT_EQUALS(stitched->y(0).rawData(), stitched2->y(0).rawData()); + TS_ASSERT_EQUALS(stitched->e(0).rawData(), stitched2->e(0).rawData()); // Remove workspaces from ADS AnalysisDataService::Instance().remove("ws1"); @@ -257,25 +257,25 @@ public: TS_ASSERT_EQUALS(stitched->getNumberHistograms(), 2); TS_ASSERT_EQUALS(stitched->blocksize(), 25); // First spectrum, Y values - TS_ASSERT_DELTA(stitched->readY(0)[0], 1, 0.00001); - TS_ASSERT_DELTA(stitched->readY(0)[9], 1, 0.00001); - TS_ASSERT_DELTA(stitched->readY(0)[16], 1, 0.00001); - TS_ASSERT_DELTA(stitched->readY(0)[24], 1, 0.00001); + TS_ASSERT_DELTA(stitched->y(0)[0], 1, 0.00001); + TS_ASSERT_DELTA(stitched->y(0)[9], 1, 0.00001); + TS_ASSERT_DELTA(stitched->y(0)[16], 1, 0.00001); + TS_ASSERT_DELTA(stitched->y(0)[24], 1, 0.00001); // Second spectrum, Y values - TS_ASSERT_DELTA(stitched->readY(1)[0], 2, 0.00001); - TS_ASSERT_DELTA(stitched->readY(1)[9], 2, 0.00001); - TS_ASSERT_DELTA(stitched->readY(1)[16], 2, 0.00001); - TS_ASSERT_DELTA(stitched->readY(1)[24], 2, 0.00001); + TS_ASSERT_DELTA(stitched->y(1)[0], 2, 0.00001); + TS_ASSERT_DELTA(stitched->y(1)[9], 2, 0.00001); + TS_ASSERT_DELTA(stitched->y(1)[16], 2, 0.00001); + TS_ASSERT_DELTA(stitched->y(1)[24], 2, 0.00001); // First spectrum, E values - TS_ASSERT_DELTA(stitched->readE(0)[0], 1, 0.00001); - TS_ASSERT_DELTA(stitched->readE(0)[9], 0.77919, 0.00001); - TS_ASSERT_DELTA(stitched->readE(0)[16], 0.90865, 0.00001); - TS_ASSERT_DELTA(stitched->readE(0)[24], 1.33144, 0.00001); + TS_ASSERT_DELTA(stitched->e(0)[0], 1, 0.00001); + TS_ASSERT_DELTA(stitched->e(0)[9], 0.77919, 0.00001); + TS_ASSERT_DELTA(stitched->e(0)[16], 0.90865, 0.00001); + TS_ASSERT_DELTA(stitched->e(0)[24], 1.33144, 0.00001); // Second spectrum, E values - TS_ASSERT_DELTA(stitched->readE(1)[0], 1.41421, 0.00001); - TS_ASSERT_DELTA(stitched->readE(1)[9], 1.10982, 0.00001); - TS_ASSERT_DELTA(stitched->readE(1)[16], 1.33430, 0.00001); - TS_ASSERT_DELTA(stitched->readE(1)[24], 2.00079, 0.00001); + TS_ASSERT_DELTA(stitched->e(1)[0], 1.41421, 0.00001); + TS_ASSERT_DELTA(stitched->e(1)[9], 1.10982, 0.00001); + TS_ASSERT_DELTA(stitched->e(1)[16], 1.33430, 0.00001); + TS_ASSERT_DELTA(stitched->e(1)[24], 2.00079, 0.00001); // Test out sclae factors std::vector<double> scales = alg.getProperty("OutScaleFactors"); @@ -337,21 +337,21 @@ public: TS_ASSERT_EQUALS(stitched->getNumberHistograms(), 2); TS_ASSERT_EQUALS(stitched->blocksize(), 25); // First spectrum, Y values - TS_ASSERT_DELTA(stitched->readY(0)[0], 1, 0.00001); - TS_ASSERT_DELTA(stitched->readY(0)[10], 0.55000, 0.00001); - TS_ASSERT_DELTA(stitched->readY(0)[18], 0.75000, 0.00001); + TS_ASSERT_DELTA(stitched->y(0)[0], 1, 0.00001); + TS_ASSERT_DELTA(stitched->y(0)[10], 0.55000, 0.00001); + TS_ASSERT_DELTA(stitched->y(0)[18], 0.75000, 0.00001); // Second spectrum, Y values - TS_ASSERT_DELTA(stitched->readY(1)[0], 2, 0.00001); - TS_ASSERT_DELTA(stitched->readY(1)[10], 1.05000, 0.00001); - TS_ASSERT_DELTA(stitched->readY(1)[18], 1.25000, 0.00001); + TS_ASSERT_DELTA(stitched->y(1)[0], 2, 0.00001); + TS_ASSERT_DELTA(stitched->y(1)[10], 1.05000, 0.00001); + TS_ASSERT_DELTA(stitched->y(1)[18], 1.25000, 0.00001); // First spectrum, E values - TS_ASSERT_DELTA(stitched->readE(0)[0], 1.00000, 0.00001); - TS_ASSERT_DELTA(stitched->readE(0)[10], 0.52440, 0.00001); - TS_ASSERT_DELTA(stitched->readE(0)[18], 0.61237, 0.00001); + TS_ASSERT_DELTA(stitched->e(0)[0], 1.00000, 0.00001); + TS_ASSERT_DELTA(stitched->e(0)[10], 0.52440, 0.00001); + TS_ASSERT_DELTA(stitched->e(0)[18], 0.61237, 0.00001); // Second spectrum, E values - TS_ASSERT_DELTA(stitched->readE(1)[0], 1.41421, 0.00001); - TS_ASSERT_DELTA(stitched->readE(1)[10], 0.72457, 0.00001); - TS_ASSERT_DELTA(stitched->readE(1)[18], 0.79057, 0.00001); + TS_ASSERT_DELTA(stitched->e(1)[0], 1.41421, 0.00001); + TS_ASSERT_DELTA(stitched->e(1)[10], 0.72457, 0.00001); + TS_ASSERT_DELTA(stitched->e(1)[18], 0.79057, 0.00001); // Test out sclae factors std::vector<double> scales = alg.getProperty("OutScaleFactors"); @@ -433,25 +433,25 @@ public: TS_ASSERT_EQUALS(stitched->getNumberHistograms(), 2); TS_ASSERT_EQUALS(stitched->blocksize(), 25); // First spectrum, Y values - TS_ASSERT_DELTA(stitched->readY(0)[0], 1, 0.00001); - TS_ASSERT_DELTA(stitched->readY(0)[9], 1, 0.00001); - TS_ASSERT_DELTA(stitched->readY(0)[16], 1, 0.00001); - TS_ASSERT_DELTA(stitched->readY(0)[24], 1, 0.00001); + TS_ASSERT_DELTA(stitched->y(0)[0], 1, 0.00001); + TS_ASSERT_DELTA(stitched->y(0)[9], 1, 0.00001); + TS_ASSERT_DELTA(stitched->y(0)[16], 1, 0.00001); + TS_ASSERT_DELTA(stitched->y(0)[24], 1, 0.00001); // Second spectrum, Y values - TS_ASSERT_DELTA(stitched->readY(1)[0], 2, 0.00001); - TS_ASSERT_DELTA(stitched->readY(1)[9], 2, 0.00001); - TS_ASSERT_DELTA(stitched->readY(1)[16], 2, 0.00001); - TS_ASSERT_DELTA(stitched->readY(1)[24], 2, 0.00001); + TS_ASSERT_DELTA(stitched->y(1)[0], 2, 0.00001); + TS_ASSERT_DELTA(stitched->y(1)[9], 2, 0.00001); + TS_ASSERT_DELTA(stitched->y(1)[16], 2, 0.00001); + TS_ASSERT_DELTA(stitched->y(1)[24], 2, 0.00001); // First spectrum, E values - TS_ASSERT_DELTA(stitched->readE(0)[0], 1, 0.00001); - TS_ASSERT_DELTA(stitched->readE(0)[9], 0.77919, 0.00001); - TS_ASSERT_DELTA(stitched->readE(0)[16], 0.90865, 0.00001); - TS_ASSERT_DELTA(stitched->readE(0)[24], 1.33144, 0.00001); + TS_ASSERT_DELTA(stitched->e(0)[0], 1, 0.00001); + TS_ASSERT_DELTA(stitched->e(0)[9], 0.77919, 0.00001); + TS_ASSERT_DELTA(stitched->e(0)[16], 0.90865, 0.00001); + TS_ASSERT_DELTA(stitched->e(0)[24], 1.33144, 0.00001); // Second spectrum, E values - TS_ASSERT_DELTA(stitched->readE(1)[0], 1.41421, 0.00001); - TS_ASSERT_DELTA(stitched->readE(1)[9], 1.10982, 0.00001); - TS_ASSERT_DELTA(stitched->readE(1)[16], 1.33430, 0.00001); - TS_ASSERT_DELTA(stitched->readE(1)[24], 2.00079, 0.00001); + TS_ASSERT_DELTA(stitched->e(1)[0], 1.41421, 0.00001); + TS_ASSERT_DELTA(stitched->e(1)[9], 1.10982, 0.00001); + TS_ASSERT_DELTA(stitched->e(1)[16], 1.33430, 0.00001); + TS_ASSERT_DELTA(stitched->e(1)[24], 2.00079, 0.00001); // Test out sclae factors std::vector<double> scales = alg.getProperty("OutScaleFactors"); @@ -508,42 +508,42 @@ public: TS_ASSERT_EQUALS(stitched->getNumberHistograms(), 2); TS_ASSERT_EQUALS(stitched->blocksize(), 17); // First spectrum, Y values - TS_ASSERT_DELTA(stitched->readY(0)[0], 1, 0.00001); - TS_ASSERT_DELTA(stitched->readY(0)[9], 1, 0.00001); - TS_ASSERT_DELTA(stitched->readY(0)[16], 1, 0.00001); + TS_ASSERT_DELTA(stitched->y(0)[0], 1, 0.00001); + TS_ASSERT_DELTA(stitched->y(0)[9], 1, 0.00001); + TS_ASSERT_DELTA(stitched->y(0)[16], 1, 0.00001); // Second spectrum, Y values - TS_ASSERT_DELTA(stitched->readY(1)[0], 2, 0.00001); - TS_ASSERT_DELTA(stitched->readY(1)[9], 2, 0.00001); - TS_ASSERT_DELTA(stitched->readY(1)[16], 2, 0.00001); + TS_ASSERT_DELTA(stitched->y(1)[0], 2, 0.00001); + TS_ASSERT_DELTA(stitched->y(1)[9], 2, 0.00001); + TS_ASSERT_DELTA(stitched->y(1)[16], 2, 0.00001); // First spectrum, E values - TS_ASSERT_DELTA(stitched->readE(0)[0], 1, 0.00001); - TS_ASSERT_DELTA(stitched->readE(0)[9], 0.77919, 0.00001); - TS_ASSERT_DELTA(stitched->readE(0)[16], 1.24316, 0.00001); + TS_ASSERT_DELTA(stitched->e(0)[0], 1, 0.00001); + TS_ASSERT_DELTA(stitched->e(0)[9], 0.77919, 0.00001); + TS_ASSERT_DELTA(stitched->e(0)[16], 1.24316, 0.00001); // Second spectrum, E values - TS_ASSERT_DELTA(stitched->readE(1)[0], 1.41421, 0.00001); - TS_ASSERT_DELTA(stitched->readE(1)[9], 1.10982, 0.00001); - TS_ASSERT_DELTA(stitched->readE(1)[16], 1.79063, 0.00001); + TS_ASSERT_DELTA(stitched->e(1)[0], 1.41421, 0.00001); + TS_ASSERT_DELTA(stitched->e(1)[9], 1.10982, 0.00001); + TS_ASSERT_DELTA(stitched->e(1)[16], 1.79063, 0.00001); // Second item in the output group stitched = boost::dynamic_pointer_cast<MatrixWorkspace>(group->getItem(1)); TS_ASSERT_EQUALS(stitched->getNumberHistograms(), 2); TS_ASSERT_EQUALS(stitched->blocksize(), 17); // First spectrum, Y values - TS_ASSERT_DELTA(stitched->readY(0)[0], 1.5, 0.00001); - TS_ASSERT_DELTA(stitched->readY(0)[9], 1.5, 0.00001); - TS_ASSERT_DELTA(stitched->readY(0)[16], 1.5, 0.00001); + TS_ASSERT_DELTA(stitched->y(0)[0], 1.5, 0.00001); + TS_ASSERT_DELTA(stitched->y(0)[9], 1.5, 0.00001); + TS_ASSERT_DELTA(stitched->y(0)[16], 1.5, 0.00001); // Second spectrum, Y values - TS_ASSERT_DELTA(stitched->readY(1)[0], 2.5, 0.00001); - TS_ASSERT_DELTA(stitched->readY(1)[9], 2.5, 0.00001); - TS_ASSERT_DELTA(stitched->readY(1)[16], 2.5, 0.00001); + TS_ASSERT_DELTA(stitched->y(1)[0], 2.5, 0.00001); + TS_ASSERT_DELTA(stitched->y(1)[9], 2.5, 0.00001); + TS_ASSERT_DELTA(stitched->y(1)[16], 2.5, 0.00001); // First spectrum, E values - TS_ASSERT_DELTA(stitched->readE(0)[0], 1.22474, 0.00001); - TS_ASSERT_DELTA(stitched->readE(0)[9], 0.95883, 0.00001); - TS_ASSERT_DELTA(stitched->readE(0)[16], 1.54110, 0.00001); + TS_ASSERT_DELTA(stitched->e(0)[0], 1.22474, 0.00001); + TS_ASSERT_DELTA(stitched->e(0)[9], 0.95883, 0.00001); + TS_ASSERT_DELTA(stitched->e(0)[16], 1.54110, 0.00001); // Second spectrum, E values - TS_ASSERT_DELTA(stitched->readE(1)[0], 1.58114, 0.00001); - TS_ASSERT_DELTA(stitched->readE(1)[9], 1.24263, 0.00001); - TS_ASSERT_DELTA(stitched->readE(1)[16], 2.00959, 0.00001); + TS_ASSERT_DELTA(stitched->e(1)[0], 1.58114, 0.00001); + TS_ASSERT_DELTA(stitched->e(1)[9], 1.24263, 0.00001); + TS_ASSERT_DELTA(stitched->e(1)[16], 2.00959, 0.00001); // Test out sclae factors std::vector<double> scales = alg.getProperty("OutScaleFactors"); @@ -606,42 +606,42 @@ public: TS_ASSERT_EQUALS(stitched->getNumberHistograms(), 2); TS_ASSERT_EQUALS(stitched->blocksize(), 17); // First spectrum, Y values - TS_ASSERT_DELTA(stitched->readY(0)[0], 1, 0.00001); - TS_ASSERT_DELTA(stitched->readY(0)[9], 0.64705, 0.00001); - TS_ASSERT_DELTA(stitched->readY(0)[16], 0.55000, 0.00001); + TS_ASSERT_DELTA(stitched->y(0)[0], 1, 0.00001); + TS_ASSERT_DELTA(stitched->y(0)[9], 0.64705, 0.00001); + TS_ASSERT_DELTA(stitched->y(0)[16], 0.55000, 0.00001); // Second spectrum, Y values - TS_ASSERT_DELTA(stitched->readY(1)[0], 2, 0.00001); - TS_ASSERT_DELTA(stitched->readY(1)[9], 1.24752, 0.00001); - TS_ASSERT_DELTA(stitched->readY(1)[16], 1.05000, 0.00001); + TS_ASSERT_DELTA(stitched->y(1)[0], 2, 0.00001); + TS_ASSERT_DELTA(stitched->y(1)[9], 1.24752, 0.00001); + TS_ASSERT_DELTA(stitched->y(1)[16], 1.05000, 0.00001); // First spectrum, E values - TS_ASSERT_DELTA(stitched->readE(0)[0], 1, 0.00001); - TS_ASSERT_DELTA(stitched->readE(0)[9], 0.46442, 0.00001); - TS_ASSERT_DELTA(stitched->readE(0)[16], 0.52440, 0.00001); + TS_ASSERT_DELTA(stitched->e(0)[0], 1, 0.00001); + TS_ASSERT_DELTA(stitched->e(0)[9], 0.46442, 0.00001); + TS_ASSERT_DELTA(stitched->e(0)[16], 0.52440, 0.00001); // Second spectrum, E values - TS_ASSERT_DELTA(stitched->readE(1)[0], 1.41421, 0.00001); - TS_ASSERT_DELTA(stitched->readE(1)[9], 0.64485, 0.00001); - TS_ASSERT_DELTA(stitched->readE(1)[16], 0.72456, 0.00001); + TS_ASSERT_DELTA(stitched->e(1)[0], 1.41421, 0.00001); + TS_ASSERT_DELTA(stitched->e(1)[9], 0.64485, 0.00001); + TS_ASSERT_DELTA(stitched->e(1)[16], 0.72456, 0.00001); // Second item in the output group stitched = boost::dynamic_pointer_cast<MatrixWorkspace>(group->getItem(1)); TS_ASSERT_EQUALS(stitched->getNumberHistograms(), 2); TS_ASSERT_EQUALS(stitched->blocksize(), 17); // First spectrum, Y values - TS_ASSERT_DELTA(stitched->readY(0)[0], 1.5, 0.00001); - TS_ASSERT_DELTA(stitched->readY(0)[9], 0.94736, 0.00001); - TS_ASSERT_DELTA(stitched->readY(0)[16], 0.8, 0.00001); + TS_ASSERT_DELTA(stitched->y(0)[0], 1.5, 0.00001); + TS_ASSERT_DELTA(stitched->y(0)[9], 0.94736, 0.00001); + TS_ASSERT_DELTA(stitched->y(0)[16], 0.8, 0.00001); // Second spectrum, Y values - TS_ASSERT_DELTA(stitched->readY(1)[0], 2.5, 0.00001); - TS_ASSERT_DELTA(stitched->readY(1)[9], 1.54762, 0.00001); - TS_ASSERT_DELTA(stitched->readY(1)[16], 1.3, 0.00001); + TS_ASSERT_DELTA(stitched->y(1)[0], 2.5, 0.00001); + TS_ASSERT_DELTA(stitched->y(1)[9], 1.54762, 0.00001); + TS_ASSERT_DELTA(stitched->y(1)[16], 1.3, 0.00001); // First spectrum, E values - TS_ASSERT_DELTA(stitched->readE(0)[0], 1.22474, 0.00001); - TS_ASSERT_DELTA(stitched->readE(0)[9], 0.56195, 0.00001); - TS_ASSERT_DELTA(stitched->readE(0)[16], 0.63245, 0.00001); + TS_ASSERT_DELTA(stitched->e(0)[0], 1.22474, 0.00001); + TS_ASSERT_DELTA(stitched->e(0)[9], 0.56195, 0.00001); + TS_ASSERT_DELTA(stitched->e(0)[16], 0.63245, 0.00001); // Second spectrum, E values - TS_ASSERT_DELTA(stitched->readE(1)[0], 1.58114, 0.00001); - TS_ASSERT_DELTA(stitched->readE(1)[9], 0.71824, 0.00001); - TS_ASSERT_DELTA(stitched->readE(1)[16], 0.80622, 0.00001); + TS_ASSERT_DELTA(stitched->e(1)[0], 1.58114, 0.00001); + TS_ASSERT_DELTA(stitched->e(1)[9], 0.71824, 0.00001); + TS_ASSERT_DELTA(stitched->e(1)[16], 0.80622, 0.00001); // Test out sclae factors std::vector<double> scales = alg.getProperty("OutScaleFactors"); @@ -652,6 +652,52 @@ public: // Clear the ADS AnalysisDataService::Instance().clear(); } + + void test_three_workspaces_scale_LHS_workspace() { + // Three matrix workspaces with two spectra each + + auto ws1 = createUniformWorkspace(0.1, 0.1, 1., 2.); + auto ws2 = createUniformWorkspace(0.8, 0.1, 1.1, 2.1); + auto ws3 = createUniformWorkspace(1.6, 0.1, 1.5, 2.5); + // The algorithm needs the workspaces to be in the ADS + AnalysisDataService::Instance().addOrReplace("ws1", ws1); + AnalysisDataService::Instance().addOrReplace("ws2", ws2); + AnalysisDataService::Instance().addOrReplace("ws3", ws3); + + Stitch1DMany alg; + alg.setChild(true); + alg.initialize(); + alg.setProperty("InputWorkspaces", "ws1, ws2, ws3"); + alg.setProperty("Params", "0.1"); + alg.setPropertyValue("ScaleRHSWorkspace", "0"); + alg.setPropertyValue("OutputWorkspace", "outws"); + alg.execute(); + + // Test output ws + Workspace_sptr outws = alg.getProperty("OutputWorkspace"); + auto stitched = boost::dynamic_pointer_cast<MatrixWorkspace>(outws); + TS_ASSERT_EQUALS(stitched->getNumberHistograms(), 2); + TS_ASSERT_EQUALS(stitched->blocksize(), 25); + // First spectrum, Y values + TS_ASSERT_DELTA(stitched->y(0)[0], 1.5, 0.00001); + TS_ASSERT_DELTA(stitched->y(0)[10], 1.5, 0.00001); + TS_ASSERT_DELTA(stitched->y(0)[18], 1.5, 0.00001); + // Second spectrum, Y values + TS_ASSERT_DELTA(stitched->y(1)[0], 2.5, 0.00001); + TS_ASSERT_DELTA(stitched->y(1)[10], 2.5, 0.00001); + TS_ASSERT_DELTA(stitched->y(1)[18], 2.5, 0.00001); + + // Test out sclae factors + std::vector<double> scales = alg.getProperty("OutScaleFactors"); + TS_ASSERT_EQUALS(scales.size(), 2); + TS_ASSERT_DELTA(scales.front(), 1.0999, 0.0001); + TS_ASSERT_DELTA(scales.back(), 1.3636, 0.0001); + + // Remove workspaces from ADS + AnalysisDataService::Instance().remove("ws1"); + AnalysisDataService::Instance().remove("ws2"); + AnalysisDataService::Instance().remove("ws3"); + } }; #endif /* MANTID_ALGORITHMS_STITCH1DMANYTEST_H_ */ diff --git a/Framework/Algorithms/test/SumSpectraTest.h b/Framework/Algorithms/test/SumSpectraTest.h index a02ea93c1d38a49cb1ee49710f7a848e9a0a8abd..528debc48b55b6e49d5ef4536b3f266c367823a2 100644 --- a/Framework/Algorithms/test/SumSpectraTest.h +++ b/Framework/Algorithms/test/SumSpectraTest.h @@ -3,12 +3,15 @@ #include "MantidAlgorithms/SumSpectra.h" #include "MantidAPI/AnalysisDataService.h" +#include "MantidAPI/SpectrumInfo.h" #include "MantidAPI/WorkspaceFactory.h" #include "MantidDataObjects/Workspace2D.h" #include "MantidGeometry/Instrument/ParameterMap.h" #include "MantidTestHelpers/WorkspaceCreationHelper.h" #include <boost/lexical_cast.hpp> #include <cxxtest/TestSuite.h> +#include <limits> +#include <cmath> using namespace Mantid; using namespace Mantid::API; @@ -24,8 +27,7 @@ public: this->inputSpace = WorkspaceCreationHelper::create2DWorkspaceWithFullInstrument(nTestHist, 102, true); - this->inputSpace->instrumentParameters().addBool( - inputSpace->getDetector(1).get(), "masked", true); + inputSpace->mutableSpectrumInfo().setMasked(1, true); inputSpace->mutableE(5)[38] = 0.0; } @@ -38,8 +40,10 @@ public: } void testExecWithLimits() { - if (!alg.isInitialized()) + if (!alg.isInitialized()) { alg.initialize(); + alg.setRethrows(true); + } // Set the properties TS_ASSERT_THROWS_NOTHING(alg.setProperty("InputWorkspace", inputSpace)); @@ -235,6 +239,7 @@ public: alg3.setPropertyValue("InputWorkspace", inName); alg3.setPropertyValue("OutputWorkspace", outName); alg3.setProperty("IncludeMonitors", false); + alg3.setProperty("RemoveSpecialValues", true); alg3.execute(); TS_ASSERT(alg3.isExecuted()); @@ -246,12 +251,12 @@ public: TS_ASSERT_EQUALS(output->getNumberHistograms(), 1); TS_ASSERT_EQUALS(output->blocksize(), 6); // Row with full acceptance - TS_ASSERT_EQUALS(output->mutableY(0)[1], 1.); - TS_ASSERT_DELTA(output->mutableE(0)[1], 0.40824829046386296, 1.e-5); + TS_ASSERT_EQUALS(output->y(0)[1], 1.); + TS_ASSERT_DELTA(output->e(0)[1], 0.40824829046386296, 1.e-5); TS_ASSERT_EQUALS(output->dataF(0)[1], 6.); // Row with limited, but non-zero acceptance, shouldn't have nans! - TS_ASSERT_DELTA(output->mutableY(0)[5], 0.66666, 1.e-5); - TS_ASSERT_DELTA(output->mutableE(0)[5], 0.47140452079103173, 1.e-5); + TS_ASSERT_DELTA(output->y(0)[5], 0.66666, 1.e-5); + TS_ASSERT_DELTA(output->e(0)[5], 0.47140452079103173, 1.e-5); TS_ASSERT_EQUALS(output->dataF(0)[5], 3.); TS_ASSERT(output->run().hasProperty("NumAllSpectra")) @@ -422,6 +427,80 @@ public: AnalysisDataService::Instance().remove(outName); } + void testRemoveSpecialValuesOn() { + constexpr size_t numOfHistos = 2; + auto inWs = + WorkspaceCreationHelper::create2DWorkspace123(numOfHistos, 3, true); + auto &yVals = inWs->mutableY(1); + + yVals[0] = std::numeric_limits<double>::infinity(); + yVals[1] = NAN; + + Mantid::Algorithms::SumSpectra sumSpectraAlg; + sumSpectraAlg.initialize(); + sumSpectraAlg.setRethrows(true); + + sumSpectraAlg.setProperty("InputWorkspace", inWs); + const std::string outWsName = "testSpecialVals"; + sumSpectraAlg.setPropertyValue("OutputWorkspace", outWsName); + sumSpectraAlg.setProperty("RemoveSpecialValues", true); + + TS_ASSERT_THROWS_NOTHING(sumSpectraAlg.execute()); + TS_ASSERT(sumSpectraAlg.isExecuted()); + + Workspace_sptr output; + TS_ASSERT_THROWS_NOTHING( + output = AnalysisDataService::Instance().retrieve(outWsName)); + Workspace2D_const_sptr output2D = + boost::dynamic_pointer_cast<const Workspace2D>(output); + + auto outYVals = output2D->y(0); + // We expect one less because of inf and NaN + TS_ASSERT_EQUALS(outYVals[0], 2.); + TS_ASSERT_EQUALS(outYVals[1], 2.); + // Should get the correct amount now + TS_ASSERT_EQUALS(outYVals[2], 4.); + + AnalysisDataService::Instance().remove(outWsName); + } + + void testRemoveSpecialValuesOff() { + constexpr size_t numOfHistos = 2; + auto inWs = + WorkspaceCreationHelper::create2DWorkspace123(numOfHistos, 3, true); + auto &yVals = inWs->mutableY(1); + + yVals[0] = std::numeric_limits<double>::infinity(); + yVals[1] = NAN; + + Mantid::Algorithms::SumSpectra sumSpectraAlg; + sumSpectraAlg.initialize(); + sumSpectraAlg.setRethrows(true); + + sumSpectraAlg.setProperty("InputWorkspace", inWs); + const std::string outWsName = "testSpecialVals"; + sumSpectraAlg.setPropertyValue("OutputWorkspace", outWsName); + sumSpectraAlg.setProperty("RemoveSpecialValues", false); + + TS_ASSERT_THROWS_NOTHING(sumSpectraAlg.execute()); + TS_ASSERT(sumSpectraAlg.isExecuted()); + + Workspace_sptr output; + TS_ASSERT_THROWS_NOTHING( + output = AnalysisDataService::Instance().retrieve(outWsName)); + Workspace2D_const_sptr output2D = + boost::dynamic_pointer_cast<const Workspace2D>(output); + + auto outYVals = output2D->y(0); + // We expect a NaN and an Inf to propagate here + TS_ASSERT_EQUALS(std::isnormal(outYVals[0]), false); + TS_ASSERT_EQUALS(std::isnormal(outYVals[1]), false); + // Should get the correct amount now + TS_ASSERT_EQUALS(outYVals[2], 4.); + + AnalysisDataService::Instance().remove(outWsName); + } + private: int nTestHist; Mantid::Algorithms::SumSpectra alg; // Test with range limits diff --git a/Framework/Crystal/inc/MantidCrystal/LoadIsawPeaks.h b/Framework/Crystal/inc/MantidCrystal/LoadIsawPeaks.h index a20c141abfb32bf64436a78348b8473c0871b568..6bd149be3fca963d7651737212058c7d87a113e9 100644 --- a/Framework/Crystal/inc/MantidCrystal/LoadIsawPeaks.h +++ b/Framework/Crystal/inc/MantidCrystal/LoadIsawPeaks.h @@ -46,7 +46,6 @@ private: /// Reads calibration/detector section and returns first word of next line std::string ApplyCalibInfo(std::ifstream &in, std::string startChar, - Geometry::Instrument_const_sptr instr_old, Geometry::Instrument_const_sptr instr, double &T0); /// Reads first line of peaks file and returns first word of next line diff --git a/Framework/Crystal/src/CalculatePeaksHKL.cpp b/Framework/Crystal/src/CalculatePeaksHKL.cpp index f59327ce146338b764ef8d1550843fd781148c1b..7f5b556a522ec6bda12211082153f4b5c1256f0a 100644 --- a/Framework/Crystal/src/CalculatePeaksHKL.cpp +++ b/Framework/Crystal/src/CalculatePeaksHKL.cpp @@ -52,7 +52,7 @@ void CalculatePeaksHKL::exec() { const int n_peaks = ws->getNumberPeaks(); OrientedLattice o_lattice = ws->mutableSample().getOrientedLattice(); - Matrix<double> UB = o_lattice.getUB(); + const Matrix<double> &UB = o_lattice.getUB(); DblMatrix UB_inverse(UB); diff --git a/Framework/Crystal/src/IndexPeaks.cpp b/Framework/Crystal/src/IndexPeaks.cpp index dfb86fb5e615bc981917138d58a7e24b3f36ee99..ddc1c214b7db7ad624bbb50188faed559522527e 100644 --- a/Framework/Crystal/src/IndexPeaks.cpp +++ b/Framework/Crystal/src/IndexPeaks.cpp @@ -51,7 +51,7 @@ void IndexPeaks::exec() { } OrientedLattice o_lattice = ws->mutableSample().getOrientedLattice(); - Matrix<double> UB = o_lattice.getUB(); + const Matrix<double> &UB = o_lattice.getUB(); if (!IndexingUtils::CheckUB(UB)) { throw std::runtime_error( diff --git a/Framework/Crystal/src/LoadIsawPeaks.cpp b/Framework/Crystal/src/LoadIsawPeaks.cpp index aac2069ec48141e72405fce255b25ff4cce4e3a0..1b7f9d1021a785e8fe4d4fd6194113af7bbe97f3 100644 --- a/Framework/Crystal/src/LoadIsawPeaks.cpp +++ b/Framework/Crystal/src/LoadIsawPeaks.cpp @@ -108,12 +108,10 @@ void LoadIsawPeaks::exec() { } //---------------------------------------------------------------------------------------------- -std::string -LoadIsawPeaks::ApplyCalibInfo(std::ifstream &in, std::string startChar, - Geometry::Instrument_const_sptr instr_old, - Geometry::Instrument_const_sptr instr, - double &T0) { - ParameterMap_sptr parMap1 = instr_old->getParameterMap(); +std::string LoadIsawPeaks::ApplyCalibInfo(std::ifstream &in, + std::string startChar, + Geometry::Instrument_const_sptr instr, + double &T0) { ParameterMap_sptr parMap = instr->getParameterMap(); @@ -138,7 +136,7 @@ LoadIsawPeaks::ApplyCalibInfo(std::ifstream &in, std::string startChar, iss >> T0; V3D sampPos = instr->getSample()->getPos(); SCDCalibratePanels::FixUpSourceParameterMap(instr, L1 / 100, sampPos, - parMap1); + parMap); } catch (...) { g_log.error() << "Invalid L1 or Time offset\n"; throw std::invalid_argument("Invalid L1 or Time offset"); @@ -198,7 +196,7 @@ LoadIsawPeaks::ApplyCalibInfo(std::ifstream &in, std::string startChar, } bankName += SbankNum; boost::shared_ptr<const Geometry::IComponent> bank = - getCachedBankByName(bankName, instr_old); + getCachedBankByName(bankName, instr); if (!bank) { g_log.error() << "There is no bank " << bankName @@ -218,7 +216,7 @@ LoadIsawPeaks::ApplyCalibInfo(std::ifstream &in, std::string startChar, bankRot.inverse(); Quat dRot = thisRot * bankRot; - boost::shared_ptr<const Geometry::RectangularDetector> bankR = + auto bankR = boost::dynamic_pointer_cast<const Geometry::RectangularDetector>(bank); if (!bankR) @@ -229,11 +227,10 @@ LoadIsawPeaks::ApplyCalibInfo(std::ifstream &in, std::string startChar, DetWScale = width / bankR->xsize() / 100; DetHtScale = height / bankR->ysize() / 100; } - std::vector<std::string> bankNames; - bankNames.push_back(bankName); + const std::vector<std::string> bankNames{bankName}; SCDCalibratePanels::FixUpBankParameterMap( - bankNames, instr, dPos, dRot, DetWScale, DetHtScale, parMap1, false); + bankNames, instr, dPos, dRot, DetWScale, DetHtScale, parMap, false); } return startChar; } @@ -296,13 +293,9 @@ std::string LoadIsawPeaks::readHeader(PeaksWorkspace_sptr outWS, // Populate the instrument parameters in this workspace - this works around a // bug tempWS->populateInstrumentParameters(); - Geometry::Instrument_const_sptr instr_old = tempWS->getInstrument(); - auto instr = instr_old; - /*auto map = boost::make_shared<ParameterMap>(); - auto instr = boost::make_shared<const Geometry::Instrument>( - instr_old->baseInstrument(), map);*/ + Geometry::Instrument_const_sptr instr = tempWS->getInstrument(); - std::string s = ApplyCalibInfo(in, "", instr_old, instr, T0); + std::string s = ApplyCalibInfo(in, "", instr, T0); outWS->setInstrument(instr); // Now skip all lines on L1, detector banks, etc. until we get to a block of @@ -567,7 +560,7 @@ void LoadIsawPeaks::appendFile(PeaksWorkspace_sptr outWS, Peak peak = readPeak(outWS, s, in, seqNum, bankName, qSign); // Get the calculated goniometer matrix - Matrix<double> gonMat = uniGonio.getR(); + const Matrix<double> &gonMat = uniGonio.getR(); peak.setGoniometerMatrix(gonMat); peak.setRunNumber(run); diff --git a/Framework/Crystal/src/PredictFractionalPeaks.cpp b/Framework/Crystal/src/PredictFractionalPeaks.cpp index 86a4906756c942366c2d9c93837b1db763e7f3e1..d422382a590adff69201c6992606f3809c0b8146 100644 --- a/Framework/Crystal/src/PredictFractionalPeaks.cpp +++ b/Framework/Crystal/src/PredictFractionalPeaks.cpp @@ -161,7 +161,7 @@ void PredictFractionalPeaks::exec() { hkl[2] = peak0.getL(); } - Kernel::DblMatrix UB = ol.getUB(); + const Kernel::DblMatrix &UB = ol.getUB(); vector<vector<int>> AlreadyDonePeaks; bool done = false; int ErrPos = 1; // Used to determine position in code of a throw diff --git a/Framework/Crystal/src/PredictPeaks.cpp b/Framework/Crystal/src/PredictPeaks.cpp index adf25dfe274df47781d4c7a767d90be9925383f2..7cc823f794cb3ecae93c4673cfa470a99bfcdc32 100644 --- a/Framework/Crystal/src/PredictPeaks.cpp +++ b/Framework/Crystal/src/PredictPeaks.cpp @@ -216,7 +216,7 @@ void PredictPeaks::exec() { const Sample &sample = inputExperimentInfo->sample(); // Retrieve the OrientedLattice (UnitCell) from the workspace - OrientedLattice orientedLattice = sample.getOrientedLattice(); + const OrientedLattice &orientedLattice = sample.getOrientedLattice(); // Get the UB matrix from it Matrix<double> ub(3, 3, true); diff --git a/Framework/Crystal/src/SCDCalibratePanels.cpp b/Framework/Crystal/src/SCDCalibratePanels.cpp index d7d9e8c43c38e46c8a461c49291da269f4b81e26..274ba9649f71c6aa0f118bc852f4a54e252452e9 100644 --- a/Framework/Crystal/src/SCDCalibratePanels.cpp +++ b/Framework/Crystal/src/SCDCalibratePanels.cpp @@ -369,7 +369,7 @@ void SCDCalibratePanels::exec() { "Workspace2D", MyBankNames.size(), nPeaks, nPeaks); TofWksp->setInstrument(inst); OrientedLattice lattice = peaksWs->mutableSample().getOrientedLattice(); - DblMatrix UB = lattice.getUB(); + const DblMatrix &UB = lattice.getUB(); // sort again since edge peaks can trace to other banks peaksWs->sort(criteria); PARALLEL_FOR_IF(Kernel::threadSafe(*ColWksp, *RowWksp, *TofWksp)) diff --git a/Framework/Crystal/src/ShowPossibleCells.cpp b/Framework/Crystal/src/ShowPossibleCells.cpp index 237c467f75c75b457ec0e961a42a302b6fdd185a..cd77926624a207893e675d677678bcfe6aff6327 100644 --- a/Framework/Crystal/src/ShowPossibleCells.cpp +++ b/Framework/Crystal/src/ShowPossibleCells.cpp @@ -51,7 +51,7 @@ void ShowPossibleCells::exec() { } OrientedLattice o_lattice = ws->sample().getOrientedLattice(); - Matrix<double> UB = o_lattice.getUB(); + const Matrix<double> &UB = o_lattice.getUB(); if (!IndexingUtils::CheckUB(UB)) { throw std::runtime_error( diff --git a/Framework/CurveFitting/CMakeLists.txt b/Framework/CurveFitting/CMakeLists.txt index 7cf5f3b3c7d25b5c3fcf144fb82d6c4a306788e8..f339292731db9e5bc404d026b40416f8c4812b9f 100644 --- a/Framework/CurveFitting/CMakeLists.txt +++ b/Framework/CurveFitting/CMakeLists.txt @@ -78,6 +78,7 @@ set ( SRC_FILES src/Functions/FlatBackground.cpp src/Functions/FullprofPolynomial.cpp src/Functions/FunctionGenerator.cpp + src/Functions/FunctionQDepends.cpp src/Functions/GausDecay.cpp src/Functions/GausOsc.cpp src/Functions/Gaussian.cpp @@ -231,6 +232,7 @@ set ( INC_FILES inc/MantidCurveFitting/Functions/FlatBackground.h inc/MantidCurveFitting/Functions/FullprofPolynomial.h inc/MantidCurveFitting/Functions/FunctionGenerator.h + inc/MantidCurveFitting/Functions/FunctionQDepends.h inc/MantidCurveFitting/Functions/GausDecay.h inc/MantidCurveFitting/Functions/GausOsc.h inc/MantidCurveFitting/Functions/Gaussian.h @@ -376,6 +378,7 @@ set ( TEST_FILES Functions/ExpDecayTest.h Functions/FlatBackgroundTest.h Functions/FullprofPolynomialTest.h + Functions/FunctionQDependsTest.h Functions/GausDecayTest.h Functions/GausOscTest.h Functions/GaussianComptonProfileTest.h diff --git a/Framework/CurveFitting/inc/MantidCurveFitting/Functions/FunctionQDepends.h b/Framework/CurveFitting/inc/MantidCurveFitting/Functions/FunctionQDepends.h new file mode 100644 index 0000000000000000000000000000000000000000..d28c2701ae1005e39b5bdfd1a3731af35e124d24 --- /dev/null +++ b/Framework/CurveFitting/inc/MantidCurveFitting/Functions/FunctionQDepends.h @@ -0,0 +1,81 @@ +#ifndef MANTID_CURVEFITTING_FUNCTIONQDEPENDS_H_ +#define MANTID_CURVEFITTING_FUNCTIONQDEPENDS_H_ + +// Mantid Coding standars <http://www.mantidproject.org/Coding_Standards> + +// Mantid Headers from the same project +#include "MantidAPI/IFunction.h" +#include "MantidAPI/IFunction1D.h" +#include "MantidAPI/ParamFunction.h" +// Mantid headers from other projects +// N/A +// 3rd party library headers +// N/A +// Standard library +// N/A + +namespace Mantid { +namespace CurveFitting { +namespace Functions { + +/** This is a specialization of IFunction1D for functions having the magnitude + of the momentum transfer (Q) as attribute. + + Main features of this interface: + - Declares attributes "Q" and "WorkspaceIndex" + - Implements setMatrixWorkspace + - Extracts or compute Q values for each spectra, if possible + + @author Jose Borreguero, NScD-ORNL + @date 12/10/2016 + + Copyright © 2009 ISIS Rutherford Appleton Laboratory, NScD Oak Ridge + National Laboratory & European Spallation Source + + This file is part of Mantid. + + Mantid is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + Mantid is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + + File change history is stored at: <https://github.com/mantidproject/mantid>. + Code Documentation is available at: <http://doxygen.mantidproject.org> +*/ + +class DLLExport FunctionQDepends : public Mantid::API::IFunction1D, + Mantid::API::ParamFunction { + +public: + /* ------------------- + Overridden methods + -------------------*/ + virtual void declareAttributes() override; + virtual void + setAttribute(const std::string &attName, + const Mantid::API::IFunction::Attribute &attValue) override; + void setMatrixWorkspace( + boost::shared_ptr<const Mantid::API::MatrixWorkspace> workspace, + size_t wi, double startX, double endX) override; + +private: + std::vector<double> + extractQValues(const Mantid::API::MatrixWorkspace &workspace); + // list of Q values associated to the spectra + std::vector<double> m_vQ; + +}; // end of class FunctionQDepends + +} // namespace Functions +} // namespace CurveFitting +} // namespace Mantid + +#endif /*MANTID_CURVEFITTING_FUNCTIONQDEPENDS_H_*/ diff --git a/Framework/CurveFitting/inc/MantidCurveFitting/Functions/IkedaCarpenterPV.h b/Framework/CurveFitting/inc/MantidCurveFitting/Functions/IkedaCarpenterPV.h index ea596f6573049ae25213db7a5dfbc5218cfd5d59..ae97e2c00daac7a74cad5dfc5af2f662856e0f6b 100644 --- a/Framework/CurveFitting/inc/MantidCurveFitting/Functions/IkedaCarpenterPV.h +++ b/Framework/CurveFitting/inc/MantidCurveFitting/Functions/IkedaCarpenterPV.h @@ -54,13 +54,8 @@ public: std::string name() const override { return "IkedaCarpenterPV"; } const std::string category() const override { return "Peak"; } - // define these instead of functionLocal if you want to custom specify the - // calculation - // domain for this function - // virtual void function(double* out, const double* xValues, const int& - // nData)const; - // virtual void functionDeriv(API::Jacobian* out, const double* xValues, const - // int& nData); + /// Returns the integral intensity of the peak + double intensity() const override; protected: void functionLocal(double *out, const double *xValues, diff --git a/Framework/CurveFitting/inc/MantidCurveFitting/Functions/Voigt.h b/Framework/CurveFitting/inc/MantidCurveFitting/Functions/Voigt.h index 36b14ecff7d2c7b9164599b21079dc94e83c9890..c959d433208105829fbb328988ee1ed8901e7ca4 100644 --- a/Framework/CurveFitting/inc/MantidCurveFitting/Functions/Voigt.h +++ b/Framework/CurveFitting/inc/MantidCurveFitting/Functions/Voigt.h @@ -65,6 +65,10 @@ private: void setHeight(const double value) override; /// Set the FWHM of the peak void setFwhm(const double value) override; + /// Returns the integral intensity of the peak + double intensity() const override; + /// Sets the integral intensity of the peak + void setIntensity(const double value) override; }; } // namespace Functions diff --git a/Framework/CurveFitting/inc/MantidCurveFitting/IFittingAlgorithm.h b/Framework/CurveFitting/inc/MantidCurveFitting/IFittingAlgorithm.h index 063888dce51367cd611677c822aebffb648d7887..0abe12832cbc8a9f1429ea903ceb9c6d272dd4cb 100644 --- a/Framework/CurveFitting/inc/MantidCurveFitting/IFittingAlgorithm.h +++ b/Framework/CurveFitting/inc/MantidCurveFitting/IFittingAlgorithm.h @@ -75,7 +75,7 @@ protected: std::vector<std::string> getCostFunctionNames() const; void declareCostFunctionProperty(); boost::shared_ptr<CostFunctions::CostFuncFitting> - getCostFunctionProperty() const; + getCostFunctionInitialized() const; /// Keep the domain type API::IDomainCreator::DomainType m_domainType{API::IDomainCreator::Simple}; diff --git a/Framework/CurveFitting/src/Algorithms/CalculateCostFunction.cpp b/Framework/CurveFitting/src/Algorithms/CalculateCostFunction.cpp index 30c9e6d89e7cffbe1acc776c27081a68186baa72..80f18582b398b17f9b9a98a3707f8ec75240976f 100644 --- a/Framework/CurveFitting/src/Algorithms/CalculateCostFunction.cpp +++ b/Framework/CurveFitting/src/Algorithms/CalculateCostFunction.cpp @@ -43,7 +43,7 @@ void CalculateCostFunction::initConcrete() { void CalculateCostFunction::execConcrete() { if (!m_costFunction) { - m_costFunction = getCostFunctionProperty(); + m_costFunction = getCostFunctionInitialized(); } // Get the result. diff --git a/Framework/CurveFitting/src/Algorithms/ConvertToYSpace.cpp b/Framework/CurveFitting/src/Algorithms/ConvertToYSpace.cpp index fe99f86d374f3b2d78dec702556751f331c83415..ebdd1b3b3d162c5cf6494b2f1003759f3c2fb64d 100644 --- a/Framework/CurveFitting/src/Algorithms/ConvertToYSpace.cpp +++ b/Framework/CurveFitting/src/Algorithms/ConvertToYSpace.cpp @@ -4,6 +4,7 @@ #include "MantidAPI/HistogramValidator.h" #include "MantidAPI/InstrumentValidator.h" #include "MantidAPI/MatrixWorkspace.h" +#include "MantidAPI/SpectrumInfo.h" #include "MantidAPI/WorkspaceFactory.h" #include "MantidAPI/WorkspaceUnitValidator.h" #include "MantidGeometry/Instrument.h" @@ -196,6 +197,11 @@ void ConvertToYSpace::exec() { const int64_t nreports = nhist; auto progress = boost::make_shared<Progress>(this, 0.0, 1.0, nreports); + auto &spectrumInfo = m_outputWS->mutableSpectrumInfo(); + SpectrumInfo *qSpectrumInfo{nullptr}; + if (m_qOutputWS) + qSpectrumInfo = &m_qOutputWS->mutableSpectrumInfo(); + PARALLEL_FOR_IF(Kernel::threadSafe(*m_inputWS, *m_outputWS)) for (int64_t i = 0; i < nhist; ++i) { PARALLEL_START_INTERUPT_REGION @@ -203,9 +209,12 @@ void ConvertToYSpace::exec() { if (!convert(i)) { g_log.warning("No detector defined for index=" + std::to_string(i) + ". Zeroing spectrum."); - m_outputWS->maskWorkspaceIndex(i); - if (m_qOutputWS) - m_qOutputWS->maskWorkspaceIndex(i); + m_outputWS->getSpectrum(i).clearData(); + spectrumInfo.setMasked(i, true); + if (m_qOutputWS) { + m_qOutputWS->getSpectrum(i).clearData(); + qSpectrumInfo->setMasked(i, true); + } } PARALLEL_END_INTERUPT_REGION diff --git a/Framework/CurveFitting/src/Algorithms/EstimateFitParameters.cpp b/Framework/CurveFitting/src/Algorithms/EstimateFitParameters.cpp index 417f84b03b8010940ba3cbcc0682a08c401f0ef9..680aa066e296164a201a07e47cdfa715bd91bb87 100644 --- a/Framework/CurveFitting/src/Algorithms/EstimateFitParameters.cpp +++ b/Framework/CurveFitting/src/Algorithms/EstimateFitParameters.cpp @@ -3,6 +3,9 @@ #include "MantidAPI/ConstraintFactory.h" #include "MantidAPI/CostFunctionFactory.h" #include "MantidAPI/Expression.h" +#include "MantidAPI/ITableWorkspace.h" +#include "MantidAPI/TableRow.h" +#include "MantidAPI/WorkspaceFactory.h" #include "MantidCurveFitting/Constraints/BoundaryConstraint.h" #include "MantidCurveFitting/CostFunctions/CostFuncFitting.h" #include "MantidCurveFitting/Functions/ChebfunBase.h" @@ -10,6 +13,7 @@ #include "MantidKernel/MersenneTwister.h" #include "MantidKernel/NormalDistribution.h" +#include <map> #include <numeric> namespace Mantid { @@ -102,6 +106,39 @@ void fixBadParameters(CostFunctions::CostFuncFitting &costFunction, } } +/// A class for sorting and storing sets of best function parameters. +class BestParameters { + /// Maximum size of the store + size_t m_size; + /// Actual storage. + std::map<double, GSLVector> m_params; + +public: + /// Constructor + explicit BestParameters(size_t size) : m_size(size) {} + /// Test a cost function value if corresponding parameters must be stored. + bool isOneOfBest(double value) const { + return m_params.size() < m_size || value < m_params.rbegin()->first; + } + /// Insert a set of parameters to the store. + void insertParams(double value, const GSLVector ¶ms) { + if (m_params.size() == m_size) { + auto it = m_params.find(m_params.rbegin()->first); + m_params.erase(it); + } + m_params[value] = params; + } + /// Return all stored parameters, drop function values. + std::vector<GSLVector> getParams() const { + std::vector<GSLVector> res; + res.reserve(m_params.size()); + for (auto &it : m_params) { + res.push_back(it.second); + } + return res; + } +}; + /// Run the Monte Carlo version of the algorithm. /// Generate random values of function parameters and return those that /// give the smallest cost function. @@ -111,19 +148,22 @@ void fixBadParameters(CostFunctions::CostFuncFitting &costFunction, /// @param constraints :: Additional constraints. /// @param nSamples :: A number of samples to generate. /// @param seed :: A seed for the random number generator. -void runMonteCarlo(CostFunctions::CostFuncFitting &costFunction, - const std::vector<std::pair<double, double>> &ranges, - const std::vector<std::unique_ptr<IConstraint>> &constraints, - size_t nSamples, size_t seed) { +std::vector<GSLVector> +runMonteCarlo(CostFunctions::CostFuncFitting &costFunction, + const std::vector<std::pair<double, double>> &ranges, + const std::vector<std::unique_ptr<IConstraint>> &constraints, + const size_t nSamples, const size_t nOutput, const size_t seed) { Kernel::MersenneTwister randGenerator; if (seed != 0) { randGenerator.setSeed(seed); } - double bestValue = costFunction.val() + getConstraints(constraints); + double value = costFunction.val() + getConstraints(constraints); auto nParams = costFunction.nParams(); - GSLVector bestParams; - costFunction.getParameters(bestParams); + GSLVector params; + costFunction.getParameters(params); + BestParameters bestParams(nOutput); + bestParams.insertParams(value, params); // Implicit cast from int to size_t for (size_t it = 0; it < nSamples; ++it) { @@ -136,18 +176,20 @@ void runMonteCarlo(CostFunctions::CostFuncFitting &costFunction, if (getConstraints(constraints) > 0.0) { continue; } - auto value = costFunction.val(); + value = costFunction.val(); if (costFunction.nParams() != nParams) { throw std::runtime_error("Cost function changed number of parameters " + std::to_string(nParams) + " -> " + std::to_string(costFunction.nParams())); } - if (value < bestValue) { - bestValue = value; - costFunction.getParameters(bestParams); + if (bestParams.isOneOfBest(value)) { + costFunction.getParameters(params); + bestParams.insertParams(value, params); } } - costFunction.setParameters(bestParams); + auto outputParams = bestParams.getParams(); + costFunction.setParameters(outputParams.front()); + return outputParams; } /// Run the Cross Entropy version of the algorithm. /// https://en.wikipedia.org/wiki/Cross-entropy_method @@ -283,6 +325,14 @@ void EstimateFitParameters::initConcrete() { declareProperty( "Type", "Monte Carlo", "Type of the algorithm: \"Monte Carlo\" or \"Cross Entropy\""); + declareProperty("NOutputs", 10, "Number of parameter sets to output to " + "OutputWorkspace. Unused if OutputWorkspace " + "isn't set. (Monte Carlo only)"); + declareProperty(Kernel::make_unique<WorkspaceProperty<ITableWorkspace>>( + "OutputWorkspace", "", Direction::Output, + Mantid::API::PropertyMode::Optional), + "Optional: A table workspace with parameter sets producing " + "the smallest values of cost function. (Monte Carlo only)"); declareProperty("NIterations", 10, "Number of iterations of the Cross Entropy algorithm."); declareProperty("Selection", 10, "Size of the selection in the Cross Entropy " @@ -300,7 +350,7 @@ void EstimateFitParameters::initConcrete() { //---------------------------------------------------------------------------------------------- /// Execute the algorithm. void EstimateFitParameters::execConcrete() { - auto costFunction = getCostFunctionProperty(); + auto costFunction = getCostFunctionInitialized(); auto func = costFunction->getFittingFunction(); // Use additional constraints on parameters tied in some way @@ -359,7 +409,35 @@ void EstimateFitParameters::execConcrete() { size_t seed = static_cast<int>(getProperty("Seed")); if (getPropertyValue("Type") == "Monte Carlo") { - runMonteCarlo(*costFunction, ranges, constraints, nSamples, seed); + int nOutput = getProperty("NOutputs"); + auto outputWorkspaceProp = getPointerToProperty("OutputWorkspace"); + if (outputWorkspaceProp->isDefault() || nOutput <= 0) { + nOutput = 1; + } + auto output = runMonteCarlo(*costFunction, ranges, constraints, nSamples, + static_cast<size_t>(nOutput), seed); + + if (!outputWorkspaceProp->isDefault()) { + auto table = API::WorkspaceFactory::Instance().createTable(); + auto column = table->addColumn("str", "Name"); + column->setPlotType(6); + for (size_t i = 0; i < output.size(); ++i) { + column = table->addColumn("double", std::to_string(i + 1)); + column->setPlotType(2); + } + + for (size_t i = 0, ia = 0; i < m_function->nParams(); ++i) { + if (!m_function->isFixed(i)) { + TableRow row = table->appendRow(); + row << m_function->parameterName(i); + for (size_t j = 0; j < output.size(); ++j) { + row << output[j][ia]; + } + ++ia; + } + } + setProperty("OutputWorkspace", table); + } } else { size_t nSelection = static_cast<int>(getProperty("Selection")); size_t nIterations = static_cast<int>(getProperty("NIterations")); diff --git a/Framework/CurveFitting/src/Algorithms/Fit.cpp b/Framework/CurveFitting/src/Algorithms/Fit.cpp index b946fc42a3b2720916bda2c7d9e8b81f0c64dc16..9fedae9cd1637ca5abe1c96ed6dceb6109a02feb 100644 --- a/Framework/CurveFitting/src/Algorithms/Fit.cpp +++ b/Framework/CurveFitting/src/Algorithms/Fit.cpp @@ -4,9 +4,7 @@ #include "MantidCurveFitting/Algorithms/Fit.h" #include "MantidCurveFitting/CostFunctions/CostFuncFitting.h" -#include "MantidAPI/CostFunctionFactory.h" #include "MantidAPI/FuncMinimizerFactory.h" -#include "MantidAPI/FunctionValues.h" #include "MantidAPI/IFuncMinimizer.h" #include "MantidAPI/ITableWorkspace.h" #include "MantidAPI/MatrixWorkspace.h" @@ -130,32 +128,16 @@ void Fit::execConcrete() { m_function->addConstraints(contstraints); } - // prepare the function for a fit - m_function->setUpForFit(); + auto costFunc = getCostFunctionInitialized(); - API::FunctionDomain_sptr domain; - API::FunctionValues_sptr values; - m_domainCreator->createDomain(domain, values); - - // do something with the function which may depend on workspace - m_domainCreator->initFunction(m_function); + // Try to retrieve optional properties + int intMaxIterations = getProperty("MaxIterations"); + const size_t maxIterations = static_cast<size_t>(intMaxIterations); // get the minimizer std::string minimizerName = getPropertyValue("Minimizer"); API::IFuncMinimizer_sptr minimizer = API::FuncMinimizerFactory::Instance().createMinimizer(minimizerName); - - // Try to retrieve optional properties - int intMaxIterations = getProperty("MaxIterations"); - const size_t maxIterations = static_cast<size_t>(intMaxIterations); - - // get the cost function which must be a CostFuncFitting - boost::shared_ptr<CostFunctions::CostFuncFitting> costFunc = - boost::dynamic_pointer_cast<CostFunctions::CostFuncFitting>( - API::CostFunctionFactory::Instance().create( - getPropertyValue("CostFunction"))); - - costFunc->setFittingFunction(m_function, domain, values); minimizer->initialize(costFunc, maxIterations); const int64_t nsteps = maxIterations * m_function->estimateNoProgressCalls(); @@ -201,7 +183,7 @@ void Fit::execConcrete() { setPropertyValue("OutputStatus", errorString); // degrees of freedom - size_t dof = domain->size() - costFunc->nParams(); + size_t dof = costFunc->getDomain()->size() - costFunc->nParams(); if (dof == 0) dof = 1; double rawcostfuncval = minimizer->costFunctionVal(); @@ -352,8 +334,8 @@ void Fit::execConcrete() { } m_domainCreator->separateCompositeMembersInOutput(unrollComposites, convolveMembers); - m_domainCreator->createOutputWorkspace(baseName, m_function, domain, - values); + m_domainCreator->createOutputWorkspace( + baseName, m_function, costFunc->getDomain(), costFunc->getValues()); } } diff --git a/Framework/CurveFitting/src/Algorithms/LeBailFunction.cpp b/Framework/CurveFitting/src/Algorithms/LeBailFunction.cpp index a85af08502f8ccd97498e50cea3c1275831d541a..6c617604a56a9bdee5ed1fdc7c7a2bfe1b2a2b8e 100644 --- a/Framework/CurveFitting/src/Algorithms/LeBailFunction.cpp +++ b/Framework/CurveFitting/src/Algorithms/LeBailFunction.cpp @@ -106,7 +106,7 @@ LeBailFunction::function(const Mantid::HistogramData::HistogramX &xvalues, // Reset output elements to zero std::vector<double> out(xvalues.size(), 0); - auto xvals = xvalues.rawData(); + const auto &xvals = xvalues.rawData(); // Peaks if (calpeaks) { @@ -799,12 +799,9 @@ void LeBailFunction::groupPeaks( if (thispeak_rightbound < rightpeak_leftbound) { // this peak and its right peak are well separated. - // finish this group by a copy - vector<pair<double, IPowderDiffPeakFunction_sptr>> peakgroupcopy = - peakgroup; - peakgroupvec.push_back(peakgroupcopy); - // clear for the next group - peakgroup.clear(); + // finish this group by swapping values + peakgroupvec.push_back(std::move(peakgroup)); + peakgroup = {}; } else { // this peak and its right peak are close enough to be in same group. // do nothing @@ -812,9 +809,7 @@ void LeBailFunction::groupPeaks( } } else { // Rightmost peak. Finish the current peak - vector<pair<double, IPowderDiffPeakFunction_sptr>> peakgroupcopy = - peakgroup; - peakgroupvec.push_back(peakgroupcopy); + peakgroupvec.push_back(peakgroup); } ++ipk; @@ -827,17 +822,14 @@ void LeBailFunction::groupPeaks( << "peak over at maximum TOF = " << xmax << ".\n"; if (!peakgroup.empty()) { - vector<pair<double, IPowderDiffPeakFunction_sptr>> peakgroupcopy = - peakgroup; - peakgroupvec.push_back(peakgroupcopy); + peakgroupvec.push_back(peakgroup); } } // FIRST out of boundary } // ENDWHILE while (ipk < m_numPeaks) { // Group peaks out of uppper boundary to a separate vector of peaks - IPowderDiffPeakFunction_sptr thispeak = m_dspPeakVec[ipk].second; - outboundpeakvec.push_back(thispeak); + outboundpeakvec.push_back(m_dspPeakVec[ipk].second); ipk += 1; } diff --git a/Framework/CurveFitting/src/Algorithms/PlotPeakByLogValue.cpp b/Framework/CurveFitting/src/Algorithms/PlotPeakByLogValue.cpp index 415298121a8ce27786df0925435175a46418e6e2..a3ae14b5c0bd4d8b04dcf85d69dc8804f6b5051e 100644 --- a/Framework/CurveFitting/src/Algorithms/PlotPeakByLogValue.cpp +++ b/Framework/CurveFitting/src/Algorithms/PlotPeakByLogValue.cpp @@ -114,6 +114,14 @@ void PlotPeakByLogValue::init() { declareProperty("MaxIterations", 500, "Stop after this number of iterations if a good fit is not " "found"); + declareProperty("PeakRadius", 0, + "A value of the peak radius the peak functions should use. A " + "peak radius defines an interval on the x axis around the " + "centre of the peak where its values are calculated. Values " + "outside the interval are not calculated and assumed zeros." + "Numerically the radius is a whole number of peak widths " + "(FWHM) that fit into the interval on each side from the " + "centre. The default value of 0 means the whole x axis."); declareProperty("CreateOutput", false, "Set to true to create output " "workspaces with the results of the " @@ -292,6 +300,7 @@ void PlotPeakByLogValue::exec() { fit->setPropertyValue("CostFunction", getPropertyValue("CostFunction")); fit->setPropertyValue("MaxIterations", getPropertyValue("MaxIterations")); + fit->setPropertyValue("PeakRadius", getPropertyValue("PeakRadius")); fit->setProperty("CalcErrors", true); fit->setProperty("CreateOutput", createFitOutput); if (!histogramFit) { @@ -636,7 +645,7 @@ std::string PlotPeakByLogValue::getMinimizerString(const std::string &wsName, Mantid::API::WorkspaceProperty<> *wsProp = dynamic_cast<Mantid::API::WorkspaceProperty<> *>(minimizerProp); if (wsProp) { - std::string wsPropValue = minimizerProp->value(); + const std::string &wsPropValue = minimizerProp->value(); if (wsPropValue != "") { std::string wsPropName = minimizerProp->name(); m_minimizerWorkspaces[wsPropName].push_back(wsPropValue); diff --git a/Framework/CurveFitting/src/FitMW.cpp b/Framework/CurveFitting/src/FitMW.cpp index e6476795227c74aad3531f76fbdc3f86fe5fd476..807884f4fbc7ae1e0037f897838b13237fbb7d21 100644 --- a/Framework/CurveFitting/src/FitMW.cpp +++ b/Framework/CurveFitting/src/FitMW.cpp @@ -187,9 +187,9 @@ void FitMW::createDomain(boost::shared_ptr<API::FunctionDomain> &domain, { if (!m_ignoreInvalidData) throw std::runtime_error("Infinte number or NaN found in input data."); - y = 0.0; // leaving inf or nan would break the fit - } else if (!std::isfinite(error)) // nan or inf error - { + y = 0.0; // leaving inf or nan would break the fit + } else if (!std::isfinite(error)) { + // nan or inf error if (!m_ignoreInvalidData) throw std::runtime_error("Infinte number or NaN found in input data."); } else if (error <= 0) { @@ -197,6 +197,12 @@ void FitMW::createDomain(boost::shared_ptr<API::FunctionDomain> &domain, weight = 1.0; } else { weight = 1.0 / error; + if (!std::isfinite(weight)) { + if (!m_ignoreInvalidData) + throw std::runtime_error( + "Error of a data point is probably too small."); + weight = 0.0; + } } values->setFitData(j, y); diff --git a/Framework/CurveFitting/src/Functions/CrystalFieldSpectrum.cpp b/Framework/CurveFitting/src/Functions/CrystalFieldSpectrum.cpp index 47a690e4bf7fd806464c70aa434d67a46b181c3c..c4ef20fd81fb0ceffc0f39770e819453b9743d2d 100644 --- a/Framework/CurveFitting/src/Functions/CrystalFieldSpectrum.cpp +++ b/Framework/CurveFitting/src/Functions/CrystalFieldSpectrum.cpp @@ -104,7 +104,7 @@ std::string CrystalFieldSpectrum::asString() const { std::vector<std::string> attr = this->getAttributeNames(); for (const auto &attName : attr) { std::string attValue = this->getAttribute(attName).value(); - if (!attValue.empty() && attValue != "\"\"") { + if (!attValue.empty() && attValue != "\"\"" && attValue != "()") { ostr << ',' << attName << '=' << attValue; } } diff --git a/Framework/CurveFitting/src/Functions/DeltaFunction.cpp b/Framework/CurveFitting/src/Functions/DeltaFunction.cpp index baab6b8cd5aa9b8978e41bdf41bf156fdda3a685..3640a821ff0c52f38d33fea71c0dd55fe4b80198 100644 --- a/Framework/CurveFitting/src/Functions/DeltaFunction.cpp +++ b/Framework/CurveFitting/src/Functions/DeltaFunction.cpp @@ -17,7 +17,7 @@ using namespace API; DECLARE_FUNCTION(DeltaFunction) -DeltaFunction::DeltaFunction() { +DeltaFunction::DeltaFunction() : IPeakFunction() { declareParameter("Height", 1.0, "Scaling factor to be applied to the resolution."); declareParameter("Centre", 0.0, diff --git a/Framework/CurveFitting/src/Functions/FunctionQDepends.cpp b/Framework/CurveFitting/src/Functions/FunctionQDepends.cpp new file mode 100644 index 0000000000000000000000000000000000000000..22490bfb7ed19ccba574e5fa44114baba1a51a16 --- /dev/null +++ b/Framework/CurveFitting/src/Functions/FunctionQDepends.cpp @@ -0,0 +1,157 @@ +// Mantid Coding standars <http://www.mantidproject.org/Coding_Standards> + +// Main Module Header +#include "MantidCurveFitting/Functions/FunctionQDepends.h" +// Mantid Headers from the same project +// N/A +// Mantid headers from other projects +#include "MantidAPI/MatrixWorkspace.h" +#include "MantidAPI/NumericAxis.h" +#include "MantidKernel/UnitConversion.h" +#include "MantidAPI/SpectrumInfo.h" +// third party libraries +// N/A +// standard library +// N/A + +using Attr = Mantid::API::IFunction::Attribute; + +namespace { +Mantid::Kernel::Logger g_log("FunctionQDepends"); +} + +namespace Mantid { +namespace CurveFitting { +namespace Functions { + +/* =========== + Public + ===========*/ + +/** + * @brief declare commonattributes Q and WorkspaceIndex. + * Subclasses containing additional attributes should override this method by + * declaring the additional + * attributes and then calling the parent (this) method to declare Q and + * WorkspaceIndex. + */ +void FunctionQDepends::declareAttributes() { + this->declareAttribute("Q", Attr(EMPTY_DBL())); + this->declareAttribute("WorkspaceIndex", Attr(EMPTY_INT())); +} + +/** + * @brief Update attributes WorkspaceIndex and Q according to certain precedence + *rules. + * Subclasses featuring additional attributes should override and insert a call + *to + * this method within the overriding setAttribute function. + * There are two ways to update Q: (i) loading the value from the spectrum, and + *(ii) manual + * input from the user. Therefore, rules of precedence must be set to prevent + *conflict. The + * priority is to accept Q from the spectrum, if a Q value can be derived from + *such. In + * this case the existing Q value will be overwritten, irrespective of the + *mannier in which + * the old Q value was set. + * + * @param attName name of the attribute + * @param attValue value of the attribute + */ +void FunctionQDepends::setAttribute(const std::string &attName, + const Attr &attValue) { + // Q value is tied to WorkspaceIndex if we have a list of Q values + if (attName == "WorkspaceIndex") { + size_t wi{static_cast<size_t>( + attValue.asInt())}; // ah!, the "joys" of C++ strong typing. + if (!m_vQ.empty() && wi < m_vQ.size()) { + Mantid::API::IFunction::setAttribute(attName, attValue); + Mantid::API::IFunction::setAttribute("Q", Attribute(m_vQ.at(wi))); + } + } + // Q can be manually changed by user only if list of Q values is empty + else if (attName == "Q") { + if (m_vQ.empty()) { + Mantid::API::IFunction::setAttribute(attName, attValue); + } + } else { + Mantid::API::IFunction::setAttribute(attName, attValue); + } +} + +/** + * @brief Learn the Q values from the workspace, if possible, and update + * attribute Q accordingly. + * @param workspace Matrix workspace + * @param wi selected spectrum to initialize attributes + * @param startX unused + * @param endX unused + */ +void FunctionQDepends::setMatrixWorkspace( + boost::shared_ptr<const Mantid::API::MatrixWorkspace> workspace, size_t wi, + double startX, double endX) { + UNUSED_ARG(startX); + UNUSED_ARG(endX); + // reset attributes if new workspace is passed + if (!m_vQ.empty()) { + Mantid::API::IFunction::setAttribute("WorkspaceIndex", Attr(EMPTY_INT())); + Mantid::API::IFunction::setAttribute("Q", Attr(EMPTY_DBL())); + } + // Obtain Q values from the passed workspace, if possible. m_vQ will be + // cleared if unsuccessful. + if (workspace) { + m_vQ = this->extractQValues(*workspace); + } + if (!m_vQ.empty()) { + this->setAttribute("WorkspaceIndex", Attr(static_cast<int>(wi))); + } +} + +/* =========== + Private + ===========*/ + +/** + * @brief Extract Q values from vertical dimension of the workspace, or compute + * them. + * @param workspace workspace possibly containing Q values. + */ +std::vector<double> FunctionQDepends::extractQValues( + const Mantid::API::MatrixWorkspace &workspace) { + std::vector<double> qs; + // Check if the vertical axis has units of momentum transfer, then extract Q + // values... + auto axis_ptr = + dynamic_cast<Mantid::API::NumericAxis *>(workspace.getAxis(1)); + if (axis_ptr) { + const boost::shared_ptr<Kernel::Unit> &unit_ptr = axis_ptr->unit(); + if (unit_ptr->unitID() == "MomentumTransfer") { + qs = axis_ptr->getValues(); + } + } + // ...otherwise, compute the momentum transfer for each spectrum, if possible + else { + const auto &spectrumInfo = workspace.spectrumInfo(); + size_t numHist = workspace.getNumberHistograms(); + for (size_t wi = 0; wi < numHist; wi++) { + try { + Mantid::Geometry::IDetector_const_sptr detector; + detector = workspace.getDetector(wi); + double efixed = workspace.getEFixed(detector); + double usignTheta = 0.5 * spectrumInfo.twoTheta(wi); + double q = Mantid::Kernel::UnitConversion::run(usignTheta, efixed); + qs.push_back(q); + } catch (Kernel::Exception::NotFoundError &) { + g_log.debug("Cannot populate Q values from workspace"); + qs.clear(); + break; + } + } + } + return qs; +} + +} // namespace Functions +} // namespace CurveFitting +} // namespace Mantid \ No newline at end of file diff --git a/Framework/CurveFitting/src/Functions/IkedaCarpenterPV.cpp b/Framework/CurveFitting/src/Functions/IkedaCarpenterPV.cpp index ab44b09e234523102e4c725b4139ac73d2fd6fd0..1fce22558c9cb3fe1358d98efa37e464629891b9 100644 --- a/Framework/CurveFitting/src/Functions/IkedaCarpenterPV.cpp +++ b/Framework/CurveFitting/src/Functions/IkedaCarpenterPV.cpp @@ -6,6 +6,7 @@ #include "MantidCurveFitting/SpecialFunctionSupport.h" #include "MantidAPI/MatrixWorkspace.h" #include "MantidAPI/FunctionFactory.h" +#include "MantidAPI/PeakFunctionIntegrator.h" #include "MantidKernel/UnitFactory.h" #include <cmath> #include <gsl/gsl_math.h> @@ -373,6 +374,21 @@ void IkedaCarpenterPV::functionDeriv(const API::FunctionDomain &domain, calNumericalDeriv(domain, jacobian); } +/// Returns the integral intensity of the peak +double IkedaCarpenterPV::intensity() const { + auto interval = getDomainInterval(1e-2); + + API::PeakFunctionIntegrator integrator; + API::IntegrationResult result = + integrator.integrate(*this, interval.first, interval.second); + + if (!result.success) { + return 0.0; + } + + return result.result; +} + } // namespace Functions } // namespace CurveFitting } // namespace Mantid diff --git a/Framework/CurveFitting/src/Functions/Voigt.cpp b/Framework/CurveFitting/src/Functions/Voigt.cpp index 3228667bdc3e9c67644d05855aec7d74830b4185..5f2cfb84f84d0aa1ef6e65baaa6ee38d75f992ed 100644 --- a/Framework/CurveFitting/src/Functions/Voigt.cpp +++ b/Framework/CurveFitting/src/Functions/Voigt.cpp @@ -6,6 +6,7 @@ #include "MantidAPI/FunctionFactory.h" #include <cmath> +#include <limits> namespace Mantid { namespace CurveFitting { @@ -132,7 +133,16 @@ double Voigt::centre() const { return getParameter(LORENTZ_POS); } * Return the value of the "LorentzAmp" parameter * @return value of height of peak */ -double Voigt::height() const { return 2.0 * getParameter(LORENTZ_AMP) / 3.0; } +double Voigt::height() const { + if (getParameter(LORENTZ_AMP) == 0.0 || getParameter(LORENTZ_FWHM) == 0.0 || + getParameter(GAUSSIAN_FWHM) == 0.0) { + return 0.0; + } + double pos = getParameter(LORENTZ_POS); + double h; + functionLocal(&h, &pos, 1); + return h; +} /** * Gives the FWHM of the peak. This is estimated as @@ -156,7 +166,22 @@ void Voigt::setCentre(const double value) { * @param value :: The new value for the centre of the peak */ void Voigt::setHeight(const double value) { - this->setParameter(LORENTZ_AMP, 1.5 * value); + auto lorentzFwhm = getParameter(LORENTZ_FWHM); + if (lorentzFwhm == 0.0) { + lorentzFwhm = std::numeric_limits<double>::epsilon(); + setParameter(LORENTZ_FWHM, lorentzFwhm); + } + auto lorentzAmp = getParameter(LORENTZ_AMP); + if (lorentzAmp == 0.0) { + lorentzAmp = std::numeric_limits<double>::epsilon(); + setParameter(LORENTZ_AMP, lorentzAmp); + } + auto gaussFwhm = getParameter(GAUSSIAN_FWHM); + if (gaussFwhm == 0.0) { + setParameter(GAUSSIAN_FWHM, std::numeric_limits<double>::epsilon()); + } + auto h = height(); + this->setParameter(LORENTZ_AMP, lorentzAmp * value / h); } /** @@ -164,8 +189,44 @@ void Voigt::setHeight(const double value) { * @param value :: The new value for the FWHM of the peak */ void Voigt::setFwhm(const double value) { - this->setParameter(LORENTZ_FWHM, 0.5 * value); - this->setParameter(GAUSSIAN_FWHM, 0.5 * value); + auto lorentzFwhm = getParameter(LORENTZ_FWHM); + if (lorentzFwhm == 0.0) { + lorentzFwhm = std::numeric_limits<double>::epsilon(); + } + auto gaussFwhm = getParameter(GAUSSIAN_FWHM); + if (gaussFwhm == 0.0) { + gaussFwhm = std::numeric_limits<double>::epsilon(); + } + auto ratio = lorentzFwhm / (lorentzFwhm + gaussFwhm); + this->setParameter(LORENTZ_FWHM, ratio * value); + this->setParameter(GAUSSIAN_FWHM, (1.0 - ratio) * value); +} + +/** + * Returns the integral intensity of the peak + */ +double Voigt::intensity() const { + if (getParameter(GAUSSIAN_FWHM) == 0.0) { + return 0.0; + } + return M_PI * getParameter(LORENTZ_AMP) * getParameter(LORENTZ_FWHM) / 2.0; +} + +/** + * Sets the integral intensity of the peak + * @param value :: The new value for the intensity. + */ +void Voigt::setIntensity(const double value) { + auto lorentzFWHM = getParameter(LORENTZ_FWHM); + if (lorentzFWHM == 0.0) { + lorentzFWHM = std::numeric_limits<double>::epsilon(); + setParameter(LORENTZ_FWHM, lorentzFWHM); + } + auto gaussFwhm = getParameter(GAUSSIAN_FWHM); + if (gaussFwhm == 0.0) { + setParameter(GAUSSIAN_FWHM, std::numeric_limits<double>::epsilon()); + } + setParameter(LORENTZ_AMP, 2.0 * value / (M_PI * lorentzFWHM)); } } // namespace Functions diff --git a/Framework/CurveFitting/src/IFittingAlgorithm.cpp b/Framework/CurveFitting/src/IFittingAlgorithm.cpp index 60190da0a709a8bd1ba4e02cc30b9f6813c024c8..c228967f6ff1402b4bb75d0fa7d7aedae21eb9ca 100644 --- a/Framework/CurveFitting/src/IFittingAlgorithm.cpp +++ b/Framework/CurveFitting/src/IFittingAlgorithm.cpp @@ -93,6 +93,14 @@ void IFittingAlgorithm::init() { "centre of each bin. If it is \"Histogram\" then function is " "integrated within the bin and the integrals returned.", Kernel::Direction::Input); + declareProperty("PeakRadius", 0, + "A value of the peak radius the peak functions should use. A " + "peak radius defines an interval on the x axis around the " + "centre of the peak where its values are calculated. Values " + "outside the interval are not calculated and assumed zeros." + "Numerically the radius is a whole number of peak widths " + "(FWHM) that fit into the interval on each side from the " + "centre. The default value of 0 means the whole x axis."); initConcrete(); } @@ -290,9 +298,10 @@ void IFittingAlgorithm::declareCostFunctionProperty() { Kernel::Direction::InOut); } -/// Create a cost function from the "CostFunction" property. +/// Create a cost function from the "CostFunction" property +/// and make it ready for evaluation. boost::shared_ptr<CostFunctions::CostFuncFitting> -IFittingAlgorithm::getCostFunctionProperty() const { +IFittingAlgorithm::getCostFunctionInitialized() const { // Function may need some preparation. m_function->setUpForFit(); @@ -300,6 +309,15 @@ IFittingAlgorithm::getCostFunctionProperty() const { API::FunctionValues_sptr values; m_domainCreator->createDomain(domain, values); + // Set peak radius to the values which will be passed to + // all IPeakFunctions + int peakRadius = getProperty("PeakRadius"); + if (auto d1d = dynamic_cast<API::FunctionDomain1D *>(domain.get())) { + if (peakRadius != 0) { + d1d->setPeakRadius(peakRadius); + } + } + // Do something with the function which may depend on workspace. m_domainCreator->initFunction(m_function); diff --git a/Framework/CurveFitting/test/Algorithms/EstimateFitParametersTest.h b/Framework/CurveFitting/test/Algorithms/EstimateFitParametersTest.h index 73440bcc4c69e39c6dbac580be9149af34c8a580..0e25179a7808241e5b7a39bfd6c1fd55190e61ca 100644 --- a/Framework/CurveFitting/test/Algorithms/EstimateFitParametersTest.h +++ b/Framework/CurveFitting/test/Algorithms/EstimateFitParametersTest.h @@ -237,6 +237,47 @@ public: TS_ASSERT(!fun->isFixed(fun->parameterIndex("I"))); TS_ASSERT(!fun->isFixed(fun->parameterIndex("S"))); } + + void test_output() { + auto ws = WorkspaceCreationHelper::create2DWorkspaceFromFunction( + [](double x, int) { return 2.0 + 3.0 * x; }, 1, 0, 1, 0.1); + + std::string funStr( + "name=UserFunction,Formula=a*x+b,a=0,b=0,constraints=(1<a<4, 0<b<4)"); + EstimateFitParameters alg; + alg.initialize(); + alg.setRethrows(true); + alg.setPropertyValue("Function", funStr); + alg.setProperty("InputWorkspace", ws); + alg.setProperty("OutputWorkspace", "out"); + alg.execute(); + IFunction_sptr fun = alg.getProperty("Function"); + auto params = + AnalysisDataService::Instance().retrieveWS<ITableWorkspace>("out"); + TS_ASSERT(params); + TS_ASSERT_EQUALS(params->rowCount(), 2); + TS_ASSERT_EQUALS(params->columnCount(), 11); + + double costValue = 0.0; + auto names = params->getColumn(0); + for (size_t col = 1; col < params->columnCount(); ++col) { + auto column = params->getColumn(col); + for (size_t row = 0; row < column->size(); ++row) { + fun->setParameter(names->cell<std::string>(row), + column->cell<double>(row)); + } + CalculateCostFunction calc; + calc.initialize(); + calc.setProperty("Function", fun); + calc.setProperty("InputWorkspace", ws); + calc.execute(); + double value = calc.getProperty("Value"); + TSM_ASSERT_LESS_THAN( + "Parameter sets aren't sorted by cost function value.", costValue, + value); + } + AnalysisDataService::Instance().clear(); + } }; #endif /* MANTID_CURVEFITTING_ESTIMATEFITPARAMETERSTEST_H_ */ diff --git a/Framework/CurveFitting/test/Algorithms/EstimatePeakErrorsTest.h b/Framework/CurveFitting/test/Algorithms/EstimatePeakErrorsTest.h index b38019f242745343b5e6af70aec35363dce7f015..17ebd69ae348f7b4bf9ca060eff278228895bdf7 100644 --- a/Framework/CurveFitting/test/Algorithms/EstimatePeakErrorsTest.h +++ b/Framework/CurveFitting/test/Algorithms/EstimatePeakErrorsTest.h @@ -148,14 +148,14 @@ public: TS_ASSERT_EQUALS(res->cell<std::string>(3, 0), "f0.Intensity"); TS_ASSERT_DELTA(res->cell<double>(0, 1), -3.9865, 1e-4); - TS_ASSERT_DELTA(res->cell<double>(1, 1), 3.1881, 1e-4); - TS_ASSERT_DELTA(res->cell<double>(2, 1), 2.0011, 1e-4); - TS_ASSERT_DELTA(res->cell<double>(3, 1), 10.0218, 1e-4); + TS_ASSERT_DELTA(res->cell<double>(1, 1), 3.1883, 1e-4); + TS_ASSERT_DELTA(res->cell<double>(2, 1), 2.0007, 1e-4); + TS_ASSERT_DELTA(res->cell<double>(3, 1), 10.0200, 1e-4); TS_ASSERT_DELTA(res->cell<double>(0, 2), 0.1764, 1e-4); - TS_ASSERT_DELTA(res->cell<double>(1, 2), 0.5690, 1e-4); - TS_ASSERT_DELTA(res->cell<double>(2, 2), 0.5968, 1e-4); - TS_ASSERT_DELTA(res->cell<double>(3, 2), 2.6126, 1e-4); + TS_ASSERT_DELTA(res->cell<double>(1, 2), 0.5684, 1e-4); + TS_ASSERT_DELTA(res->cell<double>(2, 2), 0.6063, 1e-4); + TS_ASSERT_DELTA(res->cell<double>(3, 2), 2.6687, 1e-4); TS_ASSERT_EQUALS(res->cell<std::string>(4, 0), "f1.Centre"); TS_ASSERT_EQUALS(res->cell<std::string>(5, 0), "f1.Height"); @@ -165,12 +165,12 @@ public: TS_ASSERT_DELTA(res->cell<double>(4, 1), 3.0064, 1e-4); TS_ASSERT_DELTA(res->cell<double>(5, 1), 2.1327, 1e-4); TS_ASSERT_DELTA(res->cell<double>(6, 1), 2.9908, 1e-4); - TS_ASSERT_DELTA(res->cell<double>(7, 1), 10.0196, 1e-4); + TS_ASSERT_DELTA(res->cell<double>(7, 1), 10.0188, 1e-4); - TS_ASSERT_DELTA(res->cell<double>(4, 2), 0.3234, 1e-4); - TS_ASSERT_DELTA(res->cell<double>(5, 2), 0.4756, 1e-4); - TS_ASSERT_DELTA(res->cell<double>(6, 2), 1.2002, 1e-4); - TS_ASSERT_DELTA(res->cell<double>(7, 2), 3.7937, 1e-4); + TS_ASSERT_DELTA(res->cell<double>(4, 2), 0.3232, 1e-4); + TS_ASSERT_DELTA(res->cell<double>(5, 2), 0.4771, 1e-4); + TS_ASSERT_DELTA(res->cell<double>(6, 2), 1.2008, 1e-4); + TS_ASSERT_DELTA(res->cell<double>(7, 2), 3.8074, 1e-4); AnalysisDataService::Instance().clear(); } @@ -206,13 +206,13 @@ public: TS_ASSERT_DELTA(res->cell<double>(0, 1), -4.0000, 1e-4); TS_ASSERT_DELTA(res->cell<double>(1, 1), 3.1878, 1e-4); - TS_ASSERT_DELTA(res->cell<double>(2, 1), 2.0012, 1e-4); - TS_ASSERT_DELTA(res->cell<double>(3, 1), 10.0207, 1e-4); + TS_ASSERT_DELTA(res->cell<double>(2, 1), 2.0006, 1e-4); + TS_ASSERT_DELTA(res->cell<double>(3, 1), 10.0181, 1e-4); TS_ASSERT_DELTA(res->cell<double>(0, 2), 0.0000, 1e-4); - TS_ASSERT_DELTA(res->cell<double>(1, 2), 0.5609, 1e-4); - TS_ASSERT_DELTA(res->cell<double>(2, 2), 0.5797, 1e-4); - TS_ASSERT_DELTA(res->cell<double>(3, 2), 2.4090, 1e-4); + TS_ASSERT_DELTA(res->cell<double>(1, 2), 0.5605, 1e-4); + TS_ASSERT_DELTA(res->cell<double>(2, 2), 0.5872, 1e-4); + TS_ASSERT_DELTA(res->cell<double>(3, 2), 2.4510, 1e-4); TS_ASSERT_EQUALS(res->cell<std::string>(4, 0), "f1.Centre"); TS_ASSERT_EQUALS(res->cell<std::string>(5, 0), "f1.Height"); @@ -221,12 +221,12 @@ public: TS_ASSERT_DELTA(res->cell<double>(4, 1), 3.0056, 1e-4); TS_ASSERT_DELTA(res->cell<double>(5, 1), 2.1320, 1e-4); - TS_ASSERT_DELTA(res->cell<double>(6, 1), 2.9921, 1e-4); - TS_ASSERT_DELTA(res->cell<double>(7, 1), 10.0207, 1e-4); + TS_ASSERT_DELTA(res->cell<double>(6, 1), 2.9915, 1e-4); + TS_ASSERT_DELTA(res->cell<double>(7, 1), 10.0181, 1e-4); - TS_ASSERT_DELTA(res->cell<double>(4, 2), 0.3231, 1e-4); - TS_ASSERT_DELTA(res->cell<double>(5, 2), 0.4668, 1e-4); - TS_ASSERT_DELTA(res->cell<double>(6, 2), 0.6551, 1e-4); + TS_ASSERT_DELTA(res->cell<double>(4, 2), 0.3229, 1e-4); + TS_ASSERT_DELTA(res->cell<double>(5, 2), 0.4677, 1e-4); + TS_ASSERT_DELTA(res->cell<double>(6, 2), 0.6563, 1e-4); TS_ASSERT_DELTA(res->cell<double>(7, 2), 0.0000, 1e-4); AnalysisDataService::Instance().clear(); diff --git a/Framework/CurveFitting/test/Algorithms/FitTest.h b/Framework/CurveFitting/test/Algorithms/FitTest.h index c6d7aabc540e7451d55fd68a0c88ccf3599a7784..822660ba5bdf26cf9f240a060b3bd20c0f966387 100644 --- a/Framework/CurveFitting/test/Algorithms/FitTest.h +++ b/Framework/CurveFitting/test/Algorithms/FitTest.h @@ -831,24 +831,40 @@ public: auto &y = data->dataY(0); auto &e = data->dataE(0); - y = {0, -1.77636e-16, -1.77636e-16, 0, -1.77636e-16, -8.88178e-17, - -1.33227e-16, 0, 0, 8.88178e-17, 3.33067e-17, 1.11022e-17, 1.27676e-16, - 6.66134e-17, 8.32667e-17, 3.88578e-17, 9.4369e-17, 1.44329e-16, - 2.66454e-16, 5.10703e-15, 9.80105e-14, 1.63027e-12, 2.31485e-11, - 2.80779e-10, 2.91067e-09, 2.58027e-08, 1.9575e-07, 1.27204e-06, - 7.08849e-06, 3.39231e-05, 0.000139678, 0.000496012, 0.00152387, - 0.0040672, 0.00948273, 0.0194574, 0.0354878, 0.0583005, 0.0877657, - 0.123662, 0.167048, 0.221547, 0.293962, 0.393859, 0.531629, 0.714256, - 0.938713, 1.18531, 1.41603, 1.58257, 1.64355, 1.58257, 1.41603, - 1.18531, 0.938713, 0.714256, 0.531629, 0.393859, 0.293962, 0.221547, - 0.167048, 0.123662, 0.0877657, 0.0583005, 0.0354878, 0.0194574, - 0.00948273, 0.0040672, 0.00152387, 0.000496012, 0.000139678, - 3.39231e-05, 7.08849e-06, 1.27204e-06, 1.9575e-07, 2.58027e-08, - 2.91067e-09, 2.80779e-10, 2.31486e-11, 1.63033e-12, 9.80771e-14, - 5.09592e-15, 2.77556e-16, 3.88578e-17, 2.22045e-17, -1.66533e-17, - -1.11022e-17, 0, -7.21645e-17, -8.88178e-17, -1.11022e-16, - -1.33227e-16, -4.44089e-17, -1.77636e-16, -1.33227e-16, -8.88178e-17, - -3.55271e-16, -8.88178e-17, -1.77636e-16, -1.77636e-16}; + y = {0.00679397551246448, 0.00684266083126313, 0.00698285916556982, + 0.00719965548825388, 0.00747519954546736, 0.00779445649068509, + 0.00814796531751759, 0.0085316132498512, 0.00894499942724, + 0.00938983058044737, 0.0098689280357672, 0.0103857911674609, + 0.0109444805899566, 0.0115496436468315, 0.0122065986210473, + 0.0129214505517302, 0.0137012349575442, 0.0145540939647495, + 0.0154894928726603, 0.0165184880798197, 0.0176540608380039, + 0.01891153608981, 0.0203091122610038, 0.021868537134057, + 0.0236159780401305, 0.0255831534292171, 0.0278088202944704, + 0.0303407524938984, 0.0332384060776671, 0.0365765613911014, + 0.0404503783689891, 0.0449825362752094, 0.0503335145708212, + 0.0567167210280417, 0.0644212970503862, 0.0738474209204705, + 0.085562497139828, 0.10039290319273, 0.119576178650528, + 0.145011665152563, 0.17965292804199, 0.228047317644744, + 0.296874083423821, 0.394987350612542, 0.532006328704948, + 0.714364415633021, 0.938739703160756, 1.18531948194073, + 1.41603503739802, 1.58257225395956, 1.64354644127685, + 1.58257225395956, 1.41603503739802, 1.18531948194073, + 0.938739703160756, 0.714364415633021, 0.532006328704948, + 0.394987350612542, 0.296874083423821, 0.228047317644743, + 0.17965292804199, 0.145011665152563, 0.119576178650528, + 0.10039290319273, 0.085562497139828, 0.0738474209204706, + 0.0644212970503863, 0.0567167210280418, 0.0503335145708214, + 0.0449825362752095, 0.0404503783689893, 0.0365765613911016, + 0.0332384060776675, 0.0303407524938988, 0.0278088202944705, + 0.0255831534292172, 0.0236159780401305, 0.0218685371340571, + 0.0203091122610038, 0.0189115360898101, 0.0176540608380039, + 0.0165184880798196, 0.0154894928726603, 0.0145540939647495, + 0.0137012349575443, 0.0129214505517302, 0.0122065986210471, + 0.0115496436468314, 0.0109444805899566, 0.0103857911674609, + 0.00986892803576708, 0.00938983058044717, 0.00894499942723977, + 0.00853161324985108, 0.0081479653175175, 0.00779445649068496, + 0.00747519954546727, 0.00719965548825406, 0.00698285916556974, + 0.00684266083126313}; x = {-10, -9.8, -9.6, -9.4, -9.2, -9, -8.8, -8.6, -8.4, -8.2, -8, -7.8, -7.6, -7.4, -7.2, -7, -6.8, -6.6, -6.4, -6.2, -6, -5.8, -5.6, -5.4, @@ -1970,6 +1986,49 @@ public: TS_ASSERT_DELTA(out->getParameter("A2"), 1.0, 0.0001); } + void test_PeakRadius() { + size_t nbins = 100; + auto ws = + WorkspaceFactory::Instance().create("Workspace2D", 1, nbins, nbins); + FunctionDomain1DVector x(-10, 10, nbins); + ws->dataX(0) = x.toVector(); + { + Fit fit; + fit.initialize(); + fit.setProperty("Function", "name=Lorentzian,Amplitude=5,FWHM=1"); + fit.setProperty("InputWorkspace", ws); + fit.setProperty("MaxIterations", 0); + fit.setProperty("Output", "out"); + fit.execute(); + auto res = AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>( + "out_Workspace"); + auto y = res->y(1); + TS_ASSERT_DIFFERS(y.front(), 0.0); + TS_ASSERT_DIFFERS(y.back(), 0.0); + } + { + Fit fit; + fit.initialize(); + fit.setProperty("Function", "name=Lorentzian,Amplitude=5,FWHM=1"); + fit.setProperty("InputWorkspace", ws); + fit.setProperty("PeakRadius", 5); + fit.setProperty("MaxIterations", 0); + fit.setProperty("Output", "out"); + fit.execute(); + auto res = AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>( + "out_Workspace"); + auto y = res->y(1); + for (size_t i = 0; i < 25; ++i) { + TS_ASSERT_EQUALS(y[i], 0.0); + TS_ASSERT_EQUALS(y[nbins - i - 1], 0.0); + } + TS_ASSERT_DIFFERS(y[26], 0.0); + TS_ASSERT_DIFFERS(y[26], 0.0); + } + + AnalysisDataService::Instance().clear(); + } + private: /// build test input workspaces for the Pawley function Fit tests MatrixWorkspace_sptr getWorkspacePawley(const std::string &functionString, @@ -2043,7 +2102,8 @@ public: } void test_fit_peaks_Damping() { - runFitAlgorithm(m_onePeakWS, FitTestHelpers::SingleB2BPeak, "Damping"); + runFitAlgorithm(m_onePeakWS, FitTestHelpers::SingleB2BPeak, + "Damped GaussNewton"); } void test_fit_peaks_SteepestDescent() { @@ -2086,7 +2146,8 @@ public: } void test_fit_smooth_Damping() { - runFitAlgorithm(m_smoothWS, FitTestHelpers::SmoothishGaussians, "Damping"); + runFitAlgorithm(m_smoothWS, FitTestHelpers::SmoothishGaussians, + "Damped GaussNewton"); } // disabled: too slow: ~17s diff --git a/Framework/CurveFitting/test/Functions/CrystalFieldMultiSpectrumTest.h b/Framework/CurveFitting/test/Functions/CrystalFieldMultiSpectrumTest.h index d36f4d4425fc4ff2cefc9ce25e15e01b3496ee9b..2e3029f73323d5b7fe04667ee5ff54fd6b4aed71 100644 --- a/Framework/CurveFitting/test/Functions/CrystalFieldMultiSpectrumTest.h +++ b/Framework/CurveFitting/test/Functions/CrystalFieldMultiSpectrumTest.h @@ -148,14 +148,14 @@ public: TS_ASSERT_EQUALS(out->getNumberHistograms(), 3); TS_ASSERT_DELTA(out->readY(1)[0], 1.094 * 2.0 * c_mbsr, 0.001 * c_mbsr); TS_ASSERT_DELTA(out->readY(1)[1], 0.738 * 2.0 * c_mbsr, 0.001 * c_mbsr); - TS_ASSERT_DELTA(out->readY(1)[2], 0.373 * 2.0 * c_mbsr, 0.001 * c_mbsr); + TS_ASSERT_DELTA(out->readY(1)[2], 59.5010, 0.001); out = AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>( "Workspace_1"); TS_ASSERT(out); TS_ASSERT_EQUALS(out->getNumberHistograms(), 3); TS_ASSERT_DELTA(out->readY(1)[0], 1.094 * 3.3 * c_mbsr, 0.001 * c_mbsr); TS_ASSERT_DELTA(out->readY(1)[1], 0.738 * 3.3 * c_mbsr, 0.001 * c_mbsr); - TS_ASSERT_DELTA(out->readY(1)[2], 0.3734 * 3.3 * c_mbsr, 0.001 * c_mbsr); + TS_ASSERT_DELTA(out->readY(1)[2], 98.1627, 0.001); AnalysisDataService::Instance().clear(); } diff --git a/Framework/CurveFitting/test/Functions/DeltaFunctionTest.h b/Framework/CurveFitting/test/Functions/DeltaFunctionTest.h index a6873994c0fb319cb6d6ca47ebaa538cccb3f681..164f9feb4f1b3be27c0f8da146a4f522b0afd5ac 100644 --- a/Framework/CurveFitting/test/Functions/DeltaFunctionTest.h +++ b/Framework/CurveFitting/test/Functions/DeltaFunctionTest.h @@ -127,7 +127,6 @@ public: } void test_delta_with_shift() { - IPeakFunction::setPeakRadius(1000); auto res = IPeakFunction_sptr(new DeltaFunctionTest_Gauss()); double a = 0.13; double ha = 1.0 / sqrt(M_PI * a); @@ -169,7 +168,6 @@ public: } void test_two_deltas_with_shifts() { - IPeakFunction::setPeakRadius(1000); auto res = IPeakFunction_sptr(new DeltaFunctionTest_Gauss()); double a = 0.13; double ha = 1.0 / sqrt(M_PI * a); diff --git a/Framework/CurveFitting/test/Functions/DiffSphereTest.h b/Framework/CurveFitting/test/Functions/DiffSphereTest.h index f1dbd7e00fe7de7e8dc491b8d3b76120f5ca84c8..91b4019a44516ff37cace8bfbab256f87b08468b 100644 --- a/Framework/CurveFitting/test/Functions/DiffSphereTest.h +++ b/Framework/CurveFitting/test/Functions/DiffSphereTest.h @@ -73,6 +73,7 @@ public: fitalg.setProperty("Function", funtion_string); fitalg.setProperty("InputWorkspace", data_workspace); fitalg.setPropertyValue("WorkspaceIndex", "0"); + fitalg.setProperty("IgnoreInvalidData", true); TS_ASSERT_THROWS_NOTHING(TS_ASSERT(fitalg.execute())); TS_ASSERT(fitalg.isExecuted()); diff --git a/Framework/CurveFitting/test/Functions/FunctionQDependsTest.h b/Framework/CurveFitting/test/Functions/FunctionQDependsTest.h new file mode 100644 index 0000000000000000000000000000000000000000..1860a032320980e32c2fbd7df29003145ed6ae2d --- /dev/null +++ b/Framework/CurveFitting/test/Functions/FunctionQDependsTest.h @@ -0,0 +1,173 @@ +#ifndef MANTID_CURVEFITTING_FUNCTIONQDEPENDSTEST_H +#define MANTID_CURVEFITTING_FUNCTIONQDEPENDSTEST_H + +// Mantid Coding standars <http://www.mantidproject.org/Coding_Standards> + +// Mantid Headers from the same project +#include "MantidCurveFitting/Functions/FunctionQDepends.h" +// Mantid headers from other projects +#include "MantidAPI/IFunction.h" +#include "MantidAPI/ParamFunction.h" +#include "MantidAPI/NumericAxis.h" +#include "MantidAPI/MatrixWorkspace.h" +#include "MantidDataObjects/Workspace2D.h" +#include "MantidTestHelpers/WorkspaceCreationHelper.h" +#include "MantidKernel/EmptyValues.h" +#include "MantidDataHandling/LoadNexus.h" +// 3rd party library headers +#include <cxxtest/TestSuite.h> +// Standard library +// N/A + +using Attr = Mantid::API::IFunction::Attribute; + +namespace { +class ImplementsFunctionQDepends + : public Mantid::CurveFitting::Functions::FunctionQDepends { + +public: + std::string name() const override { return "ImplementsFunctionQDepends"; } + + void function1D(double *out, const double *xValues, + const size_t nData) const override { + double Q = this->getAttribute("Q").asDouble(); + for (size_t i = 0; i < nData; i++) { + out[i] = Q * xValues[i]; + } + } +}; +} // end of namespace + +class FunctionQDependsTest : public CxxTest::TestSuite { + +public: + // This pair of boilerplate methods prevent the suite being created statically + // This means the constructor isn't called when running other tests + static FunctionQDependsTest *createSuite() { + return new FunctionQDependsTest(); + } + static void destroySuite(FunctionQDependsTest *suite) { delete suite; } + + void testConstruction() { + TS_ASSERT_THROWS_NOTHING(ImplementsFunctionQDepends f); + } + + void testInitialization() { + ImplementsFunctionQDepends f; + TS_ASSERT_THROWS_NOTHING(f.initialize()); + } + + void testSetWorkspace() { + double startX{0.0}, endX{1.0}; + ImplementsFunctionQDepends f; + f.initialize(); // declare attributes + // test with an non matrix workspace + TS_ASSERT_THROWS_NOTHING( + f.setMatrixWorkspace(this->unsuitableWS(), 0, startX, endX)); + // test with a non-suitable matrix workspace + TS_ASSERT_THROWS_NOTHING( + f.setMatrixWorkspace(this->withoutQ(), 0, startX, endX)); + // test with a workspace containing Q values in the vertical axis + TS_ASSERT_THROWS_NOTHING( + f.setMatrixWorkspace(this->withQonVerticalAxis(), 0, startX, endX)); + // test with a workspace containing detectors for calculation of Q values + TS_ASSERT_THROWS_NOTHING( + f.setMatrixWorkspace(this->withDetectors(), 0, startX, endX)); + } + + void testQAttribute() { + double startX{0.0}, endX{1.0}; + ImplementsFunctionQDepends f; + f.initialize(); // declare attributes + auto Q = f.getAttribute("Q").asDouble(); + TS_ASSERT_EQUALS(Q, Mantid::EMPTY_DBL()); + f.setMatrixWorkspace(this->unsuitableWS(), 0, startX, endX); + TS_ASSERT_EQUALS(Q, Mantid::EMPTY_DBL()); + f.setMatrixWorkspace(this->withoutQ(), 0, startX, endX); + TS_ASSERT_EQUALS(Q, Mantid::EMPTY_DBL()); + // test assigning Q when no matrix workspace has been set + f.setAttribute("Q", Attr(0.18)); + TS_ASSERT_EQUALS(f.getAttribute("Q").asDouble(), 0.18); + // test assigning Q when a workspace has been set + f.setMatrixWorkspace(this->withQonVerticalAxis(), 1, startX, endX); + TS_ASSERT_EQUALS(f.getAttribute("Q").asDouble(), 0.5); // Q overwritten + f.setAttribute("Q", Attr(0.18)); + TS_ASSERT_EQUALS(f.getAttribute("Q").asDouble(), 0.5); // Q not overwritten + } + + void testWorkspaceIndexAttribute() { + double startX{0.0}, endX{1.0}; + ImplementsFunctionQDepends f; + f.initialize(); // declare attributes + auto wi = f.getAttribute("WorkspaceIndex").asInt(); + TS_ASSERT_EQUALS(wi, Mantid::EMPTY_INT()); + f.setMatrixWorkspace(this->unsuitableWS(), 0, startX, endX); + TS_ASSERT_EQUALS(wi, Mantid::EMPTY_INT()); + f.setMatrixWorkspace(this->withoutQ(), 0, startX, endX); + TS_ASSERT_EQUALS(wi, Mantid::EMPTY_INT()); + // test assigning wi when no matrix workspace has been set + f.setAttribute("WorkspaceIndex", Attr(1)); + TS_ASSERT_EQUALS(f.getAttribute("WorkspaceIndex").asInt(), + Mantid::EMPTY_INT()); // not overwritten + // test assigning wi when a workspace has been set + f.setMatrixWorkspace(this->withQonVerticalAxis(), 1, startX, endX); + TS_ASSERT_EQUALS(f.getAttribute("WorkspaceIndex").asInt(), 1); + f.setAttribute("WorkspaceIndex", Attr(0)); + TS_ASSERT_EQUALS(f.getAttribute("WorkspaceIndex").asInt(), + 0); // WorkspaceIndex overwritten + } + + void testWorkspaceIndexTiesQ() { + double startX{0.0}, endX{1.0}; + ImplementsFunctionQDepends f; + f.initialize(); // declare attributes + f.setMatrixWorkspace(this->withQonVerticalAxis(), 1, startX, endX); + TS_ASSERT_EQUALS(f.getAttribute("Q").asDouble(), 0.5); // Q overwritten + f.setAttribute("WorkspaceIndex", Attr(0)); + TS_ASSERT_EQUALS(f.getAttribute("Q").asDouble(), 0.3); // Q overwritten + f.setMatrixWorkspace(this->withDetectors(), 9, startX, endX); + TS_ASSERT_DELTA(f.getAttribute("Q").asDouble(), 1.82, + 0.01); // Q overwritten + Mantid::API::AnalysisDataService::Instance().clear(); + } + +private: + // return a MatrixWorkspace with Q values on the vertical axis + Mantid::DataObjects::Workspace2D_sptr withQonVerticalAxis() { + int nhist{4}, nbins{9}; + // create an axis of Q-values + std::vector<double> qvalues{ + 0.3, 0.5, 0.5, 0.9}; // as many elements as the value of variable nhist + auto momenta = new Mantid::API::NumericAxis(qvalues); + momenta->setUnit("MomentumTransfer"); + // create the matrix workspace + auto ws = WorkspaceCreationHelper::create2DWorkspaceBinned(nhist, nbins); + ws->replaceAxis(1, momenta); + return ws; + } + + // return a MatrixWorkspace with detectors allowing computations of Q values + Mantid::API::MatrixWorkspace_sptr withDetectors() { + Mantid::DataHandling::LoadNexus loader; + loader.initialize(); + loader.setPropertyValue("Filename", "irs26173_graphite002_red"); + loader.setPropertyValue("OutputWorkspace", "irs26173"); + TS_ASSERT_THROWS_NOTHING(loader.execute()); + TS_ASSERT(loader.isExecuted()); + return Mantid::API::AnalysisDataService::Instance() + .retrieveWS<Mantid::API::MatrixWorkspace>("irs26173"); + } + + // return a MatrixWorkspace without Q values + Mantid::DataObjects::Workspace2D_sptr withoutQ() { + int nhist{3}, nbins{9}; + return WorkspaceCreationHelper::create2DWorkspaceBinned(nhist, nbins); + } + + // return a Workspace not of MatrixWorkspace type + Mantid::DataObjects::EventWorkspace_sptr unsuitableWS() { + return WorkspaceCreationHelper::createEventWorkspace(); + } +}; + +#endif /* MANTID_API_FUNCTIONQDEPENDSTEST_H */ diff --git a/Framework/CurveFitting/test/Functions/IkedaCarpenterPVTest.h b/Framework/CurveFitting/test/Functions/IkedaCarpenterPVTest.h index 5ef06fa8236207d4497cf6154e477670faa9d2da..6285adf379bafde31d3faa212ef52e2567bae6ee 100644 --- a/Framework/CurveFitting/test/Functions/IkedaCarpenterPVTest.h +++ b/Framework/CurveFitting/test/Functions/IkedaCarpenterPVTest.h @@ -56,6 +56,20 @@ public: TS_ASSERT_DELTA(y[13], 77.7493, 1e-4); TS_ASSERT_DELTA(y[14], 53.8871, 1e-4); } + + void test_intensity() { + IkedaCarpenterPV fn; + fn.initialize(); + fn.setParameter("I", 67.2548); + fn.setParameter("Alpha0", 1.6); + fn.setParameter("Alpha1", 1.5); + fn.setParameter("Beta0", 31.9); + fn.setParameter("Kappa", 46.0); + fn.setParameter("SigmaSquared", 0.00281776); + fn.setParameter("Gamma", 0.125); + fn.setParameter("X0", 0); + TS_ASSERT_DELTA(fn.intensity(), 810.7256, 1e-4); + } }; #endif /*IKEDACARPENTERPVTEST_H_*/ diff --git a/Framework/CurveFitting/test/Functions/VoigtTest.h b/Framework/CurveFitting/test/Functions/VoigtTest.h index 74c76e0aa518baa8c9d7ed76c45d70b2b04ea523..34d940fac854c525e2a8d2d8ec4f1a5b5d0ad6b1 100644 --- a/Framework/CurveFitting/test/Functions/VoigtTest.h +++ b/Framework/CurveFitting/test/Functions/VoigtTest.h @@ -14,6 +14,7 @@ using Mantid::CurveFitting::Functions::Voigt; using Mantid::API::IFunction; +using Mantid::API::IPeakFunction; class VoigtTest : public CxxTest::TestSuite { public: @@ -104,7 +105,7 @@ public: boost::dynamic_pointer_cast<Mantid::API::IPeakFunction>(voigtFn); TS_ASSERT_DELTA(peakFn->centre(), pos, 1e-12); - TS_ASSERT_DELTA(peakFn->height(), 2.0 * a_L / 3.0, 1e-12); + TS_ASSERT_DELTA(peakFn->height(), 4.9570, 1e-4); TS_ASSERT_DELTA(peakFn->fwhm(), (gamma_L + gamma_G), 1e-12); } @@ -128,16 +129,150 @@ public: TS_ASSERT_DELTA(peakFn->fwhm(), (gamma_L + gamma_G), 1e-12); } + void test_height() { + { + auto voigt = createFunction(0, 0, 0, 0); + TS_ASSERT_EQUALS(voigt->height(), 0.0); + voigt->setHeight(3.0); + TS_ASSERT_DELTA(voigt->height(), 3.0, 1e-10); + TS_ASSERT_DELTA(voigt->fwhm(), 0, 1e-10); + TS_ASSERT_DELTA(voigt->intensity(), 0, 1e-10); + } + { + auto voigt = createFunction(1, 0, 0, 0); + TS_ASSERT_EQUALS(voigt->height(), 0.0); + voigt->setHeight(3.0); + TS_ASSERT_DELTA(voigt->height(), 3.0, 1e-10); + TS_ASSERT_DELTA(voigt->fwhm(), 0, 1e-10); + TS_ASSERT_DELTA(voigt->intensity(), 0, 1e-10); + } + { + auto voigt = createFunction(1, 0, 1, 0); + TS_ASSERT_EQUALS(voigt->height(), 0.0); + voigt->setHeight(3.0); + TS_ASSERT_DELTA(voigt->height(), 3.0, 1e-10); + TS_ASSERT_DELTA(voigt->fwhm(), 1, 1e-10); + TS_ASSERT_DELTA(voigt->intensity(), 4.7123, 1e-4); + } + { + auto voigt = createFunction(1, 0, 0, 1); + TS_ASSERT_EQUALS(voigt->height(), 0.0); + voigt->setHeight(3.0); + TS_ASSERT_DELTA(voigt->height(), 3.0, 1e-10); + TS_ASSERT_DELTA(voigt->fwhm(), 1, 1e-10); + TS_ASSERT_DELTA(voigt->intensity(), 3.1933, 1e-4); + } + { + auto voigt = createFunction(0, 0, 1, 1); + TS_ASSERT_EQUALS(voigt->height(), 0.0); + voigt->setHeight(3.0); + TS_ASSERT_DELTA(voigt->height(), 3.0, 1e-10); + TS_ASSERT_DELTA(voigt->fwhm(), 2, 1e-10); + TS_ASSERT_DELTA(voigt->intensity(), 6.6795, 1e-4); + } + { + auto voigt = createFunction(4, 0, 2, 3); + TS_ASSERT_DELTA(voigt->height(), 2.3159, 1e-4); + voigt->setHeight(3.0); + TS_ASSERT_DELTA(voigt->height(), 3.0, 1e-10); + TS_ASSERT_DELTA(voigt->fwhm(), 5, 1e-10); + TS_ASSERT_DELTA(voigt->intensity(), 16.2778, 1e-4); + } + } + + void test_intensity() { + { + auto voigt = createFunction(0, 0, 0, 0); + TS_ASSERT_EQUALS(voigt->intensity(), 0.0); + voigt->setIntensity(3.0); + TS_ASSERT_DELTA(voigt->height(), 6068115080134125.22, 1e10); + TS_ASSERT_DELTA(voigt->fwhm(), 0, 1e-10); + TS_ASSERT_DELTA(voigt->intensity(), 3.0, 1e-10); + } + { + auto voigt = createFunction(1, 0, 0, 0); + TS_ASSERT_EQUALS(voigt->intensity(), 0.0); + voigt->setIntensity(3.0); + TS_ASSERT_DELTA(voigt->height(), 6068115080134125.22, 1e10); + TS_ASSERT_DELTA(voigt->fwhm(), 0, 1e-10); + TS_ASSERT_DELTA(voigt->intensity(), 3.0, 1e-10); + } + { + auto voigt = createFunction(1, 0, 0, 1); + TS_ASSERT_EQUALS(voigt->intensity(), 0.0); + voigt->setIntensity(3.0); + TS_ASSERT_DELTA(voigt->height(), 2.8183, 1e-4); + TS_ASSERT_DELTA(voigt->fwhm(), 1, 1e-10); + TS_ASSERT_DELTA(voigt->intensity(), 3.0, 1e-10); + } + { + auto voigt = createFunction(1, 0, 1, 0); + TS_ASSERT_EQUALS(voigt->intensity(), 0.0); + voigt->setIntensity(3.0); + TS_ASSERT_DELTA(voigt->height(), 1.9098, 1e-4); + TS_ASSERT_DELTA(voigt->fwhm(), 1, 1e-10); + TS_ASSERT_DELTA(voigt->intensity(), 3.0, 1e-10); + } + { + auto voigt = createFunction(4, 0, 2, 3); + TS_ASSERT_DELTA(voigt->intensity(), 12.5663, 1e-4); + voigt->setIntensity(3.0); + TS_ASSERT_DELTA(voigt->height(), 0.5528, 1e-4); + TS_ASSERT_DELTA(voigt->fwhm(), 5, 1e-10); + TS_ASSERT_DELTA(voigt->intensity(), 3.0, 1e-10); + TS_ASSERT_DELTA(voigt->IPeakFunction::intensity(), 3.0, 1e-2); + } + } + + void test_fwhm() { + { + auto voigt = createFunction(0, 0, 0, 0); + TS_ASSERT_EQUALS(voigt->fwhm(), 0.0); + voigt->setFwhm(3.0); + TS_ASSERT_DELTA(voigt->height(), 0, 1e-10); + TS_ASSERT_DELTA(voigt->fwhm(), 3, 1e-10); + TS_ASSERT_DELTA(voigt->intensity(), 0.0, 1e-10); + TS_ASSERT_DELTA(voigt->getParameter("LorentzFWHM"), 1.5, 1e-10); + TS_ASSERT_DELTA(voigt->getParameter("GaussianFWHM"), 1.5, 1e-10); + } + { + auto voigt = createFunction(0, 0, 1, 0); + TS_ASSERT_EQUALS(voigt->fwhm(), 1.0); + voigt->setFwhm(3.0); + TS_ASSERT_DELTA(voigt->height(), 0, 1e-10); + TS_ASSERT_DELTA(voigt->fwhm(), 3, 1e-10); + TS_ASSERT_DELTA(voigt->intensity(), 0.0, 1e-10); + TS_ASSERT_DELTA(voigt->getParameter("LorentzFWHM"), 3.0, 1e-10); + TS_ASSERT_DELTA(voigt->getParameter("GaussianFWHM"), 0.0, 1e-10); + } + { + auto voigt = createFunction(0, 0, 0, 1); + TS_ASSERT_EQUALS(voigt->fwhm(), 1.0); + voigt->setFwhm(3.0); + TS_ASSERT_DELTA(voigt->height(), 0, 1e-10); + TS_ASSERT_DELTA(voigt->fwhm(), 3, 1e-10); + TS_ASSERT_DELTA(voigt->intensity(), 0.0, 1e-10); + TS_ASSERT_DELTA(voigt->getParameter("LorentzFWHM"), 0.0, 1e-10); + TS_ASSERT_DELTA(voigt->getParameter("GaussianFWHM"), 3.0, 1e-10); + } + { + auto voigt = createFunction(2, 0, 2, 1); + TS_ASSERT_EQUALS(voigt->fwhm(), 3.0); + voigt->setFwhm(5.5); + TS_ASSERT_DELTA(voigt->fwhm(), 5.5, 1e-10); + TS_ASSERT_DELTA(voigt->intensity(), 11.5191, 1e-4); + TS_ASSERT_DELTA(voigt->getParameter("LorentzFWHM"), 3.6666, 1e-4); + TS_ASSERT_DELTA(voigt->getParameter("GaussianFWHM"), 1.8333, 1e-4); + } + } + private: - boost::shared_ptr<IFunction> createFunction(const double a_L, - const double pos, - const double gamma_L, - const double gamma_G) { + boost::shared_ptr<Mantid::API::IPeakFunction> + createFunction(const double a_L, const double pos, const double gamma_L, + const double gamma_G) { boost::shared_ptr<IFunction> voigtFn = boost::make_shared<Voigt>(); auto peakFn = boost::dynamic_pointer_cast<Mantid::API::IPeakFunction>(voigtFn); - // Set a fairly wide radius for simple tests - peakFn->setPeakRadius(10); voigtFn->initialize(); voigtFn->setParameter("LorentzAmp", a_L); @@ -145,7 +280,7 @@ private: voigtFn->setParameter("LorentzFWHM", gamma_L); voigtFn->setParameter("GaussianFWHM", gamma_G); - return voigtFn; + return peakFn; } enum { g_domainSize = 10 }; diff --git a/Framework/DataHandling/inc/MantidDataHandling/LoadSpiceXML2DDet.h b/Framework/DataHandling/inc/MantidDataHandling/LoadSpiceXML2DDet.h index 2ca875626e948a142d4c34efaaea40519c43973e..ea13c77dc54ee1c22a7ff1b516503051e6121ad9 100644 --- a/Framework/DataHandling/inc/MantidDataHandling/LoadSpiceXML2DDet.h +++ b/Framework/DataHandling/inc/MantidDataHandling/LoadSpiceXML2DDet.h @@ -133,6 +133,9 @@ private: std::string m_idfFileName; /// User specified wave length double m_userSpecifiedWaveLength; + /// shift of detector on X and Y direction + double m_detXShift; + double m_detYShift; }; } // namespace DataHandling diff --git a/Framework/DataHandling/src/ImggAggregateWavelengths.cpp b/Framework/DataHandling/src/ImggAggregateWavelengths.cpp index e9c1f83695eefd7eb664b53fbb37c38c45db5687..797635f18381285d2b415070fbc3fd1c74dbe8ec 100644 --- a/Framework/DataHandling/src/ImggAggregateWavelengths.cpp +++ b/Framework/DataHandling/src/ImggAggregateWavelengths.cpp @@ -560,7 +560,7 @@ ImggAggregateWavelengths::findInputSubdirs(const Poco::Path &path) { // there is at least one image file: take just the first level directory if (it->isFile()) { - const std::string name = it.name(); + const std::string &name = it.name(); const std::string extShort = name.substr(name.size() - 3); const std::string extLong = name.substr(name.size() - 4); diff --git a/Framework/DataHandling/src/Load.cpp b/Framework/DataHandling/src/Load.cpp index 45f340ae1f5dc69c9fb94fbc83dacf6ecbd539c6..67a48fdfd187c47c0fc89b2153238408a6693553 100644 --- a/Framework/DataHandling/src/Load.cpp +++ b/Framework/DataHandling/src/Load.cpp @@ -243,7 +243,7 @@ void Load::declareLoaderProperties(const API::IAlgorithm_sptr &loader) { // THIS IS A COPY as the properties are mutated as we move through them const std::vector<Property *> existingProps = this->getProperties(); for (auto existingProp : existingProps) { - const std::string name = existingProp->name(); + const std::string &name = existingProp->name(); // Wipe all properties except the Load native ones if (m_baseProps.find(name) == m_baseProps.end()) { this->removeProperty(name); diff --git a/Framework/DataHandling/src/LoadCalFile.cpp b/Framework/DataHandling/src/LoadCalFile.cpp index d41a66d19ec8f33529041582b59cb2345856cb97..804decf8b19cb974817c2fc411fe8c18d215bc08 100644 --- a/Framework/DataHandling/src/LoadCalFile.cpp +++ b/Framework/DataHandling/src/LoadCalFile.cpp @@ -2,6 +2,7 @@ #include "MantidAPI/FileProperty.h" #include "MantidAPI/MatrixWorkspace.h" #include "MantidAPI/ITableWorkspace.h" +#include "MantidAPI/SpectrumInfo.h" #include "MantidAPI/Run.h" #include "MantidDataHandling/LoadCalFile.h" #include "MantidDataObjects/GroupingWorkspace.h" @@ -259,6 +260,9 @@ void LoadCalFile::readCalFile(const std::string &calFileName, int n, udet, select, group; double n_d, udet_d, offset, select_d, group_d; + SpectrumInfo *maskSpectrumInfo{nullptr}; + if (maskWS) + maskSpectrumInfo = &maskWS->mutableSpectrumInfo(); std::string str; while (getline(grFile, str)) { if (str.empty() || str[0] == '#') @@ -309,7 +313,8 @@ void LoadCalFile::readCalFile(const std::string &calFileName, if (select <= 0) { // Not selected, then mask this detector - maskWS->maskWorkspaceIndex(wi); + maskWS->getSpectrum(wi).clearData(); + maskSpectrumInfo->setMasked(wi, true); maskWS->mutableY(wi)[0] = 1.0; } else { // Selected, set the value to be 0 diff --git a/Framework/DataHandling/src/LoadEventNexus.cpp b/Framework/DataHandling/src/LoadEventNexus.cpp index c174216a327c67aa5a859f3daf50f26259cd8118..fc4e2dd7ebc05cd5ea2759b4dbdc4a5143e6bf4c 100644 --- a/Framework/DataHandling/src/LoadEventNexus.cpp +++ b/Framework/DataHandling/src/LoadEventNexus.cpp @@ -1941,8 +1941,7 @@ void LoadEventNexus::runLoadMonitorsAsEvents(API::Progress *const prog) { << "data workspace.\n"; try { auto to = m_ws->getSingleHeldWorkspace(); - auto from = dataWS; - copyLogs(from, to); + copyLogs(dataWS, to); g_log.information() << "Log data copied.\n"; } catch (std::runtime_error &) { g_log.error() diff --git a/Framework/DataHandling/src/LoadFITS.cpp b/Framework/DataHandling/src/LoadFITS.cpp index 75484764462d97af2e1c537dfc97616a53a2f859..f8ed6a97fd9dbdfe18e10a69c48d537a53898f60 100644 --- a/Framework/DataHandling/src/LoadFITS.cpp +++ b/Framework/DataHandling/src/LoadFITS.cpp @@ -473,19 +473,17 @@ void LoadFITS::doLoadFiles(const std::vector<std::string> &paths, // Create a group for these new workspaces, if the group already exists, add // to it. - std::string groupName = outWSName; - size_t fileNumberInGroup = 0; WorkspaceGroup_sptr wsGroup; - if (!AnalysisDataService::Instance().doesExist(groupName)) { - wsGroup = WorkspaceGroup_sptr(new WorkspaceGroup()); - wsGroup->setTitle(groupName); + if (!AnalysisDataService::Instance().doesExist(outWSName)) { + wsGroup = boost::make_shared<WorkspaceGroup>(); + wsGroup->setTitle(outWSName); } else { // Get the name of the latest file in group to start numbering from - if (AnalysisDataService::Instance().doesExist(groupName)) + if (AnalysisDataService::Instance().doesExist(outWSName)) wsGroup = - AnalysisDataService::Instance().retrieveWS<WorkspaceGroup>(groupName); + AnalysisDataService::Instance().retrieveWS<WorkspaceGroup>(outWSName); std::string latestName = wsGroup->getNames().back(); // Set next file number diff --git a/Framework/DataHandling/src/LoadInstrument.cpp b/Framework/DataHandling/src/LoadInstrument.cpp index 9e285030651f90d18ac60e609e8efd3981734177..3353a6d762e21731dd96ae0fcecf8476a4d438cd 100644 --- a/Framework/DataHandling/src/LoadInstrument.cpp +++ b/Framework/DataHandling/src/LoadInstrument.cpp @@ -268,7 +268,7 @@ std::string LoadInstrument::getFullPathParamIDF(std::string directoryName) { directoryPath.makeDirectory(); // Remove the path from the filename Poco::Path filePath(m_filename); - std::string instrumentFile = filePath.getFileName(); + const std::string &instrumentFile = filePath.getFileName(); // First check whether there is a parameter file whose name is the same as the // IDF file, diff --git a/Framework/DataHandling/src/LoadMLZ.cpp b/Framework/DataHandling/src/LoadMLZ.cpp index cead7cb1e2dea549cb67ab19d832cf333abebef2..8a574397602efdf3dba67348a6e7c497a057ee54 100644 --- a/Framework/DataHandling/src/LoadMLZ.cpp +++ b/Framework/DataHandling/src/LoadMLZ.cpp @@ -1,9 +1,7 @@ -//---------------------------------------------------------------------- -// Includes -//---------------------------------------------------------------------- #include "MantidDataHandling/LoadMLZ.h" #include "MantidDataHandling/LoadHelper.h" #include "MantidAPI/Axis.h" +#include "MantidAPI/DetectorInfo.h" #include "MantidAPI/FileProperty.h" #include "MantidAPI/MatrixWorkspace.h" #include "MantidAPI/Progress.h" @@ -18,7 +16,6 @@ #include <cmath> #include <limits> #include <vector> -//----------------------------------------------------------------------- namespace Mantid { namespace DataHandling { @@ -30,7 +27,6 @@ using namespace NeXus; // Register the algorithm into the AlgorithmFactory DECLARE_NEXUS_FILELOADER_ALGORITHM(LoadMLZ) -//---------------------------------------------------------------------------------------------- /** Constructor */ LoadMLZ::LoadMLZ() @@ -40,7 +36,6 @@ LoadMLZ::LoadMLZ() m_monitorCounts{0}, m_chopper_speed{0.0}, m_chopper_ratio{0}, m_l1{0.0}, m_l2{0.0}, m_t1{0.0}, m_supportedInstruments{"TOFTOF", "DNS"} {} -//--------------------------------------------------------------------------- /// Algorithm's name for identification. @see Algorithm::name const std::string LoadMLZ::name() const { return "LoadMLZ"; } @@ -50,7 +45,6 @@ int LoadMLZ::version() const { return 1; } /// Algorithm's category for identification. @see Algorithm::category const std::string LoadMLZ::category() const { return "DataHandling\\Nexus"; } -//--------------------------------------------------------------------------- /** Initialize the algorithm's properties. */ void LoadMLZ::init() { @@ -64,7 +58,6 @@ void LoadMLZ::init() { "The name to use for the output workspace"); } -//--------------------------------------------------------------------------- /** Execute the algorithm. */ void LoadMLZ::exec() { @@ -126,34 +119,23 @@ void LoadMLZ::maskDetectors(NeXus::NXEntry &entry) { g_log.debug() << "Number of masked detectors: " << masked_detectors.size() << '\n'; + auto &detInfo = m_localWorkspace->mutableDetectorInfo(); + std::vector<size_t> indicesToMask; for (auto masked_detector : masked_detectors) { g_log.debug() << "List of masked detectors: "; g_log.debug() << masked_detector; g_log.debug() << ", "; + try { + indicesToMask.push_back(detInfo.indexOf(masked_detector)); + } catch (std::out_of_range &) { + g_log.warning() << "Invalid detector ID " << masked_detector + << ". Found while running LoadMLZ\n"; + } } g_log.debug() << '\n'; - // Need to get hold of the parameter map - Geometry::ParameterMap &pmap = m_localWorkspace->instrumentParameters(); - - // If explicitly given a list of detectors to mask, just mark those. - // Otherwise, mask all detectors pointing to the requested spectra in - // indexlist loop below - std::vector<detid_t>::const_iterator it; - Geometry::Instrument_const_sptr instrument = - m_localWorkspace->getInstrument(); - if (!masked_detectors.empty()) { - for (it = masked_detectors.begin(); it != masked_detectors.end(); ++it) { - try { - if (const Geometry::ComponentID det = - instrument->getDetector(*it)->getComponentID()) { - pmap.addBool(det, "masked", true); - } - } catch (Kernel::Exception::NotFoundError &e) { - g_log.warning() << e.what() << " Found while running MaskDetectors\n"; - } - } - } + for (const auto index : indicesToMask) + detInfo.setMasked(index, true); } /** diff --git a/Framework/DataHandling/src/LoadNXSPE.cpp b/Framework/DataHandling/src/LoadNXSPE.cpp index 0dc488aa121cccc62cd513f2c6deacaa85d8f278..ed21240d1821ce6e2f2ffdb7e465c20eb0a66410 100644 --- a/Framework/DataHandling/src/LoadNXSPE.cpp +++ b/Framework/DataHandling/src/LoadNXSPE.cpp @@ -7,6 +7,7 @@ #include "MantidAPI/RegisterFileLoader.h" #include "MantidAPI/Run.h" #include "MantidAPI/SpectraAxis.h" +#include "MantidAPI/SpectrumInfo.h" #include "MantidAPI/WorkspaceFactory.h" #include <nexus/NeXusFile.hpp> @@ -294,9 +295,9 @@ void LoadNXSPE::exec() { instrument->markAsDetector(det); } - Geometry::ParameterMap &pmap = outputWS->instrumentParameters(); std::vector<double>::iterator itdata = data.begin(), iterror = error.begin(), itdataend, iterrorend; + auto &spectrumInfo = outputWS->mutableSpectrumInfo(); API::Progress prog = API::Progress(this, 0.0, 0.9, numSpectra); for (std::size_t i = 0; i < numSpectra; ++i) { itdataend = itdata + numBins; @@ -304,9 +305,7 @@ void LoadNXSPE::exec() { outputWS->dataX(i) = energies; if ((!std::isfinite(*itdata)) || (*itdata <= -1e10)) // masked bin { - outputWS->dataY(i) = std::vector<double>(numBins, 0); - outputWS->dataE(i) = std::vector<double>(numBins, 0); - pmap.addBool(outputWS->getDetector(i)->getComponentID(), "masked", true); + spectrumInfo.setMasked(i, true); } else { outputWS->dataY(i) = std::vector<double>(itdata, itdataend); outputWS->dataE(i) = std::vector<double>(iterror, iterrorend); diff --git a/Framework/DataHandling/src/LoadNXcanSAS.cpp b/Framework/DataHandling/src/LoadNXcanSAS.cpp index 858e4740eacb3547555e4f1230983156cb3456c3..dbfabd47a5a98d333f06bad186a48d14ebe1c9b7 100644 --- a/Framework/DataHandling/src/LoadNXcanSAS.cpp +++ b/Framework/DataHandling/src/LoadNXcanSAS.cpp @@ -132,7 +132,7 @@ std::string extractIdfFileOnCurrentSystem(std::string idf) { // Get the specified IDF name Poco::Path path(idf); - auto fileName = path.getFileName(); + const auto &fileName = path.getFileName(); // Compare against all available IDFs const std::vector<std::string> &directoryNames = diff --git a/Framework/DataHandling/src/LoadSpiceXML2DDet.cpp b/Framework/DataHandling/src/LoadSpiceXML2DDet.cpp index 67dec0804108200b2f81732527c4fda3a2a470a7..bfa7af894abe58907b07395ff252ba8a45065743 100644 --- a/Framework/DataHandling/src/LoadSpiceXML2DDet.cpp +++ b/Framework/DataHandling/src/LoadSpiceXML2DDet.cpp @@ -201,15 +201,23 @@ void LoadSpiceXML2DDet::init() { declareProperty("PtNumber", 0, "Pt. value for the row to get sample log from. "); + declareProperty("UserSpecifiedWaveLength", EMPTY_DBL(), + "User can specify the wave length of the instrument if it is " + "drifted from the designed value." + "It happens often."); + declareProperty( "ShiftedDetectorDistance", 0., "Amount of shift of the distance between source and detector centre." "It is used to apply instrument calibration."); - declareProperty("UserSpecifiedWaveLength", EMPTY_DBL(), - "User can specify the wave length of the instrument if it is " - "drifted from the designed value." - "It haappens often."); + declareProperty("DetectorCenterXShift", 0.0, "The amount of shift of " + "detector center along X " + "direction in the unit meter."); + + declareProperty("DetectorCenterYShift", 0.0, "The amount of shift of " + "detector center along Y " + "direction in the unit meter."); } /** Process inputs arguments @@ -240,6 +248,9 @@ void LoadSpiceXML2DDet::processInputs() { m_ptNumber4Log = getProperty("PtNumber"); m_userSpecifiedWaveLength = getProperty("UserSpecifiedWaveLength"); + + m_detXShift = getProperty("DetectorCenterXShift"); + m_detYShift = getProperty("DetectorCenterYShift"); } /** Set up sample logs especially 2theta and diffr for loading instrument @@ -254,12 +265,13 @@ bool LoadSpiceXML2DDet::setupSampleLogs(API::MatrixWorkspace_sptr outws) { setupSampleLogFromSpiceTable(outws, spicetablews, m_ptNumber4Log); } + Kernel::DateAndTime anytime(1000); + // Process 2theta bool return_true = true; if (!outws->run().hasProperty("2theta") && outws->run().hasProperty("_2theta")) { // Set up 2theta if it is not set up yet - Kernel::DateAndTime anytime(1000); double logvalue = atof(outws->run().getProperty("_2theta")->value().c_str()); TimeSeriesProperty<double> *newlogproperty = @@ -275,8 +287,16 @@ bool LoadSpiceXML2DDet::setupSampleLogs(API::MatrixWorkspace_sptr outws) { return_true = false; } + // set up the caibrated detector center to beam + TimeSeriesProperty<double> *det_dx = new TimeSeriesProperty<double>("deltax"); + det_dx->addValue(anytime, m_detXShift); + outws->mutableRun().addProperty(det_dx); + + TimeSeriesProperty<double> *det_dy = new TimeSeriesProperty<double>("deltay"); + det_dy->addValue(anytime, m_detYShift); + outws->mutableRun().addProperty(det_dy); + // set up Sample-detetor distance calibration - Kernel::DateAndTime anytime(1000); double sampledetdistance = m_detSampleDistanceShift; TimeSeriesProperty<double> *distproperty = new TimeSeriesProperty<double>("diffr"); @@ -465,7 +485,7 @@ MatrixWorkspace_sptr LoadSpiceXML2DDet::createMatrixWorkspace( << "\n"; // XML file records data in the order of column-major - size_t icol = 0; + size_t i_col = 0; for (size_t i = 0; i < vecLines.size(); ++i) { std::string &line = vecLines[i]; @@ -476,9 +496,9 @@ MatrixWorkspace_sptr LoadSpiceXML2DDet::createMatrixWorkspace( } // Check whether it exceeds boundary - if (icol == numpixelx) { + if (i_col == numpixelx) { std::stringstream errss; - errss << "Number of non-empty rows (" << icol + 1 + errss << "Number of non-empty rows (" << i_col + 1 << ") in detector data " << "exceeds user defined geometry size " << numpixelx << "."; throw std::runtime_error(errss.str()); @@ -492,18 +512,20 @@ MatrixWorkspace_sptr LoadSpiceXML2DDet::createMatrixWorkspace( // in Y direction if (veccounts.size() != numpixely) { std::stringstream errss; - errss << "Row " << icol << " contains " << veccounts.size() + errss << "Row " << i_col << " contains " << veccounts.size() << " items other than " << numpixely << " counts specified by user."; throw std::runtime_error(errss.str()); } - // scan per row + // scan per column for (size_t j_row = 0; j_row < veccounts.size(); ++j_row) { double counts = atof(veccounts[j_row].c_str()); if (loadinstrument) { - size_t wsindex = j_row * numpixely + icol; + // the detector ID and ws index are set up in column-major too! + size_t wsindex = i_col * numpixelx + j_row; + // size_t wsindex = j_row * numpixely + icol; // size_t wsindex = icol * numpixelx + j_row; outws->dataX(wsindex)[0] = static_cast<double>(wsindex); outws->dataY(wsindex)[0] = counts; @@ -513,12 +535,12 @@ MatrixWorkspace_sptr LoadSpiceXML2DDet::createMatrixWorkspace( outws->dataE(wsindex)[0] = 1.0; } else { - outws->dataX(j_row)[icol] = static_cast<double>(j_row); - outws->dataY(j_row)[icol] = counts; + outws->dataX(j_row)[i_col] = static_cast<double>(j_row); + outws->dataY(j_row)[i_col] = counts; if (counts > 0) - outws->dataE(j_row)[icol] = sqrt(counts); + outws->dataE(j_row)[i_col] = sqrt(counts); else - outws->dataE(j_row)[icol] = 1.0; + outws->dataE(j_row)[i_col] = 1.0; } // record max count @@ -527,8 +549,8 @@ MatrixWorkspace_sptr LoadSpiceXML2DDet::createMatrixWorkspace( } } - // Update irow - icol += 1; + // Update column index (i.e., column number) + i_col += 1; } // END-FOR (i-vec line) // Set flag diff --git a/Framework/DataHandling/src/LoadVulcanCalFile.cpp b/Framework/DataHandling/src/LoadVulcanCalFile.cpp index 7a66d7defd77d85ade19b6b82c064026dc9bdee3..a6105e01e1978131f2502845afbb357e025a3171 100644 --- a/Framework/DataHandling/src/LoadVulcanCalFile.cpp +++ b/Framework/DataHandling/src/LoadVulcanCalFile.cpp @@ -2,6 +2,7 @@ #include "MantidAPI/Algorithm.h" #include "MantidAPI/FileProperty.h" #include "MantidAPI/MatrixWorkspace.h" +#include "MantidAPI/SpectrumInfo.h" #include "MantidAPI/Run.h" #include "MantidDataObjects/GroupingWorkspace.h" #include "MantidDataObjects/MaskWorkspace.h" @@ -288,9 +289,11 @@ void LoadVulcanCalFile::setupMaskWorkspace() { // Mask workspace index std::ostringstream msg; + auto &spectrumInfo = m_maskWS->mutableSpectrumInfo(); for (size_t i = 0; i < m_maskWS->getNumberHistograms(); ++i) { if (m_maskWS->readY(i)[0] > 0.5) { - m_maskWS->maskWorkspaceIndex(i); + m_maskWS->getSpectrum(i).clearData(); + spectrumInfo.setMasked(i, true); m_maskWS->dataY(i)[0] = 1.0; msg << "Spectrum " << i << " is masked. DataY = " << m_maskWS->readY(i)[0] << "\n"; @@ -628,6 +631,9 @@ void LoadVulcanCalFile::readCalFile(const std::string &calFileName, int n, udet, select, group; double n_d, udet_d, offset, select_d, group_d; + SpectrumInfo *maskSpectrumInfo{nullptr}; + if (maskWS) + maskSpectrumInfo = &maskWS->mutableSpectrumInfo(); std::string str; while (getline(grFile, str)) { if (str.empty() || str[0] == '#') @@ -674,7 +680,8 @@ void LoadVulcanCalFile::readCalFile(const std::string &calFileName, if (select <= 0) { // Not selected, then mask this detector - maskWS->maskWorkspaceIndex(wi); + maskWS->getSpectrum(wi).clearData(); + maskSpectrumInfo->setMasked(wi, true); maskWS->dataY(wi)[0] = 1.0; } else { // Selected, set the value to be 0 diff --git a/Framework/DataHandling/src/MaskDetectors.cpp b/Framework/DataHandling/src/MaskDetectors.cpp index 87c9e673c5d3bb6bb29913e6334a70bafa68d786..21a3148f6c82f2b54765943c75c1202a102e3743 100644 --- a/Framework/DataHandling/src/MaskDetectors.cpp +++ b/Framework/DataHandling/src/MaskDetectors.cpp @@ -1,11 +1,10 @@ -//---------------------------------------------------------------------- -// Includes -//---------------------------------------------------------------------- #include "MantidDataHandling/MaskDetectors.h" #include "MantidDataObjects/EventWorkspace.h" #include "MantidDataObjects/MaskWorkspace.h" +#include "MantidAPI/DetectorInfo.h" +#include "MantidAPI/SpectrumInfo.h" #include "MantidKernel/ArrayProperty.h" #include "MantidKernel/BoundedValidator.h" #include "MantidKernel/EnabledWhenProperty.h" @@ -211,10 +210,12 @@ void MaskDetectors::exec() { } // Get a reference to the spectra-detector map to get hold of detector ID's + auto &spectrumInfo = WS->mutableSpectrumInfo(); double prog = 0.0; - std::vector<size_t>::const_iterator wit; - for (wit = indexList.begin(); wit != indexList.end(); ++wit) { - WS->maskWorkspaceIndex(*wit); + for (const auto i : indexList) { + WS->getSpectrum(i).clearData(); + if (spectrumInfo.hasDetectors(i)) + spectrumInfo.setMasked(i, true); // Progress prog += (1.0 / static_cast<int>(indexList.size())); @@ -335,61 +336,39 @@ void MaskDetectors::execPeaks(PeaksWorkspace_sptr WS) { return; } - // Need to get hold of the parameter map and instrument - Geometry::ParameterMap &pmap = WS->instrumentParameters(); - Instrument_const_sptr instrument = WS->getInstrument(); + auto &detInfo = WS->mutableDetectorInfo(); + std::vector<size_t> indicesToMask; + for (const auto &detID : detectorList) { + try { + indicesToMask.push_back(detInfo.indexOf(detID)); + } catch (std::out_of_range &) { + g_log.warning() << "Invalid detector ID " << detID + << ". Found while running MaskDetectors\n"; + } + } // If we have a workspace that could contain masking,copy that in too - if (prevMasking) { DataObjects::MaskWorkspace_sptr maskWS = boost::dynamic_pointer_cast<DataObjects::MaskWorkspace>(prevMasking); if (maskWS) { - const auto &maskPmap = maskWS->constInstrumentParameters(); - Instrument_const_sptr maskInstrument = maskWS->getInstrument(); - if (maskInstrument->getDetectorIDs().size() != - WS->getInstrument()->getDetectorIDs().size()) { + const auto &maskDetInfo = maskWS->detectorInfo(); + if (detInfo.size() != maskDetInfo.size()) { throw std::runtime_error( "Size mismatch between input Workspace and MaskWorkspace"); } g_log.debug() << "Extracting mask from MaskWorkspace (" << maskWS->name() << ")\n"; - std::vector<detid_t> detectorIDs = maskInstrument->getDetectorIDs(); - std::vector<detid_t>::const_iterator it; - for (it = detectorIDs.begin(); it != detectorIDs.end(); ++it) { - try { - if (const Geometry::ComponentID det = - maskInstrument->getDetector(*it)->getComponentID()) { - Geometry::Parameter_sptr maskedParam = maskPmap.get(det, "masked"); - int detID = - static_cast<int>(maskInstrument->getDetector(*it)->getID()); - if (maskedParam) - detectorList.push_back(detID); - } - } catch (Kernel::Exception::NotFoundError &e) { - g_log.warning() << e.what() << " Found while running MaskDetectors\n"; - } - } - } - } - // If explicitly given a list of detectors to mask, just mark those. - // Otherwise, mask all detectors pointing to the requested spectra in - // index list loop below - std::vector<detid_t>::const_iterator it; - if (!detectorList.empty()) { - for (it = detectorList.begin(); it != detectorList.end(); ++it) { - try { - if (const Geometry::ComponentID det = - instrument->getDetector(*it)->getComponentID()) { - pmap.addBool(det, "masked", true); - } - } catch (Kernel::Exception::NotFoundError &e) { - g_log.warning() << e.what() << " Found while running MaskDetectors\n"; - } + for (size_t i = 0; i < maskDetInfo.size(); ++i) + if (maskDetInfo.isMasked(i)) + indicesToMask.push_back(i); } } + + for (const auto index : indicesToMask) + detInfo.setMasked(index, true); } /* Convert a list of spectra numbers into the corresponding workspace indices. diff --git a/Framework/DataHandling/src/SaveGSS.cpp b/Framework/DataHandling/src/SaveGSS.cpp index 107a0e007c8e0e4ef82f25f0da4a02e7efdc40f6..95ea9ad41ec08dc88252b5d296ad7971b4391964 100644 --- a/Framework/DataHandling/src/SaveGSS.cpp +++ b/Framework/DataHandling/src/SaveGSS.cpp @@ -161,8 +161,7 @@ void SaveGSS::exec() { // Check whether append or not if (!split) { - const std::string file(filename); - Poco::File fileobj(file); + Poco::File fileobj(filename); if (fileobj.exists() && !append) { // Non-append mode and will be overwritten g_log.warning() << "Target GSAS file " << filename diff --git a/Framework/DataHandling/test/LoadSpiceXML2DDetTest.h b/Framework/DataHandling/test/LoadSpiceXML2DDetTest.h index 7821c9fc0e2993a4967e1cef1d5ae2165b235e79..d5ab96dc8938af0e3303ed7698a87f99b73f5eec 100644 --- a/Framework/DataHandling/test/LoadSpiceXML2DDetTest.h +++ b/Framework/DataHandling/test/LoadSpiceXML2DDetTest.h @@ -43,9 +43,13 @@ public: //---------------------------------------------------------------------------------------------- /** Sample test load data without instrument - * @brief test_LoadHB3AXML + * test data: HB3A_exp355_scan0001_0522 + * 2theta = 42.70975 degree + * check: + * sample logs: including run_start, monitor, omega, chi, phi and 2theta + * @brief Load data without instrument */ - void test_LoadHB3AXML() { + void test_LoadDataNoInstrument() { LoadSpiceXML2DDet loader; loader.initialize(); @@ -122,13 +126,15 @@ public: //---------------------------------------------------------------------------------------------- /** Test algorithm with loading HB3A with instrument and presense of SPICE - * scan table - * such that it can be set to zero-2-theta position - * @brief test_LoadHB3AXML2InstrumentedWS - * Testing include - * 1. 2theta = 0 degree: scattering angle of all 4 corners should be same; + * scan table such that it will override 2theta value in the XML file + * Test: Set 2theta = 0 + * 1. Detector should be symmetric along the X-axis and about the center of + * detector; + * 2. All pixels on the X-axis will have position Y value zero; + * 3. All pixels on the Y-axis will have position X value zero + * @brief test: load data with instrument whose detector's 2theta value is 0. */ - void test_LoadHB3ADataZeroPosition() { + void test_LoadDataOverwrite2ThetaZero() { // Test 2theta at 0 degree LoadSpiceXML2DDet loader; loader.initialize(); @@ -143,7 +149,7 @@ public: loader.setProperty("DetectorGeometry", sizelist); loader.setProperty("LoadInstrument", true); loader.setProperty("SpiceTableWorkspace", scantablews); - loader.setProperty("PtNumber", 3); + loader.setProperty("PtNumber", 3); // pt number 3 has 2theta value as 0.0 loader.setProperty("ShiftedDetectorDistance", 0.); loader.execute(); @@ -155,9 +161,11 @@ public: TS_ASSERT(outws); TS_ASSERT_EQUALS(outws->getNumberHistograms(), 256 * 256); - // Value - TS_ASSERT_DELTA(outws->readY(255 * 256)[0], 1.0, 0.0001); - TS_ASSERT_DELTA(outws->readY(9 * 256 + 253)[0], 1.0, 0.00001); + // test signal value on various pixels + // pixel at (256, 1): column 1 + TS_ASSERT_DELTA(outws->readY(255)[0], 1.0, 0.0001); + // pixel at (254, 256): colun 256 + TS_ASSERT_DELTA(outws->readY(255 * 256 + 138)[0], 2.0, 0.00001); // Instrument TS_ASSERT(outws->getInstrument()); @@ -168,14 +176,54 @@ public: // check center of the detector @ (128, 115) size_t center_col = 128; size_t center_row = 115; - size_t center_ws_index = (center_row - 1) * 256 + (center_col - 1); + size_t center_ws_index = (center_row - 1) + (center_col - 1) * 256; Kernel::V3D det_center = outws->getDetector(center_ws_index)->getPos(); // distance to sample double dist_r = det_center.distance(sample); TS_ASSERT_DELTA(dist_r, 0.3750, 0.0001); // center of the detector must be at zero TS_ASSERT_DELTA(det_center.X(), 0.0, 0.0000001); - TS_ASSERT_DELTA(det_center.Y(), 0.0, 0.0000001) + TS_ASSERT_DELTA(det_center.Y(), 0.0, 0.0000001); + + // check the sequence of the detector to each ws index + detid_t det0id = outws->getDetector(0)->getID(); + TS_ASSERT_EQUALS(det0id, 0); + detid_t det1id = outws->getDetector(1)->getID(); + TS_ASSERT_EQUALS(det1id, 1); + detid_t detlastid = outws->getDetector(256 * 255 + 255)->getID(); + TS_ASSERT_EQUALS(detlastid, 255 * 256 + 255); + // test the whole sequence + for (size_t irow = 1; irow < 250; ++irow) + for (size_t jcol = 10; jcol < 20; ++jcol) { + size_t iws = irow + jcol * 256; + detid_t detid = outws->getDetector(iws)->getID(); + TS_ASSERT_EQUALS(detid, static_cast<detid_t>(iws)); + } + + // test the geometry position whether det ID is from lower right corner and + // move along positive Y direction + // right most column + Kernel::V3D det0pos = outws->getDetector(0)->getPos(); + TS_ASSERT_DELTA(det0pos.X(), 0.0252015625, 0.000001); + TS_ASSERT_DELTA(det0pos.Y(), -0.022621875, 0.000001); + TS_ASSERT_DELTA(det0pos.Z(), 0.375, 0.0001); + + double dY = 0.0001984375; + + Kernel::V3D det1pos = outws->getDetector(1)->getPos(); + TS_ASSERT_DELTA(det1pos.X(), 0.0252015625, 0.000001); + TS_ASSERT_DELTA(det1pos.Y(), -0.022621875 + dY, 0.000001); + TS_ASSERT_DELTA(det1pos.Z(), 0.375, 0.0001); + + // center is tested before + + // lower left column + size_t i_wsll = 255 * 256 + 1; + double dX = -0.0001984375; + Kernel::V3D detllpos = outws->getDetector(i_wsll)->getPos(); + TS_ASSERT_DELTA(detllpos.X(), 0.0252015625 + 255 * dX, 0.000001); + TS_ASSERT_DELTA(detllpos.Y(), -0.022621875 + dY, 0.000001); + TS_ASSERT_DELTA(detllpos.Z(), 0.375, 0.0001); // test the detectors with symmetric to each other // they should have opposite X or Y @@ -183,22 +231,22 @@ public: // ll: low-left, lr: low-right, ul: upper-left; ur: upper-right size_t row_ll = 0; size_t col_ll = 2; - size_t ws_index_ll = row_ll * 256 + col_ll; + size_t ws_index_ll = row_ll + col_ll * 256; Kernel::V3D det_ll_pos = outws->getDetector(ws_index_ll)->getPos(); size_t row_lr = 0; size_t col_lr = 2 * 127 - 2; - size_t ws_index_lr = row_lr * 256 + col_lr; + size_t ws_index_lr = row_lr + col_lr * 256; Kernel::V3D det_lr_pos = outws->getDetector(ws_index_lr)->getPos(); size_t row_ul = 114 * 2; size_t col_ul = 2; - size_t ws_index_ul = row_ul * 256 + col_ul; + size_t ws_index_ul = row_ul + col_ul * 256; Kernel::V3D det_ul_pos = outws->getDetector(ws_index_ul)->getPos(); size_t row_ur = 114 * 2; size_t col_ur = 2 * 127 - 2; - size_t ws_index_ur = row_ur * 256 + col_ur; + size_t ws_index_ur = row_ur + col_ur * 256; Kernel::V3D det_ur_pos = outws->getDetector(ws_index_ur)->getPos(); double det_size = 0.0508; // meter @@ -222,12 +270,16 @@ public: } //---------------------------------------------------------------------------------------------- - /** Test with loading instrument but without Spice scan Table. - * Other tests include check the positions of detectors - * 2-theta = 42.797 - * @brief test_LoadHB3AXMLInstrumentNoTable + /** Test with loading instrument without Spice scan Table, while the 2theta + * value is from sample + * sample log + * Testing includes: + * 1. Load the instrument without Spice Table; + * 2. Check the positions of detectors. + * (a) at center pixel, 2-theta = 42.797 + * @brief Load data and instrument with sample log value */ - void test_LoadHB3AXMLInstrumentNoTable() { + void test_loadDataUsingSampleLogValue() { // initialize the algorithm LoadSpiceXML2DDet loader; loader.initialize(); @@ -254,8 +306,11 @@ public: TS_ASSERT_EQUALS(outws->getNumberHistograms(), 256 * 256); // Value - TS_ASSERT_DELTA(outws->readY(255 * 256)[0], 1.0, 0.0001); - TS_ASSERT_DELTA(outws->readY(9 * 256 + 253)[0], 1.0, 0.00001); + // test signal value on various pixels + // pixel at (256, 1): column 1 + TS_ASSERT_DELTA(outws->readY(255)[0], 1.0, 0.0001); + // pixel at (254, 256): colun 256 + TS_ASSERT_DELTA(outws->readY(255 * 256 + 138)[0], 2.0, 0.00001); // Instrument TS_ASSERT(outws->getInstrument()); @@ -280,7 +335,7 @@ public: // check the center position size_t center_row = 115 - 1; size_t center_col = 128 - 1; - size_t center_ws_index = 256 * center_row + center_col; + size_t center_ws_index = 256 * center_col + center_row; Kernel::V3D center_det_pos = outws->getDetector(center_ws_index)->getPos(); TS_ASSERT_DELTA(center_det_pos.Y(), 0., 0.00000001); double sample_center_distance = sample.distance(center_det_pos); @@ -295,7 +350,7 @@ public: double ll_sample_r = sample.distance(ll_det_pos); TS_ASSERT_DELTA(ll_sample_r, 0.37597, 0.001); - size_t lu_ws_index = 255 * 256; // row = 255, col = 1 + size_t lu_ws_index = 255; // row = 255, col = 1 Kernel::V3D lu_det_pos = outws->getDetector(lu_ws_index)->getPos(); double lu_sample_r = sample.distance(lu_det_pos); TS_ASSERT_DELTA(lu_sample_r, 0.37689, 0.001); @@ -345,8 +400,11 @@ public: TS_ASSERT_EQUALS(outws->getNumberHistograms(), 256 * 256); // Value - TS_ASSERT_DELTA(outws->readY(255 * 256)[0], 1.0, 0.0001); - TS_ASSERT_DELTA(outws->readY(9 * 256 + 253)[0], 1.0, 0.00001); + // test signal value on various pixels + // pixel at (256, 1): column 1 + TS_ASSERT_DELTA(outws->readY(255)[0], 1.0, 0.0001); + // pixel at (254, 256): colun 256 + TS_ASSERT_DELTA(outws->readY(255 * 256 + 138)[0], 2.0, 0.00001); // Instrument TS_ASSERT(outws->getInstrument()); @@ -358,7 +416,7 @@ public: // check center of the detector @ (128, 115) size_t center_col = 128; size_t center_row = 115; - size_t center_ws_index = (center_row - 1) * 256 + (center_col - 1); + size_t center_ws_index = (center_row - 1) + (center_col - 1) * 256; Kernel::V3D center_det_pos = outws->getDetector(center_ws_index)->getPos(); // distance to sample double dist_r = center_det_pos.distance(sample); @@ -374,22 +432,22 @@ public: // ll: low-left, lr: low-right, ul: upper-left; ur: upper-right size_t row_ll = 0; size_t col_ll = 2; - size_t ws_index_ll = row_ll * 256 + col_ll; + size_t ws_index_ll = row_ll + col_ll * 256; Kernel::V3D det_ll_pos = outws->getDetector(ws_index_ll)->getPos(); size_t row_lr = 0; size_t col_lr = 2 * 127 - 2; - size_t ws_index_lr = row_lr * 256 + col_lr; + size_t ws_index_lr = row_lr + col_lr * 256; Kernel::V3D det_lr_pos = outws->getDetector(ws_index_lr)->getPos(); size_t row_ul = 114 * 2; size_t col_ul = 2; - size_t ws_index_ul = row_ul * 256 + col_ul; + size_t ws_index_ul = row_ul + col_ul * 256; Kernel::V3D det_ul_pos = outws->getDetector(ws_index_ul)->getPos(); size_t row_ur = 114 * 2; size_t col_ur = 2 * 127 - 2; - size_t ws_index_ur = row_ur * 256 + col_ur; + size_t ws_index_ur = row_ur + col_ur * 256; Kernel::V3D det_ur_pos = outws->getDetector(ws_index_ur)->getPos(); // Check symmetry @@ -404,6 +462,131 @@ public: AnalysisDataService::Instance().remove("Exp0335_S0038D"); } + //---------------------------------------------------------------------------------------------- + /** Test with loading instrument without Spice scan Table and detector is + *shifted from original + * center + * + * Testing includes: + * 1. Load the instrument without Spice Table; + * 2. Check the positions of shifted detector: from (115, 128) to (127,137) + * (a) at center pixel, 2-theta = 42.797 and pixel ID + * 3. Check the symmetry of the peak positions + * @brief Load data and instrument with sample log value + */ + void test_loadDataShiftDetectorCenter() { + // initialize the algorithm + LoadSpiceXML2DDet loader; + loader.initialize(); + + // calculate shift of the detector center from (115, 128) to (127, 127) + double det_step_x = -0.0001984375; + double shift_x = static_cast<double>(137 - 128) * det_step_x * + -1.; // shift x comes from column + double det_step_y = 0.0001984375; + double shift_y = static_cast<double>(127 - 115) * det_step_y * + -1; // shift y comes from row + + // set up properties + const std::string filename("HB3A_exp355_scan0001_0522.xml"); + TS_ASSERT_THROWS_NOTHING(loader.setProperty("Filename", filename)); + TS_ASSERT_THROWS_NOTHING( + loader.setProperty("OutputWorkspace", "Exp0335_S0038C")); + std::vector<size_t> sizelist(2); + sizelist[0] = 256; + sizelist[1] = 256; + loader.setProperty("DetectorGeometry", sizelist); + loader.setProperty("LoadInstrument", true); + loader.setProperty("ShiftedDetectorDistance", 0.); + loader.setProperty("DetectorCenterXShift", shift_x); + loader.setProperty("DetectorCenterYShift", shift_y); + + loader.execute(); + TS_ASSERT(loader.isExecuted()); + + // Get data + MatrixWorkspace_sptr outws = boost::dynamic_pointer_cast<MatrixWorkspace>( + AnalysisDataService::Instance().retrieve("Exp0335_S0038C")); + TS_ASSERT(outws); + TS_ASSERT_EQUALS(outws->getNumberHistograms(), 256 * 256); + + // Value + // test signal value on various pixels + // pixel at (256, 1): column 1 + TS_ASSERT_DELTA(outws->readY(255)[0], 1.0, 0.0001); + // pixel at (254, 256): column 256 + TS_ASSERT_DELTA(outws->readY(255 * 256 + 138)[0], 2.0, 0.00001); + + // Instrument + TS_ASSERT(outws->getInstrument()); + + // get 2theta from workspace + double twotheta_raw = + atof(outws->run().getProperty("_2theta")->value().c_str()); + + Kernel::Property *raw_property = outws->run().getProperty("2theta"); + Kernel::TimeSeriesProperty<double> *twotheta_property = + dynamic_cast<Kernel::TimeSeriesProperty<double> *>(raw_property); + TS_ASSERT(twotheta_property); + double twotheta_log = twotheta_property->valuesAsVector()[0]; + TS_ASSERT_DELTA(twotheta_log, 42.70975, 0.0001); + + TS_ASSERT_EQUALS(twotheta_raw, twotheta_log); + + // check the center of the detector + Kernel::V3D source = outws->getInstrument()->getSource()->getPos(); + Kernel::V3D sample = outws->getInstrument()->getSample()->getPos(); + + // check the center position + size_t center_row = 127 - 1; + size_t center_col = 137 - 1; + size_t center_ws_index = 256 * center_col + center_row; + // y should be 0. in the Z-Y plane + Kernel::V3D center_det_pos = outws->getDetector(center_ws_index)->getPos(); + TS_ASSERT_DELTA(center_det_pos.Y(), 0., 0.00000001); + double sample_center_distance = sample.distance(center_det_pos); + // distance + std::cout << "Sample center distance: " << sample_center_distance << "\n"; + TS_ASSERT_DELTA(sample_center_distance, 0.3750, 0.0000001); + // 2-theta angle + double sample_center_angle = + (sample - source).angle(center_det_pos - sample); + TS_ASSERT_DELTA(sample_center_angle * 180. / M_PI, twotheta_log, 0.0001); + + // symmetry from now on! + size_t ws_d_row = 10; + size_t ws_d_col = 15; + + size_t ll_ws_index = + (center_row - ws_d_row) + (center_col - ws_d_col) * 256; + Kernel::V3D ll_det_pos = outws->getDetector(ll_ws_index)->getPos(); + double ll_sample_r = sample.distance(ll_det_pos); + + size_t lr_ws_index = + (center_row + ws_d_row) + (center_col - ws_d_col) * 256; + Kernel::V3D lr_det_pos = outws->getDetector(lr_ws_index)->getPos(); + double lr_sample_r = sample.distance(lr_det_pos); + + TS_ASSERT_DELTA(ll_sample_r, lr_sample_r, 0.0000001); + + size_t ur_ws_index = + (center_row + ws_d_row) + (center_col + ws_d_col) * 256; + Kernel::V3D ur_det_pos = outws->getDetector(ur_ws_index)->getPos(); + double ur_sample_r = sample.distance(ur_det_pos); + + TS_ASSERT_DELTA(ll_sample_r, ur_sample_r, 0.0000001); + + size_t ul_ws_index = + (center_row - ws_d_row) + (center_col + ws_d_col) * 256; + Kernel::V3D ul_det_pos = outws->getDetector(ul_ws_index)->getPos(); + double ul_sample_r = sample.distance(ul_det_pos); + + TS_ASSERT_DELTA(ul_sample_r, ur_sample_r, 0.0000001); + + // Clean + AnalysisDataService::Instance().remove("Exp0335_S0038C"); + } + /** Create SPICE scan table workspace * @brief createSpiceScanTable * @return diff --git a/Framework/DataHandling/test/MaskDetectorsTest.h b/Framework/DataHandling/test/MaskDetectorsTest.h index 7360e49c0edf6d4d6c91b918b695c156472a71a9..3550b9ebc1e211df33a54dc439fc3e098a708eea 100644 --- a/Framework/DataHandling/test/MaskDetectorsTest.h +++ b/Framework/DataHandling/test/MaskDetectorsTest.h @@ -6,6 +6,7 @@ #include "MantidHistogramData/LinearGenerator.h" #include "MantidDataHandling/MaskDetectors.h" #include "MantidAPI/AnalysisDataService.h" +#include "MantidAPI/DetectorInfo.h" #include "MantidAPI/WorkspaceProperty.h" #include "MantidKernel/ArrayProperty.h" #include "MantidDataObjects/Workspace2D.h" @@ -252,15 +253,10 @@ public: masked_indices.insert(3); masked_indices.insert(4); - ParameterMap &pmap = existingMask->instrumentParameters(); - for (int i = 0; i < static_cast<int>(existingMask->getNumberHistograms()); - ++i) { - if (masked_indices.count(i) == 1) { - IDetector_const_sptr det; - TS_ASSERT_THROWS_NOTHING(det = existingMask->getDetector(i)); - pmap.addBool(det.get(), "masked", true); - } - } + auto &detInfo = existingMask->mutableDetectorInfo(); + for (int i = 0; i < static_cast<int>(detInfo.size()); ++i) + if (masked_indices.count(i) == 1) + detInfo.setMasked(i, true); MaskDetectors masker; TS_ASSERT_THROWS_NOTHING(masker.initialize()); diff --git a/Framework/DataHandling/test/SaveCalFileTest.h b/Framework/DataHandling/test/SaveCalFileTest.h index cdd7025bb62c4c66ac33de8ed84cc96ef0be0039..9d0d643b19622b7e75b4dfbe85bc58bbe55d1459 100644 --- a/Framework/DataHandling/test/SaveCalFileTest.h +++ b/Framework/DataHandling/test/SaveCalFileTest.h @@ -6,6 +6,7 @@ #include "MantidDataObjects/GroupingWorkspace.h" #include "MantidDataObjects/OffsetsWorkspace.h" #include "MantidDataObjects/MaskWorkspace.h" +#include "MantidAPI/SpectrumInfo.h" #include "MantidKernel/System.h" #include "MantidKernel/Timer.h" #include "MantidTestHelpers/ComponentCreationHelper.h" @@ -42,7 +43,8 @@ public: groupWS->setValue(3, 45); offsetsWS->setValue(1, 0.123); offsetsWS->setValue(2, 0.456); - maskWS->maskWorkspaceIndex(0); + maskWS->getSpectrum(0).clearData(); + maskWS->mutableSpectrumInfo().setMasked(0, true); // Name of the output workspace. std::string outWSName("SaveCalFileTest_OutputWS"); diff --git a/Framework/DataHandling/test/SaveDiffCalTest.h b/Framework/DataHandling/test/SaveDiffCalTest.h index 0b0d52e967b61f1d0afa676bac39246496cb08a1..3aa6f969260c2e1c28e332cfec1b8e99b92b217e 100644 --- a/Framework/DataHandling/test/SaveDiffCalTest.h +++ b/Framework/DataHandling/test/SaveDiffCalTest.h @@ -4,6 +4,7 @@ #include <cxxtest/TestSuite.h> #include <Poco/File.h> +#include "MantidAPI/SpectrumInfo.h" #include "MantidAPI/TableRow.h" #include "MantidDataHandling/SaveDiffCal.h" #include "MantidDataObjects/MaskWorkspace.h" @@ -50,7 +51,8 @@ public: MaskWorkspace_sptr createMasking(Instrument_sptr instr) { MaskWorkspace_sptr maskWS = boost::make_shared<MaskWorkspace>(instr); - maskWS->maskWorkspaceIndex(0); + maskWS->getSpectrum(0).clearData(); + maskWS->mutableSpectrumInfo().setMasked(0, true); return maskWS; } diff --git a/Framework/DataHandling/test/SaveNXSPETest.h b/Framework/DataHandling/test/SaveNXSPETest.h index 5e89432558201fc403caa275457689b6142be5ca..9ae197484cda9c06d9bba1b1d11d68ebe1d40fb3 100644 --- a/Framework/DataHandling/test/SaveNXSPETest.h +++ b/Framework/DataHandling/test/SaveNXSPETest.h @@ -6,6 +6,7 @@ #include "MantidDataHandling/SaveNXSPE.h" #include "MantidKernel/UnitFactory.h" #include "MantidTestHelpers/WorkspaceCreationHelper.h" +#include "MantidAPI/DetectorInfo.h" #include "MantidAPI/NumericAxis.h" #include "MantidAPI/FrameworkManager.h" #include "MantidDataHandling/LoadInstrument.h" @@ -28,7 +29,7 @@ using Mantid::Geometry::ParameterMap; using Mantid::Geometry::Instrument; using Mantid::Geometry::IDetector_const_sptr; -static const int THEMASKED = 2; +static const int THEMASKED = 1; class SaveNXSPETest : public CxxTest::TestSuite { public: @@ -160,11 +161,7 @@ private: } // mask the detector - ParameterMap *m_Pmap = &(inputWS->instrumentParameters()); - boost::shared_ptr<const Instrument> instru = inputWS->getInstrument(); - IDetector_const_sptr toMask = instru->getDetector(THEMASKED); - TS_ASSERT(toMask); - m_Pmap->addBool(toMask.get(), "masked", true); + inputWS->mutableDetectorInfo().setMasked(THEMASKED, true); // required to get it passed the algorthms validator inputWS->setDistribution(true); diff --git a/Framework/DataHandling/test/SavePARTest.h b/Framework/DataHandling/test/SavePARTest.h index fdde15cba964554c4586d36752f8176fe05f0dcd..3ffd964724ead2c2aa7206e9445fd6ddb21c9472 100644 --- a/Framework/DataHandling/test/SavePARTest.h +++ b/Framework/DataHandling/test/SavePARTest.h @@ -168,13 +168,6 @@ private: loader.setPropertyValue("Workspace", input); loader.execute(); - // mask the detector - Geometry::ParameterMap *m_Pmap = &(inputWS->instrumentParameters()); - boost::shared_ptr<const Instrument> instru = inputWS->getInstrument(); - Geometry::IDetector_const_sptr toMask = instru->getDetector(THEMASKED); - TS_ASSERT(toMask); - m_Pmap->addBool(toMask.get(), "masked", true); - // required to get it passed the algorthms validator inputWS->setDistribution(true); diff --git a/Framework/DataHandling/test/SavePHXTest.h b/Framework/DataHandling/test/SavePHXTest.h index 675aabc7e7df2cd74342d8fe515428b1746efcdc..5c62ee46df092731fe76784aa5f76fb0286551a7 100644 --- a/Framework/DataHandling/test/SavePHXTest.h +++ b/Framework/DataHandling/test/SavePHXTest.h @@ -198,13 +198,6 @@ private: loader.setProperty("RewriteSpectraMap", Mantid::Kernel::OptionalBool(true)); loader.execute(); - // mask the detector - Geometry::ParameterMap *m_Pmap = &(inputWS->instrumentParameters()); - boost::shared_ptr<const Instrument> instru = inputWS->getInstrument(); - Geometry::IDetector_const_sptr toMask = instru->getDetector(THEMASKED); - TS_ASSERT(toMask) - m_Pmap->addBool(toMask.get(), "masked", true); - // required to get it passed the algorthms validator inputWS->setDistribution(true); diff --git a/Framework/DataHandling/test/SaveSPETest.h b/Framework/DataHandling/test/SaveSPETest.h index 8d61e0662974dbe80c2209f865419fdc7e7ab5a1..a59e61ae980ee52a050552ce2f7daacf9454c663 100644 --- a/Framework/DataHandling/test/SaveSPETest.h +++ b/Framework/DataHandling/test/SaveSPETest.h @@ -5,6 +5,7 @@ #include "MantidDataHandling/SaveSPE.h" #include "MantidTestHelpers/WorkspaceCreationHelper.h" +#include "MantidAPI/DetectorInfo.h" #include "MantidAPI/FrameworkManager.h" #include "MantidAPI/NumericAxis.h" #include "MantidDataHandling/LoadInstrument.h" @@ -27,7 +28,7 @@ static const double MASK_FLAG = static const double MASK_ERROR = 0.0; static const int NHIST = 3; -static const int THEMASKED = 2; +static const int THEMASKED = 1; static const int DEFAU_Y = 2; class SaveSPETest : public CxxTest::TestSuite { @@ -91,7 +92,7 @@ public: ++i) { // if the spectrum number (1+index number) is that of the masked // spectrum look for the mask flag, otherwise value in the // workspace - double value = i + 1 != THEMASKED ? DEFAU_Y : MASK_FLAG; + double value = i != THEMASKED ? DEFAU_Y : MASK_FLAG; getline(file, tmp); TS_ASSERT_EQUALS(tmp, "### S(Phi,w)") @@ -102,7 +103,7 @@ public: TS_ASSERT_EQUALS(tmp2, value) getline(file, tmp); - double error = i + 1 != THEMASKED ? M_SQRT2 : MASK_ERROR; + double error = i != THEMASKED ? M_SQRT2 : MASK_ERROR; getline(file, tmp); TS_ASSERT_EQUALS(tmp, "### Errors") file >> tmp2; @@ -187,11 +188,7 @@ private: loader.execute(); // mask the detector - Geometry::ParameterMap *m_Pmap = &(inputWS->instrumentParameters()); - boost::shared_ptr<const Instrument> instru = inputWS->getInstrument(); - Geometry::IDetector_const_sptr toMask = instru->getDetector(THEMASKED); - TS_ASSERT(toMask); - m_Pmap->addBool(toMask.get(), "masked", true); + inputWS->mutableDetectorInfo().setMasked(THEMASKED, true); // required to get it passed the algorthms validator inputWS->setDistribution(true); diff --git a/Framework/DataObjects/inc/MantidDataObjects/VectorColumn.h b/Framework/DataObjects/inc/MantidDataObjects/VectorColumn.h index 2833c272232b313e357f7854965e2c0b71b9b3fd..26c868a2bc38d50ad5139c8a95ca6214ba2afc53 100644 --- a/Framework/DataObjects/inc/MantidDataObjects/VectorColumn.h +++ b/Framework/DataObjects/inc/MantidDataObjects/VectorColumn.h @@ -80,8 +80,7 @@ public: Mantid::Kernel::StringTokenizer elements( text, ",", Mantid::Kernel::StringTokenizer::TOK_TRIM); - for (const auto &it : elements) { - std::string element(it); + for (const auto &element : elements) { try { newValues.push_back(boost::lexical_cast<Type>(element)); } catch (boost::bad_lexical_cast &) { diff --git a/Framework/DataObjects/src/MaskWorkspace.cpp b/Framework/DataObjects/src/MaskWorkspace.cpp index c7c02b228ba759a69df95448b98ac86915e93d5e..068ced80296a7d5b9d7cf4e802305308d6060cf8 100644 --- a/Framework/DataObjects/src/MaskWorkspace.cpp +++ b/Framework/DataObjects/src/MaskWorkspace.cpp @@ -1,6 +1,7 @@ #include "MantidDataObjects/MaskWorkspace.h" #include "MantidKernel/System.h" #include "MantidKernel/IPropertyManager.h" +#include "MantidAPI/DetectorInfo.h" #include "MantidAPI/WorkspaceFactory.h" namespace Mantid { @@ -71,8 +72,7 @@ void MaskWorkspace::clearMask() { } // Clear the mask flags - Geometry::ParameterMap &pmap = this->instrumentParameters(); - pmap.clearParametersByName("masked"); + mutableDetectorInfo().clearMaskFlags(); } /** @@ -170,7 +170,16 @@ bool MaskWorkspace::isMasked(const detid_t detectorID) const { } // the mask bit on the workspace can be set - return this->getInstrument()->isDetectorMasked(detectorID); + // Performance wise, it is not optimal to call detectorInfo() for every index, + // but this method seems to be used rarely enough to justify this until the + // Instrument-2.0 implementation has progressed far enough to make this cheap. + const auto &detectorInfo = this->detectorInfo(); + try { + return detectorInfo.isMasked(detectorInfo.indexOf(detectorID)); + } catch (std::out_of_range &) { + // The workspace can contain bad detector IDs. DetectorInfo::indexOf throws. + return false; + } } /** diff --git a/Framework/DataObjects/test/EventWorkspaceTest.h b/Framework/DataObjects/test/EventWorkspaceTest.h index 6672f8ea050ec2e56cf00a1e22a4f0a6f9eac9f2..73024a94bcbd99ca2b6f2e1b84b199a5d9f778e9 100644 --- a/Framework/DataObjects/test/EventWorkspaceTest.h +++ b/Framework/DataObjects/test/EventWorkspaceTest.h @@ -17,6 +17,7 @@ #include "MantidHistogramData/LinearGenerator.h" #include "MantidAPI/Axis.h" +#include "MantidAPI/SpectrumInfo.h" #include "MantidDataObjects/EventList.h" #include "MantidDataObjects/EventWorkspace.h" #include "MantidTestHelpers/WorkspaceCreationHelper.h" @@ -169,7 +170,8 @@ public: WorkspaceCreationHelper::createEventWorkspaceWithFullInstrument( 1, 10, false /*dont clear the events*/); TS_ASSERT_EQUALS(ws->getSpectrum(2).getNumberEvents(), 200); - ws->maskWorkspaceIndex(2); + ws->getSpectrum(2).clearData(); + ws->mutableSpectrumInfo().setMasked(2, true); TS_ASSERT_EQUALS(ws->getSpectrum(2).getNumberEvents(), 0); } diff --git a/Framework/Geometry/CMakeLists.txt b/Framework/Geometry/CMakeLists.txt index de7a6ed907a007b4b7c07c69f68459acee95e078..0f7812e6ecc086980ef2ed03fce0d6390443be0f 100644 --- a/Framework/Geometry/CMakeLists.txt +++ b/Framework/Geometry/CMakeLists.txt @@ -53,7 +53,6 @@ set ( SRC_FILES src/Instrument/Goniometer.cpp src/Instrument/IDFObject.cpp src/Instrument/InstrumentDefinitionParser.cpp - src/Instrument/NearestNeighbours.cpp src/Instrument/ObjCompAssembly.cpp src/Instrument/ObjComponent.cpp src/Instrument/ParComponentFactory.cpp @@ -206,7 +205,6 @@ set ( INC_FILES inc/MantidGeometry/Instrument/Goniometer.h inc/MantidGeometry/Instrument/IDFObject.h inc/MantidGeometry/Instrument/InstrumentDefinitionParser.h - inc/MantidGeometry/Instrument/NearestNeighbours.h inc/MantidGeometry/Instrument/ObjCompAssembly.h inc/MantidGeometry/Instrument/ObjComponent.h inc/MantidGeometry/Instrument/ParComponentFactory.h @@ -350,7 +348,6 @@ set ( TEST_FILES MathSupportTest.h MatrixVectorPairParserTest.h MatrixVectorPairTest.h - NearestNeighboursTest.h NiggliCellTest.h NullImplicitFunctionTest.h ObjCompAssemblyTest.h diff --git a/Framework/Geometry/inc/MantidGeometry/Instrument.h b/Framework/Geometry/inc/MantidGeometry/Instrument.h index 00639c0af60e1f4a4f5db2d29b039ff3a7569209..f2920fe0c36ab513b7cab988605a59947a8ed491 100644 --- a/Framework/Geometry/inc/MantidGeometry/Instrument.h +++ b/Framework/Geometry/inc/MantidGeometry/Instrument.h @@ -86,8 +86,6 @@ public: const IDetector *getBaseDetector(const detid_t &detector_id) const; bool isMonitor(const detid_t &detector_id) const; bool isMonitor(const std::set<detid_t> &detector_ids) const; - bool isDetectorMasked(const detid_t &detector_id) const; - bool isDetectorMasked(const std::set<detid_t> &detector_ids) const; /// Returns a pointer to the geometrical object for the given set of IDs IDetector_const_sptr getDetectorG(const std::vector<detid_t> &det_ids) const; diff --git a/Framework/Geometry/src/Crystal/CompositeBraggScatterer.cpp b/Framework/Geometry/src/Crystal/CompositeBraggScatterer.cpp index c36f94ac2505dd30f4194f7d4ddfa8b55362bab8..3e49afd85880d8f856895931d019b794cbbfd355 100644 --- a/Framework/Geometry/src/Crystal/CompositeBraggScatterer.cpp +++ b/Framework/Geometry/src/Crystal/CompositeBraggScatterer.cpp @@ -186,7 +186,7 @@ void CompositeBraggScatterer::redeclareProperties() { std::vector<Property *> properties = scatterer->getPropertiesInGroup(getPropagatingGroupName()); for (auto &property : properties) { - std::string propertyName = property->name(); + const std::string &propertyName = property->name(); if (!existsProperty(propertyName)) { declareProperty(std::unique_ptr<Property>(property->clone())); } diff --git a/Framework/Geometry/src/Instrument.cpp b/Framework/Geometry/src/Instrument.cpp index 96afd7b431f093a52c285e72a5e348710544af7c..d93be437605d00138834451817526ae635a5fda7 100644 --- a/Framework/Geometry/src/Instrument.cpp +++ b/Framework/Geometry/src/Instrument.cpp @@ -514,53 +514,6 @@ bool Instrument::isMonitor(const std::set<detid_t> &detector_ids) const { return false; } -//-------------------------------------------------------------------------- -/** Is the detector with the given ID masked? - * - * @param detector_id :: detector ID to look for. - * @return true if masked; false if not masked or if the detector was not found. - */ -bool Instrument::isDetectorMasked(const detid_t &detector_id) const { - // With no parameter map, then no detector is EVER masked - if (!isParametrized()) - return false; - // Find the (base) detector object in the map. - auto it = m_instr->m_detectorCache.find(detector_id); - if (it == m_instr->m_detectorCache.end()) - return false; - // This is the detector - const Detector *det = dynamic_cast<const Detector *>(it->second.get()); - if (det == nullptr) - return false; - // Access the parameter map directly. - Parameter_sptr maskedParam = m_map->get(det, "masked"); - if (!maskedParam) - return false; - // If the parameter is defined, then yes, it is masked. - return maskedParam->value<bool>(); -} - -//-------------------------------------------------------------------------- -/** Is this group of detectors masked? - * - * This returns true (masked) if ALL of the detectors listed are masked. - * It returns false (not masked) if there are no detectors in the list - * It returns false (not masked) if any of the detectors are NOT masked. - * - * @param detector_ids :: set of detector IDs - * @return true if masked. - */ -bool Instrument::isDetectorMasked(const std::set<detid_t> &detector_ids) const { - if (detector_ids.empty()) - return false; - - for (auto detector_id : detector_ids) { - if (!this->isDetectorMasked(detector_id)) - return false; - } - return true; -} - /** * Returns a pointer to the geometrical object for the given set of IDs * @param det_ids :: A list of detector ids diff --git a/Framework/Geometry/src/Instrument/InstrumentDefinitionParser.cpp b/Framework/Geometry/src/Instrument/InstrumentDefinitionParser.cpp index f755d6a5a48c76b0fe52e6e46a784f846f7b859d..c3a34c389ea6938a628daf9ff29bbca4771f3bbf 100644 --- a/Framework/Geometry/src/Instrument/InstrumentDefinitionParser.cpp +++ b/Framework/Geometry/src/Instrument/InstrumentDefinitionParser.cpp @@ -754,7 +754,7 @@ Poco::XML::Element *InstrumentDefinitionParser::getParentComponent( const Poco::XML::Element *pLocElem) { if ((pLocElem->tagName()).compare("location") && (pLocElem->tagName()).compare("locations")) { - std::string tagname = pLocElem->tagName(); + const std::string &tagname = pLocElem->tagName(); g_log.error("Argument to function getParentComponent must be a pointer to " "an XML element with tag name location or locations."); throw std::logic_error( diff --git a/Framework/Kernel/src/ArrayBoundedValidator.cpp b/Framework/Kernel/src/ArrayBoundedValidator.cpp index 130af1d0a9c22db45b2a189975d6f30ca902d0b1..68ae912ea9f50fcc354761a3d63dbbe9279f5e50 100644 --- a/Framework/Kernel/src/ArrayBoundedValidator.cpp +++ b/Framework/Kernel/src/ArrayBoundedValidator.cpp @@ -139,7 +139,7 @@ template <typename TYPE> void ArrayBoundedValidator<TYPE>::clearUpper() { template class ArrayBoundedValidator<double>; template class ArrayBoundedValidator<int32_t>; template class ArrayBoundedValidator<int64_t>; -#if defined(_WIN32) || defined(__clang__) +#if defined(_WIN32) || defined(__clang__) && defined(__APPLE__) template class ArrayBoundedValidator<long>; #endif diff --git a/Framework/Kernel/src/ArrayLengthValidator.cpp b/Framework/Kernel/src/ArrayLengthValidator.cpp index e7f315d9cec9f577826e020c859187e76d2a1c0d..72e740564b5b6739ced66695f33030ddaf66e403 100644 --- a/Framework/Kernel/src/ArrayLengthValidator.cpp +++ b/Framework/Kernel/src/ArrayLengthValidator.cpp @@ -188,7 +188,7 @@ template class ArrayLengthValidator<double>; template class ArrayLengthValidator<int32_t>; template class ArrayLengthValidator<int64_t>; template class ArrayLengthValidator<std::string>; -#if defined(_WIN32) || defined(__clang__) +#if defined(_WIN32) || defined(__clang__) && defined(__APPLE__) template class ArrayLengthValidator<long>; #endif } // namespace Mantid diff --git a/Framework/Kernel/src/ArrayProperty.cpp b/Framework/Kernel/src/ArrayProperty.cpp index 1feedc269922463ef2c50ed7c7c9670ce6987a63..a951c7972aad406c501338cae00beaf7b86937d8 100644 --- a/Framework/Kernel/src/ArrayProperty.cpp +++ b/Framework/Kernel/src/ArrayProperty.cpp @@ -116,7 +116,7 @@ template class DLLExport ArrayProperty<std::vector<float>>; template class DLLExport ArrayProperty<std::vector<double>>; template class DLLExport ArrayProperty<std::vector<std::string>>; -#if defined(_WIN32) || defined(__clang__) +#if defined(_WIN32) || defined(__clang__) && defined(__APPLE__) template class DLLExport ArrayProperty<long>; template class DLLExport ArrayProperty<unsigned long>; template class DLLExport ArrayProperty<std::vector<long>>; diff --git a/Framework/Kernel/src/InstrumentInfo.cpp b/Framework/Kernel/src/InstrumentInfo.cpp index 283da46162e0c42904661582ab5fdfa708657b9c..e4c30cefef1748e96f5a813328cc523257597769 100644 --- a/Framework/Kernel/src/InstrumentInfo.cpp +++ b/Framework/Kernel/src/InstrumentInfo.cpp @@ -254,7 +254,7 @@ void InstrumentInfo::fillTechniques(const Poco::XML::Element *elem) { if (pNL->length() > 0) { Poco::XML::Text *txt = dynamic_cast<Poco::XML::Text *>(pNL->item(0)); if (txt) { - std::string tech = txt->getData(); + const std::string &tech = txt->getData(); if (!tech.empty()) { m_technique.insert(tech); } diff --git a/Framework/Kernel/src/MandatoryValidator.cpp b/Framework/Kernel/src/MandatoryValidator.cpp index 7ef39a3c077d9919fd87897297586f6f980668f2..95fdcc1793429e0d46611d23ae3d73e82641a715 100644 --- a/Framework/Kernel/src/MandatoryValidator.cpp +++ b/Framework/Kernel/src/MandatoryValidator.cpp @@ -42,7 +42,7 @@ template <> DLLExport bool checkIsEmpty(const long &value) { // 32 bit for Windows and Clang, 64 bit for GCC return (value == Mantid::EMPTY_LONG()); } -#if defined(_WIN32) || defined(__clang__) +#if defined(_WIN32) || defined(__clang__) && defined(__APPLE__) /** * Specialization of checkIsEmpty for 64 bit intiger * @param value :: A int64_t value diff --git a/Framework/Kernel/src/NormalDistribution.cpp b/Framework/Kernel/src/NormalDistribution.cpp index 6b097fff4679f363ef79e6dee4f89ca586414cb0..e7ff30c4280bd54e798bfbebb1b4b41b55f734f4 100644 --- a/Framework/Kernel/src/NormalDistribution.cpp +++ b/Framework/Kernel/src/NormalDistribution.cpp @@ -1,6 +1,7 @@ //------------------------------------------------------------------------------ // Includes //------------------------------------------------------------------------------ +#include <string> #include "MantidKernel/NormalDistribution.h" #include "MantidKernel/MersenneTwister.h" diff --git a/Framework/Kernel/src/PropertyWithValue.cpp b/Framework/Kernel/src/PropertyWithValue.cpp index 92c5ec6159549c3346ce4f206d63543a0e150cdc..52d17727d30bd08ba6f867d7554c2b5c4d8a3b4f 100644 --- a/Framework/Kernel/src/PropertyWithValue.cpp +++ b/Framework/Kernel/src/PropertyWithValue.cpp @@ -49,7 +49,7 @@ template class MANTID_KERNEL_DLL PropertyWithValue<boost::shared_ptr<IValidator>>; template class MANTID_KERNEL_DLL PropertyWithValue<boost::shared_ptr<PropertyManager>>; -#if defined(_WIN32) || defined(__clang__) +#if defined(_WIN32) || defined(__clang__) && defined(__APPLE__) template class MANTID_KERNEL_DLL PropertyWithValue<long>; template class MANTID_KERNEL_DLL PropertyWithValue<unsigned long>; template class MANTID_KERNEL_DLL PropertyWithValue<std::vector<long>>; diff --git a/Framework/LiveData/src/SNSLiveEventDataListener.cpp b/Framework/LiveData/src/SNSLiveEventDataListener.cpp index c7e33810366c74ffb1dac28ea5c12f4814b81ce2..dcc75ff81ecb133857f0da9f4171a19b3f98cdee 100644 --- a/Framework/LiveData/src/SNSLiveEventDataListener.cpp +++ b/Framework/LiveData/src/SNSLiveEventDataListener.cpp @@ -1199,7 +1199,7 @@ bool SNSLiveEventDataListener::rxPacket(const ADARA::AnnotationPkt &pkt) { } // mutex auto unlocks here // if there's a comment in the packet, log it at the info level - std::string comment = pkt.comment(); + const std::string &comment = pkt.comment(); if (comment.size() > 0) { g_log.information() << "Annotation: " << comment << '\n'; } diff --git a/Framework/MDAlgorithms/inc/MantidMDAlgorithms/ConvertCWSDExpToMomentum.h b/Framework/MDAlgorithms/inc/MantidMDAlgorithms/ConvertCWSDExpToMomentum.h index 212e0608c2e093fdfb28afda5036255664bda50f..6b2cdab5a565553a9d638043281894251e7851d0 100644 --- a/Framework/MDAlgorithms/inc/MantidMDAlgorithms/ConvertCWSDExpToMomentum.h +++ b/Framework/MDAlgorithms/inc/MantidMDAlgorithms/ConvertCWSDExpToMomentum.h @@ -97,6 +97,12 @@ private: API::IMDEventWorkspace_sptr m_outputWS; Geometry::Instrument_sptr m_virtualInstrument; + /// Shifts in detector position set from user (calibration): all in the unit + /// as meter + double m_detSampleDistanceShift; + double m_detXShift; + double m_detYShift; + Kernel::V3D m_samplePos; Kernel::V3D m_sourcePos; diff --git a/Framework/MDAlgorithms/src/CompareMDWorkspaces.cpp b/Framework/MDAlgorithms/src/CompareMDWorkspaces.cpp index 4223a88d247cf121b17b51b33020dc46cbff1658..e11d0a2a9c98131cf29363fb787b4066361e7c5d 100644 --- a/Framework/MDAlgorithms/src/CompareMDWorkspaces.cpp +++ b/Framework/MDAlgorithms/src/CompareMDWorkspaces.cpp @@ -178,8 +178,7 @@ void CompareMDWorkspaces::compareMDHistoWorkspaces( */ template <typename MDE, size_t nd> void CompareMDWorkspaces::compareMDWorkspaces( - typename MDEventWorkspace<MDE, nd>::sptr ws) { - typename MDEventWorkspace<MDE, nd>::sptr ws1 = ws; + typename MDEventWorkspace<MDE, nd>::sptr ws1) { typename MDEventWorkspace<MDE, nd>::sptr ws2 = boost::dynamic_pointer_cast<MDEventWorkspace<MDE, nd>>(inWS2); if (!ws1 || !ws2) diff --git a/Framework/MDAlgorithms/src/ConvertCWSDExpToMomentum.cpp b/Framework/MDAlgorithms/src/ConvertCWSDExpToMomentum.cpp index 29299895cfadd7f8e28881b6b2a99f8e30b892b5..d454a9c9ca0f81c17e75a3313172b607ac852736 100644 --- a/Framework/MDAlgorithms/src/ConvertCWSDExpToMomentum.cpp +++ b/Framework/MDAlgorithms/src/ConvertCWSDExpToMomentum.cpp @@ -38,6 +38,21 @@ void ConvertCWSDExpToMomentum::init() { Direction::Input), "Name of table workspace for data file names in the experiment."); + declareProperty( + "DetectorSampleDistanceShift", 0.0, + "Amount of shift in sample-detector distance from 0.3750 meter."); + + declareProperty( + "DetectorCenterXShift", 0.0, + "Amount of shift of detector center in X-direction from (115, 128)."); + + declareProperty( + "DetectorCenterYShift", 0.0, + "Amount of shift of detector center in Y-direction from (115, 128)."); + + declareProperty("UserDefinedWavelength", EMPTY_DBL(), + "User defined wave length if it is specified."); + declareProperty("CreateVirtualInstrument", false, "Flag to create virtual instrument."); @@ -88,6 +103,9 @@ void ConvertCWSDExpToMomentum::exec() { g_log.error() << "Importing error: " << errmsg << "\n"; throw std::runtime_error(errmsg); } + m_detSampleDistanceShift = getProperty("DetectorSampleDistanceShift"); + m_detXShift = getProperty("DetectorCenterXShift"); + m_detYShift = getProperty("DetectorCenterYShift"); // background std::string bkgdwsname = getPropertyValue("BackgroundWorkspace"); @@ -601,6 +619,15 @@ ConvertCWSDExpToMomentum::loadSpiceData(const std::string &filename, sizelist[1] = 256; loader->setProperty("DetectorGeometry", sizelist); loader->setProperty("LoadInstrument", true); + loader->setProperty("ShiftedDetectorDistance", m_detSampleDistanceShift); + loader->setProperty("DetectorCenterXShift", m_detXShift); + loader->setProperty("DetectorCenterYShift", m_detYShift); + + double wavelength = getProperty("UserDefinedWavelength"); + + if (wavelength != EMPTY_DBL()) { + loader->setProperty("UserSpecifiedWaveLength", wavelength); + } loader->execute(); diff --git a/Framework/MDAlgorithms/src/LoadILLAscii.cpp b/Framework/MDAlgorithms/src/LoadILLAscii.cpp index e5cb0a709f132cdf732e78fb9f5c504e027c3954..589437c2d6779eb87385ee750fa55e59f09105de 100644 --- a/Framework/MDAlgorithms/src/LoadILLAscii.cpp +++ b/Framework/MDAlgorithms/src/LoadILLAscii.cpp @@ -270,7 +270,7 @@ IMDEventWorkspace_sptr LoadILLAscii::mergeWorkspaces( std::vector<API::MatrixWorkspace_sptr> &workspaceList) { Poco::TemporaryFile tmpFile; - std::string tempFileName = tmpFile.path(); + const std::string &tempFileName = tmpFile.path(); g_log.debug() << "Dumping WSs in a temp file: " << tempFileName << '\n'; std::ofstream myfile; diff --git a/Framework/MDAlgorithms/src/MDNormDirectSC.cpp b/Framework/MDAlgorithms/src/MDNormDirectSC.cpp index c94731a248957e867b3def5d05b739bfba952656..f98a6f9163bac07fed28efa86504bf88bd6a386c 100644 --- a/Framework/MDAlgorithms/src/MDNormDirectSC.cpp +++ b/Framework/MDAlgorithms/src/MDNormDirectSC.cpp @@ -121,8 +121,10 @@ void MDNormDirectSC::exec() { cacheInputs(); auto outputWS = binInputWS(); convention = Kernel::ConfigService::Instance().getString("Q.convention"); + outputWS->setDisplayNormalization(Mantid::API::NoNormalization); setProperty<Workspace_sptr>("OutputWorkspace", outputWS); createNormalizationWS(*outputWS); + m_normWS->setDisplayNormalization(Mantid::API::NoNormalization); setProperty("OutputNormalizationWorkspace", m_normWS); // Check for other dimensions if we could measure anything in the original diff --git a/Framework/MDAlgorithms/src/MDNormSCD.cpp b/Framework/MDAlgorithms/src/MDNormSCD.cpp index 49d18a24226244e310df8513fb7161fab402e3d5..4b28410b3e1e292013ae1bedb4feadbbef920f99 100644 --- a/Framework/MDAlgorithms/src/MDNormSCD.cpp +++ b/Framework/MDAlgorithms/src/MDNormSCD.cpp @@ -116,8 +116,10 @@ void MDNormSCD::exec() { cacheInputs(); auto outputWS = binInputWS(); convention = Kernel::ConfigService::Instance().getString("Q.convention"); + outputWS->setDisplayNormalization(Mantid::API::NoNormalization); setProperty<Workspace_sptr>("OutputWorkspace", outputWS); createNormalizationWS(*outputWS); + m_normWS->setDisplayNormalization(Mantid::API::NoNormalization); setProperty("OutputNormalizationWorkspace", m_normWS); // Check for other dimensions if we could measure anything in the original diff --git a/Framework/MDAlgorithms/src/MergeMD.cpp b/Framework/MDAlgorithms/src/MergeMD.cpp index 88e7e435313656d5f4bbc7f809995bd34da186ed..9359273e58f90fb53f2381f46a335ad3c6b21117 100644 --- a/Framework/MDAlgorithms/src/MergeMD.cpp +++ b/Framework/MDAlgorithms/src/MergeMD.cpp @@ -159,11 +159,10 @@ void MergeMD::createOutputWorkspace(std::vector<std::string> &inputs) { * @param ws :: MDEventWorkspace to clone */ template <typename MDE, size_t nd> -void MergeMD::doPlus(typename MDEventWorkspace<MDE, nd>::sptr ws) { +void MergeMD::doPlus(typename MDEventWorkspace<MDE, nd>::sptr ws2) { // CPUTimer tim; typename MDEventWorkspace<MDE, nd>::sptr ws1 = boost::dynamic_pointer_cast<MDEventWorkspace<MDE, nd>>(out); - typename MDEventWorkspace<MDE, nd>::sptr ws2 = ws; if (!ws1 || !ws2) throw std::runtime_error("Incompatible workspace types passed to MergeMD."); diff --git a/Framework/MDAlgorithms/src/MinusMD.cpp b/Framework/MDAlgorithms/src/MinusMD.cpp index 91d846e94bfed80b43ee710483bdbad9ba71188f..c0c2cb8e91ac001e301bb50730f765f7f7d4a0fb 100644 --- a/Framework/MDAlgorithms/src/MinusMD.cpp +++ b/Framework/MDAlgorithms/src/MinusMD.cpp @@ -51,8 +51,7 @@ void MinusMD::checkInputs() { * @param ws :: MDEventWorkspace being added to */ template <typename MDE, size_t nd> -void MinusMD::doMinus(typename MDEventWorkspace<MDE, nd>::sptr ws) { - typename MDEventWorkspace<MDE, nd>::sptr ws1 = ws; +void MinusMD::doMinus(typename MDEventWorkspace<MDE, nd>::sptr ws1) { typename MDEventWorkspace<MDE, nd>::sptr ws2 = boost::dynamic_pointer_cast<MDEventWorkspace<MDE, nd>>(m_operand_event); if (!ws1 || !ws2) diff --git a/Framework/MDAlgorithms/src/PlusMD.cpp b/Framework/MDAlgorithms/src/PlusMD.cpp index 3beb2ec6044ae32e080b86d1f3b56831c9c054f1..1fbe4b1d6b00551f2cdaa3e45e25a33fc06f007e 100644 --- a/Framework/MDAlgorithms/src/PlusMD.cpp +++ b/Framework/MDAlgorithms/src/PlusMD.cpp @@ -25,8 +25,7 @@ DECLARE_ALGORITHM(PlusMD) * @param ws :: MDEventWorkspace being added to */ template <typename MDE, size_t nd> -void PlusMD::doPlus(typename MDEventWorkspace<MDE, nd>::sptr ws) { - typename MDEventWorkspace<MDE, nd>::sptr ws1 = ws; +void PlusMD::doPlus(typename MDEventWorkspace<MDE, nd>::sptr ws1) { typename MDEventWorkspace<MDE, nd>::sptr ws2 = boost::dynamic_pointer_cast<MDEventWorkspace<MDE, nd>>(m_operand_event); if (!ws1 || !ws2) diff --git a/Framework/MDAlgorithms/src/SlicingAlgorithm.cpp b/Framework/MDAlgorithms/src/SlicingAlgorithm.cpp index 05d6ee29d070ee276d31ccd2334ce312d75661d1..3a820ca51608c949db0a65499bd03db3ed511edf 100644 --- a/Framework/MDAlgorithms/src/SlicingAlgorithm.cpp +++ b/Framework/MDAlgorithms/src/SlicingAlgorithm.cpp @@ -251,20 +251,19 @@ void SlicingAlgorithm::makeBasisVectorFromString(const std::string &str) { double binningScaling = double(numBins) / (lengthInInput); // Extract the arguments - std::string id = name; std::string units = Strings::strip(strs[0]); // Create the appropriate frame auto frame = createMDFrameForNonAxisAligned(units, basis); // Create the output dimension - MDHistoDimension_sptr out( - new MDHistoDimension(name, id, *frame, static_cast<coord_t>(min), - static_cast<coord_t>(max), numBins)); + auto out = boost::make_shared<MDHistoDimension>( + name, name, *frame, static_cast<coord_t>(min), static_cast<coord_t>(max), + numBins); // Put both in the algo for future use m_bases.push_back(basis); - m_binDimensions.push_back(out); + m_binDimensions.push_back(std::move(out)); m_binningScaling.push_back(binningScaling); m_transformScaling.push_back(transformScaling); } @@ -430,8 +429,7 @@ void SlicingAlgorithm::createGeneralTransform() { if (m_outD == inD) { // Can't reverse transform if you lost dimensions. auto ctTo = new DataObjects::CoordTransformAffine(inD, m_outD); - Matrix<coord_t> fromMatrix = ctFrom->getMatrix(); - Matrix<coord_t> toMatrix = fromMatrix; + Matrix<coord_t> toMatrix = ctFrom->getMatrix(); // Invert the affine matrix to get the reverse transformation toMatrix.Invert(); ctTo->setMatrix(toMatrix); diff --git a/Framework/MDAlgorithms/test/ConvertToMDComponentsTest.h b/Framework/MDAlgorithms/test/ConvertToMDComponentsTest.h index e18e52ac16e17d9fe8818c1a71bdd5ce9ff26caf..65ff6bd5aa8a4b5a81e690252fb2ced6bd8631cc 100644 --- a/Framework/MDAlgorithms/test/ConvertToMDComponentsTest.h +++ b/Framework/MDAlgorithms/test/ConvertToMDComponentsTest.h @@ -3,6 +3,7 @@ // tests for different parts of ConvertToMD exec functions #include "MantidAPI/FrameworkManager.h" +#include "MantidAPI/SpectrumInfo.h" #include "MantidGeometry/Instrument/Goniometer.h" #include "MantidMDAlgorithms/ConvertToMD.h" #include "MantidMDAlgorithms/MDWSTransform.h" @@ -343,9 +344,10 @@ public: // detectorList.push_back(spDet->getID()); } - std::vector<size_t>::const_iterator wit; - for (wit = indexLis.begin(); wit != indexLis.end(); ++wit) { - inputWS->maskWorkspaceIndex(*wit); + auto &spectrumInfo = inputWS->mutableSpectrumInfo(); + for (const auto i : indexLis) { + inputWS->getSpectrum(i).clearData(); + spectrumInfo.setMasked(i, true); } } }; diff --git a/Framework/MDAlgorithms/test/PreprocessDetectorsToMDTest.h b/Framework/MDAlgorithms/test/PreprocessDetectorsToMDTest.h index 22c3734a8c904fc0a60272ed866226dcd0e7ac03..87d904b05fe2f1675c590dbc9d9b4140a1700848 100644 --- a/Framework/MDAlgorithms/test/PreprocessDetectorsToMDTest.h +++ b/Framework/MDAlgorithms/test/PreprocessDetectorsToMDTest.h @@ -5,6 +5,7 @@ #include "MantidGeometry/Instrument/Goniometer.h" #include "MantidMDAlgorithms/PreprocessDetectorsToMD.h" #include "MantidTestHelpers/WorkspaceCreationHelper.h" +#include "MantidAPI/SpectrumInfo.h" using namespace Mantid; using namespace Mantid::MDAlgorithms; @@ -258,9 +259,10 @@ public: } // Now mask all detectors in the workspace - std::vector<size_t>::const_iterator wit; - for (wit = indexLis.begin(); wit != indexLis.end(); ++wit) { - inputWS->maskWorkspaceIndex(*wit); + auto &spectrumInfo = inputWS->mutableSpectrumInfo(); + for (const auto i : indexLis) { + inputWS->getSpectrum(i).clearData(); + spectrumInfo.setMasked(i, true); } // let's retrieve masks now diff --git a/Framework/Properties/Mantid.properties.template b/Framework/Properties/Mantid.properties.template index 7921eb64b5010772538bd1e3fb3fc98a43ecdf12..f8d66cc81e82fd7d09a90e203325ef6ca5e4a826 100644 --- a/Framework/Properties/Mantid.properties.template +++ b/Framework/Properties/Mantid.properties.template @@ -124,7 +124,6 @@ MultiThreaded.MaxCores = 0 # Defines the area (in FWHM) on both sides of the peak centre within which peaks are calculated. # Outside this area peak functions return zero. -curvefitting.peakRadius = 5 curvefitting.defaultPeak=Gaussian curvefitting.findPeaksFWHM=7 curvefitting.findPeaksTolerance=4 diff --git a/Framework/PythonInterface/mantid/api/src/Exports/IMDHistoWorkspace.cpp b/Framework/PythonInterface/mantid/api/src/Exports/IMDHistoWorkspace.cpp index 90b2dd1cc43fcb73cc6c73e761a3e0f262715bce..2a085a4a41b32ea1bc559e89bee5784a6308c1d4 100644 --- a/Framework/PythonInterface/mantid/api/src/Exports/IMDHistoWorkspace.cpp +++ b/Framework/PythonInterface/mantid/api/src/Exports/IMDHistoWorkspace.cpp @@ -257,7 +257,13 @@ void export_IMDHistoWorkspace() { .def("getCenter", &IMDHistoWorkspace::getCenter, (arg("self"), arg("linear_index")), return_value_policy<return_by_value>(), - "Return the position of the center of a bin at a given position"); + "Return the position of the center of a bin at a given position") + + .def("setDisplayNormalization", + &IMDHistoWorkspace::setDisplayNormalization, + (arg("self"), arg("normalization")), + "Sets the visual normalization of" + " the workspace."); //------------------------------------------------------------------------------------------------- diff --git a/Framework/PythonInterface/plugins/algorithms/CollectHB3AExperimentInfo.py b/Framework/PythonInterface/plugins/algorithms/CollectHB3AExperimentInfo.py index 094213968ef0dcc86767a301bda4a619e5fd7f12..2ee26e43abc642dabc6acc4276bb8b6ae48d5b82 100644 --- a/Framework/PythonInterface/plugins/algorithms/CollectHB3AExperimentInfo.py +++ b/Framework/PythonInterface/plugins/algorithms/CollectHB3AExperimentInfo.py @@ -326,7 +326,7 @@ class CollectHB3AExperimentInfo(PythonAlgorithm): dataws = self._loadHB3ADetCountFile(scannumber, ptnumber) # write each detector's position and ID to table workspace - maxdetid = 0 + maxdetid = -1 for iws in range(dataws.getNumberHistograms()): detector = dataws.getDetector(iws) detpos = detector.getPos() diff --git a/Framework/PythonInterface/plugins/algorithms/ExtractMonitors.py b/Framework/PythonInterface/plugins/algorithms/ExtractMonitors.py index feb6cb70d5db1439c56caef78e9a2b9b0c5b7a40..a6de5b803264bde0ef009a87ac7d3c4d92513147 100644 --- a/Framework/PythonInterface/plugins/algorithms/ExtractMonitors.py +++ b/Framework/PythonInterface/plugins/algorithms/ExtractMonitors.py @@ -64,26 +64,26 @@ class ExtractMonitors(DataProcessorAlgorithm): if detector_ws_name: if detectors: - detector_ws = ExtractSpectra(InputWorkspace=in_ws, - WorkspaceIndexList=detectors) + extract_alg = self.createChildAlgorithm("ExtractSpectra") + extract_alg.setProperty("InputWorkspace", in_ws) + extract_alg.setProperty("WorkspaceIndexList", detectors) + extract_alg.execute() + detector_ws = extract_alg.getProperty("OutputWorkspace").value + self.setProperty("DetectorWorkspace", detector_ws) else: self.log().error("No detectors found in input workspace. No detector output workspace created.") if monitor_ws_name: if monitors: - monitor_ws = ExtractSpectra(InputWorkspace=in_ws, - WorkspaceIndexList=monitors) + extract_alg = self.createChildAlgorithm("ExtractSpectra") + extract_alg.setProperty("InputWorkspace", in_ws) + extract_alg.setProperty("WorkspaceIndexList", monitors) + extract_alg.execute() + monitor_ws = extract_alg.getProperty("OutputWorkspace").value + self.setProperty("MonitorWorkspace", monitor_ws) else: self.log().error("No monitors found in input workspace. No monitor output workspace created.") - if detector_ws_name and detectors: - self.setProperty("DetectorWorkspace", detector_ws) - DeleteWorkspace(detector_ws) - - if monitor_ws_name and monitors: - self.setProperty("MonitorWorkspace", monitor_ws) - DeleteWorkspace(monitor_ws) - if detector_ws_name and detectors and monitor_ws_name and monitors: detector_ws.setMonitorWorkspace(monitor_ws) diff --git a/Framework/PythonInterface/plugins/algorithms/SNAPReduce.py b/Framework/PythonInterface/plugins/algorithms/SNAPReduce.py new file mode 100644 index 0000000000000000000000000000000000000000..41939d68612338f07e6474b9c6bd4aafbfb592f1 --- /dev/null +++ b/Framework/PythonInterface/plugins/algorithms/SNAPReduce.py @@ -0,0 +1,444 @@ +# pylint: disable=invalid-name,no-init,too-many-lines +from __future__ import (absolute_import, division, print_function) +from mantid.kernel import Direction, FloatArrayProperty, IntArrayBoundedValidator, \ + IntArrayProperty, StringListValidator +from mantid.api import AlgorithmFactory, DataProcessorAlgorithm, FileAction, FileProperty, \ + PropertyMode, WorkspaceProperty +from mantid.simpleapi import AlignDetectors, CloneWorkspace, CompressEvents, \ + ConvertUnits, CreateGroupingWorkspace, CropWorkspace, DeleteWorkspace, DiffractionFocussing, \ + Divide, EditInstrumentGeometry, GetIPTS, Load, LoadDetectorsGroupingFile, LoadMask, \ + LoadNexusProcessed, LoadPreNexusLive, MaskDetectors, NormaliseByCurrent, \ + PreprocessDetectorsToMD, Rebin, RenameWorkspace, ReplaceSpecialValues, RemovePromptPulse, \ + SaveAscii, SaveFocusedXYE, SaveGSS, SaveNexusProcessed, mtd +import os +import numpy as np + + +class SNAPReduce(DataProcessorAlgorithm): + IPTS_dir = None + + def get_IPTS_Local(self, run): + if self.IPTS_dir is None: + self.IPTS_dir = GetIPTS(Instrument='SNAP', + RunNumber=str(run)) + return self.IPTS_dir + + def smooth(self, data, order): + # This smooths data based on linear weigthed average around + # point i for example for an order of 7 the i point is + # weighted 4, i=/- 1 weighted 3, i+/-2 weighted 2 and i+/-3 + # weighted 1 this input is only the y values + sm = np.zeros(len(data)) + factor = order / 2 + 1 + + for i in range(len(data)): + temp = 0 + ave = 0 + for r in range(max(0, i - int(order / 2)), + min(i + int(order / 2), len(data) - 1) + 1): + temp = temp + (factor - abs(r - i)) * data[r] + ave = ave + factor - abs(r - i) + sm[i] = temp / ave + + return sm + + def LLS_transformation(self, input): + # this transforms data to be more sensitive to weak peaks. The + # function is reversed by the Inv_LLS function below + out = np.log(np.log((input + 1)**0.5 + 1) + 1) + + return out + + def Inv_LLS_transformation(self, input): + # See Function LLS function above + out = (np.exp(np.exp(input) - 1) - 1)**2 - 1 + + return out + + def peak_clip(self, data, win=30, decrese=True, LLS=True, smooth_window=0): + start_data = np.copy(data) + + window = win + self.log().information(str(smooth_window)) + + if smooth_window > 0: + data = self.smooth(data, smooth_window) + + if LLS: + data = self.LLS_transformation(data) + + temp = data.copy() + + if decrese: + scan = list(range(window + 1, 0, -1)) + else: + scan = list(range(1, window + 1)) + + for w in scan: + for i in range(len(temp)): + if i < w or i > (len(temp) - w - 1): + continue + else: + win_array = temp[i - w:i + w + 1].copy() + win_array_reversed = win_array[::-1] + average = (win_array + win_array_reversed) / 2 + temp[i] = np.min(average[:len(average) / 2]) + + if LLS: + temp = self.Inv_LLS_transformation(temp) + + self.log().information(str(min(start_data - temp))) + + index = np.where((start_data - temp) == min(start_data - temp))[0][0] + + output = temp * (start_data[index] / temp[index]) + + return output + + def category(self): + return "Diffraction\\Reduction" + + def PyInit(self): + + validator = IntArrayBoundedValidator() + validator.setLower(0) + self.declareProperty(IntArrayProperty("RunNumbers", values=[0], direction=Direction.Input, + validator=validator), + "Run numbers to process, comma separated") + + self.declareProperty("LiveData", False, + "Read live data - requires a saved run in the current IPTS " + + "with the same Instrument configuration as the live run") + + mask = ["None", "Horizontal", "Vertical", + "Masking Workspace", "Custom - xml masking file"] + self.declareProperty("Masking", "None", StringListValidator(mask), + "Mask to be applied to the data") + + self.declareProperty(WorkspaceProperty("MaskingWorkspace", "", + Direction.Input, PropertyMode.Optional), + "The workspace containing the mask.") + + self.declareProperty(FileProperty(name="MaskingFilename", defaultValue="", + direction=Direction.Input, + action=FileAction.OptionalLoad), + doc="The file containing the xml mask.") + + self.declareProperty(name="Calibration", defaultValue="Convert Units", + validator=StringListValidator( + ["Convert Units", "Calibration File"]), + direction=Direction.Input, + doc="The type of conversion to d_spacing to be used.") + + self.declareProperty(FileProperty(name="CalibrationFilename", defaultValue="", + direction=Direction.Input, + action=FileAction.OptionalLoad), + doc="The calibration file to convert to d_spacing.") + + self.declareProperty(FloatArrayProperty("Binning", [0.5, -0.004, 7.0]), + "Min, Step, and Max of d-space bins. Logarithmic binning is used if Step is negative.") + + nor_corr = ["None", "From Workspace", + "From Processed Nexus", "Extracted from Data"] + self.declareProperty("Normalization", "None", StringListValidator(nor_corr), + "If needed what type of input to use as normalization, Extracted from " + + "Data uses a background determination that is peak independent.This " + + "implemantation can be tested in algorithm SNAP Peak Clipping Background") + + self.declareProperty(FileProperty(name="NormalizationFilename", defaultValue="", + direction=Direction.Input, + action=FileAction.OptionalLoad), + doc="The file containing the processed nexus for normalization.") + + self.declareProperty(WorkspaceProperty("NormalizationWorkspace", "", + Direction.Input, PropertyMode.Optional), + "The workspace containing the normalization data.") + + self.declareProperty("PeakClippingWindowSize", 10, + "Read live data - requires a saved run in the current " + + "IPTS with the same Instrumnet configuration") + + self.declareProperty("SmoothingRange", 10, + "Read live data - requires a saved run in the " + + "current IPTS with the same Instrumnet configuration") + + grouping = ["All", "Column", "Banks", "Modules", "2_4 Grouping"] + self.declareProperty("GroupDetectorsBy", "All", StringListValidator(grouping), + "Detector groups to use for future focussing: " + + "All detectors as one group, Groups (East,West for " + + "SNAP), Columns for SNAP, detector banks") + + mode = ["Set-Up", "Production"] + self.declareProperty("ProcessingMode", "Production", StringListValidator(mode), + "Set-Up Mode is used for establishing correct parameters. Production " + + "Mode only Normalized workspace is kept for each run.") + + self.declareProperty(name="OptionalPrefix", defaultValue="", + direction=Direction.Input, + doc="Optional Prefix to be added to workspaces and output filenames") + + self.declareProperty("SaveData", False, + "Save data in the following formats: Ascii- " + + "d-spacing ,Nexus Processed,GSAS and Fullprof") + + self.declareProperty(FileProperty(name="OutputDirectory", defaultValue="", + action=FileAction.OptionalDirectory), + doc='Default value is proposal shared directory') + + def validateInputs(self): + issues = dict() + + # cross check masking + masking = self.getProperty("Masking").value + if masking in ("None", "Horizontal", "Vertical"): + pass + elif masking in ("Custom - xml masking file"): + filename = self.getProperty("MaskingFilename").value + if len(filename) <= 0: + issues[ + "MaskingFilename"] = "Masking=\"%s\" requires a filename" % masking + elif masking == "MaskingWorkspace": + mask_workspace = self.getPropertyValue("MaskingWorkspace") + if mask_workspace is None or len(mask_workspace) <= 0: + issues["MaskingWorkspace"] = "Must supply masking workspace" + else: + raise RuntimeError("Masking value \"%s\" not supported" % masking) + + # cross check normalization + normalization = self.getProperty("Normalization").value + if normalization in ("None", "Extracted from Data"): + pass + elif normalization == "From Workspace": + norm_workspace = self.getPropertyValue("NormalizationWorkspace") + if norm_workspace is None: + issues['NormalizationWorkspace'] = 'Cannot be unset' + elif normalization == "From Processed Nexus": + filename = self.getProperty("NormalizationFilename").value + if len(filename) <= 0: + issues["NormalizationFilename"] = "Normalization=\"%s\" requires a filename" \ + % normalization + else: + raise RuntimeError( + "Normalization value \"%s\" not supported" % normalization) + + return issues + + def _getMaskWSname(self): + masking = self.getProperty("Masking").value + maskWSname = None + if masking == 'Custom - xml masking file': + maskWSname = 'CustomMask' + LoadMask(InputFile=self.getProperty('MaskingFilename').value, + Instrument='SNAP', OutputWorkspace=maskWSname) + elif masking == 'Horizontal': + maskWSname = 'HorizontalMask' + if not mtd.doesExist('HorizontalMask'): + LoadMask(InputFile='/SNS/SNAP/shared/libs/Horizontal_Mask.xml', + Instrument='SNAP', OutputWorkspace=maskWSname) + elif masking == 'Vertical': + maskWSname = 'VerticalMask' + if not mtd.doesExist('VerticalMask'): + LoadMask(InputFile='/SNS/SNAP/shared/libs/Vertical_Mask.xml', + Instrument='SNAP', OutputWorkspace=maskWSname) + elif masking == "Masking Workspace": + maskWSname = str(self.getProperty("MaskingWorkspace").value) + + return maskWSname + + def _generateNormalization(self, WS, normType, normWS): + if normType == 'None': + return None + elif normType == "Extracted from Data": + window = self.getProperty("PeakClippingWindowSize").value + + smooth_range = self.getProperty("SmoothingRange").value + + peak_clip_WS = CloneWorkspace(WS) + n_histo = peak_clip_WS.getNumberHistograms() + + x = peak_clip_WS.extractX() + y = peak_clip_WS.extractY() + e = peak_clip_WS.extractE() + + for h in range(n_histo): + peak_clip_WS.setX(h, x[h]) + peak_clip_WS.setY(h, self.peak_clip(y[h], win=window, decrese=True, + LLS=True, smooth_window=smooth_range)) + peak_clip_WS.setE(h, e[h]) + return peak_clip_WS + else: # other values are already held in normWS + return normWS + + def _save(self, runnumber, basename, norm): + if not self.getProperty("SaveData").value: + return + + saveDir = self.getProperty("OutputDirectory").value.strip() + if len(saveDir) <= 0: + self.log().notice('Using default save location') + saveDir = os.path.join( + self.get_IPTS_Local(runnumber), 'shared', 'data') + self.log().notice('Writing to \'' + saveDir + '\'') + + if norm == 'None': + SaveNexusProcessed(InputWorkspace='WS_red', + Filename=os.path.join(saveDir, 'nexus', basename + '.nxs')) + SaveAscii(InputWorkspace='WS_red', + Filename=os.path.join(saveDir, 'd_spacing', basename + '.dat')) + ConvertUnits(InputWorkspace='WS_red', OutputWorkspace='WS_tof', + Target="TOF", AlignBins=False) + else: + SaveNexusProcessed(InputWorkspace='WS_nor', + Filename=os.path.join(saveDir, 'nexus', basename + '.nxs')) + SaveAscii(InputWorkspace='WS_nor', + Filename=os.path.join(saveDir, 'd_spacing', basename + '.dat')) + ConvertUnits(InputWorkspace='WS_nor', OutputWorkspace='WS_tof', + Target="TOF", AlignBins=False) + + SaveGSS(InputWorkspace='WS_tof', + Filename=os.path.join(saveDir, 'gsas', basename + '.gsa'), + Format='SLOG', SplitFiles=False, Append=False, ExtendedHeader=True) + SaveFocusedXYE(InputWorkspace='WS_tof', + Filename=os.path.join( + saveDir, 'fullprof', basename + '.dat'), + SplitFiles=True, Append=False) + DeleteWorkspace(Workspace='WS_tof') + + def PyExec(self): + # Retrieve all relevant notice + + in_Runs = self.getProperty("RunNumbers").value + + maskWSname = self._getMaskWSname() + + calib = self.getProperty("Calibration").value + if calib == "Calibration File": + cal_File = self.getProperty("CalibrationFilename").value + + params = self.getProperty("Binning").value + norm = self.getProperty("Normalization").value + + if norm == "From Processed Nexus": + norm_File = self.getProperty("Normalization filename").value + normWS = LoadNexusProcessed(Filename=norm_File) + elif norm == "From Workspace": + normWS = self.getProperty("NormalizationWorkspace").value + else: + normWS = None + + group_to_real = {'Banks':'Group', 'Modules':'bank', '2_4 Grouping':'2_4_Grouping'} + group = self.getProperty("GroupDetectorsBy").value + real_name = group_to_real.get(group, group) + + if not mtd.doesExist(group): + if group == "2_4 Grouping": + group = real_name + LoadDetectorsGroupingFile(InputFile=r'/SNS/SNAP/shared/libs/SNAP_group_2_4.xml', + OutputWorkspace=group) + else: + CreateGroupingWorkspace(InstrumentName='SNAP', GroupDetectorsBy=real_name, + OutputWorkspace=group) + + Process_Mode = self.getProperty("ProcessingMode").value + + prefix = self.getProperty("OptionalPrefix").value + + # --------------------------- REDUCE DATA ----------------------------- + + Tag = 'SNAP' + for r in in_Runs: + self.log().notice("processing run %s" % r) + self.log().information(str(self.get_IPTS_Local(r))) + if self.getProperty("LiveData").value: + Tag = 'Live' + WS = LoadPreNexusLive(Instrument='SNAP') + else: + WS = Load(Filename='SNAP' + str(r), Outputworkspace='WS') + WS = NormaliseByCurrent(InputWorkspace=WS, + Outputworkspace='WS') + + WS = CompressEvents(InputWorkspace=WS, Outputworkspace='WS') + WS = CropWorkspace(InputWorkspace='WS', + OutputWorkspace='WS', XMax=50000) + WS = RemovePromptPulse(InputWorkspace=WS, OutputWorkspace='WS', + Width='1600', Frequency='60.4') + + if maskWSname is not None: + WS = MaskDetectors(Workspace=WS, MaskedWorkspace=maskWSname) + + if calib == "Convert Units": + WS_d = ConvertUnits(InputWorkspace='WS', + Target='dSpacing', Outputworkspace='WS_d') + else: + self.log().notice("\n calibration file : %s" % cal_File) + WS_d = AlignDetectors( + InputWorkspace='WS', CalibrationFile=cal_File, Outputworkspace='WS_d') + + WS_d = Rebin(InputWorkspace=WS_d, Params=params, + Outputworkspace='WS_d') + + WS_red = DiffractionFocussing(InputWorkspace=WS_d, GroupingWorkspace=group, + PreserveEvents=False) + + normWS = self._generateNormalization(WS_red, norm, normWS) + WS_nor = None + if normWS is not None: + WS_nor = Divide(LHSWorkspace=WS_red, RHSWorkspace=normWS) + WS_nor = ReplaceSpecialValues(Inputworkspace=WS_nor, + NaNValue='0', NaNError='0', + InfinityValue='0', InfinityError='0') + + new_Tag = Tag + if len(prefix) > 0: + new_Tag += '_' + prefix + + # Edit instrument geomety to make final workspace smaller on disk + det_table = PreprocessDetectorsToMD(Inputworkspace='WS_red', + OutputWorkspace='__SNAP_det_table') + polar = np.degrees(det_table.column('TwoTheta')) + azi = np.degrees(det_table.column('Azimuthal')) + EditInstrumentGeometry(Workspace="WS_red", L2=det_table.column('L2'), + Polar=polar, Azimuthal=azi) + if WS_nor is not None: + EditInstrumentGeometry(Workspace="WS_nor", L2=det_table.column('L2'), + Polar=polar, Azimuthal=azi) + mtd.remove('__SNAP_det_table') + + # Save requested formats + basename = '%s_%s_%s' % (new_Tag, r, group) + self._save(r, basename, norm) + + # temporary workspace no longer needed + DeleteWorkspace(Workspace='WS') + + # rename everything as appropriate and determine output workspace name + RenameWorkspace(Inputworkspace='WS_d', + OutputWorkspace='%s_%s_d' % (new_Tag, r)) + RenameWorkspace(Inputworkspace='WS_red', + OutputWorkspace=basename + '_red') + if norm == 'None': + outputWksp = basename + '_red' + else: + outputWksp = basename + '_nor' + RenameWorkspace(Inputworkspace='WS_nor', + OutputWorkspace=basename + '_nor') + if norm == "Extracted from Data": + RenameWorkspace(Inputworkspace='peak_clip_WS', + OutputWorkspace='%s_%s_normalizer' % (new_Tag, r)) + + # delte some things in production + if Process_Mode == "Production": + DeleteWorkspace(Workspace='%s_%s_d' % (new_Tag, r)) # was 'WS_d' + + if norm != "None": + DeleteWorkspace(Workspace=basename + '_red') # was 'WS_red' + + if norm == "Extracted from Data": + DeleteWorkspace(Workspace='%s_%s_normalizer' % (new_Tag, r)) # was 'peak_clip_WS' + + propertyName = 'OutputWorkspace' + self.declareProperty(WorkspaceProperty( + propertyName, outputWksp, Direction.Output)) + self.setProperty(propertyName, outputWksp) + +AlgorithmFactory.subscribe(SNAPReduce) diff --git a/Framework/PythonInterface/plugins/algorithms/SNSPowderReduction.py b/Framework/PythonInterface/plugins/algorithms/SNSPowderReduction.py index 838e13e6c3f6ef76f663d0aeb865d0d51f844720..376a9d879ae6551219b96aeb8a30d95f90c5149c 100644 --- a/Framework/PythonInterface/plugins/algorithms/SNSPowderReduction.py +++ b/Framework/PythonInterface/plugins/algorithms/SNSPowderReduction.py @@ -95,6 +95,8 @@ def allEventWorkspaces(*args): def getBasename(filename): + if type(filename) == list: + filename = filename[0] name = os.path.split(filename)[-1] for extension in EXTENSIONS_NXS: name = name.replace(extension, '') @@ -268,6 +270,11 @@ class SNSPowderReduction(DataProcessorAlgorithm): self._outTypes = self.getProperty("SaveAs").value.lower() samRuns = self.getProperty("Filename").value + if type(samRuns[0]) == list: + linearizedRuns = [] + for item in samRuns: + linearizedRuns.extend(item) + samRuns = linearizedRuns[:] # deep copy self._determineInstrument(samRuns[0]) preserveEvents = self.getProperty("PreserveEvents").value @@ -973,24 +980,22 @@ class SNSPowderReduction(DataProcessorAlgorithm): # Determine characterization if mtd.doesExist("characterizations"): # get the correct row of the table if table workspace 'charactersizations' exists - - #pylint: disable=unused-variable - charac = api.PDDetermineCharacterizations(InputWorkspace=wksp_name, - Characterizations="characterizations", - ReductionProperties="__snspowderreduction", - BackRun=self.getProperty("BackgroundNumber").value, - NormRun=self.getProperty("VanadiumNumber").value, - NormBackRun=self.getProperty("VanadiumBackgroundNumber").value, - FrequencyLogNames=self.getProperty("FrequencyLogNames").value, - WaveLengthLogNames=self.getProperty("WaveLengthLogNames").value) + api.PDDetermineCharacterizations(InputWorkspace=wksp_name, + Characterizations="characterizations", + ReductionProperties="__snspowderreduction", + BackRun=self.getProperty("BackgroundNumber").value, + NormRun=self.getProperty("VanadiumNumber").value, + NormBackRun=self.getProperty("VanadiumBackgroundNumber").value, + FrequencyLogNames=self.getProperty("FrequencyLogNames").value, + WaveLengthLogNames=self.getProperty("WaveLengthLogNames").value) else: - charac = api.PDDetermineCharacterizations(InputWorkspace=wksp_name, - ReductionProperties="__snspowderreduction", - BackRun=self.getProperty("BackgroundNumber").value, - NormRun=self.getProperty("VanadiumNumber").value, - NormBackRun=self.getProperty("VanadiumBackgroundNumber").value, - FrequencyLogNames=self.getProperty("FrequencyLogNames").value, - WaveLengthLogNames=self.getProperty("WaveLengthLogNames").value) + api.PDDetermineCharacterizations(InputWorkspace=wksp_name, + ReductionProperties="__snspowderreduction", + BackRun=self.getProperty("BackgroundNumber").value, + NormRun=self.getProperty("VanadiumNumber").value, + NormBackRun=self.getProperty("VanadiumBackgroundNumber").value, + FrequencyLogNames=self.getProperty("FrequencyLogNames").value, + WaveLengthLogNames=self.getProperty("WaveLengthLogNames").value) # convert the result into a dict return PropertyManagerDataService.retrieve("__snspowderreduction") diff --git a/Framework/PythonInterface/test/python/plugins/algorithms/TOSCABankCorrectionTest.py b/Framework/PythonInterface/test/python/plugins/algorithms/TOSCABankCorrectionTest.py index 0200db03404bbe9aa5dca72e758bd0e47af4ebf3..a445a4efbed93a7264e1d05ec884941238b49f7a 100644 --- a/Framework/PythonInterface/test/python/plugins/algorithms/TOSCABankCorrectionTest.py +++ b/Framework/PythonInterface/test/python/plugins/algorithms/TOSCABankCorrectionTest.py @@ -34,9 +34,9 @@ class TOSCABankCorrectionTest(unittest.TestCase): corrected_reduction, peak_position, scale_factor_1, scale_factor_2 = \ TOSCABankCorrection(InputWorkspace=self._original) - self.assertAlmostEqual(peak_position, 1077.47222328) - self.assertAlmostEqual(scale_factor_1, 1.0059271) - self.assertAlmostEqual(scale_factor_2, 0.9941423) + self.assertAlmostEqual(peak_position, 1079.84991188) + self.assertAlmostEqual(scale_factor_1, 1.0060389) + self.assertAlmostEqual(scale_factor_2, 0.9940331) def test_automatic_peak_in_range(self): @@ -48,9 +48,9 @@ class TOSCABankCorrectionTest(unittest.TestCase): TOSCABankCorrection(InputWorkspace=self._original, SearchRange=[200, 800]) - self.assertAlmostEqual(peak_position, 713.20080359) - self.assertAlmostEqual(scale_factor_1, 1.006076146) - self.assertAlmostEqual(scale_factor_2, 0.993996806) + self.assertAlmostEqual(peak_position, 714.008962427) + self.assertAlmostEqual(scale_factor_1, 1.004949468) + self.assertAlmostEqual(scale_factor_2, 0.995099045) def test_manual_peak_selection(self): @@ -62,9 +62,9 @@ class TOSCABankCorrectionTest(unittest.TestCase): TOSCABankCorrection(InputWorkspace=self._original, PeakPosition='715') - self.assertAlmostEqual(peak_position, 713.4430671) - self.assertAlmostEqual(scale_factor_1, 1.00611439) - self.assertAlmostEqual(scale_factor_2, 0.99395947) + self.assertAlmostEqual(peak_position, 714.29114157) + self.assertAlmostEqual(scale_factor_1, 1.00491105) + self.assertAlmostEqual(scale_factor_2, 0.99513671) def test_manual_peak_not_found(self): diff --git a/Framework/RemoteAlgorithms/src/SCARFTomoReconstruction.cpp b/Framework/RemoteAlgorithms/src/SCARFTomoReconstruction.cpp index a943acabb8f495664c0ff47377d68a882d10db88..78c7e4df5728289b624e9083ad6aafb7137298d0 100644 --- a/Framework/RemoteAlgorithms/src/SCARFTomoReconstruction.cpp +++ b/Framework/RemoteAlgorithms/src/SCARFTomoReconstruction.cpp @@ -1351,12 +1351,11 @@ void SCARFTomoReconstruction::getOneJobFile(const std::string &jobId, {"Content-Type", "application/xml"}, {"Cookie", token}, {"Accept", m_acceptType}}; - std::string body = remotePath; int code; std::stringstream ss; try { - code = doSendRequestGetResponse(httpsURL, ss, headers, - Poco::Net::HTTPRequest::HTTP_GET, body); + code = doSendRequestGetResponse( + httpsURL, ss, headers, Poco::Net::HTTPRequest::HTTP_GET, remotePath); } catch (Kernel::Exception::InternetError &ie) { throw std::runtime_error( "Error while sending HTTP request to download a file: " + diff --git a/Framework/RemoteJobManagers/src/LSFJobManager.cpp b/Framework/RemoteJobManagers/src/LSFJobManager.cpp index d2b137a95de34929eb619ea5d018f4b343584063..cbedc1178227127ed7743d2b046e89e471345128 100644 --- a/Framework/RemoteJobManagers/src/LSFJobManager.cpp +++ b/Framework/RemoteJobManagers/src/LSFJobManager.cpp @@ -1125,12 +1125,11 @@ void LSFJobManager::getOneJobFile(const std::string &jobId, const Poco::URI fullURL = makeFullURI(t.m_url, g_downloadOneBasePath, jobId); const StringToStringMap headers = makeHeaders(std::string("application/xml"), token, g_acceptType); - const std::string body = remotePath; int code = 0; std::stringstream ss; try { - code = doSendRequestGetResponse(fullURL, ss, headers, - Poco::Net::HTTPRequest::HTTP_GET, body); + code = doSendRequestGetResponse( + fullURL, ss, headers, Poco::Net::HTTPRequest::HTTP_GET, remotePath); } catch (Kernel::Exception::InternetError &ie) { throw std::runtime_error( "Error while sending HTTP request to download a file: " + diff --git a/Framework/RemoteJobManagers/src/MantidWebServiceAPIJobManager.cpp b/Framework/RemoteJobManagers/src/MantidWebServiceAPIJobManager.cpp index ba53b73cd36280c297152f15dd2cf9273d9f6487..beb5de2fe487c257d36d7f2de6d0dc2562670300 100644 --- a/Framework/RemoteJobManagers/src/MantidWebServiceAPIJobManager.cpp +++ b/Framework/RemoteJobManagers/src/MantidWebServiceAPIJobManager.cpp @@ -369,8 +369,7 @@ std::string MantidWebServiceAPIJobManager::startRemoteTransaction() { * (remote) compute resource. */ void MantidWebServiceAPIJobManager::stopRemoteTransaction( - const std::string &transactionID) { - std::string transId = transactionID; + const std::string &transId) { std::istream &respStream = httpGet("/transaction", std::string("Action=Stop&TransID=") + transId); @@ -420,9 +419,8 @@ std::string MantidWebServiceAPIJobManager::submitRemoteJob( postData[runnable] = param; // Job name is optional - std::string jobName = taskName; - if (jobName.length() > 0) { - postData["JobName"] = jobName; + if (taskName.length() > 0) { + postData["JobName"] = taskName; } std::istream &respStream = httpPost("/submit", postData); diff --git a/Framework/SINQ/inc/MantidSINQ/PoldiUtilities/PoldiDeadWireDecorator.h b/Framework/SINQ/inc/MantidSINQ/PoldiUtilities/PoldiDeadWireDecorator.h index 34593fc70c2a18da4dd438b3f3abca92d5c16332..4c6abeb74f98b067b38179c6b973e0e57ccdae3c 100644 --- a/Framework/SINQ/inc/MantidSINQ/PoldiUtilities/PoldiDeadWireDecorator.h +++ b/Framework/SINQ/inc/MantidSINQ/PoldiUtilities/PoldiDeadWireDecorator.h @@ -3,12 +3,13 @@ #include "MantidKernel/System.h" -#include "MantidGeometry/Instrument.h" - #include "MantidSINQ/DllConfig.h" #include "MantidSINQ/PoldiUtilities/PoldiDetectorDecorator.h" namespace Mantid { +namespace API { +class DetectorInfo; +} namespace Poldi { /** PoldiDeadWireDecorator : @@ -47,7 +48,7 @@ public: PoldiDeadWireDecorator(std::set<int> deadWires, boost::shared_ptr<PoldiAbstractDetector> detector = boost::shared_ptr<PoldiAbstractDetector>()); - PoldiDeadWireDecorator(Geometry::Instrument_const_sptr poldiInstrument, + PoldiDeadWireDecorator(const API::DetectorInfo &poldiDetectorInfo, boost::shared_ptr<PoldiAbstractDetector> detector = boost::shared_ptr<PoldiAbstractDetector>()); @@ -61,8 +62,6 @@ protected: void detectorSetHook() override; std::vector<int> getGoodElements(std::vector<int> rawElements); - static bool detectorIsNotMasked(Geometry::Instrument_const_sptr instrument, - detid_t detectorId); bool isDeadElement(int index); std::set<int> m_deadWireSet; diff --git a/Framework/SINQ/src/PoldiAnalyseResiduals.cpp b/Framework/SINQ/src/PoldiAnalyseResiduals.cpp index 70670b14988ec38e333a23a88497ff79c2808d73..50f3f6143d8109f9afd6453f35601805df7ff34e 100644 --- a/Framework/SINQ/src/PoldiAnalyseResiduals.cpp +++ b/Framework/SINQ/src/PoldiAnalyseResiduals.cpp @@ -199,7 +199,7 @@ void PoldiAnalyseResiduals::exec() { boost::make_shared<PoldiInstrumentAdapter>(measured); // Dead wires need to be taken into account PoldiAbstractDetector_sptr deadWireDetector = - boost::make_shared<PoldiDeadWireDecorator>(measured->getInstrument(), + boost::make_shared<PoldiDeadWireDecorator>(measured->detectorInfo(), poldiInstrument->detector()); // Since the valid workspace indices are required for some calculations, we diff --git a/Framework/SINQ/src/PoldiAutoCorrelation5.cpp b/Framework/SINQ/src/PoldiAutoCorrelation5.cpp index c43f02d4c9c9802e03e8e821bdf7ee86e2e910c7..ba2c2c4954343cb8609384764f3fefc7087cab22 100644 --- a/Framework/SINQ/src/PoldiAutoCorrelation5.cpp +++ b/Framework/SINQ/src/PoldiAutoCorrelation5.cpp @@ -83,7 +83,7 @@ void PoldiAutoCorrelation5::exec() { PoldiAbstractDetector_sptr detector = instrumentAdapter.detector(); boost::shared_ptr<PoldiDeadWireDecorator> cleanDetector( - new PoldiDeadWireDecorator(localWorkspace->getInstrument(), detector)); + new PoldiDeadWireDecorator(localWorkspace->detectorInfo(), detector)); // log configuration information logConfigurationInformation(cleanDetector, chopper); diff --git a/Framework/SINQ/src/PoldiFitPeaks2D.cpp b/Framework/SINQ/src/PoldiFitPeaks2D.cpp index fcccde183b78f04a2aeb3132a8b31c341aa1352a..2996cdf60e1d0b1906cfac437a9b7c8febabde7d 100644 --- a/Framework/SINQ/src/PoldiFitPeaks2D.cpp +++ b/Framework/SINQ/src/PoldiFitPeaks2D.cpp @@ -858,7 +858,7 @@ MatrixWorkspace_sptr PoldiFitPeaks2D::get1DSpectrum( } PoldiAbstractDetector_sptr detector(new PoldiDeadWireDecorator( - workspace->getInstrument(), m_poldiInstrument->detector())); + workspace->detectorInfo(), m_poldiInstrument->detector())); std::vector<int> indices = detector->availableElements(); // Create the grid for the diffractogram and corresponding domain/values diff --git a/Framework/SINQ/src/PoldiUtilities/PoldiDeadWireDecorator.cpp b/Framework/SINQ/src/PoldiUtilities/PoldiDeadWireDecorator.cpp index 566f7e0b72aaa036bf792e2c739bc5dc8daef37a..440c0f75248f3f0fe58f0438f894f967ad3327e5 100644 --- a/Framework/SINQ/src/PoldiUtilities/PoldiDeadWireDecorator.cpp +++ b/Framework/SINQ/src/PoldiUtilities/PoldiDeadWireDecorator.cpp @@ -1,3 +1,4 @@ +#include "MantidAPI/DetectorInfo.h" #include "MantidSINQ/PoldiUtilities/PoldiDeadWireDecorator.h" #include <algorithm> @@ -17,18 +18,19 @@ PoldiDeadWireDecorator::PoldiDeadWireDecorator( } PoldiDeadWireDecorator::PoldiDeadWireDecorator( - Instrument_const_sptr poldiInstrument, + const API::DetectorInfo &poldiDetectorInfo, boost::shared_ptr<PoldiAbstractDetector> detector) : PoldiDetectorDecorator(detector), m_deadWireSet(), m_goodElements() { setDecoratedDetector(detector); - std::vector<detid_t> allDetectorIds = poldiInstrument->getDetectorIDs(); + std::vector<detid_t> allDetectorIds = poldiDetectorInfo.detectorIDs(); std::vector<detid_t> deadDetectorIds(allDetectorIds.size()); auto endIterator = std::remove_copy_if( allDetectorIds.begin(), allDetectorIds.end(), deadDetectorIds.begin(), - boost::bind<bool>(&PoldiDeadWireDecorator::detectorIsNotMasked, - poldiInstrument, _1)); + [&](const detid_t detID) -> bool { + return !poldiDetectorInfo.isMasked(poldiDetectorInfo.indexOf(detID)); + }); deadDetectorIds.resize(std::distance(deadDetectorIds.begin(), endIterator)); setDeadWires(std::set<int>(deadDetectorIds.begin(), deadDetectorIds.end())); @@ -76,11 +78,6 @@ PoldiDeadWireDecorator::getGoodElements(std::vector<int> rawElements) { return rawElements; } -bool PoldiDeadWireDecorator::detectorIsNotMasked( - Instrument_const_sptr instrument, detid_t detectorId) { - return !instrument->isDetectorMasked(detectorId); -} - bool PoldiDeadWireDecorator::isDeadElement(int index) { return m_deadWireSet.count(index) != 0; } diff --git a/Framework/TestHelpers/src/WorkspaceCreationHelper.cpp b/Framework/TestHelpers/src/WorkspaceCreationHelper.cpp index cd1492a407629a42f1a75134b4e0c55bc0cfad55..de759f1f43dd0b711cfa37fa01b55bb5308564d6 100644 --- a/Framework/TestHelpers/src/WorkspaceCreationHelper.cpp +++ b/Framework/TestHelpers/src/WorkspaceCreationHelper.cpp @@ -18,6 +18,7 @@ #include "MantidAPI/Algorithm.h" #include "MantidAPI/Sample.h" #include "MantidAPI/SpectraAxis.h" +#include "MantidAPI/SpectrumInfo.h" #include "MantidAPI/NumericAxis.h" #include "MantidAPI/WorkspaceGroup.h" #include "MantidDataObjects/PeaksWorkspace.h" @@ -223,13 +224,9 @@ Workspace2D_sptr maskSpectra(Workspace2D_sptr workspace, workspace->setInstrument(instrument); } - ParameterMap &pmap = workspace->instrumentParameters(); - for (int i = 0; i < nhist; ++i) { - if (maskedWorkspaceIndices.find(i) != maskedWorkspaceIndices.end()) { - IDetector_const_sptr det = workspace->getDetector(i); - pmap.addBool(det.get(), "masked", true); - } - } + auto &spectrumInfo = workspace->mutableSpectrumInfo(); + for (const auto index : maskedWorkspaceIndices) + spectrumInfo.setMasked(index, true); return workspace; } diff --git a/Framework/WorkflowAlgorithms/src/ConvolutionFitSequential.cpp b/Framework/WorkflowAlgorithms/src/ConvolutionFitSequential.cpp index 7e05ad35f573b30a148baf169e939bc14f628df5..93801abbccf4470a48dfe2b240a44ff834cf137c 100644 --- a/Framework/WorkflowAlgorithms/src/ConvolutionFitSequential.cpp +++ b/Framework/WorkflowAlgorithms/src/ConvolutionFitSequential.cpp @@ -109,6 +109,14 @@ void ConvolutionFitSequential::init() { declareProperty("MaxIterations", 500, boundedV, "The maximum number of iterations permitted", Direction::Input); + declareProperty("PeakRadius", 0, + "A value of the peak radius the peak functions should use. A " + "peak radius defines an interval on the x axis around the " + "centre of the peak where its values are calculated. Values " + "outside the interval are not calculated and assumed zeros." + "Numerically the radius is a whole number of peak widths " + "(FWHM) that fit into the interval on each side from the " + "centre. The default value of 0 means the whole x axis."); declareProperty(make_unique<WorkspaceProperty<>>("OutputWorkspace", "", Direction::Output), @@ -131,6 +139,7 @@ void ConvolutionFitSequential::exec() { const bool convolve = getProperty("Convolve"); const int maxIter = getProperty("MaxIterations"); const std::string minimizer = getProperty("Minimizer"); + const int peakRadius = getProperty("PeakRadius"); // Inspect function to obtain fit Type and background const auto functionValues = findValuesFromFunction(function); @@ -207,6 +216,7 @@ void ConvolutionFitSequential::exec() { plotPeaks->setProperty("MaxIterations", maxIter); plotPeaks->setProperty("Minimizer", minimizer); plotPeaks->setProperty("PassWSIndexToFunction", passIndex); + plotPeaks->setProperty("PeakRadius", peakRadius); plotPeaks->executeAsChildAlg(); ITableWorkspace_sptr outputWs = plotPeaks->getProperty("OutputWorkspace"); diff --git a/Framework/WorkflowAlgorithms/src/EQSANSPatchSensitivity.cpp b/Framework/WorkflowAlgorithms/src/EQSANSPatchSensitivity.cpp index 9c5c8a0da6e7d04159d97ba958722e3b6689e34b..7c62bb2edf8a10983f60e2c4bfb1470049115536 100644 --- a/Framework/WorkflowAlgorithms/src/EQSANSPatchSensitivity.cpp +++ b/Framework/WorkflowAlgorithms/src/EQSANSPatchSensitivity.cpp @@ -1,10 +1,7 @@ -//---------------------------------------------------------------------- -// Includes -//---------------------------------------------------------------------- #include "MantidWorkflowAlgorithms/EQSANSPatchSensitivity.h" #include "MantidAPI/MatrixWorkspace.h" +#include "MantidAPI/SpectrumInfo.h" #include "MantidGeometry/Instrument.h" -#include "MantidGeometry/Instrument/ParameterMap.h" #include "MantidKernel/cow_ptr.h" namespace Mantid { @@ -40,8 +37,6 @@ void EQSANSPatchSensitivity::exec() { inputWS->getInstrument()->getNumberParameter("number-of-y-pixels")[0]); const int numberOfSpectra = static_cast<int>(inputWS->getNumberHistograms()); - // Need to get hold of the parameter map - Geometry::ParameterMap &pmap = inputWS->instrumentParameters(); // Loop over all tubes and patch as necessary for (int i = 0; i < nx_pixels; i++) { @@ -104,26 +99,23 @@ void EQSANSPatchSensitivity::exec() { // Apply patch progress(0.91, "Applying patch"); + auto &spectrumInfo = inputWS->mutableSpectrumInfo(); for (auto patched_id : patched_ids) { - const Geometry::ComponentID det = - inputWS->getDetector(patched_id)->getComponentID(); - try { - if (det) { - MantidVec &YValues = inputWS->dataY(patched_id); - MantidVec &YErrors = inputWS->dataE(patched_id); - if (useRegression) { - YValues[0] = alpha + beta * det->getPos().Y(); - YErrors[0] = error; - } else { - YValues[0] = average; - YErrors[0] = error; - } - - pmap.addBool(det, "masked", false); - } - } catch (Kernel::Exception::NotFoundError &e) { - g_log.warning() << e.what() << " Found while setting mask bit\n"; + if (!spectrumInfo.hasDetectors(patched_id)) { + g_log.warning() << "Spectrum " << patched_id + << " has no detector, skipping (not clearing mask)\n"; + continue; } + MantidVec &YValues = inputWS->dataY(patched_id); + MantidVec &YErrors = inputWS->dataE(patched_id); + if (useRegression) { + YValues[0] = alpha + beta * spectrumInfo.position(patched_id).Y(); + YErrors[0] = error; + } else { + YValues[0] = average; + YErrors[0] = error; + } + spectrumInfo.setMasked(patched_id, false); } } } diff --git a/MantidPlot/src/ApplicationWindow.cpp b/MantidPlot/src/ApplicationWindow.cpp index e388d940432c630ef709957e47382209867d3fbe..d6e555ea6a40d015e02198e387ebd122b148d67f 100644 --- a/MantidPlot/src/ApplicationWindow.cpp +++ b/MantidPlot/src/ApplicationWindow.cpp @@ -189,7 +189,6 @@ #include "Mantid/ManageInterfaceCategories.h" #include "Mantid/FirstTimeSetup.h" -#include "MantidQtAPI/FileDialogHandler.h" #include "MantidQtAPI/InterfaceManager.h" #include "MantidQtAPI/UserSubWindow.h" #include "MantidQtAPI/AlgorithmInputHistory.h" @@ -202,6 +201,7 @@ #include "MantidQtMantidWidgets/FitPropertyBrowser.h" #include "MantidQtMantidWidgets/MessageDisplay.h" #include "MantidQtMantidWidgets/MuonFitPropertyBrowser.h" +#include "MantidQtMantidWidgets/TrackedAction.h" #include "MantidKernel/ConfigService.h" #include "MantidKernel/FacilityInfo.h" @@ -5940,13 +5940,11 @@ std::string ApplicationWindow::windowGeometryInfo(MdiSubWindow *w) { } tsv << x << y; - if (w->status() != MdiSubWindow::Minimized) - tsv << w->width() << w->height(); - else - tsv << w->minRestoreSize().width() << w->minRestoreSize().height() - << "minimized"; + tsv << w->width() << w->height(); - if (hidden(w)) + if (w->status() == MdiSubWindow::Minimized) + tsv << "minimized"; + else if (hidden(w)) tsv << "hidden"; else if (w == activeWindow()) tsv << "active"; @@ -6040,7 +6038,7 @@ void ApplicationWindow::savetoNexusFile() { QString selectedFilter; QString fileDir = MantidQt::API::AlgorithmInputHistory::Instance().getPreviousDirectory(); - QString fileName = MantidQt::API::FileDialogHandler::getSaveFileName( + QString fileName = QFileDialog::getSaveFileName( this, tr("Save File As"), fileDir, filter, &selectedFilter); if (!fileName.isEmpty()) { std::string wsName; @@ -6088,6 +6086,9 @@ void ApplicationWindow::loadDataFileByName(QString fn) { if (fnInfo.suffix() == "py") { // We have a python file, just load it into script window loadScript(fn, true); + } else if (fnInfo.suffix() == "mantid") { + // We have a mantid project file, pass on to project loading + open(fn); } else if (mantidUI) { // Run Load algorithm on file QHash<QString, QString> params; @@ -6103,8 +6104,8 @@ void ApplicationWindow::saveProjectAs(const QString &fileName, bool compress) { filter += tr("Compressed MantidPlot project") + " (*.mantid.gz)"; QString selectedFilter; - fn = MantidQt::API::FileDialogHandler::getSaveFileName( - this, tr("Save Project As"), workingDir, filter, &selectedFilter); + fn = QFileDialog::getSaveFileName(this, tr("Save Project As"), workingDir, + filter, &selectedFilter); if (selectedFilter.contains(".gz")) compress = true; } @@ -6478,10 +6479,10 @@ void ApplicationWindow::exportASCII(const QString &tableName, return; QString selectedFilter; - QString fname = MantidQt::API::FileDialogHandler::getSaveFileName( - this, tr("Choose a filename to save under"), - asciiDirPath + "/" + w->objectName(), "*.txt;;*.dat;;*.DAT", - &selectedFilter); + QString fname = + QFileDialog::getSaveFileName(this, tr("Choose a filename to save under"), + asciiDirPath + "/" + w->objectName(), + "*.txt;;*.dat;;*.DAT", &selectedFilter); if (!fname.isEmpty()) { QFileInfo fi(fname); QString baseName = fi.fileName(); @@ -7615,7 +7616,7 @@ void ApplicationWindow::exportPDF() { return; } - QString fname = MantidQt::API::FileDialogHandler::getSaveFileName( + QString fname = QFileDialog::getSaveFileName( this, tr("Choose a filename to save under"), workingDir, "*.pdf"); if (!fname.isEmpty()) { QFileInfo fi(fname); @@ -11471,126 +11472,133 @@ void ApplicationWindow::setPlot3DOptions() { } void ApplicationWindow::createActions() { - actionCustomActionDialog = new QAction(tr("Manage Custom Menus..."), this); + actionCustomActionDialog = new MantidQt::MantidWidgets::TrackedAction( + tr("Manage Custom Menus..."), this); connect(actionCustomActionDialog, SIGNAL(triggered()), this, SLOT(showCustomActionDialog())); - actionManageDirs = new QAction(QIcon(getQPixmap("managefolders_xpm")), - tr("Manage User Directories"), this); + actionManageDirs = new MantidQt::MantidWidgets::TrackedAction( + QIcon(getQPixmap("managefolders_xpm")), tr("Manage User Directories"), + this); connect(actionManageDirs, SIGNAL(triggered()), this, SLOT(showUserDirectoryDialog())); - actionFirstTimeSetup = new QAction(tr("First Time Setup"), this); + actionFirstTimeSetup = + new MantidQt::MantidWidgets::TrackedAction(tr("First Time Setup"), this); connect(actionFirstTimeSetup, SIGNAL(triggered()), this, SLOT(showFirstTimeSetup())); - actionNewProject = - new QAction(QIcon(":/NewProject16x16.png"), tr("New &Project"), this); + actionNewProject = new MantidQt::MantidWidgets::TrackedAction( + QIcon(":/NewProject16x16.png"), tr("New &Project"), this); actionNewProject->setShortcut(tr("Ctrl+N")); connect(actionNewProject, SIGNAL(triggered()), this, SLOT(newProject())); - actionSaveProject = - new QAction(QIcon(":/SaveProject16x16.png"), tr("Save &Project"), this); + actionSaveProject = new MantidQt::MantidWidgets::TrackedAction( + QIcon(":/SaveProject16x16.png"), tr("Save &Project"), this); actionSaveProject->setShortcut(tr("Ctrl+Shift+S")); connect(actionSaveProject, SIGNAL(triggered()), this, SLOT(saveProject())); - actionSaveFile = new QAction(QIcon(getQPixmap("filesave_nexus_xpm")), - tr("Save Nexus &File"), this); + actionSaveFile = new MantidQt::MantidWidgets::TrackedAction( + QIcon(getQPixmap("filesave_nexus_xpm")), tr("Save Nexus &File"), this); actionSaveFile->setShortcut(tr("Ctrl+S")); connect(actionSaveFile, SIGNAL(triggered()), this, SLOT(savetoNexusFile())); - actionNewGraph = - new QAction(QIcon(getQPixmap("new_graph_xpm")), tr("New &Graph"), this); + actionNewGraph = new MantidQt::MantidWidgets::TrackedAction( + QIcon(getQPixmap("new_graph_xpm")), tr("New &Graph"), this); actionNewGraph->setShortcut(tr("Ctrl+G")); connect(actionNewGraph, SIGNAL(triggered()), this, SLOT(newGraph())); - actionNewNote = - new QAction(QIcon(getQPixmap("new_note_xpm")), tr("New &Note"), this); + actionNewNote = new MantidQt::MantidWidgets::TrackedAction( + QIcon(getQPixmap("new_note_xpm")), tr("New &Note"), this); connect(actionNewNote, SIGNAL(triggered()), this, SLOT(newNote())); - actionNewTable = - new QAction(QIcon(getQPixmap("table_xpm")), tr("New &Table"), this); + actionNewTable = new MantidQt::MantidWidgets::TrackedAction( + QIcon(getQPixmap("table_xpm")), tr("New &Table"), this); actionNewTable->setShortcut(tr("Ctrl+T")); connect(actionNewTable, SIGNAL(triggered()), this, SLOT(newTable())); - actionNewTiledWindow = new QAction(QIcon(getQPixmap("tiledwindow_xpm")), - tr("New Tiled &Window"), this); + actionNewTiledWindow = new MantidQt::MantidWidgets::TrackedAction( + QIcon(getQPixmap("tiledwindow_xpm")), tr("New Tiled &Window"), this); actionNewTiledWindow->setShortcut(tr("Ctrl+Shift+T")); connect(actionNewTiledWindow, SIGNAL(triggered()), this, SLOT(newTiledWindow())); - actionNewMatrix = - new QAction(QIcon(getQPixmap("new_matrix_xpm")), tr("New &Matrix"), this); + actionNewMatrix = new MantidQt::MantidWidgets::TrackedAction( + QIcon(getQPixmap("new_matrix_xpm")), tr("New &Matrix"), this); actionNewMatrix->setShortcut(tr("Ctrl+M")); connect(actionNewMatrix, SIGNAL(triggered()), this, SLOT(newMatrix())); - actionNewFunctionPlot = new QAction(QIcon(getQPixmap("newF_xpm")), - tr("New &Function Plot"), this); + actionNewFunctionPlot = new MantidQt::MantidWidgets::TrackedAction( + QIcon(getQPixmap("newF_xpm")), tr("New &Function Plot"), this); connect(actionNewFunctionPlot, SIGNAL(triggered()), this, SLOT(functionDialog())); - actionNewSurfacePlot = new QAction(QIcon(getQPixmap("newFxy_xpm")), - tr("New 3D &Surface Plot"), this); + actionNewSurfacePlot = new MantidQt::MantidWidgets::TrackedAction( + QIcon(getQPixmap("newFxy_xpm")), tr("New 3D &Surface Plot"), this); actionNewSurfacePlot->setShortcut(tr("Ctrl+ALT+Z")); connect(actionNewSurfacePlot, SIGNAL(triggered()), this, SLOT(newSurfacePlot())); - actionOpenProj = - new QAction(QIcon(":/LoadProject16x16.png"), tr("&Project"), this); + actionOpenProj = new MantidQt::MantidWidgets::TrackedAction( + QIcon(":/LoadProject16x16.png"), tr("&Project"), this); actionOpenProj->setShortcut(tr("Ctrl+Shift+O")); connect(actionOpenProj, SIGNAL(triggered()), this, SLOT(open())); - actionLoadFile = - new QAction(QIcon(":/Open-icon16x16.png"), tr("Data File"), this); + actionLoadFile = new MantidQt::MantidWidgets::TrackedAction( + QIcon(":/Open-icon16x16.png"), tr("Data File"), this); actionLoadFile->setShortcut(tr("Ctrl+Shift+F")); connect(actionLoadFile, SIGNAL(triggered()), this, SLOT(loadDataFile())); - actionLoadImage = new QAction(tr("Open Image &File"), this); + actionLoadImage = + new MantidQt::MantidWidgets::TrackedAction(tr("Open Image &File"), this); actionLoadImage->setShortcut(tr("Ctrl+I")); connect(actionLoadImage, SIGNAL(triggered()), this, SLOT(loadImage())); - actionScriptRepo = new QAction(tr("Script Repositor&y"), this); + actionScriptRepo = new MantidQt::MantidWidgets::TrackedAction( + tr("Script Repositor&y"), this); connect(actionScriptRepo, SIGNAL(triggered()), this, SLOT(loadScriptRepo())); - actionImportImage = new QAction(tr("Import I&mage..."), this); + actionImportImage = + new MantidQt::MantidWidgets::TrackedAction(tr("Import I&mage..."), this); connect(actionImportImage, SIGNAL(triggered()), this, SLOT(importImage())); - actionSaveProjectAs = new QAction(QIcon(":/SaveProject16x16.png"), - tr("Save Project &As..."), this); + actionSaveProjectAs = new MantidQt::MantidWidgets::TrackedAction( + QIcon(":/SaveProject16x16.png"), tr("Save Project &As..."), this); connect(actionSaveProjectAs, SIGNAL(triggered()), this, SLOT(saveProjectAs())); actionSaveProjectAs->setEnabled(false); - actionSaveNote = new QAction(tr("Save Note As..."), this); + actionSaveNote = + new MantidQt::MantidWidgets::TrackedAction(tr("Save Note As..."), this); connect(actionSaveNote, SIGNAL(triggered()), this, SLOT(saveNoteAs())); - actionLoad = new QAction(QIcon(getQPixmap("import_xpm")), - tr("&Import ASCII..."), this); + actionLoad = new MantidQt::MantidWidgets::TrackedAction( + QIcon(getQPixmap("import_xpm")), tr("&Import ASCII..."), this); connect(actionLoad, SIGNAL(triggered()), this, SLOT(importASCII())); - actionCopyWindow = - new QAction(QIcon(getQPixmap("duplicate_xpm")), tr("&Duplicate"), this); + actionCopyWindow = new MantidQt::MantidWidgets::TrackedAction( + QIcon(getQPixmap("duplicate_xpm")), tr("&Duplicate"), this); connect(actionCopyWindow, SIGNAL(triggered()), this, SLOT(clone())); - actionCutSelection = - new QAction(QIcon(getQPixmap("cut_xpm")), tr("Cu&t Selection"), this); + actionCutSelection = new MantidQt::MantidWidgets::TrackedAction( + QIcon(getQPixmap("cut_xpm")), tr("Cu&t Selection"), this); actionCutSelection->setShortcut(tr("Ctrl+X")); connect(actionCutSelection, SIGNAL(triggered()), this, SLOT(cutSelection())); - actionCopySelection = - new QAction(QIcon(getQPixmap("copy_xpm")), tr("&Copy Selection"), this); + actionCopySelection = new MantidQt::MantidWidgets::TrackedAction( + QIcon(getQPixmap("copy_xpm")), tr("&Copy Selection"), this); actionCopySelection->setShortcut(tr("Ctrl+C")); connect(actionCopySelection, SIGNAL(triggered()), this, SLOT(copySelection())); - actionPasteSelection = - new QAction(QIcon(getQPixmap("paste_xpm")), tr("&Paste Selection"), this); + actionPasteSelection = new MantidQt::MantidWidgets::TrackedAction( + QIcon(getQPixmap("paste_xpm")), tr("&Paste Selection"), this); actionPasteSelection->setShortcut(tr("Ctrl+V")); connect(actionPasteSelection, SIGNAL(triggered()), this, SLOT(pasteSelection())); - actionClearSelection = new QAction(QIcon(getQPixmap("erase_xpm")), - tr("&Delete Selection"), this); + actionClearSelection = new MantidQt::MantidWidgets::TrackedAction( + QIcon(getQPixmap("erase_xpm")), tr("&Delete Selection"), this); actionClearSelection->setShortcut(tr("Del", "delete key")); connect(actionClearSelection, SIGNAL(triggered()), this, SLOT(clearSelection())); @@ -11603,8 +11611,8 @@ void ApplicationWindow::createActions() { actionShowLog->setIcon(getQPixmap("log_xpm")); #ifdef SCRIPTING_PYTHON - actionShowScriptWindow = - new QAction(getQPixmap("python_xpm"), tr("Toggle &Script Window"), this); + actionShowScriptWindow = new MantidQt::MantidWidgets::TrackedAction( + getQPixmap("python_xpm"), tr("Toggle &Script Window"), this); #ifdef __APPLE__ actionShowScriptWindow->setShortcut( tr("Ctrl+3")); // F3 is used by the window manager on Mac @@ -11615,7 +11623,7 @@ void ApplicationWindow::createActions() { connect(actionShowScriptWindow, SIGNAL(triggered()), this, SLOT(showScriptWindow())); - actionShowScriptInterpreter = new QAction( + actionShowScriptInterpreter = new MantidQt::MantidWidgets::TrackedAction( getQPixmap("python_xpm"), tr("Toggle Script &Interpreter"), this); #ifdef __APPLE__ actionShowScriptInterpreter->setShortcut( @@ -11628,783 +11636,891 @@ void ApplicationWindow::createActions() { SLOT(showScriptInterpreter())); #endif - actionAddLayer = - new QAction(QIcon(getQPixmap("newLayer_xpm")), tr("Add La&yer"), this); + actionAddLayer = new MantidQt::MantidWidgets::TrackedAction( + QIcon(getQPixmap("newLayer_xpm")), tr("Add La&yer"), this); actionAddLayer->setShortcut(tr("Alt+L")); connect(actionAddLayer, SIGNAL(triggered()), this, SLOT(addLayer())); - actionShowLayerDialog = new QAction(QIcon(getQPixmap("arrangeLayers_xpm")), - tr("Arran&ge Layers"), this); + actionShowLayerDialog = new MantidQt::MantidWidgets::TrackedAction( + QIcon(getQPixmap("arrangeLayers_xpm")), tr("Arran&ge Layers"), this); actionShowLayerDialog->setShortcut(tr("Alt+A")); connect(actionShowLayerDialog, SIGNAL(triggered()), this, SLOT(showLayerDialog())); - actionAutomaticLayout = new QAction(QIcon(getQPixmap("auto_layout_xpm")), - tr("Automatic Layout"), this); + actionAutomaticLayout = new MantidQt::MantidWidgets::TrackedAction( + QIcon(getQPixmap("auto_layout_xpm")), tr("Automatic Layout"), this); connect(actionAutomaticLayout, SIGNAL(triggered()), this, SLOT(autoArrangeLayers())); - actionExportGraph = new QAction(tr("&Current"), this); + actionExportGraph = + new MantidQt::MantidWidgets::TrackedAction(tr("&Current"), this); actionExportGraph->setShortcut(tr("Alt+G")); connect(actionExportGraph, SIGNAL(triggered()), this, SLOT(exportGraph())); - actionExportAllGraphs = new QAction(tr("&All"), this); + actionExportAllGraphs = + new MantidQt::MantidWidgets::TrackedAction(tr("&All"), this); actionExportAllGraphs->setShortcut(tr("Alt+X")); connect(actionExportAllGraphs, SIGNAL(triggered()), this, SLOT(exportAllGraphs())); - actionExportPDF = - new QAction(QIcon(getQPixmap("pdf_xpm")), tr("&Export PDF"), this); + actionExportPDF = new MantidQt::MantidWidgets::TrackedAction( + QIcon(getQPixmap("pdf_xpm")), tr("&Export PDF"), this); actionExportPDF->setShortcut(tr("Ctrl+Alt+P")); connect(actionExportPDF, SIGNAL(triggered()), this, SLOT(exportPDF())); - actionPrint = - new QAction(QIcon(getQPixmap("fileprint_xpm")), tr("&Print"), this); + actionPrint = new MantidQt::MantidWidgets::TrackedAction( + QIcon(getQPixmap("fileprint_xpm")), tr("&Print"), this); actionPrint->setShortcut(tr("Ctrl+P")); connect(actionPrint, SIGNAL(triggered()), this, SLOT(print())); - actionPrintAllPlots = new QAction(tr("Print All Plo&ts"), this); + actionPrintAllPlots = + new MantidQt::MantidWidgets::TrackedAction(tr("Print All Plo&ts"), this); connect(actionPrintAllPlots, SIGNAL(triggered()), this, SLOT(printAllPlots())); - actionShowExportASCIIDialog = new QAction(tr("E&xport ASCII"), this); + actionShowExportASCIIDialog = + new MantidQt::MantidWidgets::TrackedAction(tr("E&xport ASCII"), this); connect(actionShowExportASCIIDialog, SIGNAL(triggered()), this, SLOT(showExportASCIIDialog())); - actionCloseAllWindows = - new QAction(QIcon(getQPixmap("quit_xpm")), tr("&Quit"), this); + actionCloseAllWindows = new MantidQt::MantidWidgets::TrackedAction( + QIcon(getQPixmap("quit_xpm")), tr("&Quit"), this); actionCloseAllWindows->setShortcut(tr("Ctrl+Q")); connect(actionCloseAllWindows, SIGNAL(triggered()), qApp, SLOT(closeAllWindows())); - actionDeleteFitTables = new QAction(QIcon(getQPixmap("close_xpm")), - tr("Delete &Fit Tables"), this); + actionDeleteFitTables = new MantidQt::MantidWidgets::TrackedAction( + QIcon(getQPixmap("close_xpm")), tr("Delete &Fit Tables"), this); connect(actionDeleteFitTables, SIGNAL(triggered()), this, SLOT(deleteFitTables())); - actionShowPlotWizard = - new QAction(QIcon(getQPixmap("wizard_xpm")), tr("Plot &Wizard"), this); + actionShowPlotWizard = new MantidQt::MantidWidgets::TrackedAction( + QIcon(getQPixmap("wizard_xpm")), tr("Plot &Wizard"), this); actionShowPlotWizard->setShortcut(tr("Ctrl+Alt+W")); connect(actionShowPlotWizard, SIGNAL(triggered()), this, SLOT(showPlotWizard())); - actionShowConfigureDialog = - new QAction(QIcon(":/configure.png"), tr("&Preferences..."), this); + actionShowConfigureDialog = new MantidQt::MantidWidgets::TrackedAction( + QIcon(":/configure.png"), tr("&Preferences..."), this); connect(actionShowConfigureDialog, SIGNAL(triggered()), this, SLOT(showPreferencesDialog())); - actionShowCurvesDialog = new QAction(QIcon(getQPixmap("curves_xpm")), - tr("Add/Remove &Curve..."), this); + actionShowCurvesDialog = new MantidQt::MantidWidgets::TrackedAction( + QIcon(getQPixmap("curves_xpm")), tr("Add/Remove &Curve..."), this); actionShowCurvesDialog->setShortcut(tr("Ctrl+Alt+C")); connect(actionShowCurvesDialog, SIGNAL(triggered()), this, SLOT(showCurvesDialog())); - actionAddErrorBars = new QAction(QIcon(getQPixmap("errors_xpm")), - tr("Add &Error Bars..."), this); + actionAddErrorBars = new MantidQt::MantidWidgets::TrackedAction( + QIcon(getQPixmap("errors_xpm")), tr("Add &Error Bars..."), this); actionAddErrorBars->setShortcut(tr("Ctrl+Alt+E")); connect(actionAddErrorBars, SIGNAL(triggered()), this, SLOT(addErrorBars())); - actionRemoveErrorBars = new QAction(QIcon(getQPixmap("errors_remove_xpm")), - tr("&Remove Error Bars..."), this); + actionRemoveErrorBars = new MantidQt::MantidWidgets::TrackedAction( + QIcon(getQPixmap("errors_remove_xpm")), tr("&Remove Error Bars..."), + this); actionRemoveErrorBars->setShortcut(tr("Ctrl+Alt+R")); connect(actionRemoveErrorBars, SIGNAL(triggered()), this, SLOT(removeErrorBars())); - actionAddFunctionCurve = - new QAction(QIcon(getQPixmap("fx_xpm")), tr("Add &Function..."), this); + actionAddFunctionCurve = new MantidQt::MantidWidgets::TrackedAction( + QIcon(getQPixmap("fx_xpm")), tr("Add &Function..."), this); actionAddFunctionCurve->setShortcut(tr("Ctrl+Alt+F")); connect(actionAddFunctionCurve, SIGNAL(triggered()), this, SLOT(addFunctionCurve())); - actionUnzoom = new QAction(QIcon(getQPixmap("unzoom_xpm")), - tr("&Rescale to Show All"), this); + actionUnzoom = new MantidQt::MantidWidgets::TrackedAction( + QIcon(getQPixmap("unzoom_xpm")), tr("&Rescale to Show All"), this); actionUnzoom->setShortcut(tr("Ctrl+Shift+R")); connect(actionUnzoom, SIGNAL(triggered()), this, SLOT(setAutoScale())); - actionNewLegend = - new QAction(QIcon(getQPixmap("legend_xpm")), tr("New &Legend"), this); + actionNewLegend = new MantidQt::MantidWidgets::TrackedAction( + QIcon(getQPixmap("legend_xpm")), tr("New &Legend"), this); actionNewLegend->setShortcut(tr("Ctrl+Alt+L")); connect(actionNewLegend, SIGNAL(triggered()), this, SLOT(newLegend())); - actionTimeStamp = - new QAction(QIcon(getQPixmap("clock_xpm")), tr("Add Time &Stamp"), this); + actionTimeStamp = new MantidQt::MantidWidgets::TrackedAction( + QIcon(getQPixmap("clock_xpm")), tr("Add Time &Stamp"), this); actionTimeStamp->setShortcut(tr("Ctrl+ALT+S")); connect(actionTimeStamp, SIGNAL(triggered()), this, SLOT(addTimeStamp())); - actionAddImage = - new QAction(QIcon(getQPixmap("monalisa_xpm")), tr("Add &Image"), this); + actionAddImage = new MantidQt::MantidWidgets::TrackedAction( + QIcon(getQPixmap("monalisa_xpm")), tr("Add &Image"), this); actionAddImage->setShortcut(tr("Ctrl+Alt+I")); connect(actionAddImage, SIGNAL(triggered()), this, SLOT(addImage())); - actionPlotL = new QAction(QIcon(getQPixmap("lPlot_xpm")), tr("&Line"), this); + actionPlotL = new MantidQt::MantidWidgets::TrackedAction( + QIcon(getQPixmap("lPlot_xpm")), tr("&Line"), this); connect(actionPlotL, SIGNAL(triggered()), this, SLOT(plotL())); - actionPlotP = - new QAction(QIcon(getQPixmap("pPlot_xpm")), tr("&Scatter"), this); + actionPlotP = new MantidQt::MantidWidgets::TrackedAction( + QIcon(getQPixmap("pPlot_xpm")), tr("&Scatter"), this); connect(actionPlotP, SIGNAL(triggered()), this, SLOT(plotP())); - actionPlotLP = - new QAction(QIcon(getQPixmap("lpPlot_xpm")), tr("Line + S&ymbol"), this); + actionPlotLP = new MantidQt::MantidWidgets::TrackedAction( + QIcon(getQPixmap("lpPlot_xpm")), tr("Line + S&ymbol"), this); connect(actionPlotLP, SIGNAL(triggered()), this, SLOT(plotLP())); - actionPlotVerticalDropLines = new QAction(QIcon(getQPixmap("dropLines_xpm")), - tr("Vertical &Drop Lines"), this); + actionPlotVerticalDropLines = new MantidQt::MantidWidgets::TrackedAction( + QIcon(getQPixmap("dropLines_xpm")), tr("Vertical &Drop Lines"), this); connect(actionPlotVerticalDropLines, SIGNAL(triggered()), this, SLOT(plotVerticalDropLines())); - actionPlotSpline = - new QAction(QIcon(getQPixmap("spline_xpm")), tr("&Spline"), this); + actionPlotSpline = new MantidQt::MantidWidgets::TrackedAction( + QIcon(getQPixmap("spline_xpm")), tr("&Spline"), this); connect(actionPlotSpline, SIGNAL(triggered()), this, SLOT(plotSpline())); - actionPlotHorSteps = - new QAction(getQPixmap("hor_steps_xpm"), tr("&Horizontal Steps"), this); + actionPlotHorSteps = new MantidQt::MantidWidgets::TrackedAction( + getQPixmap("hor_steps_xpm"), tr("&Horizontal Steps"), this); connect(actionPlotHorSteps, SIGNAL(triggered()), this, SLOT(plotHorSteps())); - actionPlotVertSteps = new QAction(QIcon(getQPixmap("vert_steps_xpm")), - tr("&Vertical Steps"), this); + actionPlotVertSteps = new MantidQt::MantidWidgets::TrackedAction( + QIcon(getQPixmap("vert_steps_xpm")), tr("&Vertical Steps"), this); connect(actionPlotVertSteps, SIGNAL(triggered()), this, SLOT(plotVertSteps())); - actionPlotVerticalBars = - new QAction(QIcon(getQPixmap("vertBars_xpm")), tr("&Columns"), this); + actionPlotVerticalBars = new MantidQt::MantidWidgets::TrackedAction( + QIcon(getQPixmap("vertBars_xpm")), tr("&Columns"), this); connect(actionPlotVerticalBars, SIGNAL(triggered()), this, SLOT(plotVerticalBars())); - actionPlotHorizontalBars = - new QAction(QIcon(getQPixmap("hBars_xpm")), tr("&Rows"), this); + actionPlotHorizontalBars = new MantidQt::MantidWidgets::TrackedAction( + QIcon(getQPixmap("hBars_xpm")), tr("&Rows"), this); connect(actionPlotHorizontalBars, SIGNAL(triggered()), this, SLOT(plotHorizontalBars())); - actionPlotArea = - new QAction(QIcon(getQPixmap("area_xpm")), tr("&Area"), this); + actionPlotArea = new MantidQt::MantidWidgets::TrackedAction( + QIcon(getQPixmap("area_xpm")), tr("&Area"), this); connect(actionPlotArea, SIGNAL(triggered()), this, SLOT(plotArea())); - actionPlotPie = new QAction(QIcon(getQPixmap("pie_xpm")), tr("&Pie"), this); + actionPlotPie = new MantidQt::MantidWidgets::TrackedAction( + QIcon(getQPixmap("pie_xpm")), tr("&Pie"), this); connect(actionPlotPie, SIGNAL(triggered()), this, SLOT(plotPie())); - actionPlotVectXYAM = - new QAction(QIcon(getQPixmap("vectXYAM_xpm")), tr("Vectors XY&AM"), this); + actionPlotVectXYAM = new MantidQt::MantidWidgets::TrackedAction( + QIcon(getQPixmap("vectXYAM_xpm")), tr("Vectors XY&AM"), this); connect(actionPlotVectXYAM, SIGNAL(triggered()), this, SLOT(plotVectXYAM())); - actionPlotVectXYXY = new QAction(QIcon(getQPixmap("vectXYXY_xpm")), - tr("&Vectors &XYXY"), this); + actionPlotVectXYXY = new MantidQt::MantidWidgets::TrackedAction( + QIcon(getQPixmap("vectXYXY_xpm")), tr("&Vectors &XYXY"), this); connect(actionPlotVectXYXY, SIGNAL(triggered()), this, SLOT(plotVectXYXY())); - actionPlotHistogram = - new QAction(QIcon(getQPixmap("histogram_xpm")), tr("&Histogram"), this); + actionPlotHistogram = new MantidQt::MantidWidgets::TrackedAction( + QIcon(getQPixmap("histogram_xpm")), tr("&Histogram"), this); connect(actionPlotHistogram, SIGNAL(triggered()), this, SLOT(plotHistogram())); - actionPlotStackedHistograms = new QAction( + actionPlotStackedHistograms = new MantidQt::MantidWidgets::TrackedAction( QIcon(getQPixmap("stacked_hist_xpm")), tr("&Stacked Histogram"), this); connect(actionPlotStackedHistograms, SIGNAL(triggered()), this, SLOT(plotStackedHistograms())); - actionStemPlot = - new QAction(QIcon(":/leaf.png"), tr("Stem-and-&Leaf Plot"), this); + actionStemPlot = new MantidQt::MantidWidgets::TrackedAction( + QIcon(":/leaf.png"), tr("Stem-and-&Leaf Plot"), this); connect(actionStemPlot, SIGNAL(triggered()), this, SLOT(newStemPlot())); - actionPlot2VerticalLayers = new QAction(QIcon(getQPixmap("panel_v2_xpm")), - tr("&Vertical 2 Layers"), this); + actionPlot2VerticalLayers = new MantidQt::MantidWidgets::TrackedAction( + QIcon(getQPixmap("panel_v2_xpm")), tr("&Vertical 2 Layers"), this); connect(actionPlot2VerticalLayers, SIGNAL(triggered()), this, SLOT(plot2VerticalLayers())); - actionPlot2HorizontalLayers = new QAction(QIcon(getQPixmap("panel_h2_xpm")), - tr("&Horizontal 2 Layers"), this); + actionPlot2HorizontalLayers = new MantidQt::MantidWidgets::TrackedAction( + QIcon(getQPixmap("panel_h2_xpm")), tr("&Horizontal 2 Layers"), this); connect(actionPlot2HorizontalLayers, SIGNAL(triggered()), this, SLOT(plot2HorizontalLayers())); - actionPlot4Layers = - new QAction(QIcon(getQPixmap("panel_4_xpm")), tr("&4 Layers"), this); + actionPlot4Layers = new MantidQt::MantidWidgets::TrackedAction( + QIcon(getQPixmap("panel_4_xpm")), tr("&4 Layers"), this); connect(actionPlot4Layers, SIGNAL(triggered()), this, SLOT(plot4Layers())); - actionPlotStackedLayers = new QAction(QIcon(getQPixmap("stacked_xpm")), - tr("&Stacked Layers"), this); + actionPlotStackedLayers = new MantidQt::MantidWidgets::TrackedAction( + QIcon(getQPixmap("stacked_xpm")), tr("&Stacked Layers"), this); connect(actionPlotStackedLayers, SIGNAL(triggered()), this, SLOT(plotStackedLayers())); - actionPlot3DRibbon = - new QAction(QIcon(getQPixmap("ribbon_xpm")), tr("&Ribbon"), this); + actionPlot3DRibbon = new MantidQt::MantidWidgets::TrackedAction( + QIcon(getQPixmap("ribbon_xpm")), tr("&Ribbon"), this); connect(actionPlot3DRibbon, SIGNAL(triggered()), this, SLOT(plot3DRibbon())); - actionPlot3DBars = - new QAction(QIcon(getQPixmap("bars_xpm")), tr("&Bars"), this); + actionPlot3DBars = new MantidQt::MantidWidgets::TrackedAction( + QIcon(getQPixmap("bars_xpm")), tr("&Bars"), this); connect(actionPlot3DBars, SIGNAL(triggered()), this, SLOT(plot3DBars())); - actionPlot3DScatter = - new QAction(QIcon(getQPixmap("scatter_xpm")), tr("&Scatter"), this); + actionPlot3DScatter = new MantidQt::MantidWidgets::TrackedAction( + QIcon(getQPixmap("scatter_xpm")), tr("&Scatter"), this); connect(actionPlot3DScatter, SIGNAL(triggered()), this, SLOT(plot3DScatter())); - actionPlot3DTrajectory = - new QAction(QIcon(getQPixmap("trajectory_xpm")), tr("&Trajectory"), this); + actionPlot3DTrajectory = new MantidQt::MantidWidgets::TrackedAction( + QIcon(getQPixmap("trajectory_xpm")), tr("&Trajectory"), this); connect(actionPlot3DTrajectory, SIGNAL(triggered()), this, SLOT(plot3DTrajectory())); - actionShowColStatistics = new QAction(QIcon(getQPixmap("col_stat_xpm")), - tr("Statistics on &Columns"), this); + actionShowColStatistics = new MantidQt::MantidWidgets::TrackedAction( + QIcon(getQPixmap("col_stat_xpm")), tr("Statistics on &Columns"), this); connect(actionShowColStatistics, SIGNAL(triggered()), this, SLOT(showColStatistics())); - actionShowRowStatistics = new QAction(QIcon(getQPixmap("stat_rows_xpm")), - tr("Statistics on &Rows"), this); + actionShowRowStatistics = new MantidQt::MantidWidgets::TrackedAction( + QIcon(getQPixmap("stat_rows_xpm")), tr("Statistics on &Rows"), this); connect(actionShowRowStatistics, SIGNAL(triggered()), this, SLOT(showRowStatistics())); - actionIntegrate = new QAction(tr("&Integrate"), this); + actionIntegrate = + new MantidQt::MantidWidgets::TrackedAction(tr("&Integrate"), this); connect(actionIntegrate, SIGNAL(triggered()), this, SLOT(integrate())); - actionShowIntDialog = new QAction(tr("Integr&ate Function..."), this); + actionShowIntDialog = new MantidQt::MantidWidgets::TrackedAction( + tr("Integr&ate Function..."), this); connect(actionShowIntDialog, SIGNAL(triggered()), this, SLOT(showIntegrationDialog())); - actionInterpolate = new QAction(tr("Inte&rpolate ..."), this); + actionInterpolate = + new MantidQt::MantidWidgets::TrackedAction(tr("Inte&rpolate ..."), this); connect(actionInterpolate, SIGNAL(triggered()), this, SLOT(showInterpolationDialog())); - actionLowPassFilter = new QAction(tr("&Low Pass..."), this); + actionLowPassFilter = + new MantidQt::MantidWidgets::TrackedAction(tr("&Low Pass..."), this); connect(actionLowPassFilter, SIGNAL(triggered()), this, SLOT(lowPassFilterDialog())); - actionHighPassFilter = new QAction(tr("&High Pass..."), this); + actionHighPassFilter = + new MantidQt::MantidWidgets::TrackedAction(tr("&High Pass..."), this); connect(actionHighPassFilter, SIGNAL(triggered()), this, SLOT(highPassFilterDialog())); - actionBandPassFilter = new QAction(tr("&Band Pass..."), this); + actionBandPassFilter = + new MantidQt::MantidWidgets::TrackedAction(tr("&Band Pass..."), this); connect(actionBandPassFilter, SIGNAL(triggered()), this, SLOT(bandPassFilterDialog())); - actionBandBlockFilter = new QAction(tr("&Band Block..."), this); + actionBandBlockFilter = + new MantidQt::MantidWidgets::TrackedAction(tr("&Band Block..."), this); connect(actionBandBlockFilter, SIGNAL(triggered()), this, SLOT(bandBlockFilterDialog())); - actionFFT = new QAction(tr("&FFT..."), this); + actionFFT = new MantidQt::MantidWidgets::TrackedAction(tr("&FFT..."), this); connect(actionFFT, SIGNAL(triggered()), this, SLOT(showFFTDialog())); - actionSmoothSavGol = new QAction(tr("&Savitzky-Golay..."), this); + actionSmoothSavGol = new MantidQt::MantidWidgets::TrackedAction( + tr("&Savitzky-Golay..."), this); connect(actionSmoothSavGol, SIGNAL(triggered()), this, SLOT(showSmoothSavGolDialog())); - actionSmoothFFT = new QAction(tr("&FFT Filter..."), this); + actionSmoothFFT = + new MantidQt::MantidWidgets::TrackedAction(tr("&FFT Filter..."), this); connect(actionSmoothFFT, SIGNAL(triggered()), this, SLOT(showSmoothFFTDialog())); - actionSmoothAverage = new QAction(tr("Moving Window &Average..."), this); + actionSmoothAverage = new MantidQt::MantidWidgets::TrackedAction( + tr("Moving Window &Average..."), this); connect(actionSmoothAverage, SIGNAL(triggered()), this, SLOT(showSmoothAverageDialog())); - actionDifferentiate = new QAction(tr("&Differentiate"), this); + actionDifferentiate = + new MantidQt::MantidWidgets::TrackedAction(tr("&Differentiate"), this); connect(actionDifferentiate, SIGNAL(triggered()), this, SLOT(differentiate())); - actionFitLinear = new QAction(tr("Fit &Linear"), this); + actionFitLinear = + new MantidQt::MantidWidgets::TrackedAction(tr("Fit &Linear"), this); connect(actionFitLinear, SIGNAL(triggered()), this, SLOT(fitLinear())); - actionShowFitPolynomDialog = new QAction(tr("Fit &Polynomial ..."), this); + actionShowFitPolynomDialog = new MantidQt::MantidWidgets::TrackedAction( + tr("Fit &Polynomial ..."), this); connect(actionShowFitPolynomDialog, SIGNAL(triggered()), this, SLOT(showFitPolynomDialog())); - actionShowExpDecayDialog = new QAction(tr("&First Order ..."), this); + actionShowExpDecayDialog = + new MantidQt::MantidWidgets::TrackedAction(tr("&First Order ..."), this); connect(actionShowExpDecayDialog, SIGNAL(triggered()), this, SLOT(showExpDecayDialog())); - actionShowTwoExpDecayDialog = new QAction(tr("&Second Order ..."), this); + actionShowTwoExpDecayDialog = + new MantidQt::MantidWidgets::TrackedAction(tr("&Second Order ..."), this); connect(actionShowTwoExpDecayDialog, SIGNAL(triggered()), this, SLOT(showTwoExpDecayDialog())); - actionShowExpDecay3Dialog = new QAction(tr("&Third Order ..."), this); + actionShowExpDecay3Dialog = + new MantidQt::MantidWidgets::TrackedAction(tr("&Third Order ..."), this); connect(actionShowExpDecay3Dialog, SIGNAL(triggered()), this, SLOT(showExpDecay3Dialog())); - actionFitExpGrowth = new QAction(tr("Fit Exponential Gro&wth ..."), this); + actionFitExpGrowth = new MantidQt::MantidWidgets::TrackedAction( + tr("Fit Exponential Gro&wth ..."), this); connect(actionFitExpGrowth, SIGNAL(triggered()), this, SLOT(showExpGrowthDialog())); - actionFitSigmoidal = new QAction(tr("Fit &Boltzmann (Sigmoidal)"), this); + actionFitSigmoidal = new MantidQt::MantidWidgets::TrackedAction( + tr("Fit &Boltzmann (Sigmoidal)"), this); connect(actionFitSigmoidal, SIGNAL(triggered()), this, SLOT(fitSigmoidal())); - actionFitGauss = new QAction(tr("Fit &Gaussian"), this); + actionFitGauss = + new MantidQt::MantidWidgets::TrackedAction(tr("Fit &Gaussian"), this); connect(actionFitGauss, SIGNAL(triggered()), this, SLOT(fitGauss())); - actionFitLorentz = new QAction(tr("Fit Lorent&zian"), this); + actionFitLorentz = + new MantidQt::MantidWidgets::TrackedAction(tr("Fit Lorent&zian"), this); connect(actionFitLorentz, SIGNAL(triggered()), this, SLOT(fitLorentz())); - actionShowFitDialog = new QAction(tr("Fit &Wizard..."), this); + actionShowFitDialog = + new MantidQt::MantidWidgets::TrackedAction(tr("Fit &Wizard..."), this); actionShowFitDialog->setShortcut(tr("Ctrl+Y")); connect(actionShowFitDialog, SIGNAL(triggered()), this, SLOT(showFitDialog())); - actionShowPlotDialog = new QAction(tr("&Plot ..."), this); + actionShowPlotDialog = + new MantidQt::MantidWidgets::TrackedAction(tr("&Plot ..."), this); connect(actionShowPlotDialog, SIGNAL(triggered()), this, SLOT(showGeneralPlotDialog())); - actionShowScaleDialog = new QAction(tr("&Scales..."), this); + actionShowScaleDialog = + new MantidQt::MantidWidgets::TrackedAction(tr("&Scales..."), this); connect(actionShowScaleDialog, SIGNAL(triggered()), this, SLOT(showScaleDialog())); - actionShowAxisDialog = new QAction(tr("&Axes..."), this); + actionShowAxisDialog = + new MantidQt::MantidWidgets::TrackedAction(tr("&Axes..."), this); connect(actionShowAxisDialog, SIGNAL(triggered()), this, SLOT(showAxisDialog())); - actionShowGridDialog = new QAction(tr("&Grid ..."), this); + actionShowGridDialog = + new MantidQt::MantidWidgets::TrackedAction(tr("&Grid ..."), this); connect(actionShowGridDialog, SIGNAL(triggered()), this, SLOT(showGridDialog())); - actionShowTitleDialog = new QAction(tr("&Title ..."), this); + actionShowTitleDialog = + new MantidQt::MantidWidgets::TrackedAction(tr("&Title ..."), this); connect(actionShowTitleDialog, SIGNAL(triggered()), this, SLOT(showTitleDialog())); - actionShowColumnOptionsDialog = new QAction(tr("Column &Options ..."), this); + actionShowColumnOptionsDialog = new MantidQt::MantidWidgets::TrackedAction( + tr("Column &Options ..."), this); actionShowColumnOptionsDialog->setShortcut(tr("Ctrl+Alt+O")); connect(actionShowColumnOptionsDialog, SIGNAL(triggered()), this, SLOT(showColumnOptionsDialog())); - actionShowColumnValuesDialog = new QAction( + actionShowColumnValuesDialog = new MantidQt::MantidWidgets::TrackedAction( QIcon(getQPixmap("formula_xpm")), tr("Set Column &Values ..."), this); connect(actionShowColumnValuesDialog, SIGNAL(triggered()), this, SLOT(showColumnValuesDialog())); actionShowColumnValuesDialog->setShortcut(tr("Alt+Q")); - actionTableRecalculate = new QAction(tr("Recalculate"), this); + actionTableRecalculate = + new MantidQt::MantidWidgets::TrackedAction(tr("Recalculate"), this); actionTableRecalculate->setShortcut(tr("Ctrl+Return")); connect(actionTableRecalculate, SIGNAL(triggered()), this, SLOT(recalculateTable())); - actionHideSelectedColumns = new QAction(tr("&Hide Selected"), this); + actionHideSelectedColumns = + new MantidQt::MantidWidgets::TrackedAction(tr("&Hide Selected"), this); connect(actionHideSelectedColumns, SIGNAL(triggered()), this, SLOT(hideSelectedColumns())); - actionShowAllColumns = new QAction(tr("Sho&w All Columns"), this); + actionShowAllColumns = + new MantidQt::MantidWidgets::TrackedAction(tr("Sho&w All Columns"), this); connect(actionShowAllColumns, SIGNAL(triggered()), this, SLOT(showAllColumns())); - actionSwapColumns = new QAction(QIcon(getQPixmap("swap_columns_xpm")), - tr("&Swap columns"), this); + actionSwapColumns = new MantidQt::MantidWidgets::TrackedAction( + QIcon(getQPixmap("swap_columns_xpm")), tr("&Swap columns"), this); connect(actionSwapColumns, SIGNAL(triggered()), this, SLOT(swapColumns())); - actionMoveColRight = new QAction(QIcon(getQPixmap("move_col_right_xpm")), - tr("Move &Right"), this); + actionMoveColRight = new MantidQt::MantidWidgets::TrackedAction( + QIcon(getQPixmap("move_col_right_xpm")), tr("Move &Right"), this); connect(actionMoveColRight, SIGNAL(triggered()), this, SLOT(moveColumnRight())); - actionMoveColLeft = new QAction(QIcon(getQPixmap("move_col_left_xpm")), - tr("Move &Left"), this); + actionMoveColLeft = new MantidQt::MantidWidgets::TrackedAction( + QIcon(getQPixmap("move_col_left_xpm")), tr("Move &Left"), this); connect(actionMoveColLeft, SIGNAL(triggered()), this, SLOT(moveColumnLeft())); - actionMoveColFirst = new QAction(QIcon(getQPixmap("move_col_first_xpm")), - tr("Move to F&irst"), this); + actionMoveColFirst = new MantidQt::MantidWidgets::TrackedAction( + QIcon(getQPixmap("move_col_first_xpm")), tr("Move to F&irst"), this); connect(actionMoveColFirst, SIGNAL(triggered()), this, SLOT(moveColumnFirst())); - actionMoveColLast = new QAction(QIcon(getQPixmap("move_col_last_xpm")), - tr("Move to Las&t"), this); + actionMoveColLast = new MantidQt::MantidWidgets::TrackedAction( + QIcon(getQPixmap("move_col_last_xpm")), tr("Move to Las&t"), this); connect(actionMoveColLast, SIGNAL(triggered()), this, SLOT(moveColumnLast())); - actionShowColsDialog = new QAction(tr("&Columns..."), this); + actionShowColsDialog = + new MantidQt::MantidWidgets::TrackedAction(tr("&Columns..."), this); connect(actionShowColsDialog, SIGNAL(triggered()), this, SLOT(showColsDialog())); - actionShowRowsDialog = new QAction(tr("&Rows..."), this); + actionShowRowsDialog = + new MantidQt::MantidWidgets::TrackedAction(tr("&Rows..."), this); connect(actionShowRowsDialog, SIGNAL(triggered()), this, SLOT(showRowsDialog())); - actionDeleteRows = new QAction(tr("&Delete Rows Interval..."), this); + actionDeleteRows = new MantidQt::MantidWidgets::TrackedAction( + tr("&Delete Rows Interval..."), this); connect(actionDeleteRows, SIGNAL(triggered()), this, SLOT(showDeleteRowsDialog())); - actionAbout = new QAction(tr("&About MantidPlot"), this); // Mantid + actionAbout = new MantidQt::MantidWidgets::TrackedAction( + tr("&About MantidPlot"), this); // Mantid actionAbout->setShortcut(tr("F1")); connect(actionAbout, SIGNAL(triggered()), this, SLOT(about())); - actionShowHelp = new QAction(tr("&Help"), this); + actionShowHelp = + new MantidQt::MantidWidgets::TrackedAction(tr("&Help"), this); actionShowHelp->setShortcut(tr("Ctrl+H")); connect(actionShowHelp, SIGNAL(triggered()), this, SLOT(showHelp())); - actionMantidConcepts = new QAction(tr("&Mantid Concepts"), this); + actionMantidConcepts = + new MantidQt::MantidWidgets::TrackedAction(tr("&Mantid Concepts"), this); connect(actionMantidConcepts, SIGNAL(triggered()), this, SLOT(showMantidConcepts())); - actionMantidAlgorithms = new QAction(tr("&Algorithm Descriptions"), this); + actionMantidAlgorithms = new MantidQt::MantidWidgets::TrackedAction( + tr("&Algorithm Descriptions"), this); connect(actionMantidAlgorithms, SIGNAL(triggered()), this, SLOT(showalgorithmDescriptions())); - actionmantidplotHelp = new QAction(tr("&MantidPlot Help"), this); + actionmantidplotHelp = + new MantidQt::MantidWidgets::TrackedAction(tr("&MantidPlot Help"), this); connect(actionmantidplotHelp, SIGNAL(triggered()), this, SLOT(showmantidplotHelp())); - actionChooseHelpFolder = new QAction(tr("&Choose Help Folder..."), this); + actionChooseHelpFolder = new MantidQt::MantidWidgets::TrackedAction( + tr("&Choose Help Folder..."), this); connect(actionChooseHelpFolder, SIGNAL(triggered()), this, SLOT(chooseHelpFolder())); - actionRename = new QAction(tr("&Rename Window"), this); + actionRename = + new MantidQt::MantidWidgets::TrackedAction(tr("&Rename Window"), this); connect(actionRename, SIGNAL(triggered()), this, SLOT(rename())); - actionCloseWindow = - new QAction(QIcon(getQPixmap("close_xpm")), tr("Close &Window"), this); + actionCloseWindow = new MantidQt::MantidWidgets::TrackedAction( + QIcon(getQPixmap("close_xpm")), tr("Close &Window"), this); actionCloseWindow->setShortcut(tr("Ctrl+W")); connect(actionCloseWindow, SIGNAL(triggered()), this, SLOT(closeActiveWindow())); - actionAddColToTable = - new QAction(QIcon(getQPixmap("addCol_xpm")), tr("Add Column"), this); + actionAddColToTable = new MantidQt::MantidWidgets::TrackedAction( + QIcon(getQPixmap("addCol_xpm")), tr("Add Column"), this); connect(actionAddColToTable, SIGNAL(triggered()), this, SLOT(addColToTable())); - actionGoToRow = new QAction(tr("&Go to Row..."), this); + actionGoToRow = + new MantidQt::MantidWidgets::TrackedAction(tr("&Go to Row..."), this); actionGoToRow->setShortcut(tr("Ctrl+Alt+G")); connect(actionGoToRow, SIGNAL(triggered()), this, SLOT(goToRow())); - actionGoToColumn = new QAction(tr("Go to Colum&n..."), this); + actionGoToColumn = + new MantidQt::MantidWidgets::TrackedAction(tr("Go to Colum&n..."), this); actionGoToColumn->setShortcut(tr("Ctrl+Alt+C")); connect(actionGoToColumn, SIGNAL(triggered()), this, SLOT(goToColumn())); - actionClearTable = new QAction(getQPixmap("erase_xpm"), tr("Clear"), this); + actionClearTable = new MantidQt::MantidWidgets::TrackedAction( + getQPixmap("erase_xpm"), tr("Clear"), this); connect(actionClearTable, SIGNAL(triggered()), this, SLOT(clearTable())); - actionDeleteLayer = - new QAction(QIcon(getQPixmap("erase_xpm")), tr("&Remove Layer"), this); + actionDeleteLayer = new MantidQt::MantidWidgets::TrackedAction( + QIcon(getQPixmap("erase_xpm")), tr("&Remove Layer"), this); actionDeleteLayer->setShortcut(tr("Alt+R")); connect(actionDeleteLayer, SIGNAL(triggered()), this, SLOT(deleteLayer())); - actionResizeActiveWindow = new QAction(QIcon(getQPixmap("resize_xpm")), - tr("Window &Geometry..."), this); + actionResizeActiveWindow = new MantidQt::MantidWidgets::TrackedAction( + QIcon(getQPixmap("resize_xpm")), tr("Window &Geometry..."), this); connect(actionResizeActiveWindow, SIGNAL(triggered()), this, SLOT(resizeActiveWindow())); - actionHideActiveWindow = new QAction(tr("&Hide Window"), this); + actionHideActiveWindow = + new MantidQt::MantidWidgets::TrackedAction(tr("&Hide Window"), this); connect(actionHideActiveWindow, SIGNAL(triggered()), this, SLOT(hideActiveWindow())); - actionShowMoreWindows = new QAction(tr("More windows..."), this); + actionShowMoreWindows = + new MantidQt::MantidWidgets::TrackedAction(tr("More windows..."), this); connect(actionShowMoreWindows, SIGNAL(triggered()), this, SLOT(showMoreWindows())); - actionPixelLineProfile = new QAction(QIcon(getQPixmap("pixelProfile_xpm")), - tr("&View Pixel Line Profile"), this); + actionPixelLineProfile = new MantidQt::MantidWidgets::TrackedAction( + QIcon(getQPixmap("pixelProfile_xpm")), tr("&View Pixel Line Profile"), + this); connect(actionPixelLineProfile, SIGNAL(triggered()), this, SLOT(pixelLineProfile())); - actionIntensityTable = new QAction(tr("&Intensity Table"), this); + actionIntensityTable = + new MantidQt::MantidWidgets::TrackedAction(tr("&Intensity Table"), this); connect(actionIntensityTable, SIGNAL(triggered()), this, SLOT(intensityTable())); - actionShowLineDialog = new QAction(tr("&Properties"), this); + actionShowLineDialog = + new MantidQt::MantidWidgets::TrackedAction(tr("&Properties"), this); connect(actionShowLineDialog, SIGNAL(triggered()), this, SLOT(showLineDialog())); - actionShowImageDialog = new QAction(tr("&Properties"), this); + actionShowImageDialog = + new MantidQt::MantidWidgets::TrackedAction(tr("&Properties"), this); connect(actionShowImageDialog, SIGNAL(triggered()), this, SLOT(showImageDialog())); - actionShowTextDialog = new QAction(tr("&Properties"), this); + actionShowTextDialog = + new MantidQt::MantidWidgets::TrackedAction(tr("&Properties"), this); connect(actionShowTextDialog, SIGNAL(triggered()), this, SLOT(showTextDialog())); - actionActivateWindow = new QAction(tr("&Activate Window"), this); + actionActivateWindow = + new MantidQt::MantidWidgets::TrackedAction(tr("&Activate Window"), this); connect(actionActivateWindow, SIGNAL(triggered()), this, SLOT(activateWindow())); - actionMinimizeWindow = new QAction(tr("Mi&nimize Window"), this); + actionMinimizeWindow = + new MantidQt::MantidWidgets::TrackedAction(tr("Mi&nimize Window"), this); connect(actionMinimizeWindow, SIGNAL(triggered()), this, SLOT(minimizeWindow())); - actionMaximizeWindow = new QAction(tr("Ma&ximize Window"), this); + actionMaximizeWindow = + new MantidQt::MantidWidgets::TrackedAction(tr("Ma&ximize Window"), this); connect(actionMaximizeWindow, SIGNAL(triggered()), this, SLOT(maximizeWindow())); - actionHideWindow = new QAction(tr("&Hide Window"), this); + actionHideWindow = + new MantidQt::MantidWidgets::TrackedAction(tr("&Hide Window"), this); connect(actionHideWindow, SIGNAL(triggered()), this, SLOT(hideWindow())); - actionResizeWindow = new QAction(QIcon(getQPixmap("resize_xpm")), - tr("Re&size Window..."), this); + actionResizeWindow = new MantidQt::MantidWidgets::TrackedAction( + QIcon(getQPixmap("resize_xpm")), tr("Re&size Window..."), this); connect(actionResizeWindow, SIGNAL(triggered()), this, SLOT(resizeWindow())); - actionEditSurfacePlot = new QAction(tr("&Surface..."), this); + actionEditSurfacePlot = + new MantidQt::MantidWidgets::TrackedAction(tr("&Surface..."), this); connect(actionEditSurfacePlot, SIGNAL(triggered()), this, SLOT(editSurfacePlot())); - actionAdd3DData = new QAction(tr("&Data Set..."), this); + actionAdd3DData = + new MantidQt::MantidWidgets::TrackedAction(tr("&Data Set..."), this); connect(actionAdd3DData, SIGNAL(triggered()), this, SLOT(add3DData())); - actionSetMatrixProperties = new QAction(tr("Set &Properties..."), this); + actionSetMatrixProperties = new MantidQt::MantidWidgets::TrackedAction( + tr("Set &Properties..."), this); connect(actionSetMatrixProperties, SIGNAL(triggered()), this, SLOT(showMatrixDialog())); - actionSetMatrixDimensions = new QAction(tr("Set &Dimensions..."), this); + actionSetMatrixDimensions = new MantidQt::MantidWidgets::TrackedAction( + tr("Set &Dimensions..."), this); connect(actionSetMatrixDimensions, SIGNAL(triggered()), this, SLOT(showMatrixSizeDialog())); actionSetMatrixDimensions->setShortcut(tr("Ctrl+D")); - actionSetMatrixValues = - new QAction(QIcon(getQPixmap("formula_xpm")), tr("Set &Values..."), this); + actionSetMatrixValues = new MantidQt::MantidWidgets::TrackedAction( + QIcon(getQPixmap("formula_xpm")), tr("Set &Values..."), this); connect(actionSetMatrixValues, SIGNAL(triggered()), this, SLOT(showMatrixValuesDialog())); actionSetMatrixValues->setShortcut(tr("Alt+Q")); - actionImagePlot = - new QAction(QIcon(getQPixmap("image_plot_xpm")), tr("&Image Plot"), this); + actionImagePlot = new MantidQt::MantidWidgets::TrackedAction( + QIcon(getQPixmap("image_plot_xpm")), tr("&Image Plot"), this); connect(actionImagePlot, SIGNAL(triggered()), this, SLOT(plotImage())); - actionTransposeMatrix = new QAction(tr("&Transpose"), this); + actionTransposeMatrix = + new MantidQt::MantidWidgets::TrackedAction(tr("&Transpose"), this); connect(actionTransposeMatrix, SIGNAL(triggered()), this, SLOT(transposeMatrix())); - actionFlipMatrixVertically = - new QAction(QIcon(getQPixmap("flip_vertical_xpm")), tr("Flip &V"), this); + actionFlipMatrixVertically = new MantidQt::MantidWidgets::TrackedAction( + QIcon(getQPixmap("flip_vertical_xpm")), tr("Flip &V"), this); actionFlipMatrixVertically->setShortcut(tr("Ctrl+Shift+V")); connect(actionFlipMatrixVertically, SIGNAL(triggered()), this, SLOT(flipMatrixVertically())); - actionFlipMatrixHorizontally = new QAction( + actionFlipMatrixHorizontally = new MantidQt::MantidWidgets::TrackedAction( QIcon(getQPixmap("flip_horizontal_xpm")), tr("Flip &H"), this); actionFlipMatrixHorizontally->setShortcut(tr("Ctrl+Shift+H")); connect(actionFlipMatrixHorizontally, SIGNAL(triggered()), this, SLOT(flipMatrixHorizontally())); - actionRotateMatrix = new QAction(QIcon(getQPixmap("rotate_clockwise_xpm")), - tr("R&otate 90"), this); + actionRotateMatrix = new MantidQt::MantidWidgets::TrackedAction( + QIcon(getQPixmap("rotate_clockwise_xpm")), tr("R&otate 90"), this); actionRotateMatrix->setShortcut(tr("Ctrl+Shift+R")); connect(actionRotateMatrix, SIGNAL(triggered()), this, SLOT(rotateMatrix90())); - actionRotateMatrixMinus = - new QAction(QIcon(getQPixmap("rotate_counterclockwise_xpm")), - tr("Rotate &-90"), this); + actionRotateMatrixMinus = new MantidQt::MantidWidgets::TrackedAction( + QIcon(getQPixmap("rotate_counterclockwise_xpm")), tr("Rotate &-90"), + this); actionRotateMatrixMinus->setShortcut(tr("Ctrl+Alt+R")); connect(actionRotateMatrixMinus, SIGNAL(triggered()), this, SLOT(rotateMatrixMinus90())); - actionInvertMatrix = new QAction(tr("&Invert"), this); + actionInvertMatrix = + new MantidQt::MantidWidgets::TrackedAction(tr("&Invert"), this); connect(actionInvertMatrix, SIGNAL(triggered()), this, SLOT(invertMatrix())); - actionMatrixDeterminant = new QAction(tr("&Determinant"), this); + actionMatrixDeterminant = + new MantidQt::MantidWidgets::TrackedAction(tr("&Determinant"), this); connect(actionMatrixDeterminant, SIGNAL(triggered()), this, SLOT(matrixDeterminant())); - actionViewMatrixImage = new QAction(tr("&Image mode"), this); + actionViewMatrixImage = + new MantidQt::MantidWidgets::TrackedAction(tr("&Image mode"), this); actionViewMatrixImage->setShortcut(tr("Ctrl+Shift+I")); connect(actionViewMatrixImage, SIGNAL(triggered()), this, SLOT(viewMatrixImage())); actionViewMatrixImage->setCheckable(true); - actionViewMatrix = new QAction(tr("&Data mode"), this); + actionViewMatrix = + new MantidQt::MantidWidgets::TrackedAction(tr("&Data mode"), this); actionViewMatrix->setShortcut(tr("Ctrl+Shift+D")); connect(actionViewMatrix, SIGNAL(triggered()), this, SLOT(viewMatrixTable())); actionViewMatrix->setCheckable(true); - actionMatrixXY = new QAction(tr("Show &X/Y"), this); + actionMatrixXY = + new MantidQt::MantidWidgets::TrackedAction(tr("Show &X/Y"), this); actionMatrixXY->setShortcut(tr("Ctrl+Shift+X")); connect(actionMatrixXY, SIGNAL(triggered()), this, SLOT(viewMatrixXY())); actionMatrixXY->setCheckable(true); - actionMatrixColumnRow = new QAction(tr("Show &Column/Row"), this); + actionMatrixColumnRow = + new MantidQt::MantidWidgets::TrackedAction(tr("Show &Column/Row"), this); actionMatrixColumnRow->setShortcut(tr("Ctrl+Shift+C")); connect(actionMatrixColumnRow, SIGNAL(triggered()), this, SLOT(viewMatrixColumnRow())); actionMatrixColumnRow->setCheckable(true); - actionMatrixGrayScale = new QAction(tr("&Gray Scale"), this); + actionMatrixGrayScale = + new MantidQt::MantidWidgets::TrackedAction(tr("&Gray Scale"), this); connect(actionMatrixGrayScale, SIGNAL(triggered()), this, SLOT(setMatrixGrayScale())); actionMatrixGrayScale->setCheckable(true); - actionMatrixRainbowScale = new QAction(tr("&Rainbow"), this); + actionMatrixRainbowScale = + new MantidQt::MantidWidgets::TrackedAction(tr("&Rainbow"), this); connect(actionMatrixRainbowScale, SIGNAL(triggered()), this, SLOT(setMatrixRainbowScale())); actionMatrixRainbowScale->setCheckable(true); - actionMatrixCustomScale = new QAction(tr("&Custom"), this); + actionMatrixCustomScale = + new MantidQt::MantidWidgets::TrackedAction(tr("&Custom"), this); connect(actionMatrixCustomScale, SIGNAL(triggered()), this, SLOT(showColorMapDialog())); actionMatrixCustomScale->setCheckable(true); - actionExportMatrix = new QAction(tr("&Export Image ..."), this); + actionExportMatrix = + new MantidQt::MantidWidgets::TrackedAction(tr("&Export Image ..."), this); connect(actionExportMatrix, SIGNAL(triggered()), this, SLOT(exportMatrix())); - actionConvertMatrixDirect = new QAction(tr("&Direct"), this); + actionConvertMatrixDirect = + new MantidQt::MantidWidgets::TrackedAction(tr("&Direct"), this); connect(actionConvertMatrixDirect, SIGNAL(triggered()), this, SLOT(convertMatrixToTableDirect())); - actionConvertMatrixXYZ = new QAction(tr("&XYZ Columns"), this); + actionConvertMatrixXYZ = + new MantidQt::MantidWidgets::TrackedAction(tr("&XYZ Columns"), this); connect(actionConvertMatrixXYZ, SIGNAL(triggered()), this, SLOT(convertMatrixToTableXYZ())); - actionConvertMatrixYXZ = new QAction(tr("&YXZ Columns"), this); + actionConvertMatrixYXZ = + new MantidQt::MantidWidgets::TrackedAction(tr("&YXZ Columns"), this); connect(actionConvertMatrixYXZ, SIGNAL(triggered()), this, SLOT(convertMatrixToTableYXZ())); - actionMatrixFFTDirect = new QAction(tr("&Forward FFT"), this); + actionMatrixFFTDirect = + new MantidQt::MantidWidgets::TrackedAction(tr("&Forward FFT"), this); connect(actionMatrixFFTDirect, SIGNAL(triggered()), this, SLOT(matrixDirectFFT())); - actionMatrixFFTInverse = new QAction(tr("&Inverse FFT"), this); + actionMatrixFFTInverse = + new MantidQt::MantidWidgets::TrackedAction(tr("&Inverse FFT"), this); connect(actionMatrixFFTInverse, SIGNAL(triggered()), this, SLOT(matrixInverseFFT())); - actionConvertTable = new QAction(tr("Convert to &Matrix"), this); + actionConvertTable = new MantidQt::MantidWidgets::TrackedAction( + tr("Convert to &Matrix"), this); connect(actionConvertTable, SIGNAL(triggered()), this, SLOT(convertTableToMatrix())); - actionConvertTableToWorkspace = - new QAction(tr("Convert to Table&Workspace"), this); + actionConvertTableToWorkspace = new MantidQt::MantidWidgets::TrackedAction( + tr("Convert to Table&Workspace"), this); connect(actionConvertTableToWorkspace, SIGNAL(triggered()), this, SLOT(convertTableToWorkspace())); actionConvertTableToMatrixWorkspace = - new QAction(tr("Convert to MatrixWorkspace"), this); + new MantidQt::MantidWidgets::TrackedAction( + tr("Convert to MatrixWorkspace"), this); connect(actionConvertTableToMatrixWorkspace, SIGNAL(triggered()), this, SLOT(convertTableToMatrixWorkspace())); - actionPlot3DWireFrame = new QAction(QIcon(getQPixmap("lineMesh_xpm")), - tr("3D &Wire Frame"), this); + actionPlot3DWireFrame = new MantidQt::MantidWidgets::TrackedAction( + QIcon(getQPixmap("lineMesh_xpm")), tr("3D &Wire Frame"), this); connect(actionPlot3DWireFrame, SIGNAL(triggered()), this, SLOT(plot3DWireframe())); - actionPlot3DHiddenLine = new QAction(QIcon(getQPixmap("grid_only_xpm")), - tr("3D &Hidden Line"), this); + actionPlot3DHiddenLine = new MantidQt::MantidWidgets::TrackedAction( + QIcon(getQPixmap("grid_only_xpm")), tr("3D &Hidden Line"), this); connect(actionPlot3DHiddenLine, SIGNAL(triggered()), this, SLOT(plot3DHiddenLine())); - actionPlot3DPolygons = - new QAction(QIcon(getQPixmap("no_grid_xpm")), tr("3D &Polygons"), this); + actionPlot3DPolygons = new MantidQt::MantidWidgets::TrackedAction( + QIcon(getQPixmap("no_grid_xpm")), tr("3D &Polygons"), this); connect(actionPlot3DPolygons, SIGNAL(triggered()), this, SLOT(plot3DPolygons())); - actionPlot3DWireSurface = new QAction(QIcon(getQPixmap("grid_poly_xpm")), - tr("3D Wire &Surface"), this); + actionPlot3DWireSurface = new MantidQt::MantidWidgets::TrackedAction( + QIcon(getQPixmap("grid_poly_xpm")), tr("3D Wire &Surface"), this); connect(actionPlot3DWireSurface, SIGNAL(triggered()), this, SLOT(plot3DWireSurface())); - actionColorMap = new QAction(QIcon(getQPixmap("color_map_xpm")), - tr("Contour - &Color Fill"), this); + actionColorMap = new MantidQt::MantidWidgets::TrackedAction( + QIcon(getQPixmap("color_map_xpm")), tr("Contour - &Color Fill"), this); connect(actionColorMap, SIGNAL(triggered()), this, SLOT(plotColorMap())); - actionContourMap = new QAction(QIcon(getQPixmap("contour_map_xpm")), - tr("Contour &Lines"), this); + actionContourMap = new MantidQt::MantidWidgets::TrackedAction( + QIcon(getQPixmap("contour_map_xpm")), tr("Contour &Lines"), this); connect(actionContourMap, SIGNAL(triggered()), this, SLOT(plotContour())); - actionGrayMap = new QAction(QIcon(getQPixmap("gray_map_xpm")), - tr("&Gray Scale Map"), this); + actionGrayMap = new MantidQt::MantidWidgets::TrackedAction( + QIcon(getQPixmap("gray_map_xpm")), tr("&Gray Scale Map"), this); connect(actionGrayMap, SIGNAL(triggered()), this, SLOT(plotGrayScale())); - actionNoContourColorMap = - new QAction(QIcon(getQPixmap("color_map_xpm")), tr("Color &Fill"), this); + actionNoContourColorMap = new MantidQt::MantidWidgets::TrackedAction( + QIcon(getQPixmap("color_map_xpm")), tr("Color &Fill"), this); connect(actionNoContourColorMap, SIGNAL(triggered()), this, SLOT(plotNoContourColorMap())); - actionSortTable = new QAction(tr("Sort Ta&ble"), this); + actionSortTable = + new MantidQt::MantidWidgets::TrackedAction(tr("Sort Ta&ble"), this); connect(actionSortTable, SIGNAL(triggered()), this, SLOT(sortActiveTable())); - actionSortSelection = new QAction(tr("Sort Columns"), this); + actionSortSelection = + new MantidQt::MantidWidgets::TrackedAction(tr("Sort Columns"), this); connect(actionSortSelection, SIGNAL(triggered()), this, SLOT(sortSelection())); - actionNormalizeTable = new QAction(tr("&Table"), this); + actionNormalizeTable = + new MantidQt::MantidWidgets::TrackedAction(tr("&Table"), this); connect(actionNormalizeTable, SIGNAL(triggered()), this, SLOT(normalizeActiveTable())); - actionNormalizeSelection = new QAction(tr("&Columns"), this); + actionNormalizeSelection = + new MantidQt::MantidWidgets::TrackedAction(tr("&Columns"), this); connect(actionNormalizeSelection, SIGNAL(triggered()), this, SLOT(normalizeSelection())); - actionCorrelate = new QAction(tr("Co&rrelate"), this); + actionCorrelate = + new MantidQt::MantidWidgets::TrackedAction(tr("Co&rrelate"), this); connect(actionCorrelate, SIGNAL(triggered()), this, SLOT(correlate())); - actionAutoCorrelate = new QAction(tr("&Autocorrelate"), this); + actionAutoCorrelate = + new MantidQt::MantidWidgets::TrackedAction(tr("&Autocorrelate"), this); connect(actionAutoCorrelate, SIGNAL(triggered()), this, SLOT(autoCorrelate())); - actionConvolute = new QAction(tr("&Convolute"), this); + actionConvolute = + new MantidQt::MantidWidgets::TrackedAction(tr("&Convolute"), this); connect(actionConvolute, SIGNAL(triggered()), this, SLOT(convolute())); - actionDeconvolute = new QAction(tr("&Deconvolute"), this); + actionDeconvolute = + new MantidQt::MantidWidgets::TrackedAction(tr("&Deconvolute"), this); connect(actionDeconvolute, SIGNAL(triggered()), this, SLOT(deconvolute())); - actionSetAscValues = new QAction(QIcon(getQPixmap("rowNumbers_xpm")), - tr("Ro&w Numbers"), this); + actionSetAscValues = new MantidQt::MantidWidgets::TrackedAction( + QIcon(getQPixmap("rowNumbers_xpm")), tr("Ro&w Numbers"), this); connect(actionSetAscValues, SIGNAL(triggered()), this, SLOT(setAscValues())); - actionSetRandomValues = new QAction(QIcon(getQPixmap("randomNumbers_xpm")), - tr("&Random Values"), this); + actionSetRandomValues = new MantidQt::MantidWidgets::TrackedAction( + QIcon(getQPixmap("randomNumbers_xpm")), tr("&Random Values"), this); connect(actionSetRandomValues, SIGNAL(triggered()), this, SLOT(setRandomValues())); - actionReadOnlyCol = new QAction(tr("&Read Only"), this); + actionReadOnlyCol = + new MantidQt::MantidWidgets::TrackedAction(tr("&Read Only"), this); connect(actionReadOnlyCol, SIGNAL(triggered()), this, SLOT(setReadOnlyCol())); - actionSetXCol = new QAction(QIcon(getQPixmap("x_col_xpm")), tr("&X"), this); + actionSetXCol = new MantidQt::MantidWidgets::TrackedAction( + QIcon(getQPixmap("x_col_xpm")), tr("&X"), this); connect(actionSetXCol, SIGNAL(triggered()), this, SLOT(setXCol())); - actionSetYCol = new QAction(QIcon(getQPixmap("y_col_xpm")), tr("&Y"), this); + actionSetYCol = new MantidQt::MantidWidgets::TrackedAction( + QIcon(getQPixmap("y_col_xpm")), tr("&Y"), this); connect(actionSetYCol, SIGNAL(triggered()), this, SLOT(setYCol())); - actionSetZCol = new QAction(QIcon(getQPixmap("z_col_xpm")), tr("&Z"), this); + actionSetZCol = new MantidQt::MantidWidgets::TrackedAction( + QIcon(getQPixmap("z_col_xpm")), tr("&Z"), this); connect(actionSetZCol, SIGNAL(triggered()), this, SLOT(setZCol())); - actionSetXErrCol = new QAction(tr("X E&rror"), this); + actionSetXErrCol = + new MantidQt::MantidWidgets::TrackedAction(tr("X E&rror"), this); connect(actionSetXErrCol, SIGNAL(triggered()), this, SLOT(setXErrCol())); - actionSetYErrCol = - new QAction(QIcon(getQPixmap("errors_xpm")), tr("Y &Error"), this); + actionSetYErrCol = new MantidQt::MantidWidgets::TrackedAction( + QIcon(getQPixmap("errors_xpm")), tr("Y &Error"), this); connect(actionSetYErrCol, SIGNAL(triggered()), this, SLOT(setYErrCol())); - actionDisregardCol = new QAction(QIcon(getQPixmap("disregard_col_xpm")), - tr("&Disregard"), this); + actionDisregardCol = new MantidQt::MantidWidgets::TrackedAction( + QIcon(getQPixmap("disregard_col_xpm")), tr("&Disregard"), this); connect(actionDisregardCol, SIGNAL(triggered()), this, SLOT(disregardCol())); - actionSetLabelCol = - new QAction(QIcon(getQPixmap("set_label_col_xpm")), tr("&Label"), this); + actionSetLabelCol = new MantidQt::MantidWidgets::TrackedAction( + QIcon(getQPixmap("set_label_col_xpm")), tr("&Label"), this); connect(actionSetLabelCol, SIGNAL(triggered()), this, SLOT(setLabelCol())); - actionBoxPlot = - new QAction(QIcon(getQPixmap("boxPlot_xpm")), tr("&Box Plot"), this); + actionBoxPlot = new MantidQt::MantidWidgets::TrackedAction( + QIcon(getQPixmap("boxPlot_xpm")), tr("&Box Plot"), this); connect(actionBoxPlot, SIGNAL(triggered()), this, SLOT(plotBoxDiagram())); - actionHomePage = new QAction(tr("&Mantid Homepage"), this); // Mantid change + actionHomePage = new MantidQt::MantidWidgets::TrackedAction( + tr("&Mantid Homepage"), this); // Mantid change connect(actionHomePage, SIGNAL(triggered()), this, SLOT(showHomePage())); - actionHelpBugReports = new QAction(tr("Report a &Bug"), this); + actionHelpBugReports = + new MantidQt::MantidWidgets::TrackedAction(tr("Report a &Bug"), this); connect(actionHelpBugReports, SIGNAL(triggered()), this, SLOT(showBugTracker())); - actionAskHelp = new QAction(tr("Ask for Help"), this); + actionAskHelp = + new MantidQt::MantidWidgets::TrackedAction(tr("Ask for Help"), this); connect(actionAskHelp, SIGNAL(triggered()), this, SLOT(showBugTracker())); - actionShowCurvePlotDialog = new QAction(tr("&Plot details..."), this); + actionShowCurvePlotDialog = + new MantidQt::MantidWidgets::TrackedAction(tr("&Plot details..."), this); connect(actionShowCurvePlotDialog, SIGNAL(triggered()), this, SLOT(showCurvePlotDialog())); - actionShowCurveWorksheet = new QAction(tr("&Worksheet"), this); + actionShowCurveWorksheet = + new MantidQt::MantidWidgets::TrackedAction(tr("&Worksheet"), this); connect(actionShowCurveWorksheet, SIGNAL(triggered()), this, SLOT(showCurveWorksheet())); - actionCurveFullRange = new QAction(tr("&Reset to Full Range"), this); + actionCurveFullRange = new MantidQt::MantidWidgets::TrackedAction( + tr("&Reset to Full Range"), this); connect(actionCurveFullRange, SIGNAL(triggered()), this, SLOT(setCurveFullRange())); - actionEditCurveRange = new QAction(tr("Edit &Range..."), this); + actionEditCurveRange = + new MantidQt::MantidWidgets::TrackedAction(tr("Edit &Range..."), this); connect(actionEditCurveRange, SIGNAL(triggered()), this, SLOT(showCurveRangeDialog())); - actionRemoveCurve = new QAction(getQPixmap("close_xpm"), tr("&Delete"), this); + actionRemoveCurve = new MantidQt::MantidWidgets::TrackedAction( + getQPixmap("close_xpm"), tr("&Delete"), this); connect(actionRemoveCurve, SIGNAL(triggered()), this, SLOT(removeCurve())); - actionHideCurve = new QAction(tr("&Hide"), this); + actionHideCurve = + new MantidQt::MantidWidgets::TrackedAction(tr("&Hide"), this); connect(actionHideCurve, SIGNAL(triggered()), this, SLOT(hideCurve())); - actionHideOtherCurves = new QAction(tr("Hide &Other Curves"), this); + actionHideOtherCurves = new MantidQt::MantidWidgets::TrackedAction( + tr("Hide &Other Curves"), this); connect(actionHideOtherCurves, SIGNAL(triggered()), this, SLOT(hideOtherCurves())); - actionShowAllCurves = new QAction(tr("&Show All Curves"), this); + actionShowAllCurves = + new MantidQt::MantidWidgets::TrackedAction(tr("&Show All Curves"), this); connect(actionShowAllCurves, SIGNAL(triggered()), this, SLOT(showAllCurves())); - actionEditFunction = new QAction(tr("&Edit Function..."), this); + actionEditFunction = + new MantidQt::MantidWidgets::TrackedAction(tr("&Edit Function..."), this); connect(actionEditFunction, SIGNAL(triggered()), this, SLOT(showFunctionDialog())); - actionFontBold = new QAction("B", this); + actionFontBold = new MantidQt::MantidWidgets::TrackedAction("B", this); actionFontBold->setToolTip(tr("Bold")); QFont font = appFont; font.setBold(true); @@ -12412,7 +12528,7 @@ void ApplicationWindow::createActions() { actionFontBold->setCheckable(true); connect(actionFontBold, SIGNAL(toggled(bool)), this, SLOT(setBoldFont(bool))); - actionFontItalic = new QAction("It", this); + actionFontItalic = new MantidQt::MantidWidgets::TrackedAction("It", this); actionFontItalic->setToolTip(tr("Italic")); font = appFont; font.setItalic(true); @@ -12421,17 +12537,18 @@ void ApplicationWindow::createActions() { connect(actionFontItalic, SIGNAL(toggled(bool)), this, SLOT(setItalicFont(bool))); - actionSuperscript = - new QAction(getQPixmap("exp_xpm"), tr("Superscript"), this); + actionSuperscript = new MantidQt::MantidWidgets::TrackedAction( + getQPixmap("exp_xpm"), tr("Superscript"), this); connect(actionSuperscript, SIGNAL(triggered()), this, SLOT(insertSuperscript())); actionSuperscript->setEnabled(false); - actionSubscript = new QAction(getQPixmap("index_xpm"), tr("Subscript"), this); + actionSubscript = new MantidQt::MantidWidgets::TrackedAction( + getQPixmap("index_xpm"), tr("Subscript"), this); connect(actionSubscript, SIGNAL(triggered()), this, SLOT(insertSubscript())); actionSubscript->setEnabled(false); - actionUnderline = new QAction("U", this); + actionUnderline = new MantidQt::MantidWidgets::TrackedAction("U", this); actionUnderline->setToolTip(tr("Underline (Ctrl+U)")); actionUnderline->setShortcut(tr("Ctrl+U")); font = appFont; @@ -12440,51 +12557,59 @@ void ApplicationWindow::createActions() { connect(actionUnderline, SIGNAL(triggered()), this, SLOT(underline())); actionUnderline->setEnabled(false); - actionGreekSymbol = - new QAction(QString(QChar(0x3B1)) + QString(QChar(0x3B2)), this); + actionGreekSymbol = new MantidQt::MantidWidgets::TrackedAction( + QString(QChar(0x3B1)) + QString(QChar(0x3B2)), this); actionGreekSymbol->setToolTip(tr("Greek")); connect(actionGreekSymbol, SIGNAL(triggered()), this, SLOT(insertGreekSymbol())); - actionGreekMajSymbol = new QAction(QString(QChar(0x393)), this); + actionGreekMajSymbol = + new MantidQt::MantidWidgets::TrackedAction(QString(QChar(0x393)), this); actionGreekMajSymbol->setToolTip(tr("Greek")); connect(actionGreekMajSymbol, SIGNAL(triggered()), this, SLOT(insertGreekMajSymbol())); - actionMathSymbol = new QAction(QString(QChar(0x222B)), this); + actionMathSymbol = + new MantidQt::MantidWidgets::TrackedAction(QString(QChar(0x222B)), this); actionMathSymbol->setToolTip(tr("Mathematical Symbols")); connect(actionMathSymbol, SIGNAL(triggered()), this, SLOT(insertMathSymbol())); - actionclearAllMemory = new QAction("&Clear All Memory", this); + actionclearAllMemory = + new MantidQt::MantidWidgets::TrackedAction("&Clear All Memory", this); actionclearAllMemory->setShortcut(QKeySequence::fromString("Ctrl+Shift+L")); connect(actionclearAllMemory, SIGNAL(triggered()), mantidUI, SLOT(clearAllMemory())); - actionPanPlot = new QAction(QIcon(":/panning.png"), tr("Panning tool"), this); + actionPanPlot = new MantidQt::MantidWidgets::TrackedAction( + QIcon(":/panning.png"), tr("Panning tool"), this); connect(actionPanPlot, SIGNAL(triggered()), this, SLOT(panOnPlot())); - actionCatalogLogin = new QAction("Login", this); + actionCatalogLogin = + new MantidQt::MantidWidgets::TrackedAction("Login", this); actionCatalogLogin->setToolTip(tr("Catalog Login")); connect(actionCatalogLogin, SIGNAL(triggered()), this, SLOT(CatalogLogin())); - actionCatalogSearch = new QAction("Search", this); + actionCatalogSearch = + new MantidQt::MantidWidgets::TrackedAction("Search", this); actionCatalogSearch->setToolTip(tr("Search data in archives.")); connect(actionCatalogSearch, SIGNAL(triggered()), this, SLOT(CatalogSearch())); - actionCatalogPublish = new QAction("Publish", this); + actionCatalogPublish = + new MantidQt::MantidWidgets::TrackedAction("Publish", this); actionCatalogPublish->setToolTip(tr("Publish data to the archives.")); connect(actionCatalogPublish, SIGNAL(triggered()), this, SLOT(CatalogPublish())); - actionCatalogLogout = new QAction("Logout", this); + actionCatalogLogout = + new MantidQt::MantidWidgets::TrackedAction("Logout", this); actionCatalogLogout->setToolTip(tr("Catalog Logout")); connect(actionCatalogLogout, SIGNAL(triggered()), this, SLOT(CatalogLogout())); - actionWaterfallPlot = - new QAction(QIcon(":/waterfall_plot.png"), tr("&Waterfall Plot"), this); + actionWaterfallPlot = new MantidQt::MantidWidgets::TrackedAction( + QIcon(":/waterfall_plot.png"), tr("&Waterfall Plot"), this); connect(actionWaterfallPlot, SIGNAL(triggered()), this, SLOT(waterfallPlot())); } @@ -13862,7 +13987,7 @@ void ApplicationWindow::saveFolderAsProject(Folder *f) { filter += tr("Compressed MantidPlot project") + " (*.qti.gz)"; QString selectedFilter; - QString fn = MantidQt::API::FileDialogHandler::getSaveFileName( + QString fn = QFileDialog::getSaveFileName( this, tr("Save project as"), workingDir, filter, &selectedFilter); if (!fn.isEmpty()) { QFileInfo fi(fn); @@ -14241,7 +14366,9 @@ bool ApplicationWindow::changeFolder(Folder *newFolder, bool force) { if (active_window) active_window_state = active_window->status(); - hideFolderWindows(oldFolder); + if (newFolder != oldFolder) + hideFolderWindows(oldFolder); + d_current_folder = newFolder; resultsLog->clear(); diff --git a/MantidPlot/src/ConfigDialog.cpp b/MantidPlot/src/ConfigDialog.cpp index 032912b7ef8db18881a14e6f7f740ee2fecf60b7..f30837b4dd25b2f05baa0af6c0b0d6b76363084a 100644 --- a/MantidPlot/src/ConfigDialog.cpp +++ b/MantidPlot/src/ConfigDialog.cpp @@ -1586,11 +1586,6 @@ void ConfigDialog::initCurveFittingTab() { findPeaksTolerance->setMaximum(1000000); grid->addWidget(findPeaksTolerance, 4, 1); - grid->addWidget(new QLabel(tr("Peak Radius (in FWHM)")), 5, 0); - peakRadius = new QSpinBox(); - peakRadius->setMaximum(std::numeric_limits<int>::max()); - grid->addWidget(peakRadius, 5, 1); - grid->addWidget(new QLabel(tr("Double property decimals")), 6, 0); decimals = new QSpinBox(); grid->addWidget(decimals, 6, 1); @@ -1675,15 +1670,6 @@ void ConfigDialog::initCurveFittingTab() { findPeaksTolerance->setValue(4); } - setting = QString::fromStdString( - Mantid::Kernel::ConfigService::Instance().getString( - "curvefitting.peakRadius")); - if (!setting.isEmpty()) { - peakRadius->setValue(setting.toInt()); - } else { - peakRadius->setValue(5); - } - decimals->setValue(app->mantidUI->fitFunctionBrowser()->getDecimals()); } @@ -2806,9 +2792,6 @@ void ConfigDialog::updateCurveFitSettings() { setting = QString::number(findPeaksTolerance->value()).toStdString(); cfgSvc.setString("curvefitting.findPeaksTolerance", setting); - setting = QString::number(peakRadius->value()).toStdString(); - cfgSvc.setString("curvefitting.peakRadius", setting); - app->mantidUI->fitFunctionBrowser()->setDecimals(decimals->value()); } diff --git a/MantidPlot/src/ConfigDialog.h b/MantidPlot/src/ConfigDialog.h index cc14cf626f202a95a2818351ba15c2fdd8fdc002..e795145e2acd681c176c82cdc12d41f23707524f 100644 --- a/MantidPlot/src/ConfigDialog.h +++ b/MantidPlot/src/ConfigDialog.h @@ -219,7 +219,6 @@ private: QLineEdit *functionArguments; QComboBox *defaultPeakShape; QSpinBox *findPeaksFWHM, *findPeaksTolerance; - QSpinBox *peakRadius; QSpinBox *decimals; /// mantid options page QWidget *mantidOptionsPage; diff --git a/MantidPlot/src/FitDialog.cpp b/MantidPlot/src/FitDialog.cpp index 225ae7a19cd01d48428e05622155d3b66fe02a3d..f4cde40d9fef22eeccff0ac10d79abbd005ea55f 100644 --- a/MantidPlot/src/FitDialog.cpp +++ b/MantidPlot/src/FitDialog.cpp @@ -65,8 +65,6 @@ #include <qwt_plot_curve.h> -#include "MantidQtAPI/FileDialogHandler.h" - using namespace MantidQt::API; FitDialog::FitDialog(Graph *g, QWidget *parent, Qt::WFlags fl) @@ -662,7 +660,7 @@ void FitDialog::saveUserFunction() { } QString filter = tr("MantidPlot fit model") + " (*.fit);;"; filter += tr("All files") + " (*)"; - QString fn = MantidQt::API::FileDialogHandler::getSaveFileName( + QString fn = QFileDialog::getSaveFileName( app, tr("MantidPlot") + " - " + tr("Save Fit Model As"), app->fitModelsPath + "/" + name, filter); if (!fn.isEmpty()) { @@ -1423,7 +1421,7 @@ void FitDialog::saveInitialGuesses() { } QString filter = tr("MantidPlot fit model") + " (*.fit);;"; filter += tr("All files") + " (*)"; - QString fn = MantidQt::API::FileDialogHandler::getSaveFileName( + QString fn = QFileDialog::getSaveFileName( app, tr("MantidPlot") + " - " + tr("Save Fit Model As"), app->fitModelsPath + "/" + d_current_fit->objectName(), filter); if (!fn.isEmpty()) { diff --git a/MantidPlot/src/FunctionCurve.cpp b/MantidPlot/src/FunctionCurve.cpp index 46ff376e7223b96b31f2a9a393c4f2aa64a93e28..6ce438adc963976b15111b3b48163bf9868342ca 100644 --- a/MantidPlot/src/FunctionCurve.cpp +++ b/MantidPlot/src/FunctionCurve.cpp @@ -254,9 +254,10 @@ void FunctionCurve::loadData(int points) { * Load the data from a MatrixWorkspace if it is a Mantid-type FunctionCurve. * @param ws :: A workspace to load the data from. * @param wi :: An index of a histogram with the data. + * @param peakRadius :: A peak radius to pass to the domain. */ void FunctionCurve::loadMantidData(Mantid::API::MatrixWorkspace_const_sptr ws, - size_t wi) { + size_t wi, int peakRadius) { if (!d_variable.isEmpty() || d_formulas.isEmpty() || d_formulas[0] != "Mantid") return; @@ -310,6 +311,9 @@ void FunctionCurve::loadMantidData(Mantid::API::MatrixWorkspace_const_sptr ws, f->applyTies(); Mantid::API::FunctionDomain1DVector domain(X); Mantid::API::FunctionValues Y(domain); + if (peakRadius > 0) { + domain.setPeakRadius(peakRadius); + } f->function(domain, Y); setData(&X[0], Y.getPointerToCalculated(0), static_cast<int>(X.size())); diff --git a/MantidPlot/src/FunctionCurve.h b/MantidPlot/src/FunctionCurve.h index d0d01b9d2ecffc25bec45b4f3d0e6ab24122cd86..fa19031030d15bfb5ced3b7f2a1f51ad1110954e 100644 --- a/MantidPlot/src/FunctionCurve.h +++ b/MantidPlot/src/FunctionCurve.h @@ -84,7 +84,7 @@ public: void loadData(int points = 0); void loadMantidData(boost::shared_ptr<const Mantid::API::MatrixWorkspace> ws, - size_t wi); + size_t wi, int peakRadius = 0); /// No error bars on this curve: Always return an empty list. QList<ErrorBarSettings *> errorBarSettingsList() const override { diff --git a/MantidPlot/src/Graph3D.cpp b/MantidPlot/src/Graph3D.cpp index 9c9950f09b4642d366b3453c81ef27f80327c31b..cb70c2e1e4872e2285cbe3a54daf4935c14e44d8 100644 --- a/MantidPlot/src/Graph3D.cpp +++ b/MantidPlot/src/Graph3D.cpp @@ -44,7 +44,6 @@ #include <QBitmap> #include <QClipboard> #include <QCursor> -#include <QFileDialog> #include <QImageWriter> #include <QMessageBox> #include <QPixmap> diff --git a/MantidPlot/src/Mantid/AlgorithmHistoryWindow.cpp b/MantidPlot/src/Mantid/AlgorithmHistoryWindow.cpp index c94ecacdb96fcf87555d9588c3b45d95f8952e14..da000c1c69f67995d6c1bd4a741484d73289144a 100644 --- a/MantidPlot/src/Mantid/AlgorithmHistoryWindow.cpp +++ b/MantidPlot/src/Mantid/AlgorithmHistoryWindow.cpp @@ -4,21 +4,20 @@ #include "MantidAPI/Workspace.h" #include "MantidQtAPI/AlgorithmInputHistory.h" -#include "MantidQtAPI/FileDialogHandler.h" -#include <QLineEdit> -#include <QLabel> -#include <QFileDialog> +#include <QAction> +#include <QApplication> +#include <QClipboard> #include <QDateTime> +#include <QDir> +#include <QFileDialog> #include <QFormLayout> +#include <QLabel> +#include <QLineEdit> #include <QMenu> -#include <QAction> #include <QMessageBox> -#include <QApplication> -#include <QClipboard> -#include <QTextStream> #include <QTemporaryFile> -#include <QDir> +#include <QTextStream> #include <numeric> #include <fstream> @@ -393,7 +392,7 @@ void AlgorithmHistoryWindow::writeToScriptFile() { } else { scriptDir = prevDir; } - QString filePath = MantidQt::API::FileDialogHandler::getSaveFileName( + QString filePath = QFileDialog::getSaveFileName( this, tr("Save Script As "), scriptDir, tr("Script files (*.py)")); // An empty string indicates they clicked cancel if (filePath.isEmpty()) diff --git a/MantidPlot/src/Mantid/MantidMatrixCurve.cpp b/MantidPlot/src/Mantid/MantidMatrixCurve.cpp index bbb80525696f0e63eb499b84f6a8723adb230081..cf38b44252fdf94650efe1afe3b7a0c68b176227 100644 --- a/MantidPlot/src/Mantid/MantidMatrixCurve.cpp +++ b/MantidPlot/src/Mantid/MantidMatrixCurve.cpp @@ -15,6 +15,7 @@ #include "../MultiLayer.h" #include "ErrorBarSettings.h" #include "MantidKernel/ReadLock.h" +#include <sstream> using namespace Mantid::API; using namespace MantidQt::API; diff --git a/MantidPlot/src/Mantid/PeakPickerTool.cpp b/MantidPlot/src/Mantid/PeakPickerTool.cpp index 084ff8b1e0b6b1a27ed0e3778f8c9c7cd0ee0260..f81882e6262b174acb6f989471ea87b91161b259 100644 --- a/MantidPlot/src/Mantid/PeakPickerTool.cpp +++ b/MantidPlot/src/Mantid/PeakPickerTool.cpp @@ -654,7 +654,8 @@ void PeakPickerTool::replot(MantidQt::MantidWidgets::PropertyHandler *h) const { // fc->loadData(); auto ws = boost::dynamic_pointer_cast<const Mantid::API::MatrixWorkspace>( m_fitPropertyBrowser->getWorkspace()); - fc->loadMantidData(ws, m_fitPropertyBrowser->workspaceIndex()); + fc->loadMantidData(ws, m_fitPropertyBrowser->workspaceIndex(), + m_fitPropertyBrowser->getPeakRadius()); } } } @@ -886,7 +887,8 @@ void PeakPickerTool::plotFitFunction( m_fitPropertyBrowser->endX()); auto ws = boost::dynamic_pointer_cast<const Mantid::API::MatrixWorkspace>( m_fitPropertyBrowser->getWorkspace()); - fc->loadMantidData(ws, m_fitPropertyBrowser->workspaceIndex()); + fc->loadMantidData(ws, m_fitPropertyBrowser->workspaceIndex(), + m_fitPropertyBrowser->getPeakRadius()); // Graph now owns m_curve. Use m_curve->removeMe() to remove (and delete) // from Graph d_graph->insertCurve(fc); diff --git a/MantidPlot/src/MultiLayer.cpp b/MantidPlot/src/MultiLayer.cpp index e6d4eb5cafc8ee7728c356d77537d820bbf4257b..b0e5c5163dc15f20b1b9618e83ea14e43b1a98c9 100644 --- a/MantidPlot/src/MultiLayer.cpp +++ b/MantidPlot/src/MultiLayer.cpp @@ -1812,18 +1812,7 @@ MultiLayer::loadFromProject(const std::string &lines, ApplicationWindow *app, if (gtsv.selectLine("ggeometry")) { int x = 0, y = 0, w = 0, h = 0; - gtsv >> x >> y; - - w = multiLayer->canvas->width(); - w -= multiLayer->left_margin; - w -= multiLayer->right_margin; - w -= (multiLayer->d_cols - 1) * multiLayer->colsSpace; - - h = multiLayer->canvas->height(); - h -= multiLayer->top_margin; - h -= multiLayer->left_margin; - h -= (multiLayer->d_rows - 1) * multiLayer->rowsSpace; - h -= LayerButton::btnSize(); + gtsv >> x >> y >> w >> h; if (isWaterfall) h -= LayerButton::btnSize(); // need an extra offset for the buttons diff --git a/MantidPlot/src/Note.cpp b/MantidPlot/src/Note.cpp index 0bcb0a4f7a4b1174b908062fff4662a85829b409..17d1dda76fff8779569357edaa7adece93cce554 100644 --- a/MantidPlot/src/Note.cpp +++ b/MantidPlot/src/Note.cpp @@ -35,15 +35,14 @@ #include <QFileDialog> #include <QMessageBox> +#include <QPrintDialog> #include <QTextCodec> #include <QTextStream> #include <Qsci/qsciprinter.h> -#include <QPrintDialog> #include "ApplicationWindow.h" #include "MantidQtAPI/TSVSerialiser.h" #include "MantidKernel/ConfigService.h" -#include "MantidQtAPI/FileDialogHandler.h" // Register the window into the WindowFactory DECLARE_WINDOW(Note) @@ -99,8 +98,8 @@ QString Note::exportASCII(const QString &filename) { QString dir(Mantid::Kernel::ConfigService::Instance() .getString("defaultsave.directory") .c_str()); - fn = MantidQt::API::FileDialogHandler::getSaveFileName( - this, tr("Save Text to File"), dir, filter, &selectedFilter); + fn = QFileDialog::getSaveFileName(this, tr("Save Text to File"), dir, + filter, &selectedFilter); } else fn = filename; diff --git a/MantidPlot/src/Plot3DDialog.cpp b/MantidPlot/src/Plot3DDialog.cpp index 95f6eefff0a752f107a4cb3387d830d3796c5d96..6c5bc1536a9b967cc36b4583afec07b591233bdb 100644 --- a/MantidPlot/src/Plot3DDialog.cpp +++ b/MantidPlot/src/Plot3DDialog.cpp @@ -47,7 +47,6 @@ #include <QMessageBox> #include <QComboBox> #include <QWidgetList> -#include <QFileDialog> #include <QGroupBox> #include <QFontDialog> #include <QApplication> diff --git a/MantidPlot/src/PlotDialog.cpp b/MantidPlot/src/PlotDialog.cpp index cebc468f8f45f53042c4421336d7e9e85a3feec6..1626c4116b57644c4b77362c511793d890cfc9ff 100644 --- a/MantidPlot/src/PlotDialog.cpp +++ b/MantidPlot/src/PlotDialog.cpp @@ -54,7 +54,7 @@ #include <QComboBox> #include <QDateTime> #include <QDoubleSpinBox> -#include <QFileDialog> +#include <QFileInfo> #include <QFontDialog> #include <QGroupBox> #include <QKeySequence> diff --git a/MantidPlot/src/ScriptOutputDisplay.cpp b/MantidPlot/src/ScriptOutputDisplay.cpp index 39825ddb9f186efc474904ded0d1f9daec0b33d0..a87e936e17e1610cdd4e7edc7e7503f08fb479f6 100644 --- a/MantidPlot/src/ScriptOutputDisplay.cpp +++ b/MantidPlot/src/ScriptOutputDisplay.cpp @@ -4,7 +4,6 @@ #include <MantidQtAPI/pixmaps.h> #include <QDateTime> -#include <QFileDialog> #include <QKeyEvent> #include <QMenu> #include <QPrintDialog> diff --git a/MantidPlot/src/ScriptingWindow.cpp b/MantidPlot/src/ScriptingWindow.cpp index 646be1e419741ee2e7a7d1694c5e66a61cef1bb9..9f0ddfb2161b9e3ed6fd9425ea25dd57e83058c0 100644 --- a/MantidPlot/src/ScriptingWindow.cpp +++ b/MantidPlot/src/ScriptingWindow.cpp @@ -23,7 +23,7 @@ #include <QApplication> #include <QCloseEvent> #include <QDateTime> -#include <QFileDialog> +#include <QFileInfo> #include <QList> #include <QMenu> #include <QMenuBar> diff --git a/MantidPlot/src/TextFileIO.cpp b/MantidPlot/src/TextFileIO.cpp index 48a221a59613aebbe038c35294e3d52a6742659f..c6da8829961cb600c8cb85d07fd22bde0b0d69b8 100644 --- a/MantidPlot/src/TextFileIO.cpp +++ b/MantidPlot/src/TextFileIO.cpp @@ -1,13 +1,11 @@ #include "TextFileIO.h" +#include "MantidQtAPI/FileDialogHandler.h" +#include <QApplication> #include <QFile> #include <QFileDialog> -#include <QFileInfo> #include <QMessageBox> #include <QTextStream> -#include <QApplication> - -#include "MantidQtAPI/FileDialogHandler.h" /** * Construct an object with a list of file filters @@ -47,15 +45,8 @@ bool TextFileIO::save(const QString &txt, const QString &filename) const { QString TextFileIO::askWhereToSave() const { QString selectedFilter; QString filter = m_filters.join(";;"); - QString filename = MantidQt::API::FileDialogHandler::getSaveFileName( - NULL, "MantidPlot - Save", "", filter, &selectedFilter); - if (filename.isEmpty()) - return QString(); - if (QFileInfo(filename).suffix().isEmpty()) { - QString ext = selectedFilter.section('(', 1).section(' ', 0, 0); - ext.remove(0, 1); - if (ext != ")") - filename += ext; - } - return filename; + QString filename = QFileDialog::getSaveFileName(NULL, "MantidPlot - Save", "", + filter, &selectedFilter); + return MantidQt::API::FileDialogHandler::addExtension(filename, + selectedFilter); } diff --git a/MantidQt/API/CMakeLists.txt b/MantidQt/API/CMakeLists.txt index f6cdaa1ed48eb1eae067d824aeece59f653ea6b8..4146c5d0fbcf1261bf700e327fe019f25dc586bc 100644 --- a/MantidQt/API/CMakeLists.txt +++ b/MantidQt/API/CMakeLists.txt @@ -5,6 +5,7 @@ src/AlgorithmRunner.cpp src/BatchAlgorithmRunner.cpp src/BoolPropertyWidget.cpp + src/FileDialogHandler.cpp src/FilePropertyWidget.cpp src/GenericDialog.cpp src/HelpWindow.cpp @@ -133,6 +134,7 @@ set ( UI_FILES set( TEST_FILES BatchAlgorithmRunnerTest.h + FileDialogHandlerTest.h InterfaceManagerTest.h MantidColorMapTest.h PlotAxisTest.h diff --git a/MantidQt/API/inc/MantidQtAPI/FileDialogHandler.h b/MantidQt/API/inc/MantidQtAPI/FileDialogHandler.h index d11d77e47399815c75d8e5029f964ab416411ba8..f53bb16def2991340ed5631058d0375817fbd81e 100644 --- a/MantidQt/API/inc/MantidQtAPI/FileDialogHandler.h +++ b/MantidQt/API/inc/MantidQtAPI/FileDialogHandler.h @@ -1,12 +1,19 @@ #ifndef MANTIDQT_API_FILEDIALOGHANDLER_H_ #define MANTIDQT_API_FILEDIALOGHANDLER_H_ +#include "MantidKernel/DllConfig.h" #include <QFileDialog> #ifdef Q_OS_DARWIN #include <errno.h> #include <sys/sysctl.h> #endif +namespace Mantid { +namespace Kernel { +class Property; +} +} + namespace MantidQt { namespace API { /** @@ -35,33 +42,41 @@ namespace API { File change history is stored at: <https://github.com/mantidproject/mantid> Code Documentation is available at: <http://doxygen.mantidproject.org> */ -struct FileDialogHandler { - /** The MacOS's native save dialog crashes when running a 10.6 package on 10.8 - * so this function, which takes - * the same arguments as the Qt function, ensures a nonnative object is used - * on the Mac when necessary. - * If compiled on 10.8 the native will be used - * @param parent :: the dialog will be shown centered over this parent widget - * @param caption :: The dialog's caption - * @param dir :: The file dialog's working directory will be set to dir. If - * dir includes a file name, the file will be selected - * @param filter :: extensions of files to look for - * @param selectedFilter :: pass a pointer an existing string that will be - * filled with the extension the user selected - * @param options :: The options argument holds various options about how to - * run the dialog +namespace FileDialogHandler { +/** + * @param parent :: the dialog will be shown centered over this parent + * widget + * @param baseProp :: The property that the dialog parameters will be extracted + * from. + * @param options :: The options argument holds various options about how + * to run the dialog */ - static QString getSaveFileName(QWidget *parent = 0, - const QString &caption = QString(), - const QString &dir = QString(), - const QString &filter = QString(), - QString *selectedFilter = 0, - QFileDialog::Options options = 0) { - options = options | QFileDialog::DontUseNativeDialog; - return QFileDialog::getSaveFileName(parent, caption, dir, filter, - selectedFilter, options); - } -}; +DLLExport QString getSaveFileName(QWidget *parent = 0, + const Mantid::Kernel::Property *baseProp = 0, + QFileDialog::Options options = 0); + +/** + * For file dialogs. This will add the selected extension if an extension + * doesn't + * already exist. + */ +DLLExport QString +addExtension(const QString &filename, const QString &selectedFilter); + +DLLExport QString getFilter(const Mantid::Kernel::Property *baseProp); + +/** For file dialogs + * + * @param exts :: vector of extensions + * @param defaultExt :: default extension to use + * @return a string that filters files by extenstions + */ +DLLExport QString +getFilter(const std::vector<std::string> &exts, const std::string &defaultExt); + +DLLExport QString +getCaption(const std::string &dialogName, const Mantid::Kernel::Property *prop); +} } } diff --git a/MantidQt/API/src/FileDialogHandler.cpp b/MantidQt/API/src/FileDialogHandler.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b355c1765da484a4982676101d92d8a96d153a02 --- /dev/null +++ b/MantidQt/API/src/FileDialogHandler.cpp @@ -0,0 +1,167 @@ +#include "MantidQtAPI/FileDialogHandler.h" +#include "MantidAPI/FileProperty.h" +#include "MantidAPI/MultipleFileProperty.h" +#include "MantidQtAPI/AlgorithmInputHistory.h" +#include <boost/regex.hpp> + +namespace { // anonymous namespace +const boost::regex FILE_EXT_REG_EXP{"^.+\\s+\\((\\S+)\\)$"}; +const QString ALL_FILES("All Files (*)"); + +QString getExtensionFromFilter(const QString &selectedFilter) { + // empty returns empty + if (selectedFilter.isEmpty()) { + return QString(""); + } + + // search for single extension + boost::smatch result; + if (boost::regex_search(selectedFilter.toStdString(), result, + FILE_EXT_REG_EXP) && + result.size() == 2) { + auto extension = QString::fromStdString(result[1]); + if (extension.startsWith("*")) + return extension.remove(0, 1); + else + return extension; + } else { + // failure to match suggests multi-extension filter + std::stringstream msg; + msg << "Failed to determine single extension from \"" + << selectedFilter.toStdString() << "\""; + throw std::runtime_error(msg.str()); + } +} +} // anonymous namespace + +namespace MantidQt { +namespace API { +namespace FileDialogHandler { +/** + Contains modifications to Qt functions where problems have been found + on certain operating systems + + Copyright © 2009-2010 ISIS Rutherford Appleton Laboratory, NScD Oak + Ridge National Laboratory & European Spallation Source + @date 17/09/2010 + + This file is part of Mantid. + + Mantid is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + Mantid is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + + File change history is stored at: <https://github.com/mantidproject/mantid> + Code Documentation is available at: <http://doxygen.mantidproject.org> +*/ +QString getSaveFileName(QWidget *parent, + const Mantid::Kernel::Property *baseProp, + QFileDialog::Options options) { + // set up filters and dialog title + const auto filter = getFilter(baseProp); + const auto caption = getCaption("Save file", baseProp); + + QString selectedFilter; + + // create the file browser + QString filename = QFileDialog::getSaveFileName( + parent, caption, AlgorithmInputHistory::Instance().getPreviousDirectory(), + filter, &selectedFilter, options); + + return addExtension(filename, selectedFilter); +} + +QString addExtension(const QString &filename, const QString &selectedFilter) { + // just return an empty string if that is what was given + if (filename.isEmpty()) + return filename; + + // Check the filename and append the selected filter if necessary + if (QFileInfo(filename).completeSuffix().isEmpty()) { + auto ext = getExtensionFromFilter(selectedFilter); + if (filename.endsWith(".") && ext.startsWith(".")) { + ext = ext.remove(0, 1); + } + return filename + ext; + } else { + return filename; + } +} + +QString getFilter(const Mantid::Kernel::Property *baseProp) { + if (!baseProp) + return ALL_FILES; + + // multiple file version + const auto *multiProp = + dynamic_cast<const Mantid::API::MultipleFileProperty *>(baseProp); + if (bool(multiProp)) + return getFilter(multiProp->getExts(), multiProp->getDefaultExt()); + + // regular file version + const auto *singleProp = + dynamic_cast<const Mantid::API::FileProperty *>(baseProp); + // The allowed values in this context are file extensions + if (bool(singleProp)) + return getFilter(singleProp->allowedValues(), singleProp->getDefaultExt()); + + // otherwise only the all files exists + return ALL_FILES; +} + +/** For file dialogs. Have each filter on a separate line with the default as + * the first. + * + * @param exts :: vector of extensions + * @param defaultExt :: default extension to use + * @return a string that filters files by extenstions + */ +QString getFilter(const std::vector<std::string> &exts, + const std::string &defaultExt) { + QString filter(""); + + if (!defaultExt.empty()) { + filter.append(QString::fromStdString(defaultExt) + " (*" + + QString::fromStdString(defaultExt) + ");;"); + } + + if (!exts.empty()) { + // Push a wild-card onto the front of each file suffix + for (auto &itr : exts) { + if (itr != defaultExt) { + filter.append(QString::fromStdString(itr) + " (*" + + QString::fromStdString(itr) + ");;"); + } + } + filter = filter.trimmed(); + } + filter.append(ALL_FILES); + return filter; +} + +QString getCaption(const std::string &dialogName, + const Mantid::Kernel::Property *prop) { + // generate the dialog title + auto dialogTitle = QString::fromStdString(dialogName); + if (bool(prop)) { + const auto name = prop->name(); + if (name != "Filename" && prop->name() != "Directory" && + prop->name() != "Dir") { + dialogTitle.append(" - "); + dialogTitle.append(QString::fromStdString(name)); + } + } + return dialogTitle; +} +} +} +} diff --git a/MantidQt/API/src/FilePropertyWidget.cpp b/MantidQt/API/src/FilePropertyWidget.cpp index 4e84296181e106943e33dfdbf808ae1f526bcc92..f640f64cd3c4127b028faf25d270ed1473d4b11b 100644 --- a/MantidQt/API/src/FilePropertyWidget.cpp +++ b/MantidQt/API/src/FilePropertyWidget.cpp @@ -77,38 +77,6 @@ void FilePropertyWidget::browseClicked() { } } -//------------------------------------------------------------------------------------------------- -/** For file dialogs - * - * @param exts :: vector of extensions - * @param defaultExt :: default extension to use - * @return a string that filters files by extenstions - */ -QString getFileDialogFilter(const std::vector<std::string> &exts, - const std::string &defaultExt) { - QString filter(""); - - if (!defaultExt.empty()) { - filter.append(QString::fromStdString(defaultExt) + " (*" + - QString::fromStdString(defaultExt) + ");;"); - } - - if (!exts.empty()) { - // --------- Load a File ------------- - auto iend = exts.end(); - // Push a wild-card onto the front of each file suffix - for (auto itr = exts.begin(); itr != iend; ++itr) { - if ((*itr) != defaultExt) { - filter.append(QString::fromStdString(*itr) + " (*" + - QString::fromStdString(*itr) + ");;"); - } - } - filter = filter.trimmed(); - } - filter.append("All Files (*)"); - return filter; -} - //---------------------------------------------------------------------------------------------- /** Open the file dialog for a given property * @@ -121,10 +89,6 @@ QString FilePropertyWidget::openFileDialog(Mantid::Kernel::Property *baseProp) { if (!prop) return ""; - // The allowed values in this context are file extensions - std::vector<std::string> exts = prop->allowedValues(); - std::string defaultExt = prop->getDefaultExt(); - /* MG 20/07/09: Static functions such as these that use native Windows and MAC dialogs in those environments are alot faster. This is unforunately at the expense @@ -133,55 +97,18 @@ QString FilePropertyWidget::openFileDialog(Mantid::Kernel::Property *baseProp) { */ QString filename; if (prop->isLoadProperty()) { - QString filter = getFileDialogFilter(exts, defaultExt); + const auto filter = FileDialogHandler::getFilter(baseProp); + const auto caption = FileDialogHandler::getCaption("Open file", baseProp); filename = QFileDialog::getOpenFileName( - NULL, "Open file", + nullptr, caption, AlgorithmInputHistory::Instance().getPreviousDirectory(), filter); } else if (prop->isSaveProperty()) { - // --------- Save a File ------------- - // Have each filter on a separate line with the default as the first - QString filter; - if (!defaultExt.empty()) { - filter = "*" + QString::fromStdString(defaultExt) + ";;"; - } - auto iend = exts.end(); - for (auto itr = exts.begin(); itr != iend; ++itr) { - if ((*itr) != defaultExt) { - filter.append("*" + QString::fromStdString(*itr) + ";;"); - } - } - // Remove last two semi-colons or else we get an extra empty option in the - // box - filter.chop(2); - // Prepend the default filter - QString selectedFilter; - filename = MantidQt::API::FileDialogHandler::getSaveFileName( - NULL, "Save file", - AlgorithmInputHistory::Instance().getPreviousDirectory(), filter, - &selectedFilter); - - // Check the filename and append the selected filter if necessary - if (QFileInfo(filename).completeSuffix().isEmpty()) { - // Hack off the first star that the filter returns - QString ext = selectedFilter; - - if (selectedFilter.startsWith("*.")) { - // 1 character from the start - ext = ext.remove(0, 1); - } else { - ext = ""; - } - - if (filename.endsWith(".") && ext.startsWith(".")) { - ext = ext.remove(0, 1); - } - - // Construct the full file name - filename += ext; - } + filename = FileDialogHandler::getSaveFileName(nullptr, prop); } else if (prop->isDirectoryProperty()) { + const auto caption = + FileDialogHandler::getCaption("Choose a Directory", baseProp); filename = QFileDialog::getExistingDirectory( - NULL, "Choose a Directory", + nullptr, caption, AlgorithmInputHistory::Instance().getPreviousDirectory()); } else { throw std::runtime_error( @@ -211,9 +138,9 @@ FilePropertyWidget::openMultipleFileDialog(Mantid::Kernel::Property *baseProp) { if (!prop) return QStringList(); - QString filter = getFileDialogFilter(prop->getExts(), prop->getDefaultExt()); + const auto filter = FileDialogHandler::getFilter(baseProp); QStringList files = QFileDialog::getOpenFileNames( - NULL, "Open Multiple Files", + nullptr, "Open Multiple Files", AlgorithmInputHistory::Instance().getPreviousDirectory(), filter); return files; diff --git a/MantidQt/API/src/PropertyWidget.cpp b/MantidQt/API/src/PropertyWidget.cpp index d8d1beb69364acb1d379828772c42a99920fc554..d107b81aebe7a7e137a547d16153c232c972dfe1 100644 --- a/MantidQt/API/src/PropertyWidget.cpp +++ b/MantidQt/API/src/PropertyWidget.cpp @@ -11,6 +11,7 @@ #include <cfloat> #include <algorithm> +#include <sstream> #include <QLineEdit> diff --git a/MantidQt/API/src/UserSubWindow.cpp b/MantidQt/API/src/UserSubWindow.cpp index 33b432775f22cba222e244e8103e813d19cc006f..13eb293f1d2edcbef273dfd101c55a535704ec3a 100644 --- a/MantidQt/API/src/UserSubWindow.cpp +++ b/MantidQt/API/src/UserSubWindow.cpp @@ -2,7 +2,6 @@ // Includes //---------------------------------- #include "MantidQtAPI/AlgorithmInputHistory.h" -#include "MantidQtAPI/FileDialogHandler.h" #include "MantidQtAPI/UserSubWindow.h" #include "MantidKernel/UsageService.h" @@ -129,7 +128,7 @@ QString UserSubWindow::openFileDialog(const bool save, QString filename; if (save) { - filename = MantidQt::API::FileDialogHandler::getSaveFileName( + filename = QFileDialog::getSaveFileName( this, "Save file", AlgorithmInputHistory::Instance().getPreviousDirectory(), filter); } else { diff --git a/MantidQt/API/test/FileDialogHandlerTest.h b/MantidQt/API/test/FileDialogHandlerTest.h new file mode 100644 index 0000000000000000000000000000000000000000..b73532723f792817ea44594532f5c5cffb925694 --- /dev/null +++ b/MantidQt/API/test/FileDialogHandlerTest.h @@ -0,0 +1,66 @@ +#ifndef MANTIDQT_API_FILEDIALOGHANDLERTEST_H_ +#define MANTIDQT_API_FILEDIALOGHANDLERTEST_H_ + +#include "MantidQtAPI/FileDialogHandler.h" +#include <cxxtest/TestSuite.h> + +class FileDialogHandlerTest : public CxxTest::TestSuite { +public: + void test_addExtension() { + // --- single extensions + const QString singleExt(".nxs (*.nxs)"); + const QString nexusResult("/tmp/testing.nxs"); + + auto result1 = MantidQt::API::FileDialogHandler::addExtension( + QString::fromStdString("/tmp/testing"), singleExt); + TS_ASSERT_EQUALS(nexusResult.toStdString(), result1.toStdString()); + + auto result2 = MantidQt::API::FileDialogHandler::addExtension( + QString::fromStdString("/tmp/testing."), singleExt); + TS_ASSERT_EQUALS(nexusResult.toStdString(), result2.toStdString()); + + auto result3 = + MantidQt::API::FileDialogHandler::addExtension(nexusResult, singleExt); + TS_ASSERT_EQUALS(nexusResult.toStdString(), result3.toStdString()); + + // don't override if it is already specified + const QString singleH5("/tmp/testing.h5"); + auto result4 = + MantidQt::API::FileDialogHandler::addExtension(singleH5, singleExt); + TS_ASSERT_EQUALS(singleH5.toStdString(), result4.toStdString()); + + // --- double extensions + const QString doubleExt("JPEG (*.jpg *.jpeg)"); + const QString jpegResult("/tmp/testing.jpg"); + + // this can't work because you can't determine one extension + TS_ASSERT_THROWS(MantidQt::API::FileDialogHandler::addExtension( + QString::fromStdString("/tmp/testing"), doubleExt), + std::runtime_error); + + // this shouldn't do anything + auto result5 = + MantidQt::API::FileDialogHandler::addExtension(jpegResult, doubleExt); + TS_ASSERT_EQUALS(jpegResult.toStdString(), result5.toStdString()); + } + + void test_getFileDialogFilter() { + std::vector<std::string> exts({"*.h5", "*.nxs"}); + + const auto result1 = MantidQt::API::FileDialogHandler::getFilter( + std::vector<std::string>(), std::string("")); + TS_ASSERT_EQUALS(std::string("All Files (*)"), result1.toStdString()); + + const auto result2 = + MantidQt::API::FileDialogHandler::getFilter(exts, std::string("")); + TS_ASSERT_EQUALS(std::string("*.h5 (**.h5);;*.nxs (**.nxs);;All Files (*)"), + result2.toStdString()); + + const auto result3 = + MantidQt::API::FileDialogHandler::getFilter(exts, std::string("*.nxs")); + TS_ASSERT_EQUALS(std::string("*.nxs (**.nxs);;*.h5 (**.h5);;All Files (*)"), + result3.toStdString()); + } +}; + +#endif /* MANTIDQT_API_FILEDIALOGHANDLERTEST_H_ */ diff --git a/MantidQt/CustomInterfaces/CMakeLists.txt b/MantidQt/CustomInterfaces/CMakeLists.txt index b4b5f0d6bf36d3cb06849fb20ba49ef853b59d47..a75c16407aaa0da701153ea95c8aa2e8cafb2ca9 100644 --- a/MantidQt/CustomInterfaces/CMakeLists.txt +++ b/MantidQt/CustomInterfaces/CMakeLists.txt @@ -94,6 +94,7 @@ set ( SRC_FILES src/Reflectometry/QtReflRunsTabView.cpp src/Reflectometry/QtReflSaveTabView.cpp src/Reflectometry/QtReflSettingsTabView.cpp + src/Reflectometry/QtReflSettingsView.cpp src/Reflectometry/ReflCatalogSearcher.cpp src/Reflectometry/ReflGenericDataProcessorPresenterFactory.cpp src/Reflectometry/ReflLegacyTransferStrategy.cpp @@ -103,6 +104,7 @@ set ( SRC_FILES src/Reflectometry/ReflRunsTabPresenter.cpp src/Reflectometry/ReflSearchModel.cpp src/Reflectometry/ReflSaveTabPresenter.cpp + src/Reflectometry/ReflSettingsPresenter.cpp src/Reflectometry/ReflSettingsTabPresenter.cpp src/Reflectometry/ReflTableSchema.cpp src/Reflectometry/TransferResults.cpp @@ -257,8 +259,9 @@ set ( INC_FILES inc/MantidQtCustomInterfaces/Reflectometry/IReflSearcher.h inc/MantidQtCustomInterfaces/Reflectometry/IReflSaveTabPresenter.h inc/MantidQtCustomInterfaces/Reflectometry/IReflSaveTabView.h + inc/MantidQtCustomInterfaces/Reflectometry/IReflSettingsPresenter.h inc/MantidQtCustomInterfaces/Reflectometry/IReflSettingsTabPresenter.h - inc/MantidQtCustomInterfaces/Reflectometry/IReflSettingsTabView.h + inc/MantidQtCustomInterfaces/Reflectometry/IReflSettingsView.h inc/MantidQtCustomInterfaces/Reflectometry/MeasurementItem.h inc/MantidQtCustomInterfaces/Reflectometry/QtReflMainWindowView.h inc/MantidQtCustomInterfaces/Reflectometry/QtReflRunsTabView.h @@ -270,6 +273,8 @@ set ( INC_FILES inc/MantidQtCustomInterfaces/Reflectometry/ReflMeasurementItemSource.h inc/MantidQtCustomInterfaces/Reflectometry/ReflNexusMeasurementItemSource.h inc/MantidQtCustomInterfaces/Reflectometry/ReflRunsTabPresenter.h + inc/MantidQtCustomInterfaces/Reflectometry/ReflSettingsPresenter.h + inc/MantidQtCustomInterfaces/Reflectometry/ReflSettingsTabPresenter.h inc/MantidQtCustomInterfaces/Reflectometry/ReflSearchModel.h inc/MantidQtCustomInterfaces/Reflectometry/ReflTableSchema.h inc/MantidQtCustomInterfaces/Reflectometry/ReflTransferStrategy.h @@ -412,6 +417,7 @@ set ( MOC_FILES inc/MantidQtCustomInterfaces/Background.h inc/MantidQtCustomInterfaces/Reflectometry/QtReflRunsTabView.h inc/MantidQtCustomInterfaces/Reflectometry/QtReflSaveTabView.h inc/MantidQtCustomInterfaces/Reflectometry/QtReflSettingsTabView.h + inc/MantidQtCustomInterfaces/Reflectometry/QtReflSettingsView.h inc/MantidQtCustomInterfaces/SampleTransmission.h inc/MantidQtCustomInterfaces/SANSBackgroundCorrectionWidget.h inc/MantidQtCustomInterfaces/SANSAddFiles.h @@ -489,6 +495,7 @@ set ( UI_FILES inc/MantidQtCustomInterfaces/DataComparison.ui inc/MantidQtCustomInterfaces/Reflectometry/ReflRunsTabWidget.ui inc/MantidQtCustomInterfaces/Reflectometry/ReflSaveTabWidget.ui inc/MantidQtCustomInterfaces/Reflectometry/ReflSettingsTabWidget.ui + inc/MantidQtCustomInterfaces/Reflectometry/ReflSettingsWidget.ui inc/MantidQtCustomInterfaces/Reflectometry/ReflWindow.ui inc/MantidQtCustomInterfaces/SampleTransmission.ui inc/MantidQtCustomInterfaces/SANSBackgroundCorrectionWidget.ui @@ -536,6 +543,7 @@ set ( TEST_FILES ReflNexusMeasurementItemSourceTest.h ReflRunsTabPresenterTest.h ReflSaveTabPresenterTest.h + ReflSettingsPresenterTest.h ReflSettingsTabPresenterTest.h StackOfImagesDirsTest.h TomographyIfaceModelTest.h diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/IReflMainWindowPresenter.h b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/IReflMainWindowPresenter.h index e3c84ecf44274434ffa031361594b6614f4abd2d..7b6b9e136e96780472997e7db3fb8125e1716392 100644 --- a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/IReflMainWindowPresenter.h +++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/IReflMainWindowPresenter.h @@ -39,11 +39,11 @@ public: /// Destructor virtual ~IReflMainWindowPresenter(){}; /// Pre-processing - virtual std::string getTransmissionOptions() const = 0; + virtual std::string getTransmissionOptions(int group) const = 0; /// Processing - virtual std::string getReductionOptions() const = 0; + virtual std::string getReductionOptions(int group) const = 0; /// Post-processing - virtual std::string getStitchOptions() const = 0; + virtual std::string getStitchOptions(int group) const = 0; /// Dialog/Prompt methods virtual std::string askUserString(const std::string &prompt, const std::string &title, diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/IReflRunsTabPresenter.h b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/IReflRunsTabPresenter.h index 77a0380e22dc57e0693aac8cd3533de216f3e8e9..50bbcf9ea26345d99015e8400f203dee611de2d1 100644 --- a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/IReflRunsTabPresenter.h +++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/IReflRunsTabPresenter.h @@ -42,7 +42,8 @@ public: SearchFlag, ICATSearchCompleteFlag, TransferFlag, - InstrumentChangedFlag + InstrumentChangedFlag, + GroupChangedFlag }; // Tell the presenter something happened diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/IReflRunsTabView.h b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/IReflRunsTabView.h index 3249d5926ab3bb7c2c4ae37267633daa9c4a384d..8fcc04d7f951c699c457feace4aafa34cf8372d0 100644 --- a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/IReflRunsTabView.h +++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/IReflRunsTabView.h @@ -71,6 +71,7 @@ public: virtual std::string getSearchInstrument() const = 0; virtual std::string getSearchString() const = 0; virtual std::string getTransferMethod() const = 0; + virtual int getSelectedGroup() const = 0; virtual IReflRunsTabPresenter *getPresenter() const = 0; virtual boost::shared_ptr<MantidQt::API::AlgorithmRunner> diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/IReflSettingsPresenter.h b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/IReflSettingsPresenter.h new file mode 100644 index 0000000000000000000000000000000000000000..25d6b7ff8db957657b5e4d039b790f7bdbf96c21 --- /dev/null +++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/IReflSettingsPresenter.h @@ -0,0 +1,56 @@ +#ifndef MANTID_CUSTOMINTERFACES_IREFLSETTINGSPRESENTER_H +#define MANTID_CUSTOMINTERFACES_IREFLSETTINGSPRESENTER_H + +#include <string> + +namespace MantidQt { +namespace CustomInterfaces { + +class IReflMainWindowPresenter; + +/** @class IReflSettingsPresenter + +IReflSettingsPresenter is an interface which defines the functions that need +to be implemented by a concrete 'Settings' presenter + +Copyright © 2011-16 ISIS Rutherford Appleton Laboratory, NScD Oak Ridge +National Laboratory & European Spallation Source + +This file is part of Mantid. + +Mantid is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 3 of the License, or +(at your option) any later version. + +Mantid is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. + +File change history is stored at: <https://github.com/mantidproject/mantid>. +Code Documentation is available at: <http://doxygen.mantidproject.org> +*/ +class IReflSettingsPresenter { +public: + virtual ~IReflSettingsPresenter(){}; + /// Pre-processing + virtual std::string getTransmissionOptions() const = 0; + /// Processing + virtual std::string getReductionOptions() const = 0; + /// Post-processing + virtual std::string getStitchOptions() const = 0; + + enum Flag { ExpDefaultsFlag, InstDefaultsFlag }; + + /// Tell the presenter something happened + virtual void notify(IReflSettingsPresenter::Flag flag) = 0; + /// Set current instrument name + virtual void setInstrumentName(const std::string &instName) = 0; +}; +} +} +#endif /* MANTID_CUSTOMINTERFACES_IREFLSETTINGSPRESENTER_H */ diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/IReflSettingsTabPresenter.h b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/IReflSettingsTabPresenter.h index f00b18d1476ff9d35ae313d8849add441d4d74fc..89845e59a881531f4264d2360acf639255bc5e0a 100644 --- a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/IReflSettingsTabPresenter.h +++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/IReflSettingsTabPresenter.h @@ -37,21 +37,14 @@ Code Documentation is available at: <http://doxygen.mantidproject.org> class IReflSettingsTabPresenter { public: virtual ~IReflSettingsTabPresenter(){}; - /// Accept a main presenter - virtual void acceptMainPresenter(IReflMainWindowPresenter *mainPresenter) = 0; /// Pre-processing - virtual std::string getTransmissionOptions() const = 0; + virtual std::string getTransmissionOptions(int group) const = 0; /// Processing - virtual std::string getReductionOptions() const = 0; + virtual std::string getReductionOptions(int group) const = 0; /// Post-processing - virtual std::string getStitchOptions() const = 0; - - enum Flag { ExpDefaultsFlag, InstDefaultsFlag }; - - /// Tell the presenter something happened - virtual void notify(IReflSettingsTabPresenter::Flag flag) = 0; + virtual std::string getStitchOptions(int group) const = 0; /// Set current instrument name - virtual void setInstrumentName(const std::string instName) = 0; + virtual void setInstrumentName(const std::string &instName) = 0; }; } } diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/IReflSettingsTabView.h b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/IReflSettingsView.h similarity index 82% rename from MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/IReflSettingsTabView.h rename to MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/IReflSettingsView.h index ff159575cb1d63dce69385112f208d956d332925..7d87dab566cb7dc80baa59880712a0690c110c06 100644 --- a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/IReflSettingsTabView.h +++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/IReflSettingsView.h @@ -1,5 +1,5 @@ -#ifndef MANTID_CUSTOMINTERFACES_IREFLSETTINGSTABVIEW_H -#define MANTID_CUSTOMINTERFACES_IREFLSETTINGSTABVIEW_H +#ifndef MANTID_CUSTOMINTERFACES_IREFLSETTINGSVIEW_H +#define MANTID_CUSTOMINTERFACES_IREFLSETTINGSVIEW_H #include "MantidQtCustomInterfaces/DllConfig.h" #include <vector> @@ -9,13 +9,12 @@ namespace MantidQt { namespace CustomInterfaces { -class IReflSettingsTabPresenter; +class IReflSettingsPresenter; -/** @class IReflSettingsTabView +/** @class IReflSettingsView -IReflSettingsTabView is the base view class for the Reflectometry Interface. It -contains -no QT specific functionality as that should be handled by a subclass. +IReflSettingsView is the base view class for the Reflectometry settings. It +contains no QT specific functionality as that should be handled by a subclass. Copyright © 2011-16 ISIS Rutherford Appleton Laboratory, NScD Oak Ridge National Laboratory & European Spallation Source @@ -39,14 +38,14 @@ File change history is stored at: <https://github.com/mantidproject/mantid>. Code Documentation is available at: <http://doxygen.mantidproject.org> */ -class DLLExport IReflSettingsTabView { +class DLLExport IReflSettingsView { public: /// Constructor - IReflSettingsTabView(){}; + IReflSettingsView(){}; /// Destructor - virtual ~IReflSettingsTabView(){}; + virtual ~IReflSettingsView(){}; /// Returns the presenter managing this view - virtual IReflSettingsTabPresenter *getPresenter() const = 0; + virtual IReflSettingsPresenter *getPresenter() const = 0; /// Post-processing virtual std::string getStitchOptions() const = 0; @@ -84,4 +83,4 @@ public: }; } } -#endif /* MANTID_CUSTOMINTERFACES_IREFLRUNSTABVIEW_H */ +#endif /* MANTID_CUSTOMINTERFACES_IREFLSETTINGSVIEW_H */ diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/QtReflRunsTabView.h b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/QtReflRunsTabView.h index deff40d87bf60fa744e2120c315771cc5702fa84..50f2e7a11992fbcd896881590fa4a8086f66b135 100644 --- a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/QtReflRunsTabView.h +++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/QtReflRunsTabView.h @@ -88,6 +88,7 @@ public: std::string getSearchInstrument() const override; std::string getSearchString() const override; std::string getTransferMethod() const override; + int getSelectedGroup() const override; IReflRunsTabPresenter *getPresenter() const override; boost::shared_ptr<MantidQt::API::AlgorithmRunner> @@ -118,6 +119,7 @@ private slots: void slitCalculatorTriggered(); void icatSearchComplete(); void instrumentChanged(int index); + void groupChanged(); void showSearchContextMenu(const QPoint &pos); }; diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/QtReflSettingsTabView.h b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/QtReflSettingsTabView.h index 4ba8ca4437a98f76bc59633e6647fefe8ed28c76..3f0df4151e6efbb778cdbeee07e056eb32e06596 100644 --- a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/QtReflSettingsTabView.h +++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/QtReflSettingsTabView.h @@ -1,7 +1,7 @@ #ifndef MANTID_CUSTOMINTERFACES_QTREFLSETTINGSTABVIEW_H_ #define MANTID_CUSTOMINTERFACES_QTREFLSETTINGSTABVIEW_H_ -#include "MantidQtCustomInterfaces/Reflectometry/IReflSettingsTabView.h" +#include "MantidQtCustomInterfaces/DllConfig.h" #include "ui_ReflSettingsTabWidget.h" #include <memory> @@ -35,7 +35,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. File change history is stored at: <https://github.com/mantidproject/mantid> Code Documentation is available at: <http://doxygen.mantidproject.org> */ -class QtReflSettingsTabView : public QWidget, public IReflSettingsTabView { +class MANTIDQT_CUSTOMINTERFACES_DLL QtReflSettingsTabView : public QWidget { Q_OBJECT public: /// Constructor @@ -43,61 +43,7 @@ public: /// Destructor ~QtReflSettingsTabView() override; /// Returns the presenter managing this view - IReflSettingsTabPresenter *getPresenter() const override; - /// Returns global options for 'Stitch1DMany' - std::string getStitchOptions() const override; - /// Return selected analysis mode - std::string getAnalysisMode() const override; - /// Return direct beam - std::string getDirectBeam() const override; - /// Return transmission runs - std::string getTransmissionRuns() const override; - /// Return selected polarisation corrections - std::string getPolarisationCorrections() const override; - /// Return CRho - std::string getCRho() const override; - /// Return CAlpha - std::string getCAlpha() const override; - /// Return CAp - std::string getCAp() const override; - /// Return Cpp - std::string getCPp() const override; - /// Return momentum transfer limits - std::string getMomentumTransferStep() const override; - /// Return scale factor - std::string getScaleFactor() const override; - /// Return integrated monitors option - std::string getIntMonCheck() const override; - /// Return monitor integral wavelength min - std::string getMonitorIntegralMin() const override; - /// Return monitor integral wavelength max - std::string getMonitorIntegralMax() const override; - /// Return monitor background wavelength min - std::string getMonitorBackgroundMin() const override; - /// Return monitor background wavelength max - std::string getMonitorBackgroundMax() const override; - /// Return wavelength min - std::string getLambdaMin() const override; - /// Return wavelength max - std::string getLambdaMax() const override; - /// Return I0MonitorIndex - std::string getI0MonitorIndex() const override; - /// Return processing instructions - std::string getProcessingInstructions() const override; - /// Set default values for experiment and instrument settings - void setExpDefaults(const std::vector<std::string> &) const override; - void setInstDefaults(const std::vector<double> &) const override; - - /// Creates hints for 'Stitch1DMany' - void - createStitchHints(const std::map<std::string, std::string> &hints) override; - /// Sets enabled status for polarisation corrections and parameters - void setPolarisationOptionsEnabled(bool enable) const override; - -public slots: - /// Request presenter to obtain default values for settings - void requestExpDefaults() const; - void requestInstDefaults() const; + IReflSettingsTabPresenter *getPresenter() const; private: /// Initialise the interface diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/QtReflSettingsView.h b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/QtReflSettingsView.h new file mode 100644 index 0000000000000000000000000000000000000000..8df499be3be7e380e04c85cf831307d10cecddcb --- /dev/null +++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/QtReflSettingsView.h @@ -0,0 +1,115 @@ +#ifndef MANTID_CUSTOMINTERFACES_QTREFLSETTINGSVIEW_H_ +#define MANTID_CUSTOMINTERFACES_QTREFLSETTINGSVIEW_H_ + +#include "MantidQtCustomInterfaces/Reflectometry/IReflSettingsView.h" +#include "ui_ReflSettingsWidget.h" +#include <memory> + +namespace MantidQt { +namespace CustomInterfaces { + +// Forward decs +class IReflSettingsPresenter; + +/** QtReflSettingsView : Provides an interface for the "Settings" widget in the +Reflectometry (Polref) interface. + +Copyright © 2016 ISIS Rutherford Appleton Laboratory, NScD Oak Ridge +National Laboratory & European Spallation Source + +This file is part of Mantid. + +Mantid is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 3 of the License, or +(at your option) any later version. + +Mantid is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. + +File change history is stored at: <https://github.com/mantidproject/mantid> +Code Documentation is available at: <http://doxygen.mantidproject.org> +*/ +class QtReflSettingsView : public QWidget, public IReflSettingsView { + Q_OBJECT +public: + /// Constructor + QtReflSettingsView(QWidget *parent = 0); + /// Destructor + ~QtReflSettingsView() override; + /// Returns the presenter managing this view + IReflSettingsPresenter *getPresenter() const override; + /// Returns global options for 'Stitch1DMany' + std::string getStitchOptions() const override; + /// Return selected analysis mode + std::string getAnalysisMode() const override; + /// Return direct beam + std::string getDirectBeam() const override; + /// Return transmission runs + std::string getTransmissionRuns() const override; + /// Return selected polarisation corrections + std::string getPolarisationCorrections() const override; + /// Return CRho + std::string getCRho() const override; + /// Return CAlpha + std::string getCAlpha() const override; + /// Return CAp + std::string getCAp() const override; + /// Return Cpp + std::string getCPp() const override; + /// Return momentum transfer limits + std::string getMomentumTransferStep() const override; + /// Return scale factor + std::string getScaleFactor() const override; + /// Return integrated monitors option + std::string getIntMonCheck() const override; + /// Return monitor integral wavelength min + std::string getMonitorIntegralMin() const override; + /// Return monitor integral wavelength max + std::string getMonitorIntegralMax() const override; + /// Return monitor background wavelength min + std::string getMonitorBackgroundMin() const override; + /// Return monitor background wavelength max + std::string getMonitorBackgroundMax() const override; + /// Return wavelength min + std::string getLambdaMin() const override; + /// Return wavelength max + std::string getLambdaMax() const override; + /// Return I0MonitorIndex + std::string getI0MonitorIndex() const override; + /// Return processing instructions + std::string getProcessingInstructions() const override; + /// Set default values for experiment and instrument settings + void setExpDefaults(const std::vector<std::string> &) const override; + void setInstDefaults(const std::vector<double> &) const override; + + /// Creates hints for 'Stitch1DMany' + void + createStitchHints(const std::map<std::string, std::string> &hints) override; + /// Sets enabled status for polarisation corrections and parameters + void setPolarisationOptionsEnabled(bool enable) const override; + +public slots: + /// Request presenter to obtain default values for settings + void requestExpDefaults() const; + void requestInstDefaults() const; + +private: + /// Initialise the interface + void initLayout(); + + /// The widget + Ui::ReflSettingsWidget m_ui; + /// The presenter + std::unique_ptr<IReflSettingsPresenter> m_presenter; +}; + +} // namespace Mantid +} // namespace CustomInterfaces + +#endif /* MANTID_CUSTOMINTERFACES_QTREFLSETTINGSVIEW_H_ */ diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/ReflMainWindowPresenter.h b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/ReflMainWindowPresenter.h index f833788dc3cf5d08cbc40a9a80a5562005daf1ac..fca9cb6c204b7f69fc70064322234b5be1d98d19 100644 --- a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/ReflMainWindowPresenter.h +++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/ReflMainWindowPresenter.h @@ -49,11 +49,11 @@ public: /// Destructor ~ReflMainWindowPresenter() override; /// Returns global options for 'CreateTransmissionWorkspaceAuto' - std::string getTransmissionOptions() const override; + std::string getTransmissionOptions(int group) const override; /// Returns global options for 'ReflectometryReductionOneAuto' - std::string getReductionOptions() const override; + std::string getReductionOptions(int group) const override; /// Returns global options for 'Stitch1DMany' - std::string getStitchOptions() const override; + std::string getStitchOptions(int group) const override; /// Dialog/Prompt methods std::string askUserString(const std::string &prompt, const std::string &title, diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/ReflRunsTabPresenter.h b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/ReflRunsTabPresenter.h index 4c859f25e3068f75f33a4ca7169b4283537dc60e..7696f2e002a7d5ff9870dd918b62dea2e7011ee0 100644 --- a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/ReflRunsTabPresenter.h +++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/ReflRunsTabPresenter.h @@ -59,7 +59,7 @@ class MANTIDQT_CUSTOMINTERFACES_DLL ReflRunsTabPresenter public: ReflRunsTabPresenter(IReflRunsTabView *mainView, ProgressableView *progressView, - DataProcessorPresenter *tablePresenter, + std::vector<DataProcessorPresenter *> tablePresenter, boost::shared_ptr<IReflSearcher> searcher = boost::shared_ptr<IReflSearcher>()); ~ReflRunsTabPresenter() override; @@ -85,8 +85,8 @@ protected: IReflRunsTabView *m_view; /// The progress view ProgressableView *m_progressView; - /// The data processor presenter - DataProcessorPresenter *m_tablePresenter; + /// The data processor presenters stored in a vector + std::vector<DataProcessorPresenter *> m_tablePresenters; /// The main presenter IReflMainWindowPresenter *m_mainPresenter; /// The search implementation @@ -98,6 +98,8 @@ protected: void pushCommands(); private: + std::string m_currentTransferMethod; + static const std::string LegacyTransferMethod; static const std::string MeasureTransferMethod; diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/ReflRunsTabWidget.ui b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/ReflRunsTabWidget.ui index 402378410e06a608daae5babb22c2070978a844a..0b93c3bb4b7974d0fd459cf4dc0a6b74b26bab4d 100644 --- a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/ReflRunsTabWidget.ui +++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/ReflRunsTabWidget.ui @@ -246,6 +246,10 @@ <property name="margin"> <number>1</number> </property> + <item> + <widget class="QToolBox" name="toolbox"> + </widget> + </item> </layout> </widget> </widget> diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/ReflSettingsPresenter.h b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/ReflSettingsPresenter.h new file mode 100644 index 0000000000000000000000000000000000000000..3d2daf0bb1dd99e74446e23f38114ae3cc5f94b4 --- /dev/null +++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/ReflSettingsPresenter.h @@ -0,0 +1,74 @@ +#ifndef MANTID_CUSTOMINTERFACES_REFLSETTINGSPRESENTER_H +#define MANTID_CUSTOMINTERFACES_REFLSETTINGSPRESENTER_H + +#include "MantidQtCustomInterfaces/DllConfig.h" +#include "MantidQtCustomInterfaces/Reflectometry/IReflSettingsPresenter.h" +#include "MantidAPI/IAlgorithm_fwd.h" +#include "MantidGeometry/Instrument_fwd.h" + +namespace MantidQt { +namespace CustomInterfaces { + +// Forward decs +class IReflSettingsView; + +/** @class ReflSettingsPresenter + +ReflSettingsPresenter is a presenter class for the widget 'Settings' in the +Reflectometry (Polref) Interface. + +Copyright © 2011-16 ISIS Rutherford Appleton Laboratory, NScD Oak Ridge +National Laboratory & European Spallation Source + +This file is part of Mantid. + +Mantid is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 3 of the License, or +(at your option) any later version. + +Mantid is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. + +File change history is stored at: <https://github.com/mantidproject/mantid>. +Code Documentation is available at: <http://doxygen.mantidproject.org> +*/ +class MANTIDQT_CUSTOMINTERFACES_DLL ReflSettingsPresenter + : public IReflSettingsPresenter { +public: + /// Constructor + ReflSettingsPresenter(IReflSettingsView *view); + /// Destructor + ~ReflSettingsPresenter() override; + void notify(IReflSettingsPresenter::Flag flag) override; + void setInstrumentName(const std::string &instName) override; + + /// Returns global options for 'CreateTransmissionWorkspaceAuto' + std::string getTransmissionOptions() const override; + /// Returns global options for 'ReflectometryReductionOneAuto' + std::string getReductionOptions() const override; + /// Returns global options for 'Stitch1DMany' + std::string getStitchOptions() const override; + +private: + void createStitchHints(); + void getExpDefaults(); + void getInstDefaults(); + Mantid::API::IAlgorithm_sptr createReductionAlg(); + Mantid::Geometry::Instrument_const_sptr + createEmptyInstrument(const std::string &instName); + std::string getTransmissionRuns() const; + + /// The view we are managing + IReflSettingsView *m_view; + /// Name of the current instrument in use + std::string m_currentInstrumentName; +}; +} +} +#endif /* MANTID_CUSTOMINTERFACES_REFLSETTINGSPRESENTER_H */ diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/ReflSettingsTabPresenter.h b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/ReflSettingsTabPresenter.h index 185428ebee3fa6dcd490f52a84428b78443309d2..ce53514041ff2775d080ea874c8a1bc85702873b 100644 --- a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/ReflSettingsTabPresenter.h +++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/ReflSettingsTabPresenter.h @@ -3,18 +3,14 @@ #include "MantidQtCustomInterfaces/DllConfig.h" #include "MantidQtCustomInterfaces/Reflectometry/IReflSettingsTabPresenter.h" -#include "MantidAPI/IAlgorithm.h" -#include "MantidGeometry/Instrument.h" +#include <vector> namespace MantidQt { namespace CustomInterfaces { -using namespace Mantid::API; -using namespace Mantid::Geometry; - // Forward decs class IReflMainWindowPresenter; -class IReflSettingsTabView; +class IReflSettingsPresenter; /** @class ReflSettingsTabPresenter @@ -46,35 +42,22 @@ class MANTIDQT_CUSTOMINTERFACES_DLL ReflSettingsTabPresenter : public IReflSettingsTabPresenter { public: /// Constructor - ReflSettingsTabPresenter(IReflSettingsTabView *view); + ReflSettingsTabPresenter(std::vector<IReflSettingsPresenter *> presenters); /// Destructor ~ReflSettingsTabPresenter() override; - /// Accept a main presenter - void acceptMainPresenter(IReflMainWindowPresenter *mainPresenter) override; - void notify(IReflSettingsTabPresenter::Flag flag) override; - void setInstrumentName(const std::string instName) override; + /// Set the instrument name + void setInstrumentName(const std::string &instName) override; /// Returns global options for 'CreateTransmissionWorkspaceAuto' - std::string getTransmissionOptions() const override; + std::string getTransmissionOptions(int group) const override; /// Returns global options for 'ReflectometryReductionOneAuto' - std::string getReductionOptions() const override; + std::string getReductionOptions(int group) const override; /// Returns global options for 'Stitch1DMany' - std::string getStitchOptions() const override; + std::string getStitchOptions(int group) const override; private: - void createStitchHints(); - void getExpDefaults(); - void getInstDefaults(); - IAlgorithm_sptr createReductionAlg(); - Instrument_const_sptr createEmptyInstrument(std::string instName); - std::string getTransmissionRuns() const; - - /// The view we are managing - IReflSettingsTabView *m_view; - /// The main presenter - IReflMainWindowPresenter *m_mainPresenter; - /// Name of the current instrument in use - std::string m_currentInstrumentName; + /// The presenters for each group as a vector + std::vector<IReflSettingsPresenter *> m_settingsPresenters; }; } } diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/ReflSettingsTabWidget.ui b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/ReflSettingsTabWidget.ui index 968b04ed0635dcf8cad15aaebe0925fe5dbbd8da..f015e7a8a514ad8074580efb0827432b7106399d 100644 --- a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/ReflSettingsTabWidget.ui +++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/ReflSettingsTabWidget.ui @@ -18,522 +18,7 @@ <number>5</number> </property> <item> - <widget class="QGroupBox" name="expSettingsGroup"> - <property name="title"> - <string>Experiment Settings</string> - </property> - <property name="checkable"> - <bool>true</bool> - </property> - <layout class="QHBoxLayout" name="expSettingsLayoutContainer"> - <item> - <layout class="QGridLayout" name="expSettingsLayout0"> - <property name="margin"> - <number>10</number> - </property> - <item row="0" column="0"> - <widget class="QLabel" name="analysisModeLabel"> - <property name="text"> - <string>AnalysisMode</string> - </property> - </widget> - </item> - <item row="0" column="1"> - <widget class="QComboBox" name="analysisModeComboBox"> - <item> - <property name="text"> - <string>PointDetectorAnalysis</string> - </property> - </item> - <item> - <property name="text"> - <string>MultiDetectorAnalysis</string> - </property> - </item> - </widget> - </item> - <item row="0" column="2"> - <widget class="QLabel" name="expSettingsDirectBeamLabel"> - <property name="text"> - <string>DirectBeam</string> - </property> - </widget> - </item> - <item row="0" column="3"> - <widget class="QLineEdit" name="directBeamEdit"/> - </item> - <item row="0" column="4"> - <spacer name="expSettings0Spacer0"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>20</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item row="1" column="0"> - <widget class="QLabel" name="transmissionRunsLabel"> - <property name="text"> - <string>Transmission run(s)</string> - </property> - </widget> - </item> - <item row="1" column="1"> - <widget class="QLineEdit" name="transmissionRunsEdit"/> - </item> - <item row="1" column="2"> - <spacer name="expSettings0Spacer1"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>20</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item row="2" column="0"> - <widget class="QLabel" name="startOverlapLabel"> - <property name="text"> - <string>StartOverlap</string> - </property> - </widget> - </item> - <item row="2" column="1"> - <widget class="QLineEdit" name="startOverlapEdit"/> - </item> - <item row="2" column="2"> - <widget class="QLabel" name="endOverlapLabel"> - <property name="text"> - <string>EndOverlap</string> - </property> - </widget> - </item> - <item row="2" column="3"> - <widget class="QLineEdit" name="endOverlapEdit"/> - </item> - <item row="2" column="4"> - <spacer name="expSettings0Spacer2"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>20</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item row="3" column="0"> - <widget class="QLabel" name="polCorrLabel"> - <property name="text"> - <string>PolarisationCorrections</string> - </property> - </widget> - </item> - <item row="3" column="1"> - <widget class="QComboBox" name="polCorrComboBox"> - <item> - <property name="text"> - <string>None</string> - </property> - </item> - <item> - <property name="text"> - <string>PA</string> - </property> - </item> - <item> - <property name="text"> - <string>PNR</string> - </property> - </item> - </widget> - </item> - <item row="3" column="2"> - <spacer name="expSettings0Spacer3"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item row="4" column="0"> - <widget class="QLabel" name="CRhoLabel"> - <property name="text"> - <string>CRho</string> - </property> - </widget> - </item> - <item row="4" column="1"> - <widget class="QLineEdit" name="CRhoEdit"/> - </item> - <item row="4" column="2"> - <widget class="QLabel" name="CAlphaLabel"> - <property name="text"> - <string>CAlpha</string> - </property> - </widget> - </item> - <item row="4" column="3"> - <widget class="QLineEdit" name="CAlphaEdit"/> - </item> - <item row="4" column="4"> - <spacer name="expSettings0Spacer4"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>20</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item row="5" column="0"> - <widget class="QLabel" name="CApLabel"> - <property name="text"> - <string>CAp</string> - </property> - </widget> - </item> - <item row="5" column="1"> - <widget class="QLineEdit" name="CApEdit"/> - </item> - <item row="5" column="2"> - <widget class="QLabel" name="CPpLabel"> - <property name="text"> - <string>CPp</string> - </property> - </widget> - </item> - <item row="5" column="3"> - <widget class="QLineEdit" name="CPpEdit"/> - </item> - <item row="5" column="4"> - <spacer name="expSettings0Spacer5"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>20</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item row="6" column="0"> - <widget class="QLabel" name="momentumTransferStepLabel"> - <property name="text"> - <string>dQ/Q</string> - </property> - </widget> - </item> - <item row="6" column="1"> - <widget class="QLineEdit" name="momentumTransferStepEdit"/> - </item> - <item row="6" column="2"> - <widget class="QLabel" name="scaleFactorLabel"> - <property name="text"> - <string>Scale</string> - </property> - </widget> - </item> - <item row="6" column="3"> - <widget class="QLineEdit" name="scaleFactorEdit"/> - </item> - <item row="6" column="4"> - <spacer name="expSettings0Spacer6"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>20</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item row="7" column="0"> - <widget class="QLabel" name="stitchLabel"> - <property name="text"> - <string>Stitch1DMany</string> - </property> - </widget> - </item> - <item row="7" column="4"> - <spacer name="expSettings0Spacer7"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>20</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - </layout> - </item> - <item> - <layout class="QGridLayout" name="expSettingsLayout1"> - <property name="margin"> - <number>10</number> - </property> - <item row="0" column="0"> - <widget class="QPushButton" name="getExpDefaultsButton"> - <property name="fixedWidth"> - <number>70</number> - </property> - <property name="fixedHeight"> - <number>100</number> - </property> - <layout class="QHBoxLayout" name="getExpDefaultsButtonLayout"> - <item> - <widget class="QLabel" name="getExpDefaultsButtonLabel"> - <property name="wordWrap"> - <bool>true</bool> - </property> - <property name="alignment"> - <set>Qt::AlignCenter</set> - </property> - <property name="text"> - <string>Get Defaults</string> - </property> - </widget> - </item> - </layout> - </widget> - </item> - </layout> - </item> - </layout> - </widget> - </item> - <item> - <widget class="QGroupBox" name="instSettingsGroup"> - <property name="title"> - <string>Instrument Settings</string> - </property> - <property name="checkable"> - <bool>true</bool> - </property> - <layout class="QHBoxLayout" name="instSettingsLayoutContainer"> - <item> - <layout class="QGridLayout" name="instSettingsLayout0"> - <property name="margin"> - <number>10</number> - </property> - <item row="0" column="0"> - <widget class="QLabel" name="intMonCheckLabel"> - <property name="text"> - <string>IntegratedMonitors</string> - </property> - </widget> - </item> - <item row="0" column="1"> - <widget class="QCheckBox" name="intMonCheckBox"> - <property name="checkState"> - <set>Qt::Checked</set> - </property> - </widget> - </item> - <item row="0" column="2"> - <spacer name="instSettings0Spacer0"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item row="1" column="0"> - <widget class="QLabel" name="monIntMinLabel"> - <property name="text"> - <string>MonitorIntegralMin</string> - </property> - </widget> - </item> - <item row="1" column="1"> - <widget class="QLineEdit" name="monIntMinEdit"/> - </item> - <item row="1" column="2"> - <widget class="QLabel" name="monIntMaxLabel"> - <property name="text"> - <string>MonitorIntegralMax</string> - </property> - </widget> - </item> - <item row="1" column="3"> - <widget class="QLineEdit" name="monIntMaxEdit"/> - </item> - <item row="1" column="4"> - <spacer name="instSettings0Spacer1"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item row="2" column="0"> - <widget class="QLabel" name="monBgMinLabel"> - <property name="text"> - <string>MonitorBackgroundMin</string> - </property> - </widget> - </item> - <item row="2" column="1"> - <widget class="QLineEdit" name="monBgMinEdit"/> - </item> - <item row="2" column="2"> - <widget class="QLabel" name="monBgMaxLabel"> - <property name="text"> - <string>MonitorBackgroundMax</string> - </property> - </widget> - </item> - <item row="2" column="3"> - <widget class="QLineEdit" name="monBgMaxEdit"/> - </item> - <item row="2" column="4"> - <spacer name="instSettings0Spacer2"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item row="3" column="0"> - <widget class="QLabel" name="lamMinLabel"> - <property name="text"> - <string>LambdaMin</string> - </property> - </widget> - </item> - <item row="3" column="1"> - <widget class="QLineEdit" name="lamMinEdit"/> - </item> - <item row="3" column="2"> - <widget class="QLabel" name="lamMaxLabel"> - <property name="text"> - <string>LambdaMax</string> - </property> - </widget> - </item> - <item row="3" column="3"> - <widget class="QLineEdit" name="lamMaxEdit"/> - </item> - <item row="3" column="4"> - <spacer name="instSettings0Spacer3"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item row="4" column="0"> - <widget class="QLabel" name="I0MonIndexLabel"> - <property name="text"> - <string>I0MonitorIndex</string> - </property> - </widget> - </item> - <item row="4" column="1"> - <widget class="QLineEdit" name="I0MonIndexEdit"/> - </item> - <item row="4" column="2"> - <widget class="QLabel" name="procInstLabel"> - <property name="text"> - <string>ProcessingInstructions</string> - </property> - </widget> - </item> - <item row="4" column="3"> - <widget class="QLineEdit" name="procInstEdit"/> - </item> - <item row="4" column="4"> - <spacer name="instSettings0Spacer4"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - </layout> - </item> - <item> - <layout class="QGridLayout" name="instSettingsLayout1"> - <property name="margin"> - <number>10</number> - </property> - <item row="0" column="0"> - <widget class="QPushButton" name="getInstDefaultsButton"> - <property name="fixedWidth"> - <number>70</number> - </property> - <property name="fixedHeight"> - <number>100</number> - </property> - <layout class="QHBoxLayout" name="getInstDefaultsButtonLayout"> - <item> - <widget class="QLabel" name="getInstDefaultsButtonLabel"> - <property name="wordWrap"> - <bool>true</bool> - </property> - <property name="alignment"> - <set>Qt::AlignCenter</set> - </property> - <property name="text"> - <string>Get Defaults</string> - </property> - </widget> - </item> - </layout> - </widget> - </item> - </layout> - </item> - </layout> + <widget class="QToolBox" name="toolbox"> </widget> </item> </layout> diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/ReflSettingsWidget.ui b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/ReflSettingsWidget.ui new file mode 100644 index 0000000000000000000000000000000000000000..ce85e5f7ca844b38d4ef757327190194dbb603f3 --- /dev/null +++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/ReflSettingsWidget.ui @@ -0,0 +1,545 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>ReflSettingsWidget</class> + <widget class="QWidget" name="ReflSettingsWidget"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>959</width> + <height>346</height> + </rect> + </property> + <property name="windowTitle"> + <string>Settings Tab</string> + </property> + <layout class="QVBoxLayout" name="settingsMainLayout"> + <property name="margin"> + <number>5</number> + </property> + <item> + <widget class="QGroupBox" name="expSettingsGroup"> + <property name="title"> + <string>Experiment Settings</string> + </property> + <property name="checkable"> + <bool>true</bool> + </property> + <layout class="QHBoxLayout" name="expSettingsLayoutContainer"> + <item> + <layout class="QGridLayout" name="expSettingsLayout0"> + <property name="margin"> + <number>10</number> + </property> + <item row="0" column="0"> + <widget class="QLabel" name="analysisModeLabel"> + <property name="text"> + <string>AnalysisMode</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QComboBox" name="analysisModeComboBox"> + <item> + <property name="text"> + <string>PointDetectorAnalysis</string> + </property> + </item> + <item> + <property name="text"> + <string>MultiDetectorAnalysis</string> + </property> + </item> + </widget> + </item> + <item row="0" column="2"> + <widget class="QLabel" name="expSettingsDirectBeamLabel"> + <property name="text"> + <string>DirectBeam</string> + </property> + </widget> + </item> + <item row="0" column="3"> + <widget class="QLineEdit" name="directBeamEdit"/> + </item> + <item row="0" column="4"> + <spacer name="expSettings0Spacer0"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item row="1" column="0"> + <widget class="QLabel" name="transmissionRunsLabel"> + <property name="text"> + <string>Transmission run(s)</string> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QLineEdit" name="transmissionRunsEdit"/> + </item> + <item row="1" column="2"> + <spacer name="expSettings0Spacer1"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item row="2" column="0"> + <widget class="QLabel" name="startOverlapLabel"> + <property name="text"> + <string>StartOverlap</string> + </property> + </widget> + </item> + <item row="2" column="1"> + <widget class="QLineEdit" name="startOverlapEdit"/> + </item> + <item row="2" column="2"> + <widget class="QLabel" name="endOverlapLabel"> + <property name="text"> + <string>EndOverlap</string> + </property> + </widget> + </item> + <item row="2" column="3"> + <widget class="QLineEdit" name="endOverlapEdit"/> + </item> + <item row="2" column="4"> + <spacer name="expSettings0Spacer2"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item row="3" column="0"> + <widget class="QLabel" name="polCorrLabel"> + <property name="text"> + <string>PolarisationCorrections</string> + </property> + </widget> + </item> + <item row="3" column="1"> + <widget class="QComboBox" name="polCorrComboBox"> + <item> + <property name="text"> + <string>None</string> + </property> + </item> + <item> + <property name="text"> + <string>PA</string> + </property> + </item> + <item> + <property name="text"> + <string>PNR</string> + </property> + </item> + </widget> + </item> + <item row="3" column="2"> + <spacer name="expSettings0Spacer3"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item row="4" column="0"> + <widget class="QLabel" name="CRhoLabel"> + <property name="text"> + <string>CRho</string> + </property> + </widget> + </item> + <item row="4" column="1"> + <widget class="QLineEdit" name="CRhoEdit"/> + </item> + <item row="4" column="2"> + <widget class="QLabel" name="CAlphaLabel"> + <property name="text"> + <string>CAlpha</string> + </property> + </widget> + </item> + <item row="4" column="3"> + <widget class="QLineEdit" name="CAlphaEdit"/> + </item> + <item row="4" column="4"> + <spacer name="expSettings0Spacer4"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item row="5" column="0"> + <widget class="QLabel" name="CApLabel"> + <property name="text"> + <string>CAp</string> + </property> + </widget> + </item> + <item row="5" column="1"> + <widget class="QLineEdit" name="CApEdit"/> + </item> + <item row="5" column="2"> + <widget class="QLabel" name="CPpLabel"> + <property name="text"> + <string>CPp</string> + </property> + </widget> + </item> + <item row="5" column="3"> + <widget class="QLineEdit" name="CPpEdit"/> + </item> + <item row="5" column="4"> + <spacer name="expSettings0Spacer5"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item row="6" column="0"> + <widget class="QLabel" name="momentumTransferStepLabel"> + <property name="text"> + <string>dQ/Q</string> + </property> + </widget> + </item> + <item row="6" column="1"> + <widget class="QLineEdit" name="momentumTransferStepEdit"/> + </item> + <item row="6" column="2"> + <widget class="QLabel" name="scaleFactorLabel"> + <property name="text"> + <string>Scale</string> + </property> + </widget> + </item> + <item row="6" column="3"> + <widget class="QLineEdit" name="scaleFactorEdit"/> + </item> + <item row="6" column="4"> + <spacer name="expSettings0Spacer6"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item row="7" column="0"> + <widget class="QLabel" name="stitchLabel"> + <property name="text"> + <string>Stitch1DMany</string> + </property> + </widget> + </item> + <item row="7" column="4"> + <spacer name="expSettings0Spacer7"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + </layout> + </item> + <item> + <layout class="QGridLayout" name="expSettingsLayout1"> + <property name="margin"> + <number>10</number> + </property> + <item row="0" column="0"> + <widget class="QPushButton" name="getExpDefaultsButton"> + <property name="fixedWidth"> + <number>70</number> + </property> + <property name="fixedHeight"> + <number>100</number> + </property> + <layout class="QHBoxLayout" name="getExpDefaultsButtonLayout"> + <item> + <widget class="QLabel" name="getExpDefaultsButtonLabel"> + <property name="wordWrap"> + <bool>true</bool> + </property> + <property name="alignment"> + <set>Qt::AlignCenter</set> + </property> + <property name="text"> + <string>Get Defaults</string> + </property> + </widget> + </item> + </layout> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QGroupBox" name="instSettingsGroup"> + <property name="title"> + <string>Instrument Settings</string> + </property> + <property name="checkable"> + <bool>true</bool> + </property> + <layout class="QHBoxLayout" name="instSettingsLayoutContainer"> + <item> + <layout class="QGridLayout" name="instSettingsLayout0"> + <property name="margin"> + <number>10</number> + </property> + <item row="0" column="0"> + <widget class="QLabel" name="intMonCheckLabel"> + <property name="text"> + <string>IntegratedMonitors</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QCheckBox" name="intMonCheckBox"> + <property name="checkState"> + <set>Qt::Checked</set> + </property> + </widget> + </item> + <item row="0" column="2"> + <spacer name="instSettings0Spacer0"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item row="1" column="0"> + <widget class="QLabel" name="monIntMinLabel"> + <property name="text"> + <string>MonitorIntegralMin</string> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QLineEdit" name="monIntMinEdit"/> + </item> + <item row="1" column="2"> + <widget class="QLabel" name="monIntMaxLabel"> + <property name="text"> + <string>MonitorIntegralMax</string> + </property> + </widget> + </item> + <item row="1" column="3"> + <widget class="QLineEdit" name="monIntMaxEdit"/> + </item> + <item row="1" column="4"> + <spacer name="instSettings0Spacer1"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item row="2" column="0"> + <widget class="QLabel" name="monBgMinLabel"> + <property name="text"> + <string>MonitorBackgroundMin</string> + </property> + </widget> + </item> + <item row="2" column="1"> + <widget class="QLineEdit" name="monBgMinEdit"/> + </item> + <item row="2" column="2"> + <widget class="QLabel" name="monBgMaxLabel"> + <property name="text"> + <string>MonitorBackgroundMax</string> + </property> + </widget> + </item> + <item row="2" column="3"> + <widget class="QLineEdit" name="monBgMaxEdit"/> + </item> + <item row="2" column="4"> + <spacer name="instSettings0Spacer2"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item row="3" column="0"> + <widget class="QLabel" name="lamMinLabel"> + <property name="text"> + <string>LambdaMin</string> + </property> + </widget> + </item> + <item row="3" column="1"> + <widget class="QLineEdit" name="lamMinEdit"/> + </item> + <item row="3" column="2"> + <widget class="QLabel" name="lamMaxLabel"> + <property name="text"> + <string>LambdaMax</string> + </property> + </widget> + </item> + <item row="3" column="3"> + <widget class="QLineEdit" name="lamMaxEdit"/> + </item> + <item row="3" column="4"> + <spacer name="instSettings0Spacer3"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item row="4" column="0"> + <widget class="QLabel" name="I0MonIndexLabel"> + <property name="text"> + <string>I0MonitorIndex</string> + </property> + </widget> + </item> + <item row="4" column="1"> + <widget class="QLineEdit" name="I0MonIndexEdit"/> + </item> + <item row="4" column="2"> + <widget class="QLabel" name="procInstLabel"> + <property name="text"> + <string>ProcessingInstructions</string> + </property> + </widget> + </item> + <item row="4" column="3"> + <widget class="QLineEdit" name="procInstEdit"/> + </item> + <item row="4" column="4"> + <spacer name="instSettings0Spacer4"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + </layout> + </item> + <item> + <layout class="QGridLayout" name="instSettingsLayout1"> + <property name="margin"> + <number>10</number> + </property> + <item row="0" column="0"> + <widget class="QPushButton" name="getInstDefaultsButton"> + <property name="fixedWidth"> + <number>70</number> + </property> + <property name="fixedHeight"> + <number>100</number> + </property> + <layout class="QHBoxLayout" name="getInstDefaultsButtonLayout"> + <item> + <widget class="QLabel" name="getInstDefaultsButtonLabel"> + <property name="wordWrap"> + <bool>true</bool> + </property> + <property name="alignment"> + <set>Qt::AlignCenter</set> + </property> + <property name="text"> + <string>Get Defaults</string> + </property> + </widget> + </item> + </layout> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + </item> + </layout> + </widget> + <tabstops/> + <customwidgets/> + <resources/> + <connections/> +</ui> \ No newline at end of file diff --git a/MantidQt/CustomInterfaces/src/EnggDiffraction/EnggDiffractionPresenter.cpp b/MantidQt/CustomInterfaces/src/EnggDiffraction/EnggDiffractionPresenter.cpp index 7e9aecbcd74c6491ec63d5c29e37574787f9601d..5c8e7b74c17ace268e1248ed2e496b5ad50bf767 100644 --- a/MantidQt/CustomInterfaces/src/EnggDiffraction/EnggDiffractionPresenter.cpp +++ b/MantidQt/CustomInterfaces/src/EnggDiffraction/EnggDiffractionPresenter.cpp @@ -183,14 +183,12 @@ void EnggDiffractionPresenter::notify( void EnggDiffractionPresenter::processStart() { EnggDiffCalibSettings cs = m_view->currentCalibSettings(); m_view->showStatus("Ready"); - - updateNewCalib(m_view->currentCalibFile()); } void EnggDiffractionPresenter::processLoadExistingCalib() { EnggDiffCalibSettings cs = m_view->currentCalibSettings(); - std::string fname = m_view->askExistingCalibFilename(); + const std::string fname = m_view->askExistingCalibFilename(); if (fname.empty()) { return; } diff --git a/MantidQt/CustomInterfaces/src/Homer.cpp b/MantidQt/CustomInterfaces/src/Homer.cpp index 19effc35cdceb15fdf1e7b72b24f415a09e6492c..2a7a8b141b87392c5f56cd813d42064def8245d7 100644 --- a/MantidQt/CustomInterfaces/src/Homer.cpp +++ b/MantidQt/CustomInterfaces/src/Homer.cpp @@ -2,7 +2,6 @@ #include "MantidQtCustomInterfaces/Background.h" #include "MantidQtCustomInterfaces/deltaECalc.h" #include "MantidQtMantidWidgets/MWDiag.h" -#include "MantidQtAPI/FileDialogHandler.h" #include "MantidQtAPI/MantidDesktopServices.h" #include "MantidKernel/ConfigService.h" @@ -392,8 +391,8 @@ QString Homer::openFileDia(const bool save, const QStringList &exts) { QString filename; if (save) { - filename = API::FileDialogHandler::getSaveFileName(this, "Save file", - m_lastSaveDir, filter); + filename = + QFileDialog::getSaveFileName(this, "Save file", m_lastSaveDir, filter); if (!filename.isEmpty()) { m_lastSaveDir = QFileInfo(filename).absoluteDir().path(); } diff --git a/MantidQt/CustomInterfaces/src/Indirect/ConvFit.cpp b/MantidQt/CustomInterfaces/src/Indirect/ConvFit.cpp index c78b40cd449818e995dd0bdb53a28fb9716c809c..840e0e01b301e99a00055e9770453ef8d2e3f4dd 100644 --- a/MantidQt/CustomInterfaces/src/Indirect/ConvFit.cpp +++ b/MantidQt/CustomInterfaces/src/Indirect/ConvFit.cpp @@ -324,6 +324,11 @@ void ConvFit::plotClicked() { const auto specNumber = m_uiForm.cbPlotType->currentIndex(); IndirectTab::plotSpectrum(QString::fromStdString(resultWs->getName()), specNumber, specNumber); + // Plot results for both Lorentzians if "Two Lorentzians" + if (m_uiForm.cbFitType->currentIndex() == 2) { + IndirectTab::plotSpectrum(QString::fromStdString(resultWs->getName()), + specNumber + 2, specNumber + 2); + } } } } else { @@ -1540,18 +1545,17 @@ QStringList ConvFit::getFunctionParameters(QString functionName) { } } // Add another Lorentzian function parameter for two Lorentzian fit - if (functionName.compare("Two Lorentzian") == 0) { + if (functionName.compare("Two Lorentzians") == 0) { currentFitFunction = "Lorentzian"; - } - if (functionName.compare("Zero Lorentzians") == 0) { - parameters.append("Zero"); - } else { IFunction_sptr func = FunctionFactory::Instance().createFunction( currentFitFunction.toStdString()); for (size_t i = 0; i < func->nParams(); i++) { parameters << QString::fromStdString(func->parameterName(i)); } } + if (functionName.compare("Zero Lorentzians") == 0) { + parameters.append("Zero"); + } return parameters; } diff --git a/MantidQt/CustomInterfaces/src/Indirect/IndirectTab.cpp b/MantidQt/CustomInterfaces/src/Indirect/IndirectTab.cpp index b33af6c3fd39db5a001dd29b02905114dd226c66..96a489bface68f9a6362220a0f26c41c7e4e8915 100644 --- a/MantidQt/CustomInterfaces/src/Indirect/IndirectTab.cpp +++ b/MantidQt/CustomInterfaces/src/Indirect/IndirectTab.cpp @@ -265,11 +265,11 @@ void IndirectTab::plotSpectrum(const QStringList &workspaceNames, int specStart, pyInput += "plotSpectrum(['"; pyInput += workspaceNames.join("','"); - pyInput += "'], range("; + pyInput += "'], list(range("; pyInput += QString::number(specStart); pyInput += ","; pyInput += QString::number(specEnd + 1); - pyInput += "), error_bars = True)\n"; + pyInput += ")), error_bars = True)\n"; m_pythonRunner.runPythonCode(pyInput); } diff --git a/MantidQt/CustomInterfaces/src/Muon/MuonAnalysis.cpp b/MantidQt/CustomInterfaces/src/Muon/MuonAnalysis.cpp index 77ba4bd7df2a5ddf96ce1e50e502f1db7089fbc5..9caa12314d5bce32a82557ab0ec6b944afc19878 100644 --- a/MantidQt/CustomInterfaces/src/Muon/MuonAnalysis.cpp +++ b/MantidQt/CustomInterfaces/src/Muon/MuonAnalysis.cpp @@ -19,7 +19,6 @@ #include "MantidKernel/Logger.h" #include "MantidKernel/Strings.h" #include "MantidKernel/cow_ptr.h" -#include "MantidQtAPI/FileDialogHandler.h" #include "MantidQtAPI/HelpWindow.h" #include "MantidQtAPI/ManageUserDirectories.h" #include "MantidQtCustomInterfaces/Muon/MuonAnalysisFitDataPresenter.h" @@ -563,7 +562,7 @@ void MuonAnalysis::runSaveGroupButton() { QString filter; filter.append("Files (*.xml *.XML)"); filter += ";;AllFiles (*)"; - QString groupingFile = MantidQt::API::FileDialogHandler::getSaveFileName( + QString groupingFile = QFileDialog::getSaveFileName( this, "Save Grouping file as", prevPath, filter); // Add extension if the groupingFile specified doesn't have one. (Solving @@ -2206,8 +2205,20 @@ void MuonAnalysis::setAppendingRun(int inc) { void MuonAnalysis::changeRun(int amountToChange) { QString filePath(""); QString currentFile = m_uiForm.mwRunFiles->getFirstFilename(); - if ((currentFile.isEmpty())) - currentFile = m_previousFilenames[0]; + if ((currentFile.isEmpty())) { + if (m_previousFilenames.isEmpty()) { + // not a valid file, and no previous valid files + QMessageBox::warning(this, tr("Muon Analysis"), + tr("Unable to open the file.\n" + "and no previous valid files available."), + QMessageBox::Ok, QMessageBox::Ok); + allowLoading(true); + return; + } else { + // blank box - use previous run + currentFile = m_previousFilenames[0]; + } + } QString run(""); int runSize(-1); diff --git a/MantidQt/CustomInterfaces/src/Muon/MuonAnalysisResultTableTab.cpp b/MantidQt/CustomInterfaces/src/Muon/MuonAnalysisResultTableTab.cpp index a302c14aba5607673b395e13f6d4b5721b6d52e9..c7fce7342bb754e574be5efc424fe05f57e5bbf6 100644 --- a/MantidQt/CustomInterfaces/src/Muon/MuonAnalysisResultTableTab.cpp +++ b/MantidQt/CustomInterfaces/src/Muon/MuonAnalysisResultTableTab.cpp @@ -19,8 +19,8 @@ #include <boost/shared_ptr.hpp> #include <boost/algorithm/string/predicate.hpp> +#include <QFileInfo> #include <QLineEdit> -#include <QFileDialog> #include <QHash> #include <QMessageBox> diff --git a/MantidQt/CustomInterfaces/src/Reflectometry/QtReflRunsTabView.cpp b/MantidQt/CustomInterfaces/src/Reflectometry/QtReflRunsTabView.cpp index a6601af6f8fcb7eca3065af343a641af04abda14..587aa09904076699e41d41f298d7c0fc63a58457 100644 --- a/MantidQt/CustomInterfaces/src/Reflectometry/QtReflRunsTabView.cpp +++ b/MantidQt/CustomInterfaces/src/Reflectometry/QtReflRunsTabView.cpp @@ -50,32 +50,54 @@ void QtReflRunsTabView::initLayout() { // Create the DataProcessor presenter ReflGenericDataProcessorPresenterFactory presenterFactory; - QDataProcessorWidget *qDataProcessorWidget = new QDataProcessorWidget( + QDataProcessorWidget *qDataProcessorWidget_1 = new QDataProcessorWidget( std::unique_ptr<DataProcessorPresenter>(presenterFactory.create()), this); - ui.layoutProcessPane->addWidget(qDataProcessorWidget); + ui.toolbox->addItem(qDataProcessorWidget_1, "Group 1"); + + QDataProcessorWidget *qDataProcessorWidget_2 = new QDataProcessorWidget( + std::unique_ptr<DataProcessorPresenter>(presenterFactory.create()), this); + ui.toolbox->addItem(qDataProcessorWidget_2, "Group 2"); + + std::vector<DataProcessorPresenter *> processingWidgets; + processingWidgets.push_back(qDataProcessorWidget_1->getPresenter()); + processingWidgets.push_back(qDataProcessorWidget_2->getPresenter()); // Create the presenter m_presenter = std::make_shared<ReflRunsTabPresenter>( this /* main view */, this /* Currently this concrete view is also responsible for prog reporting */, - qDataProcessorWidget->getPresenter() /* The data processor presenter */); + processingWidgets /* The data processor presenters */); m_algoRunner = boost::make_shared<MantidQt::API::AlgorithmRunner>(this); // Custom context menu for table connect(ui.tableSearchResults, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(showSearchContextMenu(const QPoint &))); - // Synchronize the two instrument selection widgets + // Synchronize the slit calculator + connect(ui.comboSearchInstrument, SIGNAL(currentIndexChanged(int)), this, + SLOT(instrumentChanged(int))); + // Selected group changed + connect(ui.toolbox, SIGNAL(currentChanged(int)), this, SLOT(groupChanged())); + + // Synchronize the instrument selection widgets + // Processing table in group 1 connect(ui.comboSearchInstrument, SIGNAL(currentIndexChanged(int)), - qDataProcessorWidget, + qDataProcessorWidget_1, SLOT(on_comboProcessInstrument_currentIndexChanged(int))); - connect(qDataProcessorWidget, + connect(qDataProcessorWidget_1, SIGNAL(comboProcessInstrument_currentIndexChanged(int)), ui.comboSearchInstrument, SLOT(setCurrentIndex(int))); - // Synchronize the slit calculator - connect(ui.comboSearchInstrument, SIGNAL(currentIndexChanged(int)), this, + connect(qDataProcessorWidget_1, + SIGNAL(comboProcessInstrument_currentIndexChanged(int)), this, SLOT(instrumentChanged(int))); - connect(qDataProcessorWidget, + // Processing table in group 2 + connect(ui.comboSearchInstrument, SIGNAL(currentIndexChanged(int)), + qDataProcessorWidget_2, + SLOT(on_comboProcessInstrument_currentIndexChanged(int))); + connect(qDataProcessorWidget_2, + SIGNAL(comboProcessInstrument_currentIndexChanged(int)), + ui.comboSearchInstrument, SLOT(setCurrentIndex(int))); + connect(qDataProcessorWidget_2, SIGNAL(comboProcessInstrument_currentIndexChanged(int)), this, SLOT(instrumentChanged(int))); } @@ -302,5 +324,19 @@ std::string QtReflRunsTabView::getTransferMethod() const { return ui.comboTransferMethod->currentText().toStdString(); } +/** +* @return the selected group +*/ +int QtReflRunsTabView::getSelectedGroup() const { + return ui.toolbox->currentIndex(); +} + +/** This is slot is triggered when the selected group changes. +* +*/ +void QtReflRunsTabView::groupChanged() { + m_presenter->notify(IReflRunsTabPresenter::GroupChangedFlag); +} + } // namespace CustomInterfaces } // namespace Mantid diff --git a/MantidQt/CustomInterfaces/src/Reflectometry/QtReflSettingsTabView.cpp b/MantidQt/CustomInterfaces/src/Reflectometry/QtReflSettingsTabView.cpp index feb486bedeb29716e07f5e77be1a32b6758ad0f2..0dd9bf213f455ba0dfc0b4c508003888f531a37d 100644 --- a/MantidQt/CustomInterfaces/src/Reflectometry/QtReflSettingsTabView.cpp +++ b/MantidQt/CustomInterfaces/src/Reflectometry/QtReflSettingsTabView.cpp @@ -1,12 +1,10 @@ #include "MantidQtCustomInterfaces/Reflectometry/QtReflSettingsTabView.h" +#include "MantidQtCustomInterfaces/Reflectometry/QtReflSettingsView.h" #include "MantidQtCustomInterfaces/Reflectometry/ReflSettingsTabPresenter.h" -#include "MantidQtMantidWidgets/HintingLineEdit.h" namespace MantidQt { namespace CustomInterfaces { -using namespace MantidQt::MantidWidgets; - //---------------------------------------------------------------------------------------------- /** Constructor * @param parent :: [input] The parent of this widget @@ -15,8 +13,6 @@ QtReflSettingsTabView::QtReflSettingsTabView(QWidget *parent) { UNUSED_ARG(parent); initLayout(); - - m_presenter.reset(new ReflSettingsTabPresenter(this)); } //---------------------------------------------------------------------------------------------- @@ -25,15 +21,22 @@ QtReflSettingsTabView::QtReflSettingsTabView(QWidget *parent) { QtReflSettingsTabView::~QtReflSettingsTabView() {} /** -Initialise the Interface +Initialise the interface */ void QtReflSettingsTabView::initLayout() { m_ui.setupUi(this); - connect(m_ui.getExpDefaultsButton, SIGNAL(clicked()), this, - SLOT(requestExpDefaults())); - connect(m_ui.getInstDefaultsButton, SIGNAL(clicked()), this, - SLOT(requestInstDefaults())); + QtReflSettingsView *settings_1 = new QtReflSettingsView(this); + m_ui.toolbox->addItem(settings_1, "Group 1"); + + QtReflSettingsView *settings_2 = new QtReflSettingsView(this); + m_ui.toolbox->addItem(settings_2, "Group 2"); + + std::vector<IReflSettingsPresenter *> presenters; + presenters.push_back(settings_1->getPresenter()); + presenters.push_back(settings_2->getPresenter()); + + m_presenter.reset(new ReflSettingsTabPresenter(presenters)); } /** Returns the presenter managing this view @@ -44,254 +47,5 @@ IReflSettingsTabPresenter *QtReflSettingsTabView::getPresenter() const { return m_presenter.get(); } -/** This slot notifies the presenter to fill experiment settings with default -* values. -*/ -void QtReflSettingsTabView::requestExpDefaults() const { - m_presenter->notify(IReflSettingsTabPresenter::ExpDefaultsFlag); -} - -/** This slot notifies the presenter to fill instrument settings with default -* values. -*/ -void QtReflSettingsTabView::requestInstDefaults() const { - m_presenter->notify(IReflSettingsTabPresenter::InstDefaultsFlag); -} - -/* Sets default values for all experiment settings given a list of default -* values. -*/ -void QtReflSettingsTabView::setExpDefaults( - const std::vector<std::string> &defaults) const { - - int amIndex = - m_ui.analysisModeComboBox->findText(QString::fromStdString(defaults[0])); - if (amIndex != -1) - m_ui.analysisModeComboBox->setCurrentIndex(amIndex); - - int pcIndex = - m_ui.polCorrComboBox->findText(QString::fromStdString(defaults[1])); - if (pcIndex != -1) - m_ui.polCorrComboBox->setCurrentIndex(pcIndex); - - m_ui.CRhoEdit->setText(QString::fromStdString(defaults[2])); - m_ui.CAlphaEdit->setText(QString::fromStdString(defaults[3])); - m_ui.CApEdit->setText(QString::fromStdString(defaults[4])); - m_ui.CPpEdit->setText(QString::fromStdString(defaults[5])); - m_ui.scaleFactorEdit->setText(QString::fromStdString(defaults[6])); -} - -/* Sets default values for all instrument settings given a list of default -* values. -*/ -void QtReflSettingsTabView::setInstDefaults( - const std::vector<double> &defaults) const { - - auto intMonCheckState = (defaults[0] != 0) ? Qt::Checked : Qt::Unchecked; - m_ui.intMonCheckBox->setCheckState(intMonCheckState); - - m_ui.monIntMinEdit->setText(QString::number(defaults[1])); - m_ui.monIntMaxEdit->setText(QString::number(defaults[2])); - m_ui.monBgMinEdit->setText(QString::number(defaults[3])); - m_ui.monBgMaxEdit->setText(QString::number(defaults[4])); - m_ui.lamMinEdit->setText(QString::number(defaults[5])); - m_ui.lamMaxEdit->setText(QString::number(defaults[6])); - m_ui.I0MonIndexEdit->setText(QString::number(defaults[7])); -} - -/* Sets the enabled status of polarisation corrections and parameters -* @param enable :: [input] bool to enable options or not -*/ -void QtReflSettingsTabView::setPolarisationOptionsEnabled(bool enable) const { - m_ui.polCorrComboBox->setEnabled(enable); - m_ui.CRhoEdit->setEnabled(enable); - m_ui.CAlphaEdit->setEnabled(enable); - m_ui.CApEdit->setEnabled(enable); - m_ui.CPpEdit->setEnabled(enable); - - if (!enable) { - // Set polarisation corrections text to 'None' when disabled - int noneIndex = m_ui.polCorrComboBox->findText("None"); - if (noneIndex != -1) - m_ui.polCorrComboBox->setCurrentIndex(noneIndex); - // Clear all parameters as well - m_ui.CRhoEdit->clear(); - m_ui.CAlphaEdit->clear(); - m_ui.CApEdit->clear(); - m_ui.CPpEdit->clear(); - } -} - -/** Returns global options for 'Stitch1DMany' -* @return :: Global options for 'Stitch1DMany' -*/ -std::string QtReflSettingsTabView::getStitchOptions() const { - - auto widget = m_ui.expSettingsLayout0->itemAtPosition(7, 1)->widget(); - return static_cast<HintingLineEdit *>(widget)->text().toStdString(); -} - -/** Creates hints for 'Stitch1DMany' -* @param hints :: Hints as a map -*/ -void QtReflSettingsTabView::createStitchHints( - const std::map<std::string, std::string> &hints) { - - m_ui.expSettingsLayout0->addWidget(new HintingLineEdit(this, hints), 7, 1, 1, - 3); -} - -/** Return selected analysis mode -* @return :: selected analysis mode -*/ -std::string QtReflSettingsTabView::getAnalysisMode() const { - - return m_ui.analysisModeComboBox->currentText().toStdString(); -} - -/** Return direct beam -* @return :: direct beam range -*/ -std::string QtReflSettingsTabView::getDirectBeam() const { - - return m_ui.directBeamEdit->text().toStdString(); -} - -/** Return selected transmission run(s) -* @return :: selected transmission run(s) -*/ -std::string QtReflSettingsTabView::getTransmissionRuns() const { - - return m_ui.transmissionRunsEdit->text().toStdString(); -} - -/** Return selected polarisation corrections -* @return :: selected polarisation corrections -*/ -std::string QtReflSettingsTabView::getPolarisationCorrections() const { - - return m_ui.polCorrComboBox->currentText().toStdString(); -} - -/** Return CRho -* @return :: polarization correction CRho -*/ -std::string QtReflSettingsTabView::getCRho() const { - - return m_ui.CRhoEdit->text().toStdString(); -} - -/** Return CAlpha -* @return :: polarization correction CAlpha -*/ -std::string QtReflSettingsTabView::getCAlpha() const { - - return m_ui.CAlphaEdit->text().toStdString(); -} - -/** Return CAp -* @return :: polarization correction CAp -*/ -std::string QtReflSettingsTabView::getCAp() const { - - return m_ui.CApEdit->text().toStdString(); -} - -/** Return CPp -* @return :: polarization correction CPp -*/ -std::string QtReflSettingsTabView::getCPp() const { - - return m_ui.CPpEdit->text().toStdString(); -} - -/** Return momentum transfer limits -* @return :: momentum transfer limits -*/ -std::string QtReflSettingsTabView::getMomentumTransferStep() const { - - return m_ui.momentumTransferStepEdit->text().toStdString(); -} - -/** Return scale factor -* @return :: scale factor -*/ -std::string QtReflSettingsTabView::getScaleFactor() const { - - return m_ui.scaleFactorEdit->text().toStdString(); -} - -/** Return integrated monitors option -* @return :: integrated monitors check -*/ -std::string QtReflSettingsTabView::getIntMonCheck() const { - - return m_ui.intMonCheckBox->isChecked() ? "1" : "0"; -} - -/** Return monitor integral wavelength min -* @return :: monitor integral min -*/ -std::string QtReflSettingsTabView::getMonitorIntegralMin() const { - - return m_ui.monIntMinEdit->text().toStdString(); -} - -/** Return monitor integral wavelength max -* @return :: monitor integral max -*/ -std::string QtReflSettingsTabView::getMonitorIntegralMax() const { - - return m_ui.monIntMaxEdit->text().toStdString(); -} - -/** Return monitor background wavelength min -* @return :: monitor background min -*/ -std::string QtReflSettingsTabView::getMonitorBackgroundMin() const { - - return m_ui.monBgMinEdit->text().toStdString(); -} - -/** Return monitor background wavelength max -* @return :: monitor background max -*/ -std::string QtReflSettingsTabView::getMonitorBackgroundMax() const { - - return m_ui.monBgMaxEdit->text().toStdString(); -} - -/** Return wavelength min -* @return :: lambda min -*/ -std::string QtReflSettingsTabView::getLambdaMin() const { - - return m_ui.lamMinEdit->text().toStdString(); -} - -/** Return wavelength max -* @return :: lambda max -*/ -std::string QtReflSettingsTabView::getLambdaMax() const { - - return m_ui.lamMaxEdit->text().toStdString(); -} - -/** Return I0MonitorIndex -* @return :: I0MonitorIndex -*/ -std::string QtReflSettingsTabView::getI0MonitorIndex() const { - - return m_ui.I0MonIndexEdit->text().toStdString(); -} - -/** Return processing instructions -* @return :: processing instructions -*/ -std::string QtReflSettingsTabView::getProcessingInstructions() const { - - return m_ui.procInstEdit->text().toStdString(); -} - } // namespace CustomInterfaces } // namespace Mantid diff --git a/MantidQt/CustomInterfaces/src/Reflectometry/QtReflSettingsView.cpp b/MantidQt/CustomInterfaces/src/Reflectometry/QtReflSettingsView.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f6511d4e0660ae7f4c336e66477c31f8a63ab6e5 --- /dev/null +++ b/MantidQt/CustomInterfaces/src/Reflectometry/QtReflSettingsView.cpp @@ -0,0 +1,297 @@ +#include "MantidQtCustomInterfaces/Reflectometry/QtReflSettingsView.h" +#include "MantidQtCustomInterfaces/Reflectometry/ReflSettingsPresenter.h" +#include "MantidQtMantidWidgets/HintingLineEdit.h" + +namespace MantidQt { +namespace CustomInterfaces { + +using namespace MantidQt::MantidWidgets; + +//---------------------------------------------------------------------------------------------- +/** Constructor +* @param parent :: [input] The parent of this widget +*/ +QtReflSettingsView::QtReflSettingsView(QWidget *parent) { + + UNUSED_ARG(parent); + initLayout(); + + m_presenter.reset(new ReflSettingsPresenter(this)); +} + +//---------------------------------------------------------------------------------------------- +/** Destructor +*/ +QtReflSettingsView::~QtReflSettingsView() {} + +/** +Initialise the Interface +*/ +void QtReflSettingsView::initLayout() { + m_ui.setupUi(this); + + connect(m_ui.getExpDefaultsButton, SIGNAL(clicked()), this, + SLOT(requestExpDefaults())); + connect(m_ui.getInstDefaultsButton, SIGNAL(clicked()), this, + SLOT(requestInstDefaults())); +} + +/** Returns the presenter managing this view +* @return :: A pointer to the presenter +*/ +IReflSettingsPresenter *QtReflSettingsView::getPresenter() const { + + return m_presenter.get(); +} + +/** This slot notifies the presenter to fill experiment settings with default +* values. +*/ +void QtReflSettingsView::requestExpDefaults() const { + m_presenter->notify(IReflSettingsPresenter::ExpDefaultsFlag); +} + +/** This slot notifies the presenter to fill instrument settings with default +* values. +*/ +void QtReflSettingsView::requestInstDefaults() const { + m_presenter->notify(IReflSettingsPresenter::InstDefaultsFlag); +} + +/* Sets default values for all experiment settings given a list of default +* values. +*/ +void QtReflSettingsView::setExpDefaults( + const std::vector<std::string> &defaults) const { + + int amIndex = + m_ui.analysisModeComboBox->findText(QString::fromStdString(defaults[0])); + if (amIndex != -1) + m_ui.analysisModeComboBox->setCurrentIndex(amIndex); + + int pcIndex = + m_ui.polCorrComboBox->findText(QString::fromStdString(defaults[1])); + if (pcIndex != -1) + m_ui.polCorrComboBox->setCurrentIndex(pcIndex); + + m_ui.CRhoEdit->setText(QString::fromStdString(defaults[2])); + m_ui.CAlphaEdit->setText(QString::fromStdString(defaults[3])); + m_ui.CApEdit->setText(QString::fromStdString(defaults[4])); + m_ui.CPpEdit->setText(QString::fromStdString(defaults[5])); + m_ui.scaleFactorEdit->setText(QString::fromStdString(defaults[6])); +} + +/* Sets default values for all instrument settings given a list of default +* values. +*/ +void QtReflSettingsView::setInstDefaults( + const std::vector<double> &defaults) const { + + auto intMonCheckState = (defaults[0] != 0) ? Qt::Checked : Qt::Unchecked; + m_ui.intMonCheckBox->setCheckState(intMonCheckState); + + m_ui.monIntMinEdit->setText(QString::number(defaults[1])); + m_ui.monIntMaxEdit->setText(QString::number(defaults[2])); + m_ui.monBgMinEdit->setText(QString::number(defaults[3])); + m_ui.monBgMaxEdit->setText(QString::number(defaults[4])); + m_ui.lamMinEdit->setText(QString::number(defaults[5])); + m_ui.lamMaxEdit->setText(QString::number(defaults[6])); + m_ui.I0MonIndexEdit->setText(QString::number(defaults[7])); +} + +/* Sets the enabled status of polarisation corrections and parameters +* @param enable :: [input] bool to enable options or not +*/ +void QtReflSettingsView::setPolarisationOptionsEnabled(bool enable) const { + m_ui.polCorrComboBox->setEnabled(enable); + m_ui.CRhoEdit->setEnabled(enable); + m_ui.CAlphaEdit->setEnabled(enable); + m_ui.CApEdit->setEnabled(enable); + m_ui.CPpEdit->setEnabled(enable); + + if (!enable) { + // Set polarisation corrections text to 'None' when disabled + int noneIndex = m_ui.polCorrComboBox->findText("None"); + if (noneIndex != -1) + m_ui.polCorrComboBox->setCurrentIndex(noneIndex); + // Clear all parameters as well + m_ui.CRhoEdit->clear(); + m_ui.CAlphaEdit->clear(); + m_ui.CApEdit->clear(); + m_ui.CPpEdit->clear(); + } +} + +/** Returns global options for 'Stitch1DMany' +* @return :: Global options for 'Stitch1DMany' +*/ +std::string QtReflSettingsView::getStitchOptions() const { + + auto widget = m_ui.expSettingsLayout0->itemAtPosition(7, 1)->widget(); + return static_cast<HintingLineEdit *>(widget)->text().toStdString(); +} + +/** Creates hints for 'Stitch1DMany' +* @param hints :: Hints as a map +*/ +void QtReflSettingsView::createStitchHints( + const std::map<std::string, std::string> &hints) { + + m_ui.expSettingsLayout0->addWidget(new HintingLineEdit(this, hints), 7, 1, 1, + 3); +} + +/** Return selected analysis mode +* @return :: selected analysis mode +*/ +std::string QtReflSettingsView::getAnalysisMode() const { + + return m_ui.analysisModeComboBox->currentText().toStdString(); +} + +/** Return direct beam +* @return :: direct beam range +*/ +std::string QtReflSettingsView::getDirectBeam() const { + + return m_ui.directBeamEdit->text().toStdString(); +} + +/** Return selected transmission run(s) +* @return :: selected transmission run(s) +*/ +std::string QtReflSettingsView::getTransmissionRuns() const { + + return m_ui.transmissionRunsEdit->text().toStdString(); +} + +/** Return selected polarisation corrections +* @return :: selected polarisation corrections +*/ +std::string QtReflSettingsView::getPolarisationCorrections() const { + + return m_ui.polCorrComboBox->currentText().toStdString(); +} + +/** Return CRho +* @return :: polarization correction CRho +*/ +std::string QtReflSettingsView::getCRho() const { + + return m_ui.CRhoEdit->text().toStdString(); +} + +/** Return CAlpha +* @return :: polarization correction CAlpha +*/ +std::string QtReflSettingsView::getCAlpha() const { + + return m_ui.CAlphaEdit->text().toStdString(); +} + +/** Return CAp +* @return :: polarization correction CAp +*/ +std::string QtReflSettingsView::getCAp() const { + + return m_ui.CApEdit->text().toStdString(); +} + +/** Return CPp +* @return :: polarization correction CPp +*/ +std::string QtReflSettingsView::getCPp() const { + + return m_ui.CPpEdit->text().toStdString(); +} + +/** Return momentum transfer limits +* @return :: momentum transfer limits +*/ +std::string QtReflSettingsView::getMomentumTransferStep() const { + + return m_ui.momentumTransferStepEdit->text().toStdString(); +} + +/** Return scale factor +* @return :: scale factor +*/ +std::string QtReflSettingsView::getScaleFactor() const { + + return m_ui.scaleFactorEdit->text().toStdString(); +} + +/** Return integrated monitors option +* @return :: integrated monitors check +*/ +std::string QtReflSettingsView::getIntMonCheck() const { + + return m_ui.intMonCheckBox->isChecked() ? "1" : "0"; +} + +/** Return monitor integral wavelength min +* @return :: monitor integral min +*/ +std::string QtReflSettingsView::getMonitorIntegralMin() const { + + return m_ui.monIntMinEdit->text().toStdString(); +} + +/** Return monitor integral wavelength max +* @return :: monitor integral max +*/ +std::string QtReflSettingsView::getMonitorIntegralMax() const { + + return m_ui.monIntMaxEdit->text().toStdString(); +} + +/** Return monitor background wavelength min +* @return :: monitor background min +*/ +std::string QtReflSettingsView::getMonitorBackgroundMin() const { + + return m_ui.monBgMinEdit->text().toStdString(); +} + +/** Return monitor background wavelength max +* @return :: monitor background max +*/ +std::string QtReflSettingsView::getMonitorBackgroundMax() const { + + return m_ui.monBgMaxEdit->text().toStdString(); +} + +/** Return wavelength min +* @return :: lambda min +*/ +std::string QtReflSettingsView::getLambdaMin() const { + + return m_ui.lamMinEdit->text().toStdString(); +} + +/** Return wavelength max +* @return :: lambda max +*/ +std::string QtReflSettingsView::getLambdaMax() const { + + return m_ui.lamMaxEdit->text().toStdString(); +} + +/** Return I0MonitorIndex +* @return :: I0MonitorIndex +*/ +std::string QtReflSettingsView::getI0MonitorIndex() const { + + return m_ui.I0MonIndexEdit->text().toStdString(); +} + +/** Return processing instructions +* @return :: processing instructions +*/ +std::string QtReflSettingsView::getProcessingInstructions() const { + + return m_ui.procInstEdit->text().toStdString(); +} + +} // namespace CustomInterfaces +} // namespace Mantid diff --git a/MantidQt/CustomInterfaces/src/Reflectometry/ReflMainWindowPresenter.cpp b/MantidQt/CustomInterfaces/src/Reflectometry/ReflMainWindowPresenter.cpp index 89f4a97d3e8fcd8970ac5c51ce42ac65d0b8b036..b7568006bfce6a287534efd7b216205eaf365b09 100644 --- a/MantidQt/CustomInterfaces/src/Reflectometry/ReflMainWindowPresenter.cpp +++ b/MantidQt/CustomInterfaces/src/Reflectometry/ReflMainWindowPresenter.cpp @@ -22,8 +22,8 @@ ReflMainWindowPresenter::ReflMainWindowPresenter( // Tell the tab presenters that this is going to be the main presenter m_runsPresenter->acceptMainPresenter(this); - m_settingsPresenter->acceptMainPresenter(this); m_savePresenter->acceptMainPresenter(this); + // Settings tab does not need a main presenter // Trigger the setting of the current instrument name in settings tab m_runsPresenter->notify(IReflRunsTabPresenter::InstrumentChangedFlag); @@ -34,35 +34,44 @@ ReflMainWindowPresenter::ReflMainWindowPresenter( ReflMainWindowPresenter::~ReflMainWindowPresenter() {} /** Returns global options for 'CreateTransmissionWorkspaceAuto' +* +* @param group :: Index of the group in 'Settings' tab from which to get the +*options * @return :: Global options for 'CreateTransmissionWorkspaceAuto' */ -std::string ReflMainWindowPresenter::getTransmissionOptions() const { +std::string ReflMainWindowPresenter::getTransmissionOptions(int group) const { checkPtrValid(m_settingsPresenter); - return m_settingsPresenter->getTransmissionOptions(); + return m_settingsPresenter->getTransmissionOptions(group); } /** Returns global processing options +* +* @param group :: Index of the group in 'Settings' tab from which to get the +*options * @return :: Global processing options */ -std::string ReflMainWindowPresenter::getReductionOptions() const { +std::string ReflMainWindowPresenter::getReductionOptions(int group) const { checkPtrValid(m_settingsPresenter); // Request global processing options to 'Settings' presenter - return m_settingsPresenter->getReductionOptions(); + return m_settingsPresenter->getReductionOptions(group); } /** Returns global post-processing options +* +* @param group :: Index of the group in 'Settings' tab from which to get the +*options * @return :: Global post-processing options */ -std::string ReflMainWindowPresenter::getStitchOptions() const { +std::string ReflMainWindowPresenter::getStitchOptions(int group) const { checkPtrValid(m_settingsPresenter); // Request global post-processing options to 'Settings' presenter - return m_settingsPresenter->getStitchOptions(); + return m_settingsPresenter->getStitchOptions(group); } /** diff --git a/MantidQt/CustomInterfaces/src/Reflectometry/ReflRunsTabPresenter.cpp b/MantidQt/CustomInterfaces/src/Reflectometry/ReflRunsTabPresenter.cpp index 1c0addb7f876cff44388053c50847e192a662fd8..9a2b9136106c95d3dc19b7050b8cac1df5adf2b5 100644 --- a/MantidQt/CustomInterfaces/src/Reflectometry/ReflRunsTabPresenter.cpp +++ b/MantidQt/CustomInterfaces/src/Reflectometry/ReflRunsTabPresenter.cpp @@ -34,21 +34,22 @@ namespace CustomInterfaces { /** Constructor * @param mainView :: [input] The view we're managing * @param progressableView :: [input] The view reporting progress -* @param tablePresenter :: [input] The data processor presenter +* @param tablePresenters :: [input] The data processor presenters * @param searcher :: [input] The search implementation */ ReflRunsTabPresenter::ReflRunsTabPresenter( IReflRunsTabView *mainView, ProgressableView *progressableView, - DataProcessorPresenter *tablePresenter, + std::vector<DataProcessorPresenter *> tablePresenters, boost::shared_ptr<IReflSearcher> searcher) : m_view(mainView), m_progressView(progressableView), - m_tablePresenter(tablePresenter), m_mainPresenter(), + m_tablePresenters(tablePresenters), m_mainPresenter(), m_searcher(searcher) { // Register this presenter as the workspace receiver - // When doing so, the inner presenter will notify this + // When doing so, the inner presenters will notify this // presenter with the list of commands - m_tablePresenter->accept(this); + for (const auto &presenter : m_tablePresenters) + presenter->accept(this); // If we don't have a searcher yet, use ReflCatalogSearcher if (!m_searcher) @@ -60,6 +61,9 @@ ReflRunsTabPresenter::ReflRunsTabPresenter( methods.insert(MeasureTransferMethod); m_view->setTransferMethods(methods); + // Set current transfer method + m_currentTransferMethod = m_view->getTransferMethod(); + // Set up the instrument selectors std::vector<std::string> instruments; instruments.emplace_back("INTER"); @@ -75,10 +79,12 @@ ReflRunsTabPresenter::ReflRunsTabPresenter( if (std::find(instruments.begin(), instruments.end(), defaultInst) != instruments.end()) { m_view->setInstrumentList(instruments, defaultInst); - m_tablePresenter->setInstrumentList(instruments, defaultInst); + for (const auto &presenter : m_tablePresenters) + presenter->setInstrumentList(instruments, defaultInst); } else { m_view->setInstrumentList(instruments, "INTER"); - m_tablePresenter->setInstrumentList(instruments, "INTER"); + for (const auto &presenter : m_tablePresenters) + presenter->setInstrumentList(instruments, "INTER"); } } @@ -113,6 +119,9 @@ void ReflRunsTabPresenter::notify(IReflRunsTabPresenter::Flag flag) { case IReflRunsTabPresenter::InstrumentChangedFlag: m_mainPresenter->setInstrumentName(m_view->getSearchInstrument()); break; + case IReflRunsTabPresenter::GroupChangedFlag: + pushCommands(); + break; } // Not having a 'default' case is deliberate. gcc issues a warning if there's // a flag we aren't handling. @@ -125,7 +134,8 @@ void ReflRunsTabPresenter::pushCommands() { // The expected number of commands const size_t nCommands = 27; - auto commands = m_tablePresenter->publishCommands(); + auto commands = + m_tablePresenters.at(m_view->getSelectedGroup())->publishCommands(); if (commands.size() != nCommands) { throw std::runtime_error("Invalid list of commands"); } @@ -197,6 +207,7 @@ void ReflRunsTabPresenter::search() { void ReflRunsTabPresenter::populateSearch(IAlgorithm_sptr searchAlg) { if (searchAlg->isExecuted()) { ITableWorkspace_sptr results = searchAlg->getProperty("OutputWorkspace"); + m_currentTransferMethod = m_view->getTransferMethod(); m_searchModel = ReflSearchModel_sptr(new ReflSearchModel( *getTransferStrategy(), results, m_view->getSearchInstrument())); m_view->showSearch(m_searchModel); @@ -211,8 +222,20 @@ void ReflRunsTabPresenter::transfer() { SearchResultMap runs; auto selectedRows = m_view->getSelectedSearchRows(); - // Do not begin transfer if nothing is selected + // Do not begin transfer if nothing is selected or if the transfer method does + // not match the one used for populating search if (selectedRows.size() == 0) { + m_mainPresenter->giveUserCritical( + "Error: Please select at least one run to transfer.", + "No runs selected"); + return; + } else if (m_currentTransferMethod != m_view->getTransferMethod()) { + m_mainPresenter->giveUserCritical( + "Error: Method selected for transferring runs (" + + m_view->getTransferMethod() + + ") must match the method used for searching runs (" + + m_currentTransferMethod + ").", + "Transfer method mismatch"); return; } @@ -274,7 +297,8 @@ void ReflRunsTabPresenter::transfer() { } } - m_tablePresenter->transfer(results.getTransferRuns()); + m_tablePresenters.at(m_view->getSelectedGroup()) + ->transfer(results.getTransferRuns()); } /** @@ -284,9 +308,8 @@ void ReflRunsTabPresenter::transfer() { */ std::unique_ptr<ReflTransferStrategy> ReflRunsTabPresenter::getTransferStrategy() { - const std::string currentMethod = m_view->getTransferMethod(); std::unique_ptr<ReflTransferStrategy> rtnStrategy; - if (currentMethod == MeasureTransferMethod) { + if (m_currentTransferMethod == MeasureTransferMethod) { // We need catalog info overrides from the user-based config service std::unique_ptr<CatalogConfigService> catConfigService( @@ -306,12 +329,12 @@ ReflRunsTabPresenter::getTransferStrategy() { rtnStrategy = Mantid::Kernel::make_unique<ReflMeasureTransferStrategy>( std::move(catInfo), std::move(source)); return rtnStrategy; - } else if (currentMethod == LegacyTransferMethod) { + } else if (m_currentTransferMethod == LegacyTransferMethod) { rtnStrategy = make_unique<ReflLegacyTransferStrategy>(); return rtnStrategy; } else { throw std::runtime_error("Unknown tranfer method selected: " + - currentMethod); + m_currentTransferMethod); } } @@ -337,7 +360,8 @@ std::map<std::string, std::string> ReflRunsTabPresenter::getPreprocessingOptions() const { std::map<std::string, std::string> options; - options["Transmission Run(s)"] = m_mainPresenter->getTransmissionOptions(); + options["Transmission Run(s)"] = + m_mainPresenter->getTransmissionOptions(m_view->getSelectedGroup()); return options; } @@ -347,7 +371,7 @@ ReflRunsTabPresenter::getPreprocessingOptions() const { * @return :: Global pre-processing options */ std::string ReflRunsTabPresenter::getProcessingOptions() const { - return m_mainPresenter->getReductionOptions(); + return m_mainPresenter->getReductionOptions(m_view->getSelectedGroup()); } /** Requests global pre-processing options. Options are supplied by the main @@ -355,7 +379,7 @@ std::string ReflRunsTabPresenter::getProcessingOptions() const { * @return :: Global pre-processing options */ std::string ReflRunsTabPresenter::getPostprocessingOptions() const { - return m_mainPresenter->getStitchOptions(); + return m_mainPresenter->getStitchOptions(m_view->getSelectedGroup()); } /** diff --git a/MantidQt/CustomInterfaces/src/Reflectometry/ReflSettingsPresenter.cpp b/MantidQt/CustomInterfaces/src/Reflectometry/ReflSettingsPresenter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..01c23e7274d6af6f9512037e3fa7d169de0bed41 --- /dev/null +++ b/MantidQt/CustomInterfaces/src/Reflectometry/ReflSettingsPresenter.cpp @@ -0,0 +1,356 @@ +#include "MantidQtCustomInterfaces/Reflectometry/ReflSettingsPresenter.h" +#include "MantidQtCustomInterfaces/Reflectometry/IReflSettingsTabPresenter.h" +#include "MantidQtCustomInterfaces/Reflectometry/IReflSettingsView.h" +#include "MantidQtMantidWidgets/AlgorithmHintStrategy.h" +#include "MantidAPI/AlgorithmManager.h" +#include "MantidAPI/AnalysisDataService.h" +#include "MantidAPI/IAlgorithm.h" +#include "MantidAPI/MatrixWorkspace.h" +#include "MantidGeometry/Instrument.h" +#include <boost/algorithm/string.hpp> + +namespace MantidQt { +namespace CustomInterfaces { + +using namespace Mantid::API; +using namespace MantidQt::MantidWidgets; +using namespace Mantid::Geometry; + +/** Constructor +* @param view :: The view we are handling +*/ +ReflSettingsPresenter::ReflSettingsPresenter(IReflSettingsView *view) + : m_view(view) { + + // Create the 'HintingLineEdits' + createStitchHints(); +} + +/** Destructor +*/ +ReflSettingsPresenter::~ReflSettingsPresenter() {} + +/** Used by the view to tell the presenter something has changed +* +* @param flag :: A flag used by the view to tell the presenter what happened +*/ +void ReflSettingsPresenter::notify(IReflSettingsPresenter::Flag flag) { + switch (flag) { + case IReflSettingsPresenter::ExpDefaultsFlag: + getExpDefaults(); + break; + case IReflSettingsPresenter::InstDefaultsFlag: + getInstDefaults(); + break; + } + // Not having a 'default' case is deliberate. gcc issues a warning if there's + // a flag we aren't handling. +} + +/** Sets the current instrument name and changes accessibility status of +* the polarisation corrections option in the view accordingly +* @param instName :: [input] The name of the instrument to set to +*/ +void ReflSettingsPresenter::setInstrumentName(const std::string &instName) { + m_currentInstrumentName = instName; + m_view->setPolarisationOptionsEnabled(instName != "INTER" && + instName != "SURF"); +} + +/** Returns global options for 'CreateTransmissionWorkspaceAuto' +* @return :: Global options for 'CreateTransmissionWorkspaceAuto' +*/ +std::string ReflSettingsPresenter::getTransmissionOptions() const { + + std::vector<std::string> options; + + // Add analysis mode + auto analysisMode = m_view->getAnalysisMode(); + if (!analysisMode.empty()) + options.push_back("AnalysisMode=" + analysisMode); + + // Add monitor integral min + auto monIntMin = m_view->getMonitorIntegralMin(); + if (!monIntMin.empty()) + options.push_back("MonitorIntegrationWavelengthMin=" + monIntMin); + + // Add monitor integral max + auto monIntMax = m_view->getMonitorIntegralMax(); + if (!monIntMax.empty()) + options.push_back("MonitorIntegrationWavelengthMax=" + monIntMax); + + // Add monitor background min + auto monBgMin = m_view->getMonitorBackgroundMin(); + if (!monBgMin.empty()) + options.push_back("MonitorBackgroundWavelengthMin=" + monBgMin); + + // Add monitor background max + auto monBgMax = m_view->getMonitorBackgroundMax(); + if (!monBgMax.empty()) + options.push_back("MonitorBackgroundWavelengthMax=" + monBgMax); + + // Add lambda min + auto lamMin = m_view->getLambdaMin(); + if (!lamMin.empty()) + options.push_back("WavelengthMin=" + lamMin); + + // Add lambda max + auto lamMax = m_view->getLambdaMax(); + if (!lamMax.empty()) + options.push_back("WavelengthMax=" + lamMax); + + // Add I0MonitorIndex + auto I0MonitorIndex = m_view->getI0MonitorIndex(); + if (!I0MonitorIndex.empty()) + options.push_back("I0MonitorIndex=" + I0MonitorIndex); + + // Add detector limits + auto procInst = m_view->getProcessingInstructions(); + if (!procInst.empty()) + options.push_back("ProcessingInstructions=" + procInst); + + return boost::algorithm::join(options, ","); +} + +/** Returns global options for 'ReflectometryReductionOneAuto' +* @return :: Global options for 'ReflectometryReductionOneAuto' +*/ +std::string ReflSettingsPresenter::getReductionOptions() const { + + std::vector<std::string> options; + + // Add analysis mode + auto analysisMode = m_view->getAnalysisMode(); + if (!analysisMode.empty()) + options.push_back("AnalysisMode=" + analysisMode); + + // Add CRho + auto crho = m_view->getCRho(); + if (!crho.empty()) + options.push_back("CRho=" + crho); + + // Add CAlpha + auto calpha = m_view->getCAlpha(); + if (!calpha.empty()) + options.push_back("CAlpha=" + calpha); + + // Add CAp + auto cap = m_view->getCAp(); + if (!cap.empty()) + options.push_back("CAp=" + cap); + + // Add CPp + auto cpp = m_view->getCPp(); + if (!cpp.empty()) + options.push_back("CPp=" + cpp); + + // Add direct beam + auto dbnr = m_view->getDirectBeam(); + if (!dbnr.empty()) + options.push_back("RegionOfDirectBeam=" + dbnr); + + // Add polarisation corrections + auto polCorr = m_view->getPolarisationCorrections(); + if (!polCorr.empty()) + options.push_back("PolarizationAnalysis=" + polCorr); + + // Add integrated monitors option + auto intMonCheck = m_view->getIntMonCheck(); + if (!intMonCheck.empty()) + options.push_back("NormalizeByIntegratedMonitors=" + intMonCheck); + + // Add monitor integral min + auto monIntMin = m_view->getMonitorIntegralMin(); + if (!monIntMin.empty()) + options.push_back("MonitorIntegrationWavelengthMin=" + monIntMin); + + // Add monitor integral max + auto monIntMax = m_view->getMonitorIntegralMax(); + if (!monIntMax.empty()) + options.push_back("MonitorIntegrationWavelengthMax=" + monIntMax); + + // Add monitor background min + auto monBgMin = m_view->getMonitorBackgroundMin(); + if (!monBgMin.empty()) + options.push_back("MonitorBackgroundWavelengthMin=" + monBgMin); + + // Add monitor background max + auto monBgMax = m_view->getMonitorBackgroundMax(); + if (!monBgMax.empty()) + options.push_back("MonitorBackgroundWavelengthMax=" + monBgMax); + + // Add lambda min + auto lamMin = m_view->getLambdaMin(); + if (!lamMin.empty()) + options.push_back("WavelengthMin=" + lamMin); + + // Add lambda max + auto lamMax = m_view->getLambdaMax(); + if (!lamMax.empty()) + options.push_back("WavelengthMax=" + lamMax); + + // Add I0MonitorIndex + auto I0MonitorIndex = m_view->getI0MonitorIndex(); + if (!I0MonitorIndex.empty()) + options.push_back("I0MonitorIndex=" + I0MonitorIndex); + + // Add scale factor + auto scaleFactor = m_view->getScaleFactor(); + if (!scaleFactor.empty()) + options.push_back("ScaleFactor=" + scaleFactor); + + // Add momentum transfer limits + auto qTransStep = m_view->getMomentumTransferStep(); + if (!qTransStep.empty()) { + options.push_back("MomentumTransferStep=" + qTransStep); + } + + // Add detector limits + auto procInst = m_view->getProcessingInstructions(); + if (!procInst.empty()) + options.push_back("ProcessingInstructions=" + procInst); + + // Add transmission runs + auto transRuns = this->getTransmissionRuns(); + if (!transRuns.empty()) + options.push_back(transRuns); + + return boost::algorithm::join(options, ","); +} + +/** Receives specified transmission runs from the view and loads them into the +*ADS. Returns a string with transmission runs so that they are considered in the +*reduction +* +* @return :: transmission run(s) as a string that will be used for the reduction +*/ +std::string ReflSettingsPresenter::getTransmissionRuns() const { + + auto runs = m_view->getTransmissionRuns(); + if (runs.empty()) + return ""; + + std::vector<std::string> transRuns; + boost::split(transRuns, runs, boost::is_any_of(",")); + + if (transRuns.size() > 2) + throw std::invalid_argument("Only one transmission run or two " + "transmission runs separated by ',' " + "are allowed."); + + for (const auto &run : transRuns) { + if (AnalysisDataService::Instance().doesExist("TRANS_" + run)) + continue; + // Load transmission runs and put them in the ADS + IAlgorithm_sptr alg = AlgorithmManager::Instance().create("LoadISISNexus"); + alg->setProperty("Filename", run); + alg->setPropertyValue("OutputWorkspace", "TRANS_" + run); + alg->execute(); + } + + // Return them as options for reduction + std::string options = "FirstTransmissionRun=TRANS_" + transRuns[0]; + if (transRuns.size() > 1) + options += ",SecondTransmissionRun=TRANS_" + transRuns[1]; + + return options; +} + +/** Returns global options for 'Stitch1DMany' +* @return :: Global options for 'Stitch1DMany' +*/ +std::string ReflSettingsPresenter::getStitchOptions() const { + + return m_view->getStitchOptions(); +} + +/** Creates hints for 'Stitch1DMany' +*/ +void ReflSettingsPresenter::createStitchHints() { + + // The algorithm + IAlgorithm_sptr alg = AlgorithmManager::Instance().create("Stitch1DMany"); + // The blacklist + std::set<std::string> blacklist = {"InputWorkspaces", "OutputWorkspace", + "OutputWorkspace"}; + AlgorithmHintStrategy strategy(alg, blacklist); + + m_view->createStitchHints(strategy.createHints()); +} + +/** Fills experiment settings with default values +*/ +void ReflSettingsPresenter::getExpDefaults() { + // Algorithm and instrument + auto alg = createReductionAlg(); + auto inst = createEmptyInstrument(m_currentInstrumentName); + + // Collect all default values and set them in view + std::vector<std::string> defaults(7); + defaults[0] = alg->getPropertyValue("AnalysisMode"); + defaults[1] = alg->getPropertyValue("PolarizationAnalysis"); + + auto cRho = inst->getStringParameter("crho"); + if (!cRho.empty()) + defaults[2] = cRho[0]; + + auto cAlpha = inst->getStringParameter("calpha"); + if (!cAlpha.empty()) + defaults[3] = cAlpha[0]; + + auto cAp = inst->getStringParameter("cAp"); + if (!cAp.empty()) + defaults[4] = cAp[0]; + + auto cPp = inst->getStringParameter("cPp"); + if (!cPp.empty()) + defaults[5] = cPp[0]; + + defaults[6] = alg->getPropertyValue("ScaleFactor"); + + m_view->setExpDefaults(defaults); +} + +/** Fills instrument settings with default values +*/ +void ReflSettingsPresenter::getInstDefaults() { + // Algorithm and instrument + auto alg = createReductionAlg(); + auto inst = createEmptyInstrument(m_currentInstrumentName); + + // Collect all default values + std::vector<double> defaults(8); + defaults[0] = boost::lexical_cast<double>( + alg->getPropertyValue("NormalizeByIntegratedMonitors")); + defaults[1] = inst->getNumberParameter("MonitorIntegralMin")[0]; + defaults[2] = inst->getNumberParameter("MonitorIntegralMax")[0]; + defaults[3] = inst->getNumberParameter("MonitorBackgroundMin")[0]; + defaults[4] = inst->getNumberParameter("MonitorBackgroundMax")[0]; + defaults[5] = inst->getNumberParameter("LambdaMin")[0]; + defaults[6] = inst->getNumberParameter("LambdaMax")[0]; + defaults[7] = inst->getNumberParameter("I0MonitorIndex")[0]; + + m_view->setInstDefaults(defaults); +} + +/** Generates and returns an instance of the ReflectometryReductionOne algorithm +*/ +IAlgorithm_sptr ReflSettingsPresenter::createReductionAlg() { + return AlgorithmManager::Instance().create("ReflectometryReductionOneAuto"); +} + +/** Creates and returns an example empty instrument given an instrument name +*/ +Instrument_const_sptr +ReflSettingsPresenter::createEmptyInstrument(const std::string &instName) { + IAlgorithm_sptr loadInst = + AlgorithmManager::Instance().create("LoadEmptyInstrument"); + loadInst->setChild(true); + loadInst->setProperty("OutputWorkspace", "outWs"); + loadInst->setProperty("InstrumentName", instName); + loadInst->execute(); + MatrixWorkspace_const_sptr ws = loadInst->getProperty("OutputWorkspace"); + return ws->getInstrument(); +} +} +} \ No newline at end of file diff --git a/MantidQt/CustomInterfaces/src/Reflectometry/ReflSettingsTabPresenter.cpp b/MantidQt/CustomInterfaces/src/Reflectometry/ReflSettingsTabPresenter.cpp index 1dc032b49b36bd5a70f2e28720e59a4c9e21ed25..6e082f7d0d26a2e6ea2adcc0da2f15b2124a3cd1 100644 --- a/MantidQt/CustomInterfaces/src/Reflectometry/ReflSettingsTabPresenter.cpp +++ b/MantidQt/CustomInterfaces/src/Reflectometry/ReflSettingsTabPresenter.cpp @@ -1,6 +1,6 @@ #include "MantidQtCustomInterfaces/Reflectometry/ReflSettingsTabPresenter.h" #include "MantidQtCustomInterfaces/Reflectometry/IReflMainWindowPresenter.h" -#include "MantidQtCustomInterfaces/Reflectometry/IReflSettingsTabView.h" +#include "MantidQtCustomInterfaces/Reflectometry/ReflSettingsPresenter.h" #include "MantidQtMantidWidgets/AlgorithmHintStrategy.h" #include "MantidAPI/AlgorithmManager.h" #include "MantidAPI/AnalysisDataService.h" @@ -11,351 +11,57 @@ namespace MantidQt { namespace CustomInterfaces { -using namespace Mantid::API; -using namespace MantidQt::MantidWidgets; -using namespace Mantid::Geometry; - /** Constructor -* @param view :: The view we are handling +* +* @param presenters :: The presenters of each group as a vector */ -ReflSettingsTabPresenter::ReflSettingsTabPresenter(IReflSettingsTabView *view) - : m_view(view), m_mainPresenter() { - - // Create the 'HintingLineEdits' - createStitchHints(); -} +ReflSettingsTabPresenter::ReflSettingsTabPresenter( + std::vector<IReflSettingsPresenter *> presenters) + : m_settingsPresenters(presenters) {} /** Destructor +* */ ReflSettingsTabPresenter::~ReflSettingsTabPresenter() {} -/** Accept a main presenter -* @param mainPresenter :: [input] The main presenter -*/ -void ReflSettingsTabPresenter::acceptMainPresenter( - IReflMainWindowPresenter *mainPresenter) { - m_mainPresenter = mainPresenter; -} - -/** Used by the view to tell the presenter something has changed -*/ -void ReflSettingsTabPresenter::notify(IReflSettingsTabPresenter::Flag flag) { - switch (flag) { - case IReflSettingsTabPresenter::ExpDefaultsFlag: - getExpDefaults(); - break; - case IReflSettingsTabPresenter::InstDefaultsFlag: - getInstDefaults(); - break; - } - // Not having a 'default' case is deliberate. gcc issues a warning if there's - // a flag we aren't handling. -} - /** Sets the current instrument name and changes accessibility status of * the polarisation corrections option in the view accordingly +* * @param instName :: [input] The name of the instrument to set to */ -void ReflSettingsTabPresenter::setInstrumentName(const std::string instName) { - m_currentInstrumentName = instName; - m_view->setPolarisationOptionsEnabled(instName != "INTER" && - instName != "SURF"); +void ReflSettingsTabPresenter::setInstrumentName(const std::string &instName) { + for (auto presenter : m_settingsPresenters) + presenter->setInstrumentName(instName); } /** Returns global options for 'CreateTransmissionWorkspaceAuto' +* +* @param group :: The group from which to get the options * @return :: Global options for 'CreateTransmissionWorkspaceAuto' */ -std::string ReflSettingsTabPresenter::getTransmissionOptions() const { - - std::vector<std::string> options; - - // Add analysis mode - auto analysisMode = m_view->getAnalysisMode(); - if (!analysisMode.empty()) - options.push_back("AnalysisMode=" + analysisMode); - - // Add monitor integral min - auto monIntMin = m_view->getMonitorIntegralMin(); - if (!monIntMin.empty()) - options.push_back("MonitorIntegrationWavelengthMin=" + monIntMin); - - // Add monitor integral max - auto monIntMax = m_view->getMonitorIntegralMax(); - if (!monIntMax.empty()) - options.push_back("MonitorIntegrationWavelengthMax=" + monIntMax); - - // Add monitor background min - auto monBgMin = m_view->getMonitorBackgroundMin(); - if (!monBgMin.empty()) - options.push_back("MonitorBackgroundWavelengthMin=" + monBgMin); - - // Add monitor background max - auto monBgMax = m_view->getMonitorBackgroundMax(); - if (!monBgMax.empty()) - options.push_back("MonitorBackgroundWavelengthMax=" + monBgMax); - - // Add lambda min - auto lamMin = m_view->getLambdaMin(); - if (!lamMin.empty()) - options.push_back("WavelengthMin=" + lamMin); - - // Add lambda max - auto lamMax = m_view->getLambdaMax(); - if (!lamMax.empty()) - options.push_back("WavelengthMax=" + lamMax); +std::string ReflSettingsTabPresenter::getTransmissionOptions(int group) const { - // Add I0MonitorIndex - auto I0MonitorIndex = m_view->getI0MonitorIndex(); - if (!I0MonitorIndex.empty()) - options.push_back("I0MonitorIndex=" + I0MonitorIndex); - - // Add detector limits - auto procInst = m_view->getProcessingInstructions(); - if (!procInst.empty()) - options.push_back("ProcessingInstructions=" + procInst); - - return boost::algorithm::join(options, ","); + return m_settingsPresenters.at(group)->getTransmissionOptions(); } /** Returns global options for 'ReflectometryReductionOneAuto' -* @return :: Global options for 'ReflectometryReductionOneAuto' -*/ -std::string ReflSettingsTabPresenter::getReductionOptions() const { - - std::vector<std::string> options; - - // Add analysis mode - auto analysisMode = m_view->getAnalysisMode(); - if (!analysisMode.empty()) - options.push_back("AnalysisMode=" + analysisMode); - - // Add CRho - auto crho = m_view->getCRho(); - if (!crho.empty()) - options.push_back("CRho=" + crho); - - // Add CAlpha - auto calpha = m_view->getCAlpha(); - if (!calpha.empty()) - options.push_back("CAlpha=" + calpha); - - // Add CAp - auto cap = m_view->getCAp(); - if (!cap.empty()) - options.push_back("CAp=" + cap); - - // Add CPp - auto cpp = m_view->getCPp(); - if (!cpp.empty()) - options.push_back("CPp=" + cpp); - - // Add direct beam - auto dbnr = m_view->getDirectBeam(); - if (!dbnr.empty()) - options.push_back("RegionOfDirectBeam=" + dbnr); - - // Add polarisation corrections - auto polCorr = m_view->getPolarisationCorrections(); - if (!polCorr.empty()) - options.push_back("PolarizationAnalysis=" + polCorr); - - // Add integrated monitors option - auto intMonCheck = m_view->getIntMonCheck(); - if (!intMonCheck.empty()) - options.push_back("NormalizeByIntegratedMonitors=" + intMonCheck); - - // Add monitor integral min - auto monIntMin = m_view->getMonitorIntegralMin(); - if (!monIntMin.empty()) - options.push_back("MonitorIntegrationWavelengthMin=" + monIntMin); - - // Add monitor integral max - auto monIntMax = m_view->getMonitorIntegralMax(); - if (!monIntMax.empty()) - options.push_back("MonitorIntegrationWavelengthMax=" + monIntMax); - - // Add monitor background min - auto monBgMin = m_view->getMonitorBackgroundMin(); - if (!monBgMin.empty()) - options.push_back("MonitorBackgroundWavelengthMin=" + monBgMin); - - // Add monitor background max - auto monBgMax = m_view->getMonitorBackgroundMax(); - if (!monBgMax.empty()) - options.push_back("MonitorBackgroundWavelengthMax=" + monBgMax); - - // Add lambda min - auto lamMin = m_view->getLambdaMin(); - if (!lamMin.empty()) - options.push_back("WavelengthMin=" + lamMin); - - // Add lambda max - auto lamMax = m_view->getLambdaMax(); - if (!lamMax.empty()) - options.push_back("WavelengthMax=" + lamMax); - - // Add I0MonitorIndex - auto I0MonitorIndex = m_view->getI0MonitorIndex(); - if (!I0MonitorIndex.empty()) - options.push_back("I0MonitorIndex=" + I0MonitorIndex); - - // Add scale factor - auto scaleFactor = m_view->getScaleFactor(); - if (!scaleFactor.empty()) - options.push_back("ScaleFactor=" + scaleFactor); - - // Add momentum transfer limits - auto qTransStep = m_view->getMomentumTransferStep(); - if (!qTransStep.empty()) { - options.push_back("MomentumTransferStep=" + qTransStep); - } - - // Add detector limits - auto procInst = m_view->getProcessingInstructions(); - if (!procInst.empty()) - options.push_back("ProcessingInstructions=" + procInst); - - // Add transmission runs - auto transRuns = this->getTransmissionRuns(); - if (!transRuns.empty()) - options.push_back(transRuns); - - return boost::algorithm::join(options, ","); -} - -/** Receives specified transmission runs from the view and loads them into the -*ADS. Returns a string with transmission runs so that they are considered in the -*reduction * -* @return :: transmission run(s) as a string that will be used for the reduction +* @param group :: The group from which to get the options +* @return :: Global options for 'ReflectometryReductionOneAuto' */ -std::string ReflSettingsTabPresenter::getTransmissionRuns() const { - - auto runs = m_view->getTransmissionRuns(); - if (runs.empty()) - return ""; - - std::vector<std::string> transRuns; - boost::split(transRuns, runs, boost::is_any_of(",")); +std::string ReflSettingsTabPresenter::getReductionOptions(int group) const { - if (transRuns.size() > 2) - throw std::invalid_argument("Only one transmission run or two " - "transmission runs separated by ',' " - "are allowed."); - - for (const auto &run : transRuns) { - if (AnalysisDataService::Instance().doesExist("TRANS_" + run)) - continue; - // Load transmission runs and put them in the ADS - IAlgorithm_sptr alg = AlgorithmManager::Instance().create("LoadISISNexus"); - alg->setProperty("Filename", run); - alg->setPropertyValue("OutputWorkspace", "TRANS_" + run); - alg->execute(); - } - - // Return them as options for reduction - std::string options = "FirstTransmissionRun=TRANS_" + transRuns[0]; - if (transRuns.size() > 1) - options += ",SecondTransmissionRun=TRANS_" + transRuns[1]; - - return options; + return m_settingsPresenters.at(group)->getReductionOptions(); } /** Returns global options for 'Stitch1DMany' +* +* @param group :: The group from which to get the options * @return :: Global options for 'Stitch1DMany' */ -std::string ReflSettingsTabPresenter::getStitchOptions() const { - - return m_view->getStitchOptions(); -} - -/** Creates hints for 'Stitch1DMany' -*/ -void ReflSettingsTabPresenter::createStitchHints() { - - // The algorithm - IAlgorithm_sptr alg = AlgorithmManager::Instance().create("Stitch1DMany"); - // The blacklist - std::set<std::string> blacklist = {"InputWorkspaces", "OutputWorkspace", - "OutputWorkspace"}; - AlgorithmHintStrategy strategy(alg, blacklist); - - m_view->createStitchHints(strategy.createHints()); -} - -/** Fills experiment settings with default values -*/ -void ReflSettingsTabPresenter::getExpDefaults() { - // Algorithm and instrument - auto alg = createReductionAlg(); - auto inst = createEmptyInstrument(m_currentInstrumentName); - - // Collect all default values and set them in view - std::vector<std::string> defaults(7); - defaults[0] = alg->getPropertyValue("AnalysisMode"); - defaults[1] = alg->getPropertyValue("PolarizationAnalysis"); - - auto cRho = inst->getStringParameter("crho"); - if (!cRho.empty()) - defaults[2] = cRho[0]; - - auto cAlpha = inst->getStringParameter("calpha"); - if (!cAlpha.empty()) - defaults[3] = cAlpha[0]; - - auto cAp = inst->getStringParameter("cAp"); - if (!cAp.empty()) - defaults[4] = cAp[0]; - - auto cPp = inst->getStringParameter("cPp"); - if (!cPp.empty()) - defaults[5] = cPp[0]; - - defaults[6] = alg->getPropertyValue("ScaleFactor"); - - m_view->setExpDefaults(defaults); -} - -/** Fills instrument settings with default values -*/ -void ReflSettingsTabPresenter::getInstDefaults() { - // Algorithm and instrument - auto alg = createReductionAlg(); - auto inst = createEmptyInstrument(m_currentInstrumentName); - - // Collect all default values - std::vector<double> defaults(8); - defaults[0] = boost::lexical_cast<double>( - alg->getPropertyValue("NormalizeByIntegratedMonitors")); - defaults[1] = inst->getNumberParameter("MonitorIntegralMin")[0]; - defaults[2] = inst->getNumberParameter("MonitorIntegralMax")[0]; - defaults[3] = inst->getNumberParameter("MonitorBackgroundMin")[0]; - defaults[4] = inst->getNumberParameter("MonitorBackgroundMax")[0]; - defaults[5] = inst->getNumberParameter("LambdaMin")[0]; - defaults[6] = inst->getNumberParameter("LambdaMax")[0]; - defaults[7] = inst->getNumberParameter("I0MonitorIndex")[0]; - - m_view->setInstDefaults(defaults); -} - -/** Generates and returns an instance of the ReflectometryReductionOne algorithm -*/ -IAlgorithm_sptr ReflSettingsTabPresenter::createReductionAlg() { - return AlgorithmManager::Instance().create("ReflectometryReductionOneAuto"); -} +std::string ReflSettingsTabPresenter::getStitchOptions(int group) const { -/** Creates and returns an example empty instrument given an instrument name -*/ -Instrument_const_sptr -ReflSettingsTabPresenter::createEmptyInstrument(std::string instName) { - IAlgorithm_sptr loadInst = - AlgorithmManager::Instance().create("LoadEmptyInstrument"); - loadInst->setChild(true); - loadInst->setProperty("OutputWorkspace", "outWs"); - loadInst->setProperty("InstrumentName", instName); - loadInst->execute(); - MatrixWorkspace_const_sptr ws = loadInst->getProperty("OutputWorkspace"); - return ws->getInstrument(); + return m_settingsPresenters.at(group)->getStitchOptions(); } } } diff --git a/MantidQt/CustomInterfaces/src/SANSRunWindow.cpp b/MantidQt/CustomInterfaces/src/SANSRunWindow.cpp index b9a5d746b3d1b694e7769c496fa580e50e3b1091..5018d487eb361c564d296bd90ade9cabe373f6dc 100644 --- a/MantidQt/CustomInterfaces/src/SANSRunWindow.cpp +++ b/MantidQt/CustomInterfaces/src/SANSRunWindow.cpp @@ -17,7 +17,6 @@ #include "MantidAPI/Run.h" #include "MantidAPI/WorkspaceGroup.h" -#include "MantidQtAPI/FileDialogHandler.h" #include "MantidQtAPI/MantidDesktopServices.h" #include "MantidQtAPI/ManageUserDirectories.h" #include "MantidQtCustomInterfaces/SANSAddFiles.h" @@ -25,6 +24,7 @@ #include "MantidQtCustomInterfaces/SANSEventSlicing.h" #include <QClipboard> +#include <QFileDialog> #include <QTemporaryFile> #include <QTextStream> #include <QUrl> @@ -1981,7 +1981,7 @@ void SANSRunWindow::saveFileBrowse() { const QString filter = ";;AllFiles (*)"; - QString oFile = FileDialogHandler::getSaveFileName( + QString oFile = QFileDialog::getSaveFileName( this, title, prevPath + "/" + m_uiForm.outfile_edit->text()); if (!oFile.isEmpty()) { @@ -2515,8 +2515,8 @@ void SANSRunWindow::handleReduceButtonClick(const QString &typeStr) { QString csv_file(m_uiForm.csv_filename->text()); if (m_dirty_batch_grid) { - QString selected_file = MantidQt::API::FileDialogHandler::getSaveFileName( - this, "Save as CSV", m_last_dir); + QString selected_file = + QFileDialog::getSaveFileName(this, "Save as CSV", m_last_dir); csv_file = saveBatchGrid(selected_file); } py_code.prepend("import SANSBatchMode as batch\n"); diff --git a/MantidQt/CustomInterfaces/test/ReflMainWindowPresenterTest.h b/MantidQt/CustomInterfaces/test/ReflMainWindowPresenterTest.h index 5bf6b733d278a65f8d4c7043b89e34c6dfba6438..2db4b1e775569aeb85d268f4532ccd67ce89669e 100644 --- a/MantidQt/CustomInterfaces/test/ReflMainWindowPresenterTest.h +++ b/MantidQt/CustomInterfaces/test/ReflMainWindowPresenterTest.h @@ -36,9 +36,14 @@ public: &mockSettingsPresenter, &mockSaveTabPresenter); - EXPECT_CALL(mockSettingsPresenter, getTransmissionOptions()) + EXPECT_CALL(mockSettingsPresenter, getTransmissionOptions(0)) .Times(Exactly(1)); - presenter.getTransmissionOptions(); + presenter.getTransmissionOptions(0); + + EXPECT_CALL(mockSettingsPresenter, getTransmissionOptions(1)) + .Times(Exactly(1)); + presenter.getTransmissionOptions(1); + TS_ASSERT(Mock::VerifyAndClearExpectations(&mockSettingsPresenter)); } @@ -51,8 +56,14 @@ public: &mockSettingsPresenter, &mockSaveTabPresenter); - EXPECT_CALL(mockSettingsPresenter, getReductionOptions()).Times(Exactly(1)); - presenter.getReductionOptions(); + EXPECT_CALL(mockSettingsPresenter, getReductionOptions(0)) + .Times(Exactly(1)); + presenter.getReductionOptions(0); + + EXPECT_CALL(mockSettingsPresenter, getReductionOptions(1)) + .Times(Exactly(1)); + presenter.getReductionOptions(1); + TS_ASSERT(Mock::VerifyAndClearExpectations(&mockSettingsPresenter)); } @@ -65,8 +76,12 @@ public: &mockSettingsPresenter, &mockSaveTabPresenter); - EXPECT_CALL(mockSettingsPresenter, getStitchOptions()).Times(Exactly(1)); - presenter.getStitchOptions(); + EXPECT_CALL(mockSettingsPresenter, getStitchOptions(0)).Times(Exactly(1)); + presenter.getStitchOptions(0); + + EXPECT_CALL(mockSettingsPresenter, getStitchOptions(1)).Times(Exactly(1)); + presenter.getStitchOptions(1); + TS_ASSERT(Mock::VerifyAndClearExpectations(&mockSettingsPresenter)); } diff --git a/MantidQt/CustomInterfaces/test/ReflMockObjects.h b/MantidQt/CustomInterfaces/test/ReflMockObjects.h index 0473e7b5614fd100f4d3b25299f21bb4edbb7f99..54c76710396d004e918e1cf6c12ba732a33c04b6 100644 --- a/MantidQt/CustomInterfaces/test/ReflMockObjects.h +++ b/MantidQt/CustomInterfaces/test/ReflMockObjects.h @@ -8,8 +8,9 @@ #include "MantidQtCustomInterfaces/Reflectometry/IReflMainWindowView.h" #include "MantidQtCustomInterfaces/Reflectometry/IReflRunsTabPresenter.h" #include "MantidQtCustomInterfaces/Reflectometry/IReflRunsTabView.h" +#include "MantidQtCustomInterfaces/Reflectometry/IReflSettingsPresenter.h" #include "MantidQtCustomInterfaces/Reflectometry/IReflSettingsTabPresenter.h" -#include "MantidQtCustomInterfaces/Reflectometry/IReflSettingsTabView.h" +#include "MantidQtCustomInterfaces/Reflectometry/IReflSettingsView.h" #include "MantidQtCustomInterfaces/Reflectometry/IReflSaveTabView.h" #include "MantidQtCustomInterfaces/Reflectometry/IReflSaveTabPresenter.h" #include "MantidQtCustomInterfaces/Reflectometry/ReflSearchModel.h" @@ -51,6 +52,7 @@ public: MOCK_CONST_METHOD0(getTransferMethod, std::string()); MOCK_CONST_METHOD0(getAlgorithmRunner, boost::shared_ptr<MantidQt::API::AlgorithmRunner>()); + MOCK_CONST_METHOD0(getSelectedGroup, int()); MOCK_METHOD1(setTransferMethods, void(const std::set<std::string> &)); MOCK_METHOD0(setTableCommandsProxy, void()); MOCK_METHOD0(setRowCommandsProxy, void()); @@ -60,10 +62,10 @@ public: // Calls we don't care about void showSearch(ReflSearchModel_sptr) override{}; - IReflRunsTabPresenter *getPresenter() const override { return nullptr; } + IReflRunsTabPresenter *getPresenter() const override { return nullptr; }; }; -class MockSettingsTabView : public IReflSettingsTabView { +class MockSettingsView : public IReflSettingsView { public: // Global options MOCK_CONST_METHOD0(getTransmissionOptions, std::string()); @@ -96,7 +98,7 @@ public: createStitchHints(const std::map<std::string, std::string> &hints) override { UNUSED_ARG(hints); }; - IReflSettingsTabPresenter *getPresenter() const override { return nullptr; } + IReflSettingsPresenter *getPresenter() const override { return nullptr; } }; class MockSaveTabView : public IReflSaveTabView { @@ -147,21 +149,24 @@ public: ~MockRunsTabPresenter() override{}; }; -class MockSettingsTabPresenter : public IReflSettingsTabPresenter { +class MockSettingsPresenter : public IReflSettingsPresenter { public: MOCK_CONST_METHOD0(getTransmissionOptions, std::string()); MOCK_CONST_METHOD0(getReductionOptions, std::string()); MOCK_CONST_METHOD0(getStitchOptions, std::string()); - // Other calls we don't care about - void acceptMainPresenter(IReflMainWindowPresenter *presenter) override { - UNUSED_ARG(presenter); - }; - void notify(IReflSettingsTabPresenter::Flag flag) override { - UNUSED_ARG(flag); - }; - void setInstrumentName(const std::string instName) override { + MOCK_METHOD1(setInstrumentName, void(const std::string &)); + void notify(IReflSettingsPresenter::Flag flag) override { UNUSED_ARG(flag); } + ~MockSettingsPresenter() override{}; +}; + +class MockSettingsTabPresenter : public IReflSettingsTabPresenter { +public: + MOCK_CONST_METHOD1(getTransmissionOptions, std::string(int)); + MOCK_CONST_METHOD1(getReductionOptions, std::string(int)); + MOCK_CONST_METHOD1(getStitchOptions, std::string(int)); + void setInstrumentName(const std::string &instName) override { UNUSED_ARG(instName); - } + }; ~MockSettingsTabPresenter() override{}; }; @@ -176,9 +181,9 @@ public: class MockMainWindowPresenter : public IReflMainWindowPresenter { public: - MOCK_CONST_METHOD0(getTransmissionOptions, std::string()); - MOCK_CONST_METHOD0(getReductionOptions, std::string()); - MOCK_CONST_METHOD0(getStitchOptions, std::string()); + MOCK_CONST_METHOD1(getTransmissionOptions, std::string(int)); + MOCK_CONST_METHOD1(getReductionOptions, std::string(int)); + MOCK_CONST_METHOD1(getStitchOptions, std::string(int)); MOCK_CONST_METHOD0(getInstrumentName, std::string()); MOCK_METHOD3(askUserString, std::string(const std::string &, const std::string &, diff --git a/MantidQt/CustomInterfaces/test/ReflRunsTabPresenterTest.h b/MantidQt/CustomInterfaces/test/ReflRunsTabPresenterTest.h index f42429c643fba381bfd9788a03c95b336b757cf5..b462c0d0237733ea26d3af46a493e6e38e7d180a 100644 --- a/MantidQt/CustomInterfaces/test/ReflRunsTabPresenterTest.h +++ b/MantidQt/CustomInterfaces/test/ReflRunsTabPresenterTest.h @@ -32,11 +32,9 @@ public: void test_constructor_sets_possible_transfer_methods() { NiceMock<MockRunsTabView> mockRunsTabView; MockProgressableView mockProgress; - MockDataProcessorPresenter mockTablePresenter; - - // Expect that the table presenter accepts this presenter as a workspace - // receiver - EXPECT_CALL(mockTablePresenter, accept(_)).Times(Exactly(1)); + NiceMock<MockDataProcessorPresenter> mockTablePresenter; + std::vector<DataProcessorPresenter *> tablePresenterVec; + tablePresenterVec.push_back(&mockTablePresenter); // Expect that the transfer methods get initialized on the view EXPECT_CALL(mockRunsTabView, setTransferMethods(_)).Times(Exactly(1)); @@ -45,20 +43,50 @@ public: // Constructor ReflRunsTabPresenter presenter(&mockRunsTabView, &mockProgress, - &mockTablePresenter); + tablePresenterVec); // Verify expectations TS_ASSERT(Mock::VerifyAndClearExpectations(&mockRunsTabView)); TS_ASSERT(Mock::VerifyAndClearExpectations(&mockTablePresenter)); } - void test_presenter_sets_commands_when_notified() { + void test_table_presenters_accept_this_presenter() { + NiceMock<MockRunsTabView> mockRunsTabView; + MockProgressableView mockProgress; + MockDataProcessorPresenter mockTablePresenter_1; + MockDataProcessorPresenter mockTablePresenter_2; + MockDataProcessorPresenter mockTablePresenter_3; + std::vector<DataProcessorPresenter *> tablePresenterVec; + tablePresenterVec.push_back(&mockTablePresenter_1); + tablePresenterVec.push_back(&mockTablePresenter_2); + tablePresenterVec.push_back(&mockTablePresenter_3); + + // Expect that the table presenters accept this presenter as a workspace + // receiver + EXPECT_CALL(mockTablePresenter_1, accept(_)).Times(Exactly(1)); + EXPECT_CALL(mockTablePresenter_2, accept(_)).Times(Exactly(1)); + EXPECT_CALL(mockTablePresenter_3, accept(_)).Times(Exactly(1)); + + // Constructor + ReflRunsTabPresenter presenter(&mockRunsTabView, &mockProgress, + tablePresenterVec); + + // Verify expectations + TS_ASSERT(Mock::VerifyAndClearExpectations(&mockRunsTabView)); + TS_ASSERT(Mock::VerifyAndClearExpectations(&mockTablePresenter_1)); + TS_ASSERT(Mock::VerifyAndClearExpectations(&mockTablePresenter_2)); + TS_ASSERT(Mock::VerifyAndClearExpectations(&mockTablePresenter_3)); + } + + void test_presenter_sets_commands_when_ADS_changed() { NiceMock<MockRunsTabView> mockRunsTabView; MockProgressableView mockProgress; NiceMock<MockDataProcessorPresenter> mockTablePresenter; + std::vector<DataProcessorPresenter *> tablePresenterVec; + tablePresenterVec.push_back(&mockTablePresenter); ReflRunsTabPresenter presenter(&mockRunsTabView, &mockProgress, - &mockTablePresenter); + tablePresenterVec); // Expect that the view clears the list of commands EXPECT_CALL(mockRunsTabView, clearCommands()).Times(Exactly(1)); @@ -78,8 +106,11 @@ public: MockProgressableView mockProgress; NiceMock<MockDataProcessorPresenter> mockTablePresenter; MockMainWindowPresenter mockMainPresenter; + std::vector<DataProcessorPresenter *> tablePresenterVec; + tablePresenterVec.push_back(&mockTablePresenter); + ReflRunsTabPresenter presenter(&mockRunsTabView, &mockProgress, - &mockTablePresenter); + tablePresenterVec); presenter.acceptMainPresenter(&mockMainPresenter); EXPECT_CALL(mockMainPresenter, @@ -94,8 +125,10 @@ public: MockProgressableView mockProgress; NiceMock<MockDataProcessorPresenter> mockTablePresenter; MockMainWindowPresenter mockMainPresenter; + std::vector<DataProcessorPresenter *> tablePresenterVec; + tablePresenterVec.push_back(&mockTablePresenter); ReflRunsTabPresenter presenter(&mockRunsTabView, &mockProgress, - &mockTablePresenter); + tablePresenterVec); presenter.acceptMainPresenter(&mockMainPresenter); EXPECT_CALL(mockMainPresenter, askUserYesNo("Prompt", "Title")).Times(1); @@ -109,8 +142,10 @@ public: MockProgressableView mockProgress; NiceMock<MockDataProcessorPresenter> mockTablePresenter; MockMainWindowPresenter mockMainPresenter; + std::vector<DataProcessorPresenter *> tablePresenterVec; + tablePresenterVec.push_back(&mockTablePresenter); ReflRunsTabPresenter presenter(&mockRunsTabView, &mockProgress, - &mockTablePresenter); + tablePresenterVec); presenter.acceptMainPresenter(&mockMainPresenter); EXPECT_CALL(mockMainPresenter, giveUserWarning("Prompt", "Warning Message")) @@ -125,8 +160,10 @@ public: MockProgressableView mockProgress; NiceMock<MockDataProcessorPresenter> mockTablePresenter; MockMainWindowPresenter mockMainPresenter; + std::vector<DataProcessorPresenter *> tablePresenterVec; + tablePresenterVec.push_back(&mockTablePresenter); ReflRunsTabPresenter presenter(&mockRunsTabView, &mockProgress, - &mockTablePresenter); + tablePresenterVec); presenter.acceptMainPresenter(&mockMainPresenter); EXPECT_CALL(mockMainPresenter, @@ -141,8 +178,10 @@ public: MockProgressableView mockProgress; NiceMock<MockDataProcessorPresenter> mockTablePresenter; MockMainWindowPresenter mockMainPresenter; + std::vector<DataProcessorPresenter *> tablePresenterVec; + tablePresenterVec.push_back(&mockTablePresenter); ReflRunsTabPresenter presenter(&mockRunsTabView, &mockProgress, - &mockTablePresenter); + tablePresenterVec); presenter.acceptMainPresenter(&mockMainPresenter); EXPECT_CALL(mockMainPresenter, runPythonAlgorithm("Python code to run")) @@ -157,14 +196,21 @@ public: MockProgressableView mockProgress; NiceMock<MockDataProcessorPresenter> mockTablePresenter; MockMainWindowPresenter mockMainPresenter; + std::vector<DataProcessorPresenter *> tablePresenterVec; + tablePresenterVec.push_back(&mockTablePresenter); ReflRunsTabPresenter presenter(&mockRunsTabView, &mockProgress, - &mockTablePresenter); + tablePresenterVec); presenter.acceptMainPresenter(&mockMainPresenter); - EXPECT_CALL(mockMainPresenter, getTransmissionOptions()).Times(1); + int group = 199; + EXPECT_CALL(mockRunsTabView, getSelectedGroup()) + .Times(Exactly(1)) + .WillOnce(Return(group)); + EXPECT_CALL(mockMainPresenter, getTransmissionOptions(group)).Times(1); presenter.getPreprocessingOptions(); TS_ASSERT(Mock::VerifyAndClearExpectations(&mockMainPresenter)); + TS_ASSERT(Mock::VerifyAndClearExpectations(&mockRunsTabView)); } void test_processingOptions() { @@ -172,14 +218,21 @@ public: MockProgressableView mockProgress; NiceMock<MockDataProcessorPresenter> mockTablePresenter; MockMainWindowPresenter mockMainPresenter; + std::vector<DataProcessorPresenter *> tablePresenterVec; + tablePresenterVec.push_back(&mockTablePresenter); ReflRunsTabPresenter presenter(&mockRunsTabView, &mockProgress, - &mockTablePresenter); + tablePresenterVec); presenter.acceptMainPresenter(&mockMainPresenter); - EXPECT_CALL(mockMainPresenter, getReductionOptions()).Times(1); + int group = 199; + EXPECT_CALL(mockRunsTabView, getSelectedGroup()) + .Times(Exactly(1)) + .WillOnce(Return(group)); + EXPECT_CALL(mockMainPresenter, getReductionOptions(group)).Times(1); presenter.getProcessingOptions(); TS_ASSERT(Mock::VerifyAndClearExpectations(&mockMainPresenter)); + TS_ASSERT(Mock::VerifyAndClearExpectations(&mockRunsTabView)); } void test_postprocessingOptions() { @@ -187,14 +240,52 @@ public: MockProgressableView mockProgress; NiceMock<MockDataProcessorPresenter> mockTablePresenter; MockMainWindowPresenter mockMainPresenter; + std::vector<DataProcessorPresenter *> tablePresenterVec; + tablePresenterVec.push_back(&mockTablePresenter); ReflRunsTabPresenter presenter(&mockRunsTabView, &mockProgress, - &mockTablePresenter); + tablePresenterVec); presenter.acceptMainPresenter(&mockMainPresenter); - EXPECT_CALL(mockMainPresenter, getStitchOptions()).Times(1); + int group = 199; + EXPECT_CALL(mockRunsTabView, getSelectedGroup()) + .Times(Exactly(1)) + .WillOnce(Return(group)); + EXPECT_CALL(mockMainPresenter, getStitchOptions(group)).Times(1); presenter.getPostprocessingOptions(); TS_ASSERT(Mock::VerifyAndClearExpectations(&mockMainPresenter)); + TS_ASSERT(Mock::VerifyAndClearExpectations(&mockRunsTabView)); + } + + void test_when_group_changes_commands_are_updated() { + NiceMock<MockRunsTabView> mockRunsTabView; + MockProgressableView mockProgress; + NiceMock<MockDataProcessorPresenter> mockTablePresenter_0; + NiceMock<MockDataProcessorPresenter> mockTablePresenter_1; + NiceMock<MockDataProcessorPresenter> mockTablePresenter_2; + MockMainWindowPresenter mockMainPresenter; + std::vector<DataProcessorPresenter *> tablePresenterVec; + tablePresenterVec.push_back(&mockTablePresenter_0); + tablePresenterVec.push_back(&mockTablePresenter_1); + tablePresenterVec.push_back(&mockTablePresenter_2); + + ReflRunsTabPresenter presenter(&mockRunsTabView, &mockProgress, + tablePresenterVec); + presenter.acceptMainPresenter(&mockMainPresenter); + + EXPECT_CALL(mockRunsTabView, getSelectedGroup()) + .Times(Exactly(1)) + .WillOnce(Return(1)); + // Commands should be updated with presenter of selected group + EXPECT_CALL(mockTablePresenter_0, publishCommandsMocked()).Times(0); + EXPECT_CALL(mockTablePresenter_1, publishCommandsMocked()).Times(1); + EXPECT_CALL(mockTablePresenter_2, publishCommandsMocked()).Times(0); + presenter.notify(IReflRunsTabPresenter::GroupChangedFlag); + + TS_ASSERT(Mock::VerifyAndClearExpectations(&mockMainPresenter)); + TS_ASSERT(Mock::VerifyAndClearExpectations(&mockTablePresenter_0)); + TS_ASSERT(Mock::VerifyAndClearExpectations(&mockTablePresenter_1)); + TS_ASSERT(Mock::VerifyAndClearExpectations(&mockTablePresenter_2)); } }; diff --git a/MantidQt/CustomInterfaces/test/ReflSettingsPresenterTest.h b/MantidQt/CustomInterfaces/test/ReflSettingsPresenterTest.h new file mode 100644 index 0000000000000000000000000000000000000000..4f2335622db0455a2fc6a0e5006a47ffb741645b --- /dev/null +++ b/MantidQt/CustomInterfaces/test/ReflSettingsPresenterTest.h @@ -0,0 +1,245 @@ +#ifndef MANTID_CUSTOMINTERFACES_REFLSETTINGSPRESENTERTEST_H +#define MANTID_CUSTOMINTERFACES_REFLSETTINGSPRESENTERTEST_H + +#include <cxxtest/TestSuite.h> +#include <gmock/gmock.h> +#include <gtest/gtest.h> + +#include "MantidAPI/AnalysisDataService.h" +#include "MantidAPI/FrameworkManager.h" +#include "MantidQtCustomInterfaces/Reflectometry/ReflSettingsPresenter.h" +#include "ReflMockObjects.h" +#include <boost/algorithm/string.hpp> + +using namespace MantidQt::CustomInterfaces; +using namespace testing; + +namespace { +class split_q { +private: + mutable bool in_q; + +public: + split_q() : in_q(false) {} + bool operator()(char c) const { + if (c == '\"') + in_q = !in_q; + return !in_q && c == ','; + } +}; +} + +//===================================================================================== +// Functional tests +//===================================================================================== +class ReflSettingsPresenterTest : public CxxTest::TestSuite { + +public: + // This pair of boilerplate methods prevent the suite being created statically + // This means the constructor isn't called when running other tests + static ReflSettingsPresenterTest *createSuite() { + return new ReflSettingsPresenterTest(); + } + static void destroySuite(ReflSettingsPresenterTest *suite) { delete suite; } + + ReflSettingsPresenterTest() { FrameworkManager::Instance(); } + + void testGetTransmissionOptions() { + MockSettingsView mockView; + ReflSettingsPresenter presenter(&mockView); + + EXPECT_CALL(mockView, getAnalysisMode()) + .Times(Exactly(1)) + .WillOnce(Return("MultiDetectorAnalysis")); + EXPECT_CALL(mockView, getMonitorIntegralMin()) + .Times(Exactly(1)) + .WillOnce(Return("4")); + EXPECT_CALL(mockView, getMonitorIntegralMax()) + .Times(Exactly(1)) + .WillOnce(Return("10")); + EXPECT_CALL(mockView, getMonitorBackgroundMin()) + .Times(Exactly(1)) + .WillOnce(Return("12")); + EXPECT_CALL(mockView, getMonitorBackgroundMax()) + .Times(Exactly(1)) + .WillOnce(Return("17")); + EXPECT_CALL(mockView, getLambdaMin()) + .Times(Exactly(1)) + .WillOnce(Return("1")); + EXPECT_CALL(mockView, getLambdaMax()) + .Times(Exactly(1)) + .WillOnce(Return("15")); + EXPECT_CALL(mockView, getI0MonitorIndex()) + .Times(Exactly(1)) + .WillOnce(Return("2")); + EXPECT_CALL(mockView, getProcessingInstructions()) + .Times(Exactly(1)) + .WillOnce(Return("\"3,4\"")); + auto options = presenter.getTransmissionOptions(); + + std::vector<std::string> optionsVec; + boost::split(optionsVec, options, split_q()); + TS_ASSERT_EQUALS(optionsVec[0], "AnalysisMode=MultiDetectorAnalysis"); + TS_ASSERT_EQUALS(optionsVec[1], "MonitorIntegrationWavelengthMin=4"); + TS_ASSERT_EQUALS(optionsVec[2], "MonitorIntegrationWavelengthMax=10"); + TS_ASSERT_EQUALS(optionsVec[3], "MonitorBackgroundWavelengthMin=12"); + TS_ASSERT_EQUALS(optionsVec[4], "MonitorBackgroundWavelengthMax=17"); + TS_ASSERT_EQUALS(optionsVec[5], "WavelengthMin=1"); + TS_ASSERT_EQUALS(optionsVec[6], "WavelengthMax=15"); + TS_ASSERT_EQUALS(optionsVec[7], "I0MonitorIndex=2"); + TS_ASSERT_EQUALS(optionsVec[8], "ProcessingInstructions=\"3,4\""); + + TS_ASSERT(Mock::VerifyAndClearExpectations(&mockView)); + } + + void testGetReductionOptions() { + MockSettingsView mockView; + ReflSettingsPresenter presenter(&mockView); + + EXPECT_CALL(mockView, getAnalysisMode()) + .Times(Exactly(1)) + .WillOnce(Return("MultiDetectorAnalysis")); + EXPECT_CALL(mockView, getCRho()).Times(Exactly(1)).WillOnce(Return("2.5")); + EXPECT_CALL(mockView, getCAlpha()) + .Times(Exactly(1)) + .WillOnce(Return("0.6")); + EXPECT_CALL(mockView, getCAp()).Times(Exactly(1)).WillOnce(Return("100.0")); + EXPECT_CALL(mockView, getCPp()).Times(Exactly(1)).WillOnce(Return("0.54")); + EXPECT_CALL(mockView, getDirectBeam()) + .Times(Exactly(1)) + .WillOnce(Return("\"0,3\"")); + EXPECT_CALL(mockView, getPolarisationCorrections()) + .Times(Exactly(1)) + .WillOnce(Return("PNR")); + EXPECT_CALL(mockView, getIntMonCheck()) + .Times(Exactly(1)) + .WillOnce(Return("True")); + EXPECT_CALL(mockView, getMonitorIntegralMin()) + .Times(Exactly(1)) + .WillOnce(Return("4")); + EXPECT_CALL(mockView, getMonitorIntegralMax()) + .Times(Exactly(1)) + .WillOnce(Return("10")); + EXPECT_CALL(mockView, getMonitorBackgroundMin()) + .Times(Exactly(1)) + .WillOnce(Return("12")); + EXPECT_CALL(mockView, getMonitorBackgroundMax()) + .Times(Exactly(1)) + .WillOnce(Return("17")); + EXPECT_CALL(mockView, getLambdaMin()) + .Times(Exactly(1)) + .WillOnce(Return("1")); + EXPECT_CALL(mockView, getLambdaMax()) + .Times(Exactly(1)) + .WillOnce(Return("15")); + EXPECT_CALL(mockView, getI0MonitorIndex()) + .Times(Exactly(1)) + .WillOnce(Return("2")); + EXPECT_CALL(mockView, getScaleFactor()) + .Times(Exactly(1)) + .WillOnce(Return("2")); + EXPECT_CALL(mockView, getMomentumTransferStep()) + .Times(Exactly(1)) + .WillOnce(Return("-0.02")); + EXPECT_CALL(mockView, getProcessingInstructions()) + .Times(Exactly(1)) + .WillOnce(Return("\"3,4\"")); + EXPECT_CALL(mockView, getTransmissionRuns()) + .Times(Exactly(1)) + .WillOnce(Return("INTER00013463,INTER00013464")); + auto options = presenter.getReductionOptions(); + + std::vector<std::string> optionsVec; + boost::split(optionsVec, options, split_q()); + TS_ASSERT_EQUALS(optionsVec[0], "AnalysisMode=MultiDetectorAnalysis"); + TS_ASSERT_EQUALS(optionsVec[1], "CRho=2.5"); + TS_ASSERT_EQUALS(optionsVec[2], "CAlpha=0.6"); + TS_ASSERT_EQUALS(optionsVec[3], "CAp=100.0"); + TS_ASSERT_EQUALS(optionsVec[4], "CPp=0.54"); + TS_ASSERT_EQUALS(optionsVec[5], "RegionOfDirectBeam=\"0,3\""); + TS_ASSERT_EQUALS(optionsVec[6], "PolarizationAnalysis=PNR"); + TS_ASSERT_EQUALS(optionsVec[7], "NormalizeByIntegratedMonitors=True"); + TS_ASSERT_EQUALS(optionsVec[8], "MonitorIntegrationWavelengthMin=4"); + TS_ASSERT_EQUALS(optionsVec[9], "MonitorIntegrationWavelengthMax=10"); + TS_ASSERT_EQUALS(optionsVec[10], "MonitorBackgroundWavelengthMin=12"); + TS_ASSERT_EQUALS(optionsVec[11], "MonitorBackgroundWavelengthMax=17"); + TS_ASSERT_EQUALS(optionsVec[12], "WavelengthMin=1"); + TS_ASSERT_EQUALS(optionsVec[13], "WavelengthMax=15"); + TS_ASSERT_EQUALS(optionsVec[14], "I0MonitorIndex=2"); + TS_ASSERT_EQUALS(optionsVec[15], "ScaleFactor=2"); + TS_ASSERT_EQUALS(optionsVec[16], "MomentumTransferStep=-0.02"); + TS_ASSERT_EQUALS(optionsVec[17], "ProcessingInstructions=\"3,4\""); + TS_ASSERT_EQUALS(optionsVec[18], + "FirstTransmissionRun=TRANS_INTER00013463"); + TS_ASSERT_EQUALS(optionsVec[19], + "SecondTransmissionRun=TRANS_INTER00013464"); + + TS_ASSERT(AnalysisDataService::Instance().doesExist("TRANS_INTER00013463")); + TS_ASSERT(AnalysisDataService::Instance().doesExist("TRANS_INTER00013464")); + AnalysisDataService::Instance().clear(); + + TS_ASSERT(Mock::VerifyAndClearExpectations(&mockView)); + } + + void testStitchOptions() { + MockSettingsView mockView; + ReflSettingsPresenter presenter(&mockView); + + EXPECT_CALL(mockView, getStitchOptions()).Times(Exactly(1)); + presenter.getStitchOptions(); + TS_ASSERT(Mock::VerifyAndClearExpectations(&mockView)); + } + + void testPolarisationOptionsEnabled() { + MockSettingsView mockView; + ReflSettingsPresenter presenter(&mockView); + + EXPECT_CALL(mockView, setPolarisationOptionsEnabled(false)) + .Times(Exactly(1)); + presenter.setInstrumentName("INTER"); + EXPECT_CALL(mockView, setPolarisationOptionsEnabled(true)) + .Times(Exactly(1)); + presenter.setInstrumentName("POLREF"); + } + + void testExperimentDefaults() { + MockSettingsView mockView; + ReflSettingsPresenter presenter(&mockView); + MockMainWindowPresenter mainPresenter; + + // Set instrument to 'POLREF' + EXPECT_CALL(mockView, setPolarisationOptionsEnabled(true)) + .Times(Exactly(1)); + presenter.setInstrumentName("POLREF"); + + std::vector<std::string> defaults = { + "PointDetectorAnalysis", "None", + "1.006831,-0.011467,0.002244,-0.000095", + "1.017526,-0.017183,0.003136,-0.000140", + "0.917940,0.038265,-0.006645,0.000282", + "0.972762,0.001828,-0.000261,0.0", "1"}; + + EXPECT_CALL(mockView, setExpDefaults(defaults)).Times(1); + presenter.notify(IReflSettingsPresenter::ExpDefaultsFlag); + TS_ASSERT(Mock::VerifyAndClearExpectations(&mockView)); + } + + void testInstrumentDefaults() { + MockSettingsView mockView; + MockMainWindowPresenter mainPresenter; + ReflSettingsPresenter presenter(&mockView); + + // Set instrument to 'INTER' + EXPECT_CALL(mockView, setPolarisationOptionsEnabled(false)) + .Times(Exactly(1)); + presenter.setInstrumentName("INTER"); + + std::vector<double> defaults = {1., 4.0, 10., 15., 17., 1.0, 17., 2.0}; + + EXPECT_CALL(mockView, setInstDefaults(defaults)).Times(1); + presenter.notify(IReflSettingsPresenter::InstDefaultsFlag); + TS_ASSERT(Mock::VerifyAndClearExpectations(&mockView)); + } +}; + +#endif /* MANTID_CUSTOMINTERFACES_REFLSETTINGSPRESENTERTEST_H */ diff --git a/MantidQt/CustomInterfaces/test/ReflSettingsTabPresenterTest.h b/MantidQt/CustomInterfaces/test/ReflSettingsTabPresenterTest.h index f5d253d142608d1c254bc1d4cc96e02c639df458..8390fc7248d85a5e47a5caab038539f782ea8337 100644 --- a/MantidQt/CustomInterfaces/test/ReflSettingsTabPresenterTest.h +++ b/MantidQt/CustomInterfaces/test/ReflSettingsTabPresenterTest.h @@ -14,21 +14,6 @@ using namespace MantidQt::CustomInterfaces; using namespace testing; -namespace { -class split_q { -private: - mutable bool in_q; - -public: - split_q() : in_q(false) {} - bool operator()(char c) const { - if (c == '\"') - in_q = !in_q; - return !in_q && c == ','; - } -}; -} - //===================================================================================== // Functional tests //===================================================================================== @@ -46,207 +31,131 @@ public: ReflSettingsTabPresenterTest() { FrameworkManager::Instance(); } - void testGetTransmissionOptions() { - MockSettingsTabView mockView; - ReflSettingsTabPresenter presenter(&mockView); - - EXPECT_CALL(mockView, getAnalysisMode()) - .Times(Exactly(1)) - .WillOnce(Return("MultiDetectorAnalysis")); - EXPECT_CALL(mockView, getMonitorIntegralMin()) - .Times(Exactly(1)) - .WillOnce(Return("4")); - EXPECT_CALL(mockView, getMonitorIntegralMax()) - .Times(Exactly(1)) - .WillOnce(Return("10")); - EXPECT_CALL(mockView, getMonitorBackgroundMin()) - .Times(Exactly(1)) - .WillOnce(Return("12")); - EXPECT_CALL(mockView, getMonitorBackgroundMax()) - .Times(Exactly(1)) - .WillOnce(Return("17")); - EXPECT_CALL(mockView, getLambdaMin()) - .Times(Exactly(1)) - .WillOnce(Return("1")); - EXPECT_CALL(mockView, getLambdaMax()) - .Times(Exactly(1)) - .WillOnce(Return("15")); - EXPECT_CALL(mockView, getI0MonitorIndex()) - .Times(Exactly(1)) - .WillOnce(Return("2")); - EXPECT_CALL(mockView, getProcessingInstructions()) - .Times(Exactly(1)) - .WillOnce(Return("\"3,4\"")); - auto options = presenter.getTransmissionOptions(); - - std::vector<std::string> optionsVec; - boost::split(optionsVec, options, split_q()); - TS_ASSERT_EQUALS(optionsVec[0], "AnalysisMode=MultiDetectorAnalysis"); - TS_ASSERT_EQUALS(optionsVec[1], "MonitorIntegrationWavelengthMin=4"); - TS_ASSERT_EQUALS(optionsVec[2], "MonitorIntegrationWavelengthMax=10"); - TS_ASSERT_EQUALS(optionsVec[3], "MonitorBackgroundWavelengthMin=12"); - TS_ASSERT_EQUALS(optionsVec[4], "MonitorBackgroundWavelengthMax=17"); - TS_ASSERT_EQUALS(optionsVec[5], "WavelengthMin=1"); - TS_ASSERT_EQUALS(optionsVec[6], "WavelengthMax=15"); - TS_ASSERT_EQUALS(optionsVec[7], "I0MonitorIndex=2"); - TS_ASSERT_EQUALS(optionsVec[8], "ProcessingInstructions=\"3,4\""); - - TS_ASSERT(Mock::VerifyAndClearExpectations(&mockView)); - } + void test_instrument_name() { + MockSettingsPresenter presenter_1; + MockSettingsPresenter presenter_2; + std::vector<IReflSettingsPresenter *> settingsPresenters; + settingsPresenters.push_back(&presenter_1); + settingsPresenters.push_back(&presenter_2); + ReflSettingsTabPresenter presenter(settingsPresenters); - void testGetReductionOptions() { - MockSettingsTabView mockView; - ReflSettingsTabPresenter presenter(&mockView); - - EXPECT_CALL(mockView, getAnalysisMode()) - .Times(Exactly(1)) - .WillOnce(Return("MultiDetectorAnalysis")); - EXPECT_CALL(mockView, getCRho()).Times(Exactly(1)).WillOnce(Return("2.5")); - EXPECT_CALL(mockView, getCAlpha()) - .Times(Exactly(1)) - .WillOnce(Return("0.6")); - EXPECT_CALL(mockView, getCAp()).Times(Exactly(1)).WillOnce(Return("100.0")); - EXPECT_CALL(mockView, getCPp()).Times(Exactly(1)).WillOnce(Return("0.54")); - EXPECT_CALL(mockView, getDirectBeam()) - .Times(Exactly(1)) - .WillOnce(Return("\"0,3\"")); - EXPECT_CALL(mockView, getPolarisationCorrections()) - .Times(Exactly(1)) - .WillOnce(Return("PNR")); - EXPECT_CALL(mockView, getIntMonCheck()) - .Times(Exactly(1)) - .WillOnce(Return("True")); - EXPECT_CALL(mockView, getMonitorIntegralMin()) - .Times(Exactly(1)) - .WillOnce(Return("4")); - EXPECT_CALL(mockView, getMonitorIntegralMax()) - .Times(Exactly(1)) - .WillOnce(Return("10")); - EXPECT_CALL(mockView, getMonitorBackgroundMin()) - .Times(Exactly(1)) - .WillOnce(Return("12")); - EXPECT_CALL(mockView, getMonitorBackgroundMax()) - .Times(Exactly(1)) - .WillOnce(Return("17")); - EXPECT_CALL(mockView, getLambdaMin()) - .Times(Exactly(1)) - .WillOnce(Return("1")); - EXPECT_CALL(mockView, getLambdaMax()) - .Times(Exactly(1)) - .WillOnce(Return("15")); - EXPECT_CALL(mockView, getI0MonitorIndex()) - .Times(Exactly(1)) - .WillOnce(Return("2")); - EXPECT_CALL(mockView, getScaleFactor()) - .Times(Exactly(1)) - .WillOnce(Return("2")); - EXPECT_CALL(mockView, getMomentumTransferStep()) - .Times(Exactly(1)) - .WillOnce(Return("-0.02")); - EXPECT_CALL(mockView, getProcessingInstructions()) - .Times(Exactly(1)) - .WillOnce(Return("\"3,4\"")); - EXPECT_CALL(mockView, getTransmissionRuns()) - .Times(Exactly(1)) - .WillOnce(Return("INTER00013463,INTER00013464")); - auto options = presenter.getReductionOptions(); - - std::vector<std::string> optionsVec; - boost::split(optionsVec, options, split_q()); - TS_ASSERT_EQUALS(optionsVec[0], "AnalysisMode=MultiDetectorAnalysis"); - TS_ASSERT_EQUALS(optionsVec[1], "CRho=2.5"); - TS_ASSERT_EQUALS(optionsVec[2], "CAlpha=0.6"); - TS_ASSERT_EQUALS(optionsVec[3], "CAp=100.0"); - TS_ASSERT_EQUALS(optionsVec[4], "CPp=0.54"); - TS_ASSERT_EQUALS(optionsVec[5], "RegionOfDirectBeam=\"0,3\""); - TS_ASSERT_EQUALS(optionsVec[6], "PolarizationAnalysis=PNR"); - TS_ASSERT_EQUALS(optionsVec[7], "NormalizeByIntegratedMonitors=True"); - TS_ASSERT_EQUALS(optionsVec[8], "MonitorIntegrationWavelengthMin=4"); - TS_ASSERT_EQUALS(optionsVec[9], "MonitorIntegrationWavelengthMax=10"); - TS_ASSERT_EQUALS(optionsVec[10], "MonitorBackgroundWavelengthMin=12"); - TS_ASSERT_EQUALS(optionsVec[11], "MonitorBackgroundWavelengthMax=17"); - TS_ASSERT_EQUALS(optionsVec[12], "WavelengthMin=1"); - TS_ASSERT_EQUALS(optionsVec[13], "WavelengthMax=15"); - TS_ASSERT_EQUALS(optionsVec[14], "I0MonitorIndex=2"); - TS_ASSERT_EQUALS(optionsVec[15], "ScaleFactor=2"); - TS_ASSERT_EQUALS(optionsVec[16], "MomentumTransferStep=-0.02"); - TS_ASSERT_EQUALS(optionsVec[17], "ProcessingInstructions=\"3,4\""); - TS_ASSERT_EQUALS(optionsVec[18], - "FirstTransmissionRun=TRANS_INTER00013463"); - TS_ASSERT_EQUALS(optionsVec[19], - "SecondTransmissionRun=TRANS_INTER00013464"); - - TS_ASSERT(AnalysisDataService::Instance().doesExist("TRANS_INTER00013463")); - TS_ASSERT(AnalysisDataService::Instance().doesExist("TRANS_INTER00013464")); - AnalysisDataService::Instance().clear(); - - TS_ASSERT(Mock::VerifyAndClearExpectations(&mockView)); - } + EXPECT_CALL(presenter_1, setInstrumentName("INSTRUMENT_NAME")).Times(1); + EXPECT_CALL(presenter_2, setInstrumentName("INSTRUMENT_NAME")).Times(1); + presenter.setInstrumentName("INSTRUMENT_NAME"); - void testStitchOptions() { - MockSettingsTabView mockView; - ReflSettingsTabPresenter presenter(&mockView); - - EXPECT_CALL(mockView, getStitchOptions()).Times(Exactly(1)); - presenter.getStitchOptions(); - TS_ASSERT(Mock::VerifyAndClearExpectations(&mockView)); + TS_ASSERT(Mock::VerifyAndClearExpectations(&presenter_1)); + TS_ASSERT(Mock::VerifyAndClearExpectations(&presenter_2)); } - void testPolarisationOptionsEnabled() { - MockSettingsTabView mockView; - ReflSettingsTabPresenter presenter(&mockView); - - EXPECT_CALL(mockView, setPolarisationOptionsEnabled(false)) - .Times(Exactly(1)); - presenter.setInstrumentName("INTER"); - EXPECT_CALL(mockView, setPolarisationOptionsEnabled(true)) - .Times(Exactly(1)); - presenter.setInstrumentName("POLREF"); + void test_transmission_options() { + MockSettingsPresenter presenter_0; + MockSettingsPresenter presenter_1; + MockSettingsPresenter presenter_2; + + std::vector<IReflSettingsPresenter *> settingsPresenters; + settingsPresenters.push_back(&presenter_0); + settingsPresenters.push_back(&presenter_1); + settingsPresenters.push_back(&presenter_2); + + ReflSettingsTabPresenter presenter(settingsPresenters); + + EXPECT_CALL(presenter_0, getTransmissionOptions()).Times(1); + EXPECT_CALL(presenter_1, getTransmissionOptions()).Times(0); + EXPECT_CALL(presenter_2, getTransmissionOptions()).Times(0); + presenter.getTransmissionOptions(0); + TS_ASSERT(Mock::VerifyAndClearExpectations(&presenter_0)); + TS_ASSERT(Mock::VerifyAndClearExpectations(&presenter_1)); + TS_ASSERT(Mock::VerifyAndClearExpectations(&presenter_2)); + + EXPECT_CALL(presenter_0, getTransmissionOptions()).Times(0); + EXPECT_CALL(presenter_1, getTransmissionOptions()).Times(1); + EXPECT_CALL(presenter_2, getTransmissionOptions()).Times(0); + presenter.getTransmissionOptions(1); + TS_ASSERT(Mock::VerifyAndClearExpectations(&presenter_0)); + TS_ASSERT(Mock::VerifyAndClearExpectations(&presenter_1)); + TS_ASSERT(Mock::VerifyAndClearExpectations(&presenter_2)); + + EXPECT_CALL(presenter_0, getTransmissionOptions()).Times(0); + EXPECT_CALL(presenter_1, getTransmissionOptions()).Times(0); + EXPECT_CALL(presenter_2, getTransmissionOptions()).Times(1); + presenter.getTransmissionOptions(2); + TS_ASSERT(Mock::VerifyAndClearExpectations(&presenter_0)); + TS_ASSERT(Mock::VerifyAndClearExpectations(&presenter_1)); + TS_ASSERT(Mock::VerifyAndClearExpectations(&presenter_2)); } - void testExperimentDefaults() { - MockSettingsTabView mockView; - ReflSettingsTabPresenter presenter(&mockView); - MockMainWindowPresenter mainPresenter; - - // This presenter accepts the main presenter - presenter.acceptMainPresenter(&mainPresenter); - - // Set instrument to 'POLREF' - EXPECT_CALL(mockView, setPolarisationOptionsEnabled(true)) - .Times(Exactly(1)); - presenter.setInstrumentName("POLREF"); - - std::vector<std::string> defaults = { - "PointDetectorAnalysis", "None", - "1.006831,-0.011467,0.002244,-0.000095", - "1.017526,-0.017183,0.003136,-0.000140", - "0.917940,0.038265,-0.006645,0.000282", - "0.972762,0.001828,-0.000261,0.0", "1"}; - - EXPECT_CALL(mockView, setExpDefaults(defaults)).Times(1); - presenter.notify(IReflSettingsTabPresenter::ExpDefaultsFlag); - TS_ASSERT(Mock::VerifyAndClearExpectations(&mockView)); + void test_reduction_options() { + MockSettingsPresenter presenter_0; + MockSettingsPresenter presenter_1; + MockSettingsPresenter presenter_2; + + std::vector<IReflSettingsPresenter *> settingsPresenters; + settingsPresenters.push_back(&presenter_0); + settingsPresenters.push_back(&presenter_1); + settingsPresenters.push_back(&presenter_2); + + ReflSettingsTabPresenter presenter(settingsPresenters); + + EXPECT_CALL(presenter_0, getReductionOptions()).Times(1); + EXPECT_CALL(presenter_1, getReductionOptions()).Times(0); + EXPECT_CALL(presenter_2, getReductionOptions()).Times(0); + presenter.getReductionOptions(0); + TS_ASSERT(Mock::VerifyAndClearExpectations(&presenter_0)); + TS_ASSERT(Mock::VerifyAndClearExpectations(&presenter_1)); + TS_ASSERT(Mock::VerifyAndClearExpectations(&presenter_2)); + + EXPECT_CALL(presenter_0, getReductionOptions()).Times(0); + EXPECT_CALL(presenter_1, getReductionOptions()).Times(1); + EXPECT_CALL(presenter_2, getReductionOptions()).Times(0); + presenter.getReductionOptions(1); + TS_ASSERT(Mock::VerifyAndClearExpectations(&presenter_0)); + TS_ASSERT(Mock::VerifyAndClearExpectations(&presenter_1)); + TS_ASSERT(Mock::VerifyAndClearExpectations(&presenter_2)); + + EXPECT_CALL(presenter_0, getReductionOptions()).Times(0); + EXPECT_CALL(presenter_1, getReductionOptions()).Times(0); + EXPECT_CALL(presenter_2, getReductionOptions()).Times(1); + presenter.getReductionOptions(2); + TS_ASSERT(Mock::VerifyAndClearExpectations(&presenter_0)); + TS_ASSERT(Mock::VerifyAndClearExpectations(&presenter_1)); + TS_ASSERT(Mock::VerifyAndClearExpectations(&presenter_2)); } - void testInstrumentDefaults() { - MockSettingsTabView mockView; - MockMainWindowPresenter mainPresenter; - ReflSettingsTabPresenter presenter(&mockView); - - // This presenter accepts the main presenter - presenter.acceptMainPresenter(&mainPresenter); - - // Set instrument to 'INTER' - EXPECT_CALL(mockView, setPolarisationOptionsEnabled(false)) - .Times(Exactly(1)); - presenter.setInstrumentName("INTER"); - - std::vector<double> defaults = {1., 4.0, 10., 15., 17., 1.0, 17., 2.0}; - - EXPECT_CALL(mockView, setInstDefaults(defaults)).Times(1); - presenter.notify(IReflSettingsTabPresenter::InstDefaultsFlag); - TS_ASSERT(Mock::VerifyAndClearExpectations(&mockView)); + void test_stitch_options() { + MockSettingsPresenter presenter_0; + MockSettingsPresenter presenter_1; + MockSettingsPresenter presenter_2; + + std::vector<IReflSettingsPresenter *> settingsPresenters; + settingsPresenters.push_back(&presenter_0); + settingsPresenters.push_back(&presenter_1); + settingsPresenters.push_back(&presenter_2); + + ReflSettingsTabPresenter presenter(settingsPresenters); + + EXPECT_CALL(presenter_0, getStitchOptions()).Times(1); + EXPECT_CALL(presenter_1, getStitchOptions()).Times(0); + EXPECT_CALL(presenter_2, getStitchOptions()).Times(0); + presenter.getStitchOptions(0); + TS_ASSERT(Mock::VerifyAndClearExpectations(&presenter_0)); + TS_ASSERT(Mock::VerifyAndClearExpectations(&presenter_1)); + TS_ASSERT(Mock::VerifyAndClearExpectations(&presenter_2)); + + EXPECT_CALL(presenter_0, getStitchOptions()).Times(0); + EXPECT_CALL(presenter_1, getStitchOptions()).Times(1); + EXPECT_CALL(presenter_2, getStitchOptions()).Times(0); + presenter.getStitchOptions(1); + TS_ASSERT(Mock::VerifyAndClearExpectations(&presenter_0)); + TS_ASSERT(Mock::VerifyAndClearExpectations(&presenter_1)); + TS_ASSERT(Mock::VerifyAndClearExpectations(&presenter_2)); + + EXPECT_CALL(presenter_0, getStitchOptions()).Times(0); + EXPECT_CALL(presenter_1, getStitchOptions()).Times(0); + EXPECT_CALL(presenter_2, getStitchOptions()).Times(1); + presenter.getStitchOptions(2); + TS_ASSERT(Mock::VerifyAndClearExpectations(&presenter_0)); + TS_ASSERT(Mock::VerifyAndClearExpectations(&presenter_1)); + TS_ASSERT(Mock::VerifyAndClearExpectations(&presenter_2)); } }; diff --git a/MantidQt/MantidWidgets/CMakeLists.txt b/MantidQt/MantidWidgets/CMakeLists.txt index e1a947158e21eb28c66a71c498940b443a6c2189..e8e15d5862eec33acfe303e23f082c2481c26c9f 100644 --- a/MantidQt/MantidWidgets/CMakeLists.txt +++ b/MantidQt/MantidWidgets/CMakeLists.txt @@ -84,13 +84,13 @@ set ( SRC_FILES src/InstrumentView/XIntegrationControl.cpp src/LineEditWithClear.cpp src/LogValueSelector.cpp - src/MantidTreeWidget.cpp - src/MantidTreeWidgetItem.cpp src/MWDiag.cpp src/MWRunFiles.cpp src/MWView.cpp src/MantidHelpWindow.cpp src/MantidSurfacePlotDialog.cpp + src/MantidTreeWidget.cpp + src/MantidTreeWidgetItem.cpp src/MantidWSIndexDialog.cpp src/MessageDisplay.cpp src/MultifitSetupDialog.cpp @@ -114,14 +114,15 @@ set ( SRC_FILES src/SlitCalculator.cpp src/StringDialogEditor.cpp src/StringEditorFactory.cpp + src/TrackedAction.cpp src/UserFunctionDialog.cpp src/WorkspaceEditorFactory.cpp + src/WorkspacePresenter/ADSAdapter.cpp + src/WorkspacePresenter/QWorkspaceDockView.cpp + src/WorkspacePresenter/WorkspacePresenter.cpp src/WorkspaceSelector.cpp src/pqHelpWindow.cxx src/pythonCalc.cpp - src/WorkspacePresenter/WorkspacePresenter.cpp - src/WorkspacePresenter/ADSAdapter.cpp - src/WorkspacePresenter/QWorkspaceDockView.cpp ) # Header files with Q_OBJECT that qmake will "moc" @@ -183,6 +184,7 @@ set ( MOC_FILES inc/MantidQtMantidWidgets/SlitCalculator.h inc/MantidQtMantidWidgets/StringDialogEditor.h inc/MantidQtMantidWidgets/StringEditorFactory.h + inc/MantidQtMantidWidgets/TrackedAction.h inc/MantidQtMantidWidgets/UserFunctionDialog.h inc/MantidQtMantidWidgets/WorkspaceEditorFactory.h inc/MantidQtMantidWidgets/WorkspaceSelector.h @@ -231,6 +233,7 @@ set ( INC_FILES inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorGenerateNotebook.h inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorGroupRowsCommand.h inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorImportTableCommand.h + inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorMainPresenter.h inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorNewTableCommand.h inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorOneLevelTreeManager.h inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorOpenTableCommand.h @@ -252,7 +255,6 @@ set ( INC_FILES inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorView.h inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorWhiteList.h inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorWorkspaceCommand.h - inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorMainPresenter.h inc/MantidQtMantidWidgets/DataProcessorUI/GenericDataProcessorPresenter.h inc/MantidQtMantidWidgets/DataProcessorUI/GenericDataProcessorPresenterFactory.h inc/MantidQtMantidWidgets/DataProcessorUI/ParseKeyValueString.h @@ -315,14 +317,13 @@ set ( INC_FILES inc/MantidQtMantidWidgets/MuonFitDataSelector.h inc/MantidQtMantidWidgets/MuonFunctionBrowser.h inc/MantidQtMantidWidgets/ProgressPresenter.h - inc/MantidQtMantidWidgets/ProgressableView.h - inc/MantidQtMantidWidgets/ProgressPresenter.h - inc/MantidQtMantidWidgets/WorkspacePresenter/ViewNotifiable.h - inc/MantidQtMantidWidgets/WorkspacePresenter/WorkspaceProviderNotifiable.h - inc/MantidQtMantidWidgets/WorkspacePresenter/WorkspacePresenter.h - inc/MantidQtMantidWidgets/WorkspacePresenter/WorkspaceProvider.h - inc/MantidQtMantidWidgets/WorkspacePresenter/ADSAdapter.h - inc/MantidQtMantidWidgets/WorkspacePresenter/IWorkspaceDockView.h + inc/MantidQtMantidWidgets/ProgressableView.h + inc/MantidQtMantidWidgets/WorkspacePresenter/ADSAdapter.h + inc/MantidQtMantidWidgets/WorkspacePresenter/IWorkspaceDockView.h + inc/MantidQtMantidWidgets/WorkspacePresenter/ViewNotifiable.h + inc/MantidQtMantidWidgets/WorkspacePresenter/WorkspacePresenter.h + inc/MantidQtMantidWidgets/WorkspacePresenter/WorkspaceProvider.h + inc/MantidQtMantidWidgets/WorkspacePresenter/WorkspaceProviderNotifiable.h ) # QtDesigner UI files to process @@ -360,22 +361,23 @@ set ( TEST_PY_FILES ) set ( TEST_FILES - AlgorithmHintStrategyTest.h - DataProcessorUI/DataProcessorPostprocessingAlgorithmTest.h - DataProcessorUI/DataProcessorPreprocessingAlgorithmTest.h - DataProcessorUI/DataProcessorProcessingAlgorithmBaseTest.h - DataProcessorUI/DataProcessorProcessingAlgorithmTest.h - DataProcessorUI/DataProcessorCommandsTest.h - DataProcessorUI/DataProcessorGenerateNotebookTest.h - DataProcessorUI/DataProcessorOneLevelTreeManagerTest.h - DataProcessorUI/DataProcessorTwoLevelTreeManagerTest.h - DataProcessorUI/DataProcessorWhiteListTest.h - DataProcessorUI/GenericDataProcessorPresenterTest.h - DataProcessorUI/ParseKeyValueStringTest.h - DataProcessorUI/QDataProcessorOneLevelTreeModelTest.h - DataProcessorUI/QDataProcessorTwoLevelTreeModelTest.h - WorkspacePresenter/WorkspacePresenterTest.h - WorkspacePresenter/ADSAdapterTest.h + AlgorithmHintStrategyTest.h + TrackedActionTest.h + DataProcessorUI/DataProcessorCommandsTest.h + DataProcessorUI/DataProcessorGenerateNotebookTest.h + DataProcessorUI/DataProcessorOneLevelTreeManagerTest.h + DataProcessorUI/DataProcessorPostprocessingAlgorithmTest.h + DataProcessorUI/DataProcessorPreprocessingAlgorithmTest.h + DataProcessorUI/DataProcessorProcessingAlgorithmBaseTest.h + DataProcessorUI/DataProcessorProcessingAlgorithmTest.h + DataProcessorUI/DataProcessorTwoLevelTreeManagerTest.h + DataProcessorUI/DataProcessorWhiteListTest.h + DataProcessorUI/GenericDataProcessorPresenterTest.h + DataProcessorUI/ParseKeyValueStringTest.h + DataProcessorUI/QDataProcessorOneLevelTreeModelTest.h + DataProcessorUI/QDataProcessorTwoLevelTreeModelTest.h + WorkspacePresenter/ADSAdapterTest.h + WorkspacePresenter/WorkspacePresenterTest.h ) find_package (Qt4 REQUIRED QtHelp QtWebKit QtNetwork QUIET) diff --git a/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorMockObjects.h b/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorMockObjects.h index 05341ea16a0283f10960843278af07c38b65f509..fe44edda61a55fd1eb293f65309d0e9d134b865d 100644 --- a/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorMockObjects.h +++ b/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorMockObjects.h @@ -108,17 +108,20 @@ public: bool(const std::string &prompt, const std::string &title)); MOCK_CONST_METHOD2(giveUserWarning, void(const std::string &prompt, const std::string &title)); + MOCK_METHOD0(publishCommandsMocked, void()); private: // Calls we don't care about const std::map<std::string, QVariant> &options() const override { return m_options; }; + std::vector<DataProcessorCommand_uptr> publishCommands() override { std::vector<DataProcessorCommand_uptr> commands; for (size_t i = 0; i < 27; i++) commands.push_back( Mantid::Kernel::make_unique<DataProcessorAppendRowCommand>(this)); + publishCommandsMocked(); return commands; }; std::set<std::string> getTableList() const { diff --git a/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/FitOptionsBrowser.h b/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/FitOptionsBrowser.h index 0ca9c6f49759c18d65f0dc5ffc6674a66a8622aa..952c7bee461b06cdfe4e74a637759aad0d66c18d 100644 --- a/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/FitOptionsBrowser.h +++ b/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/FitOptionsBrowser.h @@ -135,6 +135,8 @@ private: QtProperty *m_maxIterations; /// EvaluationType property QtProperty *m_evaluationType; + /// Peak radius property + QtProperty *m_peakRadius; // Fit properties /// Output property diff --git a/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/FitPropertyBrowser.h b/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/FitPropertyBrowser.h index d333b85018a54e1ec190425df60636c2e125adc8..d0e88e72c1c9e4060a2721e8cdadaa7e3ab91f5c 100644 --- a/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/FitPropertyBrowser.h +++ b/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/FitPropertyBrowser.h @@ -151,6 +151,8 @@ public: void normaliseData(bool on) { m_shouldBeNormalised = on; } /// Get the max number of iterations int maxIterations() const; + /// Get the peak radius for peak functions + int getPeakRadius() const; /// Get the start X double startX() const; @@ -413,6 +415,7 @@ protected: QtProperty *m_ignoreInvalidData; QtProperty *m_costFunction; QtProperty *m_maxIterations; + QtProperty *m_peakRadius; QtProperty *m_logValue; QtProperty *m_plotDiff; QtProperty *m_plotCompositeMembers; diff --git a/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/TrackedAction.h b/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/TrackedAction.h new file mode 100644 index 0000000000000000000000000000000000000000..9186fc6da17ae45f30c3562941efb8352b596942 --- /dev/null +++ b/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/TrackedAction.h @@ -0,0 +1,64 @@ +#ifndef MANTID_MANTIDWIDGETS_TRACKEDACTION_H_ +#define MANTID_MANTIDWIDGETS_TRACKEDACTION_H_ + +#include "WidgetDllOption.h" +#include <QAction> + +namespace MantidQt { +namespace MantidWidgets { + +/** TrackedAction : This is a version of QAction that tracks usage through the + Mantid usage service + + Copyright © 2016 ISIS Rutherford Appleton Laboratory, NScD Oak Ridge + National Laboratory & European Spallation Source + + This file is part of Mantid. + + Mantid is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + Mantid is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + + File change history is stored at: <https://github.com/mantidproject/mantid> + Code Documentation is available at: <http://doxygen.mantidproject.org> +*/ +class EXPORT_OPT_MANTIDQT_MANTIDWIDGETS TrackedAction : public QAction { + Q_OBJECT +public: + TrackedAction(QObject *parent); + TrackedAction(const QString &text, QObject *parent); + TrackedAction(const QIcon &icon, const QString &text, QObject *parent); + virtual ~TrackedAction() = default; + + void setTrackingName(const std::string &name); + std::string getTrackingName() const; + + void setIsTracking(const bool enableTracking); + bool getIsTracking() const; + +protected: + virtual std::string generateTrackingName() const; + virtual void registerUsage(const std::string &name); + +private: + void setupTracking(); + bool m_isTracking; + mutable std::string m_trackingName; + +public slots: + void trackActivation(const bool checked); +}; + +} // namespace MantidWidgets +} // namespace Mantid + +#endif /* MANTID_MANTIDWIDGETS_TRACKEDACTION_H_ */ \ No newline at end of file diff --git a/MantidQt/MantidWidgets/src/DataProcessorUI/GenericDataProcessorPresenter.cpp b/MantidQt/MantidWidgets/src/DataProcessorUI/GenericDataProcessorPresenter.cpp index 57158352343d44c3faa22205bde63dba53170af2..b46972caa7a88748ffbfc40b72ce5e47b0d62ef0 100644 --- a/MantidQt/MantidWidgets/src/DataProcessorUI/GenericDataProcessorPresenter.cpp +++ b/MantidQt/MantidWidgets/src/DataProcessorUI/GenericDataProcessorPresenter.cpp @@ -194,6 +194,10 @@ void GenericDataProcessorPresenter::process() { const auto items = m_manager->selectedData(true); + // Don't bother continuing if there are no items to process + if (items.size() == 0) + return; + // Progress: each group and each row within count as a progress step. int progress = 0; int maxProgress = (int)(items.size()); diff --git a/MantidQt/MantidWidgets/src/DataProcessorUI/QDataProcessorWidget.cpp b/MantidQt/MantidWidgets/src/DataProcessorUI/QDataProcessorWidget.cpp index 73d2f0d176ff5a9c14b4f2d86af7dda51a55dec2..afc2cc5cca755254d96d4c4a19a27b4b3a1562fd 100644 --- a/MantidQt/MantidWidgets/src/DataProcessorUI/QDataProcessorWidget.cpp +++ b/MantidQt/MantidWidgets/src/DataProcessorUI/QDataProcessorWidget.cpp @@ -1,5 +1,4 @@ #include "MantidQtMantidWidgets/DataProcessorUI/QDataProcessorWidget.h" -#include "MantidQtAPI/FileDialogHandler.h" #include "MantidQtAPI/MantidWidget.h" #include "MantidQtMantidWidgets/DataProcessorUI/DataProcessorCommandAdapter.h" #include "MantidQtMantidWidgets/DataProcessorUI/DataProcessorPresenter.h" @@ -184,7 +183,7 @@ std::string QDataProcessorWidget::requestNotebookPath() { // We won't use QFileDialog directly here as using the NativeDialog option // causes problems on MacOS. - QString qfilename = API::FileDialogHandler::getSaveFileName( + QString qfilename = QFileDialog::getSaveFileName( this, "Save notebook file", QDir::currentPath(), "IPython Notebook files (*.ipynb);;All files (*)", new QString("IPython Notebook files (*.ipynb)")); diff --git a/MantidQt/MantidWidgets/src/DoubleDialogEditor.cpp b/MantidQt/MantidWidgets/src/DoubleDialogEditor.cpp index d45b46f7c6976f9ab1c87c8ee6ba747efc3badcc..7c68cae72a15ace3a33d13e0209596850eff1480 100644 --- a/MantidQt/MantidWidgets/src/DoubleDialogEditor.cpp +++ b/MantidQt/MantidWidgets/src/DoubleDialogEditor.cpp @@ -3,7 +3,6 @@ #include <QHBoxLayout> #include <QLineEdit> #include <QPushButton> -#include <QFileDialog> #include <QLabel> #include <QDialog> #include <QSettings> diff --git a/MantidQt/MantidWidgets/src/FitOptionsBrowser.cpp b/MantidQt/MantidWidgets/src/FitOptionsBrowser.cpp index 1ed2d41fbd275cd37c417f4bac0b3ffd25271413..a3b9bedbbe12411be85b4709ad902e9ad7e1476f 100644 --- a/MantidQt/MantidWidgets/src/FitOptionsBrowser.cpp +++ b/MantidQt/MantidWidgets/src/FitOptionsBrowser.cpp @@ -201,6 +201,15 @@ void FitOptionsBrowser::createCommonProperties() { &FitOptionsBrowser::getStringEnumProperty, &FitOptionsBrowser::setStringEnumProperty); } + // Create PeakRadius property + m_peakRadius = m_intManager->addProperty("Peak Radius"); + { + m_intManager->setValue(m_peakRadius, 0); + m_intManager->setMinimum(m_peakRadius, 0); + m_browser->addProperty(m_peakRadius); + addProperty("PeakRadius", m_peakRadius, &FitOptionsBrowser::getIntProperty, + &FitOptionsBrowser::setIntProperty); + } } void FitOptionsBrowser::createSimultaneousFitProperties() { diff --git a/MantidQt/MantidWidgets/src/FitPropertyBrowser.cpp b/MantidQt/MantidWidgets/src/FitPropertyBrowser.cpp index facc17cbd3b4fdc6f7559d197185fb4351dd9c91..d2b71f940712a0cf907eba61a8ba3f00fe2c0b64 100644 --- a/MantidQt/MantidWidgets/src/FitPropertyBrowser.cpp +++ b/MantidQt/MantidWidgets/src/FitPropertyBrowser.cpp @@ -68,29 +68,31 @@ namespace MantidWidgets { * @param mantidui :: The UI form for MantidPlot */ FitPropertyBrowser::FitPropertyBrowser(QWidget *parent, QObject *mantidui) - : QDockWidget("Fit Function", parent), m_workspaceIndex(NULL), - m_startX(NULL), m_endX(NULL), m_output(NULL), m_minimizer(NULL), - m_ignoreInvalidData(NULL), m_costFunction(NULL), m_maxIterations(NULL), - m_logValue(NULL), m_plotDiff(NULL), m_plotCompositeMembers(NULL), - m_convolveMembers(NULL), m_rawData(NULL), m_xColumn(NULL), - m_yColumn(NULL), m_errColumn(NULL), m_showParamErrors(NULL), - m_evaluationType(nullptr), m_compositeFunction(), m_browser(NULL), - m_fitActionUndoFit(NULL), m_fitActionSeqFit(NULL), m_fitActionFit(NULL), - m_fitActionEvaluate(NULL), m_functionsGroup(NULL), m_settingsGroup(NULL), - m_customSettingsGroup(NULL), m_changeSlotsEnabled(false), + : QDockWidget("Fit Function", parent), m_workspaceIndex(nullptr), + m_startX(nullptr), m_endX(nullptr), m_output(nullptr), + m_minimizer(nullptr), m_ignoreInvalidData(nullptr), + m_costFunction(nullptr), m_maxIterations(nullptr), m_peakRadius(nullptr), + m_logValue(nullptr), m_plotDiff(nullptr), m_plotCompositeMembers(nullptr), + m_convolveMembers(nullptr), m_rawData(nullptr), m_xColumn(nullptr), + m_yColumn(nullptr), m_errColumn(nullptr), m_showParamErrors(nullptr), + m_evaluationType(nullptr), m_compositeFunction(), m_browser(nullptr), + m_fitActionUndoFit(nullptr), m_fitActionSeqFit(nullptr), + m_fitActionFit(nullptr), m_fitActionEvaluate(nullptr), + m_functionsGroup(nullptr), m_settingsGroup(nullptr), + m_customSettingsGroup(nullptr), m_changeSlotsEnabled(false), m_guessOutputName(true), m_updateObserver(*this, &FitPropertyBrowser::handleFactoryUpdate), - m_fitMapper(NULL), m_fitMenu(NULL), m_displayActionPlotGuess(NULL), - m_displayActionQuality(NULL), m_displayActionClearAll(NULL), - m_setupActionCustomSetup(NULL), m_setupActionRemove(NULL), m_tip(NULL), - m_fitSelector(NULL), m_fitTree(NULL), m_currentHandler(0), - m_defaultFunction("Gaussian"), m_defaultPeak("Gaussian"), - m_defaultBackground("LinearBackground"), m_index_(0), m_peakToolOn(false), - m_auto_back(false), + m_fitMapper(nullptr), m_fitMenu(nullptr), + m_displayActionPlotGuess(nullptr), m_displayActionQuality(nullptr), + m_displayActionClearAll(nullptr), m_setupActionCustomSetup(nullptr), + m_setupActionRemove(nullptr), m_tip(nullptr), m_fitSelector(nullptr), + m_fitTree(nullptr), m_currentHandler(0), m_defaultFunction("Gaussian"), + m_defaultPeak("Gaussian"), m_defaultBackground("LinearBackground"), + m_index_(0), m_peakToolOn(false), m_auto_back(false), m_autoBgName(QString::fromStdString( Mantid::Kernel::ConfigService::Instance().getString( "curvefitting.autoBackground"))), - m_autoBackground(NULL), m_decimals(-1), m_mantidui(mantidui), + m_autoBackground(nullptr), m_decimals(-1), m_mantidui(mantidui), m_shouldBeNormalised(false) { // Make sure plugins are loaded std::string libpath = @@ -193,6 +195,10 @@ void FitPropertyBrowser::init() { m_intManager->setValue(m_maxIterations, settings.value("Max Iterations", 500).toInt()); + m_peakRadius = m_intManager->addProperty("Peak Radius"); + m_intManager->setValue(m_peakRadius, + settings.value("Peak Radius", 0).toInt()); + m_plotDiff = m_boolManager->addProperty("Plot Difference"); bool plotDiff = settings.value("Plot Difference", QVariant(true)).toBool(); m_boolManager->setValue(m_plotDiff, plotDiff); @@ -241,6 +247,7 @@ void FitPropertyBrowser::init() { settingsGroup->addSubProperty(m_ignoreInvalidData); settingsGroup->addSubProperty(m_costFunction); settingsGroup->addSubProperty(m_maxIterations); + settingsGroup->addSubProperty(m_peakRadius); settingsGroup->addSubProperty(m_plotDiff); settingsGroup->addSubProperty(m_plotCompositeMembers); settingsGroup->addSubProperty(m_convolveMembers); @@ -671,7 +678,7 @@ void FitPropertyBrowser::acceptFit() { if (items.size() != 1) return; - if (items[0]->parent() == NULL) + if (items[0]->parent() == nullptr) return; PropertyHandler *h = getHandler()->findHandler(cf); @@ -691,7 +698,7 @@ void FitPropertyBrowser::createCompositeFunction( const Mantid::API::IFunction_sptr func) { if (m_compositeFunction) { emit functionRemoved(); - m_autoBackground = NULL; + m_autoBackground = nullptr; } if (!func) { m_compositeFunction.reset(new Mantid::API::CompositeFunction); @@ -749,7 +756,7 @@ void FitPropertyBrowser::popupMenu(const QPoint &) { bool isFunctionsGroup = ci == m_functionsGroup; bool isSettingsGroup = ci == m_settingsGroup; bool isASetting = ci->parent() == m_settingsGroup; - bool isFunction = getHandler()->findFunction(ci) != NULL; + bool isFunction = getHandler()->findFunction(ci) != nullptr; bool isCompositeFunction = isFunction && getHandler()->findCompositeFunction(ci); @@ -1146,6 +1153,11 @@ int FitPropertyBrowser::maxIterations() const { return m_intManager->value(m_maxIterations); } +/// Get the peak radius for peak functions +int FitPropertyBrowser::getPeakRadius() const { + return m_intManager->value(m_peakRadius); +} + /// Get the registered function names void FitPropertyBrowser::populateFunctionNames() { const std::vector<std::string> names = @@ -1273,11 +1285,14 @@ void FitPropertyBrowser::intChanged(QtProperty *prop) { if (!h) return; h->setFunctionWorkspace(); - } else if (prop == m_maxIterations) { + } else if (prop == m_maxIterations || prop == m_peakRadius) { QSettings settings; settings.beginGroup("Mantid/FitBrowser"); int val = m_intManager->value(prop); settings.setValue(prop->propertyName(), val); + if (prop == m_peakRadius) { + sendParameterChanged(m_compositeFunction.get()); + } } else { // it could be an attribute PropertyHandler *h = getHandler()->findHandler(prop); if (!h) @@ -1524,6 +1539,7 @@ void FitPropertyBrowser::doFit(int maxIterations) { alg->setProperty("IgnoreInvalidData", ignoreInvalidData()); alg->setPropertyValue("CostFunction", costFunction()); alg->setProperty("MaxIterations", maxIterations); + alg->setProperty("PeakRadius", getPeakRadius()); if (!isHistogramFit()) { alg->setProperty("Normalise", m_shouldBeNormalised); // Always output each composite function but not necessarily plot it @@ -1763,7 +1779,7 @@ void FitPropertyBrowser::currentItemChanged(QtBrowserItem *current) { if (current) { m_currentHandler = getHandler()->findHandler(current->property()); } else { - m_currentHandler = NULL; + m_currentHandler = nullptr; } emit currentChanged(); } @@ -2014,7 +2030,7 @@ void FitPropertyBrowser::hasConstraints(QtProperty *parProp, bool &hasTie, } } -/** Returns the tie property for a parameter property, or NULL +/** Returns the tie property for a parameter property, or nullptr * @param parProp :: parameter property */ QtProperty *FitPropertyBrowser::getTieProperty(QtProperty *parProp) const { @@ -2024,7 +2040,7 @@ QtProperty *FitPropertyBrowser::getTieProperty(QtProperty *parProp) const { return subs[i]; } } - return NULL; + return nullptr; } /** @@ -2160,7 +2176,7 @@ void FitPropertyBrowser::clearAllPlots() { emit removeFitCurves(); } QtProperty * FitPropertyBrowser::addDoubleProperty(const QString &name, QtDoublePropertyManager *manager) const { - if (manager == NULL) + if (manager == nullptr) manager = m_doubleManager; QtProperty *prop = manager->addProperty(name); manager->setDecimals(prop, m_decimals); @@ -2328,11 +2344,11 @@ void FitPropertyBrowser::addAutoBackground() { PropertyHandler *ch = currentHandler(); if (m_autoBackground) { // remove old background if (ch == m_autoBackground) { - ch = NULL; + ch = nullptr; } hasPlot = m_autoBackground->hasPlot(); m_autoBackground->removeFunction(); - m_autoBackground = NULL; + m_autoBackground = nullptr; } // Create the function PropertyHandler *h = getHandler()->addFunction(m_autoBgName.toStdString()); @@ -2446,7 +2462,7 @@ void FitPropertyBrowser::removeLogValue() { if (isWorkspaceAGroup()) return; m_settingsGroup->property()->removeSubProperty(m_logValue); - m_logValue = NULL; + m_logValue = nullptr; } void FitPropertyBrowser::sequentialFit() { @@ -2850,7 +2866,8 @@ FitPropertyBrowser::createMatrixFromTableWorkspace() const { return boost::shared_ptr<Mantid::API::Workspace>(); const size_t rowCount = tws->rowCount(); if (rowCount == 0) { - QMessageBox::critical(NULL, "Mantid - Error", "TableWorkspace is empty."); + QMessageBox::critical(nullptr, "Mantid - Error", + "TableWorkspace is empty."); return boost::shared_ptr<Mantid::API::Workspace>(); } @@ -2859,7 +2876,8 @@ FitPropertyBrowser::createMatrixFromTableWorkspace() const { // get the x column int ix = m_columnManager->value(m_xColumn); if (ix >= static_cast<int>(columns.size())) { - QMessageBox::critical(NULL, "Mantid - Error", "X column was not found."); + QMessageBox::critical(nullptr, "Mantid - Error", + "X column was not found."); return boost::shared_ptr<Mantid::API::Workspace>(); } auto xcol = tws->getColumn(columns[ix]); @@ -2867,7 +2885,8 @@ FitPropertyBrowser::createMatrixFromTableWorkspace() const { // get the y column int iy = m_columnManager->value(m_yColumn); if (iy >= static_cast<int>(columns.size())) { - QMessageBox::critical(NULL, "Mantid - Error", "Y column was not found."); + QMessageBox::critical(nullptr, "Mantid - Error", + "Y column was not found."); return boost::shared_ptr<Mantid::API::Workspace>(); } auto ycol = tws->getColumn(columns[iy]); @@ -2876,7 +2895,7 @@ FitPropertyBrowser::createMatrixFromTableWorkspace() const { int ie = m_columnManager->value(m_errColumn) - 1; // first entry is empty string if (ie >= 0 && ie >= static_cast<int>(columns.size())) { - QMessageBox::critical(NULL, "Mantid - Error", + QMessageBox::critical(nullptr, "Mantid - Error", "Error column was not found."); return boost::shared_ptr<Mantid::API::Workspace>(); } @@ -2898,7 +2917,7 @@ FitPropertyBrowser::createMatrixFromTableWorkspace() const { return mws; } catch (std::exception &e) { - QMessageBox::critical(NULL, "Mantid - Error", e.what()); + QMessageBox::critical(nullptr, "Mantid - Error", e.what()); return boost::shared_ptr<Mantid::API::Workspace>(); } } @@ -2954,7 +2973,7 @@ void FitPropertyBrowser::minimizerChanged() { auto &properties = minzer->getProperties(); for (auto it = properties.begin(); it != properties.end(); ++it) { QString propName = QString::fromStdString((**it).name()); - QtProperty *prop = NULL; + QtProperty *prop = nullptr; if (auto prp = dynamic_cast<Mantid::Kernel::PropertyWithValue<bool> *>(*it)) { prop = m_boolManager->addProperty(propName); diff --git a/MantidQt/MantidWidgets/src/FormulaDialogEditor.cpp b/MantidQt/MantidWidgets/src/FormulaDialogEditor.cpp index 253787cd1a23547c671b1f7849875f39dc289608..b35535076cbed264ae02905ebbfb3b5b66c10b9b 100644 --- a/MantidQt/MantidWidgets/src/FormulaDialogEditor.cpp +++ b/MantidQt/MantidWidgets/src/FormulaDialogEditor.cpp @@ -1,7 +1,6 @@ #include "MantidQtMantidWidgets/FormulaDialogEditor.h" #include "MantidQtMantidWidgets/UserFunctionDialog.h" -#include <QFileDialog> #include <QSettings> namespace MantidQt { diff --git a/MantidQt/MantidWidgets/src/InstrumentView/InstrumentActor.cpp b/MantidQt/MantidWidgets/src/InstrumentView/InstrumentActor.cpp index 7824ad8d701be064879232d01bc4478d04a020c1..f8c0b1457ec127795a7719b6502928bce0c61aff 100644 --- a/MantidQt/MantidWidgets/src/InstrumentView/InstrumentActor.cpp +++ b/MantidQt/MantidWidgets/src/InstrumentView/InstrumentActor.cpp @@ -16,6 +16,7 @@ #include "MantidAPI/IAlgorithm.h" #include "MantidAPI/IMaskWorkspace.h" #include "MantidAPI/MatrixWorkspace.h" +#include "MantidAPI/SpectrumInfo.h" #include "MantidAPI/WorkspaceFactory.h" #include "MantidGeometry/Objects/Object.h" @@ -634,8 +635,8 @@ void InstrumentActor::resetColors() { m_colors.resize(m_specIntegrs.size()); auto sharedWorkspace = getWorkspace(); + const auto &spectrumInfo = sharedWorkspace->spectrumInfo(); - Instrument_const_sptr inst = getInstrument(); IMaskWorkspace_sptr mask = getMaskWorkspaceIfExists(); for (int iwi = 0; iwi < int(m_specIntegrs.size()); iwi++) { @@ -649,7 +650,7 @@ void InstrumentActor::resetColors() { if (mask) { masked = mask->isMasked(dets); } else { - masked = inst->isDetectorMasked(dets); + masked = spectrumInfo.hasDetectors(wi) && spectrumInfo.isMasked(wi); } if (masked) { diff --git a/MantidQt/MantidWidgets/src/InstrumentView/InstrumentWidget.cpp b/MantidQt/MantidWidgets/src/InstrumentView/InstrumentWidget.cpp index aef9bea4e6f2dfff6267cde040cc2571741ac060..ad0515e69b88a2bb6ae9030a4ebe9bdde22b0b0e 100644 --- a/MantidQt/MantidWidgets/src/InstrumentView/InstrumentWidget.cpp +++ b/MantidQt/MantidWidgets/src/InstrumentView/InstrumentWidget.cpp @@ -51,8 +51,6 @@ #include <QVBoxLayout> #include <QWidget> -#include "MantidQtAPI/FileDialogHandler.h" - #include <numeric> #include <stdexcept> @@ -317,8 +315,8 @@ InstrumentWidgetTab *InstrumentWidget::getTab(const Tab tab) const { QString InstrumentWidget::getSaveFileName(const QString &title, const QString &filters, QString *selectedFilter) { - QString filename = MantidQt::API::FileDialogHandler::getSaveFileName( - this, title, m_savedialog_dir, filters, selectedFilter); + QString filename = QFileDialog::getSaveFileName(this, title, m_savedialog_dir, + filters, selectedFilter); // If its empty, they cancelled the dialog if (!filename.isEmpty()) { @@ -676,9 +674,9 @@ void InstrumentWidget::saveImage(QString filename) { * Use the file dialog to select a filename to save grouping. */ QString InstrumentWidget::getSaveGroupingFilename() { - QString filename = MantidQt::API::FileDialogHandler::getSaveFileName( - this, "Save grouping file", m_savedialog_dir, - "Grouping (*.xml);;All files (*)"); + QString filename = + QFileDialog::getSaveFileName(this, "Save grouping file", m_savedialog_dir, + "Grouping (*.xml);;All files (*)"); // If its empty, they cancelled the dialog if (!filename.isEmpty()) { diff --git a/MantidQt/MantidWidgets/src/InstrumentView/InstrumentWidgetMaskTab.cpp b/MantidQt/MantidWidgets/src/InstrumentView/InstrumentWidgetMaskTab.cpp index e78ba4deb84688dc8aa2cbdb972c0b92eb28f4f9..b990ae4fb7ee2803e0cc809205fd09db3c3e2cce 100644 --- a/MantidQt/MantidWidgets/src/InstrumentView/InstrumentWidgetMaskTab.cpp +++ b/MantidQt/MantidWidgets/src/InstrumentView/InstrumentWidgetMaskTab.cpp @@ -39,7 +39,6 @@ #include <QAction> #include <QApplication> #include <QCheckBox> -#include <QFileDialog> #include <QGridLayout> #include <QGroupBox> #include <QHBoxLayout> diff --git a/MantidQt/MantidWidgets/src/InstrumentView/InstrumentWidgetRenderTab.cpp b/MantidQt/MantidWidgets/src/InstrumentView/InstrumentWidgetRenderTab.cpp index bac87256e2ef321ea30d470e2d73b6a50d5c6f6f..02d89b5281a1d4f5f4d885ee279d02390fb8c0f2 100644 --- a/MantidQt/MantidWidgets/src/InstrumentView/InstrumentWidgetRenderTab.cpp +++ b/MantidQt/MantidWidgets/src/InstrumentView/InstrumentWidgetRenderTab.cpp @@ -12,7 +12,6 @@ #include <QLabel> #include <QComboBox> #include <QCheckBox> -#include <QFileDialog> #include <QFileInfo> #include <QSettings> #include <QAction> diff --git a/MantidQt/MantidWidgets/src/MWDiag.cpp b/MantidQt/MantidWidgets/src/MWDiag.cpp index bc6867f12cb989ac9cdb25828204bd7c4c1452df..a832a84b69149bbc34ced9d3a2c15afb6b5faee2 100644 --- a/MantidQt/MantidWidgets/src/MWDiag.cpp +++ b/MantidQt/MantidWidgets/src/MWDiag.cpp @@ -2,7 +2,6 @@ #include "MantidQtMantidWidgets/DiagResults.h" #include "MantidQtMantidWidgets/MWRunFiles.h" #include "MantidQtAPI/AlgorithmInputHistory.h" -#include "MantidQtAPI/FileDialogHandler.h" #include "MantidAPI/FrameworkManager.h" #include "MantidAPI/AnalysisDataService.h" #include "MantidAPI/MatrixWorkspace.h" @@ -492,7 +491,7 @@ QString MWDiag::openFileDialog(const bool save, const QStringList &exts) { QString filename; if (save) { - filename = FileDialogHandler::getSaveFileName( + filename = QFileDialog::getSaveFileName( this, "Save file", m_prevSets.value("save file dir", "").toString(), filter); if (!filename.isEmpty()) { diff --git a/MantidQt/MantidWidgets/src/MWRunFiles.cpp b/MantidQt/MantidWidgets/src/MWRunFiles.cpp index c755185269f7b3345a4c492b09b827ccfe955e2e..cca9d2599fe2bbe7af578fc12c44a35275f1f473 100644 --- a/MantidQt/MantidWidgets/src/MWRunFiles.cpp +++ b/MantidQt/MantidWidgets/src/MWRunFiles.cpp @@ -974,13 +974,13 @@ QString MWRunFiles::openFileDialog() { if (!file.isEmpty()) filenames.append(file); } else if (m_allowMultipleFiles) { - filenames = - QFileDialog::getOpenFileNames(this, "Open file", dir, m_fileFilter, 0, - QFileDialog::DontResolveSymlinks); + filenames = QFileDialog::getOpenFileNames(this, "Open file", dir, + m_fileFilter, nullptr, + QFileDialog::DontResolveSymlinks); } else { QString file = - QFileDialog::getOpenFileName(this, "Open file", dir, m_fileFilter, 0, - QFileDialog::DontResolveSymlinks); + QFileDialog::getOpenFileName(this, "Open file", dir, m_fileFilter, + nullptr, QFileDialog::DontResolveSymlinks); if (!file.isEmpty()) filenames.append(file); } diff --git a/MantidQt/MantidWidgets/src/ProcessingAlgoWidget.cpp b/MantidQt/MantidWidgets/src/ProcessingAlgoWidget.cpp index f7b08ce64b7621d3bb0432b0026ad3ebac7e76f6..b6b356851b6aa264b658d7baad5771112b395fa4 100644 --- a/MantidQt/MantidWidgets/src/ProcessingAlgoWidget.cpp +++ b/MantidQt/MantidWidgets/src/ProcessingAlgoWidget.cpp @@ -2,7 +2,6 @@ #include <Qsci/qscilexerpython.h> #include "MantidAPI/Algorithm.h" #include "MantidAPI/AlgorithmManager.h" -#include "MantidQtAPI/FileDialogHandler.h" #include <iosfwd> #include <fstream> #include <QFileInfo> @@ -75,7 +74,7 @@ void ProcessingAlgoWidget::saveSettings() { /** Slot called when the save button is clicked */ void ProcessingAlgoWidget::btnSaveClicked() { // Save to a .py file - QString fileselection = MantidQt::API::FileDialogHandler::getSaveFileName( + QString fileselection = QFileDialog::getSaveFileName( this, "Save a Python Script", QFileInfo(m_lastFile).absoluteFilePath(), "Python scripts (*.py);;All files (*)"); if (!fileselection.isEmpty()) { diff --git a/MantidQt/MantidWidgets/src/SaveWorkspaces.cpp b/MantidQt/MantidWidgets/src/SaveWorkspaces.cpp index e0582c8b5fdf186f37fc6543e36a1f463532942e..076773096edc72c0bbf301612da4bb82288b8d1f 100644 --- a/MantidQt/MantidWidgets/src/SaveWorkspaces.cpp +++ b/MantidQt/MantidWidgets/src/SaveWorkspaces.cpp @@ -2,7 +2,6 @@ // Includes //---------------------- #include "MantidQtMantidWidgets/SaveWorkspaces.h" -#include "MantidQtAPI/FileDialogHandler.h" #include "MantidAPI/AlgorithmManager.h" #include "MantidAPI/AnalysisDataService.h" #include "MantidAPI/FileProperty.h" @@ -11,16 +10,17 @@ #include "MantidGeometry/Instrument.h" #include "MantidKernel/ConfigService.h" -#include <QLabel> -#include <QHBoxLayout> -#include <QVBoxLayout> -#include <QPushButton> -#include <QDoubleValidator> #include <QCloseEvent> -#include <QShowEvent> +#include <QDoubleValidator> +#include <QFileDialog> #include <QGroupBox> -#include <QSettings> +#include <QHBoxLayout> +#include <QLabel> #include <QMessageBox> +#include <QPushButton> +#include <QSettings> +#include <QShowEvent> +#include <QVBoxLayout> namespace { void setDetectorNamesOnCanSasFormat(QString &saveCommands, @@ -387,8 +387,8 @@ void SaveWorkspaces::saveFileBrowse() { QFileDialog::Option userCon = m_append->isChecked() ? QFileDialog::DontConfirmOverwrite : static_cast<QFileDialog::Option>(0); - QString oFile = API::FileDialogHandler::getSaveFileName( - this, title, prevPath, filter, NULL, userCon); + QString oFile = QFileDialog::getSaveFileName(this, title, prevPath, filter, + NULL, userCon); if (!oFile.isEmpty()) { m_fNameEdit->setText(oFile); diff --git a/MantidQt/MantidWidgets/src/ScriptEditor.cpp b/MantidQt/MantidWidgets/src/ScriptEditor.cpp index 8b1abc4605119336449d7ae817dd3411022c9db2..2eabd6fcbabc29a9293750129b0c0bc1b6360068 100644 --- a/MantidQt/MantidWidgets/src/ScriptEditor.cpp +++ b/MantidQt/MantidWidgets/src/ScriptEditor.cpp @@ -3,12 +3,10 @@ //----------------------------------------------- #include "MantidQtMantidWidgets/ScriptEditor.h" #include "MantidQtMantidWidgets/FindReplaceDialog.h" -#include "MantidQtAPI/FileDialogHandler.h" // Qt #include <QApplication> #include <QFile> -#include <QFileInfo> #include <QFileDialog> #include <QTextStream> @@ -260,8 +258,8 @@ QSize ScriptEditor::sizeHint() const { return QSize(600, 500); } void ScriptEditor::saveAs() { QString selectedFilter; QString filter = "Scripts (*.py *.PY);;All Files (*)"; - QString filename = MantidQt::API::FileDialogHandler::getSaveFileName( - NULL, "MantidPlot - Save", "", filter, &selectedFilter); + QString filename = QFileDialog::getSaveFileName(NULL, "MantidPlot - Save", "", + filter, &selectedFilter); if (filename.isEmpty()) { throw SaveCancelledException(); diff --git a/MantidQt/MantidWidgets/src/StringDialogEditor.cpp b/MantidQt/MantidWidgets/src/StringDialogEditor.cpp index c9da15cc8c0a8ae5634104bc8c3c64574b8fa047..2254036b33141aee89a81565e5a422427feb98bf 100644 --- a/MantidQt/MantidWidgets/src/StringDialogEditor.cpp +++ b/MantidQt/MantidWidgets/src/StringDialogEditor.cpp @@ -3,7 +3,6 @@ #include <QHBoxLayout> #include <QLineEdit> #include <QPushButton> -#include <QFileDialog> #include <QLabel> #include <QDialog> #include <QSettings> diff --git a/MantidQt/MantidWidgets/src/TrackedAction.cpp b/MantidQt/MantidWidgets/src/TrackedAction.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d94c3259e5cf0fc5cb329df7ae51c1d670b95b8e --- /dev/null +++ b/MantidQt/MantidWidgets/src/TrackedAction.cpp @@ -0,0 +1,100 @@ +#include "MantidQtMantidWidgets/TrackedAction.h" +#include "MantidKernel/UsageService.h" +#include <QCoreApplication> + +namespace MantidQt { +namespace MantidWidgets { + +/** Constructor +* @param parent The parent of this action +**/ +TrackedAction::TrackedAction(QObject *parent) + : QAction(parent), m_isTracking(true), m_trackingName() { + setupTracking(); +} + +/** Constructor +* @param text The text for the action +* @param parent The parent of this action +**/ +TrackedAction::TrackedAction(const QString &text, QObject *parent) + : QAction(text, parent), m_isTracking(true), m_trackingName() { + setupTracking(); +} + +/** Constructor +* @param icon The icon for the action +* @param text The text for the action +* @param parent The parent of this action +**/ +TrackedAction::TrackedAction(const QIcon &icon, const QString &text, + QObject *parent) + : QAction(icon, text, parent), m_isTracking(true), m_trackingName() { + setupTracking(); +} + +/** Sets the tracking name for this action +* @param name the tracking name for this action +**/ +void TrackedAction::setTrackingName(const std::string &name) { + m_trackingName = name; +} + +/** Gets the tracking name for this action +* If the tacking name is not set a default name will be generated using +* generateTrackingName +* @returns The tracking name for this action +**/ +std::string TrackedAction::getTrackingName() const { + if (m_trackingName.empty()) { + m_trackingName = generateTrackingName(); + } + return m_trackingName; +} + +/** Sets whether this action is tracking usage +* @param enableTracking True if the action should tracking usage +**/ +void TrackedAction::setIsTracking(const bool enableTracking) { + m_isTracking = enableTracking; +} + +/** Gets whether this action is tracking usage +* @returns True if the action is tracking usage +**/ +bool TrackedAction::getIsTracking() const { return m_isTracking; } + +/** Sets up tracking for the class +**/ +void TrackedAction::setupTracking() { + connect(this, SIGNAL(triggered(bool)), this, SLOT(trackActivation(bool))); +} + +/** Creates a tracking name from the action text +* @returns A generated name using ApplicationName->ActionText +**/ +std::string TrackedAction::generateTrackingName() const { + return QCoreApplication::applicationName().toStdString() + "->" + + QAction::text().remove("&").remove(" ").toStdString(); +} + +/** Registers the feature usage if usage is enabled +* @param checked Whether the QAction is checked +**/ +void TrackedAction::trackActivation(const bool checked) { + UNUSED_ARG(checked); + if (m_isTracking) { + // do tracking + registerUsage(getTrackingName()); + } +} + +/** Registers the feature usage with the usage service +* @param name The name to use when registering usage +**/ +void TrackedAction::registerUsage(const std::string &name) { + Mantid::Kernel::UsageService::Instance().registerFeatureUsage("Feature", name, + false); +} +} // namespace MantidWidgets +} // namespace Mantid diff --git a/MantidQt/MantidWidgets/test/TrackedActionTest.h b/MantidQt/MantidWidgets/test/TrackedActionTest.h new file mode 100644 index 0000000000000000000000000000000000000000..5be95a63207ef5de85c46b378721e3321cd47e7c --- /dev/null +++ b/MantidQt/MantidWidgets/test/TrackedActionTest.h @@ -0,0 +1,80 @@ +#ifndef MANTID_MANTIDWIDGETS_TRACKEDACTIONEST_H_ +#define MANTID_MANTIDWIDGETS_TRACKEDACTIONEST_H_ + +#include <cxxtest/TestSuite.h> + +#include "MantidQtMantidWidgets/TrackedAction.h" +#include <QCoreApplication> + +using MantidQt::MantidWidgets::TrackedAction; + +class TrackedActionTest : public CxxTest::TestSuite { + // inner class + class TestableTrackedAction : public TrackedAction { + public: + TestableTrackedAction(QObject *parent) + : TrackedAction(parent), m_lastName(){}; + TestableTrackedAction(const QString &text, QObject *parent) + : TrackedAction(text, parent), m_lastName(){}; + TestableTrackedAction(const QIcon &icon, const QString &text, + QObject *parent) + : TrackedAction(icon, text, parent), m_lastName(){}; + + std::string getLastUsedName() const { return m_lastName; }; + + protected: + void registerUsage(const std::string &name) override { m_lastName = name; }; + + private: + std::string m_lastName; + }; + +public: + // This pair of boilerplate methods prevent the suite being created statically + // This means the constructor isn't called when running other tests + static TrackedActionTest *createSuite() { return new TrackedActionTest(); } + static void destroySuite(TrackedActionTest *suite) { delete suite; } + + void testIsTrackingGetSetGet() { + QObject parent; + TestableTrackedAction action(&parent); + + TS_ASSERT_EQUALS(action.getIsTracking(), true); // default state + action.setIsTracking(false); + TS_ASSERT_EQUALS(action.getIsTracking(), false); // altered state + } + + void testTrackingNameGetSetGet() { + QObject parent; + TestableTrackedAction action(QString::fromStdString("TestName"), &parent); + + std::string appNamePrefix = + QCoreApplication::applicationName().toStdString() + "->"; + + TS_ASSERT_EQUALS(action.getTrackingName(), + appNamePrefix + "TestName"); // default state + action.setTrackingName("TestName2"); + TS_ASSERT_EQUALS(action.getTrackingName(), "TestName2"); // altered state + } + + void testTrackingCallLogic() { + QObject parent; + TestableTrackedAction action(QString::fromStdString("TestName"), &parent); + + // tracking should be on by default + TS_ASSERT_EQUALS(action.getIsTracking(), true); // default state + TS_ASSERT_EQUALS(action.getLastUsedName(), ""); // default state + + action.setTrackingName("ShouldTrack"); + action.trigger(); + TS_ASSERT_EQUALS(action.getLastUsedName(), + "ShouldTrack"); // tracking occurred state + action.setIsTracking(false); + action.setTrackingName("ShouldNotTrack"); + action.trigger(); + TS_ASSERT_DIFFERS(action.getLastUsedName(), + "ShouldNotTrack"); // Should not have tracked + } +}; + +#endif /* MANTID_MANTIDWIDGETS_TRACKEDACTIONEST_H_ */ \ No newline at end of file diff --git a/MantidQt/SliceViewer/src/SliceViewer.cpp b/MantidQt/SliceViewer/src/SliceViewer.cpp index 4c5b74dd9546f9bc55171987c465fb0f53bdf447..248f90eab330f5ee7dfb8650120c53b96b5c9194 100644 --- a/MantidQt/SliceViewer/src/SliceViewer.cpp +++ b/MantidQt/SliceViewer/src/SliceViewer.cpp @@ -22,7 +22,6 @@ #include "MantidGeometry/MDGeometry/MDHistoDimension.h" #include "MantidGeometry/MDGeometry/MDTypes.h" #include "MantidKernel/ReadLock.h" -#include "MantidQtAPI/FileDialogHandler.h" #include "MantidQtAPI/PlotAxis.h" #include "MantidQtAPI/MantidDesktopServices.h" #include "MantidQtAPI/MdSettings.h" @@ -1297,7 +1296,7 @@ QString SliceViewer::ensurePngExtension(const QString &fname) const { void SliceViewer::saveImage(const QString &filename) { QString fileselection; if (filename.isEmpty()) { - fileselection = MantidQt::API::FileDialogHandler::getSaveFileName( + fileselection = QFileDialog::getSaveFileName( this, tr("Pick a file to which to save the image"), QFileInfo(m_lastSavedFile).absoluteFilePath(), tr("PNG files(*.png *.png)")); diff --git a/Testing/Data/SystemTest/ENGINX193749_calibration_spec651.nxs.md5 b/Testing/Data/SystemTest/ENGINX193749_calibration_spec651.nxs.md5 new file mode 100644 index 0000000000000000000000000000000000000000..08de317c6839811bcfd49e5a88a462a541fb5d26 --- /dev/null +++ b/Testing/Data/SystemTest/ENGINX193749_calibration_spec651.nxs.md5 @@ -0,0 +1 @@ +cf09048bb10e7e10c381c92db5373225 diff --git a/Testing/Data/SystemTest/ENGINX236516_vanadium_bank1.nxs.md5 b/Testing/Data/SystemTest/ENGINX236516_vanadium_bank1.nxs.md5 new file mode 100644 index 0000000000000000000000000000000000000000..1503e40c721663cac288cd83fa32eae2c5a6f13c --- /dev/null +++ b/Testing/Data/SystemTest/ENGINX236516_vanadium_bank1.nxs.md5 @@ -0,0 +1 @@ +e5262f4b8faee3aeb0670dc6a6a79c70 diff --git a/Testing/Data/SystemTest/EVS14188-90_peaks.nxs.md5 b/Testing/Data/SystemTest/EVS14188-90_peaks.nxs.md5 new file mode 100644 index 0000000000000000000000000000000000000000..c78bd5e0903037b655801518b920b48f52296ccd --- /dev/null +++ b/Testing/Data/SystemTest/EVS14188-90_peaks.nxs.md5 @@ -0,0 +1 @@ +ad4f858fb125ca3baeb53e176a84f725 diff --git a/Testing/Data/SystemTest/FittingTestProblems/CUTEst/DIAMON2D.dat.md5 b/Testing/Data/SystemTest/FittingTestProblems/CUTEst/DIAMON2D.dat.md5 new file mode 100644 index 0000000000000000000000000000000000000000..51fe156bfa8fc9cb9bf315e6095c47fc69d4fe18 --- /dev/null +++ b/Testing/Data/SystemTest/FittingTestProblems/CUTEst/DIAMON2D.dat.md5 @@ -0,0 +1 @@ +6932c34dc495a3dff1b9922e312695f3 diff --git a/Testing/Data/SystemTest/FittingTestProblems/CUTEst/DMN15102LS.dat.md5 b/Testing/Data/SystemTest/FittingTestProblems/CUTEst/DMN15102LS.dat.md5 new file mode 100644 index 0000000000000000000000000000000000000000..dc0dc9d49667a41bd04bb827b704909b5107b7a2 --- /dev/null +++ b/Testing/Data/SystemTest/FittingTestProblems/CUTEst/DMN15102LS.dat.md5 @@ -0,0 +1 @@ +82099c7fbc6dc3a8de4b9217ae563ed5 diff --git a/Testing/Data/SystemTest/FittingTestProblems/CUTEst/PALMER6C.dat.md5 b/Testing/Data/SystemTest/FittingTestProblems/CUTEst/PALMER6C.dat.md5 new file mode 100644 index 0000000000000000000000000000000000000000..0aeaf584df8229b0ec0a53b56160613e46e2607a --- /dev/null +++ b/Testing/Data/SystemTest/FittingTestProblems/CUTEst/PALMER6C.dat.md5 @@ -0,0 +1 @@ +da35838eaec5e81808242156059412a0 diff --git a/Testing/Data/SystemTest/FittingTestProblems/CUTEst/PALMER7C.dat.md5 b/Testing/Data/SystemTest/FittingTestProblems/CUTEst/PALMER7C.dat.md5 new file mode 100644 index 0000000000000000000000000000000000000000..1b5f52b11b677af80fcde7db5b85665c36ef8745 --- /dev/null +++ b/Testing/Data/SystemTest/FittingTestProblems/CUTEst/PALMER7C.dat.md5 @@ -0,0 +1 @@ +6a995d22ba05590931b142e9feab0d88 diff --git a/Testing/Data/SystemTest/FittingTestProblems/CUTEst/PALMER8C.dat.md5 b/Testing/Data/SystemTest/FittingTestProblems/CUTEst/PALMER8C.dat.md5 new file mode 100644 index 0000000000000000000000000000000000000000..553bf242eda15c07a79145b6eaceffb2fdf4d878 --- /dev/null +++ b/Testing/Data/SystemTest/FittingTestProblems/CUTEst/PALMER8C.dat.md5 @@ -0,0 +1 @@ +2ab8ce743107eb738ba99094c9957cb7 diff --git a/Testing/Data/SystemTest/FittingTestProblems/CUTEst/VESUVIOLS.dat.md5 b/Testing/Data/SystemTest/FittingTestProblems/CUTEst/VESUVIOLS.dat.md5 new file mode 100644 index 0000000000000000000000000000000000000000..92928d169bc74d5f766629c1f1cf1bcaeb81472e --- /dev/null +++ b/Testing/Data/SystemTest/FittingTestProblems/CUTEst/VESUVIOLS.dat.md5 @@ -0,0 +1 @@ +58c89b19a947308dd4609e6743f26434 diff --git a/Testing/Data/SystemTest/FittingTestProblems/CUTEst/VIBRBEAM.dat.md5 b/Testing/Data/SystemTest/FittingTestProblems/CUTEst/VIBRBEAM.dat.md5 new file mode 100644 index 0000000000000000000000000000000000000000..51fe156bfa8fc9cb9bf315e6095c47fc69d4fe18 --- /dev/null +++ b/Testing/Data/SystemTest/FittingTestProblems/CUTEst/VIBRBEAM.dat.md5 @@ -0,0 +1 @@ +6932c34dc495a3dff1b9922e312695f3 diff --git a/Testing/Data/SystemTest/FittingTestProblems/CUTEst/YFITU.dat.md5 b/Testing/Data/SystemTest/FittingTestProblems/CUTEst/YFITU.dat.md5 new file mode 100644 index 0000000000000000000000000000000000000000..582f18effd743287f207425d817e48d3b98fe1fe --- /dev/null +++ b/Testing/Data/SystemTest/FittingTestProblems/CUTEst/YFITU.dat.md5 @@ -0,0 +1 @@ +8a9dd1453a5133b7f273838ebf932482 diff --git a/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Bennett5.dat.md5 b/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Bennett5.dat.md5 new file mode 100644 index 0000000000000000000000000000000000000000..51fe156bfa8fc9cb9bf315e6095c47fc69d4fe18 --- /dev/null +++ b/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Bennett5.dat.md5 @@ -0,0 +1 @@ +6932c34dc495a3dff1b9922e312695f3 diff --git a/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/BoxBOD.dat.md5 b/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/BoxBOD.dat.md5 new file mode 100644 index 0000000000000000000000000000000000000000..5cb9652e59f25ca445e4c978d5545a4f625c744c --- /dev/null +++ b/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/BoxBOD.dat.md5 @@ -0,0 +1 @@ +be28381269aeec353f6272ebc50d378e diff --git a/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Chwirut1.dat.md5 b/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Chwirut1.dat.md5 new file mode 100644 index 0000000000000000000000000000000000000000..391b51d07825b50d45de7b7f56463aad8bb3b920 --- /dev/null +++ b/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Chwirut1.dat.md5 @@ -0,0 +1 @@ +fe023591c01067f2ba0b4a2f71da39b6 diff --git a/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Chwirut2.dat.md5 b/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Chwirut2.dat.md5 new file mode 100644 index 0000000000000000000000000000000000000000..c41cfaad110eb6958b12641f9e851bf004e16697 --- /dev/null +++ b/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Chwirut2.dat.md5 @@ -0,0 +1 @@ +03c03c5ce0965a569e9c5eb79a275ed0 diff --git a/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/DanWood.dat.md5 b/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/DanWood.dat.md5 new file mode 100644 index 0000000000000000000000000000000000000000..07efbd62ffb3a666eabd50e8c7e9be645f037e36 --- /dev/null +++ b/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/DanWood.dat.md5 @@ -0,0 +1 @@ +3021097cf0fae99affd670d1e8e0ffa4 diff --git a/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/ENSO.dat.md5 b/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/ENSO.dat.md5 new file mode 100644 index 0000000000000000000000000000000000000000..f4fb9ce4df0f0d5c29584b399b8744c0ebff03ad --- /dev/null +++ b/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/ENSO.dat.md5 @@ -0,0 +1 @@ +4a09069042123934377380f82dae3b05 diff --git a/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Eckerle4.dat.md5 b/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Eckerle4.dat.md5 new file mode 100644 index 0000000000000000000000000000000000000000..3fd84a8abf876cf1501153e8b996de4a0be61650 --- /dev/null +++ b/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Eckerle4.dat.md5 @@ -0,0 +1 @@ +d5c6719f27ca3177fbe207455b95b8ed diff --git a/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Gauss1.dat.md5 b/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Gauss1.dat.md5 new file mode 100644 index 0000000000000000000000000000000000000000..5745b7d6cceba8e3907368ce02b239cc44ae61a9 --- /dev/null +++ b/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Gauss1.dat.md5 @@ -0,0 +1 @@ +8192d4256dc45613dd1e44e115330f5e diff --git a/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Gauss2.dat.md5 b/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Gauss2.dat.md5 new file mode 100644 index 0000000000000000000000000000000000000000..6436dc8037c16ccc9b9da7b9ef5458ecc503a910 --- /dev/null +++ b/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Gauss2.dat.md5 @@ -0,0 +1 @@ +09e1e27e2df64ea776d60b04e4f8e56a diff --git a/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Gauss3.dat.md5 b/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Gauss3.dat.md5 new file mode 100644 index 0000000000000000000000000000000000000000..e9ca6d92c5c65500d247ec9a742824d0e72a354c --- /dev/null +++ b/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Gauss3.dat.md5 @@ -0,0 +1 @@ +63f81fbacbb68705d4cc3e34b40d0f5e diff --git a/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Hahn1.dat.md5 b/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Hahn1.dat.md5 new file mode 100644 index 0000000000000000000000000000000000000000..ca3ad5c0e96de9a0037a97a5e2084c302a10622e --- /dev/null +++ b/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Hahn1.dat.md5 @@ -0,0 +1 @@ +490de048c82e4e2e4a2ce93500ea3dc9 diff --git a/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Kirby2.dat.md5 b/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Kirby2.dat.md5 new file mode 100644 index 0000000000000000000000000000000000000000..2bba9aaa8b0f6c0b51b6cb8031f3c7900b88dd0d --- /dev/null +++ b/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Kirby2.dat.md5 @@ -0,0 +1 @@ +527d973fc9afbb3f5dc2461071ddc854 diff --git a/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Lanczos1.dat.md5 b/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Lanczos1.dat.md5 new file mode 100644 index 0000000000000000000000000000000000000000..7d318d06287b41514b11072347b0776b7473d6bf --- /dev/null +++ b/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Lanczos1.dat.md5 @@ -0,0 +1 @@ +294e0a2ee9e98d13f707b76fb139e364 diff --git a/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Lanczos2.dat.md5 b/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Lanczos2.dat.md5 new file mode 100644 index 0000000000000000000000000000000000000000..f97dd2c9cb610861a791df25c0b6c98145ca2a2c --- /dev/null +++ b/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Lanczos2.dat.md5 @@ -0,0 +1 @@ +cde7f529948475c64f733f1de64c428e diff --git a/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Lanczos3.dat.md5 b/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Lanczos3.dat.md5 new file mode 100644 index 0000000000000000000000000000000000000000..22df8dcd95a68020c876e4e118a7c4b6be15911e --- /dev/null +++ b/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Lanczos3.dat.md5 @@ -0,0 +1 @@ +22653ff912c702db9c769eb9352427fe diff --git a/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/MGH09.dat.md5 b/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/MGH09.dat.md5 new file mode 100644 index 0000000000000000000000000000000000000000..62949647dc8c58fb617d35277e2676a648f566c6 --- /dev/null +++ b/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/MGH09.dat.md5 @@ -0,0 +1 @@ +38fb721b88ab95ecbd39bbc31c7b80ea diff --git a/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/MGH10.dat.md5 b/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/MGH10.dat.md5 new file mode 100644 index 0000000000000000000000000000000000000000..317c0ad767661188889ef9a86b2d3785a7e06c37 --- /dev/null +++ b/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/MGH10.dat.md5 @@ -0,0 +1 @@ +a615c3047d837b06598dd34b6a0df56c diff --git a/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/MGH17.dat.md5 b/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/MGH17.dat.md5 new file mode 100644 index 0000000000000000000000000000000000000000..c35f10855d39ee4bb144e86d812498baf1abeebb --- /dev/null +++ b/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/MGH17.dat.md5 @@ -0,0 +1 @@ +3bc29da66158998faecec51f3cdd9dd6 diff --git a/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Misra1a.dat.md5 b/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Misra1a.dat.md5 new file mode 100644 index 0000000000000000000000000000000000000000..e1da9bd946ef1c56b06738eac7579cc06542ab6a --- /dev/null +++ b/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Misra1a.dat.md5 @@ -0,0 +1 @@ +984c8d2b2efdd3d3e24efeba48a9fd92 diff --git a/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Misra1b.dat.md5 b/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Misra1b.dat.md5 new file mode 100644 index 0000000000000000000000000000000000000000..3afa276210a262dfbea8beaa5ed3dfde43f0169a --- /dev/null +++ b/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Misra1b.dat.md5 @@ -0,0 +1 @@ +28b7e399c1588c77b12e241780c91040 diff --git a/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Misra1c.dat.md5 b/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Misra1c.dat.md5 new file mode 100644 index 0000000000000000000000000000000000000000..57f69bfd22edbe0383602b872717b72014589f54 --- /dev/null +++ b/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Misra1c.dat.md5 @@ -0,0 +1 @@ +06cde8a4e094c290a618dc7bb7b6fcc3 diff --git a/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Misra1d.dat.md5 b/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Misra1d.dat.md5 new file mode 100644 index 0000000000000000000000000000000000000000..3b1dfd0812037d2266cab6d3d39c85c42b16e74a --- /dev/null +++ b/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Misra1d.dat.md5 @@ -0,0 +1 @@ +1e7286e296105a708ad93c891614e307 diff --git a/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Nelson.dat.md5 b/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Nelson.dat.md5 new file mode 100644 index 0000000000000000000000000000000000000000..c44dab0c7ed9f7156e26855a77fe238acbca98b3 --- /dev/null +++ b/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Nelson.dat.md5 @@ -0,0 +1 @@ +7aa2c811325939e074dad698053b5412 diff --git a/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Rat42.dat.md5 b/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Rat42.dat.md5 new file mode 100644 index 0000000000000000000000000000000000000000..c77bc76f40a563bb19ceaac009c9be8e24c11776 --- /dev/null +++ b/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Rat42.dat.md5 @@ -0,0 +1 @@ +cca8ea6f5087b155060c8f243d02e9cd diff --git a/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Rat43.dat.md5 b/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Rat43.dat.md5 new file mode 100644 index 0000000000000000000000000000000000000000..9b63e65b352695e4c4faefb90e950d476967c7f8 --- /dev/null +++ b/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Rat43.dat.md5 @@ -0,0 +1 @@ +b0d1db54d68fec53a4d998cc4f69927a diff --git a/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Roszman1.dat.md5 b/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Roszman1.dat.md5 new file mode 100644 index 0000000000000000000000000000000000000000..01ce65814f851796da32ed09581e2c34d4c83997 --- /dev/null +++ b/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Roszman1.dat.md5 @@ -0,0 +1 @@ +ce3f6494693655f59b49714c30ccd219 diff --git a/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Thurber.dat.md5 b/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Thurber.dat.md5 new file mode 100644 index 0000000000000000000000000000000000000000..f41a064e3d372ba0637102d192a0080b90b4ee2e --- /dev/null +++ b/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Thurber.dat.md5 @@ -0,0 +1 @@ +96fd4140cf2abc03ac4cad8b113895a1 diff --git a/Testing/Data/SystemTest/FittingTestProblems/Neutron_data/ENGINX193749_calibration_peak19.txt.md5 b/Testing/Data/SystemTest/FittingTestProblems/Neutron_data/ENGINX193749_calibration_peak19.txt.md5 new file mode 100644 index 0000000000000000000000000000000000000000..6a8ae3f42c96e524ab42e4835b2f7c8f52ee0b08 --- /dev/null +++ b/Testing/Data/SystemTest/FittingTestProblems/Neutron_data/ENGINX193749_calibration_peak19.txt.md5 @@ -0,0 +1 @@ +b268192abbc9c076a51e47234fef04d6 diff --git a/Testing/Data/SystemTest/FittingTestProblems/Neutron_data/ENGINX193749_calibration_peak20.txt.md5 b/Testing/Data/SystemTest/FittingTestProblems/Neutron_data/ENGINX193749_calibration_peak20.txt.md5 new file mode 100644 index 0000000000000000000000000000000000000000..b5d5f45fce93f4e1453cbf8ccf202fcf06c2a051 --- /dev/null +++ b/Testing/Data/SystemTest/FittingTestProblems/Neutron_data/ENGINX193749_calibration_peak20.txt.md5 @@ -0,0 +1 @@ +0b042ae6660bd794774847c13e4316c8 diff --git a/Testing/Data/SystemTest/FittingTestProblems/Neutron_data/ENGINX193749_calibration_peak23.txt.md5 b/Testing/Data/SystemTest/FittingTestProblems/Neutron_data/ENGINX193749_calibration_peak23.txt.md5 new file mode 100644 index 0000000000000000000000000000000000000000..076027fde429d181ef3d798cb830a9aa78984e8e --- /dev/null +++ b/Testing/Data/SystemTest/FittingTestProblems/Neutron_data/ENGINX193749_calibration_peak23.txt.md5 @@ -0,0 +1 @@ +c154a8fe628c0db7c10921a7babfafbe diff --git a/Testing/Data/SystemTest/FittingTestProblems/Neutron_data/ENGINX193749_calibration_peak5.txt.md5 b/Testing/Data/SystemTest/FittingTestProblems/Neutron_data/ENGINX193749_calibration_peak5.txt.md5 new file mode 100644 index 0000000000000000000000000000000000000000..890edc97ae79032ec5cc643f713bcf16f8fe53af --- /dev/null +++ b/Testing/Data/SystemTest/FittingTestProblems/Neutron_data/ENGINX193749_calibration_peak5.txt.md5 @@ -0,0 +1 @@ +5ff4214f4e5e9f45a0632045e502d6ff diff --git a/Testing/Data/SystemTest/FittingTestProblems/Neutron_data/ENGINX193749_calibration_peak6.txt.md5 b/Testing/Data/SystemTest/FittingTestProblems/Neutron_data/ENGINX193749_calibration_peak6.txt.md5 new file mode 100644 index 0000000000000000000000000000000000000000..267878e2bf72585cd8c47ced6dee0d4818a7ec24 --- /dev/null +++ b/Testing/Data/SystemTest/FittingTestProblems/Neutron_data/ENGINX193749_calibration_peak6.txt.md5 @@ -0,0 +1 @@ +c02038557722f6f601a11641c13b8f55 diff --git a/Testing/Data/SystemTest/FittingTestProblems/Neutron_data/ENGINX236516_vanadium_bank1_10brk.txt.md5 b/Testing/Data/SystemTest/FittingTestProblems/Neutron_data/ENGINX236516_vanadium_bank1_10brk.txt.md5 new file mode 100644 index 0000000000000000000000000000000000000000..ffd53c9261d7e90ddead7c467706ca5cb7c42b73 --- /dev/null +++ b/Testing/Data/SystemTest/FittingTestProblems/Neutron_data/ENGINX236516_vanadium_bank1_10brk.txt.md5 @@ -0,0 +1 @@ +80561f35628e26b957fd8fbab5502d93 diff --git a/Testing/Data/SystemTest/FittingTestProblems/Neutron_data/ENGINX236516_vanadium_bank1_20brk.txt.md5 b/Testing/Data/SystemTest/FittingTestProblems/Neutron_data/ENGINX236516_vanadium_bank1_20brk.txt.md5 new file mode 100644 index 0000000000000000000000000000000000000000..bc381407d5b4b92845a823352128426b75b33808 --- /dev/null +++ b/Testing/Data/SystemTest/FittingTestProblems/Neutron_data/ENGINX236516_vanadium_bank1_20brk.txt.md5 @@ -0,0 +1 @@ +68bf0586cce1d875e162423a2447b9b5 diff --git a/Testing/Data/SystemTest/FittingTestProblems/Neutron_data/EVS14188-90_Gaussian_peaks_1.txt.md5 b/Testing/Data/SystemTest/FittingTestProblems/Neutron_data/EVS14188-90_Gaussian_peaks_1.txt.md5 new file mode 100644 index 0000000000000000000000000000000000000000..0cce87070041d390e557819869f4ee0a10253710 --- /dev/null +++ b/Testing/Data/SystemTest/FittingTestProblems/Neutron_data/EVS14188-90_Gaussian_peaks_1.txt.md5 @@ -0,0 +1 @@ +05994950f8867e839a687a536b677595 diff --git a/Testing/Data/SystemTest/FittingTestProblems/Neutron_data/EVS14188-90_Gaussian_peaks_2.txt.md5 b/Testing/Data/SystemTest/FittingTestProblems/Neutron_data/EVS14188-90_Gaussian_peaks_2.txt.md5 new file mode 100644 index 0000000000000000000000000000000000000000..0307a07e4e514ac8a77a8fb5f6251dce7cf9e610 --- /dev/null +++ b/Testing/Data/SystemTest/FittingTestProblems/Neutron_data/EVS14188-90_Gaussian_peaks_2.txt.md5 @@ -0,0 +1 @@ +139c8317571234cda311afbef9a286f5 diff --git a/Testing/Data/SystemTest/FittingTestProblems/Neutron_data/GEMpeak1.txt.md5 b/Testing/Data/SystemTest/FittingTestProblems/Neutron_data/GEMpeak1.txt.md5 new file mode 100644 index 0000000000000000000000000000000000000000..7cca87602774f12f15b50b5d023d7a64de96f541 --- /dev/null +++ b/Testing/Data/SystemTest/FittingTestProblems/Neutron_data/GEMpeak1.txt.md5 @@ -0,0 +1 @@ +39a5f5d5585fb2821d9b887d18e80197 diff --git a/Testing/Data/SystemTest/FittingTestProblems/Neutron_data/WISH17701_peak1.txt.md5 b/Testing/Data/SystemTest/FittingTestProblems/Neutron_data/WISH17701_peak1.txt.md5 new file mode 100644 index 0000000000000000000000000000000000000000..fe852094540c203dbea2f3c827552e956ee13ec3 --- /dev/null +++ b/Testing/Data/SystemTest/FittingTestProblems/Neutron_data/WISH17701_peak1.txt.md5 @@ -0,0 +1 @@ +9d6bc75a57b064126aab14e7c5eb32ea diff --git a/Testing/Data/SystemTest/FittingTestProblems/Neutron_data/WISH17701_peak2.txt.md5 b/Testing/Data/SystemTest/FittingTestProblems/Neutron_data/WISH17701_peak2.txt.md5 new file mode 100644 index 0000000000000000000000000000000000000000..f3915ecf82b0d35195f89fd3c3d17e9c5ad29425 --- /dev/null +++ b/Testing/Data/SystemTest/FittingTestProblems/Neutron_data/WISH17701_peak2.txt.md5 @@ -0,0 +1 @@ +61fb6cec75bdd035361dbaea6710e96c diff --git a/Testing/Data/SystemTest/FittingTestProblems/Neutron_data/WISH17701_peak3.txt.md5 b/Testing/Data/SystemTest/FittingTestProblems/Neutron_data/WISH17701_peak3.txt.md5 new file mode 100644 index 0000000000000000000000000000000000000000..ff5ea373233eb3831910caf5145033f27d36946b --- /dev/null +++ b/Testing/Data/SystemTest/FittingTestProblems/Neutron_data/WISH17701_peak3.txt.md5 @@ -0,0 +1 @@ +655d1a9f81d2e2b0095dd108819d918a diff --git a/Testing/Data/SystemTest/FittingTestProblems/Neutron_data/WISH17701_peak4.txt.md5 b/Testing/Data/SystemTest/FittingTestProblems/Neutron_data/WISH17701_peak4.txt.md5 new file mode 100644 index 0000000000000000000000000000000000000000..96c3969ea0c0f95a7a17865e8d4ce9a180616812 --- /dev/null +++ b/Testing/Data/SystemTest/FittingTestProblems/Neutron_data/WISH17701_peak4.txt.md5 @@ -0,0 +1 @@ +f41f1751f64e2c895d9dddaf0a8dbbce diff --git a/Testing/Data/SystemTest/FittingTestProblems/Neutron_data/WISH17701_peak5.txt.md5 b/Testing/Data/SystemTest/FittingTestProblems/Neutron_data/WISH17701_peak5.txt.md5 new file mode 100644 index 0000000000000000000000000000000000000000..7237c12ba27659d616aa75dc03aa520563f6ae25 --- /dev/null +++ b/Testing/Data/SystemTest/FittingTestProblems/Neutron_data/WISH17701_peak5.txt.md5 @@ -0,0 +1 @@ +25620760fec116854cd419e7aad4b047 diff --git a/Testing/Data/SystemTest/FittingTestProblems/Neutron_data/WISH17701_peak6.txt.md5 b/Testing/Data/SystemTest/FittingTestProblems/Neutron_data/WISH17701_peak6.txt.md5 new file mode 100644 index 0000000000000000000000000000000000000000..5c3b9f825d57229ef73decfa5de9a0eca05144ae --- /dev/null +++ b/Testing/Data/SystemTest/FittingTestProblems/Neutron_data/WISH17701_peak6.txt.md5 @@ -0,0 +1 @@ +046092c6b317018ca4f21af0cf6a11fb diff --git a/Testing/Data/SystemTest/FittingTestProblems/Neutron_data/WISH17701_peak7.txt.md5 b/Testing/Data/SystemTest/FittingTestProblems/Neutron_data/WISH17701_peak7.txt.md5 new file mode 100644 index 0000000000000000000000000000000000000000..d85f9fda11f316e745a3c93b36cbec3da3c68066 --- /dev/null +++ b/Testing/Data/SystemTest/FittingTestProblems/Neutron_data/WISH17701_peak7.txt.md5 @@ -0,0 +1 @@ +eb629c8b1b5fceb83fcd92f97598ef00 diff --git a/Testing/Data/SystemTest/FittingTestProblems/Neutron_data/WISH17701_peak8.txt.md5 b/Testing/Data/SystemTest/FittingTestProblems/Neutron_data/WISH17701_peak8.txt.md5 new file mode 100644 index 0000000000000000000000000000000000000000..81ce182db601f672d2fa89ebb17f1f82c093c0a5 --- /dev/null +++ b/Testing/Data/SystemTest/FittingTestProblems/Neutron_data/WISH17701_peak8.txt.md5 @@ -0,0 +1 @@ +7e013fa7700c776316a6643b4185a203 diff --git a/Testing/Data/SystemTest/FittingTestProblems/Neutron_data/WISH17701_peak9.txt.md5 b/Testing/Data/SystemTest/FittingTestProblems/Neutron_data/WISH17701_peak9.txt.md5 new file mode 100644 index 0000000000000000000000000000000000000000..67a6df33aa1e77b462a0a01666ba10effd27f78b --- /dev/null +++ b/Testing/Data/SystemTest/FittingTestProblems/Neutron_data/WISH17701_peak9.txt.md5 @@ -0,0 +1 @@ +0350effd9980b5f25823d8b67bb6c7d3 diff --git a/Testing/Data/SystemTest/GEM63437_focused_bank3.nxs.md5 b/Testing/Data/SystemTest/GEM63437_focused_bank3.nxs.md5 new file mode 100644 index 0000000000000000000000000000000000000000..4849a0bb040c8fe38eb3162a5f1e102cc91efccb --- /dev/null +++ b/Testing/Data/SystemTest/GEM63437_focused_bank3.nxs.md5 @@ -0,0 +1 @@ +14aa520da8b7aa7421db00d42a08e2dc diff --git a/Testing/Data/SystemTest/WISH17701_calibration_panel103_tube3.nxs.md5 b/Testing/Data/SystemTest/WISH17701_calibration_panel103_tube3.nxs.md5 new file mode 100644 index 0000000000000000000000000000000000000000..493e99c0d094050cce0d657d4513fdf1d793ad22 --- /dev/null +++ b/Testing/Data/SystemTest/WISH17701_calibration_panel103_tube3.nxs.md5 @@ -0,0 +1 @@ +a32c3ce038d1c0cb85a08b8bddab5101 diff --git a/Testing/SystemTests/tests/analysis/FittingBenchmarks.py b/Testing/SystemTests/tests/analysis/FittingBenchmarks.py new file mode 100644 index 0000000000000000000000000000000000000000..ea2d43b7efa47b6a92cfd895e731bd24737d24fa --- /dev/null +++ b/Testing/SystemTests/tests/analysis/FittingBenchmarks.py @@ -0,0 +1,152 @@ +""" +This systemtest tests that the fit executes with different minimizers for the fitting test problems used for benchmarking minimizers. + +Note the complete benchmarking suite is not tested here since I find this takes too long, but enough to provide +an additional health test of Mantid fitting and to test that the scripts used for fit minimizer benchmarking are working. + +Fitting problem are stored as follows in the FittingTestProblems directory: + + CUTEst/ + NIST_nonlinear_regression/ + Neutron_data/ + +For more information what these problems are see the Mantid FittingMinimizers concept page. +""" +from __future__ import (absolute_import, division, print_function) + +import unittest +import stresstesting + +import os + +import mantid.simpleapi as msapi +import fitting_benchmarking as fitbk +import results_output as fitout + + +class FittingBenchmarkTests(unittest.TestCase): + + def setUp(self): + self.color_scale = [(1.1, 'ranking-top-1'), + (1.33, 'ranking-top-2'), + (1.75, 'ranking-med-3'), + (3, 'ranking-low-4'), + (float('nan'), 'ranking-low-5') + ] + + # Create the path for the specific fitting test files location + input_data_dir = msapi.config['datasearch.directories'].split(';')[0] + self.base_problem_files_dir = os.path.join(input_data_dir, 'FittingTestProblems') + + def test_all_nist_problem(self): + """ + Runs benchmark on all NIST problems on about half of the available Mantid minimizers + and without using weights. + """ + + minimizers = ['BFGS', 'Conjugate gradient (Fletcher-Reeves imp.)', + 'Conjugate gradient (Polak-Ribiere imp.)', 'Damped GaussNewton'] + group_names = ['NIST, "lower" difficulty', 'NIST, "average" difficulty', 'NIST, "higher" difficulty'] + group_suffix_names = ['nist_lower', 'nist_average', 'nist_higher'] + + use_errors = False + + nist_group_dir = os.path.join(self.base_problem_files_dir, 'NIST_nonlinear_regression') + + # test that fit executes on all NIST problems against a number of different minimizers + problems, results_per_group = fitbk.do_fitting_benchmark(nist_group_dir=nist_group_dir, + minimizers=minimizers, use_errors=use_errors) + + # test that can print individual group tables + for idx, group_results in enumerate(results_per_group): + print("\n\n") + print("********************************************************") + print("**************** RESULTS FOR GROUP {0}, {1} ************".format(idx+1, + group_names[idx])) + print("********************************************************") + fitout.print_group_results_tables(minimizers, group_results, problems[idx], + group_name=group_suffix_names[idx], use_errors=use_errors, + simple_text=True, rst=True, save_to_file=False, + color_scale=self.color_scale) + + # test that can print summary tables + header = '\n\n**************** OVERALL SUMMARY - ALL GROUPS ******** \n\n' + print(header) + fitout.print_overall_results_table(minimizers, results_per_group, problems, group_names, + use_errors=use_errors, save_to_file=False) + + def test_all_cutest_problem(self): + """ + Runs benchmark on all CUTEst problems on about half of the available Mantid minimizers + and with using weights. + """ + minimizers = ['Levenberg-Marquardt', 'Levenberg-MarquardtMD', + 'Simplex', 'SteepestDescent', 'Trust Region'] + group_suffix_names = ['cutest'] + + use_errors = True + + cutest_group_dir = os.path.join(self.base_problem_files_dir, 'CUTEst') + + # test that fit executes on all NIST problems against a number of different minimizers + problems, results_per_group = fitbk.do_fitting_benchmark(cutest_group_dir=cutest_group_dir, + minimizers=minimizers, use_errors=use_errors) + + # test that can print individual group table + for idx, group_results in enumerate(results_per_group): + fitout.print_group_results_tables(minimizers, group_results, problems[idx], + group_name=group_suffix_names[idx], use_errors=use_errors, + simple_text=True, rst=True, save_to_file=False, + color_scale=self.color_scale) + + def test_all_neutron_data_problem(self): + """ + Runs benchmark on all neutron data problems on one minimizers + and using weights. + """ + minimizers = ['Trust Region'] + group_suffix_names = ['neutron_data'] + + use_errors = True + + neutron_data_group_dirs = [os.path.join(self.base_problem_files_dir, 'Neutron_data')] + + # test that fit executes on all Neutron data problems + problems, results_per_group = fitbk.do_fitting_benchmark(neutron_data_group_dirs=neutron_data_group_dirs, + minimizers=minimizers, use_errors=use_errors) + + # test that can print individual group table + for idx, group_results in enumerate(results_per_group): + fitout.print_group_results_tables(minimizers, group_results, problems[idx], + group_name=group_suffix_names[idx], use_errors=use_errors, + simple_text=True, rst=True, save_to_file=False, + color_scale=self.color_scale) + + +# Run the unittest tests defined above as a Mantid system test +class FittingBenchmars(stresstesting.MantidStressTest): + + _success = False + + def __init__(self, *args, **kwargs): + # super(FittingBenchmarkTests, self).__init__(*args, **kwargs) + # old-style + stresstesting.MantidStressTest.__init__(self, *args, **kwargs) + self._success = False + + def requiredFile(self): + return None + + def runTest(self): + + self._success = False + # Custom code to create and run this single test suite + suite = unittest.TestSuite() + suite.addTest(unittest.makeSuite(FittingBenchmarkTests, "test") ) + runner = unittest.TextTestRunner() + # Run and check success + res = runner.run(suite) + self._success = res.wasSuccessful() + + def validate(self): + return self._success diff --git a/Testing/SystemTests/tests/analysis/ISISIndirectInelastic.py b/Testing/SystemTests/tests/analysis/ISISIndirectInelastic.py index 7523cfc37ac82a79add468e9658b29f6b0a570cc..2c56de5abdedd246fd7a825aca98c931a669f77c 100644 --- a/Testing/SystemTests/tests/analysis/ISISIndirectInelastic.py +++ b/Testing/SystemTests/tests/analysis/ISISIndirectInelastic.py @@ -1024,6 +1024,7 @@ class ISISIndirectInelasticConvFit(ISISIndirectInelasticBase): BackgroundType=self.bg, SpecMin=self.spectra_min, SpecMax=self.spectra_max, + PeakRadius=5, OutputWorkspace='result') def _validate_properties(self): diff --git a/Testing/SystemTests/tests/analysis/SNAPRedux.py b/Testing/SystemTests/tests/analysis/SNAPRedux.py new file mode 100644 index 0000000000000000000000000000000000000000..85a2dcbb3d11f4be3637247117799c68d2f2fa62 --- /dev/null +++ b/Testing/SystemTests/tests/analysis/SNAPRedux.py @@ -0,0 +1,63 @@ +#pylint: disable=no-init,invalid-name,attribute-defined-outside-init +from __future__ import (absolute_import, division, print_function) +import stresstesting +from mantid.simpleapi import * +import os + + +def _skip_test(): + """Helper function to determine if we run the test""" + import platform + + # Only runs on RHEL6 at the moment + return "Linux" not in platform.platform() + + +def getSaveDir(): + """determine where to save - the current working directory""" + return os.path.abspath(os.path.curdir) + + +def do_cleanup(): + Files = [os.path.join('d_spacing', 'SNAP_34172_2_4_Grouping.dat'), + os.path.join('gsas', 'SNAP_34172_2_4_Grouping.gsa'), + os.path.join('fullprof', 'SNAP_34172_2_4_Grouping-0.dat'), + os.path.join('fullprof', 'SNAP_34172_2_4_Grouping-1.dat'), + os.path.join('nexus', 'SNAP_34172_2_4_Grouping.nxs')] + savedir = getSaveDir() + for filename in Files: + absfile = os.path.join(savedir, filename) + if os.path.exists(absfile): + os.remove(absfile) + for direc in ['d_spacing', 'gsas', 'fullprof', 'nexus']: + direc = os.path.join(savedir, direc) + if os.listdir(direc) == []: + os.rmdir(direc) + + return True + + +class SNAP_short(stresstesting.MantidStressTest): + def skipTests(self): + return _skip_test() + + def cleanup(self): + do_cleanup() + return True + + def requiredFiles(self): + files = [] + files.append("SNAP_34172_event.nxs") + return files + + def runTest(self): + # run the actual code + SNAPReduce(RunNumbers='34172', Masking='Horizontal', Binning='0.9,-0.004,6', + Normalization='Extracted from Data', PeakClippingWindowSize=7, + SmoothingRange=5, GroupDetectorsBy='2_4 Grouping', + SaveData=True, OutputDirectory=getSaveDir()) + + def validate(self): + self.tolerance = 1.0e-2 + # default validation of workspace to processed nexus is right + return ('SNAP_34172_2_4_Grouping_nor','SNAP_34172_2_4_Grouping_nor.nxs') diff --git a/Testing/SystemTests/tests/analysis/reference/SNAP_34172_2_4_Grouping_nor.nxs.md5 b/Testing/SystemTests/tests/analysis/reference/SNAP_34172_2_4_Grouping_nor.nxs.md5 new file mode 100644 index 0000000000000000000000000000000000000000..218741c01fad2569fcb820d0d846fcf0ff580989 --- /dev/null +++ b/Testing/SystemTests/tests/analysis/reference/SNAP_34172_2_4_Grouping_nor.nxs.md5 @@ -0,0 +1 @@ +648aeeed791af5dea783e6550a3fab97 diff --git a/Vates/VatesAPI/inc/MantidVatesAPI/SaveMDWorkspaceToVTKImpl.h b/Vates/VatesAPI/inc/MantidVatesAPI/SaveMDWorkspaceToVTKImpl.h index 2a9210ac47a8c5c3e22adeb83159ec90315f2818..92557f4f376941256214c1ba489f693bbbbe4e6b 100644 --- a/Vates/VatesAPI/inc/MantidVatesAPI/SaveMDWorkspaceToVTKImpl.h +++ b/Vates/VatesAPI/inc/MantidVatesAPI/SaveMDWorkspaceToVTKImpl.h @@ -2,8 +2,10 @@ #define VATES_API_SAVE_MD_WORKSPACE_TO_VTK_IMPL_H_ #include "MantidAPI/IMDWorkspace.h" +#include "MantidAPI/Progress.h" #include "MantidKernel/System.h" #include "MantidVatesAPI/Normalization.h" +#include "MantidVatesAPI/SaveMDWorkspaceToVTK.h" #include "MantidVatesAPI/ThresholdRange.h" #include <map> @@ -44,7 +46,7 @@ Code Documentation is available at: <http://doxygen.mantidproject.org> */ class DLLExport SaveMDWorkspaceToVTKImpl { public: - SaveMDWorkspaceToVTKImpl(); + SaveMDWorkspaceToVTKImpl(SaveMDWorkspaceToVTK *parent = nullptr); ~SaveMDWorkspaceToVTKImpl() {} void saveMDWorkspace(Mantid::API::IMDWorkspace_sptr workspace, const std::string &filename, @@ -66,6 +68,7 @@ public: bool is3DWorkspace(Mantid::API::IMDWorkspace_sptr workspace) const; private: + mutable API::Progress m_progress; std::map<std::string, VisualNormalization> m_normalizations; std::vector<std::string> m_thresholds; diff --git a/Vates/VatesAPI/src/SaveMDWorkspaceToVTK.cpp b/Vates/VatesAPI/src/SaveMDWorkspaceToVTK.cpp index e7b77406bbe7a8aaf374806215c5010f57cbbee7..d211a49fb5d28350cd094435214e8af9f5f37ec2 100644 --- a/Vates/VatesAPI/src/SaveMDWorkspaceToVTK.cpp +++ b/Vates/VatesAPI/src/SaveMDWorkspaceToVTK.cpp @@ -18,7 +18,7 @@ namespace VATES { DECLARE_ALGORITHM(SaveMDWorkspaceToVTK) SaveMDWorkspaceToVTK::SaveMDWorkspaceToVTK() - : saver(Mantid::Kernel::make_unique<SaveMDWorkspaceToVTKImpl>()) {} + : saver(Mantid::Kernel::make_unique<SaveMDWorkspaceToVTKImpl>(this)) {} SaveMDWorkspaceToVTK::~SaveMDWorkspaceToVTK() {} diff --git a/Vates/VatesAPI/src/SaveMDWorkspaceToVTKImpl.cpp b/Vates/VatesAPI/src/SaveMDWorkspaceToVTKImpl.cpp index 1d7440130c49f53cd459f63e419a020fca5c623e..6e4d61c4408d5ed99ec4933fa26c2f1168c814e1 100644 --- a/Vates/VatesAPI/src/SaveMDWorkspaceToVTKImpl.cpp +++ b/Vates/VatesAPI/src/SaveMDWorkspaceToVTKImpl.cpp @@ -1,6 +1,5 @@ #include "MantidVatesAPI/SaveMDWorkspaceToVTKImpl.h" #include "MantidVatesAPI/Normalization.h" - #include "MantidVatesAPI/IgnoreZerosThresholdRange.h" #include "MantidVatesAPI/NoThresholdRange.h" @@ -18,6 +17,7 @@ #include "MantidKernel/Logger.h" #include "MantidKernel/make_unique.h" +#include "vtkCallbackCommand.h" #include "vtkFloatArray.h" #include "vtkNew.h" #include "vtkSmartPointer.h" @@ -26,6 +26,7 @@ #include "vtkXMLUnstructuredGridWriter.h" #include <boost/make_shared.hpp> +#include <boost/math/special_functions/round.hpp> #include <memory> namespace { @@ -60,7 +61,10 @@ namespace VATES { const std::string SaveMDWorkspaceToVTKImpl::structuredGridExtension = "vts"; const std::string SaveMDWorkspaceToVTKImpl::unstructuredGridExtension = "vtu"; -SaveMDWorkspaceToVTKImpl::SaveMDWorkspaceToVTKImpl() { setupMembers(); } +SaveMDWorkspaceToVTKImpl::SaveMDWorkspaceToVTKImpl(SaveMDWorkspaceToVTK *parent) + : m_progress(parent, 0.0, 1.0, 101) { + setupMembers(); +} /** * Save an MD workspace to a vts/vtu file. @@ -195,6 +199,22 @@ SaveMDWorkspaceToVTKImpl::getPresenter(bool isHistoWorkspace, return presenter; } +void ProgressFunction(vtkObject *caller, long unsigned int vtkNotUsed(eventId), + void *clientData, void *vtkNotUsed(callData)) { + vtkXMLWriter *testFilter = dynamic_cast<vtkXMLWriter *>(caller); + if (!testFilter) + return; + const char *progressText = testFilter->GetProgressText(); + if (progressText) { + reinterpret_cast<Kernel::ProgressBase *>(clientData) + ->report(boost::math::iround(testFilter->GetProgress() * 100.0), + progressText); + } else { + reinterpret_cast<Kernel::ProgressBase *>(clientData) + ->report(boost::math::iround(testFilter->GetProgress() * 100.0)); + } +} + /** * Write an unstructured grid or structured grid to a vtk file. * @param writer: a vtk xml writer @@ -206,6 +226,10 @@ SaveMDWorkspaceToVTKImpl::getPresenter(bool isHistoWorkspace, int SaveMDWorkspaceToVTKImpl::writeDataSetToVTKFile( vtkXMLWriter *writer, vtkDataSet *dataSet, const std::string &filename, vtkXMLWriter::CompressorType compressor) const { + vtkNew<vtkCallbackCommand> progressCallback; + progressCallback->SetCallback(ProgressFunction); + writer->AddObserver(vtkCommand::ProgressEvent, progressCallback.GetPointer()); + progressCallback->SetClientData(&m_progress); writer->SetFileName(filename.c_str()); writer->SetInputData(dataSet); writer->SetCompressorType(compressor); diff --git a/docs/source/algorithms/CollectHB3AExperimentInfo-v1.rst b/docs/source/algorithms/CollectHB3AExperimentInfo-v1.rst index 8f3a05d7d27ee3d617f330b55f951ce88d0f9d74..eb89bb31aec3a30e2a014477692817967ed9a0d7 100644 --- a/docs/source/algorithms/CollectHB3AExperimentInfo-v1.rst +++ b/docs/source/algorithms/CollectHB3AExperimentInfo-v1.rst @@ -82,7 +82,7 @@ Output: Number of input files = 2 Number of detectors in virtual instrument = 131072 - Virtual detectors are from ID = 1 to ID = 131072 + Virtual detectors are from ID = 0 to ID = 131070 .. categories:: diff --git a/docs/source/algorithms/ConvertCWSDExpToMomentum-v1.rst b/docs/source/algorithms/ConvertCWSDExpToMomentum-v1.rst index e3733cb4093c4169d19fd45d8bd4494479805a12..319715c4f232bc17fa8536e8c146b430311c2124 100644 --- a/docs/source/algorithms/ConvertCWSDExpToMomentum-v1.rst +++ b/docs/source/algorithms/ConvertCWSDExpToMomentum-v1.rst @@ -190,7 +190,7 @@ Output: Output MDEventWorkspace has 397 events. There are 1 peaks found in output MDWorkspace - In Q-sample frame, center of peak 0 is at (-6.93624, -0.08360, 8.16733) at detector with ID 35724 + In Q-sample frame, center of peak 0 is at (-6.93624, -0.08360, 8.16733) at detector with ID 35723 **Example - convert an HB3A experiment to MDEventWorkspace by copying instrument.:** @@ -234,7 +234,7 @@ Output: Output MDEventWorkspace has 397 events. There are 1 peaks found in output MDWorkspace - In Q-sample frame, center of peak 0 is at (-3.58246, -4.40803, -3.06320) at detector with ID 29057 + In Q-sample frame, center of peak 0 is at (-3.58246, -4.40802, -3.06320) at detector with ID 32881 .. categories:: diff --git a/docs/source/algorithms/ConvertCWSDMDtoHKL-v1.rst b/docs/source/algorithms/ConvertCWSDMDtoHKL-v1.rst index 219f648c8b5f9c388fa5ba5e4701471bcece86fc..37f8a256c687bdec8ddf055578154a280f565d2b 100644 --- a/docs/source/algorithms/ConvertCWSDMDtoHKL-v1.rst +++ b/docs/source/algorithms/ConvertCWSDMDtoHKL-v1.rst @@ -9,7 +9,7 @@ Description ----------- -This algorithms is to convert an MDEventWorkspace in Q-sample coordinate +This algorithms is to convert an MDEventWorkspace in Q-sample coordinate to HKL coordindate for a reactor-based four-circle single crystal diffractometer. Meanwhile, the algorithm is able to export the MDEvents to file. @@ -26,20 +26,20 @@ Inputs **InputWorkspace** is an MDEventWorkspace ???. -**PeakWorkspace** is an optional input as in many cases especially after calculating UB matrix, ... +**PeakWorkspace** is an optional input as in many cases especially after calculating UB matrix, ... -**UBMatrix** is ???. +**UBMatrix** is ???. Outputs ####### -The output is an MDEventWorkspace that... .. +The output is an MDEventWorkspace that... .. MDEvent +++++++ -Each MDEvent in output MDEventWorkspace contain +Each MDEvent in output MDEventWorkspace contain * *H* * *K* * *L* @@ -58,50 +58,53 @@ Usage **Example - Convert detector counts of an HB3A's measurement to HKL.** -.. testcode:: ExConvertHB3AToHKL +.. .. testcode:: ExConvertHB3AToHKL +.. code-block:: python # Create input table workspaces for experiment information and virtual instrument parameters - CollectHB3AExperimentInfo(ExperimentNumber='406', ScanList='298', PtLists='-1,22', + CollectHB3AExperimentInfo(ExperimentNumber='406', ScanList='298', PtLists='-1,22', DataDirectory='', GenerateVirtualInstrument=False, OutputWorkspace='ExpInfoTable', DetectorTableWorkspace='VirtualInstrumentTable') # Convert to MDWorkspace - ConvertCWSDExpToMomentum(InputWorkspace='ExpInfoTable', CreateVirtualInstrument=False, + ConvertCWSDExpToMomentum(InputWorkspace='ExpInfoTable', CreateVirtualInstrument=False, OutputWorkspace='QSampleMD', Directory='') - - ConvertCWSDMDtoHKL(InputWorkspace='QSampleMD', + + ConvertCWSDMDtoHKL(InputWorkspace='QSampleMD', UBMatrix='0.13329061, 0.07152342, -0.04215966, 0.01084569, -0.1620849, 0.0007607, -0.14018499, -0.07841385, -0.04002737', OutputWorkspace='HKLMD') - - + + # Examine mdws = mtd['QSampleMD'] print 'Output MDEventWorkspace has %d events.'%(mdws.getNEvents()) - + hklws = mtd['HKLMD'] print 'H: range from %.5f to %.5f.' % (hklws.getXDimension().getMinimum(), hklws.getXDimension().getMaximum()) print 'K: range from %.5f to %.5f.' % (hklws.getYDimension().getMinimum(), hklws.getYDimension().getMaximum()) print 'L: range from %.5f to %.5f.' % (hklws.getZDimension().getMinimum(), hklws.getZDimension().getMaximum()) -.. testcleanup:: ExConvertHB3AToHKL +.. + .. testcleanup:: ExConvertHB3AToHKL - DeleteWorkspace(Workspace='QSampleMD') - DeleteWorkspace(Workspace='ExpInfoTable') - DeleteWorkspace(Workspace='VirtualInstrumentTable') - DeleteWorkspace(Workspace='HKLMD') - DeleteWorkspace(Workspace='HB3A_exp0406_scan0298') - DeleteWorkspace(Workspace='spicematrixws') + DeleteWorkspace(Workspace='QSampleMD') + DeleteWorkspace(Workspace='ExpInfoTable') + DeleteWorkspace(Workspace='VirtualInstrumentTable') + DeleteWorkspace(Workspace='HKLMD') + DeleteWorkspace(Workspace='HB3A_exp0406_scan0298') + DeleteWorkspace(Workspace='spicematrixws') -Output: +.. + Output: -.. testoutput:: ExConvertHB3AToHKL + .. testoutput:: ExConvertHB3AToHKL - Output MDEventWorkspace has 1631 events. - H: range from -0.26128 to 0.24943. - K: range from -0.35012 to 0.44396. - L: range from 4.96512 to 7.18855. + Output MDEventWorkspace has 1631 events. + H: range from -0.26509 to 0.22324. + K: range from -0.33148 to 0.45354. + L: range from 4.92654 to 7.17077. .. categories:: diff --git a/docs/source/algorithms/ConvolutionFitSequential-v1.rst b/docs/source/algorithms/ConvolutionFitSequential-v1.rst index 615c0e177f848ee0e63ad5ee31ef4b5d55361c8a..d8d8018e11e9d97d8a09e5289f1cc9fd67bb9eca 100644 --- a/docs/source/algorithms/ConvolutionFitSequential-v1.rst +++ b/docs/source/algorithms/ConvolutionFitSequential-v1.rst @@ -71,7 +71,7 @@ Output: Result has 2 Spectra - Amplitude 0: 4.293 + Amplitude 0: 4.314 Amplitude 1: 4.179 Amplitude 2: 3.979 @@ -79,7 +79,7 @@ Output: X axis at 1: 0.72917 X axis at 2: 0.92340 - Amplitude Err 0: 0.00465 + Amplitude Err 0: 0.00460 Amplitude Err 1: 0.00464 Amplitude Err 2: 0.00504 diff --git a/docs/source/algorithms/CreateGroupingWorkspace-v1.rst b/docs/source/algorithms/CreateGroupingWorkspace-v1.rst index afdebe3f470942d0d01e5705a31979a994609740..96c7607422e589c2c6e5e8a358fd8c38dd43a6e9 100644 --- a/docs/source/algorithms/CreateGroupingWorkspace-v1.rst +++ b/docs/source/algorithms/CreateGroupingWorkspace-v1.rst @@ -29,6 +29,10 @@ the detectors for the given component will be grouped into the number of groups specified, detectors will be left ungrouped in the event that the number of detectors does not divide equally into the number of groups. +GroupDetectorsBy has a new option, 2_4Grouping, to create one group of 4 +columns of SNAP detectors and another with the remaining 2 columns. This +grouping is used frequently in their reduction. + Usage ----- diff --git a/docs/source/algorithms/EstimateFitParameters-v1.rst b/docs/source/algorithms/EstimateFitParameters-v1.rst index 6c922476a5d32838f626d2fa9328832da5a8fe83..87afb8e80a313494a21413613940bf2895f7bb46 100644 --- a/docs/source/algorithms/EstimateFitParameters-v1.rst +++ b/docs/source/algorithms/EstimateFitParameters-v1.rst @@ -34,6 +34,12 @@ In this strategy a number (defined by `NSamples` property) of paramter sets are gives the smallest cost function is considered the winner. These best parameters are set to `Function` property (it has the `InOut` direction). +If `OutputWorkspace` property is set then more than 1 parameter set can be output. The output workspace is +a table workspace in which the first column contains the names of the parameters and the subsequent columns +have the parameter sets with the smallest cost fnction values. Below is an example of such a workspace. + +.. figure:: /images/EstimateFitParameters_output.png + Cross Entropy ############# @@ -103,9 +109,12 @@ Usage Output: +(You may see different numbers for the parameters when you run this example on your machine.) + .. testoutput:: ExMonteCarloBackToBackExponential + :options: +ELLIPSIS, +NORMALIZE_WHITESPACE - name=BackToBackExponential,I=130.029,A=124.254,B=1.93148,X0=-1.91278,S=1.67663,constraints=(50<I<200,0.1<A<300,0.01<B<10,-5<X0<0,0.001<S<4) + name=BackToBackExponential,I=...,A=...,B=...,X0=...,S=...,constraints=(50<I<200,0.1<A<300,0.01<B<10,-5<X0<0,0.001<S<4) **Example 2.** @@ -157,9 +166,12 @@ Output: Output: +(You may see different numbers for the parameters when you run this example on your machine.) + .. testoutput:: Ex2 + :options: +ELLIPSIS, +NORMALIZE_WHITESPACE - name=BackToBackExponential,I=3.89204,A=107.646,B=57.3761,X0=0.0452285,S=1.58316,constraints=(0.01<I<200,0.001<A<300,0.001<B<300,-5<X0<5,0.001<S<4),ties=(A=107.645731,B=57.376105) + name=BackToBackExponential,I=...,A=...,B=...,X0=...,S=...,constraints=(0.01<I<200,0.001<A<300,0.001<B<300,-5<X0<5,0.001<S<4),ties=(A=...,B=...) .. categories:: diff --git a/docs/source/algorithms/Fit-v1.rst b/docs/source/algorithms/Fit-v1.rst index 9267c4e1abbb5a76826f75f11081c9c2203eba52..cf45eaafa023c9da55d31cbb1fbf4e945636f00d 100644 --- a/docs/source/algorithms/Fit-v1.rst +++ b/docs/source/algorithms/Fit-v1.rst @@ -209,6 +209,16 @@ Currently only the following functions can be used in a fit with "Histogram" eva If any other functions need to be included in the list please leave a request at the `Forum <http://forum.mantidproject.org/>`_. +Peak Radius +########### + +The effect of setting `PeakRadius` to a non-default value can be seen from next figure. + +.. figure:: /images/PeakRadius_Fit.png + :width: 700 + +It can be used to speed up computations but there is a danger of introducing higher errors. + Output ###### diff --git a/docs/source/algorithms/LoadSpiceXML2DDet-v1.rst b/docs/source/algorithms/LoadSpiceXML2DDet-v1.rst index 1544bd488267decbd9031e17bcbd210ef34e0586..68f8a43df094ee532d8290deee27eedd4a2b3e7a 100644 --- a/docs/source/algorithms/LoadSpiceXML2DDet-v1.rst +++ b/docs/source/algorithms/LoadSpiceXML2DDet-v1.rst @@ -41,6 +41,14 @@ Counts of an :math:`n\times m` 2D detectors are recorded in XML file as below:: And the (1,1) position is the bottom left corner of the Anger camera as seen from the sample position. +HB3A instrument facts +##################### + +HB3A has 1 detector with :math:`256 \times 256` pixels. + + - Pixel: width = :math:`2 \times 9.921875e-05` m, height = :math:`2 \times 9.921875e-05` m, depth = 0.0001 m. + - Detector: + Output Worskpaces ################# diff --git a/docs/source/algorithms/SNAPReduce-v1.rst b/docs/source/algorithms/SNAPReduce-v1.rst new file mode 100644 index 0000000000000000000000000000000000000000..7d79a441b31246feba4be7aa23ab6d68e65f3a07 --- /dev/null +++ b/docs/source/algorithms/SNAPReduce-v1.rst @@ -0,0 +1,23 @@ +.. algorithm:: + +.. summary:: + +.. alias:: + +.. properties:: + +Description +----------- + +The purpose of this algorithm is to do a full reduction of SNAP +data. This allows several runs, and with all the typical options that +are usually used at the beamline, including calibrate from a cal file +and from Convert Units, mask from file workspace and default masks, +several groupings and save in GSAS or Fullprof format. + +Usage +----- + +.. categories:: + +.. sourcelink:: diff --git a/docs/source/algorithms/TOSCABankCorrection-v1.rst b/docs/source/algorithms/TOSCABankCorrection-v1.rst index 22fee78069ae00a94287f9a423d0964dfdfe89dc..21a1da9a677f5faa15638beb7bb632d46cc22292 100644 --- a/docs/source/algorithms/TOSCABankCorrection-v1.rst +++ b/docs/source/algorithms/TOSCABankCorrection-v1.rst @@ -77,7 +77,7 @@ Output: .. testoutput:: ExTOSCABankCorrectionAutomatic - Target peak centre: 1077 + Target peak centre: 1080 **Example - Manual peak selection.** @@ -95,6 +95,6 @@ Output: .. testoutput:: ExTOSCABankCorrectionManual - Target peak centre: 713 + Target peak centre: 714 .. categories:: diff --git a/docs/source/concepts/ErrorPropagation.rst b/docs/source/concepts/ErrorPropagation.rst index c45bfd1fa1b9f4cbabf28c69c6998835f9494766..6a5f084056344e9b4d3a9a7be6f806fdb88a8faa 100644 --- a/docs/source/concepts/ErrorPropagation.rst +++ b/docs/source/concepts/ErrorPropagation.rst @@ -3,62 +3,66 @@ Error Propagation ================= -The purpose of this document is to explain how Mantid deals with Error -Propogation and how it is used in its algorithms. +The purpose of this document is to explain how Mantid deals with error +propagation and how it is used in its algorithms. Theory ------ -In order to deal with error propagation, Mantid treats errors as guassian -probabilities (also known as a bell curve or normal probabilities) and each -observation as independent. Meaning that if X = 100 +- 1 then it is still -possible for a value of 102 to occur, but less likely than 101 or 99, and a -value of 105 is far less likely still than any of these values. +In order to deal with error propagation, Mantid treats errors as Gaussian +probabilities (also known as a bell curve or normal probabilities) and each +observation as independent. Meaning that if :math:`X = 100 \pm 1` then it is still +possible for a value of :math:`102` to occur, but less likely than :math:`101` +or :math:`99`, and a value of :math:`105` is far less likely still than any of +these values. Plus and Minus Algorithm ------------------------ -The plus algorithm adds a selection of datasets together, including their -margin of errors. Mantid has to therefore adapt the margin of error so it -continues to work with just one margin of error. The way it does this is by -simply adding together the certain values. Consider the example where: -X\ :sub:`1` = 101 ± 2 and X\ :sub:`2` = 99 ± 2. Then for the Plus algorithm +The :ref:`algm-Plus` algorithm adds two datasets together, propagating the +uncertainties. Mantid calculates the result of :math:`X_1 + X_2` as -X = 200 = (101 + 99). +:math:`X = X_1 + X_2` -The propagated error is calculated by taking the root of the sum of the -squares of the two error margins: +with uncertainty -(√2:sup:`2` + 2\ :sup:`2`) = √8 +:math:`\sigma_X = \sqrt{ \left( \sigma_{X_1} \right)^2 + \left( \sigma_{X_2} \right)^2 }`. -Hence the result of the Plus algorithm can be summarised as: +Consider the example where :math:`X_1 = 101 \pm 2` and :math:`X_2 = 99 \pm 2`. +Then for this algorithm: -X = 200 ± √8 +:math:`X = X_1 + X_2 = 101 + 99 = 200` -Mantid deals with the Minus algorithm similarly. +:math:`\sigma_X = \sqrt{ 2^2 + 2^2} = \sqrt{8} = 2.8284` -Multiply and Divide Algorithm ------------------------------ +Hence the result of :ref:`algm-Plus` can be summarised as :math:`X = 200 \pm \sqrt{8}`. + +Mantid deals with the :ref:`algm-Minus` algorithm similarly: the result of :math:`X_1 - X_2` is -The Multiply and Divide Algorithm work slightly different from the Plus -and Minus Algorithms, in the sense that they have to be more complex, -see also `here <http://en.wikipedia.org/wiki/Propagation_of_uncertainty>`_. +:math:`X = X_1 - X_2` -To calculate error propagation, of say X\ :sub:`1` and X\ :sub:`2`. -X\ :sub:`1` = 101 ± 2 and X\ :sub:`2` = 99 ± 2 ,Mantid would -undertake the following calculation for divide: +with error -Q = X\ :sub:`1`/X:sub:`2` = 101/99 +:math:`\sigma_X = \sqrt{ \left( \sigma_{X_1} \right)^2 + \left( \sigma_{X_2} \right)^2 }`. + +Multiply and Divide Algorithm +----------------------------- -Error Propogation = (√ ± 2/99 + ±2/101) All multiplied by Q = 0.22425 +The :ref:`algm-Multiply` and :ref:`algm-Divide` algorithms propagate the uncertainties according +to (see also `here <http://en.wikipedia.org/wiki/Propagation_of_uncertainty>`_): -For the multiply algorithm, the only difference is in how Q is created, -which in turn affects the Error Propogation, +:math:`\sigma_X = \left|X\right| \sqrt{ \left( \frac{\sigma_{X_1}}{X_1} \right)^2 + \left( \frac{\sigma_{X_2}}{X_2} \right)^2 }`, -Q = X\ :sub:`1`\ \*X\ :sub:`2` = 101\*99 +where :math:`X` is the result of the multiplication, :math:`X = X_1 \cdot X_2`, or the division, :math:`X = X_1 / X_2`. -Error Propogation = (√ ± 2/99 + ±2/101) All multiplied by Q = 0.22425 +Considering the example above where :math:`X_1 = 101 \pm 2` and +:math:`X_2 = 99 \pm 2`. Mantid would calculate the result of :math:`X_1 / X_2` as +:math:`X = 101 / 99 = 1.0202`, with uncertainty +:math:`\sigma_X = 1.0202 \sqrt{ \left(2/101\right)^2 + \left(2/99\right)^2} = 0.0288`. +For :ref:`algm-Multiply`, the result of :math:`X_1 \times X_2` is +:math:`X = 101 \times 99 = 9999`, with uncertainty +:math:`\sigma_X = 9999 \sqrt{ \left(2/101\right)^2 + \left(2/99\right)^2} = 282.8568`. -.. categories:: Concepts \ No newline at end of file +.. categories:: Concepts diff --git a/docs/source/concepts/FittingMinimizers.rst b/docs/source/concepts/FittingMinimizers.rst index 4664ca4148136e672b350e57433a660b8ccc34d7..a66d7b16dd78564fb88e9071f29a77ded12c1687 100644 --- a/docs/source/concepts/FittingMinimizers.rst +++ b/docs/source/concepts/FittingMinimizers.rst @@ -36,12 +36,7 @@ options are available: A `Levenberg-Marquardt <https://en.wikipedia.org/wiki/Levenberg-Marquardt_algorithm>`__ implementation generalised to allow different cost functions, and supporting chunking techniques for large datasets. - `Gauss-Newton <../fitminimizers/DampedGaussNewton.html>`__ algorithm with damping. - :ref:`FABADA <FABADA>` -- `Trust region - <https://ccpforge.cse.rl.ac.uk/gf/project/ral_nlls>`__: a `trust - region algorithm <https://en.wikipedia.org/wiki/Trust_region>`__ that, - at each iteration, calculates and returns the step that reduces the - model by an acceptable amount by solving (or approximating a - solution to) the trust-region subproblem +- `Trust region <../fitminimizers/TrustRegion.html>`__ All these algorithms are `iterative <https://en.wikipedia.org/wiki/Iterative_method>`__. The *Simplex* diff --git a/docs/source/fitfunctions/FunctionQDepends.rst b/docs/source/fitfunctions/FunctionQDepends.rst new file mode 100644 index 0000000000000000000000000000000000000000..c94cf75a8f9218c18acad057bdcbca8f32f14284 --- /dev/null +++ b/docs/source/fitfunctions/FunctionQDepends.rst @@ -0,0 +1,30 @@ +.. _func-FunctionQDepends: + +================ +FunctionQDepends +================ + +.. index:: FunctionQDepends + +Description +----------- + +This fitting function is the base class for all fitting functions that have: + +- A range of energy transfers as their one-dimensional domain from which to take values +- The magnitude of the momemtum transfer, :math:`Q`, as one of their attributes. + +Fitting functions for QENS data depending on :math:`Q` should derive from this class. + +There are two ways to update attribute :math:`Q` in the fit funtion: + +- The user inputs a particular value. +- The spectrum contains :math:`Q` in addition to the range of energy transfers. + +Conflict may arise when both options are available. In that case, priority is given to the :math:`Q`-value contained +in the spectrum. Here are some user cases: + +- User cannot override the value of attribute :math:`Q` if the spectrum contains a :math:`Q`-value. +- User can set or update the value of of attribute :math:`Q` is the spectrum does not contain a :math:`Q`-value. +- The value of attribute :math:`Q` will be updated everytime we pass a new spectrum containing a :math:`Q`-value. +- The value of attribute :math:`Q` will be erased if we pass a new spectrum not containing a :math:`Q`-value. In this case it is the responsability of the user to set the appropriate value. diff --git a/docs/source/fitminimizers/TrustRegion.rst b/docs/source/fitminimizers/TrustRegion.rst new file mode 100644 index 0000000000000000000000000000000000000000..5e6d87879f7214b5160684813175ad04a7a2a327 --- /dev/null +++ b/docs/source/fitminimizers/TrustRegion.rst @@ -0,0 +1,15 @@ +.. _TrustRegion: + +Trust Region Minimizer +====================== + +This minimizer is a hybrid +`Gauss-Newton <https://en.wikipedia.org/wiki/Gauss%E2%80%93Newton_algorithm>`__/`Quasi-Newton <https://en.wikipedia.org/wiki/Quasi-Newton_method>`__ +method, that makes use of a `trust region <https://en.wikipedia.org/wiki/Trust_region>`__. + +It is a reimplementation of part of `RALFit_nonlinear least squares solver <https://github.com/ralna/RALFit>`__. + +It is listed in `a comparison of fitting minimizers <../concepts/FittingMinimizers.html>`__. + +.. categories:: FitMinimizers + diff --git a/docs/source/images/EstimateFitParameters_output.png b/docs/source/images/EstimateFitParameters_output.png new file mode 100644 index 0000000000000000000000000000000000000000..6427f0a5549f00f87fc95899973e8f77403a8f21 Binary files /dev/null and b/docs/source/images/EstimateFitParameters_output.png differ diff --git a/docs/source/images/NoPeakRadius_3.9.png b/docs/source/images/NoPeakRadius_3.9.png new file mode 100644 index 0000000000000000000000000000000000000000..f8e515f062e9f77c7a28cb0e79d13cc80a28ffd4 Binary files /dev/null and b/docs/source/images/NoPeakRadius_3.9.png differ diff --git a/docs/source/images/PeakRadius_Fit.png b/docs/source/images/PeakRadius_Fit.png new file mode 100644 index 0000000000000000000000000000000000000000..b9cfc71c6a220ee13382a097ae911aa6bca61841 Binary files /dev/null and b/docs/source/images/PeakRadius_Fit.png differ diff --git a/docs/source/images/release38.png b/docs/source/images/release38.png new file mode 100644 index 0000000000000000000000000000000000000000..433124b8bd2a1a2a6b0aa0588da0fb3cad0c85fd Binary files /dev/null and b/docs/source/images/release38.png differ diff --git a/docs/source/interfaces/CrystalFieldPythonInterface.rst b/docs/source/interfaces/CrystalFieldPythonInterface.rst index 3e764b69ab79fd3f5f878d25340f395f93bb0c4d..ba5b49f81fb2adb78236554feef52c02a327173f 100644 --- a/docs/source/interfaces/CrystalFieldPythonInterface.rst +++ b/docs/source/interfaces/CrystalFieldPythonInterface.rst @@ -355,14 +355,14 @@ After fitting finishes the `CrystalField` object updates automatically and conta Finding Initial Parameters -------------------------- -If the initial values of the fitting parameters are not known they can be estimated using `monte_carlo()` method. +If the initial values of the fitting parameters are not known they can be estimated using `estimate_parameters()` method. It randomly searches the parameter space in a given region such that the calculated spectra are as close to the fit data as possible. The method uses :ref:`EstimateFitParameters <algm-EstimateFitParameters>` internally. See algorithm's description for the available properties. Here is an example of a fit with initial estimation:: from CrystalField.fitting import makeWorkspace - from CrystalField import CrystalField, CrystalFieldFit + from CrystalField import CrystalField, CrystalFieldFit, Background, Function # Create some crystal field data origin = CrystalField('Ce', 'C2v', B20=0.37737, B22=3.9770, B40=-0.031787, B42=-0.11611, B44=-0.12544, @@ -370,18 +370,26 @@ Here is an example of a fit with initial estimation:: x, y = origin.getSpectrum() ws = makeWorkspace(x, y) - # Define a CrystalField object. + # Define a CrystalField object with parameters slightly shifted. cf = CrystalField('Ce', 'C2v', B20=0, B22=0, B40=0, B42=0, B44=0, Temperature=44.0, FWHM=1.0, ResolutionModel=([0, 100], [1, 1]), FWHMVariation=0) # Set any ties on the field parameters. cf.ties(B20=0.37737) - # Define the search intervals. Only these parameters will be estimated. - cf.constraints('2<B22<6', '-0.2<B40<0.2', '-0.2<B42<0.2', '-0.2<B44<0.2') # Create a fit object fit = CrystalFieldFit(cf, InputWorkspace=ws) # Find initial values for the field parameters. - fit.monte_carlo(NSamples=1000) + # You need to define the energy splitting and names of parameters to estimate. + # Optionally additional constraints can be set on tied parameters (eg, peak centres). + fit.estimate_parameters(EnergySplitting=50, + Parameters=['B22', 'B40', 'B42', 'B44'], + Constraints='20<f1.PeakCentre<45,20<f2.PeakCentre<45', + NSamples=1000) + print 'Returned', fit.get_number_estimates(), 'sets of parameters.' + # The first set (the smallest chi squared) is selected by default. + # Select a different parameter set if required + fit.select_estimated_parameters(3) + print cf['B22'], cf['B40'], cf['B42'], cf['B44'] # Run fit fit.fit() diff --git a/docs/source/interfaces/ISIS_Reflectometry.rst b/docs/source/interfaces/ISIS_Reflectometry.rst index 7a7527eaf3d22b7b31674af35a7265838e7484ae..2f11e40546da785df6a51d38e236a5e737677f34 100644 --- a/docs/source/interfaces/ISIS_Reflectometry.rst +++ b/docs/source/interfaces/ISIS_Reflectometry.rst @@ -56,7 +56,7 @@ A table workspace called ``MyTable`` should now exist in the ADS (:ref:`Analysis In addition the table workspace should be opened as well and the processing table (shown below) should now contain four rows (13460, 13462, 13469, 13470). -.. figure:: /images/ISISReflectometryPolref_INTER_table.PNG +.. figure:: /images/ISISReflectometryPolref_INTER_table.png :align: center Let's process the first group, which consists of the first two rows of the @@ -373,7 +373,7 @@ In the image below we select two runs from the Search table that we wish to tran Attempting to transfer an invalid run will result in that run not being transferred to the processing table. If the transfer was not successful then that specific run will be highlighted in the Search table. -.. figure:: /images/ISISReflectometryPolref_failed_transfer_run.PNG +.. figure:: /images/ISISReflectometryPolref_failed_transfer_run.png :alt: Failed transfer will be highlighted in orange, successful transfer is put into processing table Hovering over the highlighted run with your cursor will allow you to see why the run was invalid. diff --git a/docs/source/release/v3.8.0/index.rst b/docs/source/release/v3.8.0/index.rst index 90227bd6100faca1a044333cdc8d808f0215b9fc..9b45cec8db0eb2449b1f4e6b8dee741f67ca89a7 100644 --- a/docs/source/release/v3.8.0/index.rst +++ b/docs/source/release/v3.8.0/index.rst @@ -2,7 +2,7 @@ Mantid 3.8.0 Release Notes ========================== -.. figure:: ../../images/release38.png +.. figure:: /images/release38.png :class: screenshot :width: 500px :align: right diff --git a/docs/source/release/v3.9.0/diffraction.rst b/docs/source/release/v3.9.0/diffraction.rst index b3aa65723f1c4fde9c185fd9dce14b3717e8f332..16169d0627316c35f74adde90e19726d63885b9d 100644 --- a/docs/source/release/v3.9.0/diffraction.rst +++ b/docs/source/release/v3.9.0/diffraction.rst @@ -9,6 +9,15 @@ Crystal Improvements -------------------- :ref:`algm-FindUBUsingLatticeParameters` will now return an oriented lattice even when the number of peaks used is very low. :ref:`algm-FindUBUsingLatticeParameters` has a new option to fix lattice parameters. This will find an orientation, but without optimisation between indexed HKLs and q vectors. +:ref:`algm-CreateGroupingWorkspace` has a new option to create one group of 4 columns of SNAP detectors and another with the remaining 2 columns. This grouping is used frequently in their reduction. + + +Single Crystal Diffraction +-------------------------- +HB3A's IDF is modified to allow its detector center shifted from default position. +:ref:`algm-LoadSpiceXML2DDet` has new options for users to input amount of detector's shift in X and Y direction. +:ref:`algm-ConvertCWSDExpToMomentum` has new options for users to input amount of detector's shift in X and Y direction. +User interface *HFIR 4Circle Reduction* has been modified to allow user to specify wave length, detector center and distance between detector and sample. Engineering Diffraction ----------------------- @@ -25,6 +34,11 @@ information about the empty sample environment and instrument. :ref:`algm-SetDetScale` has a new option, DetScaleFile, to input a text file with each line containing the detector number and scale factor for that detector. These scales will be used in SaveHKL and AnvredCorrection. If scales for a detector are given in both the DetScaleList text string and the DetScaleFile file, the values from the text string will be used. +:ref:`algm-SNAPReduce` is new to mantid, but not for SNAP +users. Adding the algorithm to mantid installations will reduce the +amount of issues that SNAP users will encounter trying to reduce their +data. + Full list of `diffraction <http://github.com/mantidproject/mantid/pulls?q=is%3Apr+milestone%3A%22Release+3.9%22+is%3Amerged+label%3A%22Component%3A+Diffraction%22>`_ and `imaging <http://github.com/mantidproject/mantid/pulls?q=is%3Apr+milestone%3A%22Release+3.9%22+is%3Amerged+label%3A%22Component%3A+Imaging%22>`_ changes on GitHub. diff --git a/docs/source/release/v3.9.0/framework.rst b/docs/source/release/v3.9.0/framework.rst index f2affaefb1c154296813b25b0c0bfe62481bb311..df944b88db76ca8804689998fb728a2e33118752 100644 --- a/docs/source/release/v3.9.0/framework.rst +++ b/docs/source/release/v3.9.0/framework.rst @@ -22,6 +22,8 @@ Improved - :ref:`StartLiveData <algm-StartLiveData>` and its dialog now support dynamic listener properties, based on the specific LiveListener being used. - :ref: All algorithms using `AsciiPointBase` now have a new property 'Separator' which allows the delimiter to be set to either comma, space or tab. This affects `SaveReflCustomAscii <algm-SaveReflCustomAscii>`, `SaveReflThreeColumnAscii <algm-SaveReflThreeColumnAscii>`, `SaveANSTOAscii <algm-SaveANSTOAscii>` and `SaveILLCosmosAscii <algm-SaveILLCosmosAscii>`. - :ref:`ReplaceSpecialValues <algm-ReplaceSpecialValues>` now can replace 'small' values below a user specified threshold. +- :ref:`SaveMDWorkspaceToVTK <algm-SaveMDWorkspaceToVTK>` has a working progress bar. +- :ref:`SumSpectra <algm-SumSpectra>` has an option to ignore special floating point values called 'RemoveSpecialValues'. This is off by default but when enabled will ignore values such as NaN or Infinity during the summation of the spectra. It was also updated to fix special values being used in some cases when the option was selected. - :ref:`MonteCarloAbsorption <algm-MonteCarloAbsorption>` gained a new option: `Interpolation`. This controls the method used for interpolation. Availabile options are: `Linear` & `CSpline`. @@ -39,15 +41,22 @@ Performance CurveFitting ------------ -New -### - +- Systemtest, FittingBenchmarks, added for testing fit minimizer benchmarking scripts generating the tables displayed on :ref:`FittingMinimzers page <FittingMinimizers>`. This Systemtest also demo how these tables can be created as a standard Mantid script. - Algorithm :ref:`CalculateCostFunction <algm-CalculateCostFunction>` calculates a value of any available cost function. - Algorithm :ref:`EstimateFitParameters <algm-EstimateFitParameters>` estimates initial values of a fiting function in given intervals. +- Fit Function :ref:`FunctionQDepends <func-FunctionQDepends>` as the base class for QENS models depending on Q. Improved ######## +- The `Peak Radius` global setting for 1D peaks that limits the interval on which they are calculated is replaced with `PeakRadius` property of the :ref:`Fit <algm-Fit>` algorithm (see algorithm's description for the details). + +.. figure:: ../../images/NoPeakRadius_3.9.png + :class: screenshot + :width: 550px + +- The output and normalization MDHistoWorkspaces from :ref:`MDNormSCD <algm-MDNormSCD>` and :ref:`MDNormDirectSC <algm-MDNormDirectSC>` have the 'displayNormalization' set to 'NoNormalization'. For older outputs, the `setDisplayNormalization` function is now exposed to python. + Python ------ diff --git a/docs/source/release/v3.9.0/index.rst b/docs/source/release/v3.9.0/index.rst index faaf7ed2f97ea12d02ee039f759f0678169d30f6..73c942256096b3a34f86c2c691bed021f3972c79 100644 --- a/docs/source/release/v3.9.0/index.rst +++ b/docs/source/release/v3.9.0/index.rst @@ -41,8 +41,8 @@ Please cite any usage of Mantid as follows: If you want to cite this specific release please use: -- *Mantid 3.9: Manipulation and Analysis Toolkit for Instrument Data.; Mantid Project*. doi: http://dx.doi.org/10.5286/SOFTWARE/MANTID3.9 - `Full author list <http://data.datacite.org/10.5286/SOFTWARE/MANTID3.9>`_ +- *Mantid 3.9: Manipulation and Analysis Toolkit for Instrument Data.; Mantid Project*. doi: http://dx.doi.org/10.5286/SOFTWARE/MANTID3.9 + `Full author list <http://data.datacite.org/10.5286/SOFTWARE/MANTID3.9>`_ Changes ------- @@ -56,6 +56,7 @@ Changes Indirect Inelastic <indirect_inelastic> SANS <sans> Diffraction <diffraction> + Imaging <imaging> Muon Analysis <muon> Reflectometry <reflectometry> diff --git a/docs/source/release/v3.9.0/indirect_inelastic.rst b/docs/source/release/v3.9.0/indirect_inelastic.rst index 0b73df1bac091cccf4de35113b692781d06f58e9..2cc86e028fb501fda44f468c6b0e3777e94229ee 100644 --- a/docs/source/release/v3.9.0/indirect_inelastic.rst +++ b/docs/source/release/v3.9.0/indirect_inelastic.rst @@ -11,7 +11,7 @@ New features Algorithms ########## -- :ref:`EnergyWindowScan <algm-EnergyWindowScan>` and :ref:`IndirectEnergyWindowScan <algm-IndirectEnergyWindowScan>` have been added +- :ref:`EnergyWindowScan <algm-EnergyWindowScan>` and :ref:`IndirectQuickRun <algm-IndirectQuickRun>` have been added to perform a quick run of *EnergyTransfer*, *Elwin* and optional *MSDFit* - A new algorithm :ref:`NMoldyn4Interpolation <algm-NMoldyn4Interpolation>` which interpolates simulated data onto reference OSIRIS data @@ -19,6 +19,7 @@ Data Reduction ############## - Q-values in :ref:`BASISReduction <algm-BASISReduction>` output are now point data so that their values display correctly when plotted +- When plotting *ConvFit* results "Two Lorentzians" will produce plots for both lorentzians Data Analysis ############# @@ -26,11 +27,6 @@ Data Analysis - :ref:`TeixeiraWaterSQE <func-TeixeiraWaterSQE>` models translation of water-like molecules (jump diffusion). - :ref:`GetQsInQENSData <algm-GetQsInQENSData>` Extracts or computes Q values from a MatrixWorkspace. -Improvements ------------- - -- When plotting from interfaces the plots now display error bars as standard - Corrections ########### @@ -60,11 +56,13 @@ Improvements - Data saved in an ASCII format using the *EnergyTransfer* interface can be re-loaded into Mantid - TOSCA instrument definition file has been updated +- When plotting from interfaces the plots now display error bars as standard Bugfixes -------- - Clicking 'Save' without creating a res file in *ISISCalibration* no longer causes an error +- Fixed issue when trying to plot multiple spectra `Full list of changes on GitHub <http://github.com/mantidproject/mantid/pulls?q=is%3Apr+milestone%3A%22Release+3.9%22+is%3Amerged+label%3A%22Component%3A+Indirect+Inelastic%22>`_ diff --git a/docs/source/release/v3.9.0/reflectometry.rst b/docs/source/release/v3.9.0/reflectometry.rst index 96bb6e45251ffd61fe75b06e9f836fd41485b228..75b3b6e41432f046288a5b08f3b2a7ebd4e6b75f 100644 --- a/docs/source/release/v3.9.0/reflectometry.rst +++ b/docs/source/release/v3.9.0/reflectometry.rst @@ -21,7 +21,10 @@ ISIS Reflectometry (Polref) - New 'Save ASCII' tab added, similar in function and purpose to the 'Save Workspaces' window accessible from Interfaces->ISIS Reflectometry->File->Save Workspaces. - When runs are transferred to the processing table groups are now labeled according to run title. - Column :literal:`dQ/Q` is used as the rebin parameter to stitch workspaces. +- Fixed a bug where if the user answered 'no' to a popup asking if they wanted to process all runs, the progress bar would show activity as though a data reduction was occurring. +- The interface is now arranged in two different groups. Groups apply to tabs 'Run' and 'Settings'. - Documentation regarding the interface has been updated accordingly. +- Error messages are displayed if the user either attempts to transfer zero runs or transfer runs with a different strategy to the one they used to search for runs with. ISIS Reflectometry ################## diff --git a/docs/source/release/v3.9.0/ui.rst b/docs/source/release/v3.9.0/ui.rst index cfa4d2ff447f86dbcb5812ce3a384c553eb6e9be..53f8048066d1bb9b779fde584e334e41e1d09fcb 100644 --- a/docs/source/release/v3.9.0/ui.rst +++ b/docs/source/release/v3.9.0/ui.rst @@ -58,6 +58,8 @@ Bugs Resolved - The "Plot Surface from Group" and "Plot Contour from Group" options have been fixed and now work for both histogram and point data. Note that all workspaces in the group must have the same X data. - Fixed a bug where enabling auto rebinning in the slice viewer and zooming would not rebin the workspace if it was a histogram workspace. - Legend placement has been fixed in the "tiled plot"/``plotSubplots`` option, and these graphs now use Mantid's default plot style options. + - Fix a bug where saving a tiled plot saved to a project file would be reloaded with different size plots. + - Fixed a bug where minimised windows would not stay minimised after being serialised to a Mantid project SliceViewer Improvements ------------------------ diff --git a/instrument/HB3A_Definition.xml b/instrument/HB3A_Definition.xml index 35f73f3af74250df6bcd1b1a910b9a176887a5a7..3cd97a7ca82d4e53e2d4015b721a63efdc94c562 100644 --- a/instrument/HB3A_Definition.xml +++ b/instrument/HB3A_Definition.xml @@ -12,7 +12,7 @@ </component> <type is="SamplePos" name="sample-position"/> <!--PANEL--> - <component idfillbyfirst="x" idstart="1" idstepbyrow="256" type="panel"> + <component idfillbyfirst="x" idstart="1" idstepbyrow="256" type="arm"> <location name="bank1"> <parameter name="r-position"> <logfile eq="1.0*value+0.3750" id="diffr"/> @@ -28,13 +28,19 @@ </parameter> </location> </component> + <type name="arm"> + <component type="panel"> + <location> + <parameter name="x"> + <logfile eq='value' id='deltax'/> + </parameter> + <parameter name="y"> + <logfile eq='value' id='deltay'/> + </parameter> + </location> + </component> + </type> <type is="rectangular_detector" name="panel" type="pixel" xpixels="256" xstart="0.0252015625" xstep="-0.0001984375" ypixels="256" ystart="-0.022621875" ystep="0.0001984375"> - <parameter name="xstart"> - <value val="0.02530078125"/> - </parameter> - <parameter name="ystart"> - <value val="-0.02530078125"/> - </parameter> </type> <type is="detector" name="pixel"> <cuboid id="pixel-shape"> diff --git a/scripts/Calibration/tube.py b/scripts/Calibration/tube.py index cb1a97d2e8fdf5a0233f5fac5a8cff3d0c0475fb..4d091ecd8212459c70c7775674d48c5e7a3d2d4d 100644 --- a/scripts/Calibration/tube.py +++ b/scripts/Calibration/tube.py @@ -1,11 +1,26 @@ # pylint: disable=invalid-name -""" +import numpy +import os +import re + +from mantid.kernel import V3D +from mantid.api import (MatrixWorkspace, ITableWorkspace) +from mantid.simpleapi import (mtd, CreateEmptyTableWorkspace, DeleteWorkspace, config) +from tube_spec import TubeSpec +from ideal_tube import IdealTube +from tube_calib_fit_params import TubeCalibFitParams +from tube_calib import getCalibration + +# Need to avoid flake8 warning but we can't do that with this +# buried directly in the string +CALIBRATE_SIGNATURE = "ws, tubeSet, knownPositions, funcForm, [fitPar, margin, rangeList, calibTable, plotTube, excludeShorTubes, overridePeaks, fitPolyn, outputPeak]" # noqa + +__doc__ = _MODULE_DOC=""" ========================= Definition of Calibration ========================= -.. autofunction:: tube.calibrate(ws, tubeSet, knownPositions, funcForm, [fitPar, margin, rangeList, calibTable, - plotTube, excludeShorTubes, overridePeaks, fitPolyn, outputPeak]) +.. autofunction:: calibrate({0}) ========= Use Cases @@ -49,19 +64,7 @@ Other Useful Methods .. autofunction:: tube.readCalibrationFile -""" - -import numpy -import os -import re - -from mantid.kernel import V3D -from mantid.api import (MatrixWorkspace, ITableWorkspace) -from mantid.simpleapi import (mtd, CreateEmptyTableWorkspace, DeleteWorkspace, config) -from tube_spec import TubeSpec -from ideal_tube import IdealTube -from tube_calib_fit_params import TubeCalibFitParams -from tube_calib import getCalibration +""".format(CALIBRATE_SIGNATURE) def calibrate(ws, tubeSet, knownPositions, funcForm, **kwargs): diff --git a/scripts/CompareFitMinimizers/fitting_benchmarking.py b/scripts/CompareFitMinimizers/fitting_benchmarking.py new file mode 100644 index 0000000000000000000000000000000000000000..fb4e9890e83eddd5464f60a0a391634728a87f20 --- /dev/null +++ b/scripts/CompareFitMinimizers/fitting_benchmarking.py @@ -0,0 +1,404 @@ +""" +Classes and utility functions to support benchmarking of fitting minimizers in +Mantid or other packages useable from Python. These benchmarks are +focused on comparing different minimizers in terms of accuracy and +computation time. +""" +# Copyright © 2016 ISIS Rutherford Appleton Laboratory, NScD +# Oak Ridge National Laboratory & European Spallation Source +# +# This file is part of Mantid. +# Mantid is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# Mantid is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# File change history is stored at: <https://github.com/mantidproject/mantid>. +# Code Documentation is available at: <http://doxygen.mantidproject.org> + +from __future__ import (absolute_import, division, print_function) + +import os +import time + +import numpy as np + +import mantid.simpleapi as msapi + +import input_parsing as iparsing +import results_output as fitout +import test_result + + +def run_all_with_or_without_errors(base_problem_files_dir, use_errors, minimizers, + group_names, group_suffix_names, color_scale, save_to_file=False): + """ + Run all benchmark problems available, with/without using weights in the cost + function. This is just a convenience function meant to be used by system/unit tests, or other scripts + + ALL means: NIST + CUTEST + any fitting problems against observed Neutron data (+ any other + which may be added in the future) + + At this point in time it is assumed that the problem files are in store relative to + a base_problem_files_dir as follows: + + CUTEst/ + NIST_nonlinear_regression/ + Neutron_data/ + + Be warned this function can be verbose. + + @param base_problem_files_dir :: base directory path of all the benchmark problems + @param use_errors :: whether to use observational errors as weights in the cost function + @param minimizers :: list of minimizers to test + @param group_names :: names for display purposes + @param group_suffix_names :: group names to use as suffixes, for example in file names + @param color_scale :: list with pairs of threshold value - color, to produce color + @param save_to_file :: whether to save the table outputs to files following specific naming conventions + """ + + # Assume the benchmark problems are stores as follows + nist_group_dir = os.path.join(base_problem_files_dir, 'NIST_nonlinear_regression') + cutest_group_dir = os.path.join(base_problem_files_dir, 'CUTEst') + neutron_data_group_dirs = [os.path.join(base_problem_files_dir, 'Neutron_data')] + + problems, results_per_group = do_fitting_benchmark(nist_group_dir=nist_group_dir, + cutest_group_dir=cutest_group_dir, + neutron_data_group_dirs=neutron_data_group_dirs, + minimizers=minimizers, use_errors=use_errors) + + # Results for every test problem in each group + for idx, group_results in enumerate(results_per_group): + print("\n\n") + print("********************************************************") + print("**************** RESULTS FOR GROUP {0}, {1} ************".format(idx+1, + group_names[idx])) + print("********************************************************") + fitout.print_group_results_tables(minimizers, group_results, problems[idx], + group_name=group_suffix_names[idx], + use_errors=use_errors, + simple_text=True, rst=True, save_to_file=save_to_file, + color_scale=color_scale) + + # Results aggregated (median) by group (NIST, Neutron data, CUTEst, etc.) + header = '\n\n**************** OVERALL SUMMARY - ALL GROUPS ******** \n\n' + print(header) + fitout.print_overall_results_table(minimizers, results_per_group, problems, group_names, + use_errors=use_errors, save_to_file=save_to_file) + + # Flush to reduce mix-up with system tests/runner output + import sys + sys.stdout.flush() + + +def do_fitting_benchmark(nist_group_dir=None, cutest_group_dir=None, neutron_data_group_dirs=None, + minimizers=None, use_errors=True): + """ + Run a fit minimizer benchmark against groups of fitting problems. + + Unless group directories of fitting problems are specified no fitting benchmarking is done. + + NIST and CUTEst refer to the NIST and CUTEst fitting test problem sets, where + for example CUTEst is used for fit tests in the mathematical numerical literature. + + The Neutron_data group contain fit tests against real noisy experimental neutron data. + This latter group may grow to contain fitting example from multiple directories. + + @param nist_group_dir :: whether to try to load NIST problems + @param cutest_group_dir :: whether to try to load CUTEst problems + @param neutron_data_group_dirs :: base directory where fitting problems are located including NIST+CUTEst + @param minimizers :: list of minimizers to test + @param use_errors :: whether to use observational errors as weights in the cost function + """ + + # Several blocks of problems. Results for each block will be calculated sequentially, and + # will go into a separate table + problem_blocks = [] + + if nist_group_dir: + # get NIST problems grouped into blocks of problems, in blocks of increasing difficulty + problem_blocks.extend(get_nist_problem_files(nist_group_dir)) + + if cutest_group_dir: + # get CUTEet problems - just treated as one block of problems + problem_blocks.extend([get_cutest_problem_files(cutest_group_dir)]) + + if neutron_data_group_dirs: + problem_blocks.extend(get_data_groups(neutron_data_group_dirs)) + + prob_results = [do_fitting_benchmark_group(block, minimizers, use_errors=use_errors) for + block in problem_blocks] + + probs, results = zip(*prob_results) + + if len(probs) != len(results): + raise RuntimeError('probs : {0}, prob_results: {1}'.format(len(probs), len(results))) + + return probs, results + + +def do_fitting_benchmark_group(problem_files, minimizers, use_errors=True): + """ + Applies minimizers to a group (collection) of test problems. For example the + collection of all NIST problems + + @param problem_files :: a list of list of files that define a group of + test problems. For example all the NIST files sub-groupped according to level + of fitting difficulty, where the lowest list level list the file names + + @param minimizers :: list of minimizers to test + @param use_errors :: whether to use observational errors as weights in the cost function + + @returns :: problem definitions loaded from the files, and results of running them with + the minimizers requested + """ + + problems = [] + results_per_problem = [] + for prob_file in problem_files: + try: + # Note the CUTEst problem are assumed to be expressed in NIST format + prob = iparsing.load_nist_fitting_problem_file(prob_file) + except (AttributeError, RuntimeError): + prob = iparsing.load_neutron_data_fitting_problem_file(prob_file) + + print("* Testing fitting for problem definition file {0}".format(prob_file)) + print("* Testing fitting of problem {0}".format(prob.name)) + + results_prob = do_fitting_benchmark_one_problem(prob, minimizers, use_errors) + results_per_problem.extend(results_prob) + + return problems, results_per_problem + + +def do_fitting_benchmark_one_problem(prob, minimizers, use_errors=True): + """ + One problem with potentially several starting points, returns a list (start points) of + lists (minimizers). + + @param prob :: fitting problem + @param minimizers :: list of minimizers to evaluate/compare + @param use_errors :: whether to use observational errors when evaluating accuracy (in the + cost function) + """ + + wks, cost_function = prepare_wks_cost_function(prob, use_errors) + + # Each NIST problem generate two results per file - from two different starting points + results_fit_problem = [] + + # Get function definitions for the problem - one for each starting point + function_defs = get_function_definitions(prob) + + # Loop over the different starting points + for user_func in function_defs: + results_problem_start = [] + for minimizer_name in minimizers: + t_start = time.clock() + + status, chi2, fit_wks, params, errors = run_fit(wks, prob, function=user_func, + minimizer=minimizer_name, + cost_function=cost_function) + t_end = time.clock() + print("*** with minimizer {0}, Status: {1}, chi2: {2}".format(minimizer_name, status, chi2)) + print(" params: {0}, errors: {1}".format(params, errors)) + + def sum_of_squares(values): + return np.sum(np.square(values)) + + if fit_wks: + sum_err_sq = sum_of_squares(fit_wks.readY(2)) + # print " output simulated values: {0}".format(fit_wks.readY(1)) + else: + sum_err_sq = float("inf") + print(" WARNING: no output fit workspace") + + print(" sum sq: {0}".format(sum_err_sq)) + + result = test_result.FittingTestResult() + result.problem = prob + result.fit_status = status + result.fit_chi2 = chi2 + result.params = params + result.errors = errors + result.sum_err_sq = sum_err_sq + result.runtime = t_end - t_start + print("Result object: {0}".format(result)) + results_problem_start.append(result) + + results_fit_problem.append(results_problem_start) + + return results_fit_problem + + +def run_fit(wks, prob, function, minimizer='Levenberg-Marquardt', cost_function='Least squares'): + """ + Fits the data in a workspace with a function, using the algorithm Fit. + Importantly, the option IgnoreInvalidData is enabled. Check the documentation of Fit for the + implications of this. + + @param wks :: MatrixWorkspace with data to fit, in the format expected by the algorithm Fit + @param prob :: Problem definition + @param function :: function definition as used in the algorithm Fit + @param minimizer :: minimizer to use in Fit + @param cost_function :: cost function to use in Fit + + @returns the fitted parameter values and error estimates for these + """ + status = None + chi2 = None + param_tbl = None + fit_wks = None + try: + # When using 'Least squares' (weighted by errors), ignore nans and zero errors, but don't + # ignore them when using 'Unweighted least squares' as that would ignore all values! + ignore_invalid = cost_function == 'Least squares' + + # Note the ugly adhoc exception. We need to reconsider these WISH problems: + if 'WISH17701' in prob.name: + ignore_invalid = False + + status, chi2, covar_tbl, param_tbl, fit_wks = msapi.Fit(function, wks, Output='ws_fitting_test', + Minimizer=minimizer, + CostFunction=cost_function, + IgnoreInvalidData=ignore_invalid, + StartX=prob.start_x, EndX=prob.end_x) + + calc_chi2 = msapi.CalculateChiSquared(Function=function, + InputWorkspace=wks, IgnoreInvalidData=ignore_invalid) + print("*** with minimizer {0}, calculated: chi2: {1}".format(minimizer, calc_chi2)) + + except RuntimeError as rerr: + print("Warning, Fit probably failed. Going on. Error: {0}".format(str(rerr))) + + if param_tbl: + params = param_tbl.column(1)[:-1] + errors = param_tbl.column(2)[:-1] + else: + params = None + errors = None + + return status, chi2, fit_wks, params, errors + + +def prepare_wks_cost_function(prob, use_errors): + """ + Build a workspace ready for Fit() and a cost function string according to the problem + definition. + """ + if use_errors: + data_e = None + if not isinstance(prob.data_pattern_obs_errors, np.ndarray): + # Fake observational errors + data_e = np.sqrt(prob.data_pattern_in) + else: + data_e = prob.data_pattern_obs_errors + + wks = msapi.CreateWorkspace(DataX=prob.data_pattern_in, DataY=prob.data_pattern_out, + DataE=data_e) + cost_function = 'Least squares' + else: + wks = msapi.CreateWorkspace(DataX=prob.data_pattern_in, DataY=prob.data_pattern_out) + cost_function = 'Unweighted least squares' + + return wks, cost_function + + +def get_function_definitions(prob): + """ + Produces function definition strings (as a full definition in + muparser format, including the function and the initial values for + the parameters), one for every different starting point defined in + the test problem. + + @param prob :: fitting test problem object + + @returns :: list of function strings ready for Fit() + """ + function_defs = [] + if prob.starting_values: + num_starts = len(prob.starting_values[0][1]) + for start_idx in range(0, num_starts): + + print("=================== starting values,: {0}, with idx: {1} ================". + format(prob.starting_values, start_idx)) + start_string = '' # like: 'b1=250, b2=0.0005' + for param in prob.starting_values: + start_string += ('{0}={1},'.format(param[0], param[1][start_idx])) + + if 'name' in prob.equation: + function_defs.append(prob.equation) + else: + function_defs.append("name=UserFunction, Formula={0}, {1}".format(prob.equation, start_string)) + else: + # Equation from a neutron data spec file. Ready to be used + function_defs.append(prob.equation) + + return function_defs + + +def get_nist_problem_files(search_dir): + """ + Group the NIST problem files into separeate blocks according + to assumed fitting different levels: lower, average, + higher. + + @returns :: list of list of problem files + """ + # Grouped by "level of difficulty" + nist_lower = ['Misra1a.dat', 'Chwirut2.dat', 'Chwirut1.dat', 'Lanczos3.dat', + 'Gauss1.dat', 'Gauss2.dat', 'DanWood.dat', 'Misra1b.dat'] + + nist_average = ['Kirby2.dat', 'Hahn1.dat', + # 'Nelson.dat' needs log[y] parsing / DONE, needs x1, x2 + 'MGH17.dat', 'Lanczos1.dat', 'Lanczos2.dat', 'Gauss3.dat', + 'Misra1c.dat', 'Misra1d.dat', + # 'Roszman1.dat' <=== needs handling the 'pi = 3.1415...' / DOME + # And the 'arctan()'/ DONE, but generated lots of NaNs + 'ENSO.dat'] + nist_higher = ['MGH09.dat', 'Thurber.dat', 'BoxBOD.dat', 'Rat42.dat', + 'MGH10.dat', 'Eckerle4.dat', 'Rat43.dat', 'Bennett5.dat'] + + nist_lower_files = [os.path.join(search_dir, fname) for fname in nist_lower] + nist_average_files = [os.path.join(search_dir, fname) for fname in nist_average] + nist_higher_files = [os.path.join(search_dir, fname) for fname in nist_higher] + problem_files = [nist_lower_files, nist_average_files, nist_higher_files] + + return problem_files + + +def get_cutest_problem_files(search_dir): + + cutest_all = ['PALMER6C.dat', 'PALMER7C.dat', 'PALMER8C.dat', 'YFITU.dat', 'VESUVIOLS.dat', 'DMN15102LS.dat'] + + cutest_files = [os.path.join(search_dir, fname) for fname in cutest_all] + + return cutest_files + + +def get_data_groups(data_groups_dirs): + + problem_groups = [] + for grp_dir in data_groups_dirs: + problem_groups.append(get_data_group_problem_files(grp_dir)) + + return problem_groups + + +def get_data_group_problem_files(grp_dir): + import glob + + search_str = os.path.join(grp_dir, "*.txt") + probs = glob.glob(search_str) + + probs.sort() + print ("Found test problem files: ", probs) + return probs diff --git a/scripts/CompareFitMinimizers/input_parsing.py b/scripts/CompareFitMinimizers/input_parsing.py new file mode 100644 index 0000000000000000000000000000000000000000..641c3ba41b855f47d9c6e22a96e80367e9defa4a --- /dev/null +++ b/scripts/CompareFitMinimizers/input_parsing.py @@ -0,0 +1,271 @@ +""" +Parse input files describing fitting test examples and load the +information into problem objects + +""" +# Copyright © 2016 ISIS Rutherford Appleton Laboratory, NScD +# Oak Ridge National Laboratory & European Spallation Source +# +# This file is part of Mantid. +# Mantid is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# Mantid is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# File change history is stored at: <https://github.com/mantidproject/mantid>. +# Code Documentation is available at: <http://doxygen.mantidproject.org> + +from __future__ import (absolute_import, division, print_function) + +import os +import re + +import numpy as np + +import test_problem + + +def load_nist_fitting_problem_file(problem_filename): + with open(problem_filename) as spec_file: + return parse_nist_file(spec_file) + + +def parse_data_pattern(data_text): + """ + Parses the data part of a NIST test problem file (the columns of + values) and produces a numpy array with the data. + + """ + if not data_text: + return None + + first = data_text[0].strip() + dim = len(first.split()) + data_points = np.zeros((len(data_text), dim)) + + for idx, line in enumerate(data_text): + line = line.strip() + point_text = line.split() + point = [float(val) for val in point_text] + data_points[idx, :] = point + + return data_points + + +def parse_equation(eq_text): + """ + Parses the equation text (possibly multi-line) and does a rough + conversion from NIST equation format to muparser format + + @param eq_text :: equation formula as given in a NIST problem description + @return formula ready to be used in the 'Formula=' of functions 'UserFunction' of + the Fit algorithm + """ + start_normal = r'\s*y\s*=(.+)' + start_log = r'\s*log\[y\]\s*=(.+)' + # try first the usual syntax + if re.match(start_normal, eq_text): + match = re.search(r'y\s*=(.+)\s*\+\s*e', eq_text) + equation = match.group(1).strip() + # log-syntax used in NIST/Nelson + elif re.match(start_log, eq_text): + match = re.search(r'log\[y\]\s*=(.+)\s*\+\s*e', eq_text) + equation = "exp(" + match.group(1).strip() + ")" + else: + raise RuntimeError("Unrecognized equation syntax when trying to parse a NIST " + "equation: " + eq_text) + + # 'NIST equation syntax' => muparser syntax + # brackets for muparser + equation = equation.replace('[', '(') + equation = equation.replace(']', ')') + equation = equation.replace('arctan', 'atan') + equation = equation.replace('**', '^') + return equation + + +def parse_starting_values(lines): + starting_vals = [] + for line in lines: + if not line.strip() or line.startswith('Residual'): + break + + comps = line.split() + if 6 != len(comps) and 5 != len(comps): + raise RuntimeError("Failed to parse this line as starting " + "values information: {0}".format(line)) + + # A bit weak/lax parsing, if there is one less column, assume only one start point + if 6 == len(comps): + alt_values = [float(comps[2]), float(comps[3])] + elif 5 == len(comps): + alt_values = [float(comps[2])] + + starting_vals.append([comps[0], alt_values]) + + return starting_vals + + +def parse_nist_file(spec_file): + """ + Produce a fitting test problem definition object from a NIST text file. + + @param spec_file :: input file, as a standard NIST text (.dat) file + """ + + lines = spec_file.readlines() + equation_text, data_pattern_text, starting_values, residual_sum_sq = parse_nist_file_line_by_line(lines) + + if not equation_text or not data_pattern_text: + raise RuntimeError('Could not find the equation and data after parsing the lines of this file: {0}'. + format(spec_file.name)) + + data_pattern = parse_data_pattern(data_pattern_text) + parsed_eq = parse_equation(equation_text) + + prob = test_problem.FittingTestProblem() + prob.name = os.path.basename(spec_file.name) + prob.linked_name = ("`{0} <http://www.itl.nist.gov/div898/strd/nls/data/{1}.shtml>`__". + format(prob.name, prob.name.lower())) + prob.equation = parsed_eq + prob.starting_values = starting_values + prob.data_pattern_in = data_pattern[:, 1:] + prob.data_pattern_out = data_pattern[:, 0] + prob.ref_residual_sum_sq = residual_sum_sq + + return prob + + +def parse_nist_file_line_by_line(lines): + """ + Get several relevant pieces of information from the lines of a NIST problem file + This parser is far from great but it does the job. + + @param lines :: lines as directly loaded from a file + + @returns :: the equation string, the data string, the starting values, and the + certified chi^2, as found in the text lines + """ + + idx, data_idx = 0, 0 + data_pattern_text = None + residual_sum_sq = 0 + equation_text = None + starting_values = None + # The first line should be: + # NIST/ITL StRD + while idx < len(lines): + line = lines[idx].strip() + idx += 1 + + if not line: + continue + + if line.startswith('Model:'): + # Would skip number of parameters, and empty line, but not + # adequate for all test problems + # idx += 3 + + # Before 'y = ...' there can be lines like 'pi = 3.14159...' + while (not re.match(r'\s*y\s*=(.+)', lines[idx]) + and not re.match(r'\s*log\[y\]\s*=(.+)', lines[idx]))\ + and idx < len(lines): # [\s*\+\s*e] + idx += 1 + # Next non-empty lines are assumed to continue the equation + equation_text = '' + while lines[idx].strip(): + equation_text += lines[idx].strip() + idx += 1 + + elif 'Starting values' in line or 'Starting Values' in line: + # 1 empty line, and one heading line before values + idx += 2 + starting_values = parse_starting_values(lines[idx:]) + idx += len(starting_values) + + elif line.startswith('Residual Sum of Squares'): + residual_sum_sq = float(line.split()[4]) + + elif line.startswith('Data:'): + if 0 == data_idx: + data_idx += 1 + elif 1 == data_idx: + data_pattern_text = lines[idx:] + idx = len(lines) + else: + raise RuntimeError('Error parsing data line: {}'.format(line)) + else: + print("unknown line in supposedly NIST test file, ignoring: {0}".format(line)) + + return equation_text, data_pattern_text, starting_values, residual_sum_sq + + +def load_neutron_data_fitting_problem_file(fname): + """ + Builds a FittingTestProblem object from a text file. The file is expected to + have a list of variables (input filename, name, equation, etc.) + + Other alternatives could be ConfigParser (ini format, parser not extermely + good), or JSON. + + @param fname :: name of the file to load + """ + with open(fname) as probf: + entries = get_neutron_data_problem_entries(probf) + + prob = test_problem.FittingTestProblem() + get_fitting_neutron_data(entries['input_file'], prob) + prob.name = entries['name'] + prob.equation = entries['function'] + prob.starting_values = None + if 'fit_parameters' in entries: + prob.start_x = entries['fit_parameters']['StartX'] + prob.end_x = entries['fit_parameters']['EndX'] + + return prob + + +def get_neutron_data_problem_entries(problem_file): + """ + Get values from the lines of a "neutron fitting problem definition file", + They are returned as a dictionary of key (lhs) - value (rhs). + """ + entries = {} + for line in problem_file: + # discard comments + line = line.partition('#')[0] + line = line.rstrip() + if not line: + continue + + # take values (lhs = rhs) + lhs, rhs = line.split("=", 1) + # assumes it is safe to evaluate the rhs (it's a string for example) + entries[lhs.strip()] = eval(rhs.strip()) + + return entries + + +def get_fitting_neutron_data(fname, prob): + """ + Load the X-Y-E data from a file and put the values into a fitting problem + definition object. + + @param fname :: file name to load (using mantid loaders) + @param prob :: problem definition to populate with X-Y-E data. + """ + import mantid.simpleapi as msapi + + wks = msapi.Load(fname) + prob.data_pattern_in = wks.readX(0) + prob.data_pattern_out = wks.readY(0) + prob.data_pattern_obs_errors = wks.readE(0) + prob.ref_residual_sum_sq = 0 diff --git a/scripts/CompareFitMinimizers/post_processing.py b/scripts/CompareFitMinimizers/post_processing.py new file mode 100644 index 0000000000000000000000000000000000000000..2a947ace4b06391f913fb735f7908c4bbf5a56e9 --- /dev/null +++ b/scripts/CompareFitMinimizers/post_processing.py @@ -0,0 +1,115 @@ +# Copyright © 2016 ISIS Rutherford Appleton Laboratory, NScD +# Oak Ridge National Laboratory & European Spallation Source +# +# This file is part of Mantid. +# Mantid is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# Mantid is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# File change history is stored at: <https://github.com/mantidproject/mantid>. +# Code Documentation is available at: <http://doxygen.mantidproject.org> + +import numpy as np +from scipy import stats # older version of numpy does not support nanmean and nanmedian + + +def calc_summary_table(minimizers, group_results): + """ + Calculates a summary from problem-individual results. At the moment the only summary + statistic calculated is the median. The output is produced as numpy matrices. + + @param minimizers :: list of minimizers used (their names) + + @param group_results :: results from running fitting tests on different problems (list + of lists, where the first level is the group, and the second level is the individual test). + + + @returns two numpy matrices (where columns are the groups, and rows are the minimizers) + with summary statistic (median) from the problem-individual results. + """ + + num_groups = len(group_results) + num_minimizers = len(minimizers) + + groups_norm_acc = np.zeros((num_groups, num_minimizers)) + groups_norm_runtime = np.zeros((num_groups, num_minimizers)) + for group_idx, results_per_test in enumerate(group_results): + num_tests = len(results_per_test) + accuracy_tbl = np.zeros((num_tests, num_minimizers)) + time_tbl = np.zeros((num_tests, num_minimizers)) + + for test_idx in range(0, num_tests): + for minimiz_idx in range(0, num_minimizers): + accuracy_tbl[test_idx, minimiz_idx] = results_per_test[test_idx][minimiz_idx].sum_err_sq + time_tbl[test_idx, minimiz_idx] = results_per_test[test_idx][minimiz_idx].runtime + + # Min across all alternative runs/minimizers + min_sum_err_sq = np.nanmin(accuracy_tbl, 1) + min_runtime = np.nanmin(time_tbl, 1) + + norm_acc_rankings = accuracy_tbl / min_sum_err_sq[:, None] + norm_runtime_rankings = time_tbl / min_runtime[:, None] + + groups_norm_acc[group_idx, :] = stats.nanmedian(norm_acc_rankings, 0) + groups_norm_runtime[group_idx, :] = stats.nanmedian(norm_runtime_rankings, 0) + + return groups_norm_acc, groups_norm_runtime + + +def calc_accuracy_runtime_tbls(results_per_test, minimizers): + """ + This produces a numpy matrix for convenience, with + 1 row per problem+start, 1 column per minimizer + """ + num_tests = len(results_per_test) + num_minimizers = len(minimizers) + accuracy_tbl = np.zeros((num_tests, num_minimizers)) + time_tbl = np.zeros((num_tests, num_minimizers)) + for test_idx in range(0, num_tests): + for minimiz_idx in range(0, num_minimizers): + accuracy_tbl[test_idx, minimiz_idx] = results_per_test[test_idx][minimiz_idx].sum_err_sq + time_tbl[test_idx, minimiz_idx] = results_per_test[test_idx][minimiz_idx].runtime + + return accuracy_tbl, time_tbl + + +def calc_norm_summary_tables(accuracy_tbl, time_tbl): + """ + Calculate normalized performance/ranking summary, as numpy + matrices as usual for convenience, and matrices of additional + statistics (min, max, percentiles, etc.) + + Here normalized means relative to the best which gets a 1, all + others get the ratio resulting from dividing by the performance of + the best. + """ + # Min across all minimizers, i.e. for each fit problem what is the lowest chi-squared and the lowest time + min_sum_err_sq = np.nanmin(accuracy_tbl, 1) + min_runtime = np.nanmin(time_tbl, 1) + + # create normalised tables + norm_acc_rankings = accuracy_tbl / min_sum_err_sq[:, None] + norm_runtimes = time_tbl / min_runtime[:, None] + + summary_cells_acc = np.array([np.nanmin(norm_acc_rankings, 0), + np.nanmax(norm_acc_rankings, 0), + stats.nanmean(norm_acc_rankings, 0), + stats.nanmedian(norm_acc_rankings, 0) + ]) + + summary_cells_runtime = np.array([np.nanmin(norm_runtimes, 0), + np.nanmax(norm_runtimes, 0), + stats.nanmean(norm_runtimes, 0), + stats.nanmedian(norm_runtimes, 0) + ]) + + return norm_acc_rankings, norm_runtimes, summary_cells_acc, summary_cells_runtime diff --git a/scripts/CompareFitMinimizers/results_output.py b/scripts/CompareFitMinimizers/results_output.py new file mode 100644 index 0000000000000000000000000000000000000000..57d28e5c23af2b95e2ca6723f5c3b07b132b5130 --- /dev/null +++ b/scripts/CompareFitMinimizers/results_output.py @@ -0,0 +1,474 @@ +""" +Produce output tables from fitting benchmarking results, in different +formats such as RST and plain text. +""" +# Copyright © 2016 ISIS Rutherford Appleton Laboratory, NScD +# Oak Ridge National Laboratory & European Spallation Source +# +# This file is part of Mantid. +# Mantid is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# Mantid is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# File change history is stored at: <https://github.com/mantidproject/mantid>. +# Code Documentation is available at: <http://doxygen.mantidproject.org> + +from __future__ import (absolute_import, division, print_function) + +import numpy as np +from scipy import stats # older version of numpy does not support nanmean and nanmedian +import post_processing as postproc + +# Some naming conventions for the output files +BENCHMARK_VERSION_STR = 'v3.8' +FILENAME_SUFFIX_ACCURACY = 'acc' +FILENAME_SUFFIX_RUNTIME = 'runtime' + + +def print_group_results_tables(minimizers, results_per_test, problems_obj, group_name, use_errors, + simple_text=True, rst=False, save_to_file=False, color_scale=None): + """ + Prints out results for a group of fit problems in accuracy and runtime tables, in a summary + format and both as simple text, rst format and/or to file depending on input arguments + + @param minimizers :: list of minimizer names + @param results_per_test :: result objects + @param problems_obj :: definitions of the test problems + @param group_name :: name of this group of problems (example 'NIST "lower difficulty"', or + 'Neutron data') + @param use_errors :: whether to use observational errors + @param simple_text :: whether to print the tables in a simple text format + @param rst :: whether to print the tables in rst format. They are printed to the standard outputs + and to files following specific naming conventions + @param save_to_file :: If rst=True, whether to save the tables to files following specific naming conventions + @param color_scale :: threshold-color pairs. This is used for RST tables. The number of levels + must be consistent with the style sheet used in the documentation pages (5 + at the moment). + """ + linked_problems = build_indiv_linked_problems(results_per_test, group_name) + + # Calculate summary tables + accuracy_tbl, runtime_tbl = postproc.calc_accuracy_runtime_tbls(results_per_test, minimizers) + norm_acc_rankings, norm_runtimes, summary_cells_acc, summary_cells_runtime = \ + postproc.calc_norm_summary_tables(accuracy_tbl, runtime_tbl) + + if simple_text: + print_tables_simple_text(minimizers, results_per_test, accuracy_tbl, runtime_tbl, norm_acc_rankings) + + if rst: + # print out accuracy table for this group of fit problems + tbl_acc_indiv = build_rst_table(minimizers, linked_problems, norm_acc_rankings, + comparison_type='accuracy', comparison_dim='', + using_errors=use_errors, color_scale=color_scale) + header = " ************* Comparison of sum of square errors (RST): *********\n" + header += " *****************************************************************\n" + header += "\n\n" + print(header) + print (tbl_acc_indiv) + + # optionally save the above table to file + if save_to_file: + fname = ('comparison_{weighted}_{version}_{metric_type}_{group_name}.txt'. + format(weighted=weighted_suffix_string(use_errors), + version=BENCHMARK_VERSION_STR, metric_type=FILENAME_SUFFIX_ACCURACY, group_name=group_name)) + with open(fname, 'w') as tbl_file: + print(tbl_acc_indiv, file=tbl_file) + + # print out accuracy summary table for this group of fit problems + ext_summary_cols = minimizers + ext_summary_rows = ['Best ranking', 'Worst ranking', 'Average', 'Median'] + tbl_acc_summary = build_rst_table(ext_summary_cols, ext_summary_rows, summary_cells_acc, + comparison_type='accuracy', comparison_dim='', + using_errors=use_errors, color_scale=color_scale) + header = '**************** Statistics/Summary (accuracy): ******** \n\n' + print(header) + print(tbl_acc_summary) + + # print out runtime table for this group of fit problems + tbl_runtime_indiv = build_rst_table(minimizers, linked_problems, norm_runtimes, + comparison_type='runtime', comparison_dim='', + using_errors=use_errors, color_scale=color_scale) + header = " ************* Comparison of runtimes (RST): ****************\n" + header += " *****************************************************************\n" + header += "\n\n" + print(header) + print (tbl_runtime_indiv) + + # optionally save the above table to file + if save_to_file: + fname = ('comparison_{weighted}_{version}_{metric_type}_{group_name}.txt'. + format(weighted=weighted_suffix_string(use_errors), + version=BENCHMARK_VERSION_STR, metric_type=FILENAME_SUFFIX_RUNTIME, group_name=group_name)) + with open(fname, 'w') as tbl_file: + print(tbl_runtime_indiv, file=tbl_file) + + # print out runtime summary table for this group of fit problems + tbl_runtime_summary = build_rst_table(ext_summary_cols, ext_summary_rows, summary_cells_runtime, + comparison_type='runtime', comparison_dim='', + using_errors=use_errors, color_scale=color_scale) + header = '**************** Statistics/Summary (runtime): ******** \n\n' + print(header) + print(tbl_runtime_summary) + + +def build_indiv_linked_problems(results_per_test, group_name): + """ + Makes a list of linked problem names which would be used for the + rows of the first column of the tables of individual results. + + @param results_per_test :: results as produces by the fitting tests + @param group_name :: name of the group (NIST, Neutron data, etc.) this problem is part of + + @returns :: list of problems with their description link tags + """ + num_tests = len(results_per_test) + prev_name = '' + prob_count = 1 + linked_problems = [] + for test_idx in range(0, num_tests): + raw_name = results_per_test[test_idx][0].problem.name + name = raw_name.split('.')[0] + if name == prev_name: + prob_count += 1 + else: + prob_count = 1 + + prev_name = name + name_index = name + ' ' + str(prob_count) + + # TO-DO: move this to the nist loader, not here! + if 'nist_' in group_name: + linked_problems.append("`{0} <http://www.itl.nist.gov/div898/strd/nls/data/{1}.shtml>`__". + format(name_index, name.lower())) + else: + linked_problems.append(name) + + return linked_problems + + +def build_group_linked_names(group_names): + """ + Add a link for RST tables if there is a website or similar describing the group. + + @param group_names :: names as plain text + + @returns :: names with RST links if available + """ + linked_names = [] + for name in group_names: + # This should be tidied up. We currently don't have links for groups other than NIST + if 'NIST' in name: + linked = "`{0} <http://www.itl.nist.gov/div898/strd/nls/nls_main.shtml>`__".format(name) + else: + linked = name + + linked_names.append(linked) + + return linked_names + + +def print_overall_results_table(minimizers, group_results, problems, group_names, use_errors, + simple_text=True, save_to_file=False): + + groups_norm_acc, groups_norm_runtime = postproc.calc_summary_table(minimizers, group_results) + + grp_linked_names = build_group_linked_names(group_names) + + header = '**************** Accuracy ******** \n\n' + print(header) + tbl_all_summary_acc = build_rst_table(minimizers, grp_linked_names, groups_norm_acc, + comparison_type='summary', comparison_dim='accuracy', + using_errors=use_errors) + print(tbl_all_summary_acc) + + if save_to_file: + fname = ('comparison_{weighted}_{version}_{metric_type}_{group_name}.txt'. + format(weighted=weighted_suffix_string(use_errors), + version=BENCHMARK_VERSION_STR, metric_type=FILENAME_SUFFIX_ACCURACY, group_name='summary')) + with open(fname, 'w') as tbl_file: + print(tbl_all_summary_acc, file=tbl_file) + + header = '**************** Runtime ******** \n\n' + print(header) + tbl_all_summary_runtime = build_rst_table(minimizers, grp_linked_names, groups_norm_runtime, + comparison_type='summary', comparison_dim='runtime', + using_errors=use_errors) + print(tbl_all_summary_runtime) + + if save_to_file: + fname = ('comparison_{weighted}_{version}_{metric_type}_{group_name}.txt'. + format(weighted=weighted_suffix_string(use_errors), + version=BENCHMARK_VERSION_STR, metric_type=FILENAME_SUFFIX_RUNTIME, group_name='summary')) + with open(fname, 'w') as tbl_file: + print(tbl_all_summary_runtime, file=tbl_file) + + +def weighted_suffix_string(use_errors): + """ + Produces a suffix weighted/unweighted. Used to generate names of + output files. + """ + values = {True: 'weighted', False: 'unweighted'} + return values[use_errors] + + +def display_name_for_minimizers(names): + """ + Converts minimizer names into their "display names". For example + to rename DTRS to "Trust region" or similar + + """ + display_names = names + # Quick fix for DTRS name in version 3.8 - REMOVE + for idx, minimizer in enumerate(names): + if 'DTRS' == minimizer: + display_names[idx] = 'Trust Region' + + return display_names + + +def calc_cell_len_rst_table(columns_txt, items_link): + """ + Calculate what width in ascii characters we need for an RST table. + + @param columns_txt :: list of the contents of the column headers + """ + # One length for all cells + cell_len = 50 + cell_len = 0 + for col in columns_txt: + new_len = len(col) + 2 + if new_len > cell_len: + cell_len = new_len + + # Beware of the long links + links_len = 0 + if items_link and isinstance(items_link, list): + links_len = max([len(item) for item in items_link]) + elif items_link: + links_len = len(items_link) + + additional_len = 0 + if items_link: + additional_len = links_len + cell_len += int(additional_len/1.2) + + return cell_len + + +def build_rst_table(columns_txt, rows_txt, cells, comparison_type, comparison_dim, + using_errors, color_scale=None): + """" + Builds an RST table as a string, given the list of column and row headers, + and a 2D numpy array with values for the cells. + This can be tricky/counterintuitive, see: + http://docutils.sourceforge.net/docs/dev/rst/problems.html + + @param columns_txt :: the text for the columns, one item per column + @param rows_txt :: the text for the rows (will go in the leftmost column) + @param cells :: a 2D numpy array with as many rows as items have been given + in rows_txt, and as many columns as items have been given in columns_txt + + @param comparison_type :: whether this is a 'summary', or a full 'accuracy', or 'runtime' + table. + @param comparison_dim :: dimension (accuracy / runtime) + @param using_errors :: whether this comparison uses errors in the cost function + (weighted or unweighted), required to link the table properly + + @param color_scale :: list with pairs of threshold value - color, to produce color + tags for the cells + """ + columns_txt = display_name_for_minimizers(columns_txt) + + items_link = build_items_links(comparison_type, comparison_dim, using_errors) + + cell_len = calc_cell_len_rst_table(columns_txt, items_link) + + # The first column tends to be disproportionately long if it has a link + first_col_len = calc_first_col_len(cell_len, rows_txt) + + tbl_header_top, tbl_header_text, tbl_header_bottom = build_rst_table_header_chunks(first_col_len, cell_len, + columns_txt) + + tbl_header = tbl_header_top + '\n' + tbl_header_text + '\n' + tbl_header_bottom + '\n' + # the footer is in general the delimiter between rows, including the last one + tbl_footer = tbl_header_top + '\n' + + tbl_body = '' + for row in range(0, cells.shape[0]): + # Pick either individual or group link + if isinstance(items_link, list): + link = items_link[row] + else: + link = items_link + + tbl_body += '|' + rows_txt[row].ljust(first_col_len, ' ') + '|' + for col in range(0, cells.shape[1]): + tbl_body += format_cell_value_rst(cells[row, col], cell_len, color_scale, link) + '|' + + tbl_body += '\n' + tbl_body += tbl_footer + + return tbl_header + tbl_body + + +def build_rst_table_header_chunks(first_col_len, cell_len, columns_txt): + """ + Prepare the horizontal and vertical lines in the RST headers. + + @param first_col_len :: length (in characters) of the first column + @param cell_len :: length of all other cells + """ + tbl_header_top = '+' + tbl_header_text = '|' + tbl_header_bottom = '+' + + # First column in the header for the name of the test or statistics + tbl_header_top += '-'.ljust(first_col_len, '-') + '+' + tbl_header_text += ' '.ljust(first_col_len, ' ') + '|' + tbl_header_bottom += '='.ljust(first_col_len, '=') + '+' + for col_name in columns_txt: + tbl_header_top += '-'.ljust(cell_len, '-') + '+' + tbl_header_text += col_name.ljust(cell_len, ' ') + '|' + tbl_header_bottom += '='.ljust(cell_len, '=') + '+' + + return tbl_header_top, tbl_header_text, tbl_header_bottom + + +def calc_first_col_len(cell_len, rows_txt): + first_col_len = cell_len + for row_name in rows_txt: + name_len = len(row_name) + if name_len > first_col_len: + first_col_len = name_len + + return first_col_len + + +def build_items_links(comparison_type, comparison_dim, using_errors): + """ + Figure out the links from rst table cells to other pages/sections of pages. + + @param comparison_type :: whether this is a 'summary', or a full 'accuracy', or 'runtime' table. + @param comparison_dim :: dimension (accuracy / runtime) + @param using_errors :: whether using observational errors in cost functions + + @returns :: link or links to use from table cells. + """ + if 'summary' == comparison_type: + items_link = ['Minimizers_{0}_comparison_in_terms_of_{1}_nist_lower'. + format(weighted_suffix_string(using_errors), comparison_dim), + 'Minimizers_{0}_comparison_in_terms_of_{1}_nist_average'. + format(weighted_suffix_string(using_errors), comparison_dim), + 'Minimizers_{0}_comparison_in_terms_of_{1}_nist_higher'. + format(weighted_suffix_string(using_errors), comparison_dim), + 'Minimizers_{0}_comparison_in_terms_of_{1}_cutest'. + format(weighted_suffix_string(using_errors), comparison_dim), + 'Minimizers_{0}_comparison_in_terms_of_{1}_neutron_data'. + format(weighted_suffix_string(using_errors), comparison_dim), + ] + elif 'accuracy' == comparison_type or 'runtime' == comparison_type: + if using_errors: + items_link = 'FittingMinimizersComparisonDetailedWithWeights' + else: + items_link = 'FittingMinimizersComparisonDetailed' + else: + items_link = '' + + return items_link + + +def format_cell_value_rst(value, width, color_scale=None, items_link=None): + """ + Build the content string for a table cell, adding style/color tags + if required. + + """ + if not color_scale: + if not items_link: + value_text = ' {0:.4g}'.format(value).ljust(width, ' ') + else: + value_text = ' :ref:`{0:.4g} <{1}>`'.format(value, items_link).ljust(width, ' ') + else: + color = '' + for color_descr in color_scale: + if value <= color_descr[0]: + color = color_descr[1] + break + if not color: + color = color_scale[-1][1] + value_text = " :{0}:`{1:.4g}`".format(color, value).ljust(width, ' ') + + return value_text + + +def print_tables_simple_text(minimizers, results_per_test, accuracy_tbl, time_tbl, norm_acc_rankings): + """ + Produces tables in plain ascii, without any markup. This is much + easier to read than RST and useful when developing or just + checking the output of the runs from the system test logs. + + """ + + header = " ============= Comparison of sum of square errors: ===============\n" + header += " =================================================================\n" + header += "\n\n" + + for minimiz in minimizers: + header += " {0} |".format(minimiz) + header += "\n" + print(header) + + min_sum_err_sq = np.amin(accuracy_tbl, 1) + num_tests = len(results_per_test) + results_text = '' + for test_idx in range(0, num_tests): + results_text += "{0}\t".format(results_per_test[test_idx][0].problem.name) + for minimiz_idx, minimiz in enumerate(minimizers): + # 'e' format is easier to read in raw text output than 'g' + results_text += (" {0:.10g}". + format(results_per_test[test_idx][minimiz_idx].sum_err_sq / + min_sum_err_sq[test_idx])) + results_text += "\n" + + # If some of the fits fail badly, they'll produce 'nan' values => + # 'nan' errors. Requires np.nanmedian() and the like nan-safe + # functions. + + # summary lines + results_text += '---------------- Summary (accuracy): -------- \n' + results_text += 'Best ranking: {0}\n'.format(np.nanmin(norm_acc_rankings, 0)) + results_text += 'Worst ranking: {0}\n'.format(np.nanmax(norm_acc_rankings, 0)) + results_text += 'Mean: {0}\n'.format(stats.nanmean(norm_acc_rankings, 0)) + results_text += 'Median: {0}\n'.format(stats.nanmedian(norm_acc_rankings, 0)) + results_text += '\n' + + print(results_text) + + print(" ======== Time: =======") + time_text = '' + for test_idx in range(0, num_tests): + time_text += "{0}\t".format(results_per_test[test_idx][0].problem.name) + for minimiz_idx, minimiz in enumerate(minimizers): + time_text += " {0}".format(results_per_test[test_idx][minimiz_idx].runtime) + time_text += "\n" + + min_runtime = np.amin(time_tbl, 1) + norm_runtimes = time_tbl / min_runtime[:, None] + time_text += '---------------- Summary (run time): -------- \n' + time_text += 'Best ranking: {0}\n'.format(np.nanmin(norm_runtimes, 0)) + time_text += 'Worst ranking: {0}\n'.format(np.nanmax(norm_runtimes, 0)) + time_text += 'Mean: {0}\n'.format(stats.nanmean(norm_runtimes, 0)) + time_text += 'Median: {0}\n'.format(stats.nanmedian(norm_runtimes, 0)) + time_text += '\n' + + print(time_text) diff --git a/scripts/CompareFitMinimizers/test_problem.py b/scripts/CompareFitMinimizers/test_problem.py new file mode 100644 index 0000000000000000000000000000000000000000..5f8f80854b625bf736b42f837aae07e557804640 --- /dev/null +++ b/scripts/CompareFitMinimizers/test_problem.py @@ -0,0 +1,43 @@ +# Copyright © 2016 ISIS Rutherford Appleton Laboratory, NScD +# Oak Ridge National Laboratory & European Spallation Source +# +# This file is part of Mantid. +# Mantid is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# Mantid is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# File change history is stored at: <https://github.com/mantidproject/mantid>. +# Code Documentation is available at: <http://doxygen.mantidproject.org> + + +class FittingTestProblem(object): + """ + Definition of a fitting test problem, normally loaded from a problem definition file. + """ + def __init__(self): + self.name = None + # If there is an online/documentation link describing this problem + self.linked_name = None + self.equation = None + self.start_x = None + self.end_x = None + # can be for example the list of starting values from NIST test problems + self.starting_values = None + # The Mantid X + self.data_pattern_in = None + # The Mantid Y + self.data_pattern_out = None + # The Mantid E + self.data_pattern_obs_errors = None + # The 'certified' or reference sum of squares, if provided (for example + # in NIST tests). + self.ref_residual_sum_sq = None diff --git a/scripts/CompareFitMinimizers/test_result.py b/scripts/CompareFitMinimizers/test_result.py new file mode 100644 index 0000000000000000000000000000000000000000..ed4d663e957c5d031a01edee5738187ea4f25f36 --- /dev/null +++ b/scripts/CompareFitMinimizers/test_result.py @@ -0,0 +1,37 @@ +# Copyright © 2016 ISIS Rutherford Appleton Laboratory, NScD +# Oak Ridge National Laboratory & European Spallation Source +# +# This file is part of Mantid. +# Mantid is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# Mantid is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# File change history is stored at: <https://github.com/mantidproject/mantid>. +# Code Documentation is available at: <http://doxygen.mantidproject.org> + + +class FittingTestResult(object): + """ + Minimal definition of a class to hold results from a fitting problem test. + """ + + def __init__(self): + self.problem = None + self.fit_status = None + self.fit_chi2 = None + # Workspace with data to fit + self.fit_wks = None + self.params = None + self.errors = None + self.sum_err_sq = None + # Time it took to run the Fit algorithm + self.runtime = None diff --git a/scripts/Engineering/EnggUtils.py b/scripts/Engineering/EnggUtils.py index 6514f44832d1e0dd2de7a0549422b421d87a34db..a4f0070d8b31cc84122e75035b16a13464691af5 100644 --- a/scripts/Engineering/EnggUtils.py +++ b/scripts/Engineering/EnggUtils.py @@ -343,6 +343,7 @@ def sumSpectra(parent, ws): """ alg = parent.createChildAlgorithm('SumSpectra') alg.setProperty('InputWorkspace', ws) + alg.setProperty('RemoveSpecialValues', True) alg.execute() return alg.getProperty('OutputWorkspace').value diff --git a/scripts/HFIR_4Circle_Reduction/MainWindow.ui b/scripts/HFIR_4Circle_Reduction/MainWindow.ui index 31133931c488a937fe7ba71c7964d8c05a8ce03e..3f4c6aa6b59885cb43f09566a4c33eff1fbb64e2 100644 --- a/scripts/HFIR_4Circle_Reduction/MainWindow.ui +++ b/scripts/HFIR_4Circle_Reduction/MainWindow.ui @@ -637,7 +637,7 @@ p, li { white-space: pre-wrap; } <string>Instrument Calibration</string> </property> <layout class="QGridLayout" name="gridLayout_16"> - <item row="0" column="7"> + <item row="0" column="11"> <spacer name="horizontalSpacer_26"> <property name="orientation"> <enum>Qt::Horizontal</enum> @@ -650,7 +650,7 @@ p, li { white-space: pre-wrap; } </property> </spacer> </item> - <item row="1" column="7"> + <item row="1" column="11"> <spacer name="horizontalSpacer_16"> <property name="orientation"> <enum>Qt::Horizontal</enum> @@ -664,7 +664,7 @@ p, li { white-space: pre-wrap; } </spacer> </item> <item row="0" column="1"> - <widget class="QLineEdit" name="lineEdit"> + <widget class="QLineEdit" name="lineEdit_defaultSampleDetDistance"> <property name="enabled"> <bool>false</bool> </property> @@ -689,7 +689,7 @@ p, li { white-space: pre-wrap; } <item row="1" column="2"> <widget class="QPushButton" name="pushButton_applyCalibratedSampleDistance"> <property name="enabled"> - <bool>false</bool> + <bool>true</bool> </property> <property name="text"> <string>Apply</string> @@ -706,13 +706,6 @@ p, li { white-space: pre-wrap; } </property> </widget> </item> - <item row="0" column="4"> - <widget class="QLabel" name="label_36"> - <property name="text"> - <string>Wavelength</string> - </property> - </widget> - </item> <item row="0" column="3"> <spacer name="horizontalSpacer_29"> <property name="orientation"> @@ -732,31 +725,21 @@ p, li { white-space: pre-wrap; } <item row="0" column="0"> <widget class="QLabel" name="label_33"> <property name="text"> - <string>Standard Detector Sample Distance</string> - </property> - </widget> - </item> - <item row="0" column="5"> - <widget class="QLineEdit" name="lineEdit_userWaveLength"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> + <string>Default Detector Sample Distance</string> </property> </widget> </item> - <item row="0" column="6"> - <widget class="QPushButton" name="pushButton_applyUserWavelength"> + <item row="0" column="8"> + <widget class="QLabel" name="label_36"> <property name="text"> - <string>Apply</string> + <string>Wavelength</string> </property> </widget> </item> <item row="1" column="4"> <widget class="QLabel" name="label_10"> <property name="text"> - <string>Detector Center</string> + <string>Calibrated Detector Center</string> </property> </widget> </item> @@ -770,6 +753,15 @@ p, li { white-space: pre-wrap; } <verstretch>0</verstretch> </sizepolicy> </property> + <property name="maximumSize"> + <size> + <width>100</width> + <height>16777215</height> + </size> + </property> + <property name="toolTip"> + <string><html><head/><body><p><span style=" font-weight:600;">ROW NUMBER</span> of User-specified detector center</p></body></html></string> + </property> </widget> </item> <item> @@ -780,6 +772,15 @@ p, li { white-space: pre-wrap; } <verstretch>0</verstretch> </sizepolicy> </property> + <property name="maximumSize"> + <size> + <width>100</width> + <height>16777215</height> + </size> + </property> + <property name="toolTip"> + <string><html><head/><body><p><span style=" font-weight:600;">COLUMN NUMBER</span> of User-specified detector center</p></body></html></string> + </property> </widget> </item> </layout> @@ -787,13 +788,66 @@ p, li { white-space: pre-wrap; } <item row="1" column="6"> <widget class="QPushButton" name="pushButton_applyUserDetCenter"> <property name="enabled"> - <bool>false</bool> + <bool>true</bool> </property> <property name="text"> <string>Apply</string> </property> </widget> </item> + <item row="0" column="4"> + <widget class="QLabel" name="label_19"> + <property name="text"> + <string>Default Detector Center</string> + </property> + </widget> + </item> + <item row="0" column="10"> + <widget class="QPushButton" name="pushButton_applyUserWavelength"> + <property name="text"> + <string>Apply</string> + </property> + </widget> + </item> + <item row="0" column="7"> + <spacer name="horizontalSpacer_34"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Preferred</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item row="0" column="9"> + <widget class="QLineEdit" name="lineEdit_userWaveLength"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string/> + </property> + </widget> + </item> + <item row="0" column="5"> + <widget class="QLineEdit" name="lineEdit_defaultDetCenter"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>115, 128</string> + </property> + </widget> + </item> </layout> </widget> </item> @@ -4479,6 +4533,22 @@ p, li { white-space: pre-wrap; } <string>Advanced Setup</string> </attribute> <layout class="QGridLayout" name="gridLayout_27"> + <item row="0" column="2"> + <spacer name="horizontalSpacer_25"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::MinimumExpanding</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> <item row="0" column="0"> <widget class="QGroupBox" name="groupBox_16"> <property name="title"> @@ -4495,7 +4565,7 @@ p, li { white-space: pre-wrap; } <item row="4" column="3"> <widget class="QLabel" name="label_last3Path"> <property name="sizePolicy"> - <sizepolicy hsizetype="Expanding" vsizetype="Preferred"> + <sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred"> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> @@ -4543,11 +4613,17 @@ p, li { white-space: pre-wrap; } <item row="1" column="3"> <widget class="QLabel" name="label_last1Path"> <property name="sizePolicy"> - <sizepolicy hsizetype="Expanding" vsizetype="Preferred"> + <sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred"> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> + <property name="minimumSize"> + <size> + <width>200</width> + <height>0</height> + </size> + </property> <property name="text"> <string>EMPTY</string> </property> @@ -4556,7 +4632,7 @@ p, li { white-space: pre-wrap; } <item row="2" column="3"> <widget class="QLabel" name="label_last2Path"> <property name="sizePolicy"> - <sizepolicy hsizetype="Expanding" vsizetype="Preferred"> + <sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred"> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> @@ -4599,7 +4675,7 @@ p, li { white-space: pre-wrap; } </layout> </widget> </item> - <item row="1" column="0"> + <item row="2" column="0"> <spacer name="verticalSpacer_25"> <property name="orientation"> <enum>Qt::Vertical</enum> @@ -4615,13 +4691,13 @@ p, li { white-space: pre-wrap; } </property> </spacer> </item> - <item row="0" column="1"> - <spacer name="horizontalSpacer_25"> + <item row="1" column="2"> + <spacer name="horizontalSpacer_35"> <property name="orientation"> <enum>Qt::Horizontal</enum> </property> <property name="sizeType"> - <enum>QSizePolicy::Expanding</enum> + <enum>QSizePolicy::MinimumExpanding</enum> </property> <property name="sizeHint" stdset="0"> <size> @@ -4631,6 +4707,117 @@ p, li { white-space: pre-wrap; } </property> </spacer> </item> + <item row="1" column="0"> + <widget class="QGroupBox" name="groupBox_23"> + <property name="title"> + <string>Constants</string> + </property> + <layout class="QGridLayout" name="gridLayout_6"> + <item row="2" column="2"> + <widget class="QLineEdit" name="lineEdit_pixelSizeX"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>0.0001984375</string> + </property> + </widget> + </item> + <item row="2" column="0"> + <widget class="QLabel" name="label_21"> + <property name="text"> + <string>Pixel Size</string> + </property> + </widget> + </item> + <item row="1" column="0"> + <widget class="QLabel" name="label_20"> + <property name="text"> + <string>Sample-detector Distance Tolerance</string> + </property> + </widget> + </item> + <item row="1" column="2"> + <widget class="QLineEdit" name="lineEdit_sampleDetDistTol"> + <property name="sizePolicy"> + <sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="maximumSize"> + <size> + <width>10000</width> + <height>16777215</height> + </size> + </property> + <property name="text"> + <string>0.2</string> + </property> + </widget> + </item> + <item row="1" column="1"> + <spacer name="horizontalSpacer_36"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Preferred</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item row="2" column="3"> + <widget class="QLineEdit" name="lineEdit_pixelSizeY"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>0.0001984375</string> + </property> + </widget> + </item> + <item row="0" column="2"> + <widget class="QLineEdit" name="lineEdit_numPixelRow"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>256</string> + </property> + </widget> + </item> + <item row="0" column="3"> + <widget class="QLineEdit" name="lineEdit_numPixelColumn"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>256</string> + </property> + </widget> + </item> + <item row="0" column="0"> + <widget class="QLabel" name="label_22"> + <property name="text"> + <string>Detector Pixel Size</string> + </property> + </widget> + </item> + </layout> + </widget> + </item> </layout> </widget> </widget> diff --git a/scripts/HFIR_4Circle_Reduction/NTableWidget.py b/scripts/HFIR_4Circle_Reduction/NTableWidget.py index 13fe655c7bad77eff1ab34a1e382e32fd838796b..e8ffda0c330e0a777e2784aa40da0dbca955ec60 100644 --- a/scripts/HFIR_4Circle_Reduction/NTableWidget.py +++ b/scripts/HFIR_4Circle_Reduction/NTableWidget.py @@ -419,7 +419,6 @@ class NTableWidget(QtGui.QTableWidget): self.remove_all_rows() # add rows back - print '[DB-BAT] Sort by column %d. Keys = ' % column_index, key_list, 'sort_order = ', sort_order for key_value in key_list: self.append_row(row_content_dict[key_value]) # END-FOR diff --git a/scripts/HFIR_4Circle_Reduction/absorption.py b/scripts/HFIR_4Circle_Reduction/absorption.py index a8bf6f3201af90ae2d47fc953699abe12b4891cd..78c87c9b36853cbfc937aa56cf8b7c405123b190 100644 --- a/scripts/HFIR_4Circle_Reduction/absorption.py +++ b/scripts/HFIR_4Circle_Reduction/absorption.py @@ -273,8 +273,6 @@ def calculate_b_matrix(lattice): b_matrix[2, 1] = 0 b_matrix[2, 2] = 1 / lattice.get_c() - # print '[DB...TEST] B matrix: determination = ', numpy.linalg.det(b_matrix), '\n', b_matrix - return b_matrix @@ -286,8 +284,6 @@ def calculate_upphi(omg0, theta2ave, chiave, phiave): up_phi[1] = m_sin(theta2ave*0.5+omg0)*m_cos(chiave)*m_sin(phiave)-m_cos(theta2ave*0.5+omg0)*m_cos(phiave) up_phi[2] = m_sin(theta2ave*0.5+omg0)*m_sin(chiave) - print '[DB...TEST] UP PHI = ', up_phi, '|UP PHI| = ', numpy.dot(up_phi, up_phi) - return up_phi @@ -299,8 +295,6 @@ def calculate_usphi(omg0, theta2ave, chiave, phiave): us_phi[1] = m_sin(theta2ave*0.5-omg0)*m_cos(chiave)*m_sin(phiave)+m_cos(theta2ave*0.5-omg0)*m_cos(phiave) us_phi[2] = m_sin(theta2ave*0.5-omg0)*m_sin(chiave) - print '[DB...TEST] US PHI = ', us_phi, '|US PHI| = ', numpy.dot(us_phi, us_phi) - return us_phi @@ -316,9 +310,6 @@ def calculate_absorption_correction_spice(exp_number, scan_number, lattice, ub_m phiave = get_average_spice_table(exp_number, scan_number, 'phi') # sum(phi(:))/length(phi); omg0 = theta2ave * 0.5 - print '[DB...TEST] Exp = %d Scan = %d:\n2theta = %f, chi = %f, phi = %f, omega = %f' \ - '' % (exp_number, scan_number, theta2ave, chiave, phiave, omg0) - upphi = calculate_upphi(omg0, theta2ave, chiave, phiave) usphi = calculate_usphi(omg0, theta2ave, chiave, phiave) @@ -421,9 +412,6 @@ def calculate_absorption_correction_2(exp_number, scan_number, spice_ub_matrix): phiave = get_average_spice_table(exp_number, scan_number, 'phi') # sum(phi(:))/length(phi); avg_omega = get_average_omega(exp_number, scan_number) - print '[DB...TEST] Exp = %d Scan = %d:\n2theta = %f, chi = %f, phi = %f, omega = %s' % ( - exp_number, scan_number, theta2ave, chiave, phiave, str(avg_omega)) - up_phi = calculate_upphi(avg_omega, theta2ave, chiave, phiave) us_phi = calculate_usphi(avg_omega, theta2ave, chiave, phiave) diff --git a/scripts/HFIR_4Circle_Reduction/fourcircle_utility.py b/scripts/HFIR_4Circle_Reduction/fourcircle_utility.py index 9e90b25bf88760bae3d7f9098d1335547f32a462..32a8c46649cb4b8b9520316aedae1b917f8ab2c5 100644 --- a/scripts/HFIR_4Circle_Reduction/fourcircle_utility.py +++ b/scripts/HFIR_4Circle_Reduction/fourcircle_utility.py @@ -660,8 +660,6 @@ def round_hkl_1(hkl): :param hkl: :return: """ - print type(hkl) - mi_h = round(hkl[0]) mi_k = round(hkl[1]) mi_l = round(hkl[2]) diff --git a/scripts/HFIR_4Circle_Reduction/fputility.py b/scripts/HFIR_4Circle_Reduction/fputility.py index 86e6ead192465a9cdabecd305d647166808ec7cc..e893e95e190d50d7d1dbdf2ea2acdc533f200951 100644 --- a/scripts/HFIR_4Circle_Reduction/fputility.py +++ b/scripts/HFIR_4Circle_Reduction/fputility.py @@ -197,8 +197,6 @@ def write_scd_fullprof_kvector(user_header, wave_length, k_vector_dict, peak_dic # END-IF # peak intensities - print '[DB...BAT] Number of peaks to output: ', len(peak_dict_list) - for i_peak, peak_dict in enumerate(peak_dict_list): # check assert isinstance(peak_dict, dict), '%d-th peak must be a dictionary but not %s.' % (i_peak, diff --git a/scripts/HFIR_4Circle_Reduction/guiutility.py b/scripts/HFIR_4Circle_Reduction/guiutility.py index 55371451d3db810cfe7e2bdc09582e7751d2bac0..3c7dea5d4b332044c74c543439eadc036b81806f 100644 --- a/scripts/HFIR_4Circle_Reduction/guiutility.py +++ b/scripts/HFIR_4Circle_Reduction/guiutility.py @@ -424,7 +424,7 @@ def show_message(parent=None, message='show message here!'): show message :param parent: :param message: - :return: + :return: True for accepting. False for rejecting or cancelling """ dialog = DisplayDialog(parent) dialog.show_message(message) diff --git a/scripts/HFIR_4Circle_Reduction/hfctables.py b/scripts/HFIR_4Circle_Reduction/hfctables.py index 36f01147e3e28197a5270f52151cc3326334d97e..4269976ed3b050608d85c7fa7908e6444c4dd3de 100644 --- a/scripts/HFIR_4Circle_Reduction/hfctables.py +++ b/scripts/HFIR_4Circle_Reduction/hfctables.py @@ -1087,11 +1087,9 @@ class ScanSurveyTable(tableBase.NTableWidget): # check with filters: original order is counts, scan, Pt., ... scan_number = sum_item[1] if scan_number < start_scan or scan_number > end_scan: - # print 'Scan %d is out of range.' % scan_number continue counts = sum_item[0] if counts < min_counts or counts > max_counts: - # print 'Scan %d Counts %f is out of range.' % (scan_number, counts) continue # modify for appending to table diff --git a/scripts/HFIR_4Circle_Reduction/mplgraphicsview.py b/scripts/HFIR_4Circle_Reduction/mplgraphicsview.py index cbdcd45faa357e3accccffbbbe3443c29faee552..83115051cad2cfe50bfaa7b031a88466ee7ff105 100644 --- a/scripts/HFIR_4Circle_Reduction/mplgraphicsview.py +++ b/scripts/HFIR_4Circle_Reduction/mplgraphicsview.py @@ -197,8 +197,6 @@ class IndicatorManager(object): for line_key in self._lineManager.keys(): - print '[MplGraph DB] Exam indicator key %s' % str(self._lineManager[line_key]) - if x is not None and y is not None: # 2 way raise NotImplementedError('ASAP') @@ -222,7 +220,6 @@ class IndicatorManager(object): :return: """ if line_id is not None: - print '[DB] Get line style. ID = %s' % str(line_id) style = '--' else: style = '--' @@ -306,8 +303,6 @@ class IndicatorManager(object): :param dy: :return: """ - # print self._lineManager[my_id][0] - if self._indicatorTypeDict[my_id] == 0: # horizontal self._lineManager[my_id][1] += dy @@ -797,7 +792,6 @@ class MplGraphicsView(QtGui.QWidget): # process marker if it has information if marker.count(' (') > 0: marker = marker.split(' (')[0] - # print "[DB] Print line %d: marker = %s, color = %s" % (self._myLineMarkerColorIndex, marker, color) # update the index self._myLineMarkerColorIndex += 1 @@ -973,7 +967,6 @@ class Qt4MplCanvas(FigureCanvas): """ if self.axes2 is None: self.axes2 = self.axes.twinx() - # print self.par1, type(self.par1) # Hold previous data self.axes2.hold(True) @@ -1303,9 +1296,6 @@ class Qt4MplCanvas(FigureCanvas): handles, labels = self.axes.get_legend_handles_labels() self.axes.legend(handles, labels, loc=location) - # print handles - # print labels - #self.axes.legend(self._myLegendHandlers, self._myLegentLabels) return diff --git a/scripts/HFIR_4Circle_Reduction/mplgraphicsview3d.py b/scripts/HFIR_4Circle_Reduction/mplgraphicsview3d.py index 6d8f0af9cd4c4bcb97112071dd8629a991f37e99..da1b11b1872f77403bf9f25f08c06b7a7a9e7b87 100644 --- a/scripts/HFIR_4Circle_Reduction/mplgraphicsview3d.py +++ b/scripts/HFIR_4Circle_Reduction/mplgraphicsview3d.py @@ -53,7 +53,6 @@ class MplPlot3dCanvas(FigureCanvas): Clear all the figures from canvas :return: """ - print '[DB-INFO] There are %d plots in current plot list.' % len(self._currPlotList) for plt in self._currPlotList: # del plt self._myAxes.collections.remove(plt) diff --git a/scripts/HFIR_4Circle_Reduction/multi_threads_helpers.py b/scripts/HFIR_4Circle_Reduction/multi_threads_helpers.py index 70bb3b8a311b78017d32e2931f8e63b13de357c9..7bc322f9e753afe495ab9c611587a7018b788509 100644 --- a/scripts/HFIR_4Circle_Reduction/multi_threads_helpers.py +++ b/scripts/HFIR_4Circle_Reduction/multi_threads_helpers.py @@ -178,12 +178,8 @@ class IntegratePeaksThread(QThread): assert isinstance(scan_tup, tuple) and len(scan_tup) == 3 scan_number, pt_number_list, merged = scan_tup - print '[DB...BAT] IntegratePeakThread: Scan %d' % scan_number - # emit signal for run start (mode 0) mode = int(0) - print '[DB...BAT] IntegratePeakThread: Sent out signal (1): %d, %d, %f' % (self._expNumber, scan_number, - float(index)) self.peakMergeSignal.emit(self._expNumber, scan_number, float(index), [0., 0., 0.], mode) # merge if not merged @@ -214,7 +210,7 @@ class IntegratePeaksThread(QThread): # self._mainWindow.ui.tableWidget_mergeScans.set_status(scan_number, 'Merged') else: # merged - print '[DB...BAT] Scan %s is merged (in thread)!' % scan_number + pass # END-IF # calculate peak center @@ -245,9 +241,6 @@ class IntegratePeaksThread(QThread): self._selectedMaskName) # integrate peak - print '[DB...BAD] Normalization: %s; Use Mask = %s, Mask Workspace = %s.' % ( - self._normalizeType, str(self._maskDetector), self._selectedMaskName - ) try: status, ret_obj = self._mainWindow.controller.integrate_scan_peaks(exp=self._expNumber, scan=scan_number, @@ -258,9 +251,8 @@ class IntegratePeaksThread(QThread): normalization=self._normalizeType, mask_ws_name=self._selectedMaskName) except ValueError as val_err: - print '[DB] Unable to integrate scan %d due to %s.' % (scan_number, str(val_err)) status = False - ret_obj = '%s.' % str(val_err) + ret_obj = 'Unable to integrate scan {0} due to {1}.'.format(scan_number, str(val_err)) # handle integration error if status: @@ -284,8 +276,6 @@ class IntegratePeaksThread(QThread): mode = 1 # center_i self.peakMergeSignal.emit(self._expNumber, scan_number, float(intensity_i), list(peak_centre), mode) - print '[DB...BAT] IntegratePeakThread: Sent out signal (2): %d, %d, %f' % (self._expNumber, scan_number, - float(intensity_i)) # END-FOR # terminate the process diff --git a/scripts/HFIR_4Circle_Reduction/peakprocesshelper.py b/scripts/HFIR_4Circle_Reduction/peakprocesshelper.py index af2e7ab1c536edb78aa8404f67eff5b3e0316bc3..8af4c2f98cd67567c65b6e9a8d1879f5400a09d7 100644 --- a/scripts/HFIR_4Circle_Reduction/peakprocesshelper.py +++ b/scripts/HFIR_4Circle_Reduction/peakprocesshelper.py @@ -293,8 +293,6 @@ class PeakProcessRecord(object): """ assert isinstance(pt_intensity_dict, dict) - print '[DB...BAT] Pt intensity dict keys: ', pt_intensity_dict.keys() - self._ptIntensityDict = pt_intensity_dict return diff --git a/scripts/HFIR_4Circle_Reduction/project_manager.py b/scripts/HFIR_4Circle_Reduction/project_manager.py index 38f1dcd15dda3bf67237817a9283e80b372c89f0..0d2463d4ed5d5a709458d7e20b4d1d7e8f742f72 100644 --- a/scripts/HFIR_4Circle_Reduction/project_manager.py +++ b/scripts/HFIR_4Circle_Reduction/project_manager.py @@ -73,12 +73,15 @@ class ProjectManager(object): :param overwrite: if specified, then any existing files with same name will be rewritten :return: """ + # create workspace directory self.create_workspace_directory() + print '[INFO] Saving {0} MDEventWorkspaces to {1}.'.format(len(self._wsList), self._wsDir) + # save MDs for ws_name in self._wsList: md_file_name = os.path.join(self._wsDir, ws_name + '.nxs') - if overwrite or os.path.exists(md_file_name): + if overwrite or not os.path.exists(md_file_name): mantidsimple.SaveMD(InputWorkspace=ws_name, Filename=md_file_name) with open(self._projectPath, 'w') as pickle_file: diff --git a/scripts/HFIR_4Circle_Reduction/reduce4circleControl.py b/scripts/HFIR_4Circle_Reduction/reduce4circleControl.py index 2cc1b0dc377c77a6da691730385343c9de0c2849..f3c4afd44e3514186432b1160048e7e785205d97 100644 --- a/scripts/HFIR_4Circle_Reduction/reduce4circleControl.py +++ b/scripts/HFIR_4Circle_Reduction/reduce4circleControl.py @@ -56,6 +56,16 @@ class CWSCDReductionControl(object): # Some set up self._expNumber = None + # instrument default constants + self._defaultDetectorSampleDistance = None + # geometry of pixel + self._defaultPixelSizeX = None + self._defaultPixelSizeY = None + # user-defined wave length + self._userWavelengthDict = dict() + # default peak center + self._defaultDetectorCenter = None + # Container for MDEventWorkspace for each Pt. self._myMDWsList = list() # Container for loaded workspaces @@ -92,6 +102,8 @@ class CWSCDReductionControl(object): # A dictionary to manage all loaded and processed MDEventWorkspaces # self._expDataDict = {} + self._detSampleDistanceDict = dict() + self._detCenterDict = dict() # register startup mantid.UsageService.registerFeatureUsage("Interface","4-Circle Reduction",False) @@ -182,57 +194,9 @@ class CWSCDReductionControl(object): sin_theta = q * wavelength/(4*math.pi) theta = math.asin(sin_theta) corrected_intensity = peak_intensity * math.sin(2*theta) * step_omega - print '[DB] Lorentz correction: I * sin(2*theta) * delta(omega) = %.5f * sin(2*%.5f) * %.5f =' \ - ' %.5f; q = %.5f.' % (peak_intensity, theta*180/math.pi, step_omega, corrected_intensity, q) return corrected_intensity - # def calculate_peak_center(self, exp_number, scan_number, pt_numbers=None): - # """ - # Calculate center of peak by weighting the peak centers of multiple Pt (slice from 3D peak) - # :param exp_number: - # :param scan_number: - # :param pt_numbers: - # :return: 2-tuple: boolean, peak center (3-tuple of float) - # """ - # # Check & set pt. numbers - # assert isinstance(exp_number, int), 'Experiment number %s must be an integer but not %s.' \ - # '' % (str(exp_number), str(type(exp_number))) - # assert isinstance(scan_number, int), 'Scan number %s must be an integer but not %s.' \ - # '' % (str(scan_number), str(type(scan_number))) - # if pt_numbers is None: - # status, pt_number_list = self.get_pt_numbers(exp_number, scan_number) - # assert status - # else: - # pt_number_list = pt_numbers - # assert isinstance(pt_number_list, list) and len(pt_number_list) > 0 - # - # # Check whether the MDEventWorkspace used to find peaks exists - # if self.has_merged_data(exp_number, scan_number, pt_number_list): - # pass - # else: - # return False, 'Exp %d Scan %d: data must be merged already.' % (exp_number, scan_number) - # - # # Find peak in Q-space - # merged_ws_name = get_merged_md_name(self._instrumentName, exp_number, scan_number, pt_number_list) - # peak_ws_name = get_peak_ws_name(exp_number, scan_number, pt_number_list) - # mantidsimple.FindPeaksMD(InputWorkspace=merged_ws_name, - # MaxPeaks=10, - # PeakDistanceThreshold=5., - # DensityThresholdFactor=0.1, - # OutputWorkspace=peak_ws_name) - # assert AnalysisDataService.doesExist(peak_ws_name), 'Output PeaksWorkspace %s cannot be found.' \ - # '' % peak_ws_name - # - # # calculate the peaks with weight - # process_record = PeakProcessRecord(exp_number, scan_number, peak_ws_name) - # process_record.calculate_peak_center() - # peak_center = process_record.get_peak_centre() - # # set the merged peak information to data structure - # self._myPeakInfoDict[(exp_number, scan_number)] = process_record - # - # return True, peak_center - def find_peak(self, exp_number, scan_number, pt_number_list=None): """ Find 1 peak in sample Q space for UB matrix :param exp_number: @@ -501,7 +465,11 @@ class CWSCDReductionControl(object): if pt_number is None: # no pt number, then check SPICE file spice_file_name = get_spice_file_name(self._instrumentName, exp_number, scan_number) - file_name = os.path.join(self._dataDir, spice_file_name) + try: + file_name = os.path.join(self._dataDir, spice_file_name) + except AttributeError: + raise AttributeError('Unable to create SPICE file name from directory %s and file name %s.' + '' % (self._dataDir, spice_file_name)) else: # pt number given, then check xml_file_name = get_det_xml_file_name(self._instrumentName, exp_number, scan_number, @@ -548,14 +516,18 @@ class CWSCDReductionControl(object): return self._myUBMatrixDict[exp_number] - @staticmethod - def get_wave_length(exp_number, scan_number_list): + def get_wave_length(self, exp_number, scan_number_list): """ Get the wavelength. Exception: RuntimeError if there are more than 1 wavelength found with all given scan numbers + :param exp_number: :param scan_number_list: :return: """ + # check whether there is use wave length + if exp_number in self._userWavelengthDict: + return self._userWavelengthDict[exp_number] + # get the SPICE workspace wave_length_set = set() @@ -656,7 +628,6 @@ class CWSCDReductionControl(object): # get ub matrix ub_matrix = self.get_ub_matrix(exp_number) - print '[DB...BAT] UB matrix is of type ', type(ub_matrix) for scan_number in scan_number_list: peak_dict = dict() @@ -782,7 +753,7 @@ class CWSCDReductionControl(object): array2d = numpy.ndarray(shape=(DET_X_SIZE, DET_Y_SIZE), dtype='float') for i in xrange(DET_X_SIZE): for j in xrange(DET_Y_SIZE): - array2d[i][j] = raw_ws.readY(i * DET_X_SIZE + j)[0] + array2d[i][j] = raw_ws.readY(j * DET_X_SIZE + i)[0] # Flip the 2D array to look detector from sample array2d = numpy.flipud(array2d) @@ -1305,7 +1276,7 @@ class CWSCDReductionControl(object): final_peak_center[i] = sum_peak_center[i] * (1./sum_bin_counts) #final_peak_center = sum_peak_center * (1./sum_bin_counts) - print 'Avg peak center = ', final_peak_center, 'Total counts = ', sum_bin_counts + print '[INFO] Avg peak center = ', final_peak_center, 'Total counts = ', sum_bin_counts # Integrate peaks total_intensity = 0. @@ -1434,7 +1405,6 @@ class CWSCDReductionControl(object): # Default for exp_no if exp_no is None: exp_no = self._expNumber - print '[DB...BAD] Load Spice Scan File Exp Number = %d, Stored Exp. Number = %d' % (exp_no, self._expNumber) # Check whether the workspace has been loaded assert isinstance(exp_no, int) @@ -1675,6 +1645,9 @@ class CWSCDReductionControl(object): # - construct a configuration with 1 scan and multiple Pts. scan_info_table_name = get_merge_pt_info_ws_name(exp_no, scan_no) try: + # collect HB3A exp info only need corrected detector position to build virtual instrument. + # so it is not necessary to specify the detector center now as virtual instrument + # is abandoned due to speed issue. mantidsimple.CollectHB3AExperimentInfo(ExperimentNumber=exp_no, ScanList='%d' % scan_no, PtLists=pt_list_str, @@ -1692,10 +1665,37 @@ class CWSCDReductionControl(object): # create MD workspace in Q-sample try: - mantidsimple.ConvertCWSDExpToMomentum(InputWorkspace=scan_info_table_name, - CreateVirtualInstrument=False, - OutputWorkspace=out_q_name, - Directory=self._dataDir) + # set up the basic algorithm parameters + alg_args = dict() + alg_args['InputWorkspace'] = scan_info_table_name + alg_args['CreateVirtualInstrument'] = False + alg_args['OutputWorkspace'] = out_q_name + alg_args['Directory'] = self._dataDir + + # Add Detector Center and Detector Distance!!! - Trace up how to calculate shifts! + # calculate the sample-detector distance shift if it is defined + if exp_no in self._detSampleDistanceDict: + alg_args['DetectorSampleDistanceShift'] = self._detSampleDistanceDict[exp_no] - \ + self._defaultDetectorSampleDistance + # calculate the shift of detector center + if exp_no in self._detCenterDict: + user_center_row, user_center_col = self._detCenterDict[exp_no] + delta_row = user_center_row - self._defaultDetectorCenter[0] + delta_col = user_center_col - self._defaultDetectorCenter[1] + # use LoadSpiceXML2DDet's unit test as a template + shift_x = float(delta_col) * self._defaultPixelSizeX + shift_y = float(delta_row) * self._defaultPixelSizeY * -1. + # set to argument + alg_args['DetectorCenterXShift'] = shift_x + alg_args['DetectorCenterYShift'] = shift_y + + # set up the user-defined wave length + if exp_no in self._userWavelengthDict: + alg_args['UserDefinedWavelength'] = self._userWavelengthDict[exp_no] + + # call: + mantidsimple.ConvertCWSDExpToMomentum(**alg_args) + self._myMDWsList.append(out_q_name) except RuntimeError as e: err_msg += 'Unable to convert scan %d data to Q-sample MDEvents due to %s' % (scan_no, str(e)) @@ -1777,6 +1777,74 @@ class CWSCDReductionControl(object): return + def set_detector_center(self, exp_number, center_row, center_col, default=False): + """ + Set detector center + :param exp_number: + :param center_row: + :param center_col: + :param default: + :return: + """ + # check + assert isinstance(exp_number, int) and exp_number > 0, 'Experiment number must be integer' + assert center_row is None or (isinstance(center_row, int) and center_row >= 0), \ + 'Center row number must either None or non-negative integer.' + assert center_col is None or (isinstance(center_col, int) and center_col >= 0), \ + 'Center column number must be either Noe or non-negative integer.' + + if default: + self._defaultDetectorCenter = (center_row, center_col) + else: + self._detCenterDict[exp_number] = (center_row, center_col) + + return + + def set_detector_sample_distance(self, exp_number, sample_det_distance): + """ + set instrument's detector - sample distance + :param exp_number: + :param sample_det_distance: + :return: + """ + # check + assert isinstance(exp_number, int) and exp_number > 0, 'Experiment number must be integer' + assert isinstance(sample_det_distance, float) and sample_det_distance > 0, \ + 'Sample - detector distance must be a positive float.' + + # set + self._detSampleDistanceDict[exp_number] = sample_det_distance + + return + + def set_default_detector_sample_distance(self, default_det_sample_distance): + """ + set default detector-sample distance + :param default_det_sample_distance: + :return: + """ + assert isinstance(default_det_sample_distance, float) and default_det_sample_distance > 0,\ + 'Wrong %s' % str(default_det_sample_distance) + + self._defaultDetectorSampleDistance = default_det_sample_distance + + return + + def set_default_pixel_size(self, pixel_x_size, pixel_y_size): + """ + set default pixel size + :param pixel_x_size: + :param pixel_y_size: + :return: + """ + assert isinstance(pixel_x_size, float) and pixel_x_size > 0, 'Pixel size-X %s is bad!' % str(pixel_x_size) + assert isinstance(pixel_y_size, float) and pixel_y_size > 0, 'Pixel size-Y %s is bad!' % str(pixel_y_size) + + self._defaultPixelSizeX = pixel_x_size + self._defaultPixelSizeY = pixel_y_size + + return + def set_server_url(self, server_url, check_link=True): """ Set URL for server to download the data @@ -1847,8 +1915,8 @@ class CWSCDReductionControl(object): except OSError as os_err: return False, str(os_err) - # Check whether the target is writable - if os.access(local_dir, os.W_OK) is False: + # Check whether the target is writable: if and only if the data directory is not from data server + if not local_dir.startswith('/HFIR/HB3A/') and os.access(local_dir, os.W_OK) is False: return False, 'Specified local data directory %s is not writable.' % local_dir # Successful @@ -1874,6 +1942,23 @@ class CWSCDReductionControl(object): # Set up self._myUBMatrixDict[exp_number] = ub_matrix + return + + def set_user_wave_length(self, exp_number, wave_length): + """ + set the user wave length for future operation + :param exp_number: + :param wave_length: + :return: + """ + assert isinstance(exp_number, int) + assert isinstance(wave_length, float) and wave_length > 0, 'Wave length %s must be a positive float but ' \ + 'not %s.' % (str(wave_length), type(wave_length)) + + self._userWavelengthDict[exp_number] = wave_length + + return + def set_working_directory(self, work_dir): """ Set up the directory for working result @@ -2390,9 +2475,8 @@ class CWSCDReductionControl(object): try: mantidsimple.DownloadFile(Address=spice_file_url, Filename=spice_file_name) except RuntimeError as download_error: - print 'Unable to download scan %d from %s due to %s.' % (scan_number, - spice_file_url, - str(download_error)) + print '[ERROR] Unable to download scan %d from %s due to %s.' % (scan_number,spice_file_url, + str(download_error)) break else: spice_file_name = get_spice_file_name(self._instrumentName, exp_number, scan_number) @@ -2460,7 +2544,6 @@ class CWSCDReductionControl(object): q_range, max_tsample]) except RuntimeError as e: - print e return False, None, str(e) except ValueError as e: # Unable to import a SPICE file without necessary information @@ -2468,7 +2551,7 @@ class CWSCDReductionControl(object): # END-FOR (scan_number) if error_message != '': - print 'Error!\n%s' % error_message + print '[Error]\n%s' % error_message self._scanSummaryList = scan_sum_list diff --git a/scripts/HFIR_4Circle_Reduction/reduce4circleGUI.py b/scripts/HFIR_4Circle_Reduction/reduce4circleGUI.py index 57f3b54c0b0b7e077f8053ecdfec712b9953590d..d7769b0f6341425c8216137d0b25f03bc80ddf83 100644 --- a/scripts/HFIR_4Circle_Reduction/reduce4circleGUI.py +++ b/scripts/HFIR_4Circle_Reduction/reduce4circleGUI.py @@ -97,6 +97,12 @@ class MainWindow(QtGui.QMainWindow): self.do_download_spice_data) self.connect(self.ui.comboBox_mode, QtCore.SIGNAL('currentIndexChanged(int)'), self.do_change_data_access_mode) + self.connect(self.ui.pushButton_applyCalibratedSampleDistance, QtCore.SIGNAL('clicked()'), + self.do_set_user_detector_distance) + self.connect(self.ui.pushButton_applyUserDetCenter, QtCore.SIGNAL('clicked()'), + self.do_set_user_detector_center) + self.connect(self.ui.pushButton_applyUserWavelength, QtCore.SIGNAL('clicked()'), + self.do_set_user_wave_length) # Tab 'View Raw Data' self.connect(self.ui.pushButton_setScanInfo, QtCore.SIGNAL('clicked()'), @@ -278,16 +284,6 @@ class MainWindow(QtGui.QMainWindow): self.connect(self.ui.pushButton_loadLastNthProject, QtCore.SIGNAL('clicked()'), self.do_load_nth_project) - # TODO/NOW/ISSUE - Implement - """ - lineEdit_userDetSampleDistance, pushButton_applyCalibratedSampleDistance, - add more to --> lineEdit_infoDetSampleDistance - pushButton_applyUserWavelength: add more to --> lineEdit_infoWavelength - - lineEdit_detCenterPixHorizontal, lineEdit_detCenterPixVertical, - pushButton_applyUserDetCenter, lineEdit_infoDetCenter - """ - # Validator ... (NEXT) # Declaration of class variable @@ -469,8 +465,14 @@ class MainWindow(QtGui.QMainWindow): project_file_name = str(QtGui.QFileDialog.getSaveFileName(self, 'Specify Project File', os.getcwd())) # NEXT ISSUE - consider to allow incremental project saving technique if os.path.exists(project_file_name): - self.pop_one_button_dialog('Project file %s does exist. Choose another name.' % project_file_name) - return + yes = gutil.show_message(self, 'Project file %s does exist. This is supposed to be ' + 'an incremental save.' % project_file_name) + if yes: + print '[INFO] Save project in incremental way.' + else: + print '[INFO] Saving activity is cancelled.' + else: + print '[INFO] Saving current project to %s.' % project_file_name # gather some useful information ui_dict = dict() @@ -510,22 +512,6 @@ class MainWindow(QtGui.QMainWindow): self.load_project(project_file_name) - # # load project - # ui_dict = self._myControl.load_project(project_file_name) - # - # # set the UI parameters to GUI - # try: - # self.ui.lineEdit_localSpiceDir.setText(ui_dict['local spice dir']) - # self.ui.lineEdit_workDir.setText(ui_dict['work dir']) - # self.ui.lineEdit_surveyStartPt.setText(ui_dict['survey start']) - # self.ui.lineEdit_surveyEndPt.setText(ui_dict['survey stop']) - # - # # now try to call some actions - # self.do_apply_setup() - # self.do_set_experiment() - # except KeyError: - # print '[Error] Some field cannot be found.' - return def load_project(self, project_file_name): @@ -588,9 +574,10 @@ class MainWindow(QtGui.QMainWindow): :param QCloseEvent: :return: """ - print '[QCloseEvent=]', str(QCloseEvent) self.menu_quit() + return + def do_accept_ub(self): """ Accept the calculated UB matrix and thus put to controller """ @@ -735,7 +722,9 @@ class MainWindow(QtGui.QMainWindow): data_server = str(self.ui.lineEdit_url.text()).strip() # set to my controller - self._myControl.set_local_data_dir(local_data_dir) + status, err_msg = self._myControl.set_local_data_dir(local_data_dir) + if not status: + raise RuntimeError(err_msg) self._myControl.set_working_directory(working_dir) self._myControl.set_server_url(data_server, check_link=False) @@ -982,7 +971,6 @@ class MainWindow(QtGui.QMainWindow): convert merged workspace in Q-sample frame to HKL frame :return: """ - # TODO/NOW/ - TEST: Convert to HKL # get experiment number exp_number = int(str(self.ui.lineEdit_exp.text())) @@ -1414,8 +1402,6 @@ class MainWindow(QtGui.QMainWindow): if len(row_number_list) == 0: self.pop_one_button_dialog('No scan is selected for scan') return - else: - print '[DB...BAT] IntegratePeaks: selected rows: ', row_number_list # get experiment number status, ret_obj = gutil.parse_integers_editors(self.ui.lineEdit_exp, allow_blank=False) @@ -1877,8 +1863,6 @@ class MainWindow(QtGui.QMainWindow): Merge several scans to a single MDWorkspace and give suggestion for re-binning :return: """ - # TODO/NOW/ISSUE - Test this! - # find the selected scans selected_rows = self.ui.tableWidget_mergeScans.get_selected_rows(True) if len(selected_rows) < 2: @@ -1969,7 +1953,6 @@ class MainWindow(QtGui.QMainWindow): else: merge_status = 'Failed. Reason: %s' % ret_tup merged_name = 'x' - print merge_status # update table self.ui.tableWidget_mergeScans.set_status(row_number, merge_status) @@ -2069,9 +2052,8 @@ class MainWindow(QtGui.QMainWindow): dlg = refineubfftsetup.RefineUBFFTSetupDialog(self) if dlg.exec_(): - min_d, max_d, tolerance = dlg.get_values() - print '[DB...BAT]', min_d, max_d, tolerance # Do stuff with values + min_d, max_d, tolerance = dlg.get_values() else: # case for cancel return @@ -2377,26 +2359,57 @@ class MainWindow(QtGui.QMainWindow): :return: """ status, ret_obj = gutil.parse_integers_editors([self.ui.lineEdit_exp]) - if status is True: + if status: + # new experiment number exp_number = ret_obj[0] + # current experiment to be replaced: warning curr_exp_number = self._myControl.get_experiment() if curr_exp_number is not None and exp_number != curr_exp_number: self.pop_one_button_dialog('Changing experiment to %d. Clean previous experiment %d\'s result' ' in Mantid manually.' % (exp_number, curr_exp_number)) + # set the new experiment number self._myControl.set_exp_number(exp_number) self.ui.lineEdit_exp.setStyleSheet('color: black') - self.setWindowTitle('%s: Experiment %d' % (self._baseTitle, exp_number)) - # TODO/NOW/ISSUE - if the current data directory is empty or as /HFIR/HB3A/, reset data directory + # try to set the default + default_data_dir = '/HFIR/HB3A/exp%d/Datafiles' % exp_number + if os.path.exists(default_data_dir): + self.ui.lineEdit_localSpiceDir.setText(default_data_dir) else: err_msg = ret_obj self.pop_one_button_dialog('Unable to set experiment as %s' % err_msg) self.ui.lineEdit_exp.setStyleSheet('color: red') + return self.ui.tabWidget.setCurrentIndex(0) + # set the instrument geometry constants + status, ret_obj = gutil.parse_float_editors([self.ui.lineEdit_defaultSampleDetDistance, + self.ui.lineEdit_pixelSizeX, + self.ui.lineEdit_pixelSizeY], + allow_blank=False) + if status: + default_det_sample_distance, pixel_x_size, pixel_y_size = ret_obj + self._myControl.set_default_detector_sample_distance(default_det_sample_distance) + self._myControl.set_default_pixel_size(pixel_x_size, pixel_y_size) + else: + self.pop_one_button_dialog('[ERROR] Unable to parse default instrument geometry constants ' + 'due to %s.' % str(ret_obj)) + return + + # set the detector center + det_center_str = str(self.ui.lineEdit_defaultDetCenter.text()) + try: + terms = det_center_str.split(',') + center_row = int(terms[0]) + center_col = int(terms[1]) + self._myControl.set_detector_center(exp_number, center_row, center_col, default=True) + except (IndexError, ValueError) as error: + self.pop_one_button_dialog('[ERROR] Unable to parse default detector center %s due to %s.' + '' % (det_center_str, str(error))) + return def do_set_ub_tab_hkl_to_integers(self): @@ -2463,7 +2476,7 @@ class MainWindow(QtGui.QMainWindow): try: ub_matrix = self._myControl.get_ub_matrix(exp_number) except KeyError as key_err: - print 'Error to get UB matrix: %s' % str(key_err) + print '[Error] unable to get UB matrix: %s' % str(key_err) self.pop_one_button_dialog('Unable to get UB matrix.\nCheck whether UB matrix is set.') return index_status, ret_tup = self._myControl.index_peak(ub_matrix, scan_i, allow_magnetic=True) @@ -2494,19 +2507,20 @@ class MainWindow(QtGui.QMainWindow): def do_setup_dir_default(self): """ Set up default directory for storing data and working + If directory /HFIR/HB3A exists, it means that the user can access HFIR archive server :return: """ home_dir = os.path.expanduser('~') - # TODO/NOW/ISSUE - make this one work for server-based - # example: os.path.exists('/HFIR/HB3A/exp322') won't take long time to find out the server is off. - # Data cache directory - data_cache_dir = os.path.join(home_dir, 'Temp/HB3ATest') - self.ui.lineEdit_localSpiceDir.setText(data_cache_dir) - self.ui.lineEdit_localSrcDir.setText(data_cache_dir) + project_cache_dir = os.path.join(home_dir, 'Temp/HB3ATest') + if os.path.exists('/HFIR/HB3A/'): + self.ui.lineEdit_localSrcDir.setText('/HFIR/HB3A/') + else: + self.ui.lineEdit_localSpiceDir.setText(project_cache_dir) - work_dir = os.path.join(data_cache_dir, 'Workspace') + # working directory + work_dir = os.path.join(project_cache_dir, 'Workspace') self.ui.lineEdit_workDir.setText(work_dir) return @@ -2546,6 +2560,84 @@ class MainWindow(QtGui.QMainWindow): return ub_matrix + def do_set_user_detector_distance(self): + """ + Set up the user-defined detector distance for loading instrument with data + :return: + """ + user_det_distance_str = str(self.ui.lineEdit_userDetSampleDistance.text()).strip() + if len(user_det_distance_str) == 0: + return + + # convert to float + try: + user_det_distance = float(user_det_distance_str) + except ValueError: + self.pop_one_button_dialog('User detector-sample distance %s must be a float.' % user_det_distance_str) + return + + # check distance value because it cannot be too far + default_det_distance = float(str(self.ui.lineEdit_defaultSampleDetDistance.text())) + distance_tol = float(str(self.ui.lineEdit_sampleDetDistTol.text())) + if abs((user_det_distance - default_det_distance) / default_det_distance) > distance_tol: + self.pop_one_button_dialog('User specified sample-detector distance is not reasonable.') + return + + # set to controller + exp_number = int(str(self.ui.lineEdit_exp.text())) + self._myControl.set_detector_sample_distance(exp_number, user_det_distance) + + # update the GUI for information + self.ui.lineEdit_infoDetSampleDistance.setText('%.5f' % user_det_distance) + + return + + def do_set_user_wave_length(self): + """ + + :return: + """ + try: + exp_number = int(str(self.ui.lineEdit_exp.text())) + user_lambda = float(str(self.ui.lineEdit_userWaveLength.text())) + except ValueError: + self.pop_one_button_dialog('Unable to set user wave length with value %s.' + '' % str(self.ui.lineEdit_infoWavelength.text())) + return + + self._myControl.set_user_wave_length(exp_number, user_lambda) + + # set back to GUI + self.ui.lineEdit_infoWavelength.setText('%.5f' % user_lambda) + + return + + def do_set_user_detector_center(self): + """ + set the user-defined detector center + :return: + """ + # get information + status, ret_obj = gutil.parse_integers_editors([self.ui.lineEdit_exp, + self.ui.lineEdit_detCenterPixHorizontal, + self.ui.lineEdit_detCenterPixVertical], + allow_blank=True) + + if not status: + self.pop_one_button_dialog(str(ret_obj)) + return + + assert isinstance(ret_obj, list) and len(ret_obj) == 3, 'Error!' + exp_number, user_center_row, user_center_col = ret_obj + assert isinstance(exp_number, int), 'Experiment number must be set up.' + + self._myControl.set_detector_center(exp_number, user_center_row, user_center_col) + + # apply to the GUI + self.ui.lineEdit_infoDetCenter.setText('%d, %d' % (user_center_row, user_center_col)) + + return + def do_show_spice_file(self): """ Show SPICE file in a window @@ -2717,8 +2809,6 @@ class MainWindow(QtGui.QMainWindow): else: raise RuntimeError('None radio button is selected for UB') - print '[DB...BAT] UB to set: ', ub_matrix - # set to in-use UB matrix and control self.ui.tableWidget_ubInUse.set_from_matrix(ub_matrix) @@ -2807,17 +2897,11 @@ class MainWindow(QtGui.QMainWindow): assert len(ret_obj) == 5 md_file_name, weight_peak_centers, weight_peak_intensities, avg_peak_centre, avg_peak_intensity = ret_obj - print 'Write file to %s' % md_file_name - for i_peak in xrange(len(weight_peak_centers)): - peak_i = weight_peak_centers[i_peak] - print '%f, %f, %f' % (peak_i[0], peak_i[1], peak_i[2]) - print - print avg_peak_centre - # Plot if self._my3DWindow is None: self._my3DWindow = plot3dwindow.Plot3DWindow(self) + print '[INFO] Write file to %s' % md_file_name self._my3DWindow.add_plot_by_file(md_file_name) self._my3DWindow.add_plot_by_array(weight_peak_centers, weight_peak_intensities) self._my3DWindow.add_plot_by_array(avg_peak_centre, avg_peak_intensity) @@ -3405,8 +3489,6 @@ class MainWindow(QtGui.QMainWindow): # gather values for updating intensity = sig_value - print '[DB...BAT] UpdatePeakIntegrationValue: Row %d: peak center %s of type %s.' \ - '' % (row_number, str(peak_centre), type(peak_centre)) # check intensity value is_error = False @@ -3494,8 +3576,6 @@ class MainWindow(QtGui.QMainWindow): except RuntimeError as run_err: self.pop_one_button_dialog(str(run_err)) return - else: - print '[DB...BAT] UpdateMergeInformation: Row = ', row_number # set intensity, state to table if mode == 0: diff --git a/scripts/Inelastic/CrystalField/fitting.py b/scripts/Inelastic/CrystalField/fitting.py index ed377f7a9dda626b42b4cc9294e7f25e4ccf9f59..85da33dab7ac033bab4f146f0136a731ffcb7b36 100644 --- a/scripts/Inelastic/CrystalField/fitting.py +++ b/scripts/Inelastic/CrystalField/fitting.py @@ -117,7 +117,7 @@ class CrystalField(object): self._fieldConstraints = [] self._temperature = None self._FWHM = None - self._intensityScaling = 1.0 + self._intensityScaling = None self._resolutionModel = None self._fwhmVariation = None self._fixAllPeaks = False @@ -185,8 +185,10 @@ class CrystalField(object): temperature = self._getTemperature(i) out = 'name=CrystalFieldSpectrum,Ion=%s,Symmetry=%s,Temperature=%s' % (self._ion, self._symmetry, temperature) out += ',ToleranceEnergy=%s,ToleranceIntensity=%s' % (self._toleranceEnergy, self._toleranceIntensity) - out += ',FixAllPeaks=%s' % self._fixAllPeaks + out += ',FixAllPeaks=%s' % (1 if self._fixAllPeaks else 0) out += ',PeakShape=%s' % self.getPeak(i).name + if self._intensityScaling is not None: + out += ',IntensityScaling=%s' % self._intensityScaling if self._FWHM is not None: out += ',FWHM=%s' % self._getFWHM(i) if len(self._fieldParameters) > 0: @@ -224,11 +226,11 @@ class CrystalField(object): out += ',constraints=(%s)' % constraints return out - # pylint: disable=too-many-public-branches - def makeMultiSpectrumFunction(self): - """Form a definition string for the CrystalFieldMultiSpectrum function""" - out = 'name=CrystalFieldMultiSpectrum,Ion=%s,Symmetry=%s' % (self._ion, self._symmetry) - out += ',ToleranceEnergy=%s,ToleranceIntensity=%s' % (self._toleranceEnergy, self._toleranceIntensity) + def _makeMultiAttributes(self): + """ + Make the main attribute part of the function string for makeMultiSpectrumFunction() + """ + out = ',ToleranceEnergy=%s,ToleranceIntensity=%s' % (self._toleranceEnergy, self._toleranceIntensity) out += ',PeakShape=%s' % self.getPeak().name out += ',FixAllPeaks=%s' % self._fixAllPeaks if self.background is not None: @@ -236,24 +238,16 @@ class CrystalField(object): out += ',Temperatures=(%s)' % ','.join(map(str, self._temperature)) if self._FWHM is not None: out += ',FWHMs=(%s)' % ','.join(map(str, self._FWHM)) - out += ',%s' % ','.join(['%s=%s' % item for item in self._fieldParameters.items()]) + if self._intensityScaling is not None: + for i in range(len(self._intensityScaling)): + out += ',IntensityScaling%s=%s' % (i, self._intensityScaling[i]) + return out - tieList = [] - constraintsList = [] - if self.background is not None: - i = 0 - for background in self.background: - prefix = 'f%s.f0.' % i - bgOut = background.paramString(prefix) - if len(bgOut) > 0: - out += ',%s' % bgOut - tieOut = background.tiesString(prefix) - if len(tieOut) > 0: - tieList.append(tieOut) - constraintsOut = background.constraintsString(prefix) - if len(constraintsOut) > 0: - constraintsList.append(constraintsOut) - i += 1 + def _makeMultiResolutionModel(self): + """ + Make the resolution model part of the function string for makeMultiSpectrumFunction() + """ + out = '' if self._resolutionModel is not None: i = 0 for model in self._resolutionModel.model: @@ -261,6 +255,13 @@ class CrystalField(object): i += 1 if self._fwhmVariation is not None: out += ',FWHMVariation=%s' % self._fwhmVariation + return out + + def _makeMultiPeaks(self): + """ + Make the peaks part of the function string for makeMultiSpectrumFunction() + """ + out = '' i = 0 for peaks in self.peaks: parOut = peaks.paramString('f%s.' % i, 1) @@ -273,6 +274,34 @@ class CrystalField(object): if len(constraintsOut) > 0: out += ',%s' % constraintsOut i += 1 + return out + + # pylint: disable=too-many-public-branches + def makeMultiSpectrumFunction(self): + """Form a definition string for the CrystalFieldMultiSpectrum function""" + out = 'name=CrystalFieldMultiSpectrum,Ion=%s,Symmetry=%s' % (self._ion, self._symmetry) + out += self._makeMultiAttributes() + out += ',%s' % ','.join(['%s=%s' % item for item in self._fieldParameters.items()]) + + tieList = [] + constraintsList = [] + if self.background is not None: + i = 0 + for background in self.background: + prefix = 'f%s.f0.' % i + bgOut = background.paramString(prefix) + if len(bgOut) > 0: + out += ',%s' % bgOut + tieOut = background.tiesString(prefix) + if len(tieOut) > 0: + tieList.append(tieOut) + constraintsOut = background.constraintsString(prefix) + if len(constraintsOut) > 0: + constraintsList.append(constraintsOut) + i += 1 + out += self._makeMultiResolutionModel() + out += self._makeMultiPeaks() + ties = self.getFieldTies() if len(ties) > 0: tieList.append(ties) @@ -381,7 +410,7 @@ class CrystalField(object): @Temperature.setter def Temperature(self, value): - self._temperature= value + self._temperature = value self._dirty_peaks = True self._dirty_spectra = True @@ -779,14 +808,14 @@ class CrystalFieldMulti(object): fun = ';'.join([a.makeSpectrumFunction() for a in self.args]) ties = self.getTies() if len(ties) > 0: - fun += ',ties=(%s)' % ties + fun += ';ties=(%s)' % ties return fun def makeMultiSpectrumFunction(self): fun = ';'.join([a.makeMultiSpectrumFunction() for a in self.args]) ties = self.getTies() if len(ties) > 0: - fun += ',ties=(%s)' % ties + fun += ';ties=(%s)' % ties return fun def ties(self, **kwargs): @@ -861,6 +890,7 @@ class CrystalFieldFit(object): self._output_workspace_base_name = 'fit' self._fit_properties = kwargs self._function = None + self._estimated_parameters = None def fit(self): """ @@ -872,12 +902,61 @@ class CrystalFieldFit(object): return self._fit_single() def monte_carlo(self, **kwargs): + fix_all_peaks = self.model.FixAllPeaks + self.model.FixAllPeaks = True if isinstance(self._input_workspace, list): self._monte_carlo_multi(**kwargs) else: self._monte_carlo_single(**kwargs) + self.model.FixAllPeaks = fix_all_peaks + + def estimate_parameters(self, EnergySplitting, Parameters, **kwargs): + from CrystalField.normalisation import split2range + from mantid.api import mtd + ranges = split2range(Ion=self.model.Ion, EnergySplitting=EnergySplitting, + Parameters=Parameters) + constraints = [('%s<%s<%s' % (-bound, parName, bound)) for parName, bound in ranges.items()] + self.model.constraints(*constraints) + if 'Type' not in kwargs or kwargs['Type'] == 'Monte Carlo': + if 'OutputWorkspace' in kwargs and kwargs['OutputWorkspace'].strip() != '': + output_workspace = kwargs['OutputWorkspace'] + else: + output_workspace = 'estimated_parameters' + kwargs['OutputWorkspace'] = output_workspace + else: + output_workspace = None + self.monte_carlo(**kwargs) + if output_workspace is not None: + self._estimated_parameters = mtd[output_workspace] + + def get_number_estimates(self): + """ + Get a number of parameter sets estimated with self.estimate_parameters(). + """ + if self._estimated_parameters is None: + return 0 + else: + return self._estimated_parameters.columnCount() - 1 + + def select_estimated_parameters(self, index): + ne = self.get_number_estimates() + if ne == 0: + raise RuntimeError('There are no estimated parameters.') + if index >= ne: + raise RuntimeError('There are only %s sets of estimated parameters, requested set #%s' % (ne, index)) + for row in range(self._estimated_parameters.rowCount()): + name = self._estimated_parameters.cell(row, 0) + value = self._estimated_parameters.cell(row, index) + self.model[name] = value + if self._function is not None: + self._function.setParameter(name, value) def _monte_carlo_single(self, **kwargs): + """ + Call EstimateFitParameters algorithm in a single spectrum case. + Args: + **kwargs: Properties of the algorithm. + """ from mantid.api import AlgorithmManager fun = self.model.makeSpectrumFunction() alg = AlgorithmManager.createUnmanaged('EstimateFitParameters') @@ -892,6 +971,11 @@ class CrystalFieldFit(object): self._function = function def _monte_carlo_multi(self, **kwargs): + """ + Call EstimateFitParameters algorithm in a multi-spectrum case. + Args: + **kwargs: Properties of the algorithm. + """ from mantid.api import AlgorithmManager fun = self.model.makeMultiSpectrumFunction() alg = AlgorithmManager.createUnmanaged('EstimateFitParameters') diff --git a/scripts/Inelastic/CrystalField/normalisation.py b/scripts/Inelastic/CrystalField/normalisation.py new file mode 100644 index 0000000000000000000000000000000000000000..088985ef6b951e3a4db57510836badaf376a862a --- /dev/null +++ b/scripts/Inelastic/CrystalField/normalisation.py @@ -0,0 +1,212 @@ +import numpy as np +from CrystalField.energies import energies as CFEnergy + + +def _get_normalisation(nre, bnames): + """ Helper function to calculate the normalisation factor. + Defined as: ||Blm|| = sum_{Jz,Jz'} |<Jz|Blm|Jz'>|^2 / (2J+1) + """ + J = [0, 5./2, 4, 9./2, 4, 5./2, 0, 7./2, 6, 15./2, 8, 15./2, 6, 7./2] + retval = {} + for bname in bnames: + bdict = {bname: 1} + ee, vv, ham = CFEnergy(nre, **bdict) + Omat = np.mat(ham) + norm = np.trace(np.real(Omat * np.conj(Omat))) / (2*J[nre]+1) + retval[bname] = np.sqrt(np.abs(norm)) * np.sign(norm) + return retval + + +def _parse_args(**kwargs): + """ Parses input arguments for stev2norm() and norm2stev(). + """ + # Some definitions + Blms = ['B20', 'B21', 'B22', 'B40', 'B41', 'B42', 'B43', 'B44', 'B60', 'B61', 'B62', 'B63', 'B64', 'B65', 'B66'] + Ions = ['Ce', 'Pr', 'Nd', 'Pm', 'Sm', 'Eu', 'Gd', 'Tb', 'Dy', 'Ho', 'Er', 'Tm', 'Yb'] + # Some Error checking + if 'Ion' not in kwargs.keys() and 'IonNum' not in kwargs.keys(): + raise NameError('You must specify the ion using either the ''Ion'', ''IonNum'' keywords') + if 'Ion' in kwargs.keys(): + nre = [id for id, val in enumerate(Ions) if val == kwargs['Ion']][0] + 1 + else: + nre = kwargs['IonNum'] + # Now parses the list of input crystal field parameters + par_names = [] + Blm = {} + for pname in Blms: + if pname in kwargs.keys(): + par_names.append(pname) + Blm[pname] = kwargs[pname] + if not par_names: + if 'B' in kwargs.keys(): + for ind, pname in enumerate(Blms): + par_names.append(pname) + Blm[pname] = kwargs['B'][ind] + else: + raise NameError('You must specify at least one input Blm parameter') + return nre, par_names, Blm + + +def stev2norm(**kwargs): + """ Calculates the "normalised" crystal field parameters of P. Fabi + These parameters are defined in the appendix of the FOCUS program manual, + http://purl.org/net/epubs/manifestation/5723 page 59. + + nlm = stev2norm(Ion=ionname, B=bvec) + nlm = stev2norm(Ion=ionname, B20=b20val, ...) + nlm = stev2norm(IonNum=ionnumber, B20=b20val, ...) + [B20, B40] = stev2norm(IonNum=ionnumber, B20=b20val, B40=b40val, OutputTuple=True) + + Note: This function only accepts keyword inputs. + + Inputs: + ionname - name of the (tripositive) rare earth ion, e.g. 'Ce', 'Pr'. + ionnumber - the number index of the rare earth ion: + 1=Ce 2=Pr 3=Nd 4=Pm 5=Sm 6=Eu 7=Gd 8=Tb 9=Dy 10=Ho 11=Er 12=Tm 13=Yb + bvec - a vector of the Stevens CF parameters in order: [B20 B21 B22 B40 B41 ... etc.] + This vector can also a be dictionary instead {'B20':1, 'B40':2} + b20val etc. - values of the Stevens CF parameters to be converted + + Outputs: + nlm - a dictionary of the normalised crystal field parameters (default) + [B20, etc] - a tuple of the normalised crystal field parameters (need to set OutputTuple flag) + + Note: one of the keywords: Ion and IonNum must be specified. + + """ + # Parses the input parameters + nre, par_names, Blm = _parse_args(**kwargs) + # Gets the normalisation constants + norm = _get_normalisation(nre, par_names) + # Calculates the normalised parameters. + Nlm = {} + for pname in par_names: + Nlm[pname] = Blm[pname] * norm[pname] + + return Nlm + + +def norm2stev(**kwargs): + """ Calculates the Stevens (conventional) crystal field parameters from "normalised" parameters + The normalised parameters of P. Fabi are defined in the appendix of the FOCUS program manual, + http://purl.org/net/epubs/manifestation/5723 page 59. + + nlm = norm2stev(Ion=ionname, B=bvec) + nlm = norm2stev(Ion=ionname, B20=b20val, ...) + nlm = norm2stev(IonNum=ionnumber, B20=b20val, ...) + [B20, B40] = norm2stev(IonNum=ionnumber, B20=b20val, B40=b40val, OutputTuple=True) + + Note: This function only accepts keyword inputs. + + Inputs: + ionname - name of the (tripositive) rare earth ion, e.g. 'Ce', 'Pr'. + ionnumber - the number index of the rare earth ion: + 1=Ce 2=Pr 3=Nd 4=Pm 5=Sm 6=Eu 7=Gd 8=Tb 9=Dy 10=Ho 11=Er 12=Tm 13=Yb + bvec - a vector of the Stevens CF parameters in order: [B20 B21 B22 B40 B41 ... etc.] + This vector can also a be dictionary instead {'B20':1, 'B40':2} + b20val etc. - values of the Stevens CF parameters to be converted + + Outputs: + nlm - a dictionary of the normalised crystal field parameters (default) + [B20, etc] - a tuple of the normalised crystal field parameters (need to set OutputTuple flag) + + Note: one of the keywords: Ion and IonNum must be specified. + + """ + # Parses the input parameters + nre, par_names, Blm = _parse_args(**kwargs) + # Gets the normalisation constants + norm = _get_normalisation(nre, par_names) + # Calculates the normalised parameters. + Nlm = {} + for pname in par_names: + Nlm[pname] = 0 if norm[pname] == 0 else Blm[pname] / norm[pname] + + return Nlm + + +def split2range(*args, **kwargs): + """ Calculates the ranges of (Stevens) crystal field parameters to give energy splittings + around a specified a desired energy splitting + + ranges = split2range(ionname, energy_splitting, bnames) + ranges = split2range(Ion=ionname, EnergySplitting=energy_splitting, Parameters=bnames) + ranges = split2range(IonNum=ionnumber, EnergySplitting=energy_splitting, Parameters=bnames) + ranges = split2range(PointGroup=point_group, EnergySplitting=energy_splitting, 'B20', 'B22', ...) + ranges = split2range(PointGroup=point_group, EnergySplitting=energy_splitting, B20=_, B22=_, ...) + ranges = split2range(..., Output='dictionary') + constraint_string = split2range(..., Output='constraints') + + Inputs: + ionname - name of the (tripositive) rare earth ion, e.g. 'Ce', 'Pr'. + ionnumber - the number index of the rare earth ion: + 1=Ce 2=Pr 3=Nd 4=Pm 5=Sm 6=Eu 7=Gd 8=Tb 9=Dy 10=Ho 11=Er 12=Tm 13=Yb + energy_splitting - the desired energy splitting (difference between the energies of the + highest and lowest crystal field energy levels) in meV + bnames - a list of names of the crystal field parameters to give the range for + 'B20', etc - the names of the parameters can be given as individual arguments or + keyword arguments. In the case of keyword arguments, only the key names will be used + + Output: + ranges - a dictionary of the ranges such that sampling uniformly in |Blm|<range[bnames] + will produce crystal field splittings distributed normally around the input + energy_splitting. + constraint_string - a string of the form '-[range]<Blm<[range]' where [range] is the + calculated range for that parameter. + By default, the Output keyword is set to "dictionary". + + Note: ionname or ionnumber must be specified. + """ + argin = {} + argnames = ['Ion', 'EnergySplitting', 'Parameters', 'Output', 'IonNum'] + # Set default values. + argin['Output'] = 'dictionary' + argin['Parameters'] = [] + # Parses the non-keyword arguments + for ia in range(3 if len(args)>3 else len(args)): + argin[argnames[ia]] = args[ia] + # Further arguments beyond the first 3 are treated as crystal field parameter names + for ia in range(3, len(args)): + if isinstance(args[ia], basestring) and args[ia].startswith('B'): + argin['Parameters'].append(args[ia]) + # Parses the keyword arguments + for key, value in kwargs.iteritems(): + for ia in range(len(argnames)): + if key == argnames[ia]: + argin[key] = value + break + if key.startswith('B'): + argin['Parameters'].append(key) + + # Error checking + if 'Ion' not in argin.keys() and 'IonNum' not in argin.keys(): + raise NameError('You must specify the ion using either the ''Ion'', ''IonNum'' keywords') + Ions = ['Ce', 'Pr', 'Nd', 'Pm', 'Sm', 'Eu', 'Gd', 'Tb', 'Dy', 'Ho', 'Er', 'Tm', 'Yb'] + if 'Ion' in argin.keys(): + nre = [ id for id,val in enumerate(Ions) if val==kwargs['Ion'] ][0] + 1 + else: + nre = argin['IonNum'] + if 'EnergySplitting' not in argin.keys(): + raise NameError('You must specify the desired energy splitting') + if not argin['Parameters']: + raise NameError('You must specify at least one crystal field parameter name') + + Nlm = {} + for bname in set(argin['Parameters']): + Nlm[bname] = 1 + Blm = norm2stev(IonNum=nre, **Nlm) + ee, vv, ham = CFEnergy(nre, **Blm) + # Factor of 2 is needed to get the Gaussian centred on the desired energy splitting. + splitting_factor = 2 * argin['EnergySplitting'] / (np.max(ee-np.min(ee))) + Nlm = {} + for bname in Blm.keys(): + Nlm[bname] = splitting_factor + ranges = norm2stev(IonNum=nre, **Nlm) + + if argin['Output'].lower() is 'constraints': + constr = '' + for bname in ranges.keys(): + constr += '%.4g<%s<%.4g,' % (-ranges[bname], bname, ranges[bname]) + return constr[:-1] + else: + return ranges diff --git a/scripts/test/CrystalFieldTest.py b/scripts/test/CrystalFieldTest.py index 57e5e4c2a022f944928b2c71eab89b0b144ac299..1b1bc58e8e0dbc9d44f80171232235b8fdd9e4e2 100644 --- a/scripts/test/CrystalFieldTest.py +++ b/scripts/test/CrystalFieldTest.py @@ -7,7 +7,7 @@ import numpy as np # Import mantid to setup the python paths to the bundled scripts import mantid from CrystalField.energies import energies -from mantid.simpleapi import CalculateChiSquared +from mantid.simpleapi import CalculateChiSquared, EvaluateFunction, mtd from mantid.kernel import ConfigService c_mbsr = 79.5774715459 # Conversion from barn to mb/sr @@ -1226,7 +1226,7 @@ class CrystalFieldFitTest(unittest.TestCase): # Define a CrystalField object with parameters slightly shifted. cf = CrystalField('Ce', 'C2v', B20=0, B22=0, B40=0, B42=0, B44=0, - Temperature=44.0, FWHM=1.0, ResolutionModel=([0, 100], [1, 1]), FWHMVariation=0) + Temperature=44.0, FWHM=1.0) # Set the ties cf.ties(B20=0.37737) @@ -1249,11 +1249,8 @@ class CrystalFieldFitTest(unittest.TestCase): ws2 = makeWorkspace(*origin.getSpectrum(1)) # Define a CrystalField object with parameters slightly shifted. - x = [0, 50] - y = [1, 2] - rm = ResolutionModel([(x, y), (x, y)]) cf = CrystalField('Ce', 'C2v', B20=0.37737, B22=3.9770, B40=0, B42=0, B44=0, NPeaks=9, - Temperature=[44.0, 50.0], FWHM=[1.0, 1.0], ResolutionModel=rm, FWHMVariation=0) + Temperature=[44.0, 50.0], FWHM=[1.0, 1.0]) # Set the ties cf.ties(B20=0.37737) @@ -1265,6 +1262,123 @@ class CrystalFieldFitTest(unittest.TestCase): fit.fit() self.assertTrue(cf.chi2 < 100.0) + def test_normalisation(self): + from CrystalField.normalisation import split2range + ranges = split2range(Ion='Pr', EnergySplitting=10, + Parameters=['B20', 'B22', 'B40', 'B42', 'B44', 'B60', 'B62', 'B64', 'B66']) + self.assertAlmostEqual(ranges['B44'], 0.013099063718959822, 7) + self.assertAlmostEqual(ranges['B60'], 0.00010601965319487525, 7) + self.assertAlmostEqual(ranges['B40'], 0.0022141458870077678, 7) + self.assertAlmostEqual(ranges['B42'], 0.009901961430901874, 7) + self.assertAlmostEqual(ranges['B64'], 0.00084150490931686321, 7) + self.assertAlmostEqual(ranges['B22'], 0.19554806997215959, 7) + self.assertAlmostEqual(ranges['B20'], 0.11289973083793813, 7) + self.assertAlmostEqual(ranges['B66'], 0.0011394030334966495, 7) + self.assertAlmostEqual(ranges['B62'], 0.00076818536847364201, 7) + + def test_estimate_parameters_cross_entropy(self): + from CrystalField.fitting import makeWorkspace + from CrystalField import CrystalField, CrystalFieldFit, Background, Function + + # Create some crystal field data + origin = CrystalField('Ce', 'C2v', B20=0.37737, B22=3.9770, B40=-0.031787, B42=-0.11611, B44=-0.12544, + Temperature=44.0, FWHM=1.1) + x, y = origin.getSpectrum() + ws = makeWorkspace(x, y) + + # Define a CrystalField object with parameters slightly shifted. + cf = CrystalField('Ce', 'C2v', B20=0, B22=0, B40=0, B42=0, B44=0, + Temperature=44.0, FWHM=1.0) + + # Set the ties + cf.ties(B20=0.37737) + # Create a fit object + fit = CrystalFieldFit(cf, InputWorkspace=ws) + fit.estimate_parameters(50, ['B22', 'B40', 'B42', 'B44'], + constraints='20<f1.PeakCentre<45,20<f2.PeakCentre<45', + Type='Cross Entropy', NSamples=100) + # Run fit + fit.fit() + self.assertTrue(cf.chi2 < 100.0) + + def test_estimate_parameters_multiple_results(self): + from CrystalField.fitting import makeWorkspace + from CrystalField import CrystalField, CrystalFieldFit, Background, Function + + # Create some crystal field data + origin = CrystalField('Ce', 'C2v', B20=0.37737, B22=3.9770, B40=-0.031787, B42=-0.11611, B44=-0.12544, + Temperature=44.0, FWHM=1.1) + x, y = origin.getSpectrum() + ws = makeWorkspace(x, y) + + # Define a CrystalField object with parameters slightly shifted. + cf = CrystalField('Ce', 'C2v', B20=0, B22=0, B40=0, B42=0, B44=0, + Temperature=44.0, FWHM=1.0) + + # Set the ties + cf.ties(B20=0.37737) + # Create a fit object + fit = CrystalFieldFit(cf, InputWorkspace=ws) + fit.estimate_parameters(50, ['B22', 'B40', 'B42', 'B44'], + constraints='20<f1.PeakCentre<45,20<f2.PeakCentre<45', NSamples=1000) + self.assertEqual(fit.get_number_estimates(), 10) + fit.fit() + self.assertTrue(cf.chi2 < 100.0) + + def test_intensity_scaling_single_spectrum(self): + from CrystalField import CrystalField, CrystalFieldFit, Background, Function + + # Define a CrystalField object with parameters slightly shifted. + cf = CrystalField('Ce', 'C2v', B20=0.37737, B22=3.9770, B40=-0.031787, B42=-0.11611, B44=-0.12544, + Temperature=44.0, FWHM=1.0) + _, y0 = cf.getSpectrum() + + cf.IntensityScaling = 2.5 + _, y1 = cf.getSpectrum() + + self.assertTrue(np.all(y1 / y0 > 2.49999999999)) + self.assertTrue(np.all(y1 / y0 < 2.50000000001)) + + def test_intensity_scaling_single_spectrum_1(self): + from CrystalField import CrystalField, CrystalFieldFit, Background, Function + + # Define a CrystalField object with parameters slightly shifted. + cf = CrystalField('Ce', 'C2v', IntensityScaling=2.5, B20=0.37737, B22=3.9770, B40=-0.031787, + B42=-0.11611, B44=-0.12544, Temperature=44.0, FWHM=1.0) + _, y0 = cf.getSpectrum() + + cf.IntensityScaling = 1.0 + _, y1 = cf.getSpectrum() + + self.assertTrue(np.all(y0 / y1 > 2.49999999999)) + self.assertTrue(np.all(y0 / y1 < 2.50000000001)) + + def test_intensity_scaling_multi_spectrum(self): + from CrystalField.fitting import makeWorkspace + from CrystalField import CrystalField, CrystalFieldFit, Background, Function + + # Define a CrystalField object with parameters slightly shifted. + cf = CrystalField('Ce', 'C2v', B20=0.37737, B22=3.9770, B40=-0.031787, B42=-0.11611, B44=-0.12544, + Temperature=[44.0, 50.0], FWHM=[1.0, 1.2]) + x, y0 = cf.getSpectrum(0) + ws0 = makeWorkspace(x, y0) + x, y1 = cf.getSpectrum(1) + ws1 = makeWorkspace(x, y1) + + cf.IntensityScaling = [2.5, 1.5] + + EvaluateFunction(cf.makeMultiSpectrumFunction(), InputWorkspace=ws0, InputWorkspace_1=ws1, + OutputWorkspace='out') + out = mtd['out'] + out0 = out[0].readY(1) + out1 = out[1].readY(1) + + self.assertTrue(np.all(out0 / y0 > 2.49999999999)) + self.assertTrue(np.all(out0 / y0 < 2.50000000001)) + + self.assertTrue(np.all(out1 / y1 > 1.49999999999)) + self.assertTrue(np.all(out1 / y1 < 1.50000000001)) + if __name__ == "__main__": unittest.main()