Ejemplo n.º 1
0
    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,
                )
Ejemplo n.º 2
0
    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,
                )
Ejemplo n.º 3
0
    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])