diff --git a/Framework/PythonInterface/test/python/plugins/functions/StretchedExpFTTestHelper.py b/Framework/PythonInterface/test/python/plugins/functions/StretchedExpFTTestHelper.py index c213098560c3394b6cbbcd287ad58a7d0b60f3bf..e0131ba3978461996ce29bb0ec69e690f4e3d034 100644 --- a/Framework/PythonInterface/test/python/plugins/functions/StretchedExpFTTestHelper.py +++ b/Framework/PythonInterface/test/python/plugins/functions/StretchedExpFTTestHelper.py @@ -34,10 +34,10 @@ def cleanFit(): def assertFit(workspace, tg): """ - + :param workspace: data MatrixHistogram :param tg: dictionary of target fitting parameters - :return: + :return: """ unacceptable_chi_square = 1.0 msg = "" @@ -80,7 +80,7 @@ def do_fit(tg, fString, shape): Given a target shape and initial fit function guess, carry out the fit :param tg: dictionary of target fitting parameters :param fString: initial guess of the fit function - :param shape: Gaussian or Lorentzian, either integrated or not + :param shape: Gaussian or Lorentzian, either integrated or not :return: success or failure of the fit """ if 'Gaussian' in shape: @@ -105,7 +105,7 @@ def do_fit(tg, fString, shape): bb = np.insert(bb, 0, 2 * E[0] - bb[0]) # external lower bin boundary bb = np.append(bb, 2 * E[-1] - bb[-1]) # external upper bin boundary # return the integral over each energy bin - return np.interp(bb[1:], efine, primitive) - np.interp(bb[:-1], efine, primitive) + return np.interp(bb[1:], efine, primitive) - np.interp(bb[:-1], efine, primitive) createData(ifunctor) else: # when testing function StretchedExpFT diff --git a/qt/scientific_interfaces/ISISReflectometry/GUI/Experiment/ExperimentPresenter.cpp b/qt/scientific_interfaces/ISISReflectometry/GUI/Experiment/ExperimentPresenter.cpp index f45cfdaeb55300a3f4b63115020e89e7ae015bf4..b12b704f8b5b00b873d2e0381ce0eb8a1a77996b 100644 --- a/qt/scientific_interfaces/ISISReflectometry/GUI/Experiment/ExperimentPresenter.cpp +++ b/qt/scientific_interfaces/ISISReflectometry/GUI/Experiment/ExperimentPresenter.cpp @@ -2,14 +2,14 @@ #include "../../Reduction/ValidatePerThetaDefaults.h" #include "PerThetaDefaultsValidationResult.h" // TODO -// - Validate the stitch options input. // - Adjust validation to handle the default angle case. namespace MantidQt { namespace CustomInterfaces { -ExperimentPresenter::ExperimentPresenter(IExperimentView *view) - : m_view(view), m_model() { +ExperimentPresenter::ExperimentPresenter(IExperimentView *view, + double defaultsThetaTolerance) + : m_view(view), m_model(), m_thetaTolerance(defaultsThetaTolerance) { m_view->subscribe(this); notifySettingsChanged(); } @@ -40,10 +40,19 @@ PerThetaDefaultsValidationResult validatePerThetaDefaultsFromView( row++; } - if (Experiment::thetaValuesAreUnique(defaults, thetaTolerance)) { + auto defaultValidationResult = + Experiment::validateThetaValues(defaults, thetaTolerance); + if (defaultValidationResult == ThetaValuesValidationResult::Ok) { return PerThetaDefaultsValidationResult(std::move(defaults), std::move(validationErrors), true); - } else { + } else if (defaultValidationResult == + ThetaValuesValidationResult::MultipleWildcards) { + for (auto row = 0u; row < perThetaDefaultsContent.size(); ++row) + validationErrors.emplace_back(row, std::vector<int>({0})); + return PerThetaDefaultsValidationResult(std::move(defaults), + std::move(validationErrors), true); + } else /* if (defaultValidationResult == + ThetaValuesValidationResult::NonUniqueTheta) */ { for (auto row = 0u; row < perThetaDefaultsContent.size(); ++row) validationErrors.emplace_back(row, std::vector<int>({0})); return PerThetaDefaultsValidationResult(std::move(defaults), @@ -66,36 +75,40 @@ RangeInLambda ExperimentPresenter::transmissionRunRangeFromView() { void ExperimentPresenter::notifySettingsChanged() { auto validationResult = updateModelFromView(); - showPerThetaDefaultsValidationResult(validationResult); + showValidationResult(validationResult); } -PerThetaDefaultsValidationResult ExperimentPresenter::updateModelFromView() { - auto perThetaValidationResult = - validatePerThetaDefaultsFromView(m_view->getPerAngleOptions(), 0.01); - if (perThetaValidationResult.isValid()) { +ExperimentValidationResult ExperimentPresenter::updateModelFromView() { + auto perThetaValidationResult = validatePerThetaDefaultsFromView( + m_view->getPerAngleOptions(), m_thetaTolerance); + auto maybeStitchParameters = parseOptions(m_view->getStitchOptions()); + + if (perThetaValidationResult.isValid() && + maybeStitchParameters.is_initialized()) { auto const analysisMode = analysisModeFromString(m_view->getAnalysisMode()); auto const reductionType = reductionTypeFromString(m_view->getReductionType()); auto const summationType = summationTypeFromString(m_view->getSummationType()); auto transmissionRunRange = transmissionRunRangeFromView(); - auto stitchParameters = m_view->getStitchOptions(); auto polarizationCorrections = polarizationCorrectionsFromView(); m_model = Experiment(analysisMode, reductionType, summationType, polarizationCorrections, transmissionRunRange, - stitchParameters, perThetaValidationResult.defaults()); + maybeStitchParameters.get(), + perThetaValidationResult.defaults()); } else { m_model = boost::none; } - return perThetaValidationResult; + return ExperimentValidationResult(perThetaValidationResult, + maybeStitchParameters.is_initialized()); } -void ExperimentPresenter::notifyPerAngleDefaultsChanged(int row, int column) { +void ExperimentPresenter::notifyPerAngleDefaultsChanged(int, int column) { auto validationResult = updateModelFromView(); - showPerThetaDefaultsValidationResult(validationResult); - if (column == 0 && !validationResult.hasUniqueThetas()) - m_view->showPerAngleThetasNonUnique(0.01); + showPerThetaDefaultsValidationResult(validationResult.perThetaDefaults()); + if (column == 0 && !validationResult.perThetaDefaults().hasUniqueThetas()) + m_view->showPerAngleThetasNonUnique(m_thetaTolerance); } void ExperimentPresenter::showPerThetaDefaultsValidationResult( @@ -111,6 +124,15 @@ void ExperimentPresenter::showPerThetaDefaultsValidationResult( } } +void ExperimentPresenter::showValidationResult( + ExperimentValidationResult const &result) { + showPerThetaDefaultsValidationResult(result.perThetaDefaults()); + if (result.stitchParametersAreValid()) + m_view->showStitchParametersValid(); + else + m_view->showStitchParametersInvalid(); +} + void ExperimentPresenter::notifySummationTypeChanged() { if (m_model.get().summationType() == SummationType::SumInQ) m_view->enableReductionType(); diff --git a/qt/scientific_interfaces/ISISReflectometry/GUI/Experiment/ExperimentPresenter.h b/qt/scientific_interfaces/ISISReflectometry/GUI/Experiment/ExperimentPresenter.h index 0d005e94f497dace10379da3f7ace67209f95b4f..3ac578b17248c5ed08510d7965ef1b78eaeae7ca 100644 --- a/qt/scientific_interfaces/ISISReflectometry/GUI/Experiment/ExperimentPresenter.h +++ b/qt/scientific_interfaces/ISISReflectometry/GUI/Experiment/ExperimentPresenter.h @@ -12,6 +12,25 @@ namespace MantidQt { namespace CustomInterfaces { +class ExperimentValidationResult { +public: + ExperimentValidationResult( + PerThetaDefaultsValidationResult perThetaDefaultsResult, + bool stitchParametersResult) + : m_perThetaDefaultsResult(perThetaDefaultsResult), + m_stitchParametersResult(stitchParametersResult) {} + + PerThetaDefaultsValidationResult const &perThetaDefaults() const { + return m_perThetaDefaultsResult; + } + + bool stitchParametersAreValid() const { return m_stitchParametersResult; } + +private: + PerThetaDefaultsValidationResult m_perThetaDefaultsResult; + bool m_stitchParametersResult; +}; + /** @class ExperimentPresenter ExperimentPresenter is a presenter class for the widget 'Event' in the @@ -42,7 +61,7 @@ class MANTIDQT_ISISREFLECTOMETRY_DLL ExperimentPresenter : public ExperimentViewSubscriber, public IExperimentPresenter { public: - ExperimentPresenter(IExperimentView *view); + ExperimentPresenter(IExperimentView *view, double defaultsThetaTolerance); void notifySettingsChanged() override; void notifySummationTypeChanged() override; void notifyNewPerAngleDefaultsRequested() override; @@ -54,11 +73,15 @@ public: private: PolarizationCorrections polarizationCorrectionsFromView(); RangeInLambda transmissionRunRangeFromView(); - PerThetaDefaultsValidationResult updateModelFromView(); + ExperimentValidationResult updateModelFromView(); + + void showValidationResult(ExperimentValidationResult const &result); void showPerThetaDefaultsValidationResult( PerThetaDefaultsValidationResult const &result); + IExperimentView *m_view; boost::optional<Experiment> m_model; + double m_thetaTolerance; }; } } diff --git a/qt/scientific_interfaces/ISISReflectometry/GUI/Experiment/ExperimentPresenterFactory.h b/qt/scientific_interfaces/ISISReflectometry/GUI/Experiment/ExperimentPresenterFactory.h index d7d21222ee66de4f11e01391566283b777b0663f..6c464e289fd79c8e31f56e87b8a842a5c44be239 100644 --- a/qt/scientific_interfaces/ISISReflectometry/GUI/Experiment/ExperimentPresenterFactory.h +++ b/qt/scientific_interfaces/ISISReflectometry/GUI/Experiment/ExperimentPresenterFactory.h @@ -11,9 +11,15 @@ namespace CustomInterfaces { class ExperimentPresenterFactory { public: + ExperimentPresenterFactory(double thetaTolerance) + : m_thetaTolerance(thetaTolerance) {} + std::unique_ptr<IExperimentPresenter> make(IExperimentView *view) { - return std::make_unique<ExperimentPresenter>(view); + return std::make_unique<ExperimentPresenter>(view, m_thetaTolerance); } + +private: + double m_thetaTolerance; }; } } diff --git a/qt/scientific_interfaces/ISISReflectometry/GUI/Experiment/ExperimentView.cpp b/qt/scientific_interfaces/ISISReflectometry/GUI/Experiment/ExperimentView.cpp index 370af9387724e502860327b64538f1fa722bbfe8..451126e4b445b729365ebd207a0e578795b046c4 100644 --- a/qt/scientific_interfaces/ISISReflectometry/GUI/Experiment/ExperimentView.cpp +++ b/qt/scientific_interfaces/ISISReflectometry/GUI/Experiment/ExperimentView.cpp @@ -36,6 +36,18 @@ void ExperimentView::showPerAngleThetasNonUnique(double tolerance) { QString::number(tolerance) + " apart."); } +void ExperimentView::showStitchParametersValid() { + auto palette = stitchOptionsLineEdit().palette(); + palette.setColor(QPalette::Base, Qt::transparent); + stitchOptionsLineEdit().setPalette(palette); +} + +void ExperimentView::showStitchParametersInvalid() { + auto palette = stitchOptionsLineEdit().palette(); + palette.setColor(QPalette::Base, QColor("#ffb8ad")); + stitchOptionsLineEdit().setPalette(palette); +} + void ExperimentView::subscribe(ExperimentViewSubscriber *notifyee) { m_notifyee = notifyee; } diff --git a/qt/scientific_interfaces/ISISReflectometry/GUI/Experiment/ExperimentView.h b/qt/scientific_interfaces/ISISReflectometry/GUI/Experiment/ExperimentView.h index e7da86e3b396e64e38224cb730c43cd9e3910087..bfe758f2228d5727a6d52494fc235f69991f234a 100644 --- a/qt/scientific_interfaces/ISISReflectometry/GUI/Experiment/ExperimentView.h +++ b/qt/scientific_interfaces/ISISReflectometry/GUI/Experiment/ExperimentView.h @@ -60,7 +60,8 @@ public: void showPerAngleOptionsAsInvalid(int row, int column) override; void showPerAngleOptionsAsValid(int row) override; void showPerAngleThetasNonUnique(double thetaTolerance) override; - + void showStitchParametersValid() override; + void showStitchParametersInvalid() override; double getTransmissionStartOverlap() const override; void setTransmissionStartOverlap(double start) override; diff --git a/qt/scientific_interfaces/ISISReflectometry/GUI/Experiment/IExperimentView.h b/qt/scientific_interfaces/ISISReflectometry/GUI/Experiment/IExperimentView.h index 7f54a948d35fbef9ea86e62e6caf2cb36cf190e7..a626799cf7e83733df039fe7b8d435b0f13c1aad 100644 --- a/qt/scientific_interfaces/ISISReflectometry/GUI/Experiment/IExperimentView.h +++ b/qt/scientific_interfaces/ISISReflectometry/GUI/Experiment/IExperimentView.h @@ -74,6 +74,8 @@ public: virtual void showPerAngleOptionsAsInvalid(int row, int column) = 0; virtual void showPerAngleOptionsAsValid(int row) = 0; virtual void showAllPerAngleOptionsAsValid() = 0; + virtual void showStitchParametersValid() = 0; + virtual void showStitchParametersInvalid() = 0; virtual void enablePolarisationCorrections() = 0; virtual void disablePolarisationCorrections() = 0; diff --git a/qt/scientific_interfaces/ISISReflectometry/QtReflMainWindowView.cpp b/qt/scientific_interfaces/ISISReflectometry/QtReflMainWindowView.cpp index 58acdeb03c397bf696f475aac6b84c9a2b282a5d..cda0f6f904b10b673d689e87f6757ee977e08c1a 100644 --- a/qt/scientific_interfaces/ISISReflectometry/QtReflMainWindowView.cpp +++ b/qt/scientific_interfaces/ISISReflectometry/QtReflMainWindowView.cpp @@ -48,26 +48,26 @@ void QtReflMainWindowView::initLayout() { auto defaultSlicing = Slicing(); auto thetaTolerance = 0.01; auto makeWorkspaceNames = WorkspaceNamesFactory(defaultSlicing); - auto makeBatchPresenter = RunsTablePresenterFactory( + auto makeRunsTablePresenter = RunsTablePresenterFactory( instruments, thetaTolerance, makeWorkspaceNames); - auto defaultInstrumentIndex = 0; // TODO: Look this up properly; + auto defaultInstrumentIndex = 0; + // TODO: Look this up properly by comparing the default instrument to the values in the list; auto searcher = boost::shared_ptr<IReflSearcher>(); auto makeRunsPresenter = RunsPresenterFactory( - std::move(makeBatchPresenter), std::move(makeWorkspaceNames), + std::move(makeRunsTablePresenter), std::move(makeWorkspaceNames), thetaTolerance, instruments, defaultInstrumentIndex, searcher); auto makeEventPresenter = EventPresenterFactory(); auto makeSettingsPresenter = SettingsPresenterFactory(); auto makeSaveSettingsPresenter = SavePresenterFactory(); - - auto makeExperimentPresenter = ExperimentPresenterFactory(); + auto makeExperimentPresenter = ExperimentPresenterFactory(thetaTolerance); auto makeReflBatchPresenter = ReflBatchPresenterFactory( std::move(makeRunsPresenter), std::move(makeEventPresenter), std::move(makeExperimentPresenter), std::move(makeSettingsPresenter), std::move(makeSaveSettingsPresenter)); - + // Create the presenter m_presenter = ReflMainWindowPresenter(this, std::move(makeReflBatchPresenter)); diff --git a/qt/scientific_interfaces/ISISReflectometry/Reduction/Experiment.cpp b/qt/scientific_interfaces/ISISReflectometry/Reduction/Experiment.cpp index bcd615564db484ee3989627e2163966aeb5075fb..649d92b7543277351b563d9fc1d2fd97a0f593f3 100644 --- a/qt/scientific_interfaces/ISISReflectometry/Reduction/Experiment.cpp +++ b/qt/scientific_interfaces/ISISReflectometry/Reduction/Experiment.cpp @@ -1,5 +1,6 @@ #include "Experiment.h" #include <cmath> +#include <iostream> namespace MantidQt { namespace CustomInterfaces { @@ -8,7 +9,7 @@ Experiment::Experiment(AnalysisMode analysisMode, ReductionType reductionType, SummationType summationType, PolarizationCorrections polarizationCorrections, RangeInLambda transmissionRunRange, - std::string stitchParameters, + std::map<std::string, std::string> stitchParameters, std::vector<PerThetaDefaults> perThetaDefaults) : m_analysisMode(analysisMode), m_reductionType(reductionType), m_summationType(summationType), @@ -24,42 +25,93 @@ PolarizationCorrections const &Experiment::polarizationCorrections() const { return m_polarizationCorrections; } -bool Experiment::thetaValuesAreUnique( - std::vector<PerThetaDefaults> perThetaDefaults, double tolerance) { - auto thetaLt = [](PerThetaDefaults const &lhs, PerThetaDefaults const &rhs) - -> bool { return lhs.theta() < rhs.theta(); }; - auto thetaWithinRange = - [tolerance](PerThetaDefaults const &lhs, PerThetaDefaults const &rhs) - -> bool { return std::abs(lhs.theta() - rhs.theta()) < tolerance; }; +int Experiment::countWildcards( + std::vector<PerThetaDefaults> const &perThetaDefaults) { + return static_cast<int>( + std::count_if(perThetaDefaults.cbegin(), perThetaDefaults.cend(), + [](PerThetaDefaults const &defaults) + -> bool { return defaults.isWildcard(); })); +} + +// Need to cope with no wildcard. +ThetaValuesValidationResult +Experiment::validateThetaValues(std::vector<PerThetaDefaults> perThetaDefaults, + double tolerance) { + if (!perThetaDefaults.empty()) { + auto wildcardCount = countWildcards(perThetaDefaults); + if (wildcardCount <= 1) { + auto thetaLt = + [](PerThetaDefaults const &lhs, PerThetaDefaults const &rhs) -> bool { + if (lhs.isWildcard()) + return true; + else if (rhs.isWildcard()) + return false; + else + return lhs.thetaOrWildcard().get() < rhs.thetaOrWildcard().get(); + }; + + auto thetaWithinRange = [tolerance](PerThetaDefaults const &lhs, + PerThetaDefaults const &rhs) -> bool { + std::cout << "lhs: " << lhs.thetaOrWildcard().get() + << ", rhs:" << rhs.thetaOrWildcard().get() + << ", tolerance: " << tolerance << std::endl; + + return std::abs(lhs.thetaOrWildcard().get() - + rhs.thetaOrWildcard().get()) < tolerance; + }; + + std::sort(perThetaDefaults.begin(), perThetaDefaults.end(), thetaLt); + + for (const auto &def : perThetaDefaults) { + std::cout << (def.isWildcard() ? "*" : "-") << std::endl; + } - std::sort(perThetaDefaults.begin(), perThetaDefaults.end(), thetaLt); - return std::adjacent_find(perThetaDefaults.cbegin(), perThetaDefaults.cend(), - thetaWithinRange) == perThetaDefaults.cend(); + return std::adjacent_find(perThetaDefaults.cbegin() + wildcardCount, + perThetaDefaults.cend(), + thetaWithinRange) == perThetaDefaults.cend() + ? ThetaValuesValidationResult::Ok + : ThetaValuesValidationResult::NonUniqueTheta; + } else { + return ThetaValuesValidationResult::MultipleWildcards; + } + } else { + return ThetaValuesValidationResult::Ok; + } } RangeInLambda const &Experiment::transissionRunRange() const { return m_transmissionRunRange; } -std::string Experiment::stitchParameters() const { return m_stitchParameters; } + +std::map<std::string, std::string> Experiment::stitchParameters() const { + return m_stitchParameters; +} + std::vector<PerThetaDefaults> const &Experiment::perThetaDefaults() const { return m_perThetaDefaults; } PerThetaDefaults const *Experiment::defaultsForTheta(double thetaAngle, double tolerance) const { - auto smallestIt = - std::min_element(m_perThetaDefaults.cbegin(), m_perThetaDefaults.cend(), - [thetaAngle](PerThetaDefaults const &lhs, - PerThetaDefaults const &rhs) -> bool { - return std::abs(thetaAngle - lhs.theta()) < - std::abs(thetaAngle - rhs.theta()); - }); - - auto const *closestCandidate = &(*smallestIt); - if (std::abs(thetaAngle - closestCandidate->theta()) <= tolerance) { - return closestCandidate; + auto nonWildcardMatch = std::find_if( + m_perThetaDefaults.cbegin(), m_perThetaDefaults.cend(), + [thetaAngle, tolerance](PerThetaDefaults const &candiate) -> bool { + return !candiate.isWildcard() && + std::abs(thetaAngle - candiate.thetaOrWildcard().get()) <= + tolerance; + }); + if (nonWildcardMatch != m_perThetaDefaults.cend()) { + return &(*nonWildcardMatch); } else { - return nullptr; + auto wildcardMatch = + std::find_if(m_perThetaDefaults.cbegin(), m_perThetaDefaults.cend(), + [](PerThetaDefaults const &candidate) + -> bool { return candidate.isWildcard(); }); + if (wildcardMatch != m_perThetaDefaults.cend()) { + return &(*wildcardMatch); + } else { + return nullptr; + } } } } diff --git a/qt/scientific_interfaces/ISISReflectometry/Reduction/Experiment.h b/qt/scientific_interfaces/ISISReflectometry/Reduction/Experiment.h index 117dd87791f59daa08605f756fa907cda2252b18..ead6cd63cc19dae643cd781d12deab1495801a39 100644 --- a/qt/scientific_interfaces/ISISReflectometry/Reduction/Experiment.h +++ b/qt/scientific_interfaces/ISISReflectometry/Reduction/Experiment.h @@ -29,16 +29,24 @@ Code Documentation is available at: <http://doxygen.mantidproject.org> #include "PerThetaDefaults.h" #include <string> #include <vector> +#include <map> namespace MantidQt { namespace CustomInterfaces { +enum class ThetaValuesValidationResult { + Ok, + MultipleWildcards, + NonUniqueTheta +}; + class MANTIDQT_ISISREFLECTOMETRY_DLL Experiment { public: Experiment(AnalysisMode analysisMode, ReductionType reductionType, SummationType summationType, PolarizationCorrections polarizationCorrections, - RangeInLambda transmissionRunRange, std::string stitchParameters, + RangeInLambda transmissionRunRange, + std::map<std::string, std::string> stitchParameters, std::vector<PerThetaDefaults> perThetaDefaults); AnalysisMode analysisMode() const; @@ -46,17 +54,22 @@ public: SummationType summationType() const; PolarizationCorrections const &polarizationCorrections() const; RangeInLambda const &transissionRunRange() const; - std::string stitchParameters() const; + std::map<std::string, std::string> stitchParameters() const; std::vector<PerThetaDefaults> const &perThetaDefaults() const; PerThetaDefaults const *defaultsForTheta(double thetaAngle, double tolerance) const; static bool - thetaValuesAreUnique(std::vector<PerThetaDefaults> perThetaDefaults, - double tolerance); + containsSingleWildcard(std::vector<PerThetaDefaults> const &perThetaDefaults); + + static ThetaValuesValidationResult + validateThetaValues(std::vector<PerThetaDefaults> perThetaDefaults, + double tolerance); private: + static int countWildcards( + std::vector<PerThetaDefaults> const &perThetaDefaults) ; AnalysisMode m_analysisMode; ReductionType m_reductionType; SummationType m_summationType; @@ -64,7 +77,7 @@ private: PolarizationCorrections m_polarizationCorrections; RangeInLambda m_transmissionRunRange; - std::string m_stitchParameters; + std::map<std::string, std::string> m_stitchParameters; std::vector<PerThetaDefaults> m_perThetaDefaults; }; } diff --git a/qt/scientific_interfaces/ISISReflectometry/Reduction/PerThetaDefaults.cpp b/qt/scientific_interfaces/ISISReflectometry/Reduction/PerThetaDefaults.cpp index 89e826a5e1e5c20a7f0015d1d786b45824629e9b..cc6e1e4fdd8fed1b32de8af7d25c53175466da81 100644 --- a/qt/scientific_interfaces/ISISReflectometry/Reduction/PerThetaDefaults.cpp +++ b/qt/scientific_interfaces/ISISReflectometry/Reduction/PerThetaDefaults.cpp @@ -4,7 +4,7 @@ namespace MantidQt { namespace CustomInterfaces { PerThetaDefaults::PerThetaDefaults( - double theta, std::pair<std::string, std::string> transmissionRuns, + boost::optional<double> theta, std::pair<std::string, std::string> transmissionRuns, boost::optional<RangeInQ> qRange, boost::optional<double> scaleFactor, ReductionOptionsMap reductionOptions) : m_theta(std::move(theta)), @@ -17,7 +17,13 @@ PerThetaDefaults::transmissionWorkspaceNames() const { return m_transmissionRuns; } -double PerThetaDefaults::theta() const { return m_theta; } +bool PerThetaDefaults::isWildcard() const { + return !m_theta.is_initialized(); +} + +boost::optional<double> PerThetaDefaults::thetaOrWildcard() const { + return m_theta; +} boost::optional<RangeInQ> const &PerThetaDefaults::qRange() const { return m_qRange; diff --git a/qt/scientific_interfaces/ISISReflectometry/Reduction/PerThetaDefaults.h b/qt/scientific_interfaces/ISISReflectometry/Reduction/PerThetaDefaults.h index 777c75461a5b1880758af220e9ce3df51b17e799..e68e7d9471aa2d1f36b13965ff85fb3337a8afc5 100644 --- a/qt/scientific_interfaces/ISISReflectometry/Reduction/PerThetaDefaults.h +++ b/qt/scientific_interfaces/ISISReflectometry/Reduction/PerThetaDefaults.h @@ -10,21 +10,22 @@ namespace CustomInterfaces { class MANTIDQT_ISISREFLECTOMETRY_DLL PerThetaDefaults { public: - PerThetaDefaults(double theta, + PerThetaDefaults(boost::optional<double> theta, std::pair<std::string, std::string> tranmissionRuns, boost::optional<RangeInQ> qRange, boost::optional<double> scaleFactor, ReductionOptionsMap reductionOptions); std::pair<std::string, std::string> const &transmissionWorkspaceNames() const; - double theta() const; + bool isWildcard() const; + boost::optional<double> thetaOrWildcard() const; boost::optional<RangeInQ> const &qRange() const; boost::optional<double> scaleFactor() const; ReductionOptionsMap const &reductionOptions() const; private: - double m_theta; + boost::optional<double> m_theta; std::pair<std::string, std::string> m_transmissionRuns; boost::optional<RangeInQ> m_qRange; boost::optional<double> m_scaleFactor; diff --git a/qt/scientific_interfaces/ISISReflectometry/Reduction/ValidatePerThetaDefaults.cpp b/qt/scientific_interfaces/ISISReflectometry/Reduction/ValidatePerThetaDefaults.cpp index c3fa2f4d7c3ea2b58751f2f9ea627714daab15ce..1aef64fa5ee78c03215da921ce5939e3b57073a0 100644 --- a/qt/scientific_interfaces/ISISReflectometry/Reduction/ValidatePerThetaDefaults.cpp +++ b/qt/scientific_interfaces/ISISReflectometry/Reduction/ValidatePerThetaDefaults.cpp @@ -38,12 +38,17 @@ private: using CellText = std::array<std::string, PerThetaDefaultsValidator::INPUT_FIELD_COUNT>; -boost::optional<double> -PerThetaDefaultsValidator::parseTheta(CellText const &cellText) { +boost::optional<boost::optional<double>> +PerThetaDefaultsValidator::parseThetaOrWhitespace(CellText const &cellText) { auto theta = ::MantidQt::CustomInterfaces::parseTheta(cellText[0]); - if (!theta.is_initialized()) + if (theta.is_initialized()) { + return theta; + } else if (isEntirelyWhitespace(cellText[0])) { + return boost::optional<double>(); + } else { m_invalidColumns.emplace_back(0); - return theta; + return boost::none; + } } boost::optional<TransmissionRunPair> @@ -85,7 +90,7 @@ PerThetaDefaultsValidator::parseOptions(CellText const &cellText) { // cppcheck-suppress syntaxError ValidationResult<PerThetaDefaults> PerThetaDefaultsValidator:: operator()(CellText const &cellText) { - auto maybeTheta = parseTheta(cellText); + auto maybeTheta = parseThetaOrWhitespace(cellText); auto maybeTransmissionRuns = parseTransmissionRuns(cellText); auto maybeQRange = parseQRange(cellText); auto maybeScaleFactor = parseScaleFactor(cellText); diff --git a/qt/scientific_interfaces/ISISReflectometry/Reduction/ValidatePerThetaDefaults.h b/qt/scientific_interfaces/ISISReflectometry/Reduction/ValidatePerThetaDefaults.h index 1bd76735be2d63d6c479feee57650be5e69495c6..6f296a4c50d54d688758815f5a8a7ccca618e58b 100644 --- a/qt/scientific_interfaces/ISISReflectometry/Reduction/ValidatePerThetaDefaults.h +++ b/qt/scientific_interfaces/ISISReflectometry/Reduction/ValidatePerThetaDefaults.h @@ -39,7 +39,7 @@ public: operator()(std::array<std::string, INPUT_FIELD_COUNT> const &cellText); private: - boost::optional<double> parseTheta(std::array<std::string, INPUT_FIELD_COUNT> const &cellText); + boost::optional<boost::optional<double>> parseThetaOrWhitespace(std::array<std::string, INPUT_FIELD_COUNT> const &cellText); boost::optional<TransmissionRunPair> parseTransmissionRuns(std::array<std::string, INPUT_FIELD_COUNT> const &cellText); boost::optional<boost::optional<RangeInQ>>