Esempio n. 1
0
 def _normaliseToSlits(self, ws):
     """Normalise ws to slit opening and update slit widths."""
     # Update slit width in any case for later re-use.
     common.slitSizes(ws)
     slitNorm = self.getProperty(Prop.SLIT_NORM).value
     if slitNorm == SlitNorm.OFF:
         return ws
     elif slitNorm == SlitNorm.AUTO and self._instrumentName != 'D17':
         return ws
     run = ws.run()
     slit2width = run.get(common.SampleLogs.SLIT2WIDTH).value
     slit3width = run.get(common.SampleLogs.SLIT3WIDTH).value
     if slit2width == '-' or slit3width == '-':
         self.log().warning('Slit information not found in sample logs. Slit normalisation disabled.')
         return ws
     f = slit2width * slit3width
     normalisedWSName = self._names.withSuffix('normalised_to_slits')
     normalisedWS = Scale(
         InputWorkspace=ws,
         OutputWorkspace=normalisedWSName,
         Factor=1.0 / f,
         EnableLogging=self._subalgLogging
     )
     self._cleanup.cleanup(ws)
     return normalisedWS
 def _peakFitting(self, ws):
     """Add peak and foreground information to the sample logs."""
     # Convert to wavelength
     l1 = ws.spectrumInfo().l1()
     hists = ws.getNumberHistograms()
     mindex = int(hists / 2)
     l2 = ws.spectrumInfo().l2(mindex)
     if not self.getProperty(Prop.LINE_POSITION).isDefault:
         linePosition = self.getProperty(Prop.LINE_POSITION).value
     else:
         # Fit peak position
         peakWSName = self._names.withSuffix('peak')
         xmin = self.getProperty(Prop.XMIN).value
         if not xmin == Property.EMPTY_DBL:
             xmin = self.getProperty(Prop.XMIN).value
             xmin = common.inTOF(xmin, l1, l2)
         xmax = self.getProperty(Prop.XMAX).value
         if not self.getProperty(Prop.XMAX).isDefault:
             xmax = self.getProperty(Prop.XMAX).value
             xmax = common.inTOF(xmax, l1, l2)
         peak = FindReflectometryLines(InputWorkspace=ws,
                                       OutputWorkspace=peakWSName,
                                       RangeLower=xmin,
                                       RangeUpper=xmax,
                                       StartWorkspaceIndex=self.getProperty(
                                           Prop.START_WS_INDEX).value,
                                       EndWorkspaceIndex=self.getProperty(
                                           Prop.END_WS_INDEX).value)
         linePosition = peak.LineCentre
         self._cleanup.cleanup(peak.OutputWorkspace)
     # Add the fractional workspace index of the beam position to the sample logs of ws.
     ws.run().addProperty(common.SampleLogs.LINE_POSITION,
                          float(linePosition), True)
     return ws, linePosition
    def PyExec(self):
        """Execute the algorithm."""
        self._subalgLogging = self.getProperty(
            Prop.SUBALG_LOGGING).value == SubalgLogging.ON
        cleanupMode = self.getProperty(Prop.CLEANUP).value
        self._cleanup = common.WSCleanup(cleanupMode, self._subalgLogging)
        wsPrefix = self.getPropertyValue(Prop.OUTPUT_WS)
        self._names = common.WSNameSource(wsPrefix, cleanupMode)

        ws, beamPosWS = self._inputWS()

        ws, monWS = self._extractMonitors(ws)

        if beamPosWS is None:
            beamPosWS = self._findLine(ws)

        ws = self._addForegroundToLogs(ws, beamPosWS)

        self._outputBeamPosition(beamPosWS)

        ws = self._waterCalibration(ws)

        ws = self._normaliseToSlits(ws)

        ws = self._normaliseToFlux(ws, monWS)
        self._cleanup.cleanup(monWS)

        ws = self._subtractFlatBkg(ws, beamPosWS)

        self._cleanup.cleanup(beamPosWS)

        ws = self._convertToWavelength(ws)

        self._finalize(ws)
 def _peakFitting(self, ws):
     """Add peak and foreground information to the sample logs."""
     # Convert to wavelength
     l1 = ws.spectrumInfo().l1()
     hists = ws.getNumberHistograms()
     mindex = int(hists / 2)
     l2 = ws.spectrumInfo().l2(mindex)
     if not self.getProperty(Prop.LINE_POSITION).isDefault:
         linePosition = self.getProperty(Prop.LINE_POSITION).value
     else:
         # Fit peak position
         peakWSName = self._names.withSuffix('peak')
         xmin = self.getProperty(Prop.XMIN).value
         if not xmin == Property.EMPTY_DBL:
             xmin = self.getProperty(Prop.XMIN).value
             xmin = common.inTOF(xmin, l1, l2)
         xmax = self.getProperty(Prop.XMAX).value
         if not self.getProperty(Prop.XMAX).isDefault:
             xmax = self.getProperty(Prop.XMAX).value
             xmax = common.inTOF(xmax, l1, l2)
         peak = FindReflectometryLines(
             InputWorkspace=ws,
             OutputWorkspace=peakWSName,
             RangeLower=xmin,
             RangeUpper=xmax,
             StartWorkspaceIndex=self.getProperty(Prop.START_WS_INDEX).value,
             EndWorkspaceIndex=self.getProperty(Prop.END_WS_INDEX).value
         )
         linePosition = peak.LineCentre
         self._cleanup.cleanup(peak.OutputWorkspace)
     # Add the fractional workspace index of the beam position to the sample logs of ws.
     ws.run().addProperty(common.SampleLogs.LINE_POSITION, float(linePosition), True)
     return ws, linePosition
 def _correctForFractionalForegroundCentre(self, ws, summedForeground):
     """
     This needs to be called after having summed the foreground but before transfering to momentum transfer.
     This needs to be called in both coherent and incoherent cases, regardless the angle calibration option.
     The reason for this is that up to this point is the fractional workspace index that correponds to the calibrated 2theta.
     However the momentum transfer calculation, which normally comes after summing the foreground,
     takes the 2theta from the spectrumInfo of the summed foreground workspace.
     Hence this code below translated the detector by the difference of the
     fractional and integer foreground centre along the detector plane.
     It also applies local rotation so that the detector continues to face the sample.
     Note that this translation has nothing to do with the difference of foreground centres in direct and reflected beams,
     which is handled already in pre-process algorithm.
     Here it's only about the difference of the fractional and integer foreground centre of the reflected beam
     with already calibrated angle no matter the option.
     Note also, that this could probably be avoided, if the loader placed
     the integer foreground at the given angle and not the fractional one.
     Fractional foreground centre only matter when calculating the difference between direct and reflected beams.
     But for the final Q (and sigma) calculation, it takes the position/angle from spectrumInfo()...(0),
     which corresponds to the centre of the pixel."""
     foreground = self._foregroundIndices(ws)
     # integer foreground centre
     beamPosIndex = foreground[1]
     # fractional foreground centre
     linePosition = ws.run().getProperty(
         common.SampleLogs.LINE_POSITION).value
     l2 = ws.run().getProperty('L2').value
     instr = common.instrumentName(ws)
     pixelSize = common.pixelSize(instr)
     # the distance between the fractional and integer foreground centres along the detector plane
     dist = pixelSize * (linePosition - beamPosIndex)
     if dist != 0.:
         detPoint1 = ws.spectrumInfo().position(0)
         detPoint2 = ws.spectrumInfo().position(20)
         beta = numpy.math.atan2((detPoint2[0] - detPoint1[0]),
                                 (detPoint2[2] - detPoint1[2]))
         xvsy = numpy.math.sin(beta) * dist
         mz = numpy.math.cos(beta) * dist
         if instr == 'D17':
             mx = xvsy
             my = 0.0
             rotationAxis = [0, 1, 0]
         else:
             mx = 0.0
             my = xvsy
             rotationAxis = [-1, 0, 0]
         MoveInstrumentComponent(Workspace=summedForeground,
                                 ComponentName='detector',
                                 X=mx,
                                 Y=my,
                                 Z=mz,
                                 RelativePosition=True)
         angle_corr = numpy.arctan2(dist, l2) * 180 / numpy.pi
         RotateInstrumentComponent(Workspace=summedForeground,
                                   ComponentName='detector',
                                   X=rotationAxis[0],
                                   Y=rotationAxis[1],
                                   Z=rotationAxis[2],
                                   Angle=angle_corr,
                                   RelativeRotation=True)
     return summedForeground
Esempio n. 6
0
    def PyExec(self):
        """Execute the algorithm."""
        self._subalgLogging = self.getProperty(
            Prop.SUBALG_LOGGING).value == SubalgLogging.ON
        cleanupMode = self.getProperty(Prop.CLEANUP).value
        self._cleanup = common.WSCleanup(cleanupMode, self._subalgLogging)
        wsPrefix = self.getPropertyValue(Prop.OUTPUT_WS)
        self._names = common.WSNameSource(wsPrefix, cleanupMode)

        ws, directWS, directForegroundWS = self._inputWS()

        ws = self._correctForChopperOpenings(ws, directWS)
        ws = self._convertToMomentumTransfer(ws, directWS)
        if directForegroundWS is not None:
            directForegroundWS = self._sameQAndDQ(ws, directForegroundWS,
                                                  'direct_')
        ws = self._toPointData(ws)
        ws = self._groupPoints(ws)

        if directForegroundWS is not None:
            directForegroundWS = self._toPointData(directForegroundWS,
                                                   'direct_')
            directForegroundWS = self._groupPoints(directForegroundWS,
                                                   'direct_')
            ws = self._divideByDirect(ws, directForegroundWS)

        self._finalize(ws)
 def _moveDetector(self, ws, linePosition):
     """Perform detector position correction for direct and reflected beams."""
     detectorMovedWSName = self._names.withSuffix('detectors_moved')
     twoTheta = ws.run().getProperty(common.SampleLogs.TWO_THETA).value
     args = {
         'InputWorkspace': ws,
         'OutputWorkspace': detectorMovedWSName,
         'TwoTheta': twoTheta,
         'EnableLogging': self._subalgLogging,
         'DetectorComponentName': 'detector',
         'PixelSize': common.pixelSize(self._instrumentName),
         'DetectorCorrectionType': 'RotateAroundSample',
         'DetectorFacesSample': True
     }
     if not self.getProperty(Prop.TWO_THETA).isDefault:
         # We should use user angle
         args['TwoTheta'] = self.getProperty(Prop.TWO_THETA).value
         # We need to subtract an offsetAngle from user given TwoTheta
         args['LinePosition'] = linePosition
     else:
         logs = ws.run()
         args['TwoTheta'] = twoTheta + common.deflectionAngle(logs)
     detectorMovedWS = SpecularReflectionPositionCorrect(**args)
     self._cleanup.cleanup(ws)
     return detectorMovedWS
 def _moveDetector(self, ws, linePosition):
     """Perform detector position correction for direct and reflected beams."""
     detectorMovedWSName = self._names.withSuffix('detectors_moved')
     twoTheta = ws.run().getProperty(common.SampleLogs.TWO_THETA).value
     args = {
         'InputWorkspace': ws,
         'OutputWorkspace': detectorMovedWSName,
         'TwoTheta': twoTheta,
         'EnableLogging': self._subalgLogging,
         'DetectorComponentName': 'detector',
         'PixelSize': common.pixelSize(self._instrumentName),
         'DetectorCorrectionType': 'RotateAroundSample',
         'DetectorFacesSample': True
     }
     if not self.getProperty(Prop.TWO_THETA).isDefault:
         # We should use user angle
         args['TwoTheta'] = self.getProperty(Prop.TWO_THETA).value
         # We need to subtract an offsetAngle from user given TwoTheta
         args['LinePosition'] = linePosition
     else:
         logs = ws.run()
         args['TwoTheta'] = twoTheta + common.deflectionAngle(logs)
     detectorMovedWS = SpecularReflectionPositionCorrect(**args)
     self._cleanup.cleanup(ws)
     return detectorMovedWS
    def PyExec(self):
        """Execute the algorithm."""
        self._subalgLogging = self.getProperty(
            Prop.SUBALG_LOGGING).value == SubalgLogging.ON
        cleanupMode = self.getProperty(Prop.CLEANUP).value
        self._cleanup = common.WSCleanup(cleanupMode, self._subalgLogging)
        wsPrefix = self.getPropertyValue(Prop.OUTPUT_WS)
        self._names = common.WSNameSource(wsPrefix, cleanupMode)

        ws = self._inputWS()
        processReflected = not self._directOnly()
        if processReflected:
            self._addBeamStatisticsToLogs(ws)

        sumType = self._sumType()
        if sumType == SumType.IN_LAMBDA:
            ws = self._sumForegroundInLambda(ws)
            self._addSumTypeToLogs(ws, SumType.IN_LAMBDA)
            if processReflected:
                ws = self._rebinToDirect(ws)
        else:
            if processReflected:
                ws = self._divideByDirect(ws)
            ws = self._sumForegroundInQ(ws)
            self._addSumTypeToLogs(ws, SumType.IN_Q)
        ws = self._applyWavelengthRange(ws)

        self._finalize(ws)
    def PyExec(self):
        """Execute the algorithm."""
        self._subalgLogging = self.getProperty(
            Prop.SUBALG_LOGGING).value == SubalgLogging.ON
        cleanupMode = self.getProperty(Prop.CLEANUP).value
        self._cleanup = common.WSCleanup(cleanupMode, self._subalgLogging)
        wsPrefix = self.getPropertyValue(Prop.OUTPUT_WS)
        self._names = common.WSNameSource(wsPrefix, cleanupMode)

        ws = self._inputWS()

        self._instrumentName = ws.getInstrument().getName()

        ws, monWS = self._extractMonitors(ws)

        ws, linePosition = self._peakFitting(ws)

        self._addSampleLogInfo(ws, linePosition)

        ws = self._moveDetector(ws, linePosition)

        ws = self._calibrateDetectorAngleByDirectBeam(ws)

        ws = self._waterCalibration(ws)

        ws = self._normaliseToSlits(ws)

        ws = self._normaliseToFlux(ws, monWS)
        self._cleanup.cleanup(monWS)

        ws = self._subtractFlatBkg(ws)

        ws = self._convertToWavelength(ws)

        self._finalize(ws)
 def testD17SlitWidthLogEntry(self):
     ws = illhelpers.create_poor_mans_d17_workspace()
     mtd.add('ws', ws)
     illhelpers.add_slit_configuration_D17(ws, 0.03, 0.02)
     run = ws.run()
     instrName = common.instrumentName(ws)
     slit2width = run.get(common.slitSizeLogEntry(instrName, 1))
     slit3width = run.get(common.slitSizeLogEntry(instrName, 2))
     common.slitSizes(ws)
     self.assertEquals(slit2width.value, run.getProperty(common.SampleLogs.SLIT2WIDTH).value)
     self.assertEquals(slit3width.value, run.getProperty(common.SampleLogs.SLIT3WIDTH).value)
     mtd.clear()
 def _convertToMomentumTransfer(self, ws):
     """Convert the X units of ws to momentum transfer."""
     logs = ws.run()
     reflectedForeground = self._foreground(logs)
     instrumentName = common.instrumentName(ws)
     sumType = logs.getProperty(common.SampleLogs.SUM_TYPE).value
     pixelSize = common.pixelSize(instrumentName)
     detResolution = common.detectorResolution()
     chopperSpeed = common.chopperSpeed(logs, instrumentName)
     chopperOpening = common.chopperOpeningAngle(logs, instrumentName)
     chopperRadius = 0.36 if instrumentName == 'D17' else 0.305
     chopperPairDist = common.chopperPairDistance(logs, instrumentName)
     slit1SizeLog = common.slitSizeLogEntry(instrumentName, 1)
     slit2SizeLog = common.slitSizeLogEntry(instrumentName, 2)
     tofBinWidth = self._TOFChannelWidth(logs)
     qWSName = self._names.withSuffix('in_momentum_transfer')
     qWS = ReflectometryMomentumTransfer(
         InputWorkspace=ws,
         OutputWorkspace=qWSName,
         SummationType=sumType,
         ReflectedForeground=reflectedForeground,
         PixelSize=pixelSize,
         DetectorResolution=detResolution,
         ChopperSpeed=chopperSpeed,
         ChopperOpening=chopperOpening,
         ChopperRadius=chopperRadius,
         ChopperPairDistance=chopperPairDist,
         FirstSlitName='slit2',
         FirstSlitSizeSampleLog=slit1SizeLog,
         SecondSlitName='slit3',
         SecondSlitSizeSampleLog=slit2SizeLog,
         TOFChannelWidth=tofBinWidth,
         EnableLogging=self._subalgLogging)
     self._cleanup.cleanup(ws)
     return qWS
Esempio n. 13
0
 def _convertToMomentumTransfer(self, ws):
     """Convert the X units of ws to momentum transfer."""
     logs = ws.run()
     reflectedForeground = self._foreground(logs)
     instrumentName = common.instrumentName(ws)
     sumType = logs.getProperty(common.SampleLogs.SUM_TYPE).value
     pixelSize = common.pixelSize(instrumentName)
     detResolution = common.detectorResolution()
     chopperSpeed = common.chopperSpeed(logs, instrumentName)
     chopperOpening = common.chopperOpeningAngle(logs, instrumentName)
     chopperRadius = 0.36 if instrumentName == 'D17' else 0.305
     chopperPairDist = common.chopperPairDistance(logs, instrumentName)
     slit1SizeLog = common.slitSizeLogEntry(instrumentName, 1)
     slit2SizeLog = common.slitSizeLogEntry(instrumentName, 2)
     tofBinWidth = self._TOFChannelWidth(logs)
     qWSName = self._names.withSuffix('in_momentum_transfer')
     qWS = ReflectometryMomentumTransfer(
         InputWorkspace=ws,
         OutputWorkspace=qWSName,
         SummationType=sumType,
         ReflectedForeground=reflectedForeground,
         PixelSize=pixelSize,
         DetectorResolution=detResolution,
         ChopperSpeed=chopperSpeed,
         ChopperOpening=chopperOpening,
         ChopperRadius=chopperRadius,
         ChopperPairDistance=chopperPairDist,
         FirstSlitName='slit2',
         FirstSlitSizeSampleLog=slit1SizeLog,
         SecondSlitName='slit3',
         SecondSlitSizeSampleLog=slit2SizeLog,
         TOFChannelWidth=tofBinWidth,
         EnableLogging=self._subalgLogging)
     self._cleanup.cleanup(ws)
     return qWS
Esempio n. 14
0
 def _correctForChopperOpenings(self, ws, directWS):
     """Corrects ws for different chopper opening angles."""
     correctedWS = common.correctForChopperOpenings(ws, directWS,
                                                    self._names,
                                                    self._cleanup,
                                                    self._subalgLogging)
     return correctedWS
Esempio n. 15
0
    def PyExec(self):
        """Execute the algorithm."""
        self._subalgLogging = self.getProperty(Prop.SUBALG_LOGGING).value == SubalgLogging.ON
        cleanupMode = self.getProperty(Prop.CLEANUP).value
        self._cleanup = common.WSCleanup(cleanupMode, self._subalgLogging)
        wsPrefix = self.getPropertyValue(Prop.OUTPUT_WS)
        self._names = common.WSNameSource(wsPrefix, cleanupMode)

        ws = self._inputWS()

        ws = self._convertToMomentumTransfer(ws)

        ws = self._toPointData(ws)
        ws = self._groupPoints(ws)

        self._finalize(ws)
Esempio n. 16
0
    def _correctForChopperOpenings(self, ws, directWS):
        """Correct reflectivity values if chopper openings between RB and DB differ."""
        def opening(instrumentName, logs, Xs):
            chopperGap = common.chopperPairDistance(logs, instrumentName)
            chopperPeriod = 60. / common.chopperSpeed(logs, instrumentName)
            openingAngle = common.chopperOpeningAngle(logs, instrumentName)
            return chopperGap * constants.m_n / constants.h / chopperPeriod * Xs * 1e-10 + openingAngle / 360.

        instrumentName = common.instrumentName(ws)
        Xbins = ws.readX(0)
        Xs = (Xbins[:-1] + Xbins[1:]) / 2.
        reflectedOpening = opening(instrumentName, ws.run(), Xs)
        directOpening = opening(instrumentName, directWS.run(), Xs)
        corFactorWSName = self._names.withSuffix(
            'chopper_opening_correction_factors')
        corFactorWS = CreateWorkspace(OutputWorkspace=corFactorWSName,
                                      DataX=Xbins,
                                      DataY=directOpening / reflectedOpening,
                                      UnitX=ws.getAxis(0).getUnit().unitID(),
                                      ParentWorkspace=ws,
                                      EnableLogging=self._subalgLogging)
        correctedWSName = self._names.withSuffix(
            'corrected_by_chopper_opening')
        correctedWS = Multiply(LHSWorkspace=ws,
                               RHSWorkspace=corFactorWS,
                               OutputWorkspace=correctedWSName,
                               EnableLogging=self._subalgLogging)
        self._cleanup.cleanup(corFactorWS)
        self._cleanup.cleanup(ws)
        return correctedWS
Esempio n. 17
0
 def _convertToMomentumTransfer(self, ws):
     """Convert the X units of ws to momentum transfer."""
     reflectedWS = self.getProperty(Prop.REFLECTED_WS).value
     reflectedForeground = self._foreground(reflectedWS.run())
     directWS = self.getProperty(Prop.DIRECT_WS).value
     directForeground = self._foreground(directWS.run())
     logs = ws.run()
     instrumentName = ws.getInstrument().getName()
     if instrumentName != 'D17' and instrumentName != 'Figaro':
         raise RuntimeError('Unrecognized instrument {}. Only D17 and Figaro are supported.'.format(instrumentName))
     sumType = logs.getProperty(common.SampleLogs.SUM_TYPE).value
     polarized = self.getProperty(Prop.POLARIZED).value
     pixelSize = 0.001195 if instrumentName == 'D17' else 0.0012
     detResolution = 0.0022
     chopperSpeed = common.chopperSpeed(logs, instrumentName)
     chopperOpening = common.chopperOpeningAngle(logs, instrumentName)
     chopperRadius = 0.36 if instrumentName == 'D17' else 0.305
     chopperPairDist = common.chopperPairDistance(logs, instrumentName)
     slit1SizeLog = 'VirtualSlitAxis.s2w_actual_width' if instrumentName == 'D17' else 'VirtualSlitAxis.S2H_actual_height'
     slit2SizeLog = 'VirtualSlitAxis.s3w_actual_width' if instrumentName == 'D17' else 'VirtualSlitAxis.S3H_actual_height'
     tofBinWidth = self._TOFChannelWidth(logs, instrumentName)
     qWSName = self._names.withSuffix('in_momentum_transfer')
     qWS = ReflectometryMomentumTransfer(
         InputWorkspace=ws,
         OutputWorkspace=qWSName,
         ReflectedBeamWorkspace=reflectedWS,
         ReflectedForeground=reflectedForeground,
         DirectBeamWorkspace=directWS,
         DirectForeground=directForeground,
         SummationType=sumType,
         Polarized=polarized,
         PixelSize=pixelSize,
         DetectorResolution=detResolution,
         ChopperSpeed=chopperSpeed,
         ChopperOpening=chopperOpening,
         ChopperRadius=chopperRadius,
         ChopperPairDistance=chopperPairDist,
         Slit1Name='slit2',
         Slit1SizeSampleLog=slit1SizeLog,
         Slit2Name='slit3',
         Slit2SizeSampleLog=slit2SizeLog,
         TOFChannelWidth=tofBinWidth,
         EnableLogging=self._subalgLogging)
     self._cleanup.cleanup(ws)
     return qWS
Esempio n. 18
0
    def PyExec(self):
        """Execute the algorithm."""
        self._subalgLogging = self.getProperty(
            Prop.SUBALG_LOGGING).value == SubalgLogging.ON
        cleanupMode = self.getProperty(Prop.CLEANUP).value
        self._cleanup = common.WSCleanup(cleanupMode, self._subalgLogging)
        wsPrefix = self.getPropertyValue(Prop.OUTPUT_WS)
        self._names = common.WSNameSource(wsPrefix, cleanupMode)

        wss = self._inputWS()

        effWS = self._efficiencies(wss[0])

        wss = self._commonBinning(wss)

        wss = self._correct(wss, effWS)

        self._finalize(wss)
 def _normaliseToSlits(self, ws):
     """Normalise ws to slit opening."""
     if self.getProperty(Prop.SLIT_NORM).value == SlitNorm.OFF:
         return ws
     r = ws.run()
     instrumentName = r.get('instrument.name').value
     slit2width = r.get(common.slitSizeLogEntry(instrumentName, 1))
     slit3width = r.get(common.slitSizeLogEntry(instrumentName, 2))
     if slit2width is None or slit3width is None:
         self.log().warning('Slit information not found in sample logs. Slit normalisation disabled.')
         return ws
     f = slit2width.value * slit3width.value
     normalisedWSName = self._names.withSuffix('normalised_to_slits')
     normalisedWS = Scale(InputWorkspace=ws,
                          OutputWorkspace=normalisedWSName,
                          Factor=1.0 / f,
                          EnableLogging=self._subalgLogging)
     self._cleanup.cleanup(ws)
     return normalisedWS
Esempio n. 20
0
 def _normaliseToSlits(self, ws):
     """Normalise ws to slit opening."""
     if self.getProperty(Prop.SLIT_NORM).value == SlitNorm.OFF:
         return ws
     r = ws.run()
     instrumentName = r.get('instrument.name').value
     slit2width = r.get(common.slitSizeLogEntry(instrumentName, 1))
     slit3width = r.get(common.slitSizeLogEntry(instrumentName, 2))
     if slit2width is None or slit3width is None:
         self.log().warning('Slit information not found in sample logs. Slit normalisation disabled.')
         return ws
     f = slit2width.value * slit3width.value
     normalisedWSName = self._names.withSuffix('normalised_to_slits')
     normalisedWS = Scale(InputWorkspace=ws,
                          OutputWorkspace=normalisedWSName,
                          Factor=1.0 / f,
                          EnableLogging=self._subalgLogging)
     self._cleanup.cleanup(ws)
     return normalisedWS
    def PyExec(self):
        """Execute the algorithm."""
        self._subalgLogging = self.getProperty(
            Prop.SUBALG_LOGGING).value == SubalgLogging.ON
        cleanupMode = self.getProperty(Prop.CLEANUP).value
        self._cleanup = common.WSCleanup(cleanupMode, self._subalgLogging)
        wsPrefix = self.getPropertyValue(Prop.OUTPUT_WS)
        self._names = common.WSNameSource(wsPrefix, cleanupMode)

        ws = self._inputWS()

        sumType = self._sumType()
        if sumType == SumType.IN_LAMBDA:
            ws = self._sumForegroundInLambda(ws)
            ws = self._reflectivity(ws)
        else:
            raise RuntimeError('Summation in Q is not yet supported.')

        self._finalize(ws)
 def _addBeamStatisticsToLogs(self, ws):
     """Calculate beam statistics and add the results to the sample logs."""
     reflectedForeground = self._foregroundIndices(ws)
     directWS = self.getProperty(Prop.DIRECT_WS).value
     directForeground = self._foregroundIndices(directWS)
     instrumentName = common.instrumentName(ws)
     pixelSize = common.pixelSize(instrumentName)
     detResolution = common.detectorResolution()
     ReflectometryBeamStatistics(
         ReflectedBeamWorkspace=ws,
         ReflectedForeground=reflectedForeground,
         DirectLineWorkspace=directWS,
         DirectForeground=directForeground,
         PixelSize=pixelSize,
         DetectorResolution=detResolution,
         FirstSlitName='slit2',
         FirstSlitSizeSampleLog=common.SampleLogs.SLIT2WIDTH,
         SecondSlitName='slit3',
         SecondSlitSizeSampleLog=common.SampleLogs.SLIT3WIDTH,
         EnableLogging=self._subalgLogging)
 def _addBeamStatisticsToLogs(self, ws):
     """Calculate beam statistics and add the results to the sample logs."""
     reflectedForeground = self._foregroundIndices(ws)
     directWS = self.getProperty(Prop.DIRECT_WS).value
     directForeground = self._foregroundIndices(directWS)
     instrumentName = common.instrumentName(ws)
     pixelSize = common.pixelSize(instrumentName)
     detResolution = common.detectorResolution()
     firstSlitSizeLog = common.slitSizeLogEntry(instrumentName, 1)
     secondSlitSizeLog = common.slitSizeLogEntry(instrumentName, 2)
     ReflectometryBeamStatistics(
         ReflectedBeamWorkspace=ws,
         ReflectedForeground=reflectedForeground,
         DirectLineWorkspace=directWS,
         DirectForeground=directForeground,
         PixelSize=pixelSize,
         DetectorResolution=detResolution,
         FirstSlitName='slit2',
         FirstSlitSizeSampleLog=firstSlitSizeLog,
         SecondSlitName='slit3',
         SecondSlitSizeSampleLog=secondSlitSizeLog,
         EnableLogging=self._subalgLogging)
Esempio n. 24
0
 def _divideByDirect(self, ws):
     """Divide ws by the direct beam."""
     ws = self._rebinToDirect(ws)
     directWS = self.getProperty(Prop.DIRECT_FOREGROUND_WS).value
     reflectivityWSName = self._names.withSuffix('reflectivity')
     reflectivityWS = Divide(
         LHSWorkspace=ws,
         RHSWorkspace=directWS,
         OutputWorkspace=reflectivityWSName,
         EnableLogging=self._subalgLogging)
     self._cleanup.cleanup(ws)
     reflectivityWS = common.correctForChopperOpenings(reflectivityWS, directWS, self._names, self._cleanup, self._subalgLogging)
     reflectivityWS.setYUnit('Reflectivity')
     reflectivityWS.setYUnitLabel('Reflectivity')
     return reflectivityWS
 def _calibrateDetectorAngleByDirectBeam(self, ws):
     """Perform detector position correction for reflected beams."""
     direct_line = self.getProperty('DirectBeamForegroundCentre').value
     calibratedWSName = self._names.withSuffix('reflected_beam_calibration')
     calibratedWS = SpecularReflectionPositionCorrect(
         InputWorkspace=ws,
         OutputWorkspace=calibratedWSName,
         DetectorComponentName='detector',
         LinePosition=direct_line, # yes, this is the direct line position!
         TwoTheta=2*self._theta_from_detector_angles(),
         PixelSize=common.pixelSize(self._instrumentName),
         DetectorCorrectionType='RotateAroundSample',
         DetectorFacesSample=True,
         EnableLogging=self._subalgLogging
     )
     self._cleanup.cleanup(ws)
     return calibratedWS
 def _calibrateDetectorAngleByDirectBeam(self, ws):
     """Perform detector position correction for reflected beams."""
     if self.getProperty(Prop.DIRECT_LINE_WORKSPACE).isDefault:
         return ws
     calibratedWSName = self._names.withSuffix('reflected_beam_calibration')
     directLineWS = self.getProperty(Prop.DIRECT_LINE_WORKSPACE).value
     directLine = directLineWS.run().getProperty(
         common.SampleLogs.LINE_POSITION).value
     calibratedWS = SpecularReflectionPositionCorrect(
         InputWorkspace=ws,
         OutputWorkspace=calibratedWSName,
         EnableLogging=self._subalgLogging,
         DetectorComponentName='detector',
         DirectLineWorkspace=directLineWS,
         DirectLinePosition=directLine,
         PixelSize=common.pixelSize(self._instrumentName),
         DetectorCorrectionType='RotateAroundSample',
         DetectorFacesSample=True)
     self._cleanup.cleanup(ws)
     return calibratedWS
 def _calibrateDetectorAngleByDirectBeam(self, ws):
     """Perform detector position correction for reflected beams."""
     if self.getProperty(Prop.DIRECT_LINE_WORKSPACE).isDefault:
         return ws
     calibratedWSName = self._names.withSuffix('reflected_beam_calibration')
     directLineWS = self.getProperty(Prop.DIRECT_LINE_WORKSPACE).value
     directLine = directLineWS.run().getProperty(common.SampleLogs.LINE_POSITION).value
     calibratedWS = SpecularReflectionPositionCorrect(
         InputWorkspace=ws,
         OutputWorkspace=calibratedWSName,
         EnableLogging=self._subalgLogging,
         DetectorComponentName='detector',
         DirectLineWorkspace=directLineWS,
         DirectLinePosition=directLine,
         PixelSize=common.pixelSize(self._instrumentName),
         DetectorCorrectionType='RotateAroundSample',
         DetectorFacesSample=True
     )
     self._cleanup.cleanup(ws)
     return calibratedWS
    def _inputWS(self):
        """Return a raw input workspace."""
        inputFiles = self.getPropertyValue(Prop.RUN)
        inputFiles = inputFiles.replace(',', '+')
        mergedWSName = self._names.withSuffix('merged')
        measurement_type = self.getPropertyValue('Measurement')
        load_options = {
            'Measurement': measurement_type,
            'XUnit': 'TimeOfFlight',
            'FitStartWorkspaceIndex': self.getProperty(Prop.START_WS_INDEX).value,
            'FitEndWorkspaceIndex': self.getProperty(Prop.END_WS_INDEX).value,
            'FitRangeLower': self.getProperty(Prop.XMIN).value,
            'FitRangeUpper': self.getProperty(Prop.XMAX).value
        }
        if measurement_type == 'ReflectedBeam':
            bragg_angle = None
            angle_option = self.getPropertyValue('AngleOption')
            first_run = self.getProperty(Prop.RUN).value[0]
            if angle_option == 'SampleAngle':
                bragg_angle = common.sample_angle(first_run)
            elif angle_option == 'DetectorAngle':
                bragg_angle = self._theta_from_detector_angles()
                # in this clause we still need to correct for the difference of foreground
                # centres between direct and reflected beams
                # but we need first to load the reflected beam to be able to do this
            elif angle_option == 'UserAngle':
                bragg_angle = self.getProperty('BraggAngle').value
            load_options['BraggAngle'] = bragg_angle

        # MergeRunsOptions are defined by the parameter files and will not be modified here!
        ws = LoadAndMerge(
            Filename=inputFiles,
            LoaderName='LoadILLReflectometry',
            LoaderOptions=load_options,
            OutputWorkspace=mergedWSName,
            EnableLogging=self._subalgLogging
        )
        return ws
Esempio n. 29
0
    def _sumForegroundInLambda(self, ws):
        """Sum the foreground region into a single histogram."""
        foreground = self._foregroundIndices(ws)
        sumIndices = [i for i in range(foreground[0], foreground[2] + 1)]
        beamPosIndex = foreground[1]
        foregroundWSName = self._names.withSuffix('grouped')
        foregroundWS = ExtractSingleSpectrum(InputWorkspace=ws,
                                             OutputWorkspace=foregroundWSName,
                                             WorkspaceIndex=beamPosIndex,
                                             EnableLogging=self._subalgLogging)
        maxIndex = ws.getNumberHistograms() - 1
        foregroundYs = foregroundWS.dataY(0)
        foregroundEs = foregroundWS.dataE(0)
        numpy.square(foregroundEs, out=foregroundEs)
        for i in sumIndices:
            if i == beamPosIndex:
                continue
            if i < 0 or i > maxIndex:
                self.log().warning(
                    'Foreground partially out of the workspace.')
            addeeWSName = self._names.withSuffix('addee')
            addeeWS = ExtractSingleSpectrum(InputWorkspace=ws,
                                            OutputWorkspace=addeeWSName,
                                            WorkspaceIndex=i,
                                            EnableLogging=self._subalgLogging)
            addeeWS = RebinToWorkspace(WorkspaceToRebin=addeeWS,
                                       WorkspaceToMatch=foregroundWS,
                                       OutputWorkspace=addeeWSName,
                                       EnableLogging=self._subalgLogging)
            ys = addeeWS.readY(0)
            foregroundYs += ys
            es = addeeWS.readE(0)
            foregroundEs += es**2
            self._cleanup.cleanup(addeeWS)
        self._cleanup.cleanup(ws)
        numpy.sqrt(foregroundEs, out=foregroundEs)
        # Move the detector to the fractional linePosition
        linePosition = ws.run().getProperty(
            common.SampleLogs.LINE_POSITION).value
        instr = common.instrumentName(ws)
        pixelSize = common.pixelSize(instr)
        dist = pixelSize * (linePosition - beamPosIndex)

        if dist != 0.:
            detPoint1 = ws.spectrumInfo().position(0)
            detPoint2 = ws.spectrumInfo().position(20)
            beta = numpy.math.atan2((detPoint2[0] - detPoint1[0]),
                                    (detPoint2[2] - detPoint1[2]))
            xvsy = numpy.math.sin(beta) * dist
            mz = numpy.math.cos(beta) * dist
            if instr == 'D17':
                mx = xvsy
                my = 0.0
                rotationAxis = [0, 1, 0]
            else:
                mx = 0.0
                my = xvsy
                rotationAxis = [-1, 0, 0]
            MoveInstrumentComponent(Workspace=foregroundWS,
                                    ComponentName='detector',
                                    X=mx,
                                    Y=my,
                                    Z=mz,
                                    RelativePosition=True)
            theta = foregroundWS.spectrumInfo().twoTheta(0) / 2.
            RotateInstrumentComponent(Workspace=foregroundWS,
                                      ComponentName='detector',
                                      X=rotationAxis[0],
                                      Y=rotationAxis[1],
                                      Z=rotationAxis[2],
                                      Angle=theta,
                                      RelativeRotation=True)
        return foregroundWS
 def _correctForChopperOpenings(self, ws, directWS):
     """Corrects ws for different chopper opening angles."""
     correctedWS = common.correctForChopperOpenings(ws, directWS, self._names, self._cleanup, self._subalgLogging)
     return correctedWS
 def _theta_from_detector_angles(self):
     """Returns the bragg angle as half of detector angle difference"""
     first_run = self.getProperty(Prop.RUN).value[0]
     db_detector_angle = self.getProperty('DirectBeamDetectorAngle').value
     return (common.detector_angle(first_run) - db_detector_angle) / 2.
Esempio n. 32
0
 def opening(instrumentName, logs, Xs):
     chopperGap = common.chopperPairDistance(logs, instrumentName)
     chopperPeriod = 60. / common.chopperSpeed(logs, instrumentName)
     openingAngle = common.chopperOpeningAngle(logs, instrumentName)
     return chopperGap * constants.m_n / constants.h / chopperPeriod * Xs * 1e-10 + openingAngle / 360.