コード例 #1
0
    def load_empty(self, workspace_name = None):
        """
            Loads the instrument definition file into a workspace with the given name.
            If no name is given a hidden workspace is used
            @param workspace_name: the name of the workspace to create and/or display
            @return the name of the workspace that was created
        """
        if workspace_name is None:
            workspace_name = '__'+self._NAME+'_empty'

        api.LoadEmptyInstrument(Filename=self._definition_file, OutputWorkspace=workspace_name)

        return workspace_name
コード例 #2
0
ファイル: test_mantid.py プロジェクト: scipp/scippneutron
    def test_advanced_geometry_with_absent_shape(self):
        import mantid.simpleapi as mantid
        # single bank 3 by 3
        ws = mantid.CreateSampleWorkspace(NumBanks=1,
                                          BankPixelWidth=3,
                                          StoreInADS=False)
        # Save and reload trick to purge sample shape info
        file_name = "example_geometry.nxs"
        geom_path = os.path.join(tempfile.gettempdir(), file_name)
        mantid.SaveNexusGeometry(ws, geom_path)  # Does not save shape info
        assert os.path.isfile(geom_path)  # sanity check
        out = mantid.LoadEmptyInstrument(
            Filename=geom_path, StoreInADS=False)  # reload without sample info
        os.remove(geom_path)

        assert not out.componentInfo().hasValidShape(0)  # sanity check
        da = scn.mantid.from_mantid(out, advanced_geometry=True)
        # Shapes have zero size
        assert sc.identical(sc.sum(da.meta['shape']),
                            sc.vector(value=[0, 0, 0], unit=sc.units.m))
コード例 #3
0
ファイル: instview.py プロジェクト: ess-dmsc/nicos
    def _load_idf(self, new_idf):
        # The widget self-destructs when you delete the workspace below, for
        # some reason, so let's remove it cleanly first.
        if self._widget is not None:
            self.layout().removeWidget(self._widget)
            self._widget = None

        # If you don't do this there is an Unhandled Exception, which crashes
        # NICOS completely, when you try to switch setups, with a message of:
        # > Instrument view: workspace doesn't exist
        if self._workspace is not None:
            simpleapi.DeleteWorkspace("ws")
            self._workspace = None

        if new_idf is not None:
            self._workspace = simpleapi.LoadEmptyInstrument(
                new_idf, OutputWorkspace="ws")
            self._widget = mpy.MantidQt.MantidWidgets.InstrumentWidget(
                "ws", self)
            self.layout().addWidget(self._widget)
            self._watcher.setClient(self.client)

        self._current_idf = new_idf
コード例 #4
0
ファイル: align_comp.py プロジェクト: sns-chops/detcalib
#
eulerConvention = 'YZX'
wks_name = "alignedWorkspace"
# use Si data
# idf_orig = os.path.join(msa.ConfigService.getInstrumentDirectory(), 'SEQUOIA_Definition.xml')

# special: use C60 data for short packs around forward beam
idf_orig = os.path.join('SEQUOIA_Definition_guessshortpacks.xml')

# ## Fit twotheta and L2
# $ DIFC = (L1+L2)/(\pi) \; sin(\theta) \times 0.0015882549421289758 \times 10^6 $
#L1 = 20.0965
L1 = 20.0114
sin_theta = difc / (0.0015882549421289758 * 1e6) * np.pi / (L1 + L2)

msa.LoadEmptyInstrument(idf_orig, OutputWorkspace=wks_name)
instrument_model = align.InstrumentModel(wks_name,
                                         detID,
                                         mask,
                                         eulerConvention="YZX")
options = collections.OrderedDict()
options['Xposition'] = (-.3, .3)
options['Yposition'] = False
options['Zposition'] = (-.3, .3)
options['AlphaRotation'] = (-2., 2.)
options['BetaRotation'] = False
options['GammaRotation'] = False

brow = ['B%s' % i for i in range(1, 38)]
crow = ['C%s' % i for i in range(1, 38)]
del crow[24]  # no C25
コード例 #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)
コード例 #6
0
    def validateInputs(self):
        """
        Does basic validation for inputs
        """
        issues = dict()

        calWS = self.getProperty('CalibrationTable').value

        if 'difc' not in calWS.getColumnNames(
        ) or 'detid' not in calWS.getColumnNames():
            issues[
                'CalibrationTable'] = "Calibration table requires detid and difc"

        maskWS = self.getProperty("MaskWorkspace").value
        if maskWS is not None and maskWS.id() != 'MaskWorkspace':
            issues[
                'MaskWorkspace'] = "MaskWorkspace must be empty or of type \"MaskWorkspace\""

        # Need to get instrument in order to check components are valid
        if self.getProperty("Workspace").value is not None:
            wks_name = self.getProperty("Workspace").value.name()
        else:
            inputFilename = self.getProperty("InstrumentFilename").value
            if inputFilename == "":
                issues[
                    "Workspace"] = "A Workspace or InstrumentFilename must be defined"
                return issues
            else:
                api.LoadEmptyInstrument(Filename=inputFilename,
                                        OutputWorkspace="alignedWorkspace")
                wks_name = "alignedWorkspace"

        # Check if each component listed is defined in the instrument
        components = self.getProperty("ComponentList").value
        if len(components) <= 0 and not self.getProperty(
                "FitSourcePosition").value and not self.getProperty(
                    "FitSamplePosition").value:
            issues['ComponentList'] = "Must supply components"
        else:
            components = [
                component for component in components
                if api.mtd[wks_name].getInstrument().getComponentByName(
                    component) is None
            ]
            if len(components) > 0:
                issues['ComponentList'] = "Instrument has no component \"" \
                                       + ','.join(components) + "\""

        # This checks that something will actually be refined,
        if not (self.getProperty("Xposition").value
                or self.getProperty("Yposition").value
                or self.getProperty("Zposition").value
                or self.getProperty("AlphaRotation").value
                or self.getProperty("BetaRotation").value
                or self.getProperty("GammaRotation").value):
            issues["Xposition"] = "You must calibrate at least one parameter."

        # Check that a position refinement is selected for sample/source
        if ((self.getProperty("FitSourcePosition").value
             or self.getProperty("FitSamplePosition").value)
                and not (self.getProperty("Xposition").value
                         or self.getProperty("Yposition").value
                         or self.getProperty("Zposition").value)):
            issues[
                "Xposition"] = "If fitting source or sample, you must calibrate at least one position parameter."

        return issues
コード例 #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)
        # 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
コード例 #8
0
ファイル: test_mantid.py プロジェクト: scipp/scippneutron
 def test_from_mantid_LoadEmptyInstrument(self):
     import mantid.simpleapi as mantid
     ws = mantid.LoadEmptyInstrument(InstrumentName='PG3')
     scn.from_mantid(ws)
コード例 #9
0
 def align(
         self,
         difc,
         mask,
         pack='C25T',
         ofile=open('new.xml', 'wt'),
         logger=None,
         params0=None,
 ):
     """
     difc, mask: for a pack
     pack: pack name
     """
     logger = logger or self.logger
     # ## Fit twotheta and L2
     # $ DIFC = (L1+L2)/(\pi) \; sin(\theta) \times 0.0015882549421289758 \times 10^6 $
     difc, mask = self._prepare_difc_and_mask_from_pack_difc(
         difc, mask, pack)
     # combine with L2 mask
     mask = np.logical_or(mask, self.L2_mask)
     #
     L1 = self.L1
     L2 = self.L2
     # import pdb; pdb.set_trace()
     # Apply mask
     difc = np.ma.masked_array(difc, mask)
     L2 = np.ma.masked_array(L2, mask)
     # calculate sin(theta)
     self.sin_theta = sin_theta = difc / (0.0015882549421289758 *
                                          1e6) * np.pi / (L1 + L2)
     #
     wks_name = "alignedWorkspace"
     msa.LoadEmptyInstrument(self.init_IDF, OutputWorkspace=wks_name)
     instrument_model = align_utils.InstrumentModel(
         wks_name, self.detIDs, mask, eulerConvention=self.eulerConvention)
     #
     options = self.options
     #
     print "- Working on %s" % (pack, )
     pack_type = pack_types[pack]
     self.pack_model = pack_model = instrument_model.component(
         '%s/%s' % (pack, pack_type), type='detpack')
     print "- pack params:", pack_model.getParams()
     init_center = pack_model.position()
     estimate = align_utils.estimate_pack_center_position(
         sin_theta, L2, pack_model, init_center)
     # fit = align_utils.FitPackTwothetaAndL2(pack_model, options, sin_theta, L2, logger)
     fit = align_utils.FitPack_DifcL2(pack_model,
                                      options,
                                      difc,
                                      L2,
                                      logger=logger,
                                      params0=params0)
     # fit = align_utils.FitPackDifc(pack_model, options, difc, logger=logger)
     fit.fit()
     print "- Estimate:", estimate
     x, y, z, ry, rz, rx = new_params = pack_model.getParams()
     print "- New:", new_params
     s = template.format(pack, pack_type, x, y, z, ry)
     print s
     ofile.write(s)
     return new_params, fit
コード例 #10
0
ファイル: AlignComponents.py プロジェクト: durong24/mantid
    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)
コード例 #11
0
ファイル: AlignComponents.py プロジェクト: durong24/mantid
    def validateInputs(self):
        """
        Does basic validation for inputs
        """
        issues = dict()

        peak_positions = self.getProperty('PeakPositions').value

        table_tof: TableWorkspace = self.getProperty(
            'PeakCentersTofTable').value

        if 'detid' not in table_tof.getColumnNames():
            issues[
                'PeakCentersTofTable'] = 'PeakCentersTofTable is missing column "detid"'

        # The titles for table columns storing the TOF peak-center positions start with '@'
        column_names = [
            name for name in table_tof.getColumnNames() if name[0] == '@'
        ]
        peak_count = len(
            peak_positions)  # number of reference peak-center values
        if len(column_names) != peak_count:
            error_message = f'The number of table columns containing the peak center positions' \
                            f' {len(column_names)} is different than the number of peak positions {peak_count}'
            issues['PeakCentersTofTable'] = error_message

        # The titles for table columns storing the TOF peak-center positions do contain the values
        # of the reference peak-center positions in d-spacing units, up to a precision of 5
        def with_precision(the_number, precision):
            r"""Analog of C++'s std::setprecision"""
            return round(the_number, precision - len(str(int(the_number))))

        for column_name, peak_position in zip(column_names,
                                              sorted(peak_positions)):
            if (float(column_name[1:]) -
                    with_precision(peak_position, 5)) > 1.e-5:
                issues[
                    'PeakCentersTofTable'] = f'{column_name} and {peak_position} differ up to precision 5'

        maskWS: MaskWorkspace = self.getProperty("MaskWorkspace").value
        if maskWS is not None:
            if maskWS.id() != 'MaskWorkspace':
                issues[
                    'MaskWorkspace'] = "MaskWorkspace must be empty or of type \"MaskWorkspace\""
            # The mask workspace should contain as many spectra as rows in the TOFS table
            if maskWS.getNumberHistograms() != table_tof.rowCount():
                error_message = 'The mask workspace must contain as many spectra as rows in the TOFS table'
                issues['MaskWorkspace'] = error_message

        # Need to get instrument in order to check if components are valid
        input_workspace = self.getProperty("InputWorkspace").value
        if bool(input_workspace) is True:
            wks_name = input_workspace.name()
        else:
            inputFilename = self.getProperty("InstrumentFilename").value
            if inputFilename == "":
                issues[
                    "InputWorkspace"] = "A Workspace or InstrumentFilename must be defined"
                return issues
            else:
                wks_name = "__alignedWorkspace"  # a temporary workspace
                api.LoadEmptyInstrument(Filename=inputFilename,
                                        OutputWorkspace=wks_name)

        # Check if each component listed is defined in the instrument
        components = self.getProperty("ComponentList").value
        source_or_sample = self.getProperty(
            "FitSourcePosition").value or self.getProperty(
                "FitSamplePosition").value
        if len(components) <= 0 and not source_or_sample:
            issues['ComponentList'] = "Must supply components"
        else:
            get_component = api.mtd[wks_name].getInstrument(
            ).getComponentByName
            components = [
                component for component in components
                if get_component(component) is None
            ]
            if len(components) > 0:
                issues['ComponentList'] = "Instrument has no component \"" \
                                       + ','.join(components) + "\""
        if wks_name == '__alignedWorkspace':
            api.DeleteWorkspace(
                '__alignedWorkspace')  # delete temporary workspace

        # This checks that something will actually be refined,
        if not (self.getProperty("Xposition").value
                or self.getProperty("Yposition").value
                or self.getProperty("Zposition").value
                or self.getProperty("AlphaRotation").value
                or self.getProperty("BetaRotation").value
                or self.getProperty("GammaRotation").value):
            issues[
                "Xposition"] = "You must calibrate at least one position or rotation parameter."

        # Check that a position refinement is selected for sample/source
        if ((self.getProperty("FitSourcePosition").value
             or self.getProperty("FitSamplePosition").value)
                and not (self.getProperty("Xposition").value
                         or self.getProperty("Yposition").value
                         or self.getProperty("Zposition").value)):
            issues[
                "Xposition"] = "If fitting source or sample, you must calibrate at least one position parameter."

        return issues