Skip to content

Commit

Permalink
refs #5532. Weighted Mean
Browse files Browse the repository at this point in the history
  • Loading branch information
OwenArnold committed Jun 26, 2012
1 parent 7e8ec1a commit dc4a74b
Show file tree
Hide file tree
Showing 6 changed files with 147 additions and 21 deletions.
133 changes: 118 additions & 15 deletions Code/Mantid/Framework/PythonAPI/PythonAlgorithms/Stitch1D.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@
Performs 1D stitching of Reflectometry 2D MDHistoWorkspaces.
"""
import mantid.simpleapi as api

from mantid.api import *
from mantid.kernel import *
import numpy as np
import math


class Stitch1D(PythonAlgorithm):
Expand All @@ -16,6 +18,13 @@ def __get_first_non_integrated_dimension(self, ws):
dim = ws.getDimension(i)
if not dim.getNBins() == 1:
return dim
raise RuntimeError("No non integrated dimension")

def __get_first_integrated_dimension(self, ws):
for i in range(0, ws.getNumDims()):
dim = ws.getDimension(i)
if dim.getNBins() == 1:
return dim
raise RuntimeError("No integrated dimension")

def __check_individual_Workspace(self, ws):
Expand Down Expand Up @@ -52,7 +61,84 @@ def __integrate_over(self, ws, fraction_low, fraction_high):
for index in range(bin_low, bin_high):
sum_signal += ws.signalAt(index)
return sum_signal

def __trim_out_integrated_dimension(self, ws):
dim = self.__get_first_non_integrated_dimension(ws)
nbins = dim.getNBins()
q_low = dim.getMinimum()
q_high = dim.getMaximum()

signals = np.empty(nbins)
errors = np.empty(nbins)

for index in range(0, nbins):
signals[index] = ws.signalAt(index)
errors[index] = ws.errorSquaredAt(index)
errors = np.sqrt(errors)

one_d_workspace = api.CreateMDHistoWorkspace(SignalInput=signals,ErrorInput=errors,Dimensionality=1,Extents=[q_low, q_high],NumberOfBins=[nbins],Names=[dim.getName()],Units=[dim.getUnits()])
result = api.RenameWorkspace(InputWorkspace=one_d_workspace, OutputWorkspace=ws.name() + "_one_d")
return result

def __extract_overlap_as_workspace(self, ws, fraction_low, fraction_high):
dim = self.__get_first_non_integrated_dimension(ws)
nbins = dim.getNBins()
bin_low = int(nbins * fraction_low)
bin_high = int(nbins * fraction_high)
step = ( dim.getMaximum() + dim.getMinimum() )/ nbins
q_low = bin_low * step
q_high = bin_high * step

bins_iterating_over = range(bin_low, bin_high)
signals = np.empty(len(bins_iterating_over))
errors = np.empty(len(bins_iterating_over))

counter = 0
for index in bins_iterating_over:
signals[counter] = ws.signalAt(index)
errors[counter] = ws.errorSquaredAt(index)
counter += 1
errors = np.sqrt(errors)
overlapped = api.CreateMDHistoWorkspace(SignalInput=signals,ErrorInput=errors,Dimensionality=1,Extents=[q_low, q_high],NumberOfBins=[len(bins_iterating_over)],Names=[dim.getName()],Units=[dim.getUnits()])
result = api.RenameWorkspace(InputWorkspace=overlapped, OutputWorkspace=ws.name() + "_overlapped")
return result

def __perform_weighed_mean(self, ws1, ws2):
dim = ws1.getDimension(0)
nbins = dim.getNBins()

step = ( dim.getMaximum() + dim.getMinimum() )/ nbins
q_low = dim.getMinimum()
q_high = dim.getMaximum()

signals = np.empty(nbins)
errors = np.empty(nbins)
for index in range(nbins):
e1 = math.sqrt(ws1.errorSquaredAt(index))
s1 = ws1.signalAt(index)
e2 = math.sqrt(ws2.errorSquaredAt(index))
s2 = ws2.signalAt(index)
if (e1 > 0.0) and (e2 > 0.0):
e1_sq = e1*e1
e2_sq = e2*e2
y = (s1/e1_sq) + (s2/e2_sq)
e = (e1_sq * e2_sq) / (e1_sq + e2_sq)
y *= e
signals[index] = y
errors[index] = math.sqrt(e)
elif (e1 > 0.0) and (e2 <= 0.0):
signals[index] = s1
errors[index] = e1
elif (e1 <= 0.0) and (e2 > 0.0):
signals[index] = s2
errors[index] = e2
else:
signals[index] = 0
errors[index] = 0

weighted_mean = api.CreateMDHistoWorkspace(SignalInput=signals,ErrorInput=errors,Dimensionality=1,Extents=[q_low, q_high],NumberOfBins=[nbins],Names=[dim.getName()],Units=[dim.getUnits()])
return weighted_mean

def category(self):
return "PythonAlgorithms"

Expand All @@ -74,37 +160,54 @@ def PyInit(self):
self.declareProperty(name="ScaleWorkspace1", defaultValue=True, doc="Scaling either with respect to workspace 1 or workspace 2.")
self.declareProperty(name="UseManualScaleFactor", defaultValue=False, doc="True to use a provided value for the scale factor.")
self.declareProperty(name="ManualScaleFactor", defaultValue=1.0, doc="Provided value for the scale factor.")
self.declareProperty(name="AppliedScaleFactor", defaultValue=-1.0, direction = Direction.Output, doc="The actual used value for the scaling factor.");

self.declareProperty(name="AppliedScaleFactor", defaultValue=-2.0, direction = Direction.Output, doc="The actual used value for the scaling factor.");


def PyExec(self):
from mantid.simpleapi import MultiplyMD, DivideMD

workspace1 = mtd[self.getPropertyValue("Workspace1")]
workspace2 = mtd[self.getPropertyValue("Workspace2")]
self.__check_individual_Workspace(workspace1)
self.__check_individual_Workspace(workspace2)
self.__check_both_Workspaces(workspace1, workspace2)
start_overlap = float(self.getPropertyValue("StartOverlap"))
end_overlap = float(self.getPropertyValue("EndOverlap"))

b_scale_workspace1 = bool(self.getProperty("ScaleWorkspace1"))
b_manual_scale_factor = self.getProperty("UseManualScaleFactor").value
b_scale_workspace1 = self.getProperty("ScaleWorkspace1").value

if start_overlap >= end_overlap:
raise RuntimeError("StartOverlap must be < EndOverlap")

ws1_overlap = self.__integrate_over(workspace1, start_overlap, end_overlap)
ws2_overlap = self.__integrate_over(workspace2, start_overlap, end_overlap)
ws1_flattened = self.__trim_out_integrated_dimension(workspace1)
ws2_flattened = self.__trim_out_integrated_dimension(workspace2)

ws1_overlap = self.__integrate_over(ws1_flattened, start_overlap, end_overlap)
ws2_overlap = self.__integrate_over(ws2_flattened, start_overlap, end_overlap)
scale_factor = None
if b_scale_workspace1 == True:
scale_factor = (ws2_overlap / ws1_overlap)
x = workspace2 * scale_factor
if b_manual_scale_factor == True:
scale_factor = float(self.getPropertyValue("ManualScaleFactor"))
else:
scale_factor = (ws1_overlap / ws2_overlap)
x = workspace1 * scale_factor
if b_scale_workspace1 == True:
scale_factor = (ws2_overlap / ws1_overlap)

else:
scale_factor = (ws1_overlap / ws2_overlap)
self.setProperty("AppliedScaleFactor", scale_factor)
#use the start and end positions to 'sum' over the appopriate region in the input workspaces
scaled_workspace_1 = ws1_flattened * scale_factor
scaled_workspace_2 = ws2_flattened * 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(ws1_flattened, start_overlap, end_overlap)
workspace2_overlap = self.__extract_overlap_as_workspace(ws2_flattened, start_overlap, end_overlap)
weighted_mean = self.__perform_weighed_mean(workspace1_overlap, workspace2_overlap)

self.setProperty("OutputWorkspace", workspace1)
mtd.remove('sum')
sum = scaled_workspace_1 + scaled_workspace_2
self.setProperty("OutputWorkspace", sum)

#Clean up

#mtd.remove(workspace1_overlap.name())
#mtd.remove(workspace2_overlap.name())
return None

registerAlgorithm(Stitch1D())
1 change: 1 addition & 0 deletions Code/Mantid/Framework/PythonAPI/src/api_exports.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -432,6 +432,7 @@ using namespace boost::python;
.def("getNBins", &IMDDimension::getNBins)
.def("getX", &IMDDimension::getX)
.def("getDimensionId", &IMDDimension::getDimensionId)
.def("getUnits", &IMDDimension::getUnits)
;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,7 @@ void export_ialgorithm()
.def("isChild", &IAlgorithm::isChild, "Returns True if the algorithm has been marked to run as a child. If True then Output workspaces "
"are NOT stored in the Analysis Data Service but must be retrieved from the property.")
.def("setLogging", &IAlgorithm::setLogging, "Toggle logging on/off.")
.def("setRethrows", &IAlgorithm::setRethrows)
.def("initialize", &IAlgorithm::initialize, "Initializes the algorithm")
.def("execute", &executeWhileReleasingGIL, "Runs the algorithm and returns whether it has been successful")
// Special methods
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ void export_IMDDimension()
.def("getX", &IMDDimension::getX, "Return coordinate of the axis at the given index")
.def("getDimensionId", &IMDDimension::getDimensionId, "Return a short name which identify the dimension among other dimension."
"A dimension can be usually find by its ID and various ")
.def("getUnits", &IMDDimension::getDimensionId, "Return the units associated with this dimension.")
;
}

29 changes: 23 additions & 6 deletions Code/Mantid/Framework/PythonInterface/test/python/Stitch1DTest.py
Original file line number Diff line number Diff line change
Expand Up @@ -214,19 +214,36 @@ def test_calculates_scaling_factor_correctly(self):
# Signal = 1, 2, 3, but only the middle to the end of the range is marked as overlap, so only 2, 3 used.
alg_b = run_algorithm("CreateMDHistoWorkspace",SignalInput='1,2,3',ErrorInput='1,1,1',Dimensionality='2',Extents='-1,1,-1,1',NumberOfBins='3,1',Names='A,B',Units='U1,U2',OutputWorkspace='rising_signal')

alg = run_algorithm("Stitch1D", Workspace1='flat_signal', Workspace2='rising_signal',OutputWorkspace='converted',StartOverlap=0.5,EndOverlap=1)
alg = run_algorithm("Stitch1D", Workspace1='flat_signal', Workspace2='rising_signal',OutputWorkspace='converted',StartOverlap=0.5,EndOverlap=1,rethrow=True)
self.assertTrue(alg.isExecuted())

b_use_manual_scaling = alg.getProperty("UseManualScaleFactor").value
self.assertEqual(False, b_use_manual_scaling)

scale_factor = float(alg.getPropertyValue("AppliedScaleFactor"))

# 1 * ((2 + 3)/( 1 + 1)) = 2.5

self.assertEqual(2.5, scale_factor)

def test_calculates_scaling_factor_correctly_inverted(self):
# Signal = 1, 1, 1, but only the middle to the end of the range is marked as overlap, so only 1, 1 used.
alg_a = run_algorithm("CreateMDHistoWorkspace",SignalInput='1,1,1',ErrorInput='1,1,1',Dimensionality='2',Extents='-1,1,-1,1',NumberOfBins='3,1',Names='A,B',Units='U1,U2',OutputWorkspace='flat_signal')
# Signal = 1, 2, 3, but only the middle to the end of the range is marked as overlap, so only 2, 3 used.
alg_b = run_algorithm("CreateMDHistoWorkspace",SignalInput='1,2,3',ErrorInput='1,1,1',Dimensionality='2',Extents='-1,1,-1,1',NumberOfBins='3,1',Names='A,B',Units='U1,U2',OutputWorkspace='rising_signal')

alg = run_algorithm("Stitch1D", Workspace1='flat_signal', Workspace2='rising_signal',OutputWorkspace='converted',StartOverlap=0.5,EndOverlap=1,ScaleWorkspace1=False,rethrow=True)
self.assertTrue(alg.isExecuted())
scale_factor = float(alg.getPropertyValue("AppliedScaleFactor"))

# 1 * (( 1 + 1) / (2 + 3)) = 0.4
self.assertEqual(0.4, scale_factor)


def test_does_something(self):
#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,child=True)
self.assertTrue(alg.isExecuted())
scale_factor = alg.getPropertyValue("AppliedScaleFactor")
#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()
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ def run_algorithm(name, **kwargs):
del kwargs['child']
if 'OutputWorkspace' in alg:
alg.setPropertyValue("OutputWorkspace","UNUSED_NAME_FOR_CHILD")
if 'rethrow' in kwargs:
alg.setRethrows(True)
del kwargs['rethrow']
for key, value in kwargs.iteritems():
alg.setProperty(key, value)
alg.execute()
Expand Down

0 comments on commit dc4a74b

Please sign in to comment.