Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/feature/8528_slice_event'
Browse files Browse the repository at this point in the history
  • Loading branch information
PeterParker committed Dec 4, 2013
2 parents 5f070ac + 41697db commit 1f76e39
Show file tree
Hide file tree
Showing 5 changed files with 311 additions and 8 deletions.
44 changes: 40 additions & 4 deletions Code/Mantid/scripts/SANS/ISISCommandInterface.py
Expand Up @@ -153,6 +153,10 @@ def MaskFile(file_name):
@param file_name: the settings file
"""
_printMessage('#Opening "'+file_name+'"')

# ensure that no slice string is kept from previous executions.
ReductionSingleton().setSlicesLimits("")

ReductionSingleton().user_settings = isis_reduction_steps.UserFile(
file_name)
status = ReductionSingleton().user_settings.execute(
Expand Down Expand Up @@ -638,23 +642,49 @@ def _applySuffix(result, name_suffix):
RenameWorkspace(InputWorkspace=old,OutputWorkspace= result)
return result

def _common_substring(val1, val2):
l = []
for i in range(len(val1)):
if val1[i]==val2[i]: l.append(val1[i])
else:
return ''.join(l)

def _group_workspaces(list_of_values, outputname):
allnames = ','.join(list_of_values)
GroupWorkspaces(InputWorkspaces=allnames, OutputWorkspace=outputname)

def _reduceAllSlices():
if ReductionSingleton().getNumSlices() > 1:
slices = []
for index in range(ReductionSingleton().getNumSlices()):
ReductionSingleton().setSliceIndex(index)
slices.append(ReductionSingleton()._reduce())
ReductionSingleton().setSliceIndex(0)
group_name = _common_substring(slices[0], slices[1])
if group_name[-2] == "_":
group_name = group_name[:-2]
_group_workspaces(slices, group_name)
return group_name
else:
return ReductionSingleton()._reduce()



result = ""
if ReductionSingleton().get_sample().loader.periods_in_file == 1:
result = ReductionSingleton()._reduce()
result = _reduceAllSlices()
return _applySuffix(result, name_suffix)

calculated = []
try:
for period in ReductionSingleton().get_sample().loader.entries:
_setUpPeriod(period)
calculated.append(ReductionSingleton()._reduce())
calculated.append(_reduceAllSlices())

finally:
if len(calculated) > 0:
allnames = ','.join(calculated)
result = ReductionSingleton().get_out_ws_name(show_period=False)
GroupWorkspaces(OutputWorkspace=result, InputWorkspaces=allnames)
_group_workspaces(calculated, result)

return _applySuffix(result, name_suffix)

Expand Down Expand Up @@ -900,6 +930,12 @@ def LimitsQXY(qmin, qmax, step, type):

settings.readLimitValues('L/QXY ' + str(qmin) + ' ' + str(qmax) + ' ' + str(step) + '/' + type, ReductionSingleton())

def SetEventSlices(input_str):
"""
"""
ReductionSingleton().setSlicesLimits(input_str)


def PlotResult(workspace, canvas=None):
"""
Draws a graph of the passed workspace. If the workspace is 2D (has many spectra
Expand Down
160 changes: 160 additions & 0 deletions Code/Mantid/scripts/SANS/SANSUtility.py
Expand Up @@ -5,6 +5,8 @@
from mantid.simpleapi import *
from mantid.api import IEventWorkspace
import math
import re


def GetInstrumentDetails(instrum):
"""
Expand Down Expand Up @@ -460,6 +462,164 @@ def fromEvent2Histogram(ws_event, ws_monitor = None):
ws_hist = RenameWorkspace(name, OutputWorkspace=str(ws_event))

return ws_hist

def getChargeAndTime(ws_event):
r = ws_event.getRun()
charges = r.getLogData('proton_charge')
total_charge = sum(charges.value)
time_passed = (charges.times[-1] - charges.times[0]).total_microseconds()
time_passed /= 1e6
return total_charge, time_passed

def sliceByTimeWs(ws_event, time_start=None, time_stop=None):
def formatTime(time_val):
return "_T%.1f" % time_val
params = dict()
outname=str(ws_event)
if time_start:
outname +=formatTime(time_start)
params['StartTime'] = time_start
if time_stop:
outname += formatTime(time_stop)
params['StopTime'] = time_stop

params['OutputWorkspace'] = outname
sliced_ws = FilterByTime(ws_event, **params)
return sliced_ws

def slice2histogram(ws_event, time_start, time_stop, monitor):
"""Return the histogram of the sliced event and a tuple with the following:
- total time of the experiment
- total charge
- time of sliced data
- charge of sliced data
@param ws_event pointer to the event workspace
@param time_start: the minimum value to filter. Pass -1 to get the minimum available
@param time_stop: the maximum value to filter. Pass -1 to get the maximum available
@param monitor: pointer to the monitor workspace
"""
tot_c, tot_t = getChargeAndTime(ws_event)

if (time_start == -1) and (time_stop == -1):
hist = fromEvent2Histogram(ws_event, monitor)
return hist, (tot_t, tot_c, tot_t, tot_c)

if time_start == -1:
time_start = 0.0
if time_stop == -1:
time_stop = tot_t+0.001

sliced_ws = sliceByTimeWs(ws_event, time_start, time_stop)
sliced_ws = RenameWorkspace(sliced_ws, OutputWorkspace=ws_event.name())

part_c, part_t = getChargeAndTime(sliced_ws)
scaled_monitor = monitor * (part_c/tot_c)


hist = fromEvent2Histogram(sliced_ws, scaled_monitor)
return hist, (tot_t, tot_c, part_t, part_c)


def sliceParser(str_to_parser):
"""
Create a list of boundaries from a string defing the slices.
Valid syntax is:
* From 8 to 9 > '8-9' --> return [[8,9]]
* From 8 to 9 and from 10 to 12 > '8-9, 10-12' --> return [[8,9],[10,12]]
* From 5 to 10 in steps of 1 > '5:1:10' --> return [[5,6],[6,7],[7,8],[8,9],[9,10]]
* From 5 > '>5' --> return [[5,-1]]
* Till 5 > '<5' --> return [[-1,5]]
Any combination of these syntax separated by comma is valid.
A special mark is used to signalize no limit: -1,
As, so, for an empty string, it will return: [[-1, -1]].
It does not accept negative values.
"""
num_pat = r'(\d+(?:\.\d+)?(?:[eE][+-]\d+)?)' # float without sign
slice_pat = num_pat + r'-' + num_pat
lowbound = '>'+num_pat
upbound = '<'+num_pat
sss_pat = num_pat+r':'+num_pat+r':'+num_pat
exception_pattern = 'Invalid input for Slicer: %s'
MARK = -1

def _check_match(inpstr, patternstr, qtde_nums):
match = re.match(patternstr, inpstr)
if match:
answer = match.groups()
if len(answer) != qtde_nums:
raise SyntaxError(exception_pattern %(inpstr))
return [float(answer[i]) for i in range(qtde_nums)]
else:
return False

def _parse_slice(inpstr):
return _check_match(inpstr, slice_pat, 2)

def _parse_lower(inpstr):
val = _check_match(inpstr, lowbound, 1)
if not val: return val
return [val[0], MARK]

def _parse_upper(inpstr):
val = _check_match(inpstr, upbound, 1)
if not val: return val
return [MARK, val[0]]

def _parse_start_step_stop(inpstr):
val = _check_match(inpstr, sss_pat, 3)
if not val: return val
start = val[0]
step = val[1]
stop = val[2]
curr_value = start

vallist = []
while True:

next_value = curr_value + step

if next_value >= stop:
vallist.append([curr_value, stop])
return vallist
else:
vallist.append([curr_value, next_value])

curr_value = next_value



def _extract_simple_input(inpstr):
for fun in _parse_slice, _parse_lower, _parse_upper:
val = fun(inpstr)
if val:
return val

return False

def _extract_composed_input(inpstr):
return _parse_start_step_stop(inpstr)

if not str_to_parser:
return [[MARK, MARK]]

parts = str_to_parser.split(',')
result = []
for inps in parts:
inps = inps.replace(' ','')
aux_res = _extract_simple_input(inps)
if aux_res:
result.append(aux_res)
continue
aux_res = _extract_composed_input(inps)
if aux_res:
result += aux_res
continue
raise SyntaxError('Invalid input '+ str_to_parser +'. Failed caused by this term:'+inps)

return result


if __name__ == '__main__':
Expand Down
49 changes: 49 additions & 0 deletions Code/Mantid/scripts/SANS/isis_reducer.py
Expand Up @@ -10,6 +10,7 @@
import isis_reduction_steps
from mantid.simpleapi import *
from mantid.api import IEventWorkspace
import SANSUtility as su
import os
import copy

Expand Down Expand Up @@ -79,6 +80,16 @@ def get_periods_in_file(self):

class Can(Sample):
ISSAMPLE = False
def set_run(self, run, reload, period, reducer):

super(Can, self).set_run(run, reload, period, reducer)

# currently, no slices will be applied to Can #8535
for period in reversed(range(self.loader.periods_in_file)):
self.loader.move2ws(period)
name = self.loader.wksp_name
if su.isEventWorkspace(name):
su.fromEvent2Histogram(mtd[name])

class ISISReducer(SANSReducer):
"""
Expand Down Expand Up @@ -163,6 +174,10 @@ def _init_steps(self):
self._rem_nans = sans_reduction_steps.StripEndNans()

self.set_Q_output_type(self.to_Q.output_type)
# keep information about event slicing
self._slices_def = []
self._slice_index = 0


def _clean_loaded_data(self):
self._sample_run = Sample()
Expand All @@ -171,6 +186,7 @@ def _clean_loaded_data(self):
self.can_trans_load = None
self.event2hist = isis_reduction_steps.SliceEvent()


def __init__(self):
SANSReducer.__init__(self)
self._dark_current_subtracter_class = None
Expand Down Expand Up @@ -220,6 +236,7 @@ def set_sample(self, run, reload, period):

def set_can(self, run, reload, period):
self._can_run.set_run(run, reload, period, self)


def get_sample(self):
"""
Expand Down Expand Up @@ -279,6 +296,13 @@ def get_out_ws_name(self, show_period=True):
if self.to_Q.get_output_type() == "1D":
name += self.mask.get_phi_limits_tag()

if self.getNumSlices() > 0:
limits = self.getCurrSliceLimit()
if limits[0] != -1:
name += '_t%.2f'%limits[0]
if limits[1] != -1:
name += '_T%.2f'%limits[1]

return name

def deep_copy(self):
Expand Down Expand Up @@ -535,6 +559,31 @@ def get_beam_center(self, bank = None):
return self._front_beam_finder.get_beam_center()
else:
return self._beam_finder.get_beam_center()

def getCurrSliceLimit(self):
if not self._slices_def:
self._slices_def = su.sliceParser("")
assert(self._slice_index == 0)
return self._slices_def[self._slice_index]

def getNumSlices(self):
# slices are defined only for event workspaces
ws = mtd[self.get_sample().wksp_name]
if not isinstance(ws, IEventWorkspace):
return 0
if not self._slices_def:
return 0
return len(self._slices_def)

def setSliceIndex(self, index):
if index < self.getNumSlices():
self._slice_index = index
else:
raise IndexError("Outside range")

def setSlicesLimits(self, str_def):
self._slices_def = su.sliceParser(str_def)
self._slice_index = 0

def deleteWorkspaces(workspaces):
"""
Expand Down
14 changes: 10 additions & 4 deletions Code/Mantid/scripts/SANS/isis_reduction_steps.py
Expand Up @@ -16,7 +16,7 @@
from SANSUtility import (GetInstrumentDetails, MaskByBinRange,
isEventWorkspace, fromEvent2Histogram,
getFilePathFromWorkspace, getWorkspaceReference,
getMonitor4event)
getMonitor4event, slice2histogram)
import isis_instrument
import os
import math
Expand Down Expand Up @@ -1611,9 +1611,15 @@ def execute(self, reducer, workspace):
# it applies only for event workspace
if not isinstance(ws_pointer, IEventWorkspace):
return
self.monitor = getMonitor4event(ws_pointer)
hist = fromEvent2Histogram(ws_pointer, self.monitor)
self.monitor = str(self.monitor)
start, stop = reducer.getCurrSliceLimit()

_monitor = getMonitor4event(ws_pointer)

hist, others = slice2histogram(ws_pointer, start, stop, _monitor)

# get the monitors scaled for the sliced event
self.monitor = '_scaled_monitor'
CropWorkspace(hist, EndWorkspaceIndex=_monitor.getNumberHistograms()-1, OutputWorkspace=self.monitor)

class UserFile(ReductionStep):
"""
Expand Down

0 comments on commit 1f76e39

Please sign in to comment.