Newer
Older
#pylint: disable=no-init,invalid-name
from mantid.kernel import *
from mantid.api import *
import math
class EnginXCalibrateFull(PythonAlgorithm):
def category(self):
return "Diffraction\Engineering;PythonAlgorithms"
def name(self):
def summary(self):
return "Calibrates every pixel position by performing single peak fitting."
def PyInit(self):
self.declareProperty(FileProperty("Filename", "", FileAction.Load),\
"Calibration run to use")
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")
def PyExec(self):
ws = self._prepareWsForFitting(ws)
positionTable = self._createPositionsTable()
indices = EnginXUtils.getWsIndicesForBank(self.getProperty('Bank').value, ws)
prog = Progress(self, 0, 1, len(indices))
newPos = self._getCalibratedDetPos(difc, det, ws)
positionTable.addRow([det.getID(), newPos])
self.setProperty("DetectorPositions", positionTable)
def _loadCalibrationRun(self):
""" 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()
def _createPositionsTable(self):
""" 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')
def _fitPeaks(self, ws, wsIndex):
""" 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
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)
def _V3DFromSpherical(self, R, polar, azimuth):
""" Returns a cartesian 3D vector for the given spherical coordinates.
Borrowed from V3D::spherical (C++).
"""
z = R*math.cos(polar)
ct=R*math.sin(polar)
x=ct*math.cos(azimuth)
y=ct*math.sin(azimuth)
AlgorithmFactory.subscribe(EnginXCalibrateFull)