def PyExec(self): setup_prog = Progress(self, start=0.05, end=0.95, nreports=3) self._tmp_fit_name = "__fit_ws" self._crop_ws(self._sample_ws, self._tmp_fit_name, self._e_min, self._e_max) convert_to_hist_alg = self.createChildAlgorithm("ConvertToHistogram", enableLogging=False) convert_to_hist_alg.setProperty("InputWorkspace", self._tmp_fit_name) convert_to_hist_alg.setProperty("OutputWorkspace", self._tmp_fit_name) convert_to_hist_alg.execute() mtd.addOrReplace(self._tmp_fit_name, convert_to_hist_alg.getProperty("OutputWorkspace").value) self._convert_to_elasticQ(self._tmp_fit_name) num_hist = self._sample_ws.getNumberHistograms() if self._hist_max is None: self._hist_max = num_hist - 1 setup_prog.report('Fitting 1 peak') self._fit(1) setup_prog.report('Fitting 2 peaks') self._fit(2) self._delete_ws(self._tmp_fit_name) chi_group = self._output_name + '_ChiSq' chi_ws1 = self._output_name + '_1L_ChiSq' chi_ws2 = self._output_name + '_2L_ChiSq' self._clone_ws(chi_ws1, chi_group) self._append(chi_group, chi_ws2, chi_group) ws = mtd[chi_group] ax = TextAxis.create(2) for i, x in enumerate(['1 peak', '2 peaks']): ax.setLabel(i, x) ws.replaceAxis(1, ax) self._delete_ws(chi_ws1) self._delete_ws(chi_ws2) res_group = self._output_name + '_Result' res_ws1 = self._output_name + '_1L_Result' res_ws2 = self._output_name + '_2L_Result' self._extract(res_ws1, res_group, 1) self._extract(res_ws2, '__spectrum', 1) self._append(res_group, '__spectrum', res_group) self._extract(res_ws2, '__spectrum', 3) self._append(res_group, '__spectrum', res_group) ws = mtd[res_group] ax = TextAxis.create(3) for i, x in enumerate(['fwhm.1', 'fwhm.2.1', 'fwhm.2.2']): ax.setLabel(i, x) ws.replaceAxis(1, ax) self._delete_ws(res_ws1) self._delete_ws(res_ws2) self._delete_ws(self._output_name + '_1L_Parameters') self._delete_ws(self._output_name + '_2L_Parameters')
def _create_parameter_workspace(num_spec, param_table): num_params = param_table.rowCount() param_workspace = WorkspaceFactory.Instance().create( "Workspace2D", num_params, num_spec, num_spec) x_axis = TextAxis.create(num_spec) param_workspace.replaceAxis(0, x_axis) y_axis = TextAxis.create(num_params) for idx, parameter_name in enumerate(param_table.column('Name')): y_axis.setLabel(idx, parameter_name) param_workspace.replaceAxis(1, y_axis) return param_workspace
def _create_param_workspace(num_spec, param_table): num_params = param_table.rowCount() param_workspace = WorkspaceFactory.Instance().create("Workspace2D", num_params, num_spec, num_spec) x_axis = TextAxis.create(num_spec) param_workspace.replaceAxis(0, x_axis) vert_axis = TextAxis.create(num_params) for idx, param_name in enumerate(param_table.column('Name')): vert_axis.setLabel(idx, param_name) param_workspace.replaceAxis(1, vert_axis) return param_workspace
def create_fit_tables(self): wslist = [] # ws to be grouped # extract fit parameters and errors nruns = len( self.get_loaded_ws_list()) # num of rows of output workspace # get unique set of function parameters across all workspaces func_params = set( chain(*[ list(d['results'].keys()) for d in self._fit_results.values() ])) for param in func_params: # get max number of repeated func in a model (num columns of output workspace) nfuncs = max([ len(d['results'][param]) for d in self._fit_results.values() if param in d['results'] ]) # make output workspace ipeak = list(range(1, nfuncs + 1)) * nruns ws = CreateWorkspace(OutputWorkspace=param, DataX=ipeak, DataY=ipeak, NSpec=nruns) # axis for labels in workspace axis = TextAxis.create(nruns) for iws, wsname in enumerate(self.get_active_ws_name_list()): if wsname in self._fit_results and param in self._fit_results[ wsname]['results']: fitvals = array( self._fit_results[wsname]['results'][param]) data = vstack( (fitvals, full((nfuncs - fitvals.shape[0], 2), nan))) else: data = full((nfuncs, 2), nan) ws.setY(iws, data[:, 0]) ws.setE(iws, data[:, 1]) # label row axis.setLabel(iws, wsname) ws.replaceAxis(1, axis) wslist += [ws] # table for model summary/info model = CreateEmptyTableWorkspace(OutputWorkspace='model') model.addColumn(type="str", name="Workspace") model.addColumn(type="float", name="chisq/DOF" ) # always is for LM minimiser (users can't change) model.addColumn(type="str", name="status") model.addColumn(type="str", name="Model") for iws, wsname in enumerate(self.get_active_ws_name_list()): if wsname in self._fit_results: row = [ wsname, self._fit_results[wsname]['costFunction'], self._fit_results[wsname]['status'], self._fit_results[wsname]['model'] ] self.write_table_row(model, row, iws) else: self.write_table_row(model, ['', nan, ''], iws) wslist += [model] group_name = self._log_workspaces.name().split('_log')[0] + '_fits' self._fit_workspaces = GroupWorkspaces(wslist, OutputWorkspace=group_name)
def convertParametersToWorkspace(params_table, x_column, param_names, output_name): """ Convert a parameter table output by PlotPeakByLogValue to a MatrixWorkspace. This will make a spectrum for each parameter name using the x_column vairable as the x values for the spectrum. @param params_table - the table workspace to convert to a MatrixWorkspace. @param x_column - the column in the table to use for the x values. @param parameter_names - list of parameter names to add to the workspace @param output_name - name to call the output workspace. """ # Search for any parameters in the table with the given parameter names, # ignoring their function index and output them to a workspace workspace_names = [] for param_name in param_names: column_names = search_for_fit_params(param_name, params_table) column_error_names = search_for_fit_params(param_name + '_Err', params_table) param_workspaces = [] for name, error_name in zip(column_names, column_error_names): ConvertTableToMatrixWorkspace(params_table, x_column, name, error_name, OutputWorkspace=name) param_workspaces.append(name) workspace_names.append(param_workspaces) # Transpose list of workspaces, ignoring unequal length of lists # this handles the case where a parameter occurs only once in the whole workspace workspace_names = map(list, itertools.izip_longest(*workspace_names)) workspace_names = [filter(None, sublist) for sublist in workspace_names] # Join all the parameters for each peak into a single workspace per peak temp_workspaces = [] for peak_params in workspace_names: temp_peak_ws = peak_params[0] for param_ws in peak_params[1:]: ConjoinWorkspaces(temp_peak_ws, param_ws, False) temp_workspaces.append(temp_peak_ws) # Join all peaks into a single workspace temp_workspace = temp_workspaces[0] for temp_ws in temp_workspaces[ 1:]: # TODO: fairly certain something is wrong here ConjoinWorkspaces(temp_workspace, temp_peak_ws, False) RenameWorkspace(temp_workspace, OutputWorkspace=output_name) # Replace axis on workspaces with text axis axis = TextAxis.create(mtd[output_name].getNumberHistograms()) workspace_names = [name for sublist in workspace_names for name in sublist] for i, name in enumerate(workspace_names): axis.setLabel(i, name) mtd[output_name].replaceAxis(1, axis)
def set_y_axis_labels(self, workspace, labels): """ adds the spectrum_index to the plot labels """ axis = TextAxis.create(len(labels)) for index, label in enumerate(labels): axis.setLabel(index, label) workspace.replaceAxis(1, axis)
def _origin_data(self, ws): workdir = config['defaultsave.directory'] path = os.path.join(workdir, self._origin_file) logger.information('Origin source is file: %s' % self._origin_file) try: handle = open(path, 'r') asc = [] for line in handle: line = line.rstrip() asc.append(line) handle.close() except: raise LookupError('Could not load file %s' % path) len_asc = len(asc) lines = int(asc[0]) if lines != len_asc -1: raise LookupError('Text file error : inconsistent number of lines %i' % lines) number_histograms = mtd[ws].getNumberHistograms() # no. of hist/groups if lines != number_histograms: raise LookupError('Text file error : number of lines %i not = spectra %i' % (lines, number_histograms)) ExtractSingleSpectrum(InputWorkspace=ws, OutputWorkspace='__left_temp', WorkspaceIndex=0) x_axis = mtd['__left_temp'].readX(0) DeleteWorkspace('__left_temp') x = [] self._left_mean = [] self._right_mean = [] for n in range(lines): values = asc[n+1].split() values = map(int, values) if values[0] != n + 1: raise LookupError('Text file error : inconsistent sequence number %i' % n) x.append(n) self._left_mean.append(x_axis[values[1]]) self._right_mean.append(x_axis[values[2]]) xData = np.array(x) xData = np.append(xData, x) yData = np.array(self._left_mean) yData = np.append(yData, self._right_mean) CreateWorkspace(OutputWorkspace=self._origin_file, DataX=xData, DataY=yData, Nspec=2) y_axis = TextAxis.create(2) mtd[self._origin_file].replaceAxis(1, y_axis) y_axis.setLabel(0, 'left') y_axis.setLabel(1, 'right') mtd[self._origin_file].setYUnitLabel('Peak centre (channel)')
def convertParametersToWorkspace(params_table, x_column, param_names, output_name): """ Convert a parameter table output by PlotPeakByLogValue to a MatrixWorkspace. This will make a spectrum for each parameter name using the x_column vairable as the x values for the spectrum. @param params_table - the table workspace to convert to a MatrixWorkspace. @param x_column - the column in the table to use for the x values. @param parameter_names - list of parameter names to add to the workspace @param output_name - name to call the output workspace. """ # Search for any parameters in the table with the given parameter names, # ignoring their function index and output them to a workspace workspace_names = [] for param_name in param_names: column_names = search_for_fit_params(param_name, params_table) column_error_names = search_for_fit_params(param_name + '_Err', params_table) param_workspaces = [] for name, error_name in zip(column_names, column_error_names): ConvertTableToMatrixWorkspace(params_table, x_column, name, error_name, OutputWorkspace=name) param_workspaces.append(name) workspace_names.append(param_workspaces) # Transpose list of workspaces, ignoring unequal length of lists # this handles the case where a parameter occurs only once in the whole workspace workspace_names = map(list, itertools.izip_longest(*workspace_names)) workspace_names = [filter(None, sublist) for sublist in workspace_names] # Join all the parameters for each peak into a single workspace per peak temp_workspaces = [] for peak_params in workspace_names: temp_peak_ws = peak_params[0] for param_ws in peak_params[1:]: ConjoinWorkspaces(temp_peak_ws, param_ws, False) temp_workspaces.append(temp_peak_ws) # Join all peaks into a single workspace temp_workspace = temp_workspaces[0] for temp_ws in temp_workspaces[1:]: # TODO: fairly certain something is wrong here ConjoinWorkspaces(temp_workspace, temp_peak_ws, False) RenameWorkspace(temp_workspace, OutputWorkspace=output_name) # Replace axis on workspaces with text axis axis = TextAxis.create(mtd[output_name].getNumberHistograms()) workspace_names = [name for sublist in workspace_names for name in sublist] for i, name in enumerate(workspace_names): axis.setLabel(i, name) mtd[output_name].replaceAxis(1, axis)
def insert_bank_numbers(input_workspace: Union[str, Workspace2D], grouping_workspace: Union[str, WorkspaceGroup]): r""" Label each spectra according to each bank number @param input_workspace : workpace with spectra to be labelled @param grouping_workspace : group workspace has the group ID (bank number) for each pixel """ input_handle, grouping_handle = mtd[str(input_workspace)], mtd[str( grouping_workspace)] group_ids = sorted(list(set(grouping_handle.extractY().flatten()))) assert input_handle.getNumberHistograms() == len(group_ids) axis = TextAxis.create(len(group_ids)) [ axis.setLabel(index, f'bank{group_id}') for index, group_id in enumerate(group_ids) ] input_handle.replaceAxis(1, axis)
def _subtract_corr(self): #subtract corrections from input to give _data_used & _result calc_prog = Progress(self, start=0.0, end=0.8, nreports=3) calc_prog.report('Subtract corrections ') logger.information('Subtracting corrections') self._data_used = self._data + '_used' if self._smooth: #select which hist to use index = 1 else: index= 0 self._extract(self._data, self._data_used, index) self._extract(self._corr, '__wcr', 0) wsc1 = 'S-1C' #1 term subtracted self._plus(self._data_used, '__wcr', wsc1) wsc2 = 'S-2C' #2 terms subtracted self._extract(self._corr, '__wcr', 1) self._plus(wsc1, '__wcr', wsc2) wsc3 = 'S-3C' #3 terms subtracted self._extract(self._corr, '__wcr', 2) self._plus(wsc2, '__wcr', wsc3) wsc4 = 'S-4C' #4 terms subtracted self._extract(self._corr, '__wcr', 3) self._plus(wsc3, '__wcr', wsc4) self._result = self._data + '_result' #results WS self._clone_ws(wsc1, self._result) self._append(self._result, wsc2, self._result) self._append(self._result, wsc3, self._result) self._append(self._result, wsc4, self._result) ax = TextAxis.create(4) for i, x in enumerate(['S-1C', 'S-2C', 'S-3C', 'S-4C']): ax.setLabel(i, x) mtd[self._result].replaceAxis(1, ax) subtract_logs = [('smooth', self._smooth)] log_names = [item[0] for item in subtract_logs] log_values = [item[1] for item in subtract_logs] self._add_sample_log_mult(self._result, log_names, log_values) workspaces = ['__wcr', wsc1, wsc2, wsc3, wsc4] for ws in workspaces: self._delete_ws(ws) logger.information('Results in WS %s' % self._result)
def _corr_terms(self): #calculates the correction terms = coef*deriv as _corr calc_prog = Progress(self, start=0.0, end=0.8, nreports=3) calc_prog.report('Correction terms ') logger.information('Calculating Correction terms') self._corr = self._data + '_corr' #corrections WS self._extract(self._deriv, '__temp', 0) self._spline_interp('__temp', self._coeff, self._coeff, '', 2) self._multiply(self._coeff, self._deriv, self._corr) ax = TextAxis.create(4) for i, x in enumerate(['Corr.1', 'Corr.2', 'Corr.3', 'Corr.4']): ax.setLabel(i, x) mtd[self._corr].replaceAxis(1, ax) self._copy_log(self._mome, self._corr, 'MergeKeepExisting') self._delete_ws('__temp') logger.information('Correction terms WS created : %s' % self._corr) calc_prog.report('Correction terms completed')
def PyExec(self): self._setup() temp_raw = '__raw' temp_left = '__red_left' temp_right = '__red_right' temp_red = '__red' # Do an energy transfer reduction IndirectILLReduction(Run=self._input_file, CalibrationWorkspace='', Analyser='silicon', Reflection='111', MirrorMode=self._mirror_mode, RawWorkspace=temp_raw, LeftWorkspace=temp_left, RightWorkspace=temp_right, ReducedWorkspace=temp_red, MapFile=self._map_file) self._setup_mirror(temp_raw) # Integrate within peak range number_histograms = mtd[temp_red].getNumberHistograms() Integration(InputWorkspace=temp_red, OutputWorkspace=self._calib_ws + '_sum', RangeLower=float(self._peak_range[0]), RangeUpper=float(self._peak_range[1])) ws_mask, num_zero_spectra = FindDetectorsOutsideLimits(InputWorkspace=self._calib_ws + '_sum', OutputWorkspace='__temp_ws_mask') DeleteWorkspace(ws_mask) if self._mirror_mode: Integration(InputWorkspace=temp_left, OutputWorkspace=self._calib_ws + '_left', RangeLower=float(self._peak_range[0]), RangeUpper=float(self._peak_range[1])) Integration(InputWorkspace=temp_right, OutputWorkspace=self._calib_ws + '_right', RangeLower=float(self._peak_range[0]), RangeUpper=float(self._peak_range[1])) workspaces = [self._calib_ws + '_sum', self._calib_ws + '_left', self._calib_ws + '_right'] else: CloneWorkspace(InputWorkspace=self._calib_ws + '_sum', OutputWorkspace=self._calib_ws + '_red') workspaces = [self._calib_ws + '_sum', self._calib_ws + '_red'] for ws in workspaces: # Process automatic scaling temp_sum = '__sum' SumSpectra(InputWorkspace=ws, OutputWorkspace=temp_sum) total = mtd[temp_sum].readY(0)[0] DeleteWorkspace(temp_sum) if self._intensity_scale is None: self._intensity_scale = 1 / (total / (number_histograms - num_zero_spectra)) # Apply scaling factor Scale(InputWorkspace=ws, OutputWorkspace=ws, Factor=self._intensity_scale, Operation='Multiply') GroupWorkspaces(InputWorkspaces=workspaces, OutputWorkspace=self._calib_ws) self.setProperty('OutputWorkspace', self._calib_ws) # if mirror mode, calculate means if self._mirror_mode: left_mean = 'left_mean' self._calc_mean(temp_left, left_mean) right_mean = 'right_mean' self._calc_mean(temp_right, right_mean) RenameWorkspace(InputWorkspace=left_mean, OutputWorkspace=self._origin_ws) ConjoinWorkspaces(InputWorkspace1=self._origin_ws, InputWorkspace2=right_mean, CheckOverlapping=False) y_axis = TextAxis.create(number_histograms) mtd[self._origin_ws].replaceAxis(1, y_axis) y_axis.setLabel(0, 'left') y_axis.setLabel(1, 'right') mtd[self._origin_ws].setYUnitLabel('Peak centre (meV)') DeleteWorkspace(temp_left) DeleteWorkspace(temp_right) else: red_mean = 'red_mean' self._calc_mean(temp_red, red_mean) RenameWorkspace(InputWorkspace=red_mean, OutputWorkspace=self._origin_ws) y_axis = TextAxis.create(number_histograms) mtd[self._origin_ws].replaceAxis(1, y_axis) y_axis.setLabel(0, 'red') # Clean up unused workspaces DeleteWorkspace(temp_raw) DeleteWorkspace(temp_red)
def set_y_axis_labels(workspace, labels): axis = TextAxis.create(len(labels)) for index, label in enumerate(labels): axis.setLabel(index, label) workspace.replaceAxis(1, axis)
def _calc_coeff(self): #creates output _coeff calc_prog = Progress(self, start=0.0, end=0.8, nreports=3) calc_prog.report('Calculating coefficents ') smooth_ws = '__smooth' mome_ws = '__mome' # start interpolating moments to S(theta) & normalising to m0 logger.information('Calculating Coefficients') self._extract(self._data, smooth_ws, 1) self._spline_interp(smooth_ws, self._mome, mome_ws, '__deriv', 2) m0 = '__M0' self._extract(mome_ws, m0, 0) m1 = '__M1' self._extract(mome_ws, m1, 1) self._divide(m1, m0, m1) m2 = '__M2' self._extract(mome_ws, m2, 2) self._divide(m2, m0, m2) m3 = '__M3' self._extract(mome_ws, m3, 3) self._divide(m3, m0, m3) m4 = '__M4' self._extract(mome_ws, m4, 4) self._divide(m4, m0, m4) ### Henry 17 Sept 14: From ADD2011 poster, here are the correct ### signs for the coeffs, using the "positive" sign convention: # c1 = -A1 # c2 = -A2 +A1*A1 # c3 = -A3 +2*A1*A2 -A1*A1*A1 # c4 = -A4 +2A1*A3 +A2*A2 -3A1*A1*A2 +A1*A1*A1*A1 ### Note that the last two terms in c4 should have DIFFERENT signs, ### rather than the same signs as Spencer uses below: # S(2q) = J +c1J1 +c2J2 +c3J3 +c4J4 # An = Mn/M0 normalised moments ### Henry 17 Sept 14: Correct signs: c1 = -A1 (-m1) self._scale(m1, '__c1', -1.0) ### Henry 17 Sept 14: Correct signs: c2 = A2 - A11 (-m2 +m1*m1) self._scale(m2, '__c2', -1.0) # c2 = -1.0 * A2 self._multiply(m1, m1, '__a11') self._plus('__c2', '__a11', '__c2') # c2 += A1 * A1 ### Henry 17 Sept 14: Correct signs: c3 = A3 -2*A1*A2 +A11*A1 self._scale(m3, '__c3', -1.0) # c3 = -1.0 * A3 self._scale(m1, '__a12', 2.0) self._multiply('__a12', m2, '__a12') self._plus('__c3', '__a12', '__c3') # c3 += 2 * A1 * A2 self._multiply('__a11', m1, '__a111') self._minus('__c3', '__a111', '__c3') # c3 += - A1 * A1 * A1 ### Henry 17 Sept 14: Correct signs: c4 = A4 -2*A1*A3 -A2*A2 +3*A11*A2 +A11*A11 self._scale(m4, '__c4', -1.0) # c4 = -1.0 * A4 self._scale(m1, '__a13', 2.0) self._multiply('__a13', m3, '__a13') self._plus('__c4', '__a13', '__c4') # c4 += 2 * A1 * A3 self._multiply(m2, m2, '__a22') self._plus('__c4', '__a22', '__c4') # c4 += A2 * A2 self._scale('__a11', '__a112', -3.0) self._multiply('__a112', m2, '__a112') self._plus('__c4', '__a112', '__c4') # c4 += - 3 * A1 * A1 * A2 self._multiply('__a11', '__a11', '__a1111') self._plus('__c4', '__a112', '__c4') # c4 += A1 * A1 * A1 * A1 self._coeff = self._data + '_coeff' #coeffients WS self._clone_ws('__c1', self._coeff) self._append(self._coeff, '__c2', self._coeff) self._append(self._coeff, '__c3', self._coeff) self._append(self._coeff, '__c4', self._coeff) ax = TextAxis.create(4) for i, x in enumerate(['Coeff.1', 'Coeff.2', 'Coeff.3', 'Coeff.4']): ax.setLabel(i, x) mtd[self._coeff].replaceAxis(1, ax) self._copy_log(self._mome, self._coeff, 'MergeKeepExisting') workspaces = [m0, m1, m2, m3, m4, smooth_ws, mome_ws] for ws in workspaces: self._delete_ws(ws) workspaces = ['__a11', '__a111', '__a1111', '__a112', '__a12', '__a13', '__a22', \ '__c1', '__c2', '__c3', '__c4'] for ws in workspaces: self._delete_ws(ws) logger.information('Coefficient WS created : %s' % self._coeff) calc_prog.report('Calculating coefficents completed')
def criterion_peak_pixel_position(peak_table: InputTable, summary: Optional[str] = None, zscore_threshold: float = 2.5, deviation_threshold: float = 3) -> np.ndarray: r""" Flag tubes whose peak pixel positions deviate considerably from the peak pixel positions when averaged for all tubes in the bank. .. math:: <p_i> = \frac{1}{n_t} \Sum_{j=1}^{n_t} p_{ij} \delta_j^2 = \frac{1}{n_w} \Sum (p_{ij} - <p_i>)^2 assert d_j < threshold :param peak_table: pixel positions of the peaks for each tube :param summary: name of output Workspace2D containing deviations and Z-score for each tube. :param zscore_threshold: maximum Z-score for the pixels positions of a tube. :param deviation_threshold: maximum deviation (in pixels) for the pixels positions of a tube. The default value (3) corresponds to the height of three pixels. :return: array of booleans, one per tube. `True` is the tube passes the acceptance criterion, `False` otherwise. """ table = mtd[str(peak_table)] # handle to the peak table peak_count = table.columnCount() - 1 # the first column contains the names of the tubes # `positions_average` stores the pixel position for each peak, averaged for all tubes positions_average = [np.mean(table.column(column_number)) for column_number in range(1, 1 + peak_count)] deviations = list() # a measure of how much the peak positions in a tube deviate from the mean positions tube_count = table.rowCount() # number of tubes in the bank for tube_index in range(tube_count): positions = np.array(list(table.row(tube_index).values())[1:]) # peak positions for the current tube deviations.append(np.sqrt(np.mean(np.square(positions - positions_average)))) # find tubes with a large Z-score outlier_values = list() values = deepcopy(deviations) z_score = 1000 outlier_value = 1000 while z_score > zscore_threshold and outlier_value > deviation_threshold and len(values) > 0: # find the tube with the highest Z-score, possibly signaling a large deviation from the mean mean, std = np.mean(values), np.std(values) outlier_index = np.argmax(np.abs((values - mean) / std)) outlier_value = values[outlier_index] # recalculate the Z-score of the tube, but removing it from the pool of values. This removes # any skewing effects from including the aberrant tube in the calculation of its Z-score del values[outlier_index] mean, std = np.mean(values), np.std(values) z_score = np.abs((outlier_value - mean) / std) if z_score > zscore_threshold and outlier_value > deviation_threshold: outlier_values.append(outlier_value) # flag the outlier tubes as failing the criterion criterion_pass = np.tile(True, tube_count) # initialize as all tubes passing the criterion if len(outlier_values) > 0: failure_indexes = [deviations.index(value) for value in outlier_values] criterion_pass[failure_indexes] = False # create an analysis summary if so requested if isinstance(summary, str) and len(summary) > 0: success = [1 if criterion else 0 for criterion in criterion_pass] x_values = list(range(1, 1 + TUBES_IN_BANK)) mean, std = np.mean(deviations), np.std(deviations) z_scores = np.abs((deviations - mean) / std) y_values = np.array([success, deviations, z_scores]).flatten() workspace = CreateWorkspace(x_values, y_values, NSpec=3, OutputWorkspace=summary, WorkspaceTitle='Tube deviations from averages taken over the bank', YUnitLabel='Pixel Units', EnableLogging=False) labels = ('success', 'deviation', 'Z-score') axis = TextAxis.create(len(labels)) [axis.setLabel(index, label) for index, label in enumerate(labels)] workspace.replaceAxis(1, axis) return criterion_pass
def collect_bank_fit_results(output_workspace: str, acceptance_summary: Optional[WorkspaceTypes] = None, parameters_table_group: Optional[WorkspaceGroupTypes] = None) -> Optional[Workspace2D]: r""" Combine different results from the fitting process for one bank into one single workspace The output workspace has one spectrum for each fitting result. The spectra run over the tubes in the bank fit-result tube1, tube2,...,tube16 success 0 1 1 # was the tube successfully fitted? deviation 0.0005 0.0001 ... 0.0003 # see the acceptance criterion function for explanation of 'deviation' Z-score # Z-score associated to 'deviation` A0-value # y(n) = A0 + A1 * n + A2 * n^2 fits the peak positions in pixel coordinates to th A0-error # known positions of the slits, in meters A1-value A1-error A2-value A2-error :param output_workspace: name of the workspace containing the fitting results :param acceptance_summary: name or reference to the Workspace2D containing deviations and Z-score for each tube. :param parameters_table_group: name or reference to the WorkspaceGroup containing individual TableWorkspace tables. Each table holds values and errors for the optimized coefficients of the polynomial that fits the peak positions (in pixel coordinates) to the known slit positions (along the Y-coordinate). The last entry in the table holds the goodness-of-fit, chi-square value. The name of each individual TableWorkspace is the string `parameters_table_group` plus the suffix `_I`, where `I` is the tube index in the bank, startin at zero. If set to `None`, no group workspace is generated. :return: reference to the fit results workspace. Return `None` if no fit results are provided """ error_message = 'At least one of the input fit results should be different than None' assert acceptance_summary is not None or parameters_table_group is not None, error_message # fit_results_values is a dictionary with entries like this: # 'A0': [-0.521, -0.517,..., -0.524] # one value for each tube in the bank, and so on with A1 and A2 coefficients fit_results_values = {} fit_results_errors = {} # errors in the optimized values of the polynomial coefficients fit_result_names = [] # ['success', 'Z-score', ...] if acceptance_summary is not None: workspace = mtd[str(acceptance_summary)] axis = workspace.getAxis(1) for spectrum_index in range(workspace.getNumberHistograms()): fit_result_name = axis.label(spectrum_index) fit_result_names.append(fit_result_name) fit_results_values[fit_result_name] = workspace.readY(spectrum_index) fit_results_errors[fit_result_name] = workspace.readE(spectrum_index) if parameters_table_group is not None: workspace = mtd[str(parameters_table_group)] # collect the names of the polynomial coefficients using the first table first_table = mtd[workspace.getNames()[0]] # handle to the first table in the list for coefficient_name in first_table.column(0)[:-1]: # exclude the last item, which is the chi-square value fit_result_names.append(coefficient_name) fit_results_values[coefficient_name], fit_results_errors[coefficient_name] = [], [] # collect values and errors of the fit results for parameters_table in workspace: # iterate over the parameter tables, one table for each tube for table_row in parameters_table: # table_row is a dictionary, e.g. {'Name': 'A0', 'Value':-0.521, 'Error':0.003} coefficient_name = table_row['Name'] # polynomial fit coefficient if coefficient_name == 'Cost function value': # don't store the Chi-square value continue fit_results_values[coefficient_name].append(table_row['Value']) fit_results_errors[coefficient_name].append(table_row['Error']) # Create a workspace with the fit results, where each (key, values, errors) pair becomes one spectrum x_values = list(range(1, 1 + TUBES_IN_BANK)) y_values = [y for fit_result_values in fit_results_values.values() for y in fit_result_values] e_values = [e for fit_result_errors in fit_results_errors.values() for e in fit_result_errors] CreateWorkspace(DataX=x_values, DataY=y_values, DataE=e_values, NSpec=len(fit_result_names), OutputWorkspace=output_workspace, WorkspaceTitle='Fitting Results', EnableLogging=False) # label each spectrum of the workspace axis = TextAxis.create(len(fit_result_names)) [axis.setLabel(index, fit_result_name) for index, fit_result_name in enumerate(fit_result_names)] workspace = mtd[output_workspace] workspace.replaceAxis(1, axis) return workspace
def test_constructor_methods_return_the_correct_type(self): self.assertTrue(isinstance(NumericAxis.create(2), NumericAxis)) self.assertTrue( isinstance(SpectraAxis.create(self._test_ws), SpectraAxis)) self.assertTrue(isinstance(TextAxis.create(2), TextAxis))
def test_constructor_methods_return_the_correct_type(self): self.assertTrue(isinstance(NumericAxis.create(2), NumericAxis)) self.assertTrue(isinstance(SpectraAxis.create(2), SpectraAxis)) self.assertTrue(isinstance(TextAxis.create(2), TextAxis))