diff --git a/docs/source/images/ISISReflectometryInterface/background_subtraction.png b/docs/source/images/ISISReflectometryInterface/background_subtraction.png new file mode 100644 index 0000000000000000000000000000000000000000..a237e2a5545a5745031126129fc31f78f5f7da97 Binary files /dev/null and b/docs/source/images/ISISReflectometryInterface/background_subtraction.png differ diff --git a/docs/source/images/ISISReflectometryInterface/experiment_settings_tab.png b/docs/source/images/ISISReflectometryInterface/experiment_settings_tab.png index 8fab52cc21060d78acb6b850c57f06bad15214a2..3d1b8769a783bc21e72451785ff0d1290632cec8 100644 Binary files a/docs/source/images/ISISReflectometryInterface/experiment_settings_tab.png and b/docs/source/images/ISISReflectometryInterface/experiment_settings_tab.png differ diff --git a/docs/source/release/v5.1.0/reflectometry.rst b/docs/source/release/v5.1.0/reflectometry.rst index 0be9fb8adc55ec2a5d15a65ac55e564804735e20..bfffda76499c1c34514d927326bc2c0686fb5f95 100644 --- a/docs/source/release/v5.1.0/reflectometry.rst +++ b/docs/source/release/v5.1.0/reflectometry.rst @@ -12,6 +12,19 @@ Reflectometry Changes ISIS Reflectometry Interface ############################ +New +--- + +.. figure:: ../../images/ISISReflectometryInterface/background_subtraction.png + :class: screenshot + :width: 700px + :align: right + :alt: Background subtraction on the ISIS Reflectometry Interface + + *Background subtraction on the ISIS Reflectometry Interface* + +- Background subtraction options have been added to the ISIS Reflectometry Interface. The subtraction is performed using :ref:`algm-ReflectometryBackgroundSubtraction`. + Bug fixes --------- diff --git a/instrument/unit_testing/REFL_Parameters_Experiment.xml b/instrument/unit_testing/REFL_Parameters_Experiment.xml index e3dd855562fbffbb76ead7f603f5c69996806c43..133a18dbfb4e185c0c4f99c74456f4beb585375d 100644 --- a/instrument/unit_testing/REFL_Parameters_Experiment.xml +++ b/instrument/unit_testing/REFL_Parameters_Experiment.xml @@ -33,6 +33,18 @@ <!-- Corrections --> + <parameter name="BackgroundCalculationMethod" type="string"> + <value val="Polynomial"/> + </parameter> + + <parameter name="DegreeOfPolynomial"> + <value val="2"/> + </parameter> + + <parameter name="CostFunction" type="string"> + <value val="Unweighted least squares"/> + </parameter> + <parameter name="PolarizationAnalysis" type="string"> <value val="ParameterFile"/> </parameter> @@ -69,6 +81,10 @@ <value val="390-415"/> </parameter> + <parameter name="BackgroundProcessingInstructions" type="string"> + <value val="370-389,416-430"/> + </parameter> + <!-- Transmission overlap range --> <parameter name="TransRunStartOverlap"> diff --git a/instrument/unit_testing/REFL_Parameters_Subtraction_Invalid.xml b/instrument/unit_testing/REFL_Parameters_Subtraction_Invalid.xml new file mode 100644 index 0000000000000000000000000000000000000000..6d81cd1869d9750742ed08c0ad0600ffb479800f --- /dev/null +++ b/instrument/unit_testing/REFL_Parameters_Subtraction_Invalid.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<parameter-file instrument="REFL" valid-from="forever"> + +<component-link name="REFL" > + + <parameter name="BackgroundCalculationMethod" type="string"> + <value val="badSubtractionMethod"/> + </parameter> + + <parameter name="DegreeOfPolynomial" type="string"> + <value val="badPolynomialType"/> + </parameter> + + <parameter name="CostFunction" type="string"> + <value val="badCostFunction"/> + </parameter> + +</component-link> + +</parameter-file> diff --git a/qt/scientific_interfaces/ISISReflectometry/GUI/Batch/RowProcessingAlgorithm.cpp b/qt/scientific_interfaces/ISISReflectometry/GUI/Batch/RowProcessingAlgorithm.cpp index ad82098a4f180b18a3004c51b91b6cd705182301..c383a441d392961628173fe70d18525850ea6b93 100644 --- a/qt/scientific_interfaces/ISISReflectometry/GUI/Batch/RowProcessingAlgorithm.cpp +++ b/qt/scientific_interfaces/ISISReflectometry/GUI/Batch/RowProcessingAlgorithm.cpp @@ -81,6 +81,22 @@ void updateTransmissionStitchProperties( properties); } +void updateBackgroundSubtractionProperties( + AlgorithmRuntimeProps &properties, + BackgroundSubtraction const &subtraction) { + AlgorithmProperties::update("SubtractBackground", + subtraction.subtractBackground(), properties); + AlgorithmProperties::update( + "BackgroundCalculationMethod", + backgroundSubtractionTypeToString(subtraction.subtractionType()), + properties); + AlgorithmProperties::update("DegreeOfPolynomial", + subtraction.degreeOfPolynomial(), properties); + AlgorithmProperties::update( + "CostFunction", costFunctionTypeToString(subtraction.costFunction()), + properties); +} + void updatePolarizationCorrectionProperties( AlgorithmRuntimeProps &properties, PolarizationCorrections const &corrections) { @@ -117,6 +133,8 @@ void updateExperimentProperties(AlgorithmRuntimeProps &properties, experiment.includePartialBins(), properties); updateTransmissionStitchProperties(properties, experiment.transmissionStitchOptions()); + updateBackgroundSubtractionProperties(properties, + experiment.backgroundSubtraction()); updatePolarizationCorrectionProperties(properties, experiment.polarizationCorrections()); updateFloodCorrectionProperties(properties, experiment.floodCorrections()); @@ -138,6 +156,9 @@ void updatePerThetaDefaultProperties(AlgorithmRuntimeProps &properties, AlgorithmProperties::update("ProcessingInstructions", perThetaDefaults->processingInstructions(), properties); + AlgorithmProperties::update( + "BackgroundProcessingInstructions", + perThetaDefaults->backgroundProcessingInstructions(), properties); } void updateWavelengthRangeProperties( diff --git a/qt/scientific_interfaces/ISISReflectometry/GUI/Common/Decoder.cpp b/qt/scientific_interfaces/ISISReflectometry/GUI/Common/Decoder.cpp index 35089ce4499f0675a05612ced158879ee82a1a53..9fbe2307b1a4d91a0efc50a5215b3ad6bd605e8e 100644 --- a/qt/scientific_interfaces/ISISReflectometry/GUI/Common/Decoder.cpp +++ b/qt/scientific_interfaces/ISISReflectometry/GUI/Common/Decoder.cpp @@ -111,6 +111,14 @@ void Decoder::decodeExperiment(const QtExperimentView *gui, map[QString("transStitchParamsEdit")].toString()); gui->m_ui.transScaleRHSCheckBox->setChecked( map[QString("transScaleRHSCheckBox")].toBool()); + gui->m_ui.subtractBackgroundCheckBox->setChecked( + map[QString("subtractBackgroundCheckBox")].toBool()); + gui->m_ui.backgroundMethodComboBox->setCurrentIndex( + map[QString("backgroundMethodComboBox")].toInt()); + gui->m_ui.polynomialDegreeSpinBox->setValue( + map[QString("polynomialDegreeSpinBox")].toInt()); + gui->m_ui.costFunctionComboBox->setCurrentIndex( + map[QString("costFunctionComboBox")].toInt()); gui->m_ui.polCorrCheckBox->setChecked( map[QString("polCorrCheckBox")].toBool()); gui->m_ui.floodCorComboBox->setCurrentIndex( diff --git a/qt/scientific_interfaces/ISISReflectometry/GUI/Common/Encoder.cpp b/qt/scientific_interfaces/ISISReflectometry/GUI/Common/Encoder.cpp index 6d4843df5a57c9a6d0a4d7759c7af8b7c7d07316..320bb44e894c36536781da4fcc79fd6d18539cd4 100644 --- a/qt/scientific_interfaces/ISISReflectometry/GUI/Common/Encoder.cpp +++ b/qt/scientific_interfaces/ISISReflectometry/GUI/Common/Encoder.cpp @@ -307,6 +307,14 @@ QMap<QString, QVariant> Encoder::encodeExperiment(const QtExperimentView *gui) { QVariant(gui->m_ui.transStitchParamsEdit->text())); map.insert(QString("transScaleRHSCheckBox"), QVariant(gui->m_ui.transScaleRHSCheckBox->isChecked())); + map.insert(QString("subtractBackgroundCheckBox"), + QVariant(gui->m_ui.subtractBackgroundCheckBox->isChecked())); + map.insert(QString("backgroundMethodComboBox"), + QVariant(gui->m_ui.backgroundMethodComboBox->currentIndex())); + map.insert(QString("polynomialDegreeSpinBox"), + QVariant(gui->m_ui.polynomialDegreeSpinBox->value())); + map.insert(QString("costFunctionComboBox"), + QVariant(gui->m_ui.costFunctionComboBox->currentIndex())); map.insert(QString("polCorrCheckBox"), QVariant(gui->m_ui.polCorrCheckBox->isChecked())); map.insert(QString("floodCorComboBox"), diff --git a/qt/scientific_interfaces/ISISReflectometry/GUI/Experiment/ExperimentOptionDefaults.cpp b/qt/scientific_interfaces/ISISReflectometry/GUI/Experiment/ExperimentOptionDefaults.cpp index 94441e5f3d46806702caf89b449397764ac32d48..3d430027e7f5461fca84d15ec3a48a83943f72be 100644 --- a/qt/scientific_interfaces/ISISReflectometry/GUI/Experiment/ExperimentOptionDefaults.cpp +++ b/qt/scientific_interfaces/ISISReflectometry/GUI/Experiment/ExperimentOptionDefaults.cpp @@ -39,6 +39,21 @@ getExperimentDefaults(Mantid::Geometry::Instrument_const_sptr instrument) { defaults.getBoolOrFalse("IncludePartialBins", "IncludePartialBins"); auto debug = defaults.getBoolOrFalse("Debug", "Debug"); + auto backgroundSubtractionMethod = defaults.getStringOrEmpty( + "BackgroundCalculationMethod", "BackgroundCalculationMethod"); + auto subtractBackground = !backgroundSubtractionMethod.empty(); + auto backgroundSubtractionType = + subtractBackground + ? backgroundSubtractionTypeFromString(backgroundSubtractionMethod) + : BackgroundSubtractionType::PerDetectorAverage; + auto degreeOfPolynomial = + defaults.getIntOrZero("DegreeOfPolynomial", "DegreeOfPolynomial"); + auto costFunction = costFunctionTypeFromString(defaults.getStringOrDefault( + "CostFunction", "CostFunction", "Least squares")); + auto backgroundSubtraction = + BackgroundSubtraction(subtractBackground, backgroundSubtractionType, + degreeOfPolynomial, costFunction); + auto polarizationCorrectionType = polarizationCorrectionTypeFromString(defaults.getStringOrDefault( "PolarizationAnalysis", "PolarizationAnalysis", "None")); @@ -89,10 +104,12 @@ getExperimentDefaults(Mantid::Geometry::Instrument_const_sptr instrument) { auto const scaleFactor = stringValueOrEmpty(maybeScaleFactor); auto const processingInstructions = defaults.getStringOrEmpty( "ProcessingInstructions", "ProcessingInstructions"); + auto const backgroundProcessingInstructions = defaults.getStringOrEmpty( + "BackgroundProcessingInstructions", "BackgroundProcessingInstructions"); auto perThetaDefaultsRow = PerThetaDefaults::ValueArray{ {theta, firstTransmissionRun, secondTransmissionRun, transmissionProcessingInstructions, qMin, qMax, qStep, scaleFactor, - processingInstructions}}; + processingInstructions, backgroundProcessingInstructions}}; auto perThetaDefaults = std::vector<PerThetaDefaults::ValueArray>{perThetaDefaultsRow}; auto validate = PerThetaDefaultsTableValidator(); @@ -104,8 +121,9 @@ getExperimentDefaults(Mantid::Geometry::Instrument_const_sptr instrument) { return Experiment( analysisMode, reductionType, summationType, includePartialBins, debug, - std::move(polarizationCorrections), std::move(floodCorrections), - std::move(transmissionStitchOptions), std::move(stitchParameters), + std::move(backgroundSubtraction), std::move(polarizationCorrections), + std::move(floodCorrections), std::move(transmissionStitchOptions), + std::move(stitchParameters), std::move(perThetaValidationResult.assertValid())); } } // unnamed namespace diff --git a/qt/scientific_interfaces/ISISReflectometry/GUI/Experiment/ExperimentPresenter.cpp b/qt/scientific_interfaces/ISISReflectometry/GUI/Experiment/ExperimentPresenter.cpp index 61e6016cc89b37bdf659753c196125f5664b696f..25de929d128d3c70a4559f20a86a1cb938685745 100644 --- a/qt/scientific_interfaces/ISISReflectometry/GUI/Experiment/ExperimentPresenter.cpp +++ b/qt/scientific_interfaces/ISISReflectometry/GUI/Experiment/ExperimentPresenter.cpp @@ -100,6 +100,7 @@ void ExperimentPresenter::updateWidgetEnabledState() { m_view->enableAll(); updateSummationTypeEnabledState(); + updateBackgroundSubtractionEnabledState(); updatePolarizationCorrectionEnabledState(); updateFloodCorrectionEnabledState(); } @@ -141,6 +142,17 @@ void ExperimentPresenter::restoreDefaults() { updateViewFromModel(); } +BackgroundSubtraction ExperimentPresenter::backgroundSubtractionFromView() { + auto const subtractBackground = m_view->getSubtractBackground(); + auto const subtractionType = backgroundSubtractionTypeFromString( + m_view->getBackgroundSubtractionMethod()); + auto const degreeOfPolynomial = m_view->getPolynomialDegree(); + auto const costFunction = + costFunctionTypeFromString(m_view->getCostFunction()); + return BackgroundSubtraction(subtractBackground, subtractionType, + degreeOfPolynomial, costFunction); +} + PolarizationCorrections ExperimentPresenter::polarizationCorrectionsFromView() { auto const correctionType = m_view->getPolarizationCorrectionOption() ? PolarizationCorrectionType::ParameterFile @@ -159,6 +171,23 @@ FloodCorrections ExperimentPresenter::floodCorrectionsFromView() { return FloodCorrections(correctionType); } +void ExperimentPresenter::updateBackgroundSubtractionEnabledState() { + if (m_view->getSubtractBackground()) { + m_view->enableBackgroundSubtractionMethod(); + if (m_view->getBackgroundSubtractionMethod() == "Polynomial") { + m_view->enablePolynomialDegree(); + m_view->enableCostFunction(); + } else { + m_view->disablePolynomialDegree(); + m_view->disableCostFunction(); + } + } else { + m_view->disableBackgroundSubtractionMethod(); + m_view->disablePolynomialDegree(); + m_view->disableCostFunction(); + } +} + void ExperimentPresenter::updatePolarizationCorrectionEnabledState() { // We could generalise which instruments polarization corrections are // applicable for but for now it's not worth it, so just hard code the @@ -251,14 +280,15 @@ ExperimentValidationResult ExperimentPresenter::validateExperimentFromView() { auto const includePartialBins = m_view->getIncludePartialBins(); auto const debugOption = m_view->getDebugOption(); auto transmissionStitchOptions = transmissionStitchOptionsFromView(); + auto backgroundSubtraction = backgroundSubtractionFromView(); auto polarizationCorrections = polarizationCorrectionsFromView(); auto floodCorrections = floodCorrectionsFromView(); auto stitchParameters = stitchParametersFromView(); - return ExperimentValidationResult( - Experiment(analysisMode, reductionType, summationType, - includePartialBins, debugOption, polarizationCorrections, - floodCorrections, transmissionStitchOptions, - stitchParameters, perThetaValidationResult.assertValid())); + return ExperimentValidationResult(Experiment( + analysisMode, reductionType, summationType, includePartialBins, + debugOption, backgroundSubtraction, polarizationCorrections, + floodCorrections, transmissionStitchOptions, stitchParameters, + perThetaValidationResult.assertValid())); } else { return ExperimentValidationResult( ExperimentValidationErrors(perThetaValidationResult.assertError())); @@ -304,6 +334,7 @@ void ExperimentPresenter::updateViewFromModel() { m_view->setIncludePartialBins(m_model.includePartialBins()); m_view->setDebugOption(m_model.debug()); m_view->setPerAngleOptions(m_model.perThetaDefaultsArray()); + // Transmission if (m_model.transmissionStitchOptions().overlapRange()) { m_view->setTransmissionStartOverlap( m_model.transmissionStitchOptions().overlapRange()->min()); @@ -317,6 +348,16 @@ void ExperimentPresenter::updateViewFromModel() { m_model.transmissionStitchOptions().rebinParameters()); m_view->setTransmissionScaleRHSWorkspace( m_model.transmissionStitchOptions().scaleRHS()); + // Background subtraction + m_view->setSubtractBackground( + m_model.backgroundSubtraction().subtractBackground()); + m_view->setBackgroundSubtractionMethod(backgroundSubtractionTypeToString( + m_model.backgroundSubtraction().subtractionType())); + m_view->setPolynomialDegree( + m_model.backgroundSubtraction().degreeOfPolynomial()); + m_view->setCostFunction( + costFunctionTypeToString(m_model.backgroundSubtraction().costFunction())); + // Corrections m_view->setPolarizationCorrectionOption( m_model.polarizationCorrections().correctionType() != PolarizationCorrectionType::None); diff --git a/qt/scientific_interfaces/ISISReflectometry/GUI/Experiment/ExperimentPresenter.h b/qt/scientific_interfaces/ISISReflectometry/GUI/Experiment/ExperimentPresenter.h index 2f540e94acf4710ad87bd5cd2ae640fe48928b60..e811989b4260f749474e8b37993b6c60cd69985c 100644 --- a/qt/scientific_interfaces/ISISReflectometry/GUI/Experiment/ExperimentPresenter.h +++ b/qt/scientific_interfaces/ISISReflectometry/GUI/Experiment/ExperimentPresenter.h @@ -76,6 +76,7 @@ private: IBatchPresenter *m_mainPresenter; ExperimentValidationResult validateExperimentFromView(); + BackgroundSubtraction backgroundSubtractionFromView(); PolarizationCorrections polarizationCorrectionsFromView(); FloodCorrections floodCorrectionsFromView(); boost::optional<RangeInLambda> transmissionRunRangeFromView(); @@ -93,6 +94,7 @@ private: void updateWidgetEnabledState(); void updateSummationTypeEnabledState(); + void updateBackgroundSubtractionEnabledState(); void updatePolarizationCorrectionEnabledState(); void updateFloodCorrectionEnabledState(); @@ -105,4 +107,4 @@ private: }; } // namespace ISISReflectometry } // namespace CustomInterfaces -} // namespace MantidQt \ No newline at end of file +} // namespace MantidQt diff --git a/qt/scientific_interfaces/ISISReflectometry/GUI/Experiment/ExperimentWidget.ui b/qt/scientific_interfaces/ISISReflectometry/GUI/Experiment/ExperimentWidget.ui index 4c6d279f7fb766beae8662ffdee86be63185d6da..e7150e409cf9ccb2ba4edc878de437ab08524b1c 100644 --- a/qt/scientific_interfaces/ISISReflectometry/GUI/Experiment/ExperimentWidget.ui +++ b/qt/scientific_interfaces/ISISReflectometry/GUI/Experiment/ExperimentWidget.ui @@ -40,7 +40,7 @@ <number>5</number> </property> <item> - <layout class="QGridLayout" name="expSettingsGrid" rowstretch="0,0,0,0,0,0,0,0,0,0,0,0,0,0,0" columnstretch="0,0,0,0"> + <layout class="QGridLayout" name="expSettingsGrid" rowstretch="0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0" columnstretch="0,0,0,0"> <property name="leftMargin"> <number>10</number> </property> @@ -53,6 +53,26 @@ <property name="bottomMargin"> <number>10</number> </property> + <item row="2" column="1"> + <widget class="QComboBox" name="summationTypeComboBox"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <item> + <property name="text"> + <string>SumInLambda</string> + </property> + </item> + <item> + <property name="text"> + <string>SumInQ</string> + </property> + </item> + </widget> + </item> <item row="9" column="3"> <widget class="QCheckBox" name="transScaleRHSCheckBox"> <property name="minimumSize"> @@ -66,8 +86,8 @@ </property> </widget> </item> - <item row="13" column="0"> - <widget class="QLabel" name="stitchLabel"> + <item row="9" column="0"> + <widget class="QLabel" name="transmissionStitchParamsLabel"> <property name="minimumSize"> <size> <width>117</width> @@ -75,25 +95,133 @@ </size> </property> <property name="text"> - <string>Output Stitch Properties</string> + <string>Transmission Stitch Params</string> </property> </widget> </item> - <item row="1" column="2"> - <widget class="QLabel" name="debugLabel"> + <item row="12" column="1"> + <widget class="QCheckBox" name="polCorrCheckBox"> + <property name="text"> + <string/> + </property> + </widget> + </item> + <item row="4" column="1" rowspan="3" colspan="3"> + <widget class="QTableWidget" name="optionsTable"> + <property name="sizePolicy"> + <sizepolicy hsizetype="MinimumExpanding" vsizetype="Expanding"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> <property name="minimumSize"> <size> - <width>117</width> + <width>600</width> <height>0</height> </size> </property> - <property name="text"> - <string>Debug</string> + <property name="toolTip"> + <string>Specify options based on the run angle. Leave the angle empty to specify defaults for all runs.</string> </property> + <property name="whatsThis"> + <string>This table allows you to specify default values for runs that do not have values specified on the Runs tab. You can specify these on a per-angle basis, where the angle from the Runs table will be looked up in the this table and those options will be used where a match is found. You may also leave the angle blank in this table to specify the default options that should be used for all runs.</string> + </property> + <property name="alternatingRowColors"> + <bool>true</bool> + </property> + <property name="sortingEnabled"> + <bool>true</bool> + </property> + <property name="rowCount"> + <number>3</number> + </property> + <property name="columnCount"> + <number>10</number> + </property> + <attribute name="horizontalHeaderVisible"> + <bool>true</bool> + </attribute> + <attribute name="horizontalHeaderMinimumSectionSize"> + <number>40</number> + </attribute> + <attribute name="horizontalHeaderStretchLastSection"> + <bool>true</bool> + </attribute> + <attribute name="verticalHeaderVisible"> + <bool>false</bool> + </attribute> + <row> + <property name="text"> + <string>New Row</string> + </property> + </row> + <row> + <property name="text"> + <string>New Row</string> + </property> + </row> + <row> + <property name="text"> + <string>New Row</string> + </property> + </row> + <column> + <property name="text"> + <string>Angle</string> + </property> + <property name="toolTip"> + <string/> + </property> + </column> + <column> + <property name="text"> + <string>1st Trans Run(s)</string> + </property> + </column> + <column> + <property name="text"> + <string>2nd Trans Run(s)</string> + </property> + </column> + <column> + <property name="text"> + <string>Trans Spectra</string> + </property> + </column> + <column> + <property name="text"> + <string>Q min</string> + </property> + </column> + <column> + <property name="text"> + <string>Q max</string> + </property> + </column> + <column> + <property name="text"> + <string>dQ/Q</string> + </property> + </column> + <column> + <property name="text"> + <string>Scale</string> + </property> + </column> + <column> + <property name="text"> + <string>ROI</string> + </property> + </column> + <column> + <property name="text"> + <string>Background</string> + </property> + </column> </widget> </item> - <item row="2" column="0"> - <widget class="QLabel" name="summationTypeLabel"> + <item row="8" column="2"> + <widget class="QLabel" name="endOverlapLabel"> <property name="minimumSize"> <size> <width>117</width> @@ -101,43 +229,33 @@ </size> </property> <property name="text"> - <string>SummationType</string> + <string>Overlap End</string> </property> </widget> </item> - <item row="14" column="3"> - <widget class="QPushButton" name="getExpDefaultsButton"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> + <item row="1" column="3"> + <widget class="QCheckBox" name="debugCheckBox"> <property name="minimumSize"> <size> - <width>71</width> - <height>32</height> + <width>50</width> + <height>0</height> </size> </property> - <property name="layoutDirection"> - <enum>Qt::RightToLeft</enum> - </property> <property name="text"> - <string>Restore Defaults</string> - </property> - <property name="fixedWidth" stdset="0"> - <number>70</number> - </property> - <property name="fixedHeight" stdset="0"> - <number>100</number> + <string/> </property> - <layout class="QHBoxLayout" name="getExpDefaultsButtonLayout"/> </widget> </item> - <item row="10" column="1"> - <widget class="QCheckBox" name="polCorrCheckBox"> + <item row="12" column="0"> + <widget class="QLabel" name="polCorrLabel"> + <property name="minimumSize"> + <size> + <width>117</width> + <height>0</height> + </size> + </property> <property name="text"> - <string/> + <string>Polarisation Corrections</string> </property> </widget> </item> @@ -151,23 +269,20 @@ </property> </widget> </item> - <item row="11" column="3"> - <widget class="MantidQt::MantidWidgets::WorkspaceSelector" name="floodWorkspaceWsSelector"> - <property name="sizePolicy"> - <sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> + <item row="3" column="0"> + <widget class="QLabel" name="reductionTypeLabel"> <property name="minimumSize"> <size> - <width>50</width> + <width>117</width> <height>0</height> </size> </property> + <property name="text"> + <string>ReductionType</string> + </property> </widget> </item> - <item row="11" column="0"> + <item row="13" column="0"> <widget class="QLabel" name="floodCorLabel"> <property name="minimumSize"> <size> @@ -180,53 +295,23 @@ </property> </widget> </item> - <item row="1" column="1"> - <widget class="QComboBox" name="analysisModeComboBox"> + <item row="13" column="3"> + <widget class="MantidQt::MantidWidgets::WorkspaceSelector" name="floodWorkspaceWsSelector"> <property name="sizePolicy"> - <sizepolicy hsizetype="Minimum" vsizetype="Fixed"> + <sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed"> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> - <item> - <property name="text"> - <string>PointDetectorAnalysis</string> - </property> - </item> - <item> - <property name="text"> - <string>MultiDetectorAnalysis</string> - </property> - </item> - </widget> - </item> - <item row="8" column="3"> - <widget class="QDoubleSpinBox" name="endOverlapEdit"> <property name="minimumSize"> <size> <width>50</width> <height>0</height> </size> </property> - <property name="decimals"> - <number>5</number> - </property> - </widget> - </item> - <item row="8" column="0"> - <widget class="QLabel" name="startOverlapLabel"> - <property name="minimumSize"> - <size> - <width>117</width> - <height>0</height> - </size> - </property> - <property name="text"> - <string>Transmission Run Overlap Start</string> - </property> </widget> </item> - <item row="11" column="2"> + <item row="13" column="2"> <widget class="QLabel" name="floodWorkspaceWsSelectorLabel"> <property name="sizePolicy"> <sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred"> @@ -264,8 +349,8 @@ </property> </widget> </item> - <item row="10" column="0"> - <widget class="QLabel" name="polCorrLabel"> + <item row="3" column="2"> + <widget class="QLabel" name="includePartialBinsLabel"> <property name="minimumSize"> <size> <width>117</width> @@ -273,56 +358,58 @@ </size> </property> <property name="text"> - <string>Polarisation Corrections</string> + <string>IncludePartialBins</string> </property> </widget> </item> - <item row="3" column="1"> - <widget class="QComboBox" name="reductionTypeComboBox"> - <property name="enabled"> - <bool>false</bool> + <item row="1" column="0"> + <widget class="QLabel" name="analysisModeLabel"> + <property name="minimumSize"> + <size> + <width>117</width> + <height>0</height> + </size> </property> - <property name="sizePolicy"> - <sizepolicy hsizetype="Minimum" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> + <property name="text"> + <string>AnalysisMode</string> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QComboBox" name="analysisModeComboBox"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> </sizepolicy> </property> <item> <property name="text"> - <string>Normal</string> - </property> - </item> - <item> - <property name="text"> - <string>DivergentBeam</string> + <string>PointDetectorAnalysis</string> </property> </item> <item> <property name="text"> - <string>NonFlatSample</string> + <string>MultiDetectorAnalysis</string> </property> </item> </widget> </item> - <item row="3" column="3"> - <widget class="QCheckBox" name="includePartialBinsCheckBox"> - <property name="enabled"> - <bool>false</bool> - </property> + <item row="1" column="2"> + <widget class="QLabel" name="debugLabel"> <property name="minimumSize"> <size> - <width>50</width> + <width>117</width> <height>0</height> </size> </property> <property name="text"> - <string/> + <string>Debug</string> </property> </widget> </item> - <item row="1" column="0"> - <widget class="QLabel" name="analysisModeLabel"> + <item row="4" column="0"> + <widget class="QLabel" name="perAngleTableLabel"> <property name="minimumSize"> <size> <width>117</width> @@ -330,12 +417,18 @@ </size> </property> <property name="text"> - <string>AnalysisMode</string> + <string>Per-angle defaults</string> + </property> + <property name="alignment"> + <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set> </property> </widget> </item> - <item row="2" column="1"> - <widget class="QComboBox" name="summationTypeComboBox"> + <item row="3" column="1"> + <widget class="QComboBox" name="reductionTypeComboBox"> + <property name="enabled"> + <bool>false</bool> + </property> <property name="sizePolicy"> <sizepolicy hsizetype="Minimum" vsizetype="Fixed"> <horstretch>0</horstretch> @@ -344,18 +437,52 @@ </property> <item> <property name="text"> - <string>SumInLambda</string> + <string>Normal</string> </property> </item> <item> <property name="text"> - <string>SumInQ</string> + <string>DivergentBeam</string> + </property> + </item> + <item> + <property name="text"> + <string>NonFlatSample</string> </property> </item> </widget> </item> - <item row="8" column="2"> - <widget class="QLabel" name="endOverlapLabel"> + <item row="16" column="3"> + <widget class="QPushButton" name="getExpDefaultsButton"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>71</width> + <height>32</height> + </size> + </property> + <property name="layoutDirection"> + <enum>Qt::RightToLeft</enum> + </property> + <property name="text"> + <string>Restore Defaults</string> + </property> + <property name="fixedWidth" stdset="0"> + <number>70</number> + </property> + <property name="fixedHeight" stdset="0"> + <number>100</number> + </property> + <layout class="QHBoxLayout" name="getExpDefaultsButtonLayout"/> + </widget> + </item> + <item row="8" column="0"> + <widget class="QLabel" name="startOverlapLabel"> <property name="minimumSize"> <size> <width>117</width> @@ -363,12 +490,28 @@ </size> </property> <property name="text"> - <string>Overlap End</string> + <string>Transmission Run Overlap Start</string> </property> </widget> </item> - <item row="9" column="0"> - <widget class="QLabel" name="transmissionStitchParamsLabel"> + <item row="3" column="3"> + <widget class="QCheckBox" name="includePartialBinsCheckBox"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="minimumSize"> + <size> + <width>50</width> + <height>0</height> + </size> + </property> + <property name="text"> + <string/> + </property> + </widget> + </item> + <item row="2" column="0"> + <widget class="QLabel" name="summationTypeLabel"> <property name="minimumSize"> <size> <width>117</width> @@ -376,12 +519,12 @@ </size> </property> <property name="text"> - <string>Transmission Stitch Params</string> + <string>SummationType</string> </property> </widget> </item> - <item row="4" column="0"> - <widget class="QLabel" name="perAngleTableLabel"> + <item row="9" column="2"> + <widget class="QLabel" name="transmissionScaleRHSLabel"> <property name="minimumSize"> <size> <width>117</width> @@ -389,14 +532,21 @@ </size> </property> <property name="text"> - <string>Per-angle defaults</string> + <string>Scale RHS Transmission</string> </property> - <property name="alignment"> - <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set> + </widget> + </item> + <item row="9" column="1"> + <widget class="QLineEdit" name="transStitchParamsEdit"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> </property> </widget> </item> - <item row="11" column="1"> + <item row="13" column="1"> <widget class="QComboBox" name="floodCorComboBox"> <property name="sizePolicy"> <sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed"> @@ -416,177 +566,103 @@ </item> </widget> </item> - <item row="3" column="0"> - <widget class="QLabel" name="reductionTypeLabel"> + <item row="8" column="3"> + <widget class="QDoubleSpinBox" name="endOverlapEdit"> <property name="minimumSize"> <size> - <width>117</width> + <width>50</width> <height>0</height> </size> </property> - <property name="text"> - <string>ReductionType</string> + <property name="decimals"> + <number>5</number> </property> </widget> </item> - <item row="1" column="3"> - <widget class="QCheckBox" name="debugCheckBox"> + <item row="15" column="0"> + <widget class="QLabel" name="stitchLabel"> <property name="minimumSize"> <size> - <width>50</width> + <width>117</width> <height>0</height> </size> </property> <property name="text"> - <string/> + <string>Output Stitch Properties</string> </property> </widget> </item> - <item row="4" column="1" rowspan="3" colspan="3"> - <widget class="QTableWidget" name="optionsTable"> - <property name="sizePolicy"> - <sizepolicy hsizetype="MinimumExpanding" vsizetype="Expanding"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="minimumSize"> - <size> - <width>600</width> - <height>0</height> - </size> - </property> - <property name="toolTip"> - <string>Specify options based on the run angle. Leave the angle empty to specify defaults for all runs.</string> - </property> - <property name="whatsThis"> - <string>This table allows you to specify default values for runs that do not have values specified on the Runs tab. You can specify these on a per-angle basis, where the angle from the Runs table will be looked up in the this table and those options will be used where a match is found. You may also leave the angle blank in this table to specify the default options that should be used for all runs.</string> - </property> - <property name="alternatingRowColors"> - <bool>true</bool> - </property> - <property name="sortingEnabled"> - <bool>true</bool> - </property> - <property name="rowCount"> - <number>3</number> + <item row="10" column="1"> + <widget class="QCheckBox" name="subtractBackgroundCheckBox"> + <property name="text"> + <string/> </property> - <property name="columnCount"> - <number>9</number> + </widget> + </item> + <item row="10" column="0"> + <widget class="QLabel" name="subtractBackgroundLabel"> + <property name="text"> + <string>Subtract Background</string> </property> - <attribute name="horizontalHeaderVisible"> - <bool>true</bool> - </attribute> - <attribute name="horizontalHeaderMinimumSectionSize"> - <number>40</number> - </attribute> - <attribute name="horizontalHeaderStretchLastSection"> - <bool>true</bool> - </attribute> - <attribute name="verticalHeaderVisible"> - <bool>false</bool> - </attribute> - <row> - <property name="text"> - <string>New Row</string> - </property> - </row> - <row> - <property name="text"> - <string>New Row</string> - </property> - </row> - <row> - <property name="text"> - <string>New Row</string> - </property> - </row> - <column> - <property name="text"> - <string>Angle</string> - </property> - <property name="toolTip"> - <string/> - </property> - </column> - <column> - <property name="text"> - <string>1st Trans Run(s)</string> - </property> - </column> - <column> - <property name="text"> - <string>2nd Trans Run(s)</string> - </property> - </column> - <column> - <property name="text"> - <string>Trans Spectra</string> - </property> - </column> - <column> - <property name="text"> - <string>Q min</string> - </property> - </column> - <column> - <property name="text"> - <string>Q max</string> - </property> - </column> - <column> + </widget> + </item> + <item row="10" column="3"> + <widget class="QComboBox" name="backgroundMethodComboBox"> + <item> <property name="text"> - <string>dQ/Q</string> + <string>PerDetectorAverage</string> </property> - </column> - <column> + </item> + <item> <property name="text"> - <string>Scale</string> + <string>Polynomial</string> </property> - </column> - <column> + </item> + <item> <property name="text"> - <string>Run Spectra</string> + <string>AveragePixelFit</string> </property> - </column> + </item> </widget> </item> - <item row="9" column="2"> - <widget class="QLabel" name="transmissionScaleRHSLabel"> - <property name="minimumSize"> - <size> - <width>117</width> - <height>0</height> - </size> - </property> + <item row="10" column="2"> + <widget class="QLabel" name="backgroundMethodLabel"> <property name="text"> - <string>Scale RHS Transmission</string> + <string>Subtraction method</string> </property> </widget> </item> - <item row="3" column="2"> - <widget class="QLabel" name="includePartialBinsLabel"> - <property name="minimumSize"> - <size> - <width>117</width> - <height>0</height> - </size> - </property> + <item row="11" column="1"> + <widget class="QSpinBox" name="polynomialDegreeSpinBox"/> + </item> + <item row="11" column="0"> + <widget class="QLabel" name="polynomialDegreeLabel"> <property name="text"> - <string>IncludePartialBins</string> + <string>Polynomial Degree</string> </property> </widget> </item> - <item row="9" column="1"> - <widget class="QLineEdit" name="transStitchParamsEdit"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Minimum" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> + <item row="11" column="2"> + <widget class="QLabel" name="costFunctionLabel"> + <property name="text"> + <string>Cost Function</string> </property> </widget> </item> + <item row="11" column="3"> + <widget class="QComboBox" name="costFunctionComboBox"> + <item> + <property name="text"> + <string>Least squares</string> + </property> + </item> + <item> + <property name="text"> + <string>Unweighted least squares</string> + </property> + </item> + </widget> + </item> </layout> </item> </layout> diff --git a/qt/scientific_interfaces/ISISReflectometry/GUI/Experiment/IExperimentView.h b/qt/scientific_interfaces/ISISReflectometry/GUI/Experiment/IExperimentView.h index 1ea331833c157e83bb08cf39c8cd90a69015745d..e37b6777e8a3a114a96cd0ef8a04d4aa1b4286a2 100644 --- a/qt/scientific_interfaces/ISISReflectometry/GUI/Experiment/IExperimentView.h +++ b/qt/scientific_interfaces/ISISReflectometry/GUI/Experiment/IExperimentView.h @@ -74,6 +74,20 @@ public: virtual void showStitchParametersValid() = 0; virtual void showStitchParametersInvalid() = 0; + virtual bool getSubtractBackground() const = 0; + virtual void setSubtractBackground(bool enable) = 0; + virtual std::string getBackgroundSubtractionMethod() const = 0; + virtual void setBackgroundSubtractionMethod(std::string const &method) = 0; + virtual void enableBackgroundSubtractionMethod() = 0; + virtual void disableBackgroundSubtractionMethod() = 0; + virtual int getPolynomialDegree() const = 0; + virtual void setPolynomialDegree(int polynomialDegree) = 0; + virtual void enablePolynomialDegree() = 0; + virtual void disablePolynomialDegree() = 0; + virtual std::string getCostFunction() const = 0; + virtual void setCostFunction(std::string const &costFunction) = 0; + virtual void enableCostFunction() = 0; + virtual void disableCostFunction() = 0; virtual void enablePolarizationCorrections() = 0; virtual void disablePolarizationCorrections() = 0; virtual void enableFloodCorrectionInputs() = 0; @@ -119,4 +133,4 @@ public: }; } // namespace ISISReflectometry } // namespace CustomInterfaces -} // namespace MantidQt \ No newline at end of file +} // namespace MantidQt diff --git a/qt/scientific_interfaces/ISISReflectometry/GUI/Experiment/QtExperimentView.cpp b/qt/scientific_interfaces/ISISReflectometry/GUI/Experiment/QtExperimentView.cpp index 60a9a6fb9c2ae1a31eb2901bd323880d0660b228..ea13b69b4e164fcca149cac07a2d513a5c02621f 100644 --- a/qt/scientific_interfaces/ISISReflectometry/GUI/Experiment/QtExperimentView.cpp +++ b/qt/scientific_interfaces/ISISReflectometry/GUI/Experiment/QtExperimentView.cpp @@ -191,6 +191,11 @@ void QtExperimentView::connectSettingsChange(QLineEdit &edit) { SLOT(onSettingsChanged())); } +void QtExperimentView::connectSettingsChange(QSpinBox &edit) { + connect(&edit, SIGNAL(valueChanged(QString const &)), this, + SLOT(onSettingsChanged())); +} + void QtExperimentView::connectSettingsChange(QDoubleSpinBox &edit) { connect(&edit, SIGNAL(valueChanged(QString const &)), this, SLOT(onSettingsChanged())); @@ -214,6 +219,10 @@ void QtExperimentView::disconnectSettingsChange(QLineEdit &edit) { disconnect(&edit, SIGNAL(textChanged(QString const &)), 0, 0); } +void QtExperimentView::disconnectSettingsChange(QSpinBox &edit) { + disconnect(&edit, SIGNAL(valueChanged(QString const &)), 0, 0); +} + void QtExperimentView::disconnectSettingsChange(QDoubleSpinBox &edit) { disconnect(&edit, SIGNAL(valueChanged(QString const &)), 0, 0); } @@ -249,6 +258,10 @@ void QtExperimentView::setEnabledStateForAllWidgets(bool enabled) { m_ui.floodCorComboBox->setEnabled(enabled); m_ui.floodWorkspaceWsSelector->setEnabled(enabled); m_ui.debugCheckBox->setEnabled(enabled); + m_ui.subtractBackgroundCheckBox->setEnabled(enabled); + m_ui.backgroundMethodComboBox->setEnabled(enabled); + m_ui.polynomialDegreeSpinBox->setEnabled(enabled); + m_ui.costFunctionComboBox->setEnabled(enabled); } void QtExperimentView::disableAll() { setEnabledStateForAllWidgets(false); } @@ -276,6 +289,13 @@ void QtExperimentView::registerExperimentSettingsWidgets( registerSettingWidget(*m_ui.floodCorComboBox, "FloodCorrection", alg); registerSettingWidget(*m_ui.floodWorkspaceWsSelector, "FloodWorkspace", alg); registerSettingWidget(*m_ui.debugCheckBox, "Debug", alg); + registerSettingWidget(*m_ui.subtractBackgroundCheckBox, "SubtractBackground", + alg); + registerSettingWidget(*m_ui.backgroundMethodComboBox, + "BackgroundCalculationMethod", alg); + registerSettingWidget(*m_ui.polynomialDegreeSpinBox, "DegreeOfPolynomial", + alg); + registerSettingWidget(*m_ui.costFunctionComboBox, "CostFunction", alg); registerSettingWidget(stitchOptionsLineEdit(), "Properties to use for stitching the output workspaces " @@ -300,6 +320,10 @@ void QtExperimentView::connectExperimentSettingsWidgets() { connectSettingsChange(*m_ui.floodCorComboBox); connectSettingsChange(*m_ui.floodWorkspaceWsSelector); connectSettingsChange(*m_ui.debugCheckBox); + connectSettingsChange(*m_ui.subtractBackgroundCheckBox); + connectSettingsChange(*m_ui.backgroundMethodComboBox); + connectSettingsChange(*m_ui.polynomialDegreeSpinBox); + connectSettingsChange(*m_ui.costFunctionComboBox); } void QtExperimentView::disconnectExperimentSettingsWidgets() { @@ -317,6 +341,10 @@ void QtExperimentView::disconnectExperimentSettingsWidgets() { disconnectSettingsChange(*m_ui.floodCorComboBox); disconnectSettingsChange(*m_ui.floodWorkspaceWsSelector); disconnectSettingsChange(*m_ui.debugCheckBox); + disconnectSettingsChange(*m_ui.subtractBackgroundCheckBox); + disconnectSettingsChange(*m_ui.backgroundMethodComboBox); + disconnectSettingsChange(*m_ui.polynomialDegreeSpinBox); + disconnectSettingsChange(*m_ui.costFunctionComboBox); } void QtExperimentView::onRestoreDefaultsRequested() { @@ -462,6 +490,63 @@ void QtExperimentView::setChecked(QCheckBox &checkBox, bool checked) { checkBox.setCheckState(checkedAsCheckState); } +bool QtExperimentView::getSubtractBackground() const { + return m_ui.subtractBackgroundCheckBox->isChecked(); +} + +void QtExperimentView::setSubtractBackground(bool enable) { + setChecked(*m_ui.subtractBackgroundCheckBox, enable); +} + +std::string QtExperimentView::getBackgroundSubtractionMethod() const { + return getText(*m_ui.backgroundMethodComboBox); +} + +void QtExperimentView::setBackgroundSubtractionMethod( + std::string const &method) { + return setSelected(*m_ui.backgroundMethodComboBox, method); +} + +void QtExperimentView::enableBackgroundSubtractionMethod() { + m_ui.backgroundMethodComboBox->setEnabled(true); +} + +void QtExperimentView::disableBackgroundSubtractionMethod() { + m_ui.backgroundMethodComboBox->setEnabled(false); +} + +int QtExperimentView::getPolynomialDegree() const { + return m_ui.polynomialDegreeSpinBox->value(); +} + +void QtExperimentView::setPolynomialDegree(int polynomialDegree) { + m_ui.polynomialDegreeSpinBox->setValue(polynomialDegree); +} + +void QtExperimentView::enablePolynomialDegree() { + m_ui.polynomialDegreeSpinBox->setEnabled(true); +} + +void QtExperimentView::disablePolynomialDegree() { + m_ui.polynomialDegreeSpinBox->setEnabled(false); +} + +std::string QtExperimentView::getCostFunction() const { + return getText(*m_ui.costFunctionComboBox); +} + +void QtExperimentView::setCostFunction(std::string const &costFunction) { + setSelected(*m_ui.costFunctionComboBox, costFunction); +} + +void QtExperimentView::enableCostFunction() { + m_ui.costFunctionComboBox->setEnabled(true); +} + +void QtExperimentView::disableCostFunction() { + m_ui.costFunctionComboBox->setEnabled(false); +} + void QtExperimentView::enablePolarizationCorrections() { m_ui.polCorrCheckBox->setEnabled(true); m_ui.polCorrLabel->setEnabled(true); @@ -659,7 +744,7 @@ QtExperimentView::getPerAngleOptions() const { textFromCell(table.item(row, 2)), textFromCell(table.item(row, 3)), textFromCell(table.item(row, 4)), textFromCell(table.item(row, 5)), textFromCell(table.item(row, 6)), textFromCell(table.item(row, 7)), - textFromCell(table.item(row, 8))}); + textFromCell(table.item(row, 8)), textFromCell(table.item(row, 9))}); } return rows; } diff --git a/qt/scientific_interfaces/ISISReflectometry/GUI/Experiment/QtExperimentView.h b/qt/scientific_interfaces/ISISReflectometry/GUI/Experiment/QtExperimentView.h index 2efaf48f3fd0fc80195586c95ac6403f40075e9d..2300adfed2ec47a3fc624d5e4340b764bc5ca0a3 100644 --- a/qt/scientific_interfaces/ISISReflectometry/GUI/Experiment/QtExperimentView.h +++ b/qt/scientific_interfaces/ISISReflectometry/GUI/Experiment/QtExperimentView.h @@ -96,8 +96,27 @@ public: void disableAll() override; void enableAll() override; + bool getSubtractBackground() const override; + void setSubtractBackground(bool enable) override; + + std::string getBackgroundSubtractionMethod() const override; + void setBackgroundSubtractionMethod(std::string const &method) override; + void enableBackgroundSubtractionMethod() override; + void disableBackgroundSubtractionMethod() override; + + int getPolynomialDegree() const override; + void setPolynomialDegree(int polynomialDegree) override; + void enablePolynomialDegree() override; + void disablePolynomialDegree() override; + + std::string getCostFunction() const override; + void setCostFunction(std::string const &costFunction) override; + void enableCostFunction() override; + void disableCostFunction() override; + void enablePolarizationCorrections() override; void disablePolarizationCorrections() override; + void enableFloodCorrectionInputs() override; void disableFloodCorrectionInputs() override; @@ -148,11 +167,13 @@ private: void connectSettingsChange(QCheckBox &edit); void connectSettingsChange(QTableWidget &edit); void connectSettingsChange(QDoubleSpinBox &edit); + void connectSettingsChange(QSpinBox &edit); void disconnectSettingsChange(QLineEdit &edit); void disconnectSettingsChange(QComboBox &edit); void disconnectSettingsChange(QCheckBox &edit); void disconnectSettingsChange(QTableWidget &edit); void disconnectSettingsChange(QDoubleSpinBox &edit); + void disconnectSettingsChange(QSpinBox &edit); QLineEdit &stitchOptionsLineEdit() const; void setSelected(QComboBox &box, std::string const &str); void setText(QLineEdit &lineEdit, int value); diff --git a/qt/scientific_interfaces/ISISReflectometry/Reduction/BackgroundSubtraction.cpp b/qt/scientific_interfaces/ISISReflectometry/Reduction/BackgroundSubtraction.cpp new file mode 100644 index 0000000000000000000000000000000000000000..bda02b2bf464ff47aa1179f2e8adff8c3c85d2b3 --- /dev/null +++ b/qt/scientific_interfaces/ISISReflectometry/Reduction/BackgroundSubtraction.cpp @@ -0,0 +1,54 @@ +// Mantid Repository : https://github.com/mantidproject/mantid +// +// Copyright © 2020 ISIS Rutherford Appleton Laboratory UKRI, +// NScD Oak Ridge National Laboratory, European Spallation Source +// & Institut Laue - Langevin +// SPDX - License - Identifier: GPL - 3.0 + +#include "BackgroundSubtraction.h" +namespace MantidQt { +namespace CustomInterfaces { +namespace ISISReflectometry { + +BackgroundSubtraction::BackgroundSubtraction() + : m_subtractBackground(false), + m_subtractionType(BackgroundSubtractionType::PerDetectorAverage), + m_degreeOfPolynomial(0), m_costFunction(CostFunctionType::LeastSquares) {} + +BackgroundSubtraction::BackgroundSubtraction( + bool subtractBackground, BackgroundSubtractionType subtractionType, + int degreeOfPolynomial, CostFunctionType costFunction) + : m_subtractBackground(subtractBackground), + m_subtractionType(subtractionType), + m_degreeOfPolynomial(degreeOfPolynomial), m_costFunction(costFunction) {} + +bool BackgroundSubtraction::subtractBackground() const { + return m_subtractBackground; +} + +BackgroundSubtractionType BackgroundSubtraction::subtractionType() const { + return m_subtractionType; +} + +int BackgroundSubtraction::degreeOfPolynomial() const { + return m_degreeOfPolynomial; +} + +CostFunctionType BackgroundSubtraction::costFunction() const { + return m_costFunction; +} + +bool operator!=(BackgroundSubtraction const &lhs, + BackgroundSubtraction const &rhs) { + return !(lhs == rhs); +} + +bool operator==(BackgroundSubtraction const &lhs, + BackgroundSubtraction const &rhs) { + return lhs.subtractBackground() == rhs.subtractBackground() && + lhs.subtractionType() == rhs.subtractionType() && + lhs.degreeOfPolynomial() == rhs.degreeOfPolynomial() && + lhs.costFunction() == rhs.costFunction(); +} +} // namespace ISISReflectometry +} // namespace CustomInterfaces +} // namespace MantidQt diff --git a/qt/scientific_interfaces/ISISReflectometry/Reduction/BackgroundSubtraction.h b/qt/scientific_interfaces/ISISReflectometry/Reduction/BackgroundSubtraction.h new file mode 100644 index 0000000000000000000000000000000000000000..a4c0d7ac9fc6eae47d7882dd4cf5aa1bfae7585a --- /dev/null +++ b/qt/scientific_interfaces/ISISReflectometry/Reduction/BackgroundSubtraction.h @@ -0,0 +1,99 @@ +// Mantid Repository : https://github.com/mantidproject/mantid +// +// Copyright © 2020 ISIS Rutherford Appleton Laboratory UKRI, +// NScD Oak Ridge National Laboratory, European Spallation Source +// & Institut Laue - Langevin +// SPDX - License - Identifier: GPL - 3.0 + +#ifndef MANTID_CUSTOMINTERFACES_BACKGROUNDSUBTRACTION_H_ +#define MANTID_CUSTOMINTERFACES_BACKGROUNDSUBTRACTION_H_ +#include "Common/DllConfig.h" +#include <boost/optional.hpp> +#include <stdexcept> +#include <string> +namespace MantidQt { +namespace CustomInterfaces { +namespace ISISReflectometry { +enum class BackgroundSubtractionType { + PerDetectorAverage, + Polynomial, + AveragePixelFit +}; +enum class CostFunctionType { LeastSquares, UnweightedLeastSquares }; + +inline BackgroundSubtractionType +backgroundSubtractionTypeFromString(std::string const &subtractionType) { + if (subtractionType.empty() || subtractionType == "PerDetectorAverage") + return BackgroundSubtractionType::PerDetectorAverage; + else if (subtractionType == "Polynomial") + return BackgroundSubtractionType::Polynomial; + else if (subtractionType == "AveragePixelFit") + return BackgroundSubtractionType::AveragePixelFit; + else + throw std::invalid_argument("Unexpected background subtraction type."); +} + +inline std::string +backgroundSubtractionTypeToString(BackgroundSubtractionType subtractionType) { + switch (subtractionType) { + case BackgroundSubtractionType::PerDetectorAverage: + return "PerDetectorAverage"; + case BackgroundSubtractionType::Polynomial: + return "Polynomial"; + case BackgroundSubtractionType::AveragePixelFit: + return "AveragePixelFit"; + } + throw std::invalid_argument("Unexpected background subtraction type."); +} + +inline CostFunctionType +costFunctionTypeFromString(std::string const &costFunction) { + if (costFunction.empty() || costFunction == "Least squares") + return CostFunctionType::LeastSquares; + else if (costFunction == "Unweighted least squares") + return CostFunctionType::UnweightedLeastSquares; + else + throw std::invalid_argument("Unexpected cost function type"); +} + +inline std::string costFunctionTypeToString(CostFunctionType costFunctionType) { + switch (costFunctionType) { + case CostFunctionType::LeastSquares: + return "Least squares"; + case CostFunctionType::UnweightedLeastSquares: + return "Unweighted least squares"; + }; + throw std::invalid_argument("Unexpected cost function type."); +} + +/** @class BackgroundSubtraction + + The BackgroundSubtraction model holds information about what + background subtraction, if any, should be done prior to reduction. + */ +class MANTIDQT_ISISREFLECTOMETRY_DLL BackgroundSubtraction { +public: + BackgroundSubtraction(); + BackgroundSubtraction(bool subtractBackground, + BackgroundSubtractionType subtractionType, + int degreeOfPolynomial, CostFunctionType costFunction); + + bool subtractBackground() const; + BackgroundSubtractionType subtractionType() const; + int degreeOfPolynomial() const; + CostFunctionType costFunction() const; + +private: + bool m_subtractBackground; + BackgroundSubtractionType m_subtractionType; + int m_degreeOfPolynomial; + CostFunctionType m_costFunction; +}; + +MANTIDQT_ISISREFLECTOMETRY_DLL bool +operator==(BackgroundSubtraction const &lhs, BackgroundSubtraction const &rhs); +MANTIDQT_ISISREFLECTOMETRY_DLL bool +operator!=(BackgroundSubtraction const &lhs, BackgroundSubtraction const &rhs); +} // namespace ISISReflectometry +} // namespace CustomInterfaces +} // namespace MantidQt +#endif // MANTID_CUSTOMINTERFACES_BACKGROUNDSUBTRACTION_H_ diff --git a/qt/scientific_interfaces/ISISReflectometry/Reduction/CMakeLists.txt b/qt/scientific_interfaces/ISISReflectometry/Reduction/CMakeLists.txt index d972b827b3f7017fe0e229410f622b51af4d68d3..cbe15d24b3f135da69e075fa38663c8995ba3c5a 100644 --- a/qt/scientific_interfaces/ISISReflectometry/Reduction/CMakeLists.txt +++ b/qt/scientific_interfaces/ISISReflectometry/Reduction/CMakeLists.txt @@ -18,6 +18,7 @@ set(REDUCTION_SRC_FILES FloodCorrections.cpp Instrument.cpp MonitorCorrections.cpp + BackgroundSubtraction.cpp PolarizationCorrections.cpp RangeInLambda.cpp RunsTable.cpp @@ -50,6 +51,7 @@ set(REDUCTION_INC_FILES FloodCorrections.h Instrument.h MonitorCorrections.h + BackgroundSubtraction.h PolarizationCorrections.h RangeInLambda.h ReductionType.h diff --git a/qt/scientific_interfaces/ISISReflectometry/Reduction/Experiment.cpp b/qt/scientific_interfaces/ISISReflectometry/Reduction/Experiment.cpp index 68be0147817bb64641a9d79a0403abab7a10bbdc..93d48cb783d652de808543c706f605a4f1f80a96 100644 --- a/qt/scientific_interfaces/ISISReflectometry/Reduction/Experiment.cpp +++ b/qt/scientific_interfaces/ISISReflectometry/Reduction/Experiment.cpp @@ -16,18 +16,19 @@ Experiment::Experiment() : m_analysisMode(AnalysisMode::PointDetector), m_reductionType(ReductionType::Normal), m_summationType(SummationType::SumInLambda), m_includePartialBins(false), - m_debug(false), m_polarizationCorrections(PolarizationCorrections( - PolarizationCorrectionType::None)), + m_debug(false), m_backgroundSubtraction(BackgroundSubtraction()), + m_polarizationCorrections( + PolarizationCorrections(PolarizationCorrectionType::None)), m_floodCorrections(FloodCorrections(FloodCorrectionType::Workspace)), m_transmissionStitchOptions(), m_stitchParameters(std::map<std::string, std::string>()), m_perThetaDefaults(std::vector<PerThetaDefaults>({PerThetaDefaults( boost::none, TransmissionRunPair(), boost::none, RangeInQ(), - boost::none, ProcessingInstructions())})) {} + boost::none, ProcessingInstructions(), boost::none)})) {} Experiment::Experiment(AnalysisMode analysisMode, ReductionType reductionType, SummationType summationType, bool includePartialBins, - bool debug, + bool debug, BackgroundSubtraction backgroundSubtraction, PolarizationCorrections polarizationCorrections, FloodCorrections floodCorrections, TransmissionStitchOptions transmissionStitchOptions, @@ -37,7 +38,7 @@ Experiment::Experiment(AnalysisMode analysisMode, ReductionType reductionType, std::vector<PerThetaDefaults> perThetaDefaults) : m_analysisMode(analysisMode), m_reductionType(reductionType), m_summationType(summationType), m_includePartialBins(includePartialBins), - m_debug(debug), + m_debug(debug), m_backgroundSubtraction(std::move(backgroundSubtraction)), m_polarizationCorrections(std::move(polarizationCorrections)), m_floodCorrections(std::move(floodCorrections)), m_transmissionStitchOptions(std::move(transmissionStitchOptions)), @@ -49,6 +50,11 @@ ReductionType Experiment::reductionType() const { return m_reductionType; } SummationType Experiment::summationType() const { return m_summationType; } bool Experiment::includePartialBins() const { return m_includePartialBins; } bool Experiment::debug() const { return m_debug; } + +BackgroundSubtraction const &Experiment::backgroundSubtraction() const { + return m_backgroundSubtraction; +} + PolarizationCorrections const &Experiment::polarizationCorrections() const { return m_polarizationCorrections; } @@ -119,6 +125,7 @@ bool operator==(Experiment const &lhs, Experiment const &rhs) { lhs.summationType() == rhs.summationType() && lhs.includePartialBins() == rhs.includePartialBins() && lhs.debug() == rhs.debug() && + lhs.backgroundSubtraction() == rhs.backgroundSubtraction() && lhs.polarizationCorrections() == rhs.polarizationCorrections() && lhs.floodCorrections() == rhs.floodCorrections() && lhs.transmissionStitchOptions() == rhs.transmissionStitchOptions() && diff --git a/qt/scientific_interfaces/ISISReflectometry/Reduction/Experiment.h b/qt/scientific_interfaces/ISISReflectometry/Reduction/Experiment.h index 56f9fa8985be3106f10ec296ad45972c49121b30..543a702b0d57761c6103302ccb0bef2a010febf9 100644 --- a/qt/scientific_interfaces/ISISReflectometry/Reduction/Experiment.h +++ b/qt/scientific_interfaces/ISISReflectometry/Reduction/Experiment.h @@ -7,6 +7,7 @@ #pragma once #include "AnalysisMode.h" +#include "BackgroundSubtraction.h" #include "Common/DllConfig.h" #include "FloodCorrections.h" #include "PerThetaDefaults.h" @@ -32,6 +33,7 @@ public: Experiment(); Experiment(AnalysisMode analysisMode, ReductionType reductionType, SummationType summationType, bool includePartialBins, bool debug, + BackgroundSubtraction backgroundSubtraction, PolarizationCorrections polarizationCorrections, FloodCorrections floodCorrections, TransmissionStitchOptions transmissionStitchOptions, @@ -43,6 +45,7 @@ public: SummationType summationType() const; bool includePartialBins() const; bool debug() const; + BackgroundSubtraction const &backgroundSubtraction() const; PolarizationCorrections const &polarizationCorrections() const; FloodCorrections const &floodCorrections() const; TransmissionStitchOptions transmissionStitchOptions() const; @@ -62,6 +65,7 @@ private: bool m_includePartialBins; bool m_debug; + BackgroundSubtraction m_backgroundSubtraction; PolarizationCorrections m_polarizationCorrections; FloodCorrections m_floodCorrections; TransmissionStitchOptions m_transmissionStitchOptions; diff --git a/qt/scientific_interfaces/ISISReflectometry/Reduction/PerThetaDefaults.cpp b/qt/scientific_interfaces/ISISReflectometry/Reduction/PerThetaDefaults.cpp index 068a9e565653ed206e95f196e461d96a412c0012..839805a5b9b995cba8085b340009b91ce59b8b95 100644 --- a/qt/scientific_interfaces/ISISReflectometry/Reduction/PerThetaDefaults.cpp +++ b/qt/scientific_interfaces/ISISReflectometry/Reduction/PerThetaDefaults.cpp @@ -16,13 +16,16 @@ PerThetaDefaults::PerThetaDefaults( TransmissionRunPair transmissionRuns, boost::optional<ProcessingInstructions> transmissionProcessingInstructions, RangeInQ qRange, boost::optional<double> scaleFactor, - boost::optional<ProcessingInstructions> processingInstructions) + boost::optional<ProcessingInstructions> processingInstructions, + boost::optional<ProcessingInstructions> backgroundProcessingInstructions) : m_theta(std::move(theta)), m_transmissionRuns(std::move(transmissionRuns)), m_qRange(std::move(qRange)), m_scaleFactor(std::move(scaleFactor)), m_transmissionProcessingInstructions( std::move(transmissionProcessingInstructions)), - m_processingInstructions(std::move(processingInstructions)) {} + m_processingInstructions(std::move(processingInstructions)), + m_backgroundProcessingInstructions( + std::move(backgroundProcessingInstructions)) {} TransmissionRunPair const & PerThetaDefaults::transmissionWorkspaceNames() const { @@ -51,13 +54,20 @@ PerThetaDefaults::transmissionProcessingInstructions() const { return m_transmissionProcessingInstructions; } +boost::optional<ProcessingInstructions> +PerThetaDefaults::backgroundProcessingInstructions() const { + return m_backgroundProcessingInstructions; +} + bool operator==(PerThetaDefaults const &lhs, PerThetaDefaults const &rhs) { return lhs.thetaOrWildcard() == rhs.thetaOrWildcard() && lhs.qRange() == rhs.qRange() && lhs.scaleFactor() == rhs.scaleFactor() && lhs.transmissionProcessingInstructions() == rhs.transmissionProcessingInstructions() && - lhs.processingInstructions() == rhs.processingInstructions(); + lhs.processingInstructions() == rhs.processingInstructions() && + lhs.backgroundProcessingInstructions() == + rhs.backgroundProcessingInstructions(); } bool operator!=(PerThetaDefaults const &lhs, PerThetaDefaults const &rhs) { @@ -83,6 +93,8 @@ perThetaDefaultsToArray(PerThetaDefaults const &perThetaDefaults) { result[7] = std::to_string(*perThetaDefaults.scaleFactor()); if (perThetaDefaults.processingInstructions()) result[8] = *perThetaDefaults.processingInstructions(); + if (perThetaDefaults.backgroundProcessingInstructions()) + result[9] = *perThetaDefaults.backgroundProcessingInstructions(); return result; } } // namespace ISISReflectometry diff --git a/qt/scientific_interfaces/ISISReflectometry/Reduction/PerThetaDefaults.h b/qt/scientific_interfaces/ISISReflectometry/Reduction/PerThetaDefaults.h index f6fb19c4f1205af7bb19ec779a9c223f797b41f6..aa5fff1a333b4e43de3e4602c052cde888609455 100644 --- a/qt/scientific_interfaces/ISISReflectometry/Reduction/PerThetaDefaults.h +++ b/qt/scientific_interfaces/ISISReflectometry/Reduction/PerThetaDefaults.h @@ -25,7 +25,7 @@ namespace ISISReflectometry { */ class MANTIDQT_ISISREFLECTOMETRY_DLL PerThetaDefaults { public: - static auto constexpr OPTIONS_TABLE_COLUMN_COUNT = 9; + static auto constexpr OPTIONS_TABLE_COLUMN_COUNT = 10; using ValueArray = std::array<std::string, OPTIONS_TABLE_COLUMN_COUNT>; enum Column { @@ -39,7 +39,8 @@ public: QMAX = 5, QSTEP = 6, SCALE = 7, - RUN_SPECTRA = 8 + RUN_SPECTRA = 8, + BACKGROUND_SPECTRA = 9 }; static auto constexpr ColumnPropertyName = @@ -52,14 +53,16 @@ public: "MomentumTransferMax", "MomentumTransferStep", "ScaleFactor", - "ProcessingInstructions"}; + "ProcessingInstructions", + "BackgroundProcessingInstructions"}; PerThetaDefaults( boost::optional<double> theta, TransmissionRunPair tranmissionRuns, boost::optional<ProcessingInstructions> transmissionProcessingInstructions, RangeInQ qRange, boost::optional<double> scaleFactor, - boost::optional<ProcessingInstructions> processingInstructions); + boost::optional<ProcessingInstructions> processingInstructions, + boost::optional<ProcessingInstructions> backgroundProcessingInstructions); TransmissionRunPair const &transmissionWorkspaceNames() const; bool isWildcard() const; @@ -69,6 +72,8 @@ public: boost::optional<ProcessingInstructions> transmissionProcessingInstructions() const; boost::optional<ProcessingInstructions> processingInstructions() const; + boost::optional<ProcessingInstructions> + backgroundProcessingInstructions() const; private: boost::optional<double> m_theta; @@ -77,6 +82,7 @@ private: boost::optional<double> m_scaleFactor; boost::optional<ProcessingInstructions> m_transmissionProcessingInstructions; boost::optional<ProcessingInstructions> m_processingInstructions; + boost::optional<ProcessingInstructions> m_backgroundProcessingInstructions; }; MANTIDQT_ISISREFLECTOMETRY_DLL bool operator==(PerThetaDefaults const &lhs, diff --git a/qt/scientific_interfaces/ISISReflectometry/Reduction/ValidatePerThetaDefaults.cpp b/qt/scientific_interfaces/ISISReflectometry/Reduction/ValidatePerThetaDefaults.cpp index 812ef2fdcabe79bf8dd4a59eb9342d83c519cb48..83c6ebbea60c94e5d3a57a0463ba8cc038485878 100644 --- a/qt/scientific_interfaces/ISISReflectometry/Reduction/ValidatePerThetaDefaults.cpp +++ b/qt/scientific_interfaces/ISISReflectometry/Reduction/ValidatePerThetaDefaults.cpp @@ -106,6 +106,16 @@ PerThetaDefaultsValidator::parseProcessingInstructions( return optionalInstructionsOrNoneIfError; } +boost::optional<boost::optional<std::string>> +PerThetaDefaultsValidator::parseBackgroundProcessingInstructions( + CellText const &cellText) { + auto optionalInstructionsOrNoneIfError = ::MantidQt::CustomInterfaces:: + ISISReflectometry::parseProcessingInstructions(cellText[9]); + if (!optionalInstructionsOrNoneIfError.is_initialized()) + m_invalidColumns.emplace_back(9); + return optionalInstructionsOrNoneIfError; +} + ValidationResult<PerThetaDefaults, std::vector<int>> PerThetaDefaultsValidator:: operator()(CellText const &cellText) { auto maybeTheta = parseThetaOrWhitespace(cellText); @@ -115,10 +125,12 @@ operator()(CellText const &cellText) { auto maybeQRange = parseQRange(cellText); auto maybeScaleFactor = parseScaleFactor(cellText); auto maybeProcessingInstructions = parseProcessingInstructions(cellText); + auto maybeBackgroundProcessingInstructions = + parseBackgroundProcessingInstructions(cellText); auto maybeDefaults = makeIfAllInitialized<PerThetaDefaults>( maybeTheta, maybeTransmissionRuns, maybeTransmissionProcessingInstructions, maybeQRange, maybeScaleFactor, - maybeProcessingInstructions); + maybeProcessingInstructions, maybeBackgroundProcessingInstructions); if (maybeDefaults.is_initialized()) return ValidationResult<PerThetaDefaults, std::vector<int>>( diff --git a/qt/scientific_interfaces/ISISReflectometry/Reduction/ValidatePerThetaDefaults.h b/qt/scientific_interfaces/ISISReflectometry/Reduction/ValidatePerThetaDefaults.h index 9b2dc6eae2fb2b8c157c5feebbd9f26c99527dba..10b515d69aabf47156aeb415f529378bd2559932 100644 --- a/qt/scientific_interfaces/ISISReflectometry/Reduction/ValidatePerThetaDefaults.h +++ b/qt/scientific_interfaces/ISISReflectometry/Reduction/ValidatePerThetaDefaults.h @@ -42,6 +42,9 @@ private: parseOptions(PerThetaDefaults::ValueArray const &cellText); boost::optional<boost::optional<std::string>> parseProcessingInstructions(PerThetaDefaults::ValueArray const &cellText); + boost::optional<boost::optional<std::string>> + parseBackgroundProcessingInstructions( + PerThetaDefaults::ValueArray const &cellText); std::vector<int> m_invalidColumns; }; diff --git a/qt/scientific_interfaces/ISISReflectometry/TestHelpers/ModelCreationHelper.cpp b/qt/scientific_interfaces/ISISReflectometry/TestHelpers/ModelCreationHelper.cpp index 27dc770b73f52e0b09468b276ba172badcbc591c..add99b50fa1848bd24fa6a459ba3244898913085 100644 --- a/qt/scientific_interfaces/ISISReflectometry/TestHelpers/ModelCreationHelper.cpp +++ b/qt/scientific_interfaces/ISISReflectometry/TestHelpers/ModelCreationHelper.cpp @@ -317,27 +317,27 @@ std::vector<PerThetaDefaults> makePerThetaDefaults() { auto perThetaDefaults = PerThetaDefaults(boost::none, TransmissionRunPair(), boost::none, RangeInQ(boost::none, boost::none, boost::none), - boost::none, boost::none); + boost::none, boost::none, boost::none); return std::vector<PerThetaDefaults>{std::move(perThetaDefaults)}; } std::vector<PerThetaDefaults> makePerThetaDefaultsWithTwoAnglesAndWildcard() { return std::vector<PerThetaDefaults>{ // wildcard row with no angle - PerThetaDefaults(boost::none, TransmissionRunPair("22345", "22346"), - ProcessingInstructions("5-6"), - RangeInQ(0.007, 0.01, 1.1), 0.7, - ProcessingInstructions("1")), + PerThetaDefaults( + boost::none, TransmissionRunPair("22345", "22346"), + ProcessingInstructions("5-6"), RangeInQ(0.007, 0.01, 1.1), 0.7, + ProcessingInstructions("1"), ProcessingInstructions("3,7")), // two angle rows PerThetaDefaults(0.5, TransmissionRunPair("22347", ""), boost::none, RangeInQ(0.008, 0.02, 1.2), 0.8, - ProcessingInstructions("2-3")), + ProcessingInstructions("2-3"), boost::none), PerThetaDefaults( 2.3, TransmissionRunPair(std::vector<std::string>{"22348", "22349"}, std::vector<std::string>{"22358", "22359"}), ProcessingInstructions("4"), RangeInQ(0.009, 0.03, 1.3), 0.9, - ProcessingInstructions("4-6"))}; + ProcessingInstructions("4-6"), ProcessingInstructions("2-3,7-8"))}; } std::map<std::string, std::string> makeStitchOptions() { @@ -349,6 +349,15 @@ std::map<std::string, std::string> makeEmptyStitchOptions() { return std::map<std::string, std::string>(); } +BackgroundSubtraction makeBackgroundSubtraction() { + return BackgroundSubtraction(true, BackgroundSubtractionType::Polynomial, 3, + CostFunctionType::UnweightedLeastSquares); +} + +BackgroundSubtraction makeEmptyBackgroundSubtraction() { + return BackgroundSubtraction(); +} + PolarizationCorrections makePolarizationCorrections() { return PolarizationCorrections(PolarizationCorrectionType::ParameterFile); } @@ -374,14 +383,16 @@ TransmissionStitchOptions makeEmptyTransmissionStitchOptions() { Experiment makeExperiment() { return Experiment(AnalysisMode::MultiDetector, ReductionType::NonFlatSample, SummationType::SumInQ, true, true, - makePolarizationCorrections(), makeFloodCorrections(), - makeTransmissionStitchOptions(), makeStitchOptions(), + makeBackgroundSubtraction(), makePolarizationCorrections(), + makeFloodCorrections(), makeTransmissionStitchOptions(), + makeStitchOptions(), makePerThetaDefaultsWithTwoAnglesAndWildcard()); } Experiment makeEmptyExperiment() { return Experiment(AnalysisMode::PointDetector, ReductionType::Normal, SummationType::SumInLambda, false, false, + makeEmptyBackgroundSubtraction(), PolarizationCorrections(PolarizationCorrectionType::None), FloodCorrections(FloodCorrectionType::Workspace), TransmissionStitchOptions(), diff --git a/qt/scientific_interfaces/ISISReflectometry/TestHelpers/ModelCreationHelper.h b/qt/scientific_interfaces/ISISReflectometry/TestHelpers/ModelCreationHelper.h index 3f5c620484defbfa4134a9fd5237ed571174776b..889ef446fb45803f92258e70acf8367ba0d35556 100644 --- a/qt/scientific_interfaces/ISISReflectometry/TestHelpers/ModelCreationHelper.h +++ b/qt/scientific_interfaces/ISISReflectometry/TestHelpers/ModelCreationHelper.h @@ -82,11 +82,15 @@ MANTIDQT_ISISREFLECTOMETRY_DLL std::map<std::string, std::string> makeStitchOptions(); MANTIDQT_ISISREFLECTOMETRY_DLL std::map<std::string, std::string> makeEmptyStitchOptions(); +MANTIDQT_ISISREFLECTOMETRY_DLL BackgroundSubtraction +makeBackgroundSubtraction(); MANTIDQT_ISISREFLECTOMETRY_DLL PolarizationCorrections makePolarizationCorrections(); MANTIDQT_ISISREFLECTOMETRY_DLL PolarizationCorrections makeEmptyPolarizationCorrections(); MANTIDQT_ISISREFLECTOMETRY_DLL FloodCorrections makeFloodCorrections(); +MANTIDQT_ISISREFLECTOMETRY_DLL TransmissionStitchOptions +makeTransmissionStitchOptions(); MANTIDQT_ISISREFLECTOMETRY_DLL RangeInLambda makeTransmissionRunRange(); MANTIDQT_ISISREFLECTOMETRY_DLL TransmissionStitchOptions makeEmptyTransmissionStitchOptions(); @@ -104,4 +108,4 @@ MANTIDQT_ISISREFLECTOMETRY_DLL Instrument makeEmptyInstrument(); } // namespace ModelCreationHelper } // namespace ISISReflectometry } // namespace CustomInterfaces -} // namespace MantidQt \ No newline at end of file +} // namespace MantidQt diff --git a/qt/scientific_interfaces/test/ISISReflectometry/Batch/GroupProcessingAlgorithmTest.h b/qt/scientific_interfaces/test/ISISReflectometry/Batch/GroupProcessingAlgorithmTest.h index 95077a7bf446636fe9f5a8421fabd3862a6d6b81..767c70f0506e707bbb5ac46dad50ff2e23dd5956 100644 --- a/qt/scientific_interfaces/test/ISISReflectometry/Batch/GroupProcessingAlgorithmTest.h +++ b/qt/scientific_interfaces/test/ISISReflectometry/Batch/GroupProcessingAlgorithmTest.h @@ -72,13 +72,13 @@ public: } void testStitchParamsSetFromStitchingOptions() { - auto experiment = - Experiment(AnalysisMode::PointDetector, ReductionType::Normal, - SummationType::SumInLambda, false, false, - PolarizationCorrections(PolarizationCorrectionType::None), - FloodCorrections(FloodCorrectionType::Workspace), - TransmissionStitchOptions(), makeStitchOptions(), - std::vector<PerThetaDefaults>()); + auto experiment = Experiment( + AnalysisMode::PointDetector, ReductionType::Normal, + SummationType::SumInLambda, false, false, BackgroundSubtraction(), + PolarizationCorrections(PolarizationCorrectionType::None), + FloodCorrections(FloodCorrectionType::Workspace), + TransmissionStitchOptions(), makeStitchOptions(), + std::vector<PerThetaDefaults>()); auto model = Batch(experiment, m_instrument, m_runsTable, m_slicing); auto group = makeGroupWithTwoRows(); auto result = createAlgorithmRuntimeProps(model, group); @@ -90,7 +90,7 @@ public: void testPerThetaDefaultsQResolutionUsedForParamsIfStitchingOptionsEmpty() { auto experiment = Experiment( AnalysisMode::PointDetector, ReductionType::Normal, - SummationType::SumInLambda, false, false, + SummationType::SumInLambda, false, false, BackgroundSubtraction(), PolarizationCorrections(PolarizationCorrectionType::None), FloodCorrections(FloodCorrectionType::Workspace), TransmissionStitchOptions(), std::map<std::string, std::string>(), @@ -104,7 +104,7 @@ public: void testQResolutionForFirstValidRowUsedForParamsIfStitchingOptionsEmpty() { auto experiment = Experiment( AnalysisMode::PointDetector, ReductionType::Normal, - SummationType::SumInLambda, false, false, + SummationType::SumInLambda, false, false, BackgroundSubtraction(), PolarizationCorrections(PolarizationCorrectionType::None), FloodCorrections(FloodCorrectionType::Workspace), TransmissionStitchOptions(), std::map<std::string, std::string>(), @@ -119,7 +119,7 @@ public: testQOutputResolutionForFirstValidRowUsedForParamsIfStitchingOptionsEmpty() { auto experiment = Experiment( AnalysisMode::PointDetector, ReductionType::Normal, - SummationType::SumInLambda, false, false, + SummationType::SumInLambda, false, false, BackgroundSubtraction(), PolarizationCorrections(PolarizationCorrectionType::None), FloodCorrections(FloodCorrectionType::Workspace), TransmissionStitchOptions(), std::map<std::string, std::string>(), @@ -137,4 +137,4 @@ private: Instrument m_instrument; RunsTable m_runsTable; Slicing m_slicing; -}; \ No newline at end of file +}; diff --git a/qt/scientific_interfaces/test/ISISReflectometry/Batch/RowProcessingAlgorithmTest.h b/qt/scientific_interfaces/test/ISISReflectometry/Batch/RowProcessingAlgorithmTest.h index ebc42bd3d4060e4c748a2e10faff5a4521ed934c..dd7b8d936e4a42b19fa50863b0f77eede3bb30af 100644 --- a/qt/scientific_interfaces/test/ISISReflectometry/Batch/RowProcessingAlgorithmTest.h +++ b/qt/scientific_interfaces/test/ISISReflectometry/Batch/RowProcessingAlgorithmTest.h @@ -39,6 +39,10 @@ public: TS_ASSERT_EQUALS(result["SummationType"], "SumInQ"); TS_ASSERT_EQUALS(result["IncludePartialBins"], "1"); TS_ASSERT_EQUALS(result["Debug"], "1"); + TS_ASSERT_EQUALS(result["SubtractBackground"], "1"); + TS_ASSERT_EQUALS(result["BackgroundCalculationMethod"], "Polynomial"); + TS_ASSERT_EQUALS(result["DegreeOfPolynomial"], "3"); + TS_ASSERT_EQUALS(result["CostFunction"], "Unweighted least squares"); TS_ASSERT_EQUALS(result["PolarizationAnalysis"], "1"); TS_ASSERT_EQUALS(result["FloodCorrection"], "Workspace"); TS_ASSERT_EQUALS(result["FloodWorkspace"], "test_workspace"); @@ -57,6 +61,10 @@ public: TS_ASSERT_EQUALS(result["SummationType"], "SumInQ"); TS_ASSERT_EQUALS(result["IncludePartialBins"], "1"); TS_ASSERT_EQUALS(result["Debug"], "1"); + TS_ASSERT_EQUALS(result["SubtractBackground"], "1"); + TS_ASSERT_EQUALS(result["BackgroundCalculationMethod"], "Polynomial"); + TS_ASSERT_EQUALS(result["DegreeOfPolynomial"], "3"); + TS_ASSERT_EQUALS(result["CostFunction"], "Unweighted least squares"); TS_ASSERT_EQUALS(result["PolarizationAnalysis"], "1"); TS_ASSERT_EQUALS(result["FloodCorrection"], "Workspace"); TS_ASSERT_EQUALS(result["FloodWorkspace"], "test_workspace"); @@ -77,6 +85,7 @@ public: TS_ASSERT_EQUALS(result["MomentumTransferMax"], "1.300000"); TS_ASSERT_EQUALS(result["ScaleFactor"], "0.900000"); TS_ASSERT_EQUALS(result["ProcessingInstructions"], "4-6"); + TS_ASSERT_EQUALS(result["BackgroundProcessingInstructions"], "2-3,7-8"); } void testPerThetaDefaultsWithWildcardLookup() { @@ -92,6 +101,7 @@ public: TS_ASSERT_EQUALS(result["MomentumTransferMax"], "1.100000"); TS_ASSERT_EQUALS(result["ScaleFactor"], "0.700000"); TS_ASSERT_EQUALS(result["ProcessingInstructions"], "1"); + TS_ASSERT_EQUALS(result["BackgroundProcessingInstructions"], "3,7"); } void testInstrumentSettings() { @@ -216,6 +226,25 @@ public: TS_ASSERT_EQUALS(result["WavelengthMin"], "3.3"); } + void testOptionsCellOverridesSubtractBackgroundAndStillPicksUpSettings() { + auto experiment = Experiment( + AnalysisMode::MultiDetector, ReductionType::NonFlatSample, + SummationType::SumInQ, true, true, + BackgroundSubtraction(false, BackgroundSubtractionType::AveragePixelFit, + 3, CostFunctionType::UnweightedLeastSquares), + makePolarizationCorrections(), makeFloodCorrections(), + makeTransmissionStitchOptions(), makeStitchOptions(), + makePerThetaDefaultsWithTwoAnglesAndWildcard()); + auto model = Batch(experiment, m_instrument, m_runsTable, m_slicing); + auto row = makeRowWithOptionsCellFilled( + 2.3, ReductionOptionsMap{{"SubtractBackground", "1"}}); + auto result = createAlgorithmRuntimeProps(model, row); + TS_ASSERT_EQUALS(result["SubtractBackground"], "1"); + TS_ASSERT_EQUALS(result["BackgroundCalculationMethod"], "AveragePixelFit"); + TS_ASSERT_EQUALS(result["DegreeOfPolynomial"], "3"); + TS_ASSERT_EQUALS(result["CostFunction"], "Unweighted least squares"); + } + private: std::vector<std::string> m_instruments; double m_thetaTolerance; @@ -223,4 +252,4 @@ private: Instrument m_instrument; RunsTable m_runsTable; Slicing m_slicing; -}; \ No newline at end of file +}; diff --git a/qt/scientific_interfaces/test/ISISReflectometry/Common/CoderCommonTester.h b/qt/scientific_interfaces/test/ISISReflectometry/Common/CoderCommonTester.h index 93ef2330d0f6e39a8bb935ccdced8fd3956bee2e..9bdfc19d2d2619be04a7f071e423367820bb5469 100644 --- a/qt/scientific_interfaces/test/ISISReflectometry/Common/CoderCommonTester.h +++ b/qt/scientific_interfaces/test/ISISReflectometry/Common/CoderCommonTester.h @@ -86,6 +86,14 @@ private: map[QString("transStitchParamsEdit")].toString()) TS_ASSERT_EQUALS(gui->m_ui.transScaleRHSCheckBox->isChecked(), map[QString("transScaleRHSCheckBox")].toBool()) + TS_ASSERT_EQUALS(gui->m_ui.subtractBackgroundCheckBox->isChecked(), + map[QString("subtractBackgroundCheckBox")].toBool()) + TS_ASSERT_EQUALS(gui->m_ui.backgroundMethodComboBox->currentIndex(), + map[QString("backgroundMethodComboBox")].toInt()) + TS_ASSERT_EQUALS(gui->m_ui.polynomialDegreeSpinBox->value(), + map[QString("polynomialDegreeSpinBox")].toInt()) + TS_ASSERT_EQUALS(gui->m_ui.costFunctionComboBox->currentIndex(), + map[QString("costFunctionComboBox")].toInt()) TS_ASSERT_EQUALS(gui->m_ui.polCorrCheckBox->isChecked(), map[QString("polCorrCheckBox")].toBool()) TS_ASSERT_EQUALS(gui->m_ui.floodCorComboBox->currentIndex(), diff --git a/qt/scientific_interfaces/test/ISISReflectometry/Common/DecoderTest.h b/qt/scientific_interfaces/test/ISISReflectometry/Common/DecoderTest.h index 858234a8e24176804f5d5ed61bb5e601870a69d0..fe24aeabf53a222c1582860e819556a0244c3152 100644 --- a/qt/scientific_interfaces/test/ISISReflectometry/Common/DecoderTest.h +++ b/qt/scientific_interfaces/test/ISISReflectometry/Common/DecoderTest.h @@ -35,13 +35,15 @@ const static QString BATCH_JSON_STRING{ " }," " \"experimentView\": {" " \"analysisModeComboBox\": 1," + " \"backgroundMethodComboBox\": 1," + " \"costFunctionComboBox\": 1," " \"debugCheckbox\": true," " \"endOverlapEdit\": 13," " \"floodCorComboBox\": 1," " \"floodWorkspaceWsSelector\": 0," " \"includePartialBinsCheckBox\": true," " \"perAngleDefaults\": {" - " \"columnsNum\": 9," + " \"columnsNum\": 10," " \"rows\": [" " [" " \"0.5\"," @@ -52,15 +54,18 @@ const static QString BATCH_JSON_STRING{ " \"0.1\"," " \"0.02\"," " \"\"," - " \"4\"" + " \"4\"," + " \"5\"" " ]" " ]," " \"rowsNum\": 1" " }," " \"polCorrCheckBox\": false," + " \"polynomialDegreeSpinBox\": 3," " \"reductionTypeComboBox\": 2," " \"startOverlapEdit\": 8," " \"stitchEdit\": \"Params=0.015\"," + " \"subtractBackgroundCheckBox\": true," " \"summationTypeComboBox\": 1," " \"transScaleRHSCheckBox\": false," " \"transStitchParamsEdit\": \"0.03\"" @@ -320,13 +325,15 @@ const static QString EMPTY_BATCH_JSON_STRING{ " }," " \"experimentView\": {" " \"analysisModeComboBox\": 0," + " \"backgroundMethodComboBox\": 0," + " \"costFunctionComboBox\": 0," " \"debugCheckbox\": false," " \"endOverlapEdit\": 12," " \"floodCorComboBox\": 0," " \"floodWorkspaceWsSelector\": 0," " \"includePartialBinsCheckBox\": false," " \"perAngleDefaults\": {" - " \"columnsNum\": 9," + " \"columnsNum\": 10," " \"rows\": [" " [" " \"\"," @@ -337,15 +344,18 @@ const static QString EMPTY_BATCH_JSON_STRING{ " \"\"," " \"\"," " \"\"," + " \"\"," " \"\"" " ]" " ]," " \"rowsNum\": 1" " }," " \"polCorrCheckBox\": false," + " \"polynomialDegreeSpinBox\": 3," " \"reductionTypeComboBox\": 0," " \"startOverlapEdit\": 10," " \"stitchEdit\": \"\"," + " \"subtractBackgroundCheckBox\": false," " \"summationTypeComboBox\": 0," " \"transScaleRHSCheckBox\": true," " \"transStitchParamsEdit\": \"\"" diff --git a/qt/scientific_interfaces/test/ISISReflectometry/Experiment/ExperimentOptionDefaultsTest.h b/qt/scientific_interfaces/test/ISISReflectometry/Experiment/ExperimentOptionDefaultsTest.h index 48eaa9b9e649ffbaa61a5e3af9a15eb4c95ed522..0f597d01f0889fb39bfc431a7deead58b7beac7a 100644 --- a/qt/scientific_interfaces/test/ISISReflectometry/Experiment/ExperimentOptionDefaultsTest.h +++ b/qt/scientific_interfaces/test/ISISReflectometry/Experiment/ExperimentOptionDefaultsTest.h @@ -83,16 +83,17 @@ public: auto expected = PerThetaDefaults(boost::none, TransmissionRunPair(), boost::none, RangeInQ(boost::none, boost::none, boost::none), - boost::none, boost::none); + boost::none, boost::none, boost::none); TS_ASSERT_EQUALS(result.perThetaDefaults().size(), 1); TS_ASSERT_EQUALS(result.perThetaDefaults().front(), expected); } void testValidPerThetaOptionsFromParamsFile() { auto result = getDefaultsFromParamsFile("Experiment"); - auto expected = PerThetaDefaults(boost::none, TransmissionRunPair(), - boost::none, RangeInQ(0.01, 0.03, 0.2), - 0.7, std::string("390-415")); + auto expected = + PerThetaDefaults(boost::none, TransmissionRunPair(), boost::none, + RangeInQ(0.01, 0.03, 0.2), 0.7, std::string("390-415"), + std::string("370-389,416-430")); TS_ASSERT_EQUALS(result.perThetaDefaults().size(), 1); TS_ASSERT_EQUALS(result.perThetaDefaults().front(), expected); } @@ -119,6 +120,31 @@ public: getDefaultsFromParamsFileThrows("TransmissionRunRange_Invalid"); } + void testDefaultSubtractionOptions() { + auto result = getDefaults(); + TS_ASSERT_EQUALS(result.backgroundSubtraction().subtractBackground(), + false); + TS_ASSERT_EQUALS(result.backgroundSubtraction().subtractionType(), + BackgroundSubtractionType::PerDetectorAverage); + TS_ASSERT_EQUALS(result.backgroundSubtraction().degreeOfPolynomial(), 0); + TS_ASSERT_EQUALS(result.backgroundSubtraction().costFunction(), + CostFunctionType::LeastSquares); + } + + void testValidSubtractionOptionsFromParamsFile() { + auto result = getDefaultsFromParamsFile("Experiment"); + TS_ASSERT_EQUALS(result.backgroundSubtraction().subtractBackground(), true); + TS_ASSERT_EQUALS(result.backgroundSubtraction().subtractionType(), + BackgroundSubtractionType::Polynomial); + TS_ASSERT_EQUALS(result.backgroundSubtraction().degreeOfPolynomial(), 2); + TS_ASSERT_EQUALS(result.backgroundSubtraction().costFunction(), + CostFunctionType::UnweightedLeastSquares); + } + + void testInvalidSubtractionOptionsFromParamsFile() { + getDefaultsFromParamsFileThrows("Subtraction_Invalid"); + } + void testDefaultCorrectionOptions() { auto result = getDefaults(); TS_ASSERT_EQUALS(result.polarizationCorrections().correctionType(), diff --git a/qt/scientific_interfaces/test/ISISReflectometry/Experiment/ExperimentPresenterTest.h b/qt/scientific_interfaces/test/ISISReflectometry/Experiment/ExperimentPresenterTest.h index 15bc9f560a104312935950d273a25b9b5d80c6a2..b1e9b6369ad2569e00351b0c76d4c0c055dc3077 100644 --- a/qt/scientific_interfaces/test/ISISReflectometry/Experiment/ExperimentPresenterTest.h +++ b/qt/scientific_interfaces/test/ISISReflectometry/Experiment/ExperimentPresenterTest.h @@ -161,6 +161,68 @@ public: verifyAndClear(); } + void testSetBackgroundSubtractionUpdatesModel() { + auto presenter = makePresenter(); + expectSubtractBackground(); + presenter.notifySettingsChanged(); + assertBackgroundSubtractionOptionsSet(presenter); + verifyAndClear(); + } + + void + testBackgroundSubtractionMethodIsEnabledWhenSubtractBackgroundIsChecked() { + auto presenter = makePresenter(); + expectSubtractBackground(true); + EXPECT_CALL(m_view, enableBackgroundSubtractionMethod()).Times(1); + presenter.notifySettingsChanged(); + verifyAndClear(); + } + + void testPolynomialInputsEnabledWhenSubtractingPolynomialBackground() { + auto presenter = makePresenter(); + expectSubtractBackground(true, "Polynomial"); + EXPECT_CALL(m_view, enablePolynomialDegree()).Times(1); + EXPECT_CALL(m_view, enableCostFunction()).Times(1); + presenter.notifySettingsChanged(); + verifyAndClear(); + } + + void testPolynomialInputsDisabledWhenSubtractingPerDetectorAverage() { + auto presenter = makePresenter(); + expectSubtractBackground(true, "PerDetectorAverage"); + EXPECT_CALL(m_view, disablePolynomialDegree()).Times(1); + EXPECT_CALL(m_view, disableCostFunction()).Times(1); + presenter.notifySettingsChanged(); + verifyAndClear(); + } + + void testPolynomialInputsDisabledWhenSubtractingAveragePixelFit() { + auto presenter = makePresenter(); + expectSubtractBackground(true, "AveragePixelFit"); + EXPECT_CALL(m_view, disablePolynomialDegree()).Times(1); + EXPECT_CALL(m_view, disableCostFunction()).Times(1); + presenter.notifySettingsChanged(); + verifyAndClear(); + } + + void testBackgroundSubtractionInputsDisabledWhenOptionTurnedOff() { + auto presenter = makePresenter(); + expectSubtractBackground(false); + EXPECT_CALL(m_view, disableBackgroundSubtractionMethod()).Times(1); + EXPECT_CALL(m_view, disablePolynomialDegree()).Times(1); + EXPECT_CALL(m_view, disableCostFunction()).Times(1); + presenter.notifySettingsChanged(); + verifyAndClear(); + } + + void testTogglePolarizationCorrectionOptionUpdatesModel() { + auto presenter = makePresenter(); + expectPolarizationAnalysisOn(); + presenter.notifySettingsChanged(); + assertPolarizationAnalysisOn(presenter); + verifyAndClear(); + } + void testSetFloodCorrectionsUpdatesModel() { auto presenter = makePresenter(); FloodCorrections floodCorr(FloodCorrectionType::Workspace, @@ -458,6 +520,19 @@ public: PerThetaDefaults::Column::RUN_SPECTRA); } + void testSetBackgroundProcessingInstructionsValid() { + OptionsTable const optionsTable = { + optionsRowWithBackgroundProcessingInstructions()}; + runTestForValidPerAngleOptions(optionsTable); + } + + void testSetBackgroundProcessingInstructionsInvalid() { + OptionsTable const optionsTable = { + optionsRowWithBackgroundProcessingInstructionsInvalid()}; + runTestForInvalidPerAngleOptions( + optionsTable, 0, PerThetaDefaults::Column::BACKGROUND_SPECTRA); + } + void testChangingSettingsNotifiesMainPresenter() { auto presenter = makePresenter(); EXPECT_CALL(m_mainPresenter, notifySettingsChanged()).Times(AtLeast(1)); @@ -543,30 +618,33 @@ public: } void testInstrumentChangedUpdatesPerThetaInView() { - auto perThetaDefaults = PerThetaDefaults( - boost::none, TransmissionRunPair(), boost::none, - RangeInQ(0.01, 0.03, 0.2), 0.7, std::string("390-415")); + auto perThetaDefaults = + PerThetaDefaults(boost::none, TransmissionRunPair(), boost::none, + RangeInQ(0.01, 0.03, 0.2), 0.7, std::string("390-415"), + std::string("370-389,416-430")); auto model = makeModelWithPerThetaDefaults(std::move(perThetaDefaults)); auto defaultOptions = expectDefaults(model); auto presenter = makePresenter(std::move(defaultOptions)); auto const expected = std::vector<PerThetaDefaults::ValueArray>{ {"", "", "", "", "0.010000", "0.200000", "0.030000", "0.700000", - "390-415"}}; + "390-415", "370-389,416-430"}}; EXPECT_CALL(m_view, setPerAngleOptions(expected)).Times(1); presenter.notifyInstrumentChanged("POLREF"); verifyAndClear(); } void testInstrumentChangedUpdatesPerThetaInModel() { - auto model = makeModelWithPerThetaDefaults(PerThetaDefaults( - boost::none, TransmissionRunPair(), boost::none, - RangeInQ(0.01, 0.03, 0.2), 0.7, std::string("390-415"))); + auto model = makeModelWithPerThetaDefaults( + PerThetaDefaults(boost::none, TransmissionRunPair(), boost::none, + RangeInQ(0.01, 0.03, 0.2), 0.7, std::string("390-415"), + std::string("370-389,416-430"))); auto defaultOptions = expectDefaults(model); auto presenter = makePresenter(std::move(defaultOptions)); presenter.notifyInstrumentChanged("POLREF"); - auto expected = PerThetaDefaults(boost::none, TransmissionRunPair(), - boost::none, RangeInQ(0.01, 0.03, 0.2), - 0.7, std::string("390-415")); + auto expected = + PerThetaDefaults(boost::none, TransmissionRunPair(), boost::none, + RangeInQ(0.01, 0.03, 0.2), 0.7, std::string("390-415"), + std::string("370-389,416-430")); TS_ASSERT_EQUALS(presenter.experiment().perThetaDefaults().size(), 1); TS_ASSERT_EQUALS(presenter.experiment().perThetaDefaults().front(), expected); @@ -599,11 +677,16 @@ public: void testInstrumentChangedUpdatesCorrectionInView() { auto model = makeModelWithCorrections( PolarizationCorrections(PolarizationCorrectionType::ParameterFile), - FloodCorrections(FloodCorrectionType::ParameterFile)); + FloodCorrections(FloodCorrectionType::ParameterFile), + makeBackgroundSubtraction()); auto defaultOptions = expectDefaults(model); auto presenter = makePresenter(std::move(defaultOptions)); EXPECT_CALL(m_view, setPolarizationCorrectionOption(true)).Times(1); EXPECT_CALL(m_view, setFloodCorrectionType("ParameterFile")).Times(1); + EXPECT_CALL(m_view, setSubtractBackground(true)); + EXPECT_CALL(m_view, setBackgroundSubtractionMethod("Polynomial")); + EXPECT_CALL(m_view, setPolynomialDegree(3)); + EXPECT_CALL(m_view, setCostFunction("Unweighted least squares")); presenter.notifyInstrumentChanged("POLREF"); verifyAndClear(); } @@ -611,15 +694,14 @@ public: void testInstrumentChangedUpdatesCorrectionInModel() { auto model = makeModelWithCorrections( PolarizationCorrections(PolarizationCorrectionType::ParameterFile), - FloodCorrections(FloodCorrectionType::ParameterFile)); + FloodCorrections(FloodCorrectionType::ParameterFile), + makeBackgroundSubtraction()); auto defaultOptions = expectDefaults(model); auto presenter = makePresenter(std::move(defaultOptions)); presenter.notifyInstrumentChanged("POLREF"); - TS_ASSERT_EQUALS( - presenter.experiment().polarizationCorrections().correctionType(), - PolarizationCorrectionType::ParameterFile); - TS_ASSERT_EQUALS(presenter.experiment().floodCorrections().correctionType(), - FloodCorrectionType::ParameterFile); + assertBackgroundSubtractionOptionsSet(presenter); + assertPolarizationAnalysisOn(presenter); + assertFloodCorrectionUsesParameterFile(presenter); verifyAndClear(); } @@ -660,45 +742,46 @@ private: Experiment makeModelWithAnalysisMode(AnalysisMode analysisMode) { return Experiment( analysisMode, ReductionType::Normal, SummationType::SumInLambda, false, - false, makeEmptyPolarizationCorrections(), makeFloodCorrections(), - makeEmptyTransmissionStitchOptions(), makeEmptyStitchOptions(), - makePerThetaDefaults()); + false, BackgroundSubtraction(), makeEmptyPolarizationCorrections(), + makeFloodCorrections(), makeEmptyTransmissionStitchOptions(), + makeEmptyStitchOptions(), makePerThetaDefaults()); } Experiment makeModelWithReduction(SummationType summationType, ReductionType reductionType, bool includePartialBins) { - return Experiment( - AnalysisMode::PointDetector, reductionType, summationType, - includePartialBins, false, makeEmptyPolarizationCorrections(), - makeFloodCorrections(), makeEmptyTransmissionStitchOptions(), - makeEmptyStitchOptions(), makePerThetaDefaults()); - } - - Experiment makeModelWithDebug(bool debug) { - return Experiment(AnalysisMode::PointDetector, ReductionType::Normal, - SummationType::SumInLambda, false, debug, + return Experiment(AnalysisMode::PointDetector, reductionType, summationType, + includePartialBins, false, BackgroundSubtraction(), makeEmptyPolarizationCorrections(), makeFloodCorrections(), makeEmptyTransmissionStitchOptions(), makeEmptyStitchOptions(), makePerThetaDefaults()); } + Experiment makeModelWithDebug(bool debug) { + return Experiment( + AnalysisMode::PointDetector, ReductionType::Normal, + SummationType::SumInLambda, false, debug, BackgroundSubtraction(), + makeEmptyPolarizationCorrections(), makeFloodCorrections(), + makeEmptyTransmissionStitchOptions(), makeEmptyStitchOptions(), + makePerThetaDefaults()); + } + Experiment makeModelWithPerThetaDefaults(PerThetaDefaults perThetaDefaults) { auto perThetaList = std::vector<PerThetaDefaults>(); perThetaList.emplace_back(std::move(perThetaDefaults)); - return Experiment(AnalysisMode::PointDetector, ReductionType::Normal, - SummationType::SumInLambda, false, false, - makeEmptyPolarizationCorrections(), - makeFloodCorrections(), - makeEmptyTransmissionStitchOptions(), - makeEmptyStitchOptions(), std::move(perThetaList)); + return Experiment( + AnalysisMode::PointDetector, ReductionType::Normal, + SummationType::SumInLambda, false, false, BackgroundSubtraction(), + makeEmptyPolarizationCorrections(), makeFloodCorrections(), + makeEmptyTransmissionStitchOptions(), makeEmptyStitchOptions(), + std::move(perThetaList)); } Experiment makeModelWithTransmissionRunRange(RangeInLambda range) { return Experiment( AnalysisMode::PointDetector, ReductionType::Normal, - SummationType::SumInLambda, false, false, + SummationType::SumInLambda, false, false, BackgroundSubtraction(), makeEmptyPolarizationCorrections(), makeFloodCorrections(), TransmissionStitchOptions(std::move(range), std::string(), false), makeEmptyStitchOptions(), makePerThetaDefaults()); @@ -706,13 +789,14 @@ private: Experiment makeModelWithCorrections(PolarizationCorrections polarizationCorrections, - FloodCorrections floodCorrections) { - return Experiment(AnalysisMode::PointDetector, ReductionType::Normal, - SummationType::SumInLambda, false, false, - std::move(polarizationCorrections), - std::move(floodCorrections), - makeEmptyTransmissionStitchOptions(), - makeEmptyStitchOptions(), makePerThetaDefaults()); + FloodCorrections floodCorrections, + BackgroundSubtraction backgroundSubtraction) { + return Experiment( + AnalysisMode::PointDetector, ReductionType::Normal, + SummationType::SumInLambda, false, false, + std::move(backgroundSubtraction), std::move(polarizationCorrections), + std::move(floodCorrections), makeEmptyTransmissionStitchOptions(), + makeEmptyStitchOptions(), makePerThetaDefaults()); } ExperimentPresenter @@ -760,6 +844,65 @@ private: .WillOnce(Return(std::string("DivergentBeam"))); } + void expectSubtractBackground( + bool subtractBackground = true, + std::string const &subtractionType = std::string("Polynomial"), + int degreeOfPolynomial = 3, + std::string const &costFunction = + std::string("Unweighted least squares")) { + EXPECT_CALL(m_view, getSubtractBackground()) + .Times(AtLeast(1)) + .WillRepeatedly(Return(subtractBackground)); + EXPECT_CALL(m_view, getBackgroundSubtractionMethod()) + .Times(AtLeast(1)) + .WillRepeatedly(Return(subtractionType)); + EXPECT_CALL(m_view, getPolynomialDegree()) + .Times(1) + .WillRepeatedly(Return(degreeOfPolynomial)); + EXPECT_CALL(m_view, getCostFunction()) + .Times(1) + .WillRepeatedly(Return(costFunction)); + } + + void assertBackgroundSubtractionOptionsSet( + ExperimentPresenter const &presenter, bool subtractBackground = true, + BackgroundSubtractionType subtractionType = + BackgroundSubtractionType::Polynomial, + int degreeOfPolynomial = 3, + CostFunctionType costFunction = + CostFunctionType::UnweightedLeastSquares) { + TS_ASSERT_EQUALS( + presenter.experiment().backgroundSubtraction().subtractBackground(), + subtractBackground); + TS_ASSERT_EQUALS( + presenter.experiment().backgroundSubtraction().subtractionType(), + subtractionType); + TS_ASSERT_EQUALS( + presenter.experiment().backgroundSubtraction().degreeOfPolynomial(), + degreeOfPolynomial); + TS_ASSERT_EQUALS( + presenter.experiment().backgroundSubtraction().costFunction(), + costFunction); + } + + void expectPolarizationAnalysisOn() { + EXPECT_CALL(m_view, getPolarizationCorrectionOption()) + .Times(AtLeast(1)) + .WillRepeatedly(Return(true)); + } + + void assertPolarizationAnalysisOn(ExperimentPresenter const &presenter) { + TS_ASSERT_EQUALS( + presenter.experiment().polarizationCorrections().correctionType(), + PolarizationCorrectionType::ParameterFile); + } + + void + assertFloodCorrectionUsesParameterFile(ExperimentPresenter const &presenter) { + TS_ASSERT_EQUALS(presenter.experiment().floodCorrections().correctionType(), + FloodCorrectionType::ParameterFile); + } + std::unique_ptr<MockExperimentOptionDefaults> expectDefaults(Experiment const &model) { // Create a defaults object, set expectations on it, and return it so @@ -853,13 +996,14 @@ private: OptionsRow optionsRowWithFirstAngle() { return {"0.5", "13463", ""}; } PerThetaDefaults defaultsWithFirstAngle() { return PerThetaDefaults(0.5, TransmissionRunPair("13463", ""), boost::none, - RangeInQ(), boost::none, boost::none); + RangeInQ(), boost::none, boost::none, boost::none); } OptionsRow optionsRowWithSecondAngle() { return {"2.3", "13463", "13464"}; } PerThetaDefaults defaultsWithSecondAngle() { return PerThetaDefaults(2.3, TransmissionRunPair("13463", "13464"), - boost::none, RangeInQ(), boost::none, boost::none); + boost::none, RangeInQ(), boost::none, boost::none, + boost::none); } OptionsRow optionsRowWithWildcard() { return {"", "13463", "13464"}; } OptionsRow optionsRowWithFirstTransmissionRun() { return {"", "13463"}; } @@ -893,6 +1037,12 @@ private: OptionsRow optionsRowWithProcessingInstructionsInvalid() { return {"", "", "", "", "", "", "", "", "bad"}; } + OptionsRow optionsRowWithBackgroundProcessingInstructions() { + return {"", "", "", "", "", "", "", "", "", "1-4"}; + } + OptionsRow optionsRowWithBackgroundProcessingInstructionsInvalid() { + return {"", "", "", "", "", "", "", "", "", "bad"}; + } void runTestForValidPerAngleOptions(OptionsTable const &optionsTable) { auto presenter = makePresenter(); diff --git a/qt/scientific_interfaces/test/ISISReflectometry/Experiment/MockExperimentView.h b/qt/scientific_interfaces/test/ISISReflectometry/Experiment/MockExperimentView.h index c2405ca043b4831fe603e1688cb227c180693465..86f544d68f874facd062df51342b64cdafaf1e08 100644 --- a/qt/scientific_interfaces/test/ISISReflectometry/Experiment/MockExperimentView.h +++ b/qt/scientific_interfaces/test/ISISReflectometry/Experiment/MockExperimentView.h @@ -58,6 +58,22 @@ public: MOCK_METHOD0(showAllPerAngleOptionsAsValid, void()); MOCK_METHOD0(showStitchParametersValid, void()); MOCK_METHOD0(showStitchParametersInvalid, void()); + + MOCK_CONST_METHOD0(getSubtractBackground, bool()); + MOCK_METHOD1(setSubtractBackground, void(bool)); + MOCK_CONST_METHOD0(getBackgroundSubtractionMethod, std::string()); + MOCK_METHOD1(setBackgroundSubtractionMethod, void(std::string const &)); + MOCK_METHOD0(enableBackgroundSubtractionMethod, void()); + MOCK_METHOD0(disableBackgroundSubtractionMethod, void()); + MOCK_CONST_METHOD0(getPolynomialDegree, int()); + MOCK_METHOD1(setPolynomialDegree, void(int)); + MOCK_METHOD0(enablePolynomialDegree, void()); + MOCK_METHOD0(disablePolynomialDegree, void()); + MOCK_CONST_METHOD0(getCostFunction, std::string()); + MOCK_METHOD1(setCostFunction, void(std::string const &)); + MOCK_METHOD0(enableCostFunction, void()); + MOCK_METHOD0(disableCostFunction, void()); + MOCK_METHOD0(enablePolarizationCorrections, void()); MOCK_METHOD0(disablePolarizationCorrections, void()); MOCK_METHOD0(enableFloodCorrectionInputs, void()); diff --git a/qt/scientific_interfaces/test/ISISReflectometry/Experiment/PerThetaDefaultsTableValidatorTest.h b/qt/scientific_interfaces/test/ISISReflectometry/Experiment/PerThetaDefaultsTableValidatorTest.h index cfd1f346c4bea414397b07dd501c0f4f067957f3..a79c23fc91e78b8feea5182677841364dd1d75fa 100644 --- a/qt/scientific_interfaces/test/ISISReflectometry/Experiment/PerThetaDefaultsTableValidatorTest.h +++ b/qt/scientific_interfaces/test/ISISReflectometry/Experiment/PerThetaDefaultsTableValidatorTest.h @@ -145,6 +145,20 @@ public: runTestInvalidCells(table, expectedErrors({0}, {8})); } + void testValidBackgroundProcessingInstructions() { + auto table = Table({Cells({"", "", "", "", "", "", "", "", "", "1-3"})}); + auto results = runTestValid(table); + TS_ASSERT_EQUALS(results.size(), 1); + TS_ASSERT(results[0].backgroundProcessingInstructions().is_initialized()); + TS_ASSERT_EQUALS(results[0].backgroundProcessingInstructions().get(), + "1-3"); + } + + void testInvalidBackgroundProcessingInstructions() { + auto table = Table({Cells({"", "", "", "", "", "", "", "", "", "bad"})}); + runTestInvalidCells(table, expectedErrors({0}, {9})); + } + void testAnglesThatDifferByTolerance() { auto table = Table({Cells({"0.5"}), Cells({"0.501"})}); auto results = runTestValid(table); diff --git a/qt/scientific_interfaces/test/ISISReflectometry/Reduction/ValidatePerThetaDefaultsTest.h b/qt/scientific_interfaces/test/ISISReflectometry/Reduction/ValidatePerThetaDefaultsTest.h index 7e0d11cbf954996799a79170a515b9fb32d87095..6ab8165787d7dc92ff56428053c68708d4f7d1e2 100644 --- a/qt/scientific_interfaces/test/ISISReflectometry/Reduction/ValidatePerThetaDefaultsTest.h +++ b/qt/scientific_interfaces/test/ISISReflectometry/Reduction/ValidatePerThetaDefaultsTest.h @@ -132,6 +132,25 @@ public: TS_ASSERT(result.isError()); TS_ASSERT_EQUALS(result.assertError(), errorCells); } + + void testParseBackgroundProcessingInstructions() { + PerThetaDefaultsValidator validator; + auto result = validator({"", "", "", "", "", "", "", "", "", "4-7"}); + TS_ASSERT(result.isValid()); + TS_ASSERT(result.assertValid() + .backgroundProcessingInstructions() + .is_initialized()); + TS_ASSERT_EQUALS( + result.assertValid().backgroundProcessingInstructions().get(), "4-7"); + } + + void testParseBackgroundProcessingInstructionsError() { + PerThetaDefaultsValidator validator; + auto result = validator({"", "", "", "", "", "", "", "", "", "bad"}); + std::vector<int> errorCells = {9}; + TS_ASSERT(result.isError()); + TS_ASSERT_EQUALS(result.assertError(), errorCells); + } }; GNU_DIAG_ON("missing-braces")