Skip to content

Commit

Permalink
refs #5532. A number of changes described below.
Browse files Browse the repository at this point in the history
Firstly, I made it more robust to having either 1d or 2d md workspaces as inputs. This allows us to iterate over the algorithm in order to recursively combine many 1D segments.

 I also fixed a bug in the calculation of the target index for the overlapping weighted-mean sections.

Tests have been extended to cover both of these.

 The algorithm has been executed on Tims test data and seems close to the benchmark outputs.
  • Loading branch information
OwenArnold committed Jul 4, 2012
1 parent 498a730 commit 26fdc94
Show file tree
Hide file tree
Showing 2 changed files with 84 additions and 41 deletions.
39 changes: 24 additions & 15 deletions Code/Mantid/Framework/PythonAPI/PythonAlgorithms/Stitch1D.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,23 @@ def __get_first_integrated_dimension(self, ws):
raise RuntimeError("No integrated dimension")

def __check_individual_Workspace(self, ws):
if not ws.getNumDims() == 2:
raise RuntimeError( ws.name() + " must have 2 dimensions" )
dim1 = ws.getDimension(0)
dim2 = ws.getDimension(1)
if not bool(dim1.getNBins() == 1) ^ bool(dim2.getNBins() == 1):
raise RuntimeError(ws.name() + " must have one integrated and one unintegrated dimension")
ndims = ws.getNumDims()
if (ndims < 1) or (ndims > 2):
raise RuntimeError( ws.name() + " must have 1 or 2 dimensions" )
if ndims == 1:
dim1 = ws.getDimension(0)
if dim1.getNBins() == 1:
raise RuntimeError(ws.name() + " is one-dimensional, so must have an un-integrated dimension.")
if ndims == 2:
dim1 = ws.getDimension(0)
dim2 = ws.getDimension(1)
if not bool(dim1.getNBins() == 1) ^ bool(dim2.getNBins() == 1):
raise RuntimeError(ws.name() + " is two-dimensional, so must have one integrated and one un-integrated dimension.")
return None

def __check_both_Workspaces(self, ws1, ws2):
for i in range(0, 2):
ndims = min(ws1.getNumDims(), ws2.getNumDims())
for i in range(0, ndims):
ws_1_dim = ws1.getDimension(i)
ws_2_dim = ws2.getDimension(i)
if not ws_1_dim.getNBins() == ws_2_dim.getNBins():
Expand All @@ -47,9 +54,9 @@ def __check_both_Workspaces(self, ws1, ws2):
ws1_integrated_dim = self.__get_first_non_integrated_dimension(ws1)
ws2_integrated_dim = self.__get_first_non_integrated_dimension(ws2)
if not ws1_integrated_dim.getMaximum() == ws2_integrated_dim.getMaximum():
raise RuntimeError("Max values in the two non-integrated dimensions of the combining workspaces are not equal")
raise RuntimeError("Max values in the two non-integrated dimensions of the combining workspaces are not equal.")
if not ws1_integrated_dim.getMinimum() == ws2_integrated_dim.getMinimum():
raise RuntimeError("Min values in the two non-integrated dimensions of the combining workspaces are not equal")
raise RuntimeError("Min values in the two non-integrated dimensions of the combining workspaces are not equal.")

def __integrate_over(self, ws, fraction_low, fraction_high):
dim = self.__get_first_non_integrated_dimension(ws)
Expand Down Expand Up @@ -118,8 +125,9 @@ def __overlay_overlap(self, sum, overlap):
overlap_step = (overlap_q_max - overlap_q_min) / overlap_nbins
overlap_c = overlap_q_min
for i in range(0, overlap_nbins):
q = (overlap_step * i) + overlap_c
target_index = int((target_step * q) + target_c)
q = float((overlap_step * i) + overlap_c)
# Find the target index by recentering (adding 0.5) and then truncating to an integer.
target_index = int((target_step * q) + target_c + 0.5)
sum.setSignalAt(target_index, overlap.signalAt(i))
sum.setErrorSquaredAt(target_index, overlap.errorSquaredAt(i))

Expand Down Expand Up @@ -181,19 +189,20 @@ def PyExec(self):
else:
if b_scale_workspace2 == True:
scale_factor = (ws1_overlap / ws2_overlap)
scaled_workspace_1 = ws1_flattened * 1
scaled_workspace_2 = ws2_flattened * scale_factor
else:
scale_factor = (ws2_overlap / ws1_overlap)
scaled_workspace_1 = ws1_flattened * 1
scaled_workspace_2 = ws2_flattened * 1
scaled_workspace_1 = ws1_flattened * scale_factor
scaled_workspace_2 = ws2_flattened * 1
self.setProperty("OutScaleFactor", scale_factor)

#use the start and end positions to 'sum' over the appropriate region in the input workspaces
workspace1_overlap = self.__extract_overlap_as_workspace(scaled_workspace_1, start_overlap, end_overlap)
workspace2_overlap = self.__extract_overlap_as_workspace(scaled_workspace_2, start_overlap, end_overlap)
weighted_mean_overlap = api.WeightedMeanMD(LHSWorkspace=workspace1_overlap,RHSWorkspace=workspace2_overlap)

mtd.remove('sum')
sum = ws1_flattened + ws2_flattened
sum = scaled_workspace_1 + scaled_workspace_2
self.__overlay_overlap(sum, weighted_mean_overlap)
self.setProperty("OutputWorkspace", sum)

Expand Down
86 changes: 60 additions & 26 deletions Code/Mantid/Framework/PythonInterface/test/python/Stitch1DTest.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,11 +135,53 @@ def test_ws1_and_ws2_have_different_binning_throws(self):
finally:
mtd.remove(a)
mtd.remove(b)
self.assertTrue(passed)
self.assertTrue(passed)

def __do_test_permitted_dimensionalities(self, a, b):
passed = True
try:
run_algorithm("Stitch1D", Workspace1=a, Workspace2=b,OutputWorkspace='converted',StartOverlap=0,EndOverlap=0.3, child=True)
except RuntimeError:
passed = False
finally:
self.assertTrue(passed)

def test_can_have_single_1d_input_workspaces(self):
# Create a one-d input workspace with 3 bins
alg_A = run_algorithm("CreateMDHistoWorkspace",SignalInput='1,2,3,4,5,6,7,8,9,10',ErrorInput='1,1,1,1,1,1,1,1,1,1',Dimensionality='1',Extents='-1,1',NumberOfBins='10',Names='A',Units='U1',OutputWorkspace='Stitch1D_test_workspace_A')
# Create a two-d input workspace with 3 * 1 bins.
alg_B = run_algorithm("CreateMDHistoWorkspace",SignalInput='1,2,3,4,5,6,7,8,9,10',ErrorInput='1,1,1,1,1,1,1,1,1,1',Dimensionality='2',Extents='-1,1,-1,1',NumberOfBins='10,1',Names='A,B',Units='U1,U2',OutputWorkspace='Stitch1D_test_workspace_B')

a = alg_A.getPropertyValue("OutputWorkspace")
b = alg_B.getPropertyValue("OutputWorkspace")

# Test with RHS as one dimensional and LHS as two dimensional
self.__do_test_permitted_dimensionalities(a, b)

#Test with RHS as two dimensional and RHS as one dimensional
self.__do_test_permitted_dimensionalities(b, a)

mtd.remove(a)
mtd.remove(b)

def test_can_have_both_input_workspaces_as_1d(self):
# Create a one-d input workspace with 3 bins
alg_A = run_algorithm("CreateMDHistoWorkspace",SignalInput='1,2,3,4,5,6,7,8,9,10',ErrorInput='1,1,1,1,1,1,1,1,1,1',Dimensionality='1',Extents='-1,1',NumberOfBins='10',Names='A',Units='U1',OutputWorkspace='Stitch1D_test_workspace_A')
# Create a two-d input workspace with 3 * 1 bins.
alg_B = run_algorithm("CreateMDHistoWorkspace",SignalInput='1,2,3,4,5,6,7,8,9,10',ErrorInput='1,1,1,1,1,1,1,1,1,1',Dimensionality='1',Extents='-1,1',NumberOfBins='10',Names='A',Units='U1',OutputWorkspace='Stitch1D_test_workspace_B')

a = alg_A.getPropertyValue("OutputWorkspace")
b = alg_B.getPropertyValue("OutputWorkspace")

# Test with RHS and LHS as one dimensional
self.__do_test_permitted_dimensionalities(a, b)

mtd.remove(a)
mtd.remove(b)

def __do_test_ws1_and_ws2_have_different_dimension_names_throws(self, ws1_dim_names, ws2_dim_names):
# Create Workspace with dim names in ws1_dim_names
alg_A = run_algorithm("CreateMDHistoWorkspace",SignalInput='1,2',ErrorInput='1,1',Dimensionality='2',Extents='-1,1,-1,1',NumberOfBins='2,1',Names=ws1_dim_names,Units='U1,U2',OutputWorkspace='Stitch1D_test_workspace_C')
alg_A = run_algorithm("CreateMDHistoWorkspace",SignalInput='1,1',ErrorInput='1,1',Dimensionality='2',Extents='-1,1,-1,1',NumberOfBins='2,1',Names=ws1_dim_names,Units='U1,U2',OutputWorkspace='Stitch1D_test_workspace_C')
# Create Workspace with dim names in ws2_dim_names
alg_B = run_algorithm("CreateMDHistoWorkspace",SignalInput='1,2',ErrorInput='1,1',Dimensionality='2',Extents='-1,1,-1,1',NumberOfBins='2,1',Names=ws2_dim_names,Units='U1,U2',OutputWorkspace='Stitch1D_test_workspace_D')

Expand All @@ -156,6 +198,7 @@ def __do_test_ws1_and_ws2_have_different_dimension_names_throws(self, ws1_dim_na
mtd.remove(a)
mtd.remove(b)
self.assertTrue(passed)


def test_ws1_and_ws2_dim1_have_different_dimension_names_throws(self):
self.__do_test_ws1_and_ws2_have_different_dimension_names_throws(['A1','B1'], ['A2', 'B1'])
Expand Down Expand Up @@ -251,48 +294,39 @@ def test_manual_scaling_factor(self):

self.assertEqual(expected_manual_scale_factor, scale_factor)

def test_flat_offsetting_schenario(self):
errors = [1,1,1,1,1,1,1,1,1,1] # Errors for both input ws1 and ws2
s1 = [1,1,1,1,1,1,1,1,1,1] # Signal values for ws1
s2 = [3,3,3,3,3,3,3,3,3,3] # Signal values for ws2
expected_output_signal =[2,2,2,2,2,4,4,4,4,4]
expected_output_error_sq = [0.5, 0.5, 0.5, 0.5, 0.5, 2, 2, 2, 2, 2]
def test_overlap_in_center(self):
errors = range(0,10)
s1 = [0,0,0,3,3,3,3,3,3,3] # Signal values for ws1
s2 = [2,2,2,2,2,2,2,0,0,0] # Signal values for ws2
expected_output_signal =[3,3,3,3,3,3,3,3,3,3]
alg_a = run_algorithm("CreateMDHistoWorkspace",SignalInput=s1,ErrorInput=errors,Dimensionality='2',Extents='-1,1,-1,1',NumberOfBins=[len(errors),1],Names='A,B',Units='U1,U2',OutputWorkspace='flat_signal_a',rethrow=True)
alg_b = run_algorithm("CreateMDHistoWorkspace",SignalInput=s2,ErrorInput=errors,Dimensionality='2',Extents='-1,1,-1,1',NumberOfBins=[len(errors),1],Names='A,B',Units='U1,U2',OutputWorkspace='flat_signal_b',rethrow=True)
# Specify that overlap goes from start to half way along workspace
alg = run_algorithm("Stitch1D", Workspace1='flat_signal_a', Workspace2='flat_signal_b',OutputWorkspace='converted',StartOverlap=0.0,EndOverlap=0.5,ScaleWorkspace2=True,rethrow=True)
alg = run_algorithm("Stitch1D", Workspace1='flat_signal_a', Workspace2='flat_signal_b',OutputWorkspace='converted',StartOverlap=0.3,EndOverlap=0.7,rethrow=True)
# Verify the calculated output values.
ws = mtd.retrieve(alg.getPropertyValue("OutputWorkspace"))
for i in range(0, len(errors)):
self.assertEqual(expected_output_signal[i], ws.signalAt(i))
self.assertEqual(expected_output_error_sq[i], ws.errorSquaredAt(i))
for i in range(0, len(s1)):
self.assertEqual(round(expected_output_signal[i], 5), round(ws.signalAt(i),5) )

def test_flat_offsetting_schenario_with_scaling(self):
errors = [1,1,1,1,1,1,1,1,1,1] # Errors for both input ws1 and ws2
s1 = [1,1,1,1,1,1,1,1,1,1] # Signal values for ws1
s2 = [3,3,3,3,3,3,3,3,3,3] # Signal values for ws2
expected_output_signal =[2,2,2,2,2,4,4,4,4,4]
expected_output_error_sq = [0.8, 0.8, 0.8, 0.8, 0.8, 2, 2, 2, 2, 2]
def test_flat_offsetting_schenario_with_manual_scaling(self):
errors = range(0,10)
s1 = [1,1,1,1,1,1,0,0,0,0] # Signal values for ws1
s2 = [0,0,0,0,3,3,3,3,3,3] # Signal values for ws2
expected_output_signal =[1,1,1,1,2,2,6,6,6,6]
alg_a = run_algorithm("CreateMDHistoWorkspace",SignalInput=s1,ErrorInput=errors,Dimensionality='2',Extents='-1,1,-1,1',NumberOfBins=[len(errors),1],Names='A,B',Units='U1,U2',OutputWorkspace='flat_signal_a',rethrow=True)
alg_b = run_algorithm("CreateMDHistoWorkspace",SignalInput=s2,ErrorInput=errors,Dimensionality='2',Extents='-1,1,-1,1',NumberOfBins=[len(errors),1],Names='A,B',Units='U1,U2',OutputWorkspace='flat_signal_b',rethrow=True)
# Supply a manual scale factor, this will mean that Workspace 1 is scaled by this amount.
manual_scale_factor = 2
# Specify that overlap goes from start to half way along workspace
alg = run_algorithm("Stitch1D", Workspace1='flat_signal_a', Workspace2='flat_signal_b',OutputWorkspace='converted',StartOverlap=0.0,EndOverlap=0.5,UseManualScaleFactor=True,ManualScaleFactor=manual_scale_factor,rethrow=True)
alg = run_algorithm("Stitch1D", Workspace1='flat_signal_a', Workspace2='flat_signal_b',OutputWorkspace='converted',StartOverlap=0.4,EndOverlap=0.6,UseManualScaleFactor=True,ManualScaleFactor=manual_scale_factor,rethrow=True)
# Verify the calculated output values.
ws = mtd.retrieve(alg.getPropertyValue("OutputWorkspace"))
for i in range(0, len(errors)):
self.assertEqual(round(expected_output_signal[i], 5), round(ws.signalAt(i), 5))
self.assertEqual(round(expected_output_error_sq[i], 5), round(ws.errorSquaredAt(i),5))#
# Sanity check that the applied scale factor is also the same as the value instructed.
scale_factor = float(alg.getPropertyValue("OutScaleFactor"))
self.assertEqual(manual_scale_factor, scale_factor)

#def test_does_something(self):
# Algorithm isn't complete at this point, but we need to have one success case to verify that all the previous failure cases are genuine failures (i.e. there is a way to get the algorithm to run properly)
#alg = run_algorithm("Stitch1D", Workspace1=self.__good_workspace_name, Workspace2=self.__good_workspace_name,OutputWorkspace='converted',StartOverlap=0,EndOverlap=0.5,rethrow=True)
#self.assertTrue(alg.isExecuted())
#scale_factor = alg.getPropertyValue("AppliedScaleFactor")


if __name__ == '__main__':
unittest.main()

0 comments on commit 26fdc94

Please sign in to comment.