Unverified Commit a4f1d351 authored by Gagik Vardanyan's avatar Gagik Vardanyan Committed by GitHub
Browse files

Merge branch 'release-next' into d33_tof_lambda_range

parents 32e1b83f 1b136e68
......@@ -59,18 +59,18 @@ private:
const std::string &);
void initWorkSpace(NeXus::NXEntry &, const std::string &);
void initWorkSpaceD11B(NeXus::NXEntry &, const std::string &);
void initWorkSpaceD22B(NeXus::NXEntry &, const std::string &);
void initWorkSpaceD33(NeXus::NXEntry &, const std::string &);
void initWorkSpaceD16(NeXus::NXEntry &, const std::string &);
void createEmptyWorkspace(const size_t, const size_t);
size_t loadDataIntoWorkspaceFromMonitors(NeXus::NXEntry &firstEntry,
size_t firstIndex = 0);
size_t loadDataIntoWorkspaceFromVerticalTubes(NeXus::NXInt &,
const std::vector<double> &,
size_t);
size_t loadDataFromMonitors(NeXus::NXEntry &firstEntry,
size_t firstIndex = 0);
size_t loadDataFromTubes(NeXus::NXInt &, const std::vector<double> &, size_t);
void runLoadInstrument();
void moveDetectorsD33(const DetectorPosition &);
void moveDetectorDistance(double, const std::string &);
void moveDetectorDistance(double distance, const std::string &componentName);
void moveDetectorHorizontal(double, const std::string &);
void moveDetectorVertical(double, const std::string &);
Kernel::V3D getComponentPosition(const std::string &componentName);
......
......@@ -147,6 +147,47 @@ void LoadILLSANS::exec() {
const double angle = firstEntry.getFloat(instrumentPath + "/Gamma/value");
placeD16(-angle, distance, "detector");
} else if (m_instrumentName == "D11B") {
initWorkSpaceD11B(firstEntry, instrumentPath);
progress.report("Loading the instrument " + m_instrumentName);
runLoadInstrument();
// we move the parent "detector" component, but since it is at (0,0,0), we
// need to find the distance it has to move and move it to this position
double finalDistance =
firstEntry.getFloat(instrumentPath + "/detector/det_calc") / 1000.;
V3D pos = getComponentPosition("detector_center");
double currentDistance = pos.Z();
moveDetectorDistance(finalDistance - currentDistance, "detector");
// L2 was put at "finalDistance - currentDistance", so we update it to the
// correct value
API::Run &runDetails = m_localWorkspace->mutableRun();
runDetails.addProperty<double>("L2", finalDistance, true);
} else if (m_instrumentName == "D22B") {
initWorkSpaceD22B(firstEntry, instrumentPath);
progress.report("Loading the instrument " + m_instrumentName);
runLoadInstrument();
// first we move the central detector
double distance =
firstEntry.getFloat(instrumentPath + "/Detector/det_calc");
moveDetectorDistance(distance, "detector");
double offset =
firstEntry.getFloat(instrumentPath + "/Detector/dtr_actual");
// TODO : check sign on actual data
moveDetectorHorizontal(-offset / 1000, "detector"); // mm to meter
// then the right one
distance = firstEntry.getFloat(instrumentPath + "/RightDetector/det_calc");
moveDetectorDistance(distance, "detector_right");
offset = firstEntry.getFloat(instrumentPath + "/RightDetector/dtr_actual");
moveDetectorHorizontal(-offset / 1000, "detector"); // mm to meter
} else {
initWorkSpace(firstEntry, instrumentPath);
progress.report("Loading the instrument " + m_instrumentName);
......@@ -186,6 +227,12 @@ void LoadILLSANS::setInstrumentName(const NeXus::NXEntry &firstEntry,
firstEntry, instrumentNamePath + "/name");
const auto inst = std::find(m_supportedInstruments.begin(),
m_supportedInstruments.end(), m_instrumentName);
if ((m_instrumentName == "D11" || m_instrumentName == "D22") &&
firstEntry.containsGroup("data1")) {
m_instrumentName += "B";
}
if (inst == m_supportedInstruments.end()) {
throw std::runtime_error(
"Instrument " + m_instrumentName +
......@@ -258,13 +305,78 @@ void LoadILLSANS::initWorkSpace(NeXus::NXEntry &firstEntry,
loadMetaData(firstEntry, instrumentPath);
size_t nextIndex;
nextIndex = loadDataIntoWorkspaceFromVerticalTubes(data, m_defaultBinning, 0);
nextIndex = loadDataIntoWorkspaceFromMonitors(firstEntry, nextIndex);
nextIndex = loadDataFromTubes(data, m_defaultBinning, 0);
nextIndex = loadDataFromMonitors(firstEntry, nextIndex);
if (data.dim1() == 128) {
m_resMode = "low";
}
}
/**
* @brief LoadILLSANS::initWorkSpaceD11B Load D11B data
* @param firstEntry
* @param instrumentPath
*/
void LoadILLSANS::initWorkSpaceD11B(NeXus::NXEntry &firstEntry,
const std::string &instrumentPath) {
g_log.debug("Fetching data...");
NXData data1 = firstEntry.openNXData("data1");
NXInt dataCenter = data1.openIntData();
dataCenter.load();
NXData data2 = firstEntry.openNXData("data2");
NXInt dataRight = data2.openIntData();
dataRight.load();
NXData data3 = firstEntry.openNXData("data3");
NXInt dataLeft = data3.openIntData();
dataLeft.load();
size_t numberOfHistograms =
static_cast<size_t>(dataCenter.dim0() * dataCenter.dim1() +
dataRight.dim0() * dataRight.dim1() +
dataLeft.dim0() * dataLeft.dim1()) +
N_MONITORS;
createEmptyWorkspace(numberOfHistograms, 1);
loadMetaData(firstEntry, instrumentPath);
size_t nextIndex;
nextIndex = loadDataFromTubes(dataCenter, m_defaultBinning, 0);
nextIndex = loadDataFromTubes(dataLeft, m_defaultBinning, nextIndex);
nextIndex = loadDataFromTubes(dataRight, m_defaultBinning, nextIndex);
nextIndex = loadDataFromMonitors(firstEntry, nextIndex);
}
/**
* @brief LoadILLSANS::initWorkSpaceD22B Load D22B data
* @param firstEntry
* @param instrumentPath
*/
void LoadILLSANS::initWorkSpaceD22B(NeXus::NXEntry &firstEntry,
const std::string &instrumentPath) {
g_log.debug("Fetching data...");
NXData data1 = firstEntry.openNXData("data1");
NXInt dataCenter = data1.openIntData();
dataCenter.load();
NXData data2 = firstEntry.openNXData("data2");
NXInt dataSide = data2.openIntData();
dataSide.load();
size_t numberOfHistograms =
static_cast<size_t>(dataCenter.dim0() * dataCenter.dim1() +
dataSide.dim0() * dataSide.dim1()) +
N_MONITORS;
createEmptyWorkspace(numberOfHistograms, 1);
loadMetaData(firstEntry, instrumentPath);
size_t nextIndex;
nextIndex = loadDataFromTubes(dataCenter, m_defaultBinning, 0);
nextIndex = loadDataFromTubes(dataSide, m_defaultBinning, nextIndex);
nextIndex = loadDataFromMonitors(firstEntry, nextIndex);
}
/**
* Loads data for D33
*/
......@@ -387,22 +499,16 @@ void LoadILLSANS::initWorkSpaceD33(NeXus::NXEntry &firstEntry,
g_log.debug("Loading the data into the workspace...");
size_t nextIndex =
loadDataIntoWorkspaceFromVerticalTubes(dataRear, binningRear, 0);
nextIndex = loadDataIntoWorkspaceFromVerticalTubes(dataRight, binningRight,
nextIndex);
nextIndex =
loadDataIntoWorkspaceFromVerticalTubes(dataLeft, binningLeft, nextIndex);
nextIndex =
loadDataIntoWorkspaceFromVerticalTubes(dataDown, binningDown, nextIndex);
nextIndex =
loadDataIntoWorkspaceFromVerticalTubes(dataUp, binningUp, nextIndex);
nextIndex = loadDataIntoWorkspaceFromMonitors(firstEntry, nextIndex);
size_t nextIndex = loadDataFromTubes(dataRear, binningRear, 0);
nextIndex = loadDataFromTubes(dataRight, binningRight, nextIndex);
nextIndex = loadDataFromTubes(dataLeft, binningLeft, nextIndex);
nextIndex = loadDataFromTubes(dataDown, binningDown, nextIndex);
nextIndex = loadDataFromTubes(dataUp, binningUp, nextIndex);
nextIndex = loadDataFromMonitors(firstEntry, nextIndex);
}
size_t
LoadILLSANS::loadDataIntoWorkspaceFromMonitors(NeXus::NXEntry &firstEntry,
size_t firstIndex) {
size_t LoadILLSANS::loadDataFromMonitors(NeXus::NXEntry &firstEntry,
size_t firstIndex) {
// let's find the monitors; should be monitor1 and monitor2
for (std::vector<NXClassInfo>::const_iterator it =
......@@ -442,9 +548,9 @@ LoadILLSANS::loadDataIntoWorkspaceFromMonitors(NeXus::NXEntry &firstEntry,
return firstIndex;
}
size_t LoadILLSANS::loadDataIntoWorkspaceFromVerticalTubes(
NeXus::NXInt &data, const std::vector<double> &timeBinning,
size_t firstIndex = 0) {
size_t LoadILLSANS::loadDataFromTubes(NeXus::NXInt &data,
const std::vector<double> &timeBinning,
size_t firstIndex = 0) {
// Workaround to get the number of tubes / pixels
int numberOfTubes;
......@@ -458,6 +564,7 @@ size_t LoadILLSANS::loadDataIntoWorkspaceFromVerticalTubes(
numberOfTubes = data.dim0();
histogramWidth = data.dim2();
}
const int numberOfPixelsPerTube = data.dim1();
const HistogramData::BinEdges binEdges(timeBinning);
......@@ -565,11 +672,13 @@ void LoadILLSANS::moveDetectorDistance(double distance,
V3D pos = getComponentPosition(componentName);
mover->setProperty<MatrixWorkspace_sptr>("Workspace", m_localWorkspace);
mover->setProperty("ComponentName", componentName);
mover->setProperty("X", pos.X());
mover->setProperty("Y", pos.Y());
mover->setProperty("Z", distance);
mover->setProperty("RelativePosition", false);
mover->executeAsChildAlg();
g_log.debug() << "Moving component '" << componentName
<< "' to Z = " << distance << '\n';
API::Run &runDetails = m_localWorkspace->mutableRun();
......
......@@ -40,7 +40,9 @@ public:
LoadILLSANSTest() {
ConfigService::Instance().appendDataSearchSubDir("ILL/D11/");
ConfigService::Instance().appendDataSearchSubDir("ILL/D11B/");
ConfigService::Instance().appendDataSearchSubDir("ILL/D22/");
ConfigService::Instance().appendDataSearchSubDir("ILL/D22B/");
ConfigService::Instance().appendDataSearchSubDir("ILL/D33/");
ConfigService::Instance().appendDataSearchSubDir("ILL/D16/");
ConfigService::Instance().setFacility("ILL");
......@@ -99,6 +101,52 @@ public:
checkTimeFormat(outputWS);
}
void test_D11B() {
LoadILLSANS alg;
alg.setChild(true);
alg.initialize();
TS_ASSERT_THROWS_NOTHING(alg.setPropertyValue("Filename", "027194.nxs"))
TS_ASSERT_THROWS_NOTHING(
alg.setPropertyValue("OutputWorkspace", "__unused_for_child"))
TS_ASSERT_THROWS_NOTHING(alg.execute())
TS_ASSERT(alg.isExecuted())
MatrixWorkspace_const_sptr outputWS = alg.getProperty("OutputWorkspace");
TS_ASSERT(outputWS)
TS_ASSERT_EQUALS(outputWS->getNumberHistograms(),
192 * 256 + 2 * 32 * 256 + 2)
TS_ASSERT_EQUALS(outputWS->blocksize(), 1)
TS_ASSERT(outputWS->detectorInfo().isMonitor(192 * 256 + 2 * 32 * 256))
TS_ASSERT(outputWS->detectorInfo().isMonitor(192 * 256 + 2 * 32 * 256 + 1))
TS_ASSERT(outputWS->isHistogramData())
TS_ASSERT(!outputWS->isDistribution())
const auto &instrument = outputWS->getInstrument();
IComponent_const_sptr component =
instrument->getComponentByName("detector_center");
V3D pos = component->getPos();
TS_ASSERT_DELTA(pos.Z(), 8.9274824298, 1E-3)
component = instrument->getComponentByName("detector_left");
pos = component->getPos();
TS_ASSERT_DELTA(pos.Z(), 8.82248, 1E-5)
component = instrument->getComponentByName("detector_right");
pos = component->getPos();
TS_ASSERT_DELTA(pos.Z(), 8.82248, 1E-5)
const auto &xAxis = outputWS->x(0).rawData();
const auto &spec = outputWS->y(3630).rawData();
const auto &err = outputWS->e(3630).rawData();
TS_ASSERT_EQUALS(xAxis.size(), 2)
TS_ASSERT_DELTA(xAxis[0], 6.685, 1E-5)
TS_ASSERT_DELTA(xAxis[1], 7.315, 1E-5)
TS_ASSERT_EQUALS(spec[0], 246)
TS_ASSERT_DELTA(err[0], sqrt(246), 1E-5)
const auto unit = outputWS->getAxis(0)->unit()->unitID();
TS_ASSERT_EQUALS(unit, "Wavelength");
checkTimeFormat(outputWS);
}
void test_D22() {
LoadILLSANS alg;
alg.setChild(true);
......@@ -135,6 +183,47 @@ public:
checkTimeFormat(outputWS);
}
void test_d22B() {
LoadILLSANS alg;
alg.setChild(true);
alg.initialize();
TS_ASSERT_THROWS_NOTHING(alg.setPropertyValue("Filename", "375508.nxs"))
TS_ASSERT_THROWS_NOTHING(
alg.setPropertyValue("OutputWorkspace", "__unused_for_child"))
TS_ASSERT_THROWS_NOTHING(alg.execute())
TS_ASSERT(alg.isExecuted())
MatrixWorkspace_const_sptr outputWS = alg.getProperty("OutputWorkspace");
TS_ASSERT(outputWS)
TS_ASSERT_EQUALS(outputWS->getNumberHistograms(), 128 * 256 + 96 * 256 + 2)
TS_ASSERT_EQUALS(outputWS->blocksize(), 1)
TS_ASSERT(outputWS->detectorInfo().isMonitor(128 * 256 + 96 * 256))
TS_ASSERT(outputWS->detectorInfo().isMonitor(128 * 256 + 96 * 256 + 1))
TS_ASSERT(outputWS->isHistogramData())
TS_ASSERT(!outputWS->isDistribution())
const auto &instrument = outputWS->getInstrument();
// TODO SET CORRECT COORDINATES
IComponent_const_sptr comp = instrument->getComponentByName("detector");
V3D pos = comp->getPos();
TS_ASSERT_DELTA(pos.Z(), 16.874, 1E-5)
comp = instrument->getComponentByName("detector_right");
pos = comp->getPos();
TS_ASSERT_DELTA(pos.Z(), 16.874, 1E-5)
const auto &xAxis = outputWS->x(0).rawData();
const auto &spec = outputWS->y(1280).rawData();
const auto &err = outputWS->e(1280).rawData();
TS_ASSERT_EQUALS(xAxis.size(), 2)
TS_ASSERT_DELTA(xAxis[0], 6.65, 1E-5)
TS_ASSERT_DELTA(xAxis[1], 7.35, 1E-5)
TS_ASSERT_EQUALS(spec[0], 10)
TS_ASSERT_DELTA(err[0], sqrt(10), 1E-5)
const auto unit = outputWS->getAxis(0)->unit()->unitID();
TS_ASSERT_EQUALS(unit, "Wavelength");
checkTimeFormat(outputWS);
}
void test_D16() {
LoadILLSANS alg;
alg.setChild(true);
......
......@@ -17,16 +17,17 @@ class MaskBTP(mantid.api.PythonAlgorithm):
"""
# list of supported instruments
INSTRUMENT_LIST = ['ARCS', 'BIOSANS', 'CG2', 'CG3', 'CHESS', 'CNCS', 'CORELLI', 'D11', 'D11lr', 'D16', 'D22',
'D22lr', 'D33', 'EQ-SANS', 'GPSANS', 'HYSPEC', 'MANDI', 'NOMAD',
'POWGEN', 'REF_M', 'SEQUOIA', 'SNAP', 'SXD', 'TOPAZ', 'WAND', 'WISH']
INSTRUMENT_LIST = ['ARCS', 'BIOSANS', 'CG2', 'CG3', 'CHESS', 'CNCS', 'CORELLI', 'D11', 'D11B', 'D11lr', 'D16',
'D22', 'D22B', 'D22lr', 'D33', 'EQ-SANS', 'GPSANS', 'HYSPEC', 'MANDI', 'NOMAD', 'POWGEN',
'REF_M', 'SEQUOIA', 'SNAP', 'SXD', 'TOPAZ', 'WAND', 'WISH']
instname = None
instrument = None
bankmin = defaultdict(lambda: 1, {'D33': 0, 'SEQUOIA': 23, 'TOPAZ': 10}) # default is one
bankmax = {'ARCS': 115, 'BIOSANS': 88, 'CG2': 48, 'CG3': 88, 'CHESS': 163, 'CNCS': 50, 'CORELLI': 91, 'D11': 1, 'D11lr': 1,
'D16': 1, 'D22': 1, 'D22lr': 1, 'D33': 4, 'EQ-SANS': 48, 'GPSANS': 48, 'HYSPEC': 20, 'MANDI': 59, 'NOMAD': 99,
'POWGEN': 300, 'REF_M': 1, 'SEQUOIA': 150, 'SNAP': 64, 'SXD': 11, 'TOPAZ': 59, 'WAND': 8, 'WISH': 10}
bankmax = {'ARCS': 115, 'BIOSANS': 88, 'CG2': 48, 'CG3': 88, 'CHESS': 163, 'CNCS': 50, 'CORELLI': 91, 'D11': 1,
'D11B': 3, 'D11lr': 1, 'D16': 1, 'D22': 1, 'D22B': 2, 'D22lr': 1, 'D33': 4, 'EQ-SANS': 48, 'GPSANS': 48,
'HYSPEC': 20, 'MANDI': 59, 'NOMAD': 99, 'POWGEN': 300, 'REF_M': 1, 'SEQUOIA': 150, 'SNAP': 64, 'SXD': 11,
'TOPAZ': 59, 'WAND': 8, 'WISH': 10}
def category(self):
""" Mantid required
......@@ -263,6 +264,10 @@ class MaskBTP(mantid.api.PythonAlgorithm):
banks = ["back_detector", "front_detector_top", "front_detector_right", "front_detector_bottom",
"front_detector_left"]
return banks[banknum]
elif self.instname == "D11B":
return ["detector_center", "detector_left", "detector_right"][banknum - 1]
elif self.instname == "D22B":
return ["detector", "detector_right"][banknum - 1]
elif self.instname in ["D11", "D11lr", "D22", "D22lr", "D16"]:
return "detector"
else:
......
......@@ -264,6 +264,21 @@ class MaskBTPTest(unittest.TestCase):
self.assertEquals(len(mask), 9*128)
self.checkConsistentMask(ws, mask)
def test_d22b(self):
ws = LoadEmptyInstrument(InstrumentName="D22B")
mask = MaskBTP(Workspace=ws, Bank="2")
self.assertEquals(len(mask), 256*96)
self.checkConsistentMask(ws, mask)
def test_d11b(self):
ws = LoadEmptyInstrument(InstrumentName="D11B")
mask = MaskBTP(Workspace=ws, Components="detector_right, detector_left")
self.assertEquals(len(mask), 256*32*2)
self.checkConsistentMask(ws, mask)
if __name__ == '__main__':
unittest.main()
e38f1cd76ab0db5a381434b195c55b67
8a4668039bb895376a804cd30162c8c0
......@@ -13,6 +13,7 @@ This loads the nexus files produced by the SANS instruments D11, D22, D33 at the
For D33, it supports both monochromatic and TOF modes.
This loader reads the detector positions from the nexus file and places the detectors accordingly.
For D11 and D22 it supports the nominal and low resolution modes (pixel splitting).
It also supports the newer version for these instruments.
The output is a histogram workspace with unit of wavelength (Angstrom).
It has a single bin for monochromatic, and many bins (ragged) for TOF mode for D33.
......
......@@ -70,5 +70,6 @@ Bugfixes
- Fixed a crash in SliceViewer when hovering the cursor over Direct or Indirect data.
- Fixed a crash when using broken e notation for axis limits in plot settings
- Fixed a bug in error bars tab in plot settings where the Error Every property was not being shown correctly
- Fixed a bug where the fit action (Fit > Fit) in the fit browser wasn't disabled if all the functions were individually removed.
:ref:`Release 6.0.0 <v6.0.0>`
......@@ -28,6 +28,7 @@ Improvements
- The output workspace will get its title from the nexus file.
- WavelengthRange is exposed to the algorithm, which is crucial for TOF reduction.
- The Rectangle option for :ref:`SolidAngle <algm-SolidAngle>` is now supported for ILL's D22 and D33.
- Added loader and MaskBTP support for D11B and D22B.
Bugfixes
########
......
......@@ -420,3 +420,4 @@ class CurvesTabWidgetPresenter:
self.view.enable_curve_config(False)
else:
self.view.enable_curve_config(True)
self.set_errorbars_tab_enabled()
......@@ -1059,10 +1059,12 @@ set(
test/FileDialogHandlerTest.h
test/FindFilesThreadPoolManagerTest.h
test/FindFilesWorkerTest.h
test/FitOptionsBrowserTest.h
test/FitPropertyBrowserTest.h
test/FitScriptGeneratorDataTableTest.h
test/FitScriptGeneratorPresenterTest.h
# test/FitScriptGeneratorViewTest.h
test/FitScriptGeneratorViewTest.h
test/FunctionTreeViewTest.h
test/ImageInfoModelMatrixWSTest.h
test/ImageInfoModelMDTest.h
test/ImageInfoPresenterTest.h
......
......@@ -52,6 +52,7 @@ public:
/// Constructor
FitOptionsBrowser(QWidget *parent = nullptr,
FittingType fitType = Simultaneous);
~FitOptionsBrowser();
QString getProperty(const QString &name) const;
void setProperty(const QString &name, const QString &value);
void copyPropertiesToAlgorithm(Mantid::API::IAlgorithm &fit) const;
......
......@@ -50,7 +50,8 @@ namespace MantidWidgets {
* @param fitType :: The type of the underlying fitting algorithm.
*/
FitOptionsBrowser::FitOptionsBrowser(QWidget *parent, FittingType fitType)
: QWidget(parent), m_decimals(6), m_fittingType(fitType) {
: QWidget(parent), m_fittingTypeProp(nullptr), m_minimizer(nullptr),
m_decimals(6), m_fittingType(fitType) {
// create m_browser
createBrowser();
createProperties();
......@@ -60,6 +61,14 @@ FitOptionsBrowser::FitOptionsBrowser(QWidget *parent, FittingType fitType)
layout->setContentsMargins(0, 0, 0, 0);
}
FitOptionsBrowser::~FitOptionsBrowser() {
m_browser->unsetFactoryForManager(m_stringManager);
m_browser->unsetFactoryForManager(m_doubleManager);
m_browser->unsetFactoryForManager(m_intManager);
m_browser->unsetFactoryForManager(m_boolManager);
m_browser->unsetFactoryForManager(m_enumManager);
}
/**
* Create the Qt property browser and set up property managers.
*/
......
......@@ -99,7 +99,21 @@ FunctionTreeView::FunctionTreeView(QWidget *parent, bool multi,
/**
* Destructor
*/
FunctionTreeView::~FunctionTreeView() {}
FunctionTreeView::~FunctionTreeView() {
m_browser->unsetFactoryForManager(m_parameterManager);
m_browser->unsetFactoryForManager(m_attributeStringManager);
m_browser->unsetFactoryForManager(m_attributeDoubleManager);
m_browser->unsetFactoryForManager(m_attributeIntManager);
m_browser->unsetFactoryForManager(m_attributeBoolManager);
m_browser->unsetFactoryForManager(m_indexManager);
m_browser->unsetFactoryForManager(m_tieManager);
m_browser->unsetFactoryForManager(m_constraintManager);
m_browser->unsetFactoryForManager(m_filenameManager);
m_browser->unsetFactoryForManager(m_formulaManager);
m_browser->unsetFactoryForManager(m_workspaceManager);
m_browser->unsetFactoryForManager(m_attributeSizeManager);
m_browser->unsetFactoryForManager(m_attributeVectorDoubleManager);
}
/**
* Create the Qt property browser and set up property managers.
......
......@@ -465,6 +465,7 @@ void PropertyHandler::removeFunction() {
}
}
ph->renameChildren();
m_browser->setFitEnabled(cf->nFunctions() > 0);
}
}
......
// Mantid Repository : https://github.com/mantidproject/mantid
//
// Copyright &copy; 2020 ISIS Rutherford Appleton Laboratory UKRI,
// NScD Oak Ridge National Laboratory, European Spallation Source,
// Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS
// SPDX - License - Identifier: GPL - 3.0 +
#pragma once
#include "MantidQtWidgets/Common/FitOptionsBrowser.h"
#include <cxxtest/TestSuite.h>
#include <memory>
using namespace MantidQt::MantidWidgets;
/*
* This test was created in response to finding an unreliable Read Access
* Violation when creating the FitOptionsBrowser. This failure would happen once
* every 100-200 attempts to instantiate this class.
*
* Its cause was a dangling pointer to a manager object being left behind when
* destructing a FitOptionsBrowser. This dangling point was still existing in a
* global static variable (m_managerToFactoryToViews or
* m_viewToManagerToFactory) in qtpropertybrowser.cpp. When creating a new
* instance of FitOptionsBrowser, the memory location would sometimes be reused,
* causing problems.
* The solution used to fix this was to do:
* m_browser->unsetFactoryForManager(m_manager)
* in the destructor of FitOptionsBrowser.
*
* A further issue caused by uninitialized memory was also fixed, and is covered
* by this test.
*/
class FitOptionsBrowserTest : public CxxTest::TestSuite {
public:
static FitOptionsBrowserTest *createSuite() {
return new FitOptionsBrowserTest;
}
static void destroySuite(FitOptionsBrowserTest *suite) { delete suite; }
void setUp() override { m_numberOfTries = 100u; }
void tearDown() override { m_fitOptionsBrowser.reset(); }
void
test_that_the_FitOptionsBrowser_can_be_instantiated_many_times_without_instability() {
for (auto i = 0u; i < m_numberOfTries; ++i)
m_fitOptionsBrowser = std::make_unique<FitOptionsBrowser>(nullptr);
}
private:
std::size_t m_numberOfTries;
std::unique_ptr<FitOptionsBrowser> m_fitOptionsBrowser;
};
// Mantid Repository : https://github.com/mantidproject/mantid
//
// Copyright &copy; 2020 ISIS Rutherford Appleton Laboratory UKRI,
// NScD Oak Ridge National Laboratory, European Spallation Source,