Skip to content

Commit

Permalink
Re #6151 Add masking and absolute scaling for APIv2
Browse files Browse the repository at this point in the history
  • Loading branch information
mdoucet committed Dec 18, 2012
1 parent cd9ea4a commit 3859900
Show file tree
Hide file tree
Showing 8 changed files with 668 additions and 95 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
"""*WIKI*
Apply mask to SANS detector
*WIKI*"""

import mantid.simpleapi as api
from mantid.api import *
from mantid.kernel import *
from reduction_workflow.instruments.sans import hfir_instrument

class HFIRSANSMask(PythonAlgorithm):
"""
Normalise detector counts by the sample thickness
"""

def category(self):
return "Workflow\\SANS;PythonAlgorithms"

def name(self):
return "HFIRSANSMask"

def PyInit(self):
self.declareProperty(MatrixWorkspaceProperty("Workspace", "",
direction=Direction.InOut))

self.declareProperty(IntArrayProperty("MaskedDetectorList", values=[],
direction=Direction.Input),
"List of detector IDs to be masked")

self.declareProperty(IntArrayProperty("MaskedEdges", values=[0,0,0,0],
direction=Direction.Input),
"Number of pixels to mask on the edges: X-low, X-high, Y-low, Y-high")

sides = [ "None", "Front", "Back"]
self.declareProperty("MaskedSide", "None",
StringListValidator(sides))

self.declareProperty("OutputMessage", "",
direction=Direction.Output, doc = "Output message")

def PyExec(self):
workspace = self.getProperty("Workspace").value

# Apply saved mask as needed
self._apply_saved_mask(workspace)

# Mask a detector side
self._mask_detector_side(workspace)

# Mask edges
edge_str = self.getPropertyValue("MaskedEdges")

edges = self.getProperty("MaskedEdges").value
if len(edges)==4:
masked_pixels = hfir_instrument.get_masked_pixels(edges[0], edges[1],
edges[2], edges[3],
workspace)
self._mask_pixels(masked_pixels, workspace)

# Mask a list of detectors
masked_dets = self.getProperty("MaskedDetectorList").value
if len(masked_dets)>0:
api.MaskDetectors(Workspace=workspace, DetectorList=masked_dets)

self.setProperty("OutputMessage", "Mask applied")

def _mask_pixels(self, pixel_list, workspace):
if len(pixel_list)>0:
# Transform the list of pixels into a list of Mantid detector IDs
masked_detectors = hfir_instrument.get_detector_from_pixel(pixel_list)
# Mask the pixels by passing the list of IDs
api.MaskDetectors(Workspace=workspace, DetectorList = masked_detectors)

def _apply_saved_mask(self, workspace):
# Check whether the workspace has mask information
if workspace.getRun().hasProperty("rectangular_masks"):
mask_str = workspace.getRun().getProperty("rectangular_masks").value
try:
rectangular_masks = pickle.loads(mask_str)
except:
rectangular_masks = []
toks = mask_str.split(',')
for item in toks:
if len(item)>0:
c = item.strip().split(' ')
if len(c)==4:
rectangular_masks.append([int(c[0]), int(c[2]), int(c[1]), int(c[3])])
masked_pixels = []
for rec in rectangular_masks:
try:
for ix in range(x_min, x_max+1):
for iy in range(y_min, y_max+1):
masked_pixels.append([ix, iy])
except:
Logger.get("HFIRSANSMask").error("Badly defined mask from configuration file: %s" % str(rec))
self._mask_pixels(masked_pixels, workspace)

def _mask_detector_side(self, workspace):
"""
Mask the back side or front side as needed
"""
side = self.getProperty("MaskedSide").value
if side == "Front":
side_to_mask = 0
elif side == "Back":
side_to_mask = 1
else:
return

nx = int(workspace.getInstrument().getNumberParameter("number-of-x-pixels")[0])
ny = int(workspace.getInstrument().getNumberParameter("number-of-y-pixels")[0])
id_side = []

for iy in range(ny):
for ix in range(side_to_mask, nx+side_to_mask, 2):
id_side.append([iy,ix])

self._mask_pixels(id_side, workspace)

registerAlgorithm(HFIRSANSMask())
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
"""*WIKI*
HFIR SANS reduction workflow
*WIKI*"""
import mantid.simpleapi as api
from mantid.api import *
Expand Down Expand Up @@ -51,7 +53,7 @@ def _load_data(filename, output_ws):
# Get instrument to use with FileFinder
instrument = ''
if property_manager.existsProperty("InstrumentName"):
instrument = property_manager.getProperty("InstrumentName")
instrument = property_manager.getProperty("InstrumentName").value

output_str = ''
if type(data_file)==str:
Expand Down Expand Up @@ -93,6 +95,7 @@ def _load_data(filename, output_ws):
def PyExec(self):
filename = self.getProperty("Filename").value
output_ws = self.getPropertyValue("OutputWorkspace")
output_ws = '__'+output_ws+'_reduced'
property_manager_name = self.getProperty("ReductionProperties").value
property_manager = PropertyManagerDataService.retrieve(property_manager_name)

Expand All @@ -110,17 +113,10 @@ def PyExec(self):
output_msg += alg.getProperty("OutputMessage").value+'\n'

# Load the sample data
if "LoadAlgorithm" not in property_list:
raise RuntimeError, "HFIR SANS reduction not set up properly: missing load algorithm"
p=property_manager.getProperty("LoadAlgorithm")
alg=Algorithm.fromString(p.valueAsStr)
alg.setProperty("Filename", filename)
alg.setProperty("OutputWorkspace", output_ws)
alg.setProperty("ReductionProperties", property_manager_name)
alg.execute()
msg = self._multiple_load(filename, output_ws,
property_manager, property_manager_name)
output_msg += "Loaded %s\n" % filename
if alg.existsProperty("OutputMessage"):
output_msg += alg.getProperty("OutputMessage").value
output_msg += msg

# Perform the main corrections on the sample data
output_msg += self.process_data_file(output_ws)
Expand All @@ -143,7 +139,7 @@ def PyExec(self):
p=property_manager.getProperty("TransmissionAlgorithm")
alg=Algorithm.fromString(p.valueAsStr)
alg.setProperty("InputWorkspace", output_ws)
alg.setProperty("OutputWorkspace", '__'+output_ws+"_reduced")
alg.setProperty("OutputWorkspace", output_ws)

if alg.existsProperty("BeamCenterX") \
and alg.existsProperty("BeamCenterY") \
Expand All @@ -157,7 +153,6 @@ def PyExec(self):
alg.execute()
if alg.existsProperty("OutputMessage"):
output_msg += alg.getProperty("OutputMessage").value+'\n'
output_ws = '__'+output_ws+'_reduced'

# Process background data
if "BackgroundFiles" in property_list:
Expand Down Expand Up @@ -214,18 +209,10 @@ def PyExec(self):
output_msg += "Background subtracted [%s]%s\n" % (background_ws, bck_msg)

# Absolute scale correction
output_msg += self._simple_execution("AbsoluteScaleAlgorithm", output_ws)

# Geometry correction
if "GeometryAlgorithm" in property_list:
p=property_manager.getProperty("GeometryAlgorithm")
alg=Algorithm.fromString(p.valueAsStr)
alg.setProperty("InputWorkspace", background_ws)
alg.setProperty("OutputWorkspace", background_ws)
if alg.existsProperty("ReductionProperties"):
alg.setProperty("ReductionProperties", property_manager_name)
alg.execute()
if alg.existsProperty("OutputMessage"):
output_msg += alg.getProperty("OutputMessage").value+'\n'
output_msg += self._simple_execution("GeometryAlgorithm", output_ws)

# Compute I(q)
iq_output = None
Expand All @@ -250,11 +237,12 @@ def PyExec(self):
if os.path.isdir(output_dir):
output_msg += self._save_output(iq_output, iqxy_output,
output_dir, property_manager)
else:
elif len(output_dir)>0:
msg = "Output directory doesn't exist: %s\n" % output_dir
Logger.get("HFIRSANSReduction").error(msg)

self.setPropertyValue("OutputWorkspace", output_ws)
ws = AnalysisDataService.retrieve(output_ws)
self.setProperty("OutputWorkspace", ws)
self.setProperty("OutputMessage", output_msg)

def process_data_file(self, workspace):
Expand All @@ -264,42 +252,16 @@ def process_data_file(self, workspace):
property_list = [p.name for p in property_manager.getProperties()]

# Dark current subtraction
if "DarkCurrentAlgorithm" in property_list:
p=property_manager.getProperty("DarkCurrentAlgorithm")
alg=Algorithm.fromString(p.valueAsStr)
alg.setProperty("InputWorkspace", workspace)
alg.setProperty("OutputWorkspace", workspace)
if alg.existsProperty("ReductionProperties"):
alg.setProperty("ReductionProperties", property_manager_name)
alg.execute()
if alg.existsProperty("OutputMessage"):
output_msg += alg.getProperty("OutputMessage").value+'\n'
output_msg += self._simple_execution("DarkCurrentAlgorithm", workspace)

# Normalize
if "NormaliseAlgorithm" in property_list:
p=property_manager.getProperty("NormaliseAlgorithm")
alg=Algorithm.fromString(p.valueAsStr)
alg.setProperty("InputWorkspace", workspace)
alg.setProperty("OutputWorkspace", workspace)
if alg.existsProperty("ReductionProperties"):
alg.setProperty("ReductionProperties", property_manager_name)
alg.execute()
if alg.existsProperty("OutputMessage"):
output_msg += alg.getProperty("OutputMessage").value+'\n'
output_msg += self._simple_execution("NormaliseAlgorithm", workspace)

# Mask
output_msg += self._simple_execution("MaskAlgorithm", workspace)

# Solid angle correction
if "SANSSolidAngleCorrection" in property_list:
p=property_manager.getProperty("SANSSolidAngleCorrection")
alg=Algorithm.fromString(p.valueAsStr)
alg.setProperty("InputWorkspace", workspace)
alg.setProperty("OutputWorkspace", workspace)
if alg.existsProperty("ReductionProperties"):
alg.setProperty("ReductionProperties", property_manager_name)
alg.execute()
if alg.existsProperty("OutputMessage"):
output_msg += alg.getProperty("OutputMessage").value+'\n'
output_msg += self._simple_execution("SANSSolidAngleCorrection", workspace)

# Sensitivity correction
if "SensitivityAlgorithm" in property_list:
Expand Down Expand Up @@ -337,6 +299,32 @@ def process_data_file(self, workspace):

return output_msg

def _simple_execution(self, algorithm_name, workspace, output_workspace=None):
"""
Simple execution of an algorithm on the given workspace
"""
property_manager_name = self.getProperty("ReductionProperties").value
property_manager = PropertyManagerDataService.retrieve(property_manager_name)

output_msg = ""
if output_workspace is None:
output_workspace = workspace

if property_manager.existsProperty(algorithm_name):
p=property_manager.getProperty(algorithm_name)
alg=Algorithm.fromString(p.valueAsStr)
if alg.existsProperty("InputWorkspace"):
alg.setProperty("InputWorkspace", workspace)
alg.setProperty("OutputWorkspace", output_workspace)
else:
alg.setProperty("Workspace", workspace)
if alg.existsProperty("ReductionProperties"):
alg.setProperty("ReductionProperties", property_manager_name)
alg.execute()
if alg.existsProperty("OutputMessage"):
output_msg = alg.getProperty("OutputMessage").value+'\n'
return output_msg

def _save_output(self, iq_output, iqxy_output, output_dir, property_manager):
"""
Save the I(Q) and I(QxQy) output to file.
Expand All @@ -360,12 +348,26 @@ def _save_output(self, iq_output, iqxy_output, output_dir, property_manager):
Logger.get("HFIRSANSReduction").error("Could not read %s\n" % process_file)

filename = os.path.join(output_dir, iq_output+'.txt')
api.SaveAscii(Filename=filename, InputWorkspace=iq_output,
Separator="Tab", CommentIndicator="# ",
WriteXError=True)

alg = AlgorithmManager.create("SaveAscii")
alg.initialize()
alg.setChild(True)
alg.setProperty("Filename", filename)
alg.setProperty("InputWorkspace", iq_output)
alg.setProperty("Separator", "Tab")
alg.setProperty("CommentIndicator", "# ")
alg.setProperty("WriteXError", True)
alg.execute()

filename = os.path.join(output_dir, iq_output+'.xml')
api.SaveCanSAS1D(Filename=filename, InputWorkspace=iq_output,
Process=proc_xml)
alg = AlgorithmManager.create("SaveCanSAS1D")
alg.initialize()
alg.setChild(True)
alg.setProperty("Filename", filename)
alg.setProperty("InputWorkspace", iq_output)
alg.setProperty("Process", proc_xml)
alg.execute()

output_msg += "I(Q) saved in %s\n" % (filename)
else:
Logger.get("HFIRSANSReduction").error("No I(Q) output found")
Expand Down

0 comments on commit 3859900

Please sign in to comment.