Newer
Older
#pylint: disable=no-init, unused-variable
# we need to disable unused_variable because ws.dataY(n) returns a reference to the underlying c++ object
# that can be modified inplace
from mantid.kernel import *
from mantid.api import *
from LoadEmptyVesuvio import LoadEmptyVesuvio
import copy
import numpy as np
RUN_PROP = "Filename"
WKSP_PROP = "OutputWorkspace"
MODE_PROP = "Mode"
MODES=["SingleDifference", "DoubleDifference", "ThickDifference", "FoilOut", "FoilIn", "FoilInOut"]
SPECTRA_PROP = "SpectrumList"
INST_PAR_PROP = "InstrumentParFile"
# Raw workspace names which are necessary at the moment
SUMMED_WS, SUMMED_MON = "__loadraw_evs", "__loadraw_evs_monitors"
# Enumerate the indexes for the different foil state sums
IOUT = 0
ITHIN = 1
ITHICK = 2
# Enumerate the detector types
BACKWARD = 0
FORWARD = 1
_LOGGING_ = False
class LoadVesuvio(LoadEmptyVesuvio):
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
_ws_index = None
_spectrum_no = None
foil_map = None
_inst_prefix = None
_mon_spectra = None
_mon_index = None
_backward_spectra_list = None
_forward_spectra_list = None
_mon_scale = None
_beta = None
_tof_max = None
_mon_tof_max = None
_back_mon_norm = None
_back_period_sum1 = None
_back_period_sum2 = None
_back_foil_out_norm = None
_forw_mon_norm = None
_forw_period_sum1 = None
_forw_period_sum2 = None
_forw_foil_out_norm = None
_diff_opt = None
_spectra = None
_sumspectra = None
_raw_grp = None
_raw_monitors = None
_nperiods = None
_goodframes = None
pt_times = None
delta_t = None
mon_pt_times = None
delta_tmon = None
summed_ws = None
summed_mon = None
_spectra_type = None
_mon_norm_start = None
_mon_norm_end = None
_period_sum1_start = None
_period_sum1_end = None
_period_sum2_start = None
_period_sum2_end = None
_foil_out_norm_start = None
_foil_out_norm_end = None
sum1 = None
sum2 = None
sum3 = None
foil_thin = None
mon_out = None
mon_thin = None
foil_thick = None
mon_thick = None
foil_out = None
#----------------------------------------------------------------------------------------
return "Loads raw data produced by the Vesuvio instrument at ISIS."
#----------------------------------------------------------------------------------------
def PyInit(self):
self.declareProperty(RUN_PROP, "", StringMandatoryValidator(),
doc="The run numbers that should be loaded. E.g."
"14188 - for single run"
"14188-14195 - for summed consecutive runs"
"14188,14195 - for summed non-consecutive runs")
self.declareProperty(SPECTRA_PROP, "", StringMandatoryValidator(),
doc="The spectrum numbers to load. "
"A dash will load a range and a semicolon delimits spectra to sum")
self.declareProperty(MODE_PROP, "DoubleDifference", StringListValidator(MODES),
doc="The difference option. Valid values: %s" % str(MODES))
self.declareProperty(FileProperty(INST_PAR_PROP, "", action=FileAction.OptionalLoad,
extensions=["dat", "par"]),
doc="An optional IP file. If provided the values are used to correct "
"the default instrument values and attach the t0 values to each "
"detector")
self.declareProperty(SUM_PROP, False,
doc="If true then the final output is a single spectrum containing "
"the sum of all of the requested spectra. All detector angles/"
"parameters are averaged over the individual inputs")
self.declareProperty(WorkspaceProperty(WKSP_PROP, "", Direction.Output),
doc="The name of the output workspace.")
#----------------------------------------------------------------------------------------
def PyExec(self):
self._load_inst_parameters()
self._retrieve_input()
if "Difference" in self._diff_opt:
self._exec_difference_mode()
else:
self._exec_single_foil_state_mode()
#----------------------------------------------------------------------------------------
def validateInputs(self):
issues = {}
# Validtae run number ranges
run_str = self.getProperty(RUN_PROP).value
if "-" in run_str:
lower, upper = run_str.split("-")
if upper < lower:
issues[RUN_PROP] = "Range must be in format lower-upper"
return issues
#----------------------------------------------------------------------------------------
def _exec_difference_mode(self):
"""
Execution path when a difference mode is selected
"""
all_spectra = [item for sublist in self._spectra for item in sublist]
self._setup_raw(all_spectra)
self._create_foil_workspaces()
for ws_index, spectrum_no in enumerate(all_spectra):
self._ws_index, self._spectrum_no = ws_index, spectrum_no
self._set_spectra_type(spectrum_no)
self.foil_map = SpectraToFoilPeriodMap(self._nperiods)
self._integrate_periods()
self._sum_foil_periods()
self._normalise_by_monitor()
self._normalise_to_foil_out()
self._calculate_diffs()
# end of differencing loop
ip_file = self.getPropertyValue(INST_PAR_PROP)
if len(ip_file) > 0:
self.foil_out = self._load_ip_file(self.foil_out, ip_file)
if self._sumspectra:
self._sum_all_spectra()
self._store_results()
finally: # Ensures it happens whether there was an error or not
self._cleanup_raw()
#----------------------------------------------------------------------------------------
def _exec_single_foil_state_mode(self):
"""
Execution path when a single foil state is requested
"""
runs = self._get_runs()
if len(runs) > 1:
raise RuntimeError("Single soil state mode does not currently support summing "
"multiple files")
isis = config.getFacility("ISIS")
inst_prefix = isis.instrument("VESUVIO").shortName()
try:
run_str = inst_prefix + runs[0]
except ValueError:
run_str = runs[0]
all_spectra = [item for sublist in self._spectra for item in sublist]
ms.LoadRaw(Filename=run_str, OutputWorkspace=SUMMED_WS, SpectrumList=all_spectra,
EnableLogging=_LOGGING_)
raw_group = mtd[SUMMED_WS]
self._nperiods = raw_group.size()
first_ws = raw_group[0]
foil_out = WorkspaceFactory.create(first_ws)
x_values = first_ws.readX(0)
self.foil_out = foil_out
foil_map = SpectraToFoilPeriodMap(self._nperiods)
for ws_index, spectrum_no in enumerate(all_spectra):
self._set_spectra_type(spectrum_no)
foil_out_periods, foil_thin_periods, _ = self._get_foil_periods()
if self._diff_opt == "FoilOut":
raw_grp_indices = foil_map.get_indices(spectrum_no, foil_out_periods)
elif self._diff_opt == "FoilIn":
indices_thin = foil_map.get_indices(spectrum_no, foil_thin_periods)
indices_thick = foil_map.get_indices(spectrum_no, foil_thin_periods)
raw_grp_indices = indices_thin + indices_thick
elif self._diff_opt == "FoilInOut":
raw_grp_indices = range(0, self._nperiods)
else:
raise RuntimeError("Unknown single foil mode: %s." % (self._diff_opt))
dataY = foil_out.dataY(ws_index)
dataE = foil_out.dataE(ws_index)
for group_index in raw_grp_indices:
dataY += raw_group[group_index].readY(ws_index)
dataE += np.square(raw_group[group_index].readE(ws_index))
np.sqrt(dataE, dataE)
foil_out.setX(ws_index, x_values)
ip_file = self.getPropertyValue(INST_PAR_PROP)
if len(ip_file) > 0:
self.foil_out = self._load_ip_file(self.foil_out, ip_file)
if self._sumspectra:
self._sum_all_spectra()
self._store_results()
#----------------------------------------------------------------------------------------
def _load_inst_parameters(self):
"""
Loads an empty VESUVIO instrument and attaches the necessary
parameters as attributes
"""
isis = config.getFacility("ISIS")
empty_vesuvio_ws = self._load_empty_evs()
empty_vesuvio = empty_vesuvio_ws.getInstrument()
def to_int_list(str_param):
"""Return the list of numbers described by the string range"""
elements = str_param.split("-")
return range(int(elements[0]),int(elements[1]) + 1) # range goes x_l,x_h-1
# Attach parameters as attributes
self._inst_prefix = isis.instrument("VESUVIO").shortName()
parnames = empty_vesuvio.getParameterNames(False)
for name in parnames:
# Irritating parameter access doesn't let you query the type
# so resort to trying
try:
parvalue = empty_vesuvio.getNumberParameter(name)
except RuntimeError:
parvalue = empty_vesuvio.getStringParameter(name)
setattr(self, name, parvalue[0])
self._mon_spectra = [int(self.monitor_spectrum)]
self._mon_index = self._mon_spectra[0] - 1
self._backward_spectra_list = to_int_list(self.backward_scatter_spectra)
self._forward_spectra_list = to_int_list(self.forward_scatter_spectra)
self._mon_scale = self.monitor_scale
self._beta = self.double_diff_mixing
self._tof_max = self.tof_max
self._mon_tof_max = self.monitor_tof_max
# Normalisation ranges
def to_range_tuple(str_range):
"""Return a list of 2 floats giving the lower,upper range"""
elements = str_range.split("-")
return (float(elements[0]),float(elements[1]))
self._back_mon_norm = to_range_tuple(self.backward_monitor_norm)
self._back_period_sum1 = to_range_tuple(self.backward_period_sum1)
self._back_period_sum2 = to_range_tuple(self.backward_period_sum2)
self._back_foil_out_norm = to_range_tuple(self.backward_foil_out_norm)
self._forw_mon_norm = to_range_tuple(self.forward_monitor_norm)
self._forw_period_sum1 = to_range_tuple(self.forward_period_sum1)
self._forw_period_sum2 = to_range_tuple(self.forward_period_sum2)
self._forw_foil_out_norm = to_range_tuple(self.forward_foil_out_norm)
#----------------------------------------------------------------------------------------
def _retrieve_input(self):
self._diff_opt = self.getProperty(MODE_PROP).value
# Check for sets of spectra to sum. Semi colon delimits sets
# that should be summed
spectra_str = self.getPropertyValue(SPECTRA_PROP)
summed_blocks = spectra_str.split(";")
self._spectra = []
for block in summed_blocks:
prop = IntArrayProperty("unnamed", block)
numbers = prop.value.tolist()
if self._mon_spectra in numbers:
numbers.remove(self._spectra)
self._spectra.append(numbers)
#endfor
self._sumspectra = self.getProperty(SUM_PROP).value
#----------------------------------------------------------------------------------------
def _setup_raw(self, spectra):
self._raw_grp, self._raw_monitors = self._load_and_sum_runs(spectra)
nperiods = self._raw_grp.size()
first_ws = self._raw_grp[0]
self._nperiods = nperiods
self._goodframes = first_ws.getRun().getLogData("goodfrm").value
# Cache delta_t values
raw_t = first_ws.readX(0)
delay = raw_t[2] - raw_t[1]
# The original EVS loader, raw.for/rawb.for, does this. Done here to match results
raw_t = raw_t - delay
self.pt_times = raw_t[1:]
self.delta_t = (raw_t[1:] - raw_t[:-1])
mon_raw_t = self._raw_monitors[0].readX(0)
delay = mon_raw_t[2] - mon_raw_t[1]
# The original EVS loader, raw.for/rawb.for, does this. Done here to match results
mon_raw_t = mon_raw_t - delay
self.mon_pt_times = mon_raw_t[1:]
self.delta_tmon = (mon_raw_t[1:] - mon_raw_t[:-1])
#----------------------------------------------------------------------------------------
def _load_and_sum_runs(self, spectra):
"""Load the input set of runs & sum them if there
is more than one.
@param spectra :: The list of spectra to load
@returns a tuple of length 2 containing (main_detector_ws, monitor_ws)
"""
isis = config.getFacility("ISIS")
inst_prefix = isis.instrument("VESUVIO").shortName()
runs = self._get_runs()
self.summed_ws, self.summed_mon = "__loadraw_evs", "__loadraw_evs_monitors"
for index, run in enumerate(runs):
run = inst_prefix + str(run)
if index == 0:
out_name, out_mon = SUMMED_WS, SUMMED_MON
out_name, out_mon = SUMMED_WS + 'tmp', SUMMED_MON + 'tmp'
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
ms.LoadRaw(Filename=run,
SpectrumList=spectra,
OutputWorkspace=out_name,
LoadMonitors='Exclude',
EnableLogging=_LOGGING_)
ms.LoadRaw(Filename=run,
SpectrumList=self._mon_spectra,
OutputWorkspace=out_mon,
EnableLogging=_LOGGING_)
# Sum
if index > 0:
ms.Plus(LHSWorkspace=SUMMED_WS,
RHSWorkspace=out_name,
OutputWorkspace=SUMMED_WS,
EnableLogging=_LOGGING_)
ms.Plus(LHSWorkspace=SUMMED_MON,
RHSWorkspace=out_mon,
OutputWorkspace=SUMMED_MON,
EnableLogging=_LOGGING_)
ms.DeleteWorkspace(out_name, EnableLogging=_LOGGING_)
ms.DeleteWorkspace(out_mon, EnableLogging=_LOGGING_)
ms.CropWorkspace(Inputworkspace= SUMMED_WS,
OutputWorkspace=SUMMED_WS,
XMax=self._tof_max,
EnableLogging=_LOGGING_)
ms.CropWorkspace(Inputworkspace= SUMMED_MON,
OutputWorkspace=SUMMED_MON,
XMax=self._mon_tof_max,
EnableLogging=_LOGGING_)
return mtd[SUMMED_WS], mtd[SUMMED_MON]
#----------------------------------------------------------------------------------------
def _get_runs(self):
"""
Returns the runs as a list of strings
"""
run_str = self.getProperty(RUN_PROP).value
# Load is not doing the right thing when summing. The numbers don't look correct
if "-" in run_str:
lower, upper = run_str.split("-")
# Range goes lower to up-1 but we want to include the last number
runs = range(int(lower), int(upper)+1)
elif "," in run_str:
runs = run_str.split(",")
else:
runs = [run_str]
return runs
#----------------------------------------------------------------------------------------
def _set_spectra_type(self, spectrum_no):
Set whether this spectrum no is forward/backward scattering
and set the normalization range appropriately
@param spectrum_no The current spectrum no
"""
if spectrum_no >= self._backward_spectra_list[0] and spectrum_no <= self._backward_spectra_list[-1]:
self._spectra_type=BACKWARD
else:
self._spectra_type=FORWARD
if self._spectra_type == BACKWARD:
self._mon_norm_start, self._mon_norm_end = self._back_mon_norm
self._period_sum1_start, self._period_sum1_end = self._back_period_sum1
self._period_sum2_start, self._period_sum2_end = self._back_period_sum2
self._foil_out_norm_start, self._foil_out_norm_end = self._back_foil_out_norm
else:
self._mon_norm_start, self._mon_norm_end = self._forw_mon_norm
self._period_sum1_start, self._period_sum1_end = self._forw_period_sum1
self._period_sum2_start, self._period_sum2_end = self._forw_period_sum2
self._foil_out_norm_start, self._foil_out_norm_end = self._forw_foil_out_norm
#----------------------------------------------------------------------------------------
def _integrate_periods(self):
Calculates 2 arrays of sums, 1 per period, of the Y values from
the raw data between:
(a) period_sum1_start & period_sum1_end
(b) period_sum2_start & period_sum2_end.
It also creates a 3rd blank array that will be filled by calculate_foil_counts_per_us.
Operates on the current workspace index
"""
self.sum1 = np.zeros(self._nperiods)
self.sum2 = np.zeros(self._nperiods)
self.sum3 = np.zeros(3)
sum1_start,sum1_end = self._period_sum1_start, self._period_sum1_end
sum2_start,sum2_end = self._period_sum2_start,self._period_sum2_end
xvalues = self.pt_times
sum1_indices = np.where((xvalues > sum1_start) & (xvalues < sum1_end))
sum2_indices = np.where((xvalues > sum2_start) & (xvalues < sum2_end))
wsindex = self._ws_index
for i in range(self._nperiods):
yvalues = self._raw_grp[i].readY(wsindex)
self.sum1[i] = np.sum(yvalues[sum1_indices])
self.sum2[i] = np.sum(yvalues[sum2_indices])
if self.sum2[i] != 0.0:
self.sum1[i] /= self.sum2[i]
# Sort sum1 in increasing order and match the foil map
self.sum1 = self.foil_map.reorder(self.sum1)
#----------------------------------------------------------------------------------------
def _create_foil_workspaces(self):
"""
Create the workspaces that will hold the foil out, thin & thick results
The output will be a point workspace
"""
first_ws = self._raw_grp[0]
ndata_bins = first_ws.blocksize()
nhists = first_ws.getNumberHistograms()
data_kwargs = {'NVectors':nhists,'XLength':ndata_bins,'YLength':ndata_bins}
# This will be used as the result workspace
self.foil_out = WorkspaceFactory.create(first_ws, **data_kwargs)
self.foil_out.setDistribution(True)
self.foil_thin = WorkspaceFactory.create(first_ws, **data_kwargs)
# Monitors will be a different size
first_monws = self._raw_monitors[0]
nmonitor_bins = first_monws.blocksize()
monitor_kwargs = copy.deepcopy(data_kwargs)
monitor_kwargs['XLength'] = nmonitor_bins
monitor_kwargs['YLength'] = nmonitor_bins
self.mon_out = WorkspaceFactory.create(first_monws, **monitor_kwargs)
self.mon_thin = WorkspaceFactory.create(first_monws, **monitor_kwargs)
if self._nperiods == 2:
self.foil_thick = None
self.mon_thick = None
else:
self.foil_thick = WorkspaceFactory.create(first_ws, **data_kwargs)
self.mon_thick = WorkspaceFactory.create(first_monws, **monitor_kwargs)
#----------------------------------------------------------------------------------------
def _sum_foil_periods(self):
"""
Sums the counts in the different periods to get the total counts
for the foil out, thin foil & thick foil states for the back scattering detectors for the
current workspace index & spectrum number
foil_out_periods, foil_thin_periods, foil_thick_periods = self._get_foil_periods()
if self._nperiods == 6 and self._spectra_type == FORWARD:
mon_out_periods = (5,6)
mon_thin_periods = (3,4)
mon_thick_periods = foil_thick_periods
else:
# None indicates same as standard foil
mon_out_periods, mon_thin_periods, mon_thick_periods = (None,None,None)
# Foil out
self._sum_foils(self.foil_out, self.mon_out, IOUT, foil_out_periods, mon_out_periods)
# Thin foil
self._sum_foils(self.foil_thin, self.mon_thin, ITHIN, foil_thin_periods, mon_thin_periods)
# Thick foil
if foil_thick_periods is not None:
self._sum_foils(self.foil_thick, self.mon_thick, ITHICK,
foil_thick_periods, mon_thick_periods)
#----------------------------------------------------------------------------------------
def _get_foil_periods(self):
"""
Return the period numbers (starting from 1) that contribute to the
respective foil states
"""
if self._nperiods == 2:
foil_out_periods = (2)
foil_thin_periods = (1)
foil_thick_periods = None
elif self._nperiods == 3:
foil_out_periods = (3)
foil_thin_periods = (2)
foil_thick_periods = (1)
elif self._nperiods == 6:
if self._spectra_type == BACKWARD:
foil_out_periods = (5,6)
foil_thin_periods = (3,4)
foil_thick_periods = (1,2)
else:
foil_out_periods = (4,5,6)
foil_thin_periods = (1,2,3)
foil_thick_periods = (1,2)
elif self._nperiods == 9:
foil_out_periods = (7,8,9)
foil_thin_periods = (4,5,6)
foil_thick_periods = (1,2,3)
else:
pass
return foil_out_periods, foil_thin_periods, foil_thick_periods
#----------------------------------------------------------------------------------------
def _sum_foils(self, foil_ws, mon_ws, sum_index, foil_periods, mon_periods=None):
"""
Sums the counts from the given foil periods in the raw data group
@param foil_ws :: The workspace that will receive the summed counts
@param mon_ws :: The monitor workspace that will receive the summed monitor counts
@param sum_index :: An index into the sum3 array where the integrated counts will be
accumulated
@param foil_periods :: The period numbers that contribute to this sum
@param mon_periods :: The period numbers of the monitors that contribute to this monitor sum
(if None then uses the foil_periods)
"""
raw_grp_indices = self.foil_map.get_indices(self._spectrum_no, foil_periods)
wsindex = self._ws_index
outY = foil_ws.dataY(wsindex)
delta_t = self.delta_t
for grp_index in raw_grp_indices:
raw_ws = self._raw_grp[grp_index]
outY += raw_ws.readY(wsindex)
self.sum3[sum_index] += self.sum2[grp_index]
# Errors are calculated from counts
eout = np.sqrt(outY)/delta_t
foil_ws.setE(wsindex,eout)
outY /= delta_t
if mon_periods is None:
mon_periods = foil_periods
raw_grp_indices = self.foil_map.get_indices(self._spectrum_no, mon_periods)
outY = mon_ws.dataY(wsindex)
for grp_index in raw_grp_indices:
raw_ws = self._raw_monitors[grp_index]
outY += raw_ws.readY(self._mon_index)
outY /= self.delta_tmon
#----------------------------------------------------------------------------------------
def _normalise_by_monitor(self):
"""
Normalises by the monitor counts between mon_norm_start & mon_norm_end
instrument parameters for the current workspace index
indices_in_range = np.where((self.mon_pt_times >= self._mon_norm_start) & (self.mon_pt_times < self._mon_norm_end))
wsindex = self._ws_index
# inner function to apply normalization
def monitor_normalization(foil_ws, mon_ws):
"""
Applies monitor normalization to the given foil spectrum from the given
monitor spectrum.
mon_values = mon_ws.readY(wsindex)
mon_values_sum = np.sum(mon_values[indices_in_range])
foil_state = foil_ws.dataY(wsindex)
foil_state *= (self._mon_scale/mon_values_sum)
err = foil_ws.dataE(wsindex)
err *= (self._mon_scale/mon_values_sum)
monitor_normalization(self.foil_out, self.mon_out)
monitor_normalization(self.foil_thin, self.mon_thin)
if self._nperiods != 2:
monitor_normalization(self.foil_thick, self.mon_thick)
#----------------------------------------------------------------------------------------
def _normalise_to_foil_out(self):
Normalises the thin/thick foil counts to the
foil out counts between (foil_out_norm_start,foil_out_norm_end)
for the current workspace index
"""
# Indices where the given condition is true
range_indices = np.where((self.pt_times >= self._foil_out_norm_start) & (self.pt_times < self._foil_out_norm_end))
wsindex = self._ws_index
cout = self.foil_out.readY(wsindex)
sum_out = np.sum(cout[range_indices])
def normalise_to_out(foil_ws, foil_type):
values = foil_ws.dataY(wsindex)
sum_values = np.sum(values[range_indices])
if sum_values == 0.0:
self.getLogger().warning("No counts in %s foil spectrum %d." % (foil_type,self._spectrum_no))
sum_values = 1.0
norm_factor = (sum_out/sum_values)
values *= norm_factor
errors = foil_ws.dataE(wsindex)
errors *= norm_factor
normalise_to_out(self.foil_thin, "thin")
if self._nperiods != 2:
normalise_to_out(self.foil_thick, "thick")
#----------------------------------------------------------------------------------------
def _calculate_diffs(self):
"""
Based on the DifferenceType property, calculate the final output
spectra for the current workspace index
wsindex = self._ws_index
if self._diff_opt == "SingleDifference":
self._calculate_thin_difference(wsindex)
elif self._diff_opt == "DoubleDifference":
self._calculate_double_difference(wsindex)
elif self._diff_opt == "ThickDifference":
self._calculate_thick_difference(wsindex)
raise RuntimeError("Unknown difference type requested: %d" % self._diff_opt)
self.foil_out.setX(wsindex, self.pt_times)
#----------------------------------------------------------------------------------------
def _calculate_thin_difference(self, ws_index):
"""
Calculate difference between the foil out & thin foil
states for the given index. The foil out workspace
will become the output workspace
@param ws_index :: The current workspace index
"""
# Counts
cout = self.foil_out.dataY(ws_index)
if self._spectra_type == BACKWARD:
cout -= self.foil_thin.readY(ws_index)
else:
cout *= -1.0
cout += self.foil_thin.readY(ws_index)
# Errors
eout = self.foil_out.dataE(ws_index)
ethin = self.foil_thin.readE(ws_index)
np.sqrt((eout**2 + ethin**2), eout) # The second argument makes it happen in place
#----------------------------------------------------------------------------------------
def _calculate_double_difference(self, ws_index):
"""
Calculates the difference between the foil out, thin & thick foils
using the mixing parameter beta. The final counts are:
y = c_out(i)*(1-\beta) -c_thin(i) + \beta*c_thick(i).
The output will be stored in cout
@param ws_index :: The current index being processed
"""
cout = self.foil_out.dataY(ws_index)
one_min_beta = (1. - self._beta)
cout *= one_min_beta
cout -= self.foil_thin.readY(ws_index)
cout += self._beta*self.foil_thick.readY(ws_index)
# Errors
eout = self.foil_out.dataE(ws_index)
ethin = self.foil_thin.readE(ws_index)
ethick = self.foil_thick.readE(ws_index)
# The second argument makes it happen in place
np.sqrt((one_min_beta*eout)**2 + ethin**2 + (self._beta**2)*ethick**2, eout)
#----------------------------------------------------------------------------------------
def _calculate_thick_difference(self, ws_index):
"""
Calculates the difference between the foil out & thick foils
The output will be stored in cout
@param ws_index :: The current index being processed
"""
# Counts
cout = self.foil_out.dataY(ws_index)
cout -= self.foil_thick.readY(ws_index)
# Errors
eout = self.foil_out.dataE(ws_index)
ethick = self.foil_thick.readE(ws_index)
np.sqrt((eout**2 + ethick**2), eout) # The second argument makes it happen in place
#----------------------------------------------------------------------------------------
def _sum_all_spectra(self):
"""
Sum requested sets of spectra together
"""
nspectra_out = len(self._spectra)
ws_out = WorkspaceFactory.create(self.foil_out, NVectors=nspectra_out)
# foil_out has all spectra in order specified by input
foil_start = 0
for idx_out in range(len(self._spectra)):
ws_out.setX(idx_out, self.foil_out.readX(foil_start))
summed_set = self._spectra[idx_out]
nsummed = len(summed_set)
y_out, e_out = ws_out.dataY(idx_out), ws_out.dataE(idx_out)
spec_out = ws_out.getSpectrum(idx_out)
spec_out.setSpectrumNo(self.foil_out.getSpectrum(foil_start).getSpectrumNo())
spec_out.clearDetectorIDs()
for foil_idx in range(foil_start, foil_start+nsummed):
y_out += self.foil_out.readY(foil_idx)
foil_err = self.foil_out.readE(foil_idx)
e_out += foil_err*foil_err # gaussian errors
in_ids = self.foil_out.getSpectrum(foil_idx).getDetectorIDs()
for det_id in in_ids:
spec_out.addDetectorID(det_id)
#endfor
np.sqrt(e_out, e_out)
foil_start += nsummed
#endfor
self.foil_out = ws_out
#----------------------------------------------------------------------------------------
def _store_results(self):
"""
Sets the values of the output workspace properties
"""
self.setProperty(WKSP_PROP, self.foil_out)
def _cleanup_raw(self):
"""
Clean up the raw data files
"""
if SUMMED_WS in mtd:
ms.DeleteWorkspace(SUMMED_WS,EnableLogging=_LOGGING_)
if SUMMED_MON in mtd:
ms.DeleteWorkspace(SUMMED_MON,EnableLogging=_LOGGING_)
#########################################################################################
class SpectraToFoilPeriodMap(object):
"""Defines the mapping between a spectrum number
& the period index into a WorkspaceGroup for a foil state.
"""
def __init__(self, nperiods=6):
"""Constructor. For nperiods seet up the mappings"""
if nperiods == 2:
self._one_to_one = {1:1, 2:2}
self._odd_even = {1:1, 2:3}
self._even_odd = {1:2, 2:4}
elif nperiods == 3:
self._one_to_one = {1:1, 2:2, 3:3}
self._odd_even = {1:1, 2:3, 3:5}
self._even_odd = {1:2, 2:4, 3:6}
elif nperiods == 6:
self._one_to_one = {1:1, 2:2, 3:3, 4:4, 5:5, 6:6}
self._odd_even = {1:1, 2:3, 3:5, 4:2, 5:4, 6:6}
self._even_odd = {1:2, 2:4, 3:6, 4:1, 5:3, 6:5}
elif nperiods == 9:
self._one_to_one = {1:1, 2:2, 3:3, 4:4, 5:5, 6:6, 7:7, 8:8, 9:9}
self._odd_even = {1:1, 2:3, 3:5, 4:2, 5:4, 6:6, 7:7, 8:8, 9:9}
self._even_odd = {1:2, 2:4, 3:6, 4:1, 5:3, 6:5, 7:7, 8:8, 9:9}
else:
raise RuntimeError("Unsupported number of periods given: " + str(nperiods) +
". Supported number of periods=2,3,6,9")
#----------------------------------------------------------------------------------------
def reorder(self, arr):
"""
Orders the given array by increasing value. At the same time
it reorders the 1:1 map to match this order
numpy
"""
vals = np.array(self._one_to_one.values())
sorted_indices = arr.argsort()
vals = vals[sorted_indices]
arr = arr[sorted_indices]
self._one_to_one = {}
for index,val in enumerate(vals):
self._one_to_one[index+1] = int(val)
return arr
#----------------------------------------------------------------------------------------
def get_foilout_periods(self, spectrum_no):
"""Returns a list of the foil-out periods for the given
spectrum number. Note that these start from 1 not zero
@param spectrum_no :: A spectrum number (1->nspectra)
@returns A list of period numbers for foil out state
"""
return self.get_foil_periods(spectrum_no, state=0)
#----------------------------------------------------------------------------------------
def get_foilin_periods(self, spectrum_no):
"""Returns a list of the foil-out periods for the given
spectrum number. Note that these start from 1 not zero
@param spectrum_no :: A spectrum number (1->nspectra)
@returns A list of period numbers for foil out state
"""
return self.get_foil_periods(spectrum_no, state=1)
#----------------------------------------------------------------------------------------
def get_foil_periods(self, spectrum_no, state):
"""Returns a list of the periods for the given
spectrum number & foil state. Note that these start from 1 not zero
@param spectrum_no :: A spectrum number (1->nspectra)
@param state :: 0 = foil out, 1 = foil in.
@returns A list of period numbers for foil out state
"""
self._validate_spectrum_number(spectrum_no)
foil_out = (state==0)
if spectrum_no < 135:
foil_periods = [1,2,3]
elif (spectrum_no >= 135 and spectrum_no <= 142) or \
(spectrum_no >= 151 and spectrum_no <= 158) or \
(spectrum_no >= 167 and spectrum_no <= 174) or \
(spectrum_no >= 183 and spectrum_no <= 190):
foil_periods = [2,4,6] if foil_out else [1,3,5]
else:
foil_periods = [1,3,5] if foil_out else [2,4,6]
return foil_periods
#----------------------------------------------------------------------------------------
def get_indices(self, spectrum_no, foil_state_numbers):
"""
Returns a tuple of indices that can be used to access the Workspace within
a WorkspaceGroup that corresponds to the foil state numbers given
@param spectrum_no :: A spectrum number (1->nspectra)
@param foil_state_no :: A number between 1 & 9(inclusive) that defines which foil
state is required
@returns A tuple of indices in a WorkspaceGroup that gives the associated Workspace
"""
indices = []
for state in foil_state_numbers:
indices.append(self.get_index(spectrum_no, state))
return tuple(indices)
#----------------------------------------------------------------------------------------
def get_index(self, spectrum_no, foil_state_no):
"""Returns an index that can be used to access the Workspace within
a WorkspaceGroup that corresponds to the foil state given
@param spectrum_no :: A spectrum number (1->nspectra)
@param foil_state_no :: A number between 1 & 9(inclusive) that defines which
foil state is required
@returns The index in a WorkspaceGroup that gives the associated Workspace
"""
self._validate_foil_number(foil_state_no)
self._validate_spectrum_number(spectrum_no)
# For the back scattering banks or foil states > 6 then there is a 1:1 map
if foil_state_no > 6 or spectrum_no < 135:
foil_periods = self._one_to_one
elif (spectrum_no >= 135 and spectrum_no <= 142) or \
(spectrum_no >= 151 and spectrum_no <= 158) or \
(spectrum_no >= 167 and spectrum_no <= 174) or \
(spectrum_no >= 183 and spectrum_no <= 190):
# foil_in = 1,3,5, foil out = 2,4,6
else:
# foil_in = 2,4,6 foil out = 1,3,5
foil_periods = self._even_odd
foil_period_no = foil_periods[foil_state_no]
return foil_period_no - 1 # Minus 1 to get to WorkspaceGroup index
#----------------------------------------------------------------------------------------
def _validate_foil_number(self, foil_number):
if foil_number < 1 or foil_number > 9:
raise ValueError("Invalid foil state given, expected a number between "
"1 and 9. number=%d" % foil_number)
#----------------------------------------------------------------------------------------
def _validate_spectrum_number(self, spectrum_no):
if spectrum_no < 1 or spectrum_no > 198:
raise ValueError("Invalid spectrum given, expected a number between 3 "
"and 198. spectrum=%d" % spectrum_no)
#########################################################################################
# Registration
AlgorithmFactory.subscribe(LoadVesuvio)