|
|
@@ -0,0 +1,505 @@ |
|
|
from MantidFramework import * |
|
|
from mantid.api import FileFinder |
|
|
|
|
|
import itertools |
|
|
|
|
|
# This is a helper "functor" for use with the "groupby" itertools function. |
|
|
# When fed a SORTED list of UNIQUE values one by one, it will return the same "group key" |
|
|
# for contiguous values. I.e. passing in 2, 3, 5, 6 and 7 will return 0, 0, 1, 1 and 1. |
|
|
class _ContiguousGrouper(): |
|
|
def __init__(self): |
|
|
self._key = int() |
|
|
self._currentVal = None |
|
|
|
|
|
def __call__(self, val): |
|
|
if self._currentVal is not None and self._currentVal + 1 is not val: |
|
|
self._key += 1 |
|
|
self._currentVal = val |
|
|
return self._key |
|
|
|
|
|
# Turns [2, 9, 3, 6, 5, 3, 9, 3, 3, 7] into ... |
|
|
def _listToIntervals(values): |
|
|
# ... [2, 3, 5, 6, 7, 9] ... |
|
|
sortedUniqueVals = sorted(list(set(values))) |
|
|
|
|
|
# ... [[2, 3], [5, 6, 7], [9]] ... |
|
|
contiguousLists = [list(g) for k, g in itertools.groupby(sortedUniqueVals, _ContiguousGrouper())] |
|
|
|
|
|
# ... and then returns [[2, 3], [5, 7], [9, 9]]. |
|
|
return [[cL[0], cL[len(cL) - 1]] for cL in contiguousLists] |
|
|
|
|
|
# Turns [[2, 3], [5, 7], [9, 9]] into [[2, 3], [5, 6, 7], [9]] |
|
|
def _intervalsToList(intervals): |
|
|
result = [range(interval[0], interval[1] + 1) for interval in intervals] |
|
|
return list(set(itertools.chain.from_iterable(result))) |
|
|
|
|
|
# Will parse a string of the form "8-10" into the list of numbers [8, 9, 10]. |
|
|
def _parseIntervalToken(intervalToken): |
|
|
# Tokenise again on "-" |
|
|
bounds = intervalToken.split("-") |
|
|
# Strip whitespace. |
|
|
bounds = [bound.strip() for bound in bounds] |
|
|
|
|
|
for bound in bounds: |
|
|
# Validate. |
|
|
if len(bounds) == 0: |
|
|
raise RuntimeError("Could not parse an empty value: " + str(_range)) |
|
|
if len(bounds) > 2: |
|
|
raise RuntimeError("Unexpected range specified: " + str(_range)) |
|
|
if not bound.isdigit(): |
|
|
raise RuntimeError("Non-numeric charater detected: " + bound) |
|
|
|
|
|
if len(bounds) == 1: |
|
|
# Return a list with a single integer. |
|
|
return [int(bounds[0])] |
|
|
else: |
|
|
# Return a list with the range of integers from lower to upper. |
|
|
return [number for number in range(int(bounds[0]), int(bounds[1]) + 1)] |
|
|
|
|
|
class Intervals: |
|
|
# Having "*intervals" as a parameter instead of "intervals" allows us |
|
|
# to type "Intervals( (0,3), (6, 8) )" instead of "Intervals( ( (0,3), (6, 8) ) )" |
|
|
def __init__(self, *intervals): |
|
|
# Convert into a list, then back into intervals, to make |
|
|
# sure we have no overlapping intervals (which would result in |
|
|
# duplicate values. |
|
|
values = _intervalsToList(intervals) |
|
|
self._intervals = _listToIntervals(values) |
|
|
|
|
|
#Factory. |
|
|
@classmethod |
|
|
def fromString(cls, string): |
|
|
# Tokenise on commas. |
|
|
intervalTokens = string.split(",") |
|
|
|
|
|
# Call parseRange on each tokenised range. |
|
|
numbers = [_parseIntervalToken(intervalToken) for intervalToken in intervalTokens] |
|
|
|
|
|
# Chain the result (a list of lists) together to make one single list of unique values. |
|
|
result = list(set(itertools.chain.from_iterable(numbers))) |
|
|
|
|
|
# Construct a new Intervals object, populate its intervals, and return. |
|
|
newObj = cls() |
|
|
newObj._intervals = _listToIntervals(result) |
|
|
return newObj |
|
|
|
|
|
#Factory. |
|
|
@classmethod |
|
|
def fromList(cls, values): |
|
|
result = list(set(values)) |
|
|
|
|
|
# Construct a new Intervals object, populate its intervals, and return. |
|
|
newObj = cls() |
|
|
newObj._intervals = _listToIntervals(result) |
|
|
return newObj |
|
|
|
|
|
# Returns an array of all the values represented by this "Intervals" instance. |
|
|
def getValues(self): |
|
|
return [value for interval in self._intervals for value in range(interval[0], interval[1] + 1)] |
|
|
|
|
|
# Returns the raw intervals. |
|
|
def getIntervals(self): |
|
|
return self._intervals |
|
|
|
|
|
# So that "2 in Intervals( (0, 3) )" returns True. |
|
|
def __contains__(self, id): |
|
|
for interval in self._intervals: |
|
|
if interval[0] <= id <= interval[1]: |
|
|
return True |
|
|
return False |
|
|
|
|
|
# So that we can type "groups = Intervals( (0, 3) ) + Intervals( (6, 10) )" |
|
|
def __add__(self, other): |
|
|
newObj = Intervals() |
|
|
newObj._intervals = self._intervals + other._intervals |
|
|
return newObj |
|
|
|
|
|
""" TODO: At the moment this is just a generator. Implement a proper iterator. """ |
|
|
# So that we can type "for i in Intervals( (0, 2), (4, 5) ):" |
|
|
def __iter__(self): |
|
|
for interval in self._intervals: |
|
|
for value in range(interval[0], interval[1] + 1): |
|
|
yield value |
|
|
|
|
|
# So we can type "interval = Intervals( (3, 5), (10, 12) )" and then "interval[3]" returns 10. |
|
|
def __getitem__(self, index): |
|
|
return self.getValues()[index] |
|
|
|
|
|
"""==================================================================================""" |
|
|
"""==================================================================================""" |
|
|
"""==================================================================================""" |
|
|
|
|
|
# Essentially, just a convenience "wrapper" for a map which maps DetectorGroupings to |
|
|
# period numbers. Allows us to call map[spectrumID], which returns the periods mapped |
|
|
# from the Grouping that spectrumID belongs to. |
|
|
class GroupingMap(): |
|
|
def __init__(self, map): |
|
|
self._map = map |
|
|
|
|
|
def __getitem__(self, spectrumID): |
|
|
for grouping in self._map: |
|
|
if spectrumID in grouping: |
|
|
return self._map[grouping] |
|
|
raise RuntimeError("Unable to find spectrum ID in map.") |
|
|
|
|
|
# Enumerating the different logical groupings of detectors, by their spectra IDs. |
|
|
class DetectorGrouping: |
|
|
# Monitors |
|
|
MONITORS = Intervals( (1, 2) ) |
|
|
|
|
|
# Backward detectors are grouped into three modules. |
|
|
BACKWARD_1 = Intervals( (3, 46) ) |
|
|
BACKWARD_2 = Intervals( (47, 90) ) |
|
|
BACKWARD_3 = Intervals( (91, 134) ) |
|
|
|
|
|
# Forward detectors are put into two groups A and B. The foils are cycled repeatedly |
|
|
# through a run so that when group A is foiled group B is not, and vice versa. |
|
|
FORWARD_A = Intervals( (135, 142), (151, 158), (167, 174), (183, 190) ) |
|
|
FORWARD_B = Intervals( (143, 150), (159, 166), (175, 182), (191, 198) ) |
|
|
|
|
|
# Further logical groupings. |
|
|
BACKWARD = BACKWARD_1 + BACKWARD_2 + BACKWARD_3 |
|
|
BACKWARD_OR_MONITOR = BACKWARD + MONITORS |
|
|
FORWARD = FORWARD_A + FORWARD_B |
|
|
ANY = MONITORS + BACKWARD + FORWARD |
|
|
|
|
|
# Enumerate the different foil states. |
|
|
class Foil: |
|
|
OUT = "Out" |
|
|
THIN = "Thin" |
|
|
THICK = "Thick" |
|
|
|
|
|
IN = THIN, THICK |
|
|
|
|
|
ANY = OUT, THIN, THICK |
|
|
|
|
|
# A "functor" to map spectra IDs to workspace indices. This is just temporary until |
|
|
# further development of the C++ MatrixWorkspace class means a good (quick) enough |
|
|
# function can be exported to the Python API. |
|
|
class SpectrumID2WsIndexMapper: |
|
|
|
|
|
# Constructor. Takes in a single workspace. |
|
|
def __init__(self, ws): |
|
|
|
|
|
# Save for later. |
|
|
self._ws = ws |
|
|
self._map = {} |
|
|
|
|
|
# Populate map. |
|
|
for wsIndex in range(0, ws.getNumberHistograms()): |
|
|
spectrumID = ws.getSpectrum(wsIndex).getSpectrumNo() |
|
|
self._map[spectrumID] = wsIndex |
|
|
|
|
|
# Make our mapper a callable object, or "functor". Returns the workspace index mapped |
|
|
# from the spectrum ID provided. |
|
|
def __call__(self, spectrumID): |
|
|
if spectrumID in self._map: |
|
|
return self._map[spectrumID] |
|
|
raise RuntimeError("Unable to find spectrum ID of " + str(spectrumID) + |
|
|
" in workspace " + self._ws.getName() + ".") |
|
|
|
|
|
# Take in a ws group (a run or sum of runs with 6 child workspaces representing each period), as well as the spectra IDs |
|
|
# that we are insterested in. |
|
|
class PeriodManager: |
|
|
def __init__(self, wsGroup, spectraIDs): |
|
|
|
|
|
""" TODO: Do the backward foil periods change depending on run? We can easily adjust |
|
|
__init__ later to accept any parameters we like, (filenames, or actual workspaces), so |
|
|
that the lists can be changed at run time, but for now, assume these lists are fine for |
|
|
all cases. Keep them here. """ |
|
|
|
|
|
""" TODO: Should the periods for spectra and the periods for monitors not ALWAYS be the |
|
|
same as each other?""" |
|
|
|
|
|
# Map groups of detectors to lists of periods. Each map value has 2 lists: periods for spectra, |
|
|
# and periods for monitors that are used with those spectra. |
|
|
self._spectraIDtoFoilOutPeriods = GroupingMap({ |
|
|
DetectorGrouping.BACKWARD_1 : ((3, 4), (3, 4)), |
|
|
DetectorGrouping.BACKWARD_2 : ((5, 6), (5, 6)), |
|
|
DetectorGrouping.BACKWARD_3 : ((1, 2), (1, 2)), |
|
|
DetectorGrouping.FORWARD_A : ((2, 4, 6), (4, 6)), |
|
|
DetectorGrouping.FORWARD_B : ((1, 3, 5), (3, 5)) |
|
|
}) |
|
|
|
|
|
self._spectraIDtoThinFoilPeriods = GroupingMap({ |
|
|
DetectorGrouping.BACKWARD_1 : ((1, 2), (1, 2)), |
|
|
DetectorGrouping.BACKWARD_2 : ((3, 4), (3, 4)), |
|
|
DetectorGrouping.BACKWARD_3 : ((5, 6), (5, 6)), |
|
|
DetectorGrouping.FORWARD_A : ((1, 3, 5), (5, 2)), |
|
|
DetectorGrouping.FORWARD_B : ((2, 4, 6), (6, 1)) |
|
|
}) |
|
|
|
|
|
self._spectraIDtoThickFoilPeriods = GroupingMap({ |
|
|
DetectorGrouping.BACKWARD_1 : ((5, 6), (5, 6)), |
|
|
DetectorGrouping.BACKWARD_2 : ((1, 2), (1, 2)), |
|
|
DetectorGrouping.BACKWARD_3 : ((3, 4), (3, 4)), |
|
|
DetectorGrouping.FORWARD_A : ((1, 3), (1, 3)), |
|
|
DetectorGrouping.FORWARD_B : ((2, 4), (2, 4)) |
|
|
}) |
|
|
|
|
|
# Arbitrarily take the first period of the workspace group, since all the information we need from it is |
|
|
# assumed to be the same in all periods. |
|
|
period = mtd[wsGroup.getNames()[0]] |
|
|
# Instantiate a spectrum ID to ws index mapper, with the period. |
|
|
toWsIndex = SpectrumID2WsIndexMapper(period) |
|
|
|
|
|
self._spectraIDs = spectraIDs |
|
|
self._mappings = {} |
|
|
self._monMappings = {} |
|
|
|
|
|
# For each spectrum ID, construct a mapping of foil states to periods, and map |
|
|
# each mapping to that spectrums ws index. |
|
|
for spectrumID in self._spectraIDs: |
|
|
# Convert spectrumID to ws index. |
|
|
wsIndex = toWsIndex(spectrumID) |
|
|
mapping = { |
|
|
Foil.OUT : self._spectraIDtoFoilOutPeriods[spectrumID][0], |
|
|
Foil.THIN : self._spectraIDtoThinFoilPeriods[spectrumID][0], |
|
|
Foil.THICK : self._spectraIDtoThickFoilPeriods[spectrumID][0] |
|
|
} |
|
|
self._mappings[wsIndex] = mapping |
|
|
|
|
|
monMapping = { |
|
|
Foil.OUT : self._spectraIDtoFoilOutPeriods[spectrumID][1], |
|
|
Foil.THIN : self._spectraIDtoThinFoilPeriods[spectrumID][1], |
|
|
Foil.THICK : self._spectraIDtoThickFoilPeriods[spectrumID][1] |
|
|
} |
|
|
|
|
|
self._monMappings[wsIndex] = monMapping |
|
|
|
|
|
# Return the mappings of foil states to periods for each ws index. |
|
|
def getMappings(self): |
|
|
return self._mappings |
|
|
|
|
|
# Return the monitor mappings of foil states to periods for each ws index. |
|
|
def getMonMappings(self): |
|
|
return self._monMappings |
|
|
|
|
|
"""==================================================================================""" |
|
|
"""==================================================================================""" |
|
|
"""==================================================================================""" |
|
|
|
|
|
# Given a list of workspaces, will sum them together into a single new workspace, with the given name. |
|
|
# If no name is given, then one is constructed from the names of the given workspaces. |
|
|
def sumWsList(wsList, summedWsName = None): |
|
|
if len(wsList) == 1: |
|
|
if summedWsName is not None: |
|
|
CloneWorkspace(InputWorkspace=wsList[0].getName(), OutputWorkspace=summedWsName) |
|
|
return mtd[summedWsName] |
|
|
return wsList[0] |
|
|
|
|
|
sum = wsList[0] + wsList[1] |
|
|
|
|
|
if len(wsList) > 2: |
|
|
for i in range(2, len(wsList) - 1): |
|
|
sum += wsList[i] |
|
|
|
|
|
if summedWsName is None: |
|
|
summedWsName = "_PLUS_".join([ws.getName() for ws in wsList]) |
|
|
|
|
|
RenameWorkspace(InputWorkspace=sum.getName(), OutputWorkspace=summedWsName) |
|
|
|
|
|
return mtd[summedWsName] |
|
|
|
|
|
# Given a spectrum and a range of times, returns the sum of the counts between those two times. |
|
|
def sumCountsBetweenTimes(spectrum, fromTime, toTime, wsIndex=0): |
|
|
dataX = spectrum.dataX(wsIndex) |
|
|
dataY = spectrum.dataY(wsIndex) |
|
|
|
|
|
return sum( [y for x, y in zip(dataX, dataY) if fromTime <= x <= toTime] ) |
|
|
|
|
|
"""==================================================================================""" |
|
|
"""==================================================================================""" |
|
|
"""==================================================================================""" |
|
|
|
|
|
class LoadEVSRaw(PythonAlgorithm): |
|
|
def category(self): |
|
|
return 'Inelastic;PythonAlgorithms' |
|
|
|
|
|
def PyInit(self): |
|
|
# Declare algorithm properties. |
|
|
self.declareProperty('Runs', '' , MandatoryValidator(), Description='Runs, e.g. \"2012-2020\"') |
|
|
self.declareWorkspaceProperty('OutputWorkspace', '' , Direction.Output, Description='Name of workspace into which the result will be put.') |
|
|
self.declareProperty('Spectra', '' , MandatoryValidator(), Description='Spectra IDs, e.g. \"5-10\". Can accept a full range of both backward and forward scattering spectra.') |
|
|
""" TODO: What is this ... ? """ |
|
|
self.declareProperty('Beta', 0.0, MandatoryValidator(), Description='') |
|
|
|
|
|
def PyExec(self): |
|
|
# Parse / store algorithm property values for later use. |
|
|
runNumbers = Intervals.fromString(self.getProperty('Runs')) |
|
|
self._spectraIDs = Intervals.fromString(self.getProperty('Spectra')) |
|
|
outputWsName = self.getPropertyValue('OutputWorkspace') |
|
|
beta = self.getProperty('Beta') |
|
|
|
|
|
# SpectraID of first monitor. |
|
|
monitorID = DetectorGrouping.MONITORS[0] |
|
|
|
|
|
# Min and max X values, used to crop loaded files. |
|
|
cropLower = 0 |
|
|
cropUpper = 700 |
|
|
|
|
|
# Find all files before loading. |
|
|
filenames = [FileFinder.Instance().getFullPath("EVS" + str(runNumber) + ".raw") for runNumber in runNumbers] |
|
|
for runNumber, filename in zip(runNumbers, filenames): |
|
|
if filename == '': |
|
|
raise RuntimeError("Unable to find file for run " + str(runNumber) + ".") |
|
|
|
|
|
# Load files, each into two group workspaces: monitors kept separate from other spectra. |
|
|
# Workspaces are cropped between cropLower and cropUpper. |
|
|
for filename in filenames: |
|
|
LoadRaw(Filename=filename, OutputWorkspace=filename, LoadLogFiles=False, |
|
|
SpectrumList=[monitorID] + self._spectraIDs.getValues(), LoadMonitors="Separate") |
|
|
CropWorkspace(InputWorkspace=filename, OutputWorkspace=filename,XMin=cropLower,XMax=cropUpper) |
|
|
CropWorkspace(InputWorkspace=filename+"_Monitors", OutputWorkspace=filename+"_Monitors",XMin=cropLower,XMax=cropUpper) |
|
|
|
|
|
# Get handles to workspaces. |
|
|
runs = [mtd[filename] for filename in filenames] |
|
|
runsMon = [mtd[filename + "_Monitors"] for filename in filenames] |
|
|
|
|
|
# Sum the runs together, and delete the individual run workspaces. |
|
|
name = "EVS" + self.getProperty('Runs') + "_sp" + self.getProperty('Spectra') |
|
|
summedRuns = sumWsList(runs, name) |
|
|
summedRunsMon = sumWsList(runsMon, name + "_Monitor") |
|
|
for ws in runs + runsMon: |
|
|
DeleteWorkspace(Workspace=ws.getName()) |
|
|
|
|
|
# Clone some new workspaces, into which we will place our calculated foil data, and place in a map so we can |
|
|
# access the workspaces by foil state. |
|
|
clonedWsName = summedRuns.getNames()[0] |
|
|
foilWsMap = {} |
|
|
monFoilWsMap = {} |
|
|
for foilState in Foil.ANY: |
|
|
# Generate names. |
|
|
wsName = summedRuns.getName() + "_" + foilState |
|
|
monWsName = wsName + "_Mon" |
|
|
# Clone new workspaces. |
|
|
CloneWorkspace(InputWorkspace=clonedWsName, OutputWorkspace=wsName) |
|
|
CloneWorkspace(InputWorkspace=clonedWsName, OutputWorkspace=monWsName) |
|
|
# Add to maps. |
|
|
foilWsMap[foilState] = mtd[wsName] |
|
|
monFoilWsMap[foilState] = mtd[monWsName] |
|
|
|
|
|
# Query an instance of a PeriodManager for maps of workspaceIndex to foil out / thin foil / thick foil period mappings. |
|
|
periodMan = PeriodManager(summedRuns, self._spectraIDs) |
|
|
periodMappings = periodMan.getMappings() |
|
|
monPeriodMappings = periodMan.getMonMappings() |
|
|
|
|
|
# Get handles to each of the period and period monitor workspaces. |
|
|
periodWsList = [ mtd[periodWsName] for periodWsName in summedRuns.getNames() ] |
|
|
monPeriodWsList = [ mtd[monPeriodWsName] for monPeriodWsName in summedRunsMon.getNames() ] |
|
|
|
|
|
""" TODO: Is this just an equivalent to a "rebinning" step? """ |
|
|
# Create a "time" workspace by arbitrarily picking the first spectra of the first period, and using its X axis data. |
|
|
# This workspace will have Y axis data that corresponds to the differences in time between each X axis time boundary. |
|
|
# It also has units of "TOF", so that other workspaces with TOF units may be divided by it. |
|
|
dataX = periodWsList[0].dataX(0) |
|
|
dataY = [dataX[i] - dataX[i - 1] for i in range(1, len(dataX))] |
|
|
timeWs = CreateWorkspace(DataX=list(dataX), DataY=list(dataY), DataE=list(dataY), UnitX="TOF") |
|
|
|
|
|
# Divide period and monitors through by the timeWs, and then delete it. |
|
|
for periodWs in periodWsList + monPeriodWsList: |
|
|
Divide(LHSWorkspace=periodWs.getName(),RHSWorkspace=timeWs.getName(),OutputWorkspace=periodWs.getName()) |
|
|
DeleteWorkspace(Workspace=timeWs.getName()) |
|
|
|
|
|
sumMap = {} |
|
|
monSumMap = {} |
|
|
|
|
|
# Iterate through each workspace index / foil state pair, and sum together the spectra data for the relavant periods, |
|
|
# and normalise to monitor. |
|
|
for wsIndex, foilState in itertools.product(periodMappings.iterkeys(), Foil.ANY): |
|
|
|
|
|
# Get the period numbers which correspond to this ws index and foil state ... |
|
|
foilPeriods = periodMappings[wsIndex][foilState] |
|
|
monFoilPeriods = monPeriodMappings[wsIndex][foilState] |
|
|
# ... then use those period numbers to get handles to the periods themselves ... |
|
|
foilPeriodWsList = [ periodWsList[foilPeriod - 1] for foilPeriod in foilPeriods ] |
|
|
monFoilPeriodWsList = [ monPeriodWsList[foilPeriod - 1] for monFoilPeriod in monFoilPeriods ] |
|
|
# .. then use those handles to get wrappers to the actual data in those periods. |
|
|
foilPeriodWsDataList = [ foilPeriodWs.dataY(wsIndex) for foilPeriodWs in foilPeriodWsList ] |
|
|
monFoilPeriodWsDataList = [ monFoilPeriodWs.dataY(0) for monFoilPeriodWs in monFoilPeriodWsList ] |
|
|
|
|
|
# Now zip up the period data. Zipping does the following: |
|
|
# A = 0, 1, 2, ... |
|
|
# B = 0, 1, 2, ... |
|
|
# zip(A, B) = (0, 0), (1, 1), (2, 2), ... |
|
|
zipped = itertools.izip(*foilPeriodWsDataList) |
|
|
monZipped = itertools.izip(*monFoilPeriodWsDataList) |
|
|
|
|
|
# Sum up the period data for each spectra. |
|
|
for i, z in itertools.izip(itertools.count(), zipped): |
|
|
foilWsMap[foilState].dataY(wsIndex)[i] = sum(z) |
|
|
|
|
|
# Sum up the period data for each spectra's monitors. |
|
|
for i, monZ in itertools.izip(itertools.count(), monZipped): |
|
|
monFoilWsMap[foilState].dataY(wsIndex)[i] = sum(monZ) |
|
|
|
|
|
# Iterate through each workspace index / foil state pair, and sum counts over spectra and monitor foil states. |
|
|
for wsIndex, foilState in itertools.product(periodMappings.iterkeys(), Foil.ANY): |
|
|
# Sum monitor counts between 600 and 700 usec, and add to monitor normalising map. |
|
|
monNorm = sumCountsBetweenTimes(monFoilWsMap[foilState], 600, 700) |
|
|
monSumMap[wsIndex, foilState] = monNorm |
|
|
|
|
|
# Convert back to spectra ID so we can decide which values to sum between. |
|
|
spectrumID = foilWsMap[foilState].getSpectrum(wsIndex).getSpectrumNo() |
|
|
# Sum between values, and add to sum normalising map. |
|
|
if spectrumID in DetectorGrouping.BACKWARD: |
|
|
sumMap[ wsIndex, foilState ] = sumCountsBetweenTimes(foilWsMap[foilState], 400, 450, wsIndex) |
|
|
elif spectrumID in DetectorGrouping.FORWARD: |
|
|
sumMap[ wsIndex, foilState ] = sumCountsBetweenTimes(foilWsMap[foilState], 410, 430, wsIndex) |
|
|
else: |
|
|
# We should never reach here. |
|
|
assert False, "Programming error in algorithm" |
|
|
|
|
|
# For each combination of ws index and foil state, normalise on monitor counts and spectra area sum. |
|
|
for wsIndex, foilState in itertools.product(periodMappings.iterkeys(), (Foil.ANY)): |
|
|
|
|
|
data = foilWsMap[foilState].dataY(wsIndex) |
|
|
|
|
|
monSum = monSumMap[wsIndex, foilState] |
|
|
if monSum is 0: |
|
|
monSum = 0.0000001 |
|
|
for i in range(0,len(data)): |
|
|
data[i] *= ( 1000 / monSum) |
|
|
|
|
|
# For each combination of ws index and foil state, normalise on monitor counts and spectra area sum. |
|
|
for wsIndex, foilState in itertools.product(periodMappings.iterkeys(), (Foil.IN)): |
|
|
|
|
|
data = foilWsMap[foilState].dataY(wsIndex) |
|
|
|
|
|
for i in range(0,len(data)): |
|
|
data[i] *= ( sumMap[wsIndex,Foil.OUT] / sumMap[wsIndex,foilState] ) |
|
|
|
|
|
CloneWorkspace(InputWorkspace=clonedWsName, OutputWorkspace=outputWsName) |
|
|
outputWs = mtd[outputWsName] |
|
|
|
|
|
for wsIndex in periodMappings: |
|
|
# Get spectra ID from wsIndex. |
|
|
spectrumID = foilWsMap[foilState].getSpectrum(wsIndex).getSpectrumNo() |
|
|
|
|
|
# |
|
|
cResult = outputWs.dataY(wsIndex) |
|
|
cOut = foilWsMap[Foil.OUT].dataY(wsIndex) |
|
|
cThin = foilWsMap[Foil.THIN].dataY(wsIndex) |
|
|
cThick = foilWsMap[Foil.THICK].dataY(wsIndex) |
|
|
|
|
|
for i in range(0, len(cResult)): |
|
|
if spectrumID in DetectorGrouping.BACKWARD: |
|
|
""" TODO: Backward difference calcs not having desired effect at the moment. |
|
|
Is the double difference below really the one used in RawB? """ |
|
|
|
|
|
#THICK DIFFERENCE |
|
|
#cResult[i] = cThick[i] - cOut[i] |
|
|
|
|
|
#DOUBLE DIFFERENCE |
|
|
#cResult[i] = cThick[i] * (1 - beta) - cOut[i] + beta * cThin[i] |
|
|
cResult[i] = cOut[i] * (1 - beta) - cThin[i] + beta * cThick[i] |
|
|
|
|
|
elif spectrumID in DetectorGrouping.FORWARD: |
|
|
# SINGLE DIFFERENCE |
|
|
cResult[i] = cThin[i] - cOut[i] |
|
|
|
|
|
# Set as the output workspace. |
|
|
self.setProperty('OutputWorkspace', outputWs) |
|
|
|
|
|
# Register algorthm with Mantid. |
|
|
mantid.registerPyAlgorithm(LoadEVSRaw()) |