Unverified Commit 47af5006 authored by DavidFair's avatar DavidFair Committed by GitHub
Browse files

Merge pull request #32536 from mantidproject/32519_phasequad_TF

Fix rebin of phasequads in muon GUI
parents c978de0b 6aab5d7f
......@@ -63,7 +63,7 @@ Improvements
- The plotting has been updated for better stability.
- The plotting now has autoscale active by default.
- It is now possible to load nexusV2 files in the GUI.
- Added a table to store phasequads in the phase tab. Also, phasequads no longer delete themselves automatically.
- Added a table to store :ref:`PhaseQuads <algm-PhaseQuad>` in the phase tab. Also, phasequads no longer delete themselves automatically.
- The labels on the tabs in the GUIs will now show in full
- When running the :ref:`DynamicKobuToyabe <func-DynamicKuboToyabe>` fitting function you should now be able to see the BinWidth to 3 decimal places.
- It is now possible to select the normalisation (``analysis_asymmetry_norm``) and group (``analysis_group``) in the :ref:`Results Tab <muon_results_tab-ref>`.
......@@ -80,6 +80,8 @@ Bugfixes
- The autoscale option when ``All`` is selected will now show the largest and smallest y value for all of the plots.
- The global parameters in a results table will no longer be given a zero error arbitrarily if one with an error exists.
- The attribute values in a Chebyshev function will no longer get reset after performing a simultaneous fit.
- Fixed a crash caused by fitting to rebinned :ref:`PhaseQuad <algm-PhaseQuad>` data.
- When :ref:`PhaseQuad <algm-PhaseQuad>` data is rebinned it now divides by the fractional change in the bin size (to keep the asymmetry to about 0.3).
ALC
---
......
......@@ -5,6 +5,7 @@
# Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS
# SPDX - License - Identifier: GPL - 3.0 +
from mantid.api import AnalysisDataService
import mantid.simpleapi as mantid
def remove_ws(name):
......@@ -26,3 +27,11 @@ def check_if_workspace_exist(name):
def add_ws_to_ads(name, workspace):
AnalysisDataService.addOrReplace(name, workspace)
# these are algs, but are related to the ADS
def delete_ws(name):
alg = mantid.AlgorithmManager.create("DeleteWorkspace")
alg.initialize()
alg.setProperty("Workspace", name)
alg.execute()
......@@ -15,9 +15,9 @@ from Muon.GUI.Common.calculate_pair_and_group import calculate_group_data, calcu
estimate_group_asymmetry_data, run_pre_processing
from Muon.GUI.Common.utilities.run_string_utils import run_list_to_string, run_string_to_list
from Muon.GUI.Common.utilities.algorithm_utils import run_PhaseQuad, split_phasequad, rebin_ws, apply_deadtime, \
run_minus, run_crop_workspace
run_minus, run_crop_workspace, run_create_workspace, run_convert_to_points, run_convert_to_histogram, run_divide
import Muon.GUI.Common.ADSHandler.workspace_naming as wsName
from Muon.GUI.Common.ADSHandler.ADS_calls import retrieve_ws
from Muon.GUI.Common.ADSHandler.ADS_calls import retrieve_ws, delete_ws
from Muon.GUI.Common.contexts.muon_group_pair_context import get_default_grouping
from Muon.GUI.Common.contexts.muon_context_ADS_observer import MuonContextADSObserver
from Muon.GUI.Common.ADSHandler.muon_workspace_wrapper import MuonWorkspaceWrapper, WorkspaceGroupDefinition
......@@ -272,16 +272,43 @@ class MuonContext(object):
parameters['InputWorkspace'] = self._run_deadtime(run_string, ws_name)
runs = self._data_context.current_runs
if runs:
parameters['InputWorkspace'] = run_crop_workspace(parameters['InputWorkspace'], self.first_good_data(runs[0]),
self.last_good_data(runs[0]))
phase_quad = run_PhaseQuad(parameters, ws_name)
phase_quad = self._run_rebin(phase_quad, rebin)
if rebin:
dt = self._get_bin_width(phase_quad)
phase_quad = self._run_rebin(phase_quad, True)
phase_quad = self._average_by_bin_widths(phase_quad, dt)
workspaces = split_phasequad(phase_quad)
return workspaces
def _get_bin_width(self, name):
tmp = self._get_x_data(name)
return tmp[1]-tmp[0]
def _get_x_data(self, name):
tmp = retrieve_ws(name)
return tmp.readX(0)
def _average_by_bin_widths(self, ws_name, dt):
#convert to Histogram to get bin widths and divide by how much bin widths have changed
ws_name= run_convert_to_histogram(ws_name)
ws_x = self._get_x_data(ws_name)
# assume constant binning in raw data
dx = [ (ws_x[j+1]-ws_x[j])/(dt) for j in range(len(ws_x)-1)]
tmp = run_create_workspace(ws_x, dx, "tmp")
tmp = run_convert_to_points(tmp)
ws_name = run_convert_to_points(ws_name)
output = run_divide(ws_name, tmp, ws_name)
delete_ws(tmp)
return output
def _calculate_phasequads(self, phasequad_obj, rebin):
for run in self._data_context.current_runs:
if self._data_context.num_periods(run) > 1:
......@@ -477,9 +504,6 @@ class MuonContext(object):
equivalent_list = []
for item in input_list:
if 'PhaseQuad' in item:
equivalent_list.append(item)
equivalent_group_pair = self.group_pair_context.get_equivalent_group_pair(
item)
if equivalent_group_pair:
......
......@@ -344,3 +344,41 @@ def run_clone_workspace(parameter_dict):
alg.setProperties(parameter_dict)
alg.execute()
return alg.getProperty("OutputWorkspace").valueAsStr
def run_convert_to_points(name):
alg = mantid.AlgorithmManager.create("ConvertToPointData")
alg.initialize()
alg.setProperty("InputWorkspace", name)
alg.setProperty("OutputWorkspace", name)
alg.execute()
return alg.getProperty("OutputWorkspace").valueAsStr
def run_convert_to_histogram(name):
alg = mantid.AlgorithmManager.create("ConvertToHistogram")
alg.initialize()
alg.setProperty("InputWorkspace", name)
alg.setProperty("OutputWorkspace", name)
alg.execute()
return alg.getProperty("OutputWorkspace").valueAsStr
def run_divide(LHS, RHS, name):
alg = mantid.AlgorithmManager.create("Divide")
alg.initialize()
alg.setProperty("LHSWorkspace", LHS)
alg.setProperty("RHSWorkspace", RHS)
alg.setProperty("OutputWorkspace", name)
alg.execute()
return alg.getProperty("OutputWorkspace").valueAsStr
def run_create_workspace(x_data, y_data, name):
alg = mantid.AlgorithmManager.create("CreateWorkspace")
alg.initialize()
alg.setProperty("DataX", x_data)
alg.setProperty("DataY", y_data)
alg.setProperty("OutputWorkspace", name)
alg.execute()
return alg.getProperty("OutputWorkspace").valueAsStr
......@@ -38,6 +38,18 @@ def crop_side_effect(name, xmin, xmax):
return name
def average_side_effect(name, dt):
return name
def convert_side_effect(name):
return name
def divide_side_effect(LHS, RHS, name):
return name
@start_qapplication
class MuonContextTest(unittest.TestCase):
def setUp(self):
......@@ -489,6 +501,10 @@ class MuonContextTest(unittest.TestCase):
# 2 + 1
self.assertEqual(3, self.context._calculate_phasequads.call_count)
def set_up_phasequad_rebin_mock(self):
self.context._get_bin_width = mock.Mock(return_value = 0.1)
self.context._average_by_bin_widths = mock.Mock(side_effect=average_side_effect)
@mock.patch('Muon.GUI.Common.contexts.muon_context.run_PhaseQuad')
@mock.patch('Muon.GUI.Common.contexts.muon_context.split_phasequad')
@mock.patch('Muon.GUI.Common.contexts.muon_context.run_crop_workspace')
......@@ -502,14 +518,17 @@ class MuonContextTest(unittest.TestCase):
self.context._run_rebin = mock.Mock(side_effect=rebin_side_effect)
split_mock.side_effect = return_list
crop_mock.side_effect = crop_side_effect
self.set_up_phasequad_rebin_mock()
result = self.context.calculate_phasequad(phasequad, 5234, False)
# names are wrong due to split mock
self.assertEqual(result, [name+"1", name+"2"])
self.context._run_rebin.assert_called_with(name, False)
self.context._run_rebin.assert_not_called()
run_mock.assert_called_with({"PhaseTable": table, 'InputWorkspace': name}, name)
split_mock.assert_called_with(name)
crop_mock.assert_called_with(name, 0.0, 0.0)
self.context._get_bin_width.assert_not_called()
self.context._average_by_bin_widths.assert_not_called()
@mock.patch('Muon.GUI.Common.contexts.muon_context.run_PhaseQuad')
@mock.patch('Muon.GUI.Common.contexts.muon_context.split_phasequad')
......@@ -524,6 +543,7 @@ class MuonContextTest(unittest.TestCase):
self.context._run_rebin = mock.Mock(side_effect=rebin_side_effect)
split_mock.side_effect = return_list
crop_mock.side_effect = crop_side_effect
self.set_up_phasequad_rebin_mock()
result = self.context.calculate_phasequad(phasequad, 5234, True)
# names are wrong due to split mock
......@@ -532,6 +552,8 @@ class MuonContextTest(unittest.TestCase):
run_mock.assert_called_with({"PhaseTable": table, 'InputWorkspace': name}, name)
split_mock.assert_called_with(name)
crop_mock.assert_called_with(name, 0.0, 0.0)
self.context._get_bin_width.assert_called_once_with(name)
self.context._average_by_bin_widths.assert_called_once_with(name,0.1)
@mock.patch('Muon.GUI.Common.contexts.muon_context.run_PhaseQuad')
@mock.patch('Muon.GUI.Common.contexts.muon_context.split_phasequad')
......@@ -545,15 +567,18 @@ class MuonContextTest(unittest.TestCase):
self.context._run_rebin = mock.Mock(side_effect=rebin_side_effect)
split_mock.side_effect = return_list
crop_mock.side_effect = crop_side_effect
self.set_up_phasequad_rebin_mock()
result = self.context.calculate_phasequad(phasequad, 5234, False)
# names are wrong due to split mock
name = "EMU5234; PhaseQuad; test_Re__Im_; MA"
self.assertEqual(result, [name+"1", name+"2"])
self.context._run_rebin.assert_called_with(name, False)
self.context._run_rebin.assert_not_called()
run_mock.assert_called_with({"PhaseTable": table, 'InputWorkspace': name}, name)
split_mock.assert_called_with(name)
crop_mock.asser_called_with(name, 0.0, 0.0)
self.context._get_bin_width.assert_not_called()
self.context._average_by_bin_widths.assert_not_called()
@mock.patch('Muon.GUI.Common.contexts.muon_context.run_PhaseQuad')
@mock.patch('Muon.GUI.Common.contexts.muon_context.split_phasequad')
......@@ -567,6 +592,7 @@ class MuonContextTest(unittest.TestCase):
self.context._run_rebin = mock.Mock(side_effect=rebin_side_effect)
split_mock.side_effect = return_list
crop_mock.side_effect = crop_side_effect
self.set_up_phasequad_rebin_mock()
result = self.context.calculate_phasequad(phasequad, 5234, True)
# names are wrong due to split mock
......@@ -576,6 +602,31 @@ class MuonContextTest(unittest.TestCase):
run_mock.assert_called_with({"PhaseTable": table, 'InputWorkspace': name}, name)
split_mock.assert_called_with(name)
crop_mock.assert_called_with(name, 0.0, 0.0)
self.context._get_bin_width.assert_called_once_with(name)
self.context._average_by_bin_widths.assert_called_once_with(name,0.1)
@mock.patch('Muon.GUI.Common.contexts.muon_context.run_convert_to_histogram')
@mock.patch('Muon.GUI.Common.contexts.muon_context.run_convert_to_points')
@mock.patch('Muon.GUI.Common.contexts.muon_context.run_create_workspace')
@mock.patch('Muon.GUI.Common.contexts.muon_context.run_divide')
@mock.patch('Muon.GUI.Common.contexts.muon_context.delete_ws')
def test_average_by_bin_widths(self, delete, divide, create, points, histo):
self.context._get_x_data = mock.Mock(return_value = [0,1,3,4,6])
divide.side_effect = divide_side_effect
name = "test"
tmp = "tmp"
create.return_value = tmp
points.side_effect = convert_side_effect
histo.side_effect = convert_side_effect
self.context._average_by_bin_widths(name, .5)
histo.assert_called_once_with(name)
create.assert_called_once_with([0,1,3,4,6], [2, 4, 2, 4], tmp)
self.assertEqual(points.call_count, 2)
points.assert_any_call(name)
points.assert_any_call(tmp)
divide.assert_called_once_with(name, tmp, name)
delete.assert_called_once_with(tmp)
@mock.patch('Muon.GUI.Common.contexts.muon_context.get_raw_data_workspace_name')
@mock.patch('Muon.GUI.Common.contexts.muon_context.apply_deadtime')
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment