Ejemplo n.º 1
0
def create_fake_dns_workspace(wsname, angle=-7.53, flipper='ON', dataY=None, loadinstrument=False):
    """
    creates DNS workspace with fake data
        @param angle   Angle of detector bank rotation
        @param flipper Flipper state (ON/OFF)
        @param dataY   Data array to set as DataY of the created workspace, will be set to np.ones if None
        @param loadinstrument  If True api.LoadInstrument will be executed, needed for DNSMergeRuns
    """
    ndet = 24
    dataX = np.zeros(2*ndet)
    dataX.fill(4.2 + 0.00001)
    dataX[::2] -= 0.000002
    if dataY is None:
        dataY = np.ones(ndet)
    dataE = np.sqrt(dataY)
    # create workspace
    api.CreateWorkspace(OutputWorkspace=wsname, DataX=dataX, DataY=dataY,
                        DataE=dataE, NSpec=ndet, UnitX="Wavelength")
    outws = api.mtd[wsname]
    p_names = 'deterota,wavelength,slit_i_left_blade_position,slit_i_right_blade_position,normalized,\
            slit_i_lower_blade_position,slit_i_upper_blade_position,polarisation,polarisation_comment,flipper'
    p_values = str(angle) + ',4.2,10,10,duration,5,20,x,7a,' + flipper
    api.AddSampleLogMultiple(Workspace=outws, LogNames=p_names, LogValues=p_values, ParseType=True)
    # rotate instrument component
    if loadinstrument:
        api.LoadInstrument(outws, InstrumentName='DNS', RewriteSpectraMap=True)
        api.RotateInstrumentComponent(outws, "bank0", X=0, Y=1, Z=0, Angle=angle)

    return outws
Ejemplo n.º 2
0
    def adjustComponent(self, component, pos, rot):
        wks_name = self.wks_name
        if pos:
            msa.MoveInstrumentComponent(wks_name, component, X=pos[0], Y=pos[1], Z=pos[2], RelativePosition=False)

        if rot:
            (rotw, rotx, roty, rotz) = eulerToAngleAxis(rot[0], rot[1], rot[2], self.eulerConvention)
            msa.RotateInstrumentComponent(
                wks_name, component, X=rotx, Y=roty, Z=rotz, Angle=rotw, RelativeRotation=False)
        return
Ejemplo n.º 3
0
    def _minimisation_func(self, x_0, wks_name, component, firstIndex,
                           lastIndex, difc, mask):
        """
        Basic minimization function used. Returns the chisquared difference between the expected
        difc and the new difc after the component has been moved or rotated.
        """
        xmap = self._mapOptions(x_0)

        if self._move:
            api.MoveInstrumentComponent(wks_name,
                                        component,
                                        X=xmap[0],
                                        Y=xmap[1],
                                        Z=xmap[2],
                                        RelativePosition=False)

        if self._rotate:
            (rotw, rotx, roty,
             rotz) = self._eulerToAngleAxis(xmap[3], xmap[4], xmap[5],
                                            self._eulerConvention)  # YZX
            api.RotateInstrumentComponent(wks_name,
                                          component,
                                          X=rotx,
                                          Y=roty,
                                          Z=rotz,
                                          Angle=rotw,
                                          RelativeRotation=False)

        api.CalculateDIFC(InputWorkspace=wks_name, OutputWorkspace=wks_name)

        difc_new = api.mtd[wks_name].extractY().flatten(
        )[firstIndex:lastIndex + 1]

        if self._masking:
            difc_new = np.ma.masked_array(difc_new, mask)

        return chisquare(f_obs=difc, f_exp=difc_new)[0]
Ejemplo n.º 4
0
    def test_DNSTwoTheta(self):
        outputWorkspaceName = "DNSFlippingRatioCorrTest_Test5"

        # rotate detector bank to different angles
        dataws_sf = self.__sf_nicrws - self.__sf_bkgrws
        dataws_nsf = self.__nsf_nicrws - self.__nsf_bkgrws
        wslist = [dataws_sf, dataws_nsf, self.__sf_nicrws, self.__nsf_nicrws, self.__sf_bkgrws, self.__nsf_bkgrws]
        for wks in wslist:
            api.LoadInstrument(wks, InstrumentName='DNS', RewriteSpectraMap=True)
        api.RotateInstrumentComponent(dataws_sf, "bank0", X=0, Y=1, Z=0, Angle=-7.53)
        api.RotateInstrumentComponent(dataws_nsf, "bank0", X=0, Y=1, Z=0, Angle=-7.53)
        api.RotateInstrumentComponent(self.__sf_nicrws, "bank0", X=0, Y=1, Z=0, Angle=-8.02)
        api.RotateInstrumentComponent(self.__nsf_nicrws, "bank0", X=0, Y=1, Z=0, Angle=-8.02)
        api.RotateInstrumentComponent(self.__sf_bkgrws, "bank0", X=0, Y=1, Z=0, Angle=-8.54)
        api.RotateInstrumentComponent(self.__nsf_bkgrws, "bank0", X=0, Y=1, Z=0, Angle=-8.54)
        # apply correction
        alg_test = run_algorithm("DNSFlippingRatioCorr", SFDataWorkspace=dataws_sf,
                                 NSFDataWorkspace=dataws_nsf, SFNiCrWorkspace=self.__sf_nicrws.getName(),
                                 NSFNiCrWorkspace=self.__nsf_nicrws.getName(), SFBkgrWorkspace=self.__sf_bkgrws.getName(),
                                 NSFBkgrWorkspace=self.__nsf_bkgrws.getName(), SFOutputWorkspace=outputWorkspaceName+'SF',
                                 NSFOutputWorkspace=outputWorkspaceName+'NSF')

        self.assertTrue(alg_test.isExecuted())
        ws_sf = AnalysisDataService.retrieve(outputWorkspaceName + 'SF')
        ws_nsf = AnalysisDataService.retrieve(outputWorkspaceName + 'NSF')
        # dimensions
        self.assertEqual(24, ws_sf.getNumberHistograms())
        self.assertEqual(24, ws_nsf.getNumberHistograms())
        self.assertEqual(2,  ws_sf.getNumDims())
        self.assertEqual(2,  ws_nsf.getNumDims())
        # 2theta angles must not change after correction has been applied
        tthetas = np.array([7.53 + i*5 for i in range(24)])
        for i in range(24):
            det = ws_sf.getDetector(i)
            self.assertAlmostEqual(tthetas[i], np.degrees(ws_sf.detectorSignedTwoTheta(det)))
            det = ws_nsf.getDetector(i)
            self.assertAlmostEqual(tthetas[i], np.degrees(ws_nsf.detectorSignedTwoTheta(det)))

        run_algorithm("DeleteWorkspace", Workspace=outputWorkspaceName + 'SF')
        run_algorithm("DeleteWorkspace", Workspace=outputWorkspaceName + 'NSF')
        run_algorithm("DeleteWorkspace", Workspace=dataws_sf)
        run_algorithm("DeleteWorkspace", Workspace=dataws_nsf)

        return
Ejemplo n.º 5
0
    def PyExec(self):
        self._eulerConvention = self.getProperty('EulerConvention').value
        calWS = self.getProperty('CalibrationTable').value
        calWS = api.SortTableWorkspace(calWS, Columns='detid')
        maskWS = self.getProperty("MaskWorkspace").value

        difc = calWS.column('difc')
        if maskWS is not None:
            self._masking = True
            mask = maskWS.extractY().flatten()
            difc = np.ma.masked_array(difc, mask)

        detID = calWS.column('detid')

        if self.getProperty("Workspace").value is not None:
            wks_name = self.getProperty("Workspace").value.name()
        else:
            wks_name = "alignedWorkspace"
            api.LoadEmptyInstrument(
                Filename=self.getProperty("InstrumentFilename").value,
                OutputWorkspace=wks_name)

        # Make a dictionary of what options are being refined for sample/source. No rotation.
        for opt in self._optionsList[:3]:
            self._optionsDict[opt] = self.getProperty(opt).value
        for opt in self._optionsList[3:]:
            self._optionsDict[opt] = False

        # First fit L1 if selected for Source and/or Sample
        for component in "Source", "Sample":
            if self.getProperty("Fit" + component + "Position").value:
                self._move = True
                if component == "Sample":
                    comp = api.mtd[wks_name].getInstrument().getSample()
                else:
                    comp = api.mtd[wks_name].getInstrument().getSource()
                componentName = comp.getFullName()
                logger.notice("Working on " + componentName +
                              " Starting position is " + str(comp.getPos()))
                firstIndex = 0
                lastIndex = len(difc)
                if self._masking:
                    mask_out = mask[firstIndex:lastIndex + 1]
                else:
                    mask_out = None

                self._initialPos = [
                    comp.getPos().getX(),
                    comp.getPos().getY(),
                    comp.getPos().getZ(), 0, 0, 0
                ]

                # Set up x0 and bounds lists
                x0List = []
                boundsList = []
                for iopt, opt in enumerate(self._optionsList[:3]):
                    if self._optionsDict[opt]:
                        x0List.append(self._initialPos[iopt])
                        boundsList.append(
                            (self._initialPos[iopt] +
                             self.getProperty("Min" + opt).value,
                             self._initialPos[iopt] +
                             self.getProperty("Max" + opt).value))

                results = minimize(self._minimisation_func,
                                   x0=x0List,
                                   method='L-BFGS-B',
                                   args=(wks_name, componentName, firstIndex,
                                         lastIndex, difc[firstIndex:lastIndex +
                                                         1], mask_out),
                                   bounds=boundsList)

                # Apply the results to the output workspace
                xmap = self._mapOptions(results.x)

                # Need to grab the component again, as things have changed
                api.MoveInstrumentComponent(wks_name,
                                            componentName,
                                            X=xmap[0],
                                            Y=xmap[1],
                                            Z=xmap[2],
                                            RelativePosition=False)
                comp = api.mtd[wks_name].getInstrument().getComponentByName(
                    componentName)
                logger.notice("Finished " + componentName +
                              " Final position is " + str(comp.getPos()))
                self._move = False

        # Now fit all the components if any
        components = self.getProperty("ComponentList").value

        # Make a dictionary of what options are being refined.
        for opt in self._optionsList:
            self._optionsDict[opt] = self.getProperty(opt).value

        self._move = (self._optionsDict["Xposition"]
                      or self._optionsDict["Yposition"]
                      or self._optionsDict["Zposition"])

        self._rotate = (self._optionsDict["AlphaRotation"]
                        or self._optionsDict["BetaRotation"]
                        or self._optionsDict["GammaRotation"])

        prog = Progress(self, start=0, end=1, nreports=len(components))
        for component in components:
            comp = api.mtd[wks_name].getInstrument().getComponentByName(
                component)
            firstDetID = self._getFirstDetID(comp)
            firstIndex = detID.index(firstDetID)
            lastDetID = self._getLastDetID(comp)
            lastIndex = detID.index(lastDetID)
            if lastDetID - firstDetID != lastIndex - firstIndex:
                raise RuntimeError(
                    "Calibration detid doesn't match instrument")

            eulerAngles = comp.getRotation().getEulerAngles(
                self._eulerConvention)

            logger.notice("Working on " + comp.getFullName() +
                          " Starting position is " + str(comp.getPos()) +
                          " Starting rotation is " + str(eulerAngles))

            x0List = []
            self._initialPos = [
                comp.getPos().getX(),
                comp.getPos().getY(),
                comp.getPos().getZ(), eulerAngles[0], eulerAngles[1],
                eulerAngles[2]
            ]

            boundsList = []

            if self._masking:
                mask_out = mask[firstIndex:lastIndex + 1]
                if mask_out.sum() == mask_out.size:
                    self.log().warning(
                        "All pixels in '%s' are masked. Skipping calibration."
                        % component)
                    continue
            else:
                mask_out = None

            for iopt, opt in enumerate(self._optionsList):
                if self._optionsDict[opt]:
                    x0List.append(self._initialPos[iopt])
                    boundsList.append((self._initialPos[iopt] +
                                       self.getProperty("Min" + opt).value,
                                       self._initialPos[iopt] +
                                       self.getProperty("Max" + opt).value))

            results = minimize(self._minimisation_func,
                               x0=x0List,
                               method='L-BFGS-B',
                               args=(wks_name, component, firstIndex,
                                     lastIndex, difc[firstIndex:lastIndex + 1],
                                     mask_out),
                               bounds=boundsList)

            # Apply the results to the output workspace
            xmap = self._mapOptions(results.x)

            if self._move:
                api.MoveInstrumentComponent(wks_name,
                                            component,
                                            X=xmap[0],
                                            Y=xmap[1],
                                            Z=xmap[2],
                                            RelativePosition=False)

            if self._rotate:
                (rotw, rotx, roty,
                 rotz) = self._eulerToAngleAxis(xmap[3], xmap[4], xmap[5],
                                                self._eulerConvention)
                api.RotateInstrumentComponent(wks_name,
                                              component,
                                              X=rotx,
                                              Y=roty,
                                              Z=rotz,
                                              Angle=rotw,
                                              RelativeRotation=False)

            # Need to grab the component again, as things have changed
            comp = api.mtd[wks_name].getInstrument().getComponentByName(
                component)
            logger.notice(
                "Finshed " + comp.getFullName() + " Final position is " +
                str(comp.getPos()) + " Final rotation is " +
                str(comp.getRotation().getEulerAngles(self._eulerConvention)))

            prog.report()
        logger.notice("Results applied to workspace " + wks_name)
Ejemplo n.º 6
0
    def PyExec(self):
        # Input
        filename = self.getPropertyValue("Filename")
        outws_name = self.getPropertyValue("OutputWorkspace")
        norm = self.getPropertyValue("Normalization")

        # load data array from the given file
        data_array = np.loadtxt(filename)
        if not data_array.size:
            message = "File " + filename + " does not contain any data!"
            self.log().error(message)
            raise RuntimeError(message)
        # sample logs
        logs = {"names": [], "values": [], "units": []}

        # load run information
        metadata = DNSdata()
        try:
            metadata.read_legacy(filename)
        except RuntimeError as err:
            message = "Error of loading of file " + filename + ": " + str(err)
            self.log().error(message)
            raise RuntimeError(message)

        tmp = api.LoadEmptyInstrument(InstrumentName='DNS')
        self.instrument = tmp.getInstrument()
        api.DeleteWorkspace(tmp)

        # load polarisation table and determine polarisation
        poltable = self.get_polarisation_table()
        pol = self.get_polarisation(metadata, poltable)
        if not pol:
            pol = ['0', 'undefined']
            self.log().warning("Failed to determine polarisation for " +
                               filename +
                               ". Values have been set to undefined.")
        ndet = 24
        unitX = "Wavelength"
        if metadata.tof_channel_number < 2:
            dataX = np.zeros(2 * ndet)
            dataX.fill(metadata.wavelength + 0.00001)
            dataX[::2] -= 0.000002
        else:
            unitX = "TOF"

            # get instrument parameters
            l1 = np.linalg.norm(self.instrument.getSample().getPos() -
                                self.instrument.getSource().getPos())
            self.log().notice("L1 = {} m".format(l1))
            dt_factor = float(
                self.instrument.getStringParameter("channel_width_factor")[0])

            # channel width
            dt = metadata.tof_channel_width * dt_factor
            # calculate tof1
            velocity = h / (m_n * metadata.wavelength * 1e-10)  # m/s
            tof1 = 1e+06 * l1 / velocity  # microseconds
            self.log().debug("TOF1 = {} microseconds".format(tof1))
            self.log().debug("Delay time = {} microsecond".format(
                metadata.tof_delay_time))
            # create dataX array
            x0 = tof1 + metadata.tof_delay_time
            self.log().debug("TOF1 = {} microseconds".format(tof1))
            dataX = np.linspace(x0, x0 + metadata.tof_channel_number * dt,
                                metadata.tof_channel_number + 1)

            # sample logs
            logs["names"].extend(
                ["channel_width", "TOF1", "delay_time", "tof_channels"])
            logs["values"].extend([
                dt, tof1, metadata.tof_delay_time, metadata.tof_channel_number
            ])
            logs["units"].extend(
                ["microseconds", "microseconds", "microseconds", ""])
            if metadata.tof_elastic_channel:
                logs["names"].append("EPP")
                logs["values"].append(metadata.tof_elastic_channel)
                logs["units"].append("")
            if metadata.chopper_rotation_speed:
                logs["names"].append("chopper_speed")
                logs["values"].append(metadata.chopper_rotation_speed)
                logs["units"].append("Hz")
            if metadata.chopper_slits:
                logs["names"].append("chopper_slits")
                logs["values"].append(metadata.chopper_slits)
                logs["units"].append("")

        # data normalization
        factor = 1.0
        yunit = "Counts"
        ylabel = "Intensity"
        if norm == 'duration':
            factor = metadata.duration
            yunit = "Counts/s"
            ylabel = "Intensity normalized to duration"
            if factor <= 0:
                raise RuntimeError("Duration is invalid for file " + filename +
                                   ". Cannot normalize.")
        if norm == 'monitor':
            factor = metadata.monitor_counts
            yunit = "Counts/monitor"
            ylabel = "Intensity normalized to monitor"
            if factor <= 0:
                raise RuntimeError("Monitor counts are invalid for file " +
                                   filename + ". Cannot normalize.")
        # set values for dataY and dataE
        dataY = data_array[0:ndet, 1:] / factor
        dataE = np.sqrt(data_array[0:ndet, 1:]) / factor
        # create workspace
        api.CreateWorkspace(OutputWorkspace=outws_name,
                            DataX=dataX,
                            DataY=dataY,
                            DataE=dataE,
                            NSpec=ndet,
                            UnitX=unitX)
        outws = api.AnalysisDataService.retrieve(outws_name)
        api.LoadInstrument(outws, InstrumentName='DNS', RewriteSpectraMap=True)

        run = outws.mutableRun()
        if metadata.start_time and metadata.end_time:
            run.setStartAndEndTime(DateAndTime(metadata.start_time),
                                   DateAndTime(metadata.end_time))
        # add name of file as a run title
        fname = os.path.splitext(os.path.split(filename)[1])[0]
        run.addProperty('run_title', fname, True)

        # rotate the detector bank to the proper position
        api.RotateInstrumentComponent(outws,
                                      "bank0",
                                      X=0,
                                      Y=1,
                                      Z=0,
                                      Angle=metadata.deterota)
        # add sample log Ei and wavelength
        logs["names"].extend(["Ei", "wavelength"])
        logs["values"].extend([metadata.incident_energy, metadata.wavelength])
        logs["units"].extend(["meV", "Angstrom"])

        # add other sample logs
        logs["names"].extend([
            "deterota", "mon_sum", "duration", "huber", "omega", "T1", "T2",
            "Tsp"
        ])
        logs["values"].extend([
            metadata.deterota, metadata.monitor_counts, metadata.duration,
            metadata.huber, metadata.huber - metadata.deterota, metadata.temp1,
            metadata.temp2, metadata.tsp
        ])
        logs["units"].extend([
            "Degrees", "Counts", "Seconds", "Degrees", "Degrees", "K", "K", "K"
        ])

        # flipper, coil currents and polarisation
        flipper_status = 'OFF'  # flipper OFF
        if abs(metadata.flipper_precession_current) > sys.float_info.epsilon:
            flipper_status = 'ON'  # flipper ON
        logs["names"].extend([
            "flipper_precession", "flipper_z_compensation", "flipper", "C_a",
            "C_b", "C_c", "C_z", "polarisation", "polarisation_comment"
        ])
        logs["values"].extend([
            metadata.flipper_precession_current,
            metadata.flipper_z_compensation_current, flipper_status,
            metadata.a_coil_current, metadata.b_coil_current,
            metadata.c_coil_current, metadata.z_coil_current,
            str(pol[0]),
            str(pol[1])
        ])
        logs["units"].extend(["A", "A", "", "A", "A", "A", "A", "", ""])

        # slits
        logs["names"].extend([
            "slit_i_upper_blade_position", "slit_i_lower_blade_position",
            "slit_i_left_blade_position", "slit_i_right_blade_position"
        ])
        logs["values"].extend([
            metadata.slit_i_upper_blade_position,
            metadata.slit_i_lower_blade_position,
            metadata.slit_i_left_blade_position,
            metadata.slit_i_right_blade_position
        ])
        logs["units"].extend(["mm", "mm", "mm", "mm"])

        # add information whether the data are normalized (duration/monitor/no):
        api.AddSampleLog(outws,
                         LogName='normalized',
                         LogText=norm,
                         LogType='String')
        api.AddSampleLogMultiple(outws,
                                 LogNames=logs["names"],
                                 LogValues=logs["values"],
                                 LogUnits=logs["units"])

        outws.setYUnit(yunit)
        outws.setYUnitLabel(ylabel)

        self.setProperty("OutputWorkspace", outws)
        self.log().debug('LoadDNSLegacy: data are loaded to the workspace ' +
                         outws_name)

        return
Ejemplo n.º 7
0
    def PyExec(self):
        # Input
        filename = self.getPropertyValue("Filename")
        outws_name = self.getPropertyValue("OutputWorkspace")
        norm = self.getPropertyValue("Normalization")

        # load data array from the given file
        data_array = np.loadtxt(filename)
        if not data_array.size:
            message = "File " + filename + " does not contain any data!"
            self.log().error(message)
            raise RuntimeError(message)

        # load run information
        metadata = DNSdata()
        try:
            metadata.read_legacy(filename)
        except RuntimeError as err:
            message = "Error of loading of file " + filename + ": " + str(err)
            self.log().error(message)
            raise RuntimeError(message)

        # load polarisation table and determine polarisation
        poltable = self.get_polarisation_table()
        pol = self.get_polarisation(metadata, poltable)
        if not pol:
            pol = ['0', 'undefined']
            self.log().warning("Failed to determine polarisation for " + filename +
                               ". Values have been set to undefined.")
        ndet = 24
        # this needed to be able to use ConvertToMD
        dataX = np.zeros(2*ndet)
        dataX.fill(metadata.wavelength + 0.00001)
        dataX[::2] -= 0.000002
        # data normalization
        factor = 1.0
        yunit = "Counts"
        ylabel = "Intensity"
        if norm == 'duration':
            factor = metadata.duration
            yunit = "Counts/s"
            ylabel = "Intensity normalized to duration"
            if factor <= 0:
                raise RuntimeError("Duration is invalid for file " + filename + ". Cannot normalize.")
        if norm == 'monitor':
            factor = metadata.monitor_counts
            yunit = "Counts/monitor"
            ylabel = "Intensity normalized to monitor"
            if factor <= 0:
                raise RuntimeError("Monitor counts are invalid for file " + filename + ". Cannot normalize.")
        # set values for dataY and dataE
        dataY = data_array[0:ndet, 1:]/factor
        dataE = np.sqrt(data_array[0:ndet, 1:])/factor
        # create workspace
        api.CreateWorkspace(OutputWorkspace=outws_name, DataX=dataX, DataY=dataY,
                            DataE=dataE, NSpec=ndet, UnitX="Wavelength")
        outws = api.AnalysisDataService.retrieve(outws_name)
        api.LoadInstrument(outws, InstrumentName='DNS', RewriteSpectraMap=True)

        run = outws.mutableRun()
        if metadata.start_time and metadata.end_time:
            run.setStartAndEndTime(DateAndTime(metadata.start_time),
                                   DateAndTime(metadata.end_time))
        # add name of file as a run title
        fname = os.path.splitext(os.path.split(filename)[1])[0]
        run.addProperty('run_title', fname, True)

        # rotate the detector bank to the proper position
        api.RotateInstrumentComponent(outws, "bank0", X=0, Y=1, Z=0, Angle=metadata.deterota)
        # add sample log Ei and wavelength
        api.AddSampleLog(outws, LogName='Ei', LogText=str(metadata.incident_energy),
                         LogType='Number', LogUnit='meV')
        api.AddSampleLog(outws, LogName='wavelength', LogText=str(metadata.wavelength),
                         LogType='Number', LogUnit='Angstrom')
        # add other sample logs
        api.AddSampleLog(outws, LogName='deterota', LogText=str(metadata.deterota),
                         LogType='Number', LogUnit='Degrees')
        api.AddSampleLog(outws, 'mon_sum',
                         LogText=str(float(metadata.monitor_counts)), LogType='Number')
        api.AddSampleLog(outws, LogName='duration', LogText=str(metadata.duration),
                         LogType='Number', LogUnit='Seconds')
        api.AddSampleLog(outws, LogName='huber', LogText=str(metadata.huber),
                         LogType='Number', LogUnit='Degrees')
        api.AddSampleLog(outws, LogName='omega', LogText=str(metadata.huber - metadata.deterota),
                         LogType='Number', LogUnit='Degrees')
        api.AddSampleLog(outws, LogName='T1', LogText=str(metadata.temp1),
                         LogType='Number', LogUnit='K')
        api.AddSampleLog(outws, LogName='T2', LogText=str(metadata.temp2),
                         LogType='Number', LogUnit='K')
        api.AddSampleLog(outws, LogName='Tsp', LogText=str(metadata.tsp),
                         LogType='Number', LogUnit='K')
        # flipper
        api.AddSampleLog(outws, LogName='flipper_precession',
                         LogText=str(metadata.flipper_precession_current),
                         LogType='Number', LogUnit='A')
        api.AddSampleLog(outws, LogName='flipper_z_compensation',
                         LogText=str(metadata.flipper_z_compensation_current),
                         LogType='Number', LogUnit='A')
        flipper_status = 'OFF'    # flipper OFF
        if abs(metadata.flipper_precession_current) > sys.float_info.epsilon:
            flipper_status = 'ON'    # flipper ON
        api.AddSampleLog(outws, LogName='flipper',
                         LogText=flipper_status, LogType='String')
        # coil currents
        api.AddSampleLog(outws, LogName='C_a', LogText=str(metadata.a_coil_current),
                         LogType='Number', LogUnit='A')
        api.AddSampleLog(outws, LogName='C_b', LogText=str(metadata.b_coil_current),
                         LogType='Number', LogUnit='A')
        api.AddSampleLog(outws, LogName='C_c', LogText=str(metadata.c_coil_current),
                         LogType='Number', LogUnit='A')
        api.AddSampleLog(outws, LogName='C_z', LogText=str(metadata.z_coil_current),
                         LogType='Number', LogUnit='A')
        # type of polarisation
        api.AddSampleLog(outws, 'polarisation', LogText=pol[0], LogType='String')
        api.AddSampleLog(outws, 'polarisation_comment', LogText=str(pol[1]), LogType='String')
        # slits
        api.AddSampleLog(outws, LogName='slit_i_upper_blade_position',
                         LogText=str(metadata.slit_i_upper_blade_position),
                         LogType='Number', LogUnit='mm')
        api.AddSampleLog(outws, LogName='slit_i_lower_blade_position',
                         LogText=str(metadata.slit_i_lower_blade_position),
                         LogType='Number', LogUnit='mm')
        api.AddSampleLog(outws, LogName='slit_i_left_blade_position',
                         LogText=str(metadata.slit_i_left_blade_position),
                         LogType='Number', LogUnit='mm')
        api.AddSampleLog(outws, 'slit_i_right_blade_position',
                         LogText=str(metadata.slit_i_right_blade_position),
                         LogType='Number', LogUnit='mm')
        # data normalization

        # add information whether the data are normalized (duration/monitor/no):
        api.AddSampleLog(outws, LogName='normalized', LogText=norm, LogType='String')

        outws.setYUnit(yunit)
        outws.setYUnitLabel(ylabel)

        self.setProperty("OutputWorkspace", outws)
        self.log().debug('LoadDNSLegacy: data are loaded to the workspace ' + outws_name)

        return
Ejemplo n.º 8
0
    print("=========================================")

    # Create workspace for current frame
    ws_for_this_frame = createWorkspace(data_x=[f.wavelength],
                                        data_y=f.IntensityUp,
                                        data_e=np.sqrt(f.IntensityUp),
                                        n_spec=f.x*f.y,
                                        unit="Wavelength")
    # Register the workspace in the mantid ADS
    mantid.mtd.addOrReplace("ws_for_this_frame", ws_for_this_frame)
    # Load the instrument from the definition file
    mantid.LoadInstrument(ws_for_this_frame, FileName="5C1_Definition.xml",
                          RewriteSpectraMap=True)
    # Rotate the instrument to the current gamma angle (in degrees)
    mantid.RotateInstrumentComponent(ws_for_this_frame, "detector_panel",
                                     X=0, Y=1, Z=0, Angle=f.Gamma,
                                     RelativeRotation=False)
    # Normalise by monitor counts
    normalised = ws_for_this_frame / f.totalmonitorcount
    # Convert to d-spacing
    dspacing = mantid.ConvertUnits(InputWorkspace=normalised,
                                   Target="dSpacing", EMode="Elastic")

    # 1. Naive accumulation of workspace data: this does not seem to work
    rebinned = mantid.Rebin(dspacing, "0.5,0.01,5.0")
    if final is None:
        final = mantid.CloneWorkspace(rebinned)
    else:
        final += rebinned

    # 2. Try to extract 1D profile from equatorial plane
Ejemplo n.º 9
0
    def _minimisation_func(self, x_0, wks_name, component, firstIndex,
                           lastIndex):
        """
        Basic minimization function used. Returns the sum of the absolute values for the fractional peak
        deviations:

        .. math::

            \\sum_i^{N_d}\\sum_j^{N_p} (1 - m_{i,j}) \\frac{|d_{i,j} - d_j^*|}{d_j^*}

        where :math:`N_d` is the number of detectors in the bank, :math:`N_p` is the number of reference peaks, and
        :math:`m_{i,j}` is the mask for peak :math:`j` and detector :math:`i`. The mask evaluates to 1 if the
        detector is defective or the peak is missing in the detector, otherwise the mask evaluates to zero.

        There's an implicit one-to-correspondence between array index of ``difc`` and workspace index of ``wks_name``,
        that is, between row index of the input TOFS table and workspace index of ``wks_name``.

        @param x_0 :: list of length 3 (new XYZ coordinates of the component) or length 6 (XYZ and rotation coords)
        @param wks_name :: name of a workspace with an embedded instrument. The instrument will be adjusted according to
            the new coordinates ``x_0`` for instrument component ``component``. It's pixel spectra will contain the new DIFC
        @param component :: name of the instrument component to be optimized
        @param firstIndex :: workspace index of first index of ``difc`` array to be considered when comparing old
            and new DIFC values. When fitting the source or sample, this is the first spectrum index.
        @param lastIndex ::  workspace index of last index of ``difc`` array to be considered when comparing old
            and new DIFC values. When fitting the source or sample, this is the last row number of the input
            TOFS table.

        @return Chi-square value between old and new DIFC values for the unmasked spectra
        """
        xmap = self._mapOptions(
            x_0)  # pad null rotations when x_0 contains only translations

        if self._move:
            api.MoveInstrumentComponent(wks_name,
                                        component,
                                        X=xmap[0],
                                        Y=xmap[1],
                                        Z=xmap[2],
                                        RelativePosition=False,
                                        EnableLogging=False)

        if self._rotate:
            (rotw, rotx, roty,
             rotz) = self._eulerToAngleAxis(xmap[3], xmap[4], xmap[5],
                                            self._eulerConvention)  # YZX
            api.RotateInstrumentComponent(wks_name,
                                          component,
                                          X=rotx,
                                          Y=roty,
                                          Z=rotz,
                                          Angle=rotw,
                                          RelativeRotation=False,
                                          EnableLogging=False)

        api.CalculateDIFC(InputWorkspace=wks_name,
                          OutputWorkspace=wks_name,
                          EnableLogging=False)
        difc = api.mtd[wks_name].extractY().flatten()[firstIndex:lastIndex + 1]
        peaks_d = self.peaks_tof[
            firstIndex:lastIndex +
            1] / difc[:, np.newaxis]  # peak centers in d-spacing units

        # calculate the fractional peak center deviations, then sum their absolute values
        return np.sum(np.abs((peaks_d - self.peaks_ref) / self.peaks_ref))
Ejemplo n.º 10
0
    def PyExec(self):
        table_tof = self.getProperty('PeakCentersTofTable').value
        self.peaks_tof = self._extract_tofs(table_tof)
        detector_count, peak_count = self.peaks_tof.shape
        table_tof = api.SortTableWorkspace(table_tof, Columns='detid')
        detID = table_tof.column('detid')
        peaks_ref = np.sort(self.getProperty(
            'PeakPositions').value)  # sort by increasing value
        self.peaks_ref = peaks_ref[np.newaxis, :]  # shape = (1, peak_count)

        # Process input mask
        maskWS = self.getProperty("MaskWorkspace").value
        if maskWS is not None:
            mask = maskWS.extractY().flatten()  # shape=(detector_count,)
            peaks_mask = np.tile(
                mask[:, np.newaxis],
                peak_count)  # shape=(detector_count, peak_count)
        else:
            peaks_mask = np.zeros(
                (detector_count, peak_count))  # no detectors are masked
        peaks_mask[np.isnan(self.peaks_tof)] = True
        # mask the defective detectors and missing peaks
        self.peaks_tof = np.ma.masked_array(self.peaks_tof, peaks_mask)

        input_workspace = self.getProperty('InputWorkspace').value

        # Table containing the optimized absolute locations and orientations for each component
        adjustments_table_name = self.getProperty('AdjustmentsTable').value
        if len(adjustments_table_name) > 0:
            adjustments_table = self._initialize_adjustments_table(
                adjustments_table_name)
            saving_adjustments = True
        else:
            saving_adjustments = False

        # Table containing the relative changes in position and euler angles for each bank component
        displacements_table_name = self.getProperty('DisplacementsTable').value
        if len(displacements_table_name) > 0:
            displacements_table = self._initialize_displacements_table(
                displacements_table_name)
            saving_displacements = True
        else:
            saving_displacements = False

        self._eulerConvention = self.getProperty('EulerConvention').value

        output_workspace = self.getPropertyValue("OutputWorkspace")
        wks_name = '__alignedworkspace'  # workspace whose counts will be DIFC values
        if bool(input_workspace) is True:
            api.CloneWorkspace(InputWorkspace=input_workspace,
                               OutputWorkspace=wks_name)
            if output_workspace != str(input_workspace):
                api.CloneWorkspace(InputWorkspace=input_workspace,
                                   OutputWorkspace=output_workspace)
        else:
            api.LoadEmptyInstrument(
                Filename=self.getProperty("InstrumentFilename").value,
                OutputWorkspace=wks_name)

        # Make a dictionary of what options are being refined for sample/source. No rotation.
        for translation_option in self._optionsList[:3]:
            self._optionsDict[translation_option] = self.getProperty(
                translation_option).value
        for rotation_option in self._optionsList[3:]:
            self._optionsDict[rotation_option] = False

        # First fit L1 if selected for Source and/or Sample
        sample_position_begin = api.mtd[wks_name].getInstrument().getSample(
        ).getPos()
        for component in "Source", "Sample":  # fit first the source position, then the sample position
            if self.getProperty("Fit" + component + "Position").value:
                self._move = True
                if component == "Sample":
                    comp = api.mtd[wks_name].getInstrument().getSample()
                else:
                    comp = api.mtd[wks_name].getInstrument().getSource()
                componentName = comp.getFullName()
                logger.notice("Working on " + componentName +
                              " Starting position is " + str(comp.getPos()))
                firstIndex = 0
                lastIndex = detector_count - 1

                self._initialPos = [
                    comp.getPos().getX(),
                    comp.getPos().getY(),
                    comp.getPos().getZ(), 0, 0, 0
                ]  # no rotation

                # Set up x0 and bounds lists
                x0List = []  # initial X, Y, Z coordinates
                boundsList = []  # [(minX, maxX), (minZ, maxZ), (minZ, maxZ)]
                for iopt, translation_option in enumerate(
                        self._optionsList[:3]):  # iterate over X, Y, and Z
                    if self._optionsDict[translation_option]:
                        x0List.append(self._initialPos[iopt])
                        # default range for X is (x0 - 0.1m, x0 + 0.1m), same for Y and Z
                        boundsList.append((
                            self._initialPos[iopt] +
                            self.getProperty("Min" + translation_option).value,
                            self._initialPos[iopt] +
                            self.getProperty("Max" +
                                             translation_option).value))

                # scipy.opimize.minimize with the L-BFGS-B algorithm
                results: OptimizeResult = minimize(
                    self._minimisation_func,
                    x0=x0List,
                    method='L-BFGS-B',
                    args=(wks_name, componentName, firstIndex, lastIndex),
                    bounds=boundsList)

                # Apply the results to the output workspace
                xmap = self._mapOptions(results.x)

                # Save translation and rotations, if requested
                if saving_adjustments:
                    instrument = api.mtd[wks_name].getInstrument()
                    name_finder = {
                        'Source': instrument.getSource().getName(),
                        'Sample': instrument.getSample().getName()
                    }
                    component_adjustments = [
                        name_finder[component]
                    ] + xmap[:3] + [0.0] * 4  # no rotations
                    adjustments_table.addRow(component_adjustments)

                # Need to grab the component again, as things have changed
                kwargs = dict(X=xmap[0],
                              Y=xmap[1],
                              Z=xmap[2],
                              RelativePosition=False,
                              EnableLogging=False)
                api.MoveInstrumentComponent(wks_name, componentName,
                                            **kwargs)  # adjust workspace
                api.MoveInstrumentComponent(output_workspace, componentName,
                                            **kwargs)  # adjust workspace
                comp = api.mtd[wks_name].getInstrument().getComponentByName(
                    componentName)
                logger.notice("Finished " + componentName +
                              " Final position is " + str(comp.getPos()))
                self._move = False
        sample_position_end = api.mtd[wks_name].getInstrument().getSample(
        ).getPos()

        # Now fit all the remaining components, if any
        components = self.getProperty("ComponentList").value

        # Make a dictionary of what translational and rotational options are being refined.
        for opt in self._optionsList:
            self._optionsDict[opt] = self.getProperty(opt).value

        self._move = any([
            self._optionsDict[t]
            for t in ('Xposition', 'Yposition', 'Zposition')
        ])
        self._rotate = any([
            self._optionsDict[r]
            for r in ('AlphaRotation', 'BetaRotation', 'GammaRotation')
        ])

        prog = Progress(self, start=0, end=1, nreports=len(components))
        for component in components:
            comp = api.mtd[wks_name].getInstrument().getComponentByName(
                component)
            firstDetID = self._getFirstDetID(comp)
            firstIndex = detID.index(
                firstDetID)  # a row index in the input TOFS table
            lastDetID = self._getLastDetID(comp)
            lastIndex = detID.index(
                lastDetID)  # a row index in the input TOFS table
            if lastDetID - firstDetID != lastIndex - firstIndex:
                raise RuntimeError("TOFS detid doesn't match instrument")

            eulerAngles: List[float] = comp.getRotation().getEulerAngles(
                self._eulerConvention)

            logger.notice("Working on " + comp.getFullName() +
                          " Starting position is " + str(comp.getPos()) +
                          " Starting rotation is " + str(eulerAngles))

            x0List = []
            self._initialPos = [
                comp.getPos().getX(),
                comp.getPos().getY(),
                comp.getPos().getZ(), eulerAngles[0], eulerAngles[1],
                eulerAngles[2]
            ]

            # Distance between the original position of the sample and the original position of the component
            comp_sample_distance_begin = (comp.getPos() -
                                          sample_position_begin).norm()

            boundsList = []

            if np.all(peaks_mask[firstIndex:lastIndex + 1].astype(bool)):
                self.log().warning(
                    "All pixels in '%s' are masked. Skipping calibration." %
                    component)
                continue

            for iopt, opt in enumerate(self._optionsList):
                if self._optionsDict[opt]:
                    x0List.append(self._initialPos[iopt])
                    boundsList.append((self._initialPos[iopt] +
                                       self.getProperty("Min" + opt).value,
                                       self._initialPos[iopt] +
                                       self.getProperty("Max" + opt).value))

            minimizer_selection = self.getProperty('Minimizer').value
            if minimizer_selection == 'L-BFGS-B':
                # scipy.opimize.minimize with the L-BFGS-B algorithm
                results: OptimizeResult = minimize(self._minimisation_func,
                                                   x0=x0List,
                                                   method='L-BFGS-B',
                                                   args=(wks_name, component,
                                                         firstIndex,
                                                         lastIndex),
                                                   bounds=boundsList)
            elif minimizer_selection == 'differential_evolution':
                results: OptimizeResult = differential_evolution(
                    self._minimisation_func,
                    bounds=boundsList,
                    args=(wks_name, component, firstIndex, lastIndex),
                    maxiter=self.getProperty('MaxIterations').value)
            # Apply the results to the output workspace
            xmap = self._mapOptions(results.x)

            comp = api.mtd[wks_name].getInstrument().getComponentByName(
                component)  # adjusted component
            # Distance between the adjusted position of the sample and the adjusted position of the component
            comp_sample_distance_end = (comp.getPos() -
                                        sample_position_end).norm()

            component_adjustments = [
                0.
            ] * 7  # 3 for translation, 3 for rotation axis, 1 for rotation angle
            component_displacements = [
                0.
            ] * 7  # 1 for distnace, 3 for translation, 3 for Euler angles
            component_displacements[0] = 1000 * (
                comp_sample_distance_end - comp_sample_distance_begin
            )  # in mili-meters

            if self._move:
                kwargs = dict(X=xmap[0],
                              Y=xmap[1],
                              Z=xmap[2],
                              RelativePosition=False,
                              EnableLogging=False)
                api.MoveInstrumentComponent(wks_name, component,
                                            **kwargs)  # adjust workspace
                api.MoveInstrumentComponent(output_workspace, component,
                                            **kwargs)  # adjust workspace
                component_adjustments[:3] = xmap[:3]
                for i in range(3):
                    component_displacements[i + 1] = 1000 * (
                        xmap[i] - self._initialPos[i])  # in mili-meters

            if self._rotate:
                (rotw, rotx, roty,
                 rotz) = self._eulerToAngleAxis(xmap[3], xmap[4], xmap[5],
                                                self._eulerConvention)
                kwargs = dict(X=rotx,
                              Y=roty,
                              Z=rotz,
                              Angle=rotw,
                              RelativeRotation=False,
                              EnableLogging=False)
                api.RotateInstrumentComponent(wks_name, component,
                                              **kwargs)  # adjust workspace
                api.RotateInstrumentComponent(output_workspace, component,
                                              **kwargs)  # adjust workspace
                component_adjustments[3:] = [rotx, roty, rotz, rotw]
                for i in range(3, 6):
                    component_displacements[
                        i + 1] = xmap[i] - self._initialPos[i]  # in degrees

            if saving_adjustments and (self._move or self._rotate):
                adjustments_table.addRow([component] + component_adjustments)

            if saving_displacements and (self._move or self._rotate):
                displacements_table.addRow([component] +
                                           component_displacements)

            # Need to grab the component object again, as things have changed
            logger.notice(
                "Finished " + comp.getFullName() + " Final position is " +
                str(comp.getPos()) + " Final rotation is " +
                str(comp.getRotation().getEulerAngles(self._eulerConvention)))

            prog.report()
        api.DeleteWorkspace(wks_name)
        self.setProperty("OutputWorkspace", output_workspace)
        logger.notice("Results applied to workspace " + wks_name)