Skip to content
Snippets Groups Projects
EnginXCalibrateFull.py 4.24 KiB
Newer Older
#pylint: disable=no-init,invalid-name
from mantid.kernel import *
from mantid.api import *
import math

class EnginXCalibrateFull(PythonAlgorithm):
        return "Diffraction\Engineering;PythonAlgorithms"
        return "EnginXCalibrateFull"
        return "Calibrates every pixel position by performing single peak fitting."
        self.declareProperty(FileProperty("Filename", "", FileAction.Load),\
        self.declareProperty(ITableWorkspaceProperty("DetectorPositions", "", Direction.Output),\
    		"A table with the detector IDs and calibrated detector positions in V3P format.")
        self.declareProperty(FloatArrayProperty("ExpectedPeaks", ""),\
    		"A list of dSpacing values where peaks are expected.")

        self.declareProperty("Bank", 1, "Which bank to calibrate")
        import EnginXUtils
        ws = self._loadCalibrationRun()
        ws = self._prepareWsForFitting(ws)
        positionTable = self._createPositionsTable()
        indices = EnginXUtils.getWsIndicesForBank(self.getProperty('Bank').value, ws)
        prog = Progress(self, 0, 1, len(indices))
        for i in indices:
            _, difc = self._fitPeaks(ws, i)
            det = ws.getDetector(i)
            newPos = self._getCalibratedDetPos(difc, det, ws)
            positionTable.addRow([det.getID(), newPos])
            prog.report()
        self.setProperty("DetectorPositions", positionTable)
        """ Loads specified calibration run
        alg = self.createChildAlgorithm('Load')
        alg.setProperty('Filename', self.getProperty('Filename').value)
        alg.execute()
        return alg.getProperty('OutputWorkspace').value

    def _prepareWsForFitting(self, ws):
        """ Rebins the workspace and converts it to distribution
        rebinAlg = self.createChildAlgorithm('Rebin')
        rebinAlg.setProperty('InputWorkspace', ws)
        rebinAlg.setProperty('Params', '-0.0005') # The value is borrowed from OG routines
        rebinAlg.execute()
        result = rebinAlg.getProperty('OutputWorkspace').value
        if result.isDistribution()==False:
            convertAlg = self.createChildAlgorithm('ConvertToDistribution')
            convertAlg.setProperty('Workspace', result)
            convertAlg.execute()
        return result
        """ Creates an empty table for storing detector positions
        alg = self.createChildAlgorithm('CreateEmptyTableWorkspace')
        alg.execute()
        table = alg.getProperty('OutputWorkspace').value
        table.addColumn('int', 'Detector ID')
        table.addColumn('V3D', 'Detector Position')
        return table
        """ Fits expected peaks to the spectrum, and returns calibrated zero and difc values.
        alg = self.createChildAlgorithm('EnginXFitPeaks')
        alg.setProperty('InputWorkspace', ws)
        alg.setProperty('WorkspaceIndex', wsIndex) # There should be only one index anyway
        alg.setProperty('ExpectedPeaks', self.getProperty('ExpectedPeaks').value)
        alg.execute()
        difc = alg.getProperty('Difc').value
        zero = alg.getProperty('Zero').value
        return (zero, difc)

    def _getCalibratedDetPos(self, newDifc, det, ws):
        """ Returns a detector position which corresponds to the newDifc value.

    		The two_theta and phi of the detector are preserved, L2 is changed.
    	"""
        detL2 = det.getDistance(ws.getInstrument().getSample())
        detTwoTheta = ws.detectorTwoTheta(det)
        detPhi = det.getPhi()
        newL2 = (newDifc / (252.816 * 2 * math.sin(detTwoTheta / 2.0))) - 50
        newPos = self._V3DFromSpherical(newL2, detTwoTheta, detPhi)
        return newPos

    def _V3DFromSpherical(self, R, polar, azimuth):
        """ Returns a cartesian 3D vector for the given spherical coordinates.
        z = R*math.cos(polar)
        ct=R*math.sin(polar)
        x=ct*math.cos(azimuth)
        y=ct*math.sin(azimuth)
        return V3D(x,y,z)
AlgorithmFactory.subscribe(EnginXCalibrateFull)