def output_data(self, x, y, e, data, NSpec, UnitX, norm, outputfn, metadata): """Save reduced data to file""" createWS_alg = self.createChildAlgorithm("CreateWorkspace", enableLogging=False) createWS_alg.setProperty("DataX", x) createWS_alg.setProperty("DataY", y) createWS_alg.setProperty("DataE", e) createWS_alg.setProperty("NSpec", NSpec) createWS_alg.setProperty("UnitX", UnitX) createWS_alg.setProperty("YUnitLabel", "Counts") createWS_alg.setProperty("WorkspaceTitle", str(metadata['scan_title']) + "_norm_" + norm) createWS_alg.execute() outWS = createWS_alg.getProperty("OutputWorkspace").value AnalysisDataService.addOrReplace(outputfn + "_norm_" + norm, outWS) self.add_metadata(outWS, metadata, data) # save reduced workspace to requested format save_data = self.getProperty("SaveData").value if save_data: outputdir = self.getProperty("OutputDirectory").value outputdir = outputdir if outputdir != "" else f"/HFIR/HB2A/IPTS-{metadata['proposal']}/shared" _outputfunc = { 'XYE': SaveFocusedXYE, 'GSAS': SaveGSSCW }[self.getProperty('OutputFormat').value] _outputext = { "XYE": 'dat', "GSAS": 'gss', }[self.getProperty('OutputFormat').value] outputbase = os.path.join(outputdir, outputfn) if norm == "mon": out_f_name = outputbase else: out_f_name = outputbase + "_norm_" + norm if self.getProperty('OutputFormat').value == "GSAS": _outputfunc( InputWorkspace=outWS, OutputFilename=f"{out_f_name}.{_outputext}", ) else: _outputfunc( InputWorkspace=outWS, Filename=f"{out_f_name}.{_outputext}", SplitFiles=False, )
def PyExec(self): scale = self.getProperty("Scale").value filenames = self.getProperty("Filename").value outputfn = self.getPropertyValue("OutputWorkspace") if not filenames: ipts = self.getProperty("IPTS").value exp = self.getProperty("Exp").value if self.getProperty("Exp").value == Property.EMPTY_INT: exp = int([ e for e in os.listdir('/HFIR/HB2A/IPTS-{0}'.format(ipts)) if 'exp' in e ][0].replace('exp', '')) filenames = [ '/HFIR/HB2A/IPTS-{0}/exp{1}/Datafiles/HB2A_exp{1:04}_scan{2:04}.dat' .format(ipts, exp, scan) for scan in self.getProperty("ScanNumbers").value ] metadata = None data = None # Read in data array and append all files for filename in filenames: # Read in all lines once with open(filename) as f: lines = f.readlines() if metadata is None: # Read in metadata from first file only file metadata = dict([ np.char.strip( re.split('#(.*?)=(.*)', line, flags=re.U)[1:3]) for line in lines if re.match('^#.*=', line) ]) # Get indir and exp from first file indir, data_filename = os.path.split(filename) _, exp, _ = data_filename.replace(".dat", "").split('_') # Find size of header, the size changes header = np.argmax( [bool(re.match('(?!^#)', line)) for line in lines]) - 1 if header < 0: raise RuntimeError("{} has no data in it".format(filename)) names = lines[header].split()[1:] try: d = np.loadtxt(lines[header:], ndmin=1, dtype={ 'names': names, 'formats': [float] * len(names) }) except (ValueError, IndexError): raise RuntimeError( "Could not read {}, file likely malformed".format( filename)) # Accumulate data data = d if data is None else np.append(data, d) # Get any masked detectors detector_mask = self.get_detector_mask(exp, indir) counts = np.array([data['anode{}'.format(n)] for n in range(1, 45)])[detector_mask] twotheta = data['2theta'] monitor = data['monitor'] # Remove points with zero monitor count monitor_mask = np.nonzero(monitor)[0] if len(monitor_mask) == 0: raise RuntimeError( "{} has all zero monitor counts".format(filename)) monitor = monitor[monitor_mask] counts = counts[:, monitor_mask] twotheta = twotheta[monitor_mask] # Get either vcorr file or vanadium data vanadium_count, vanadium_monitor, vcorr = self.get_vanadium( detector_mask, data['m1'][0], data['colltrans'][0], exp, indir, metadata) def_x = self.getProperty("DefX").value if not def_x: def_x = metadata['def_x'] if def_x not in data.dtype.names: logger.warning( "Could not find {} property in datafile, using 2theta instead". format(def_x)) def_x = '2theta' if def_x == '2theta': x = twotheta + self._gaps[:, np.newaxis][detector_mask] UnitX = 'Degrees' else: x = np.tile(data[def_x], (44, 1))[detector_mask][:, monitor_mask] UnitX = def_x if self.getProperty("IndividualDetectors").value: # Separate spectrum per anode y, e = self.process(counts, scale, monitor, vanadium_count, vanadium_monitor, vcorr) NSpec = len(x) else: if self.getProperty("BinData").value: # Data binned with bin x, y, e = self.process_binned(counts, x.ravel(), scale, monitor, vanadium_count, vanadium_monitor, vcorr) else: y, e = self.process(counts, scale, monitor, vanadium_count, vanadium_monitor, vcorr) NSpec = 1 createWS_alg = self.createChildAlgorithm("CreateWorkspace", enableLogging=False) createWS_alg.setProperty("DataX", x) createWS_alg.setProperty("DataY", y) createWS_alg.setProperty("DataE", e) createWS_alg.setProperty("NSpec", NSpec) createWS_alg.setProperty("UnitX", UnitX) createWS_alg.setProperty("YUnitLabel", "Counts") createWS_alg.setProperty("WorkspaceTitle", str(metadata['scan_title'])) createWS_alg.execute() outWS = createWS_alg.getProperty("OutputWorkspace").value AnalysisDataService.addOrReplace(outputfn, outWS) self.setProperty("OutputWorkspace", outWS) self.add_metadata(outWS, metadata, data) # save reduced workspace to requested format save_data = self.getProperty("SaveData").value if save_data: outputdir = self.getProperty("OutputDirectory").value outputdir = outputdir if outputdir != "" else f"/HFIR/HB2A/IPTS-{metadata['proposal']}/shared" _outputfunc = { 'XYE': SaveFocusedXYE, 'GSAS': SaveGSSCW }[self.getProperty('OutputFormat').value] _outputext = { "XYE": 'dat', "GSAS": 'gss', }[self.getProperty('OutputFormat').value] outputbase = os.path.join(outputdir, outputfn) if self.getProperty('OutputFormat').value == "GSAS": _outputfunc( InputWorkspace=outWS, OutputFilename=f"{outputbase}.{_outputext}", ) else: _outputfunc( InputWorkspace=outWS, Filename=f"{outputbase}.{_outputext}", SplitFiles=False, )
def PyExec(self): input_workspaces = self._expand_groups() outWS = self.getPropertyValue("OutputWorkspace") CreatePeaksWorkspace(OutputType='LeanElasticPeak', InstrumentWorkspace=input_workspaces[0], NumberOfPeaks=0, OutputWorkspace=outWS, EnableLogging=False) method = self.getProperty("Method").value n_bkgr_pts = self.getProperty("NumBackgroundPts").value n_fwhm = self.getProperty("WidthScale").value scale = self.getProperty("ScaleFactor").value chisqmax = self.getProperty("ChiSqMax").value signalNoiseMin = self.getProperty("SignalNoiseMin").value ll = self.getProperty("LowerLeft").value ur = self.getProperty("UpperRight").value startX = self.getProperty('StartX').value endX = self.getProperty('EndX').value use_lorentz = self.getProperty("ApplyLorentz").value optmize_q = self.getProperty("OptimizeQVector").value output_fit = self.getProperty("OutputFitResults").value if output_fit and method != "Counts": fit_results = WorkspaceGroup() AnalysisDataService.addOrReplace(outWS + "_fit_results", fit_results) for inWS in input_workspaces: tmp_inWS = '__tmp_' + inWS IntegrateMDHistoWorkspace(InputWorkspace=inWS, P1Bin=f'{ll[1]},{ur[1]}', P2Bin=f'{ll[0]},{ur[0]}', OutputWorkspace=tmp_inWS, EnableLogging=False) ConvertMDHistoToMatrixWorkspace(tmp_inWS, OutputWorkspace=tmp_inWS, EnableLogging=False) data = ConvertToPointData(tmp_inWS, OutputWorkspace=tmp_inWS, EnableLogging=False) run = mtd[inWS].getExperimentInfo(0).run() scan_log = 'omega' if np.isclose(run.getTimeAveragedStd('phi'), 0.0) else 'phi' scan_axis = run[scan_log].value scan_step = (scan_axis[-1] - scan_axis[0]) / (scan_axis.size - 1) data.setX(0, scan_axis) y = data.extractY().flatten() x = data.extractX().flatten() __tmp_pw = CreatePeaksWorkspace(OutputType='LeanElasticPeak', InstrumentWorkspace=inWS, NumberOfPeaks=0, EnableLogging=False) if method != "Counts": # fit against gaussian with flat background for both the Fitted and CountsWithFitting methods fit_result = self._fit_gaussian(inWS, data, x, y, startX, endX, output_fit) if fit_result and fit_result.OutputStatus == 'success' and fit_result.OutputChi2overDoF < chisqmax: B, A, peak_centre, sigma, _ = fit_result.OutputParameters.toDict( )['Value'] _, errA, _, errs, _ = fit_result.OutputParameters.toDict( )['Error'] if method == "Fitted": integrated_intensity = A * sigma * np.sqrt(2 * np.pi) # Convert correlation back into covariance cor_As = ( fit_result.OutputNormalisedCovarianceMatrix.cell( 1, 4) / 100 * fit_result.OutputParameters.cell(1, 2) * fit_result.OutputParameters.cell(3, 2)) # σ^2 = 2π (A^2 σ_s^2 + σ_A^2 s^2 + 2 A s σ_As) integrated_intensity_error = np.sqrt( 2 * np.pi * (A**2 * errs**2 + sigma**2 * errA**2 + 2 * A * sigma * cor_As)) elif method == "CountsWithFitting": y = y[slice( np.searchsorted( x, peak_centre - 2.3548 * sigma * n_fwhm / 2), np.searchsorted( x, peak_centre + 2.3548 * sigma * n_fwhm / 2))] # subtract out the fitted flat background integrated_intensity = (y.sum() - B * y.size) * scan_step integrated_intensity_error = np.sum( np.sqrt(y)) * scan_step # update the goniometer position based on the fitted peak center if scan_log == 'omega': SetGoniometer(Workspace=__tmp_pw, Axis0=f'{peak_centre},0,1,0,-1', Axis1='chi,0,0,1,-1', Axis2='phi,0,1,0,-1', EnableLogging=False) else: SetGoniometer(Workspace=__tmp_pw, Axis0='omega,0,1,0,-1', Axis1='chi,0,0,1,-1', Axis2=f'{peak_centre},0,1,0,-1', EnableLogging=False) else: self.log().warning( "Failed to fit workspace {}: Output Status={}, ChiSq={}" .format(inWS, fit_result.OutputStatus, fit_result.OutputChi2overDoF)) self._delete_tmp_workspaces(str(__tmp_pw), tmp_inWS) continue else: integrated_intensity, integrated_intensity_error = self._counts_integration( data, n_bkgr_pts, scan_step) # set the goniometer position to use the average of the scan SetGoniometer(Workspace=__tmp_pw, Axis0='omega,0,1,0,-1', Axis1='chi,0,0,1,-1', Axis2='phi,0,1,0,-1', EnableLogging=False) integrated_intensity *= scale integrated_intensity_error *= scale peak = __tmp_pw.createPeakHKL([ run['h'].getStatistics().median, run['k'].getStatistics().median, run['l'].getStatistics().median ]) peak.setWavelength(float(run['wavelength'].value)) peak.setIntensity(integrated_intensity) peak.setSigmaIntensity(integrated_intensity_error) if integrated_intensity / integrated_intensity_error > signalNoiseMin: __tmp_pw.addPeak(peak) # correct q-vector using CentroidPeaksMD if optmize_q: __tmp_q_ws = HB3AAdjustSampleNorm(InputWorkspaces=inWS, NormaliseBy='None', EnableLogging=False) __tmp_pw = CentroidPeaksMD(__tmp_q_ws, __tmp_pw, EnableLogging=False) DeleteWorkspace(__tmp_q_ws, EnableLogging=False) if use_lorentz: # ILL Neutron Data Booklet, Second Edition, Section 2.9, Part 4.1, Equation 7 peak = __tmp_pw.getPeak(0) lorentz = abs( np.sin(peak.getScattering() * np.cos(peak.getAzimuthal()))) peak.setIntensity(peak.getIntensity() * lorentz) peak.setSigmaIntensity(peak.getSigmaIntensity() * lorentz) CombinePeaksWorkspaces(outWS, __tmp_pw, OutputWorkspace=outWS, EnableLogging=False) if output_fit and method != "Counts": fit_results.addWorkspace( RenameWorkspace(tmp_inWS + '_Workspace', outWS + "_" + inWS + '_Workspace', EnableLogging=False)) fit_results.addWorkspace( RenameWorkspace(tmp_inWS + '_Parameters', outWS + "_" + inWS + '_Parameters', EnableLogging=False)) fit_results.addWorkspace( RenameWorkspace( tmp_inWS + '_NormalisedCovarianceMatrix', outWS + "_" + inWS + '_NormalisedCovarianceMatrix', EnableLogging=False)) fit_results.addWorkspace( IntegrateMDHistoWorkspace( InputWorkspace=inWS, P1Bin=f'{ll[1]},0,{ur[1]}', P2Bin=f'{ll[0]},0,{ur[0]}', P3Bin='0,{}'.format( mtd[inWS].getDimension(2).getNBins()), OutputWorkspace=outWS + "_" + inWS + "_ROI", EnableLogging=False)) else: self.log().warning( "Skipping peak from {} because Signal/Noise={:.3f} which is less than {}" .format(inWS, integrated_intensity / integrated_intensity_error, signalNoiseMin)) self._delete_tmp_workspaces(str(__tmp_pw), tmp_inWS) self.setProperty("OutputWorkspace", mtd[outWS])
def PyExec(self): input_workspaces = self._expand_groups() outWS = self.getPropertyValue("OutputWorkspace") CreatePeaksWorkspace(OutputType='LeanElasticPeak', InstrumentWorkspace=input_workspaces[0], NumberOfPeaks=0, OutputWorkspace=outWS, EnableLogging=False) scale = self.getProperty("ScaleFactor").value chisqmax = self.getProperty("ChiSqMax").value signalNoiseMin = self.getProperty("SignalNoiseMin").value ll = self.getProperty("LowerLeft").value ur = self.getProperty("UpperRight").value startX = self.getProperty('StartX').value endX = self.getProperty('EndX').value use_lorentz = self.getProperty("ApplyLorentz").value optmize_q = self.getProperty("OptimizeQVector").value output_fit = self.getProperty("OutputFitResults").value if output_fit: fit_results = WorkspaceGroup() AnalysisDataService.addOrReplace(outWS + "_fit_results", fit_results) for inWS in input_workspaces: tmp_inWS = '__tmp_' + inWS IntegrateMDHistoWorkspace(InputWorkspace=inWS, P1Bin=f'{ll[1]},{ur[1]}', P2Bin=f'{ll[0]},{ur[0]}', OutputWorkspace=tmp_inWS, EnableLogging=False) ConvertMDHistoToMatrixWorkspace(tmp_inWS, OutputWorkspace=tmp_inWS, EnableLogging=False) data = ConvertToPointData(tmp_inWS, OutputWorkspace=tmp_inWS, EnableLogging=False) run = mtd[inWS].getExperimentInfo(0).run() scan_log = 'omega' if np.isclose(run.getTimeAveragedStd('phi'), 0.0) else 'phi' scan_axis = run[scan_log].value data.setX(0, scan_axis) y = data.extractY().flatten() x = data.extractX().flatten() function = f"name=FlatBackground, A0={np.nanmin(y)};" \ f"name=Gaussian, PeakCentre={x[np.nanargmax(y)]}, Height={np.nanmax(y)-np.nanmin(y)}, Sigma=0.25" constraints = f"f0.A0 > 0, f1.Height > 0, {x.min()} < f1.PeakCentre < {x.max()}" try: fit_result = Fit(function, data, Output=str(data), IgnoreInvalidData=True, OutputParametersOnly=not output_fit, Constraints=constraints, StartX=startX, EndX=endX, EnableLogging=False) except RuntimeError as e: self.log().warning("Failed to fit workspace {}: {}".format( inWS, e)) continue if fit_result.OutputStatus == 'success' and fit_result.OutputChi2overDoF < chisqmax: __tmp_pw = CreatePeaksWorkspace(OutputType='LeanElasticPeak', InstrumentWorkspace=inWS, NumberOfPeaks=0, EnableLogging=False) _, A, x, s, _ = fit_result.OutputParameters.toDict()['Value'] _, errA, _, errs, _ = fit_result.OutputParameters.toDict( )['Error'] if scan_log == 'omega': SetGoniometer(Workspace=__tmp_pw, Axis0=f'{x},0,1,0,-1', Axis1='chi,0,0,1,-1', Axis2='phi,0,1,0,-1', EnableLogging=False) else: SetGoniometer(Workspace=__tmp_pw, Axis0='omega,0,1,0,-1', Axis1='chi,0,0,1,-1', Axis2=f'{x},0,1,0,-1', EnableLogging=False) peak = __tmp_pw.createPeakHKL([ run['h'].getStatistics().median, run['k'].getStatistics().median, run['l'].getStatistics().median ]) peak.setWavelength(float(run['wavelength'].value)) integrated_intensity = A * s * np.sqrt(2 * np.pi) * scale peak.setIntensity(integrated_intensity) # Convert correlation back into covariance cor_As = ( fit_result.OutputNormalisedCovarianceMatrix.cell(1, 4) / 100 * fit_result.OutputParameters.cell(1, 2) * fit_result.OutputParameters.cell(3, 2)) # σ^2 = 2π (A^2 σ_s^2 + σ_A^2 s^2 + 2 A s σ_As) integrated_intensity_error = np.sqrt( 2 * np.pi * (A**2 * errs**2 + s**2 * errA**2 + 2 * A * s * cor_As)) * scale peak.setSigmaIntensity(integrated_intensity_error) if integrated_intensity / integrated_intensity_error > signalNoiseMin: __tmp_pw.addPeak(peak) # correct q-vector using CentroidPeaksMD if optmize_q: __tmp_q_ws = HB3AAdjustSampleNorm(InputWorkspaces=inWS, NormaliseBy='None', EnableLogging=False) __tmp_pw = CentroidPeaksMD(__tmp_q_ws, __tmp_pw, EnableLogging=False) DeleteWorkspace(__tmp_q_ws, EnableLogging=False) if use_lorentz: # ILL Neutron Data Booklet, Second Edition, Section 2.9, Part 4.1, Equation 7 peak = __tmp_pw.getPeak(0) lorentz = abs( np.sin(peak.getScattering() * np.cos(peak.getAzimuthal()))) peak.setIntensity(peak.getIntensity() * lorentz) peak.setSigmaIntensity(peak.getSigmaIntensity() * lorentz) CombinePeaksWorkspaces(outWS, __tmp_pw, OutputWorkspace=outWS, EnableLogging=False) DeleteWorkspace(__tmp_pw, EnableLogging=False) if output_fit: fit_results.addWorkspace( RenameWorkspace(tmp_inWS + '_Workspace', outWS + "_" + inWS + '_Workspace', EnableLogging=False)) fit_results.addWorkspace( RenameWorkspace(tmp_inWS + '_Parameters', outWS + "_" + inWS + '_Parameters', EnableLogging=False)) fit_results.addWorkspace( RenameWorkspace(tmp_inWS + '_NormalisedCovarianceMatrix', outWS + "_" + inWS + '_NormalisedCovarianceMatrix', EnableLogging=False)) fit_results.addWorkspace( IntegrateMDHistoWorkspace( InputWorkspace=inWS, P1Bin=f'{ll[1]},0,{ur[1]}', P2Bin=f'{ll[0]},0,{ur[0]}', P3Bin='0,{}'.format( mtd[inWS].getDimension(2).getNBins()), OutputWorkspace=outWS + "_" + inWS + "_ROI", EnableLogging=False)) else: self.log().warning( "Skipping peak from {} because Signal/Noise={:.3f} which is less than {}" .format( inWS, integrated_intensity / integrated_intensity_error, signalNoiseMin)) else: self.log().warning( "Failed to fit workspace {}: Output Status={}, ChiSq={}". format(inWS, fit_result.OutputStatus, fit_result.OutputChi2overDoF)) for tmp_ws in (tmp_inWS, tmp_inWS + '_Workspace', tmp_inWS + '_Parameters', tmp_inWS + '_NormalisedCovarianceMatrix'): if mtd.doesExist(tmp_ws): DeleteWorkspace(tmp_ws, EnableLogging=False) self.setProperty("OutputWorkspace", mtd[outWS])