diff --git a/Code/Mantid/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/Fury.py b/Code/Mantid/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/TransformToIqt.py similarity index 87% rename from Code/Mantid/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/Fury.py rename to Code/Mantid/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/TransformToIqt.py index ab8aff547bafaa64f74b506e7e0a53a778fd6715..ab2d4a4c5129930c1eb751de12641d099251eecf 100644 --- a/Code/Mantid/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/Fury.py +++ b/Code/Mantid/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/TransformToIqt.py @@ -7,7 +7,7 @@ import math import os -class Fury(PythonAlgorithm): +class TransformToIqt(PythonAlgorithm): _sample = None _resolution = None @@ -21,29 +21,35 @@ class Fury(PythonAlgorithm): _save = None _dry_run = None + def category(self): - return "Workflow\\MIDAS;PythonAlgorithms" + return "Workflow\\Inelastic;PythonAlgorithms" + + + def summary(self): + return 'Transforms an inelastic reduction to I(Q, t)' + def PyInit(self): - self.declareProperty(MatrixWorkspaceProperty('Sample', '',\ + self.declareProperty(MatrixWorkspaceProperty('SampleWorkspace', '',\ optional=PropertyMode.Mandatory, direction=Direction.Input), - doc="Name for the Sample workspace.") + doc="Name for the sample workspace.") - self.declareProperty(MatrixWorkspaceProperty('Resolution', '',\ + self.declareProperty(MatrixWorkspaceProperty('ResolutionWorkspace', '',\ optional=PropertyMode.Mandatory, direction=Direction.Input), - doc="Name for the Resolution workspace.") + doc="Name for the resolution workspace.") self.declareProperty(name='EnergyMin', defaultValue=-0.5, doc='Minimum energy for fit. Default=-0.5') self.declareProperty(name='EnergyMax', defaultValue=0.5, doc='Maximum energy for fit. Default=0.5') - self.declareProperty(name='NumBins', defaultValue=1, + self.declareProperty(name='BinReductionFactor', defaultValue=10.0, doc='Decrease total number of spectrum points by this ratio through merging of ' 'intensities from neighbouring bins. Default=1') self.declareProperty(MatrixWorkspaceProperty('ParameterWorkspace', '',\ direction=Direction.Output, optional=PropertyMode.Optional), - doc='Table workspace for saving Fury properties') + doc='Table workspace for saving TransformToIqt properties') self.declareProperty(MatrixWorkspaceProperty('OutputWorkspace', '',\ direction=Direction.Output, optional=PropertyMode.Optional), @@ -76,7 +82,7 @@ class Fury(PythonAlgorithm): if self._plot: self._plot_output() else: - logger.information('Dry run, will not run Fury') + logger.information('Dry run, will not run TransformToIqt') self.setProperty('ParameterWorkspace', self._parameter_table) self.setProperty('OutputWorkspace', self._output_workspace) @@ -88,16 +94,16 @@ class Fury(PythonAlgorithm): """ from IndirectCommon import getWSprefix - self._sample = self.getPropertyValue('Sample') - self._resolution = self.getPropertyValue('Resolution') + self._sample = self.getPropertyValue('SampleWorkspace') + self._resolution = self.getPropertyValue('ResolutionWorkspace') self._e_min = self.getProperty('EnergyMin').value self._e_max = self.getProperty('EnergyMax').value - self._number_points_per_bin = self.getProperty('NumBins').value + self._number_points_per_bin = self.getProperty('BinReductionFactor').value self._parameter_table = self.getPropertyValue('ParameterWorkspace') if self._parameter_table == '': - self._parameter_table = getWSprefix(self._sample) + 'FuryParameters' + self._parameter_table = getWSprefix(self._sample) + 'TransformToIqtParameters' self._output_workspace = self.getPropertyValue('OutputWorkspace') if self._output_workspace == '': @@ -128,13 +134,13 @@ class Fury(PythonAlgorithm): def _calculate_parameters(self): """ - Calculates the Fury parameters and saves in a table workspace. + Calculates the TransformToIqt parameters and saves in a table workspace. """ - CropWorkspace(InputWorkspace=self._sample, OutputWorkspace='__Fury_sample_cropped', + CropWorkspace(InputWorkspace=self._sample, OutputWorkspace='__TransformToIqt_sample_cropped', Xmin=self._e_min, Xmax=self._e_max) - x_data = mtd['__Fury_sample_cropped'].readX(0) + x_data = mtd['__TransformToIqt_sample_cropped'].readX(0) number_input_points = len(x_data) - 1 - num_bins = number_input_points / self._number_points_per_bin + num_bins = int(number_input_points / self._number_points_per_bin) self._e_width = (abs(self._e_min) + abs(self._e_max)) / num_bins try: @@ -167,7 +173,7 @@ class Fury(PythonAlgorithm): param_table = CreateEmptyTableWorkspace(OutputWorkspace=self._parameter_table) param_table.addColumn('int', 'SampleInputBins') - param_table.addColumn('int', 'NumberBins') + param_table.addColumn('float', 'BinReductionFactor') param_table.addColumn('int', 'SampleOutputBins') param_table.addColumn('float', 'EnergyMin') param_table.addColumn('float', 'EnergyMax') @@ -179,7 +185,7 @@ class Fury(PythonAlgorithm): self._e_min, self._e_max, self._e_width, resolution, resolution_bins]) - DeleteWorkspace('__Fury_sample_cropped') + DeleteWorkspace('__TransformToIqt_sample_cropped') self.setProperty('ParameterWorkspace', param_table) @@ -212,7 +218,7 @@ class Fury(PythonAlgorithm): def _fury(self): """ - Run Fury. + Run TransformToIqt. """ from IndirectCommon import CheckHistZero, CheckHistSame, CheckAnalysers @@ -261,4 +267,4 @@ class Fury(PythonAlgorithm): # Register algorithm with Mantid -AlgorithmFactory.subscribe(Fury) +AlgorithmFactory.subscribe(TransformToIqt) diff --git a/Code/Mantid/Framework/PythonInterface/test/python/plugins/algorithms/CMakeLists.txt b/Code/Mantid/Framework/PythonInterface/test/python/plugins/algorithms/CMakeLists.txt index f1582a8b2e1e9be6eb6563f424cb8d6990f0c5dc..77b67b9edc8f9142c083ae3d3004f4ffe577537f 100644 --- a/Code/Mantid/Framework/PythonInterface/test/python/plugins/algorithms/CMakeLists.txt +++ b/Code/Mantid/Framework/PythonInterface/test/python/plugins/algorithms/CMakeLists.txt @@ -55,6 +55,7 @@ set ( TEST_PY_FILES UpdatePeakParameterTableValueTest.py SANSSubtractTest.py TimeSliceTest.py + TransformToIqtTest.py ExportSampleLogsToCSVFileTest.py ExportExperimentLogTest.py PoldiMergeTest.py diff --git a/Code/Mantid/Framework/PythonInterface/test/python/plugins/algorithms/TransformToIqtTest.py b/Code/Mantid/Framework/PythonInterface/test/python/plugins/algorithms/TransformToIqtTest.py new file mode 100644 index 0000000000000000000000000000000000000000..ac64daa184372cf0ff5cdb01be99549a8036cff2 --- /dev/null +++ b/Code/Mantid/Framework/PythonInterface/test/python/plugins/algorithms/TransformToIqtTest.py @@ -0,0 +1,60 @@ +import unittest +from mantid.simpleapi import * +from mantid.api import * + + +class TransformToIqtTest(unittest.TestCase): + + + def setUp(self): + """ + Generate reference result param table. + """ + + CreateEmptyTableWorkspace(OutputWorkspace='__TransformToIqtTest_param') + self._param_table = mtd['__TransformToIqtTest_param'] + + self._param_table.addColumn('int', 'SampleInputBins') + self._param_table.addColumn('float', 'BinReductionFactor') + self._param_table.addColumn('int', 'SampleOutputBins') + self._param_table.addColumn('float', 'EnergyMin') + self._param_table.addColumn('float', 'EnergyMax') + self._param_table.addColumn('float', 'EnergyWidth') + self._param_table.addColumn('float', 'Resolution') + self._param_table.addColumn('int', 'ResolutionBins') + + self._param_table.addRow([1725, 10.0, 172, -0.5, 0.5, 0.00581395, 0.0175, 6]) + + + def test_with_can_reduction(self): + """ + Tests running using the container reduction as a resolution. + """ + + sample = Load('irs26176_graphite002_red') + can = Load('irs26173_graphite002_red') + + params, iqt = TransformToIqt(SampleWorkspace=sample, + ResolutionWorkspace=can, + BinReductionFactor=10) + + self.assertEqual(CheckWorkspacesMatch(params, self._param_table), "Success!") + + + def test_with_resolution_reduction(self): + """ + Tests running using the instrument resolution workspace. + """ + + sample = Load('irs26176_graphite002_red') + resolution = Load('irs26173_graphite002_res') + + params, iqt = TransformToIqt(SampleWorkspace=sample, + ResolutionWorkspace=resolution, + BinReductionFactor=10) + + self.assertEqual(CheckWorkspacesMatch(params, self._param_table), "Success!") + + +if __name__ == '__main__': + unittest.main() diff --git a/Code/Mantid/MantidQt/CustomInterfaces/src/Indirect/Fury.cpp b/Code/Mantid/MantidQt/CustomInterfaces/src/Indirect/Fury.cpp index 87c3b3416da06f74275c0db18fc57d6105fd32eb..d1f64dc1bcc2e7b197c66ee3d8896b230585af8f 100644 --- a/Code/Mantid/MantidQt/CustomInterfaces/src/Indirect/Fury.cpp +++ b/Code/Mantid/MantidQt/CustomInterfaces/src/Indirect/Fury.cpp @@ -89,20 +89,20 @@ namespace IDA double energyMin = m_dblManager->value(m_properties["ELow"]); double energyMax = m_dblManager->value(m_properties["EHigh"]); - long numBins = static_cast<long>(m_dblManager->value(m_properties["SampleBinning"])); + double numBins = m_dblManager->value(m_properties["SampleBinning"]); bool plot = m_uiForm.ckPlot->isChecked(); bool save = m_uiForm.ckSave->isChecked(); - IAlgorithm_sptr furyAlg = AlgorithmManager::Instance().create("Fury", -1); + IAlgorithm_sptr furyAlg = AlgorithmManager::Instance().create("TransformToIqt", -1); furyAlg->initialize(); - furyAlg->setProperty("Sample", wsName.toStdString()); - furyAlg->setProperty("Resolution", resName.toStdString()); + furyAlg->setProperty("SampleWorkspace", wsName.toStdString()); + furyAlg->setProperty("ResolutionWorkspace", resName.toStdString()); furyAlg->setProperty("EnergyMin", energyMin); furyAlg->setProperty("EnergyMax", energyMax); - furyAlg->setProperty("NumBins", numBins); + furyAlg->setProperty("BinReductionFactor", numBins); furyAlg->setProperty("Plot", plot); furyAlg->setProperty("Save", save); @@ -188,20 +188,20 @@ namespace IDA double energyMin = m_dblManager->value(m_properties["ELow"]); double energyMax = m_dblManager->value(m_properties["EHigh"]); - long numBins = static_cast<long>(m_dblManager->value(m_properties["SampleBinning"])); // Default value + double numBins = m_dblManager->value(m_properties["SampleBinning"]); if(numBins == 0) return; - IAlgorithm_sptr furyAlg = AlgorithmManager::Instance().create("Fury"); + IAlgorithm_sptr furyAlg = AlgorithmManager::Instance().create("TransformToIqt"); furyAlg->initialize(); - furyAlg->setProperty("Sample", wsName.toStdString()); - furyAlg->setProperty("Resolution", resName.toStdString()); + furyAlg->setProperty("SampleWorkspace", wsName.toStdString()); + furyAlg->setProperty("ResolutionWorkspace", resName.toStdString()); furyAlg->setProperty("ParameterWorkspace", "__FuryProperties_temp"); furyAlg->setProperty("EnergyMin", energyMin); furyAlg->setProperty("EnergyMax", energyMax); - furyAlg->setProperty("NumBins", numBins); + furyAlg->setProperty("BinReductionFactor", numBins); furyAlg->setProperty("Plot", false); furyAlg->setProperty("Save", false); diff --git a/Code/Mantid/Testing/Data/UnitTest/irs26173_graphite002_res.nxs.md5 b/Code/Mantid/Testing/Data/UnitTest/irs26173_graphite002_res.nxs.md5 new file mode 100644 index 0000000000000000000000000000000000000000..f8094ffb61e4994fb5350f25c238d1d2730c85b6 --- /dev/null +++ b/Code/Mantid/Testing/Data/UnitTest/irs26173_graphite002_res.nxs.md5 @@ -0,0 +1 @@ +4a322a634e527c87fbef27f1cc9559d2 \ No newline at end of file diff --git a/Code/Mantid/Testing/SystemTests/tests/analysis/ISISIndirectInelastic.py b/Code/Mantid/Testing/SystemTests/tests/analysis/ISISIndirectInelastic.py index 573b3654654da2b0eec2c3a4d0506ada2e03acb9..60c6e04a961de78ed7c22d955ade098454380b06 100644 --- a/Code/Mantid/Testing/SystemTests/tests/analysis/ISISIndirectInelastic.py +++ b/Code/Mantid/Testing/SystemTests/tests/analysis/ISISIndirectInelastic.py @@ -682,7 +682,7 @@ class OSIRISDiagnostics(ISISIndirectInelasticDiagnostics): #============================================================================== class ISISIndirectInelasticMoments(ISISIndirectInelasticBase): - '''A base class for the ISIS indirect inelastic Fury/FuryFit tests + '''A base class for the ISIS indirect inelastic TransformToIqt/TransformToIqtFit tests The output of Elwin is usually used with MSDFit and so we plug one into the other in this test. @@ -849,7 +849,7 @@ class ISISIndirectInelasticFuryAndFuryFit(ISISIndirectInelasticBase): ''' A base class for the ISIS indirect inelastic Fury/FuryFit tests - The output of Fury is usually used with FuryFit and so we plug one into + The output of TransformToIqt is usually used with FuryFit and so we plug one into the other in this test. ''' @@ -865,14 +865,14 @@ class ISISIndirectInelasticFuryAndFuryFit(ISISIndirectInelasticBase): LoadNexus(sample, OutputWorkspace=sample) LoadNexus(self.resolution, OutputWorkspace=self.resolution) - fury_props, fury_ws = Fury(Sample=self.samples[0], - Resolution=self.resolution, - EnergyMin=self.e_min, - EnergyMax=self.e_max, - NumBins=self.num_bins, - DryRun=False, - Save=False, - Plot=False) + fury_props, fury_ws = TransformToIqt(SampleWorkspace=self.samples[0], + ResolutionWorkspace=self.resolution, + EnergyMin=self.e_min, + EnergyMax=self.e_max, + BinReductionFactor=self.num_bins, + DryRun=False, + Save=False, + Plot=False) # Test FuryFit Sequential furyfitSeq_ws = furyfitSeq(fury_ws.getName(), @@ -922,7 +922,7 @@ class OSIRISFuryAndFuryFit(ISISIndirectInelasticFuryAndFuryFit): def __init__(self): ISISIndirectInelasticFuryAndFuryFit.__init__(self) - # Fury + # TransformToIqt self.samples = ['osi97935_graphite002_red.nxs'] self.resolution = 'osi97935_graphite002_res.nxs' self.e_min = -0.4 @@ -947,7 +947,7 @@ class IRISFuryAndFuryFit(ISISIndirectInelasticFuryAndFuryFit): def __init__(self): ISISIndirectInelasticFuryAndFuryFit.__init__(self) - # Fury + # TransformToIqt self.samples = ['irs53664_graphite002_red.nxs'] self.resolution = 'irs53664_graphite002_res.nxs' self.e_min = -0.4 @@ -986,14 +986,14 @@ class ISISIndirectInelasticFuryAndFuryFitMulti(ISISIndirectInelasticBase): LoadNexus(sample, OutputWorkspace=sample) LoadNexus(self.resolution, OutputWorkspace=self.resolution) - fury_props, fury_ws = Fury(Sample=self.samples[0], - Resolution=self.resolution, - EnergyMin=self.e_min, - EnergyMax=self.e_max, - NumBins=self.num_bins, - DryRun=False, - Save=False, - Plot=False) + fury_props, fury_ws = TransformToIqt(SampleWorkspace=self.samples[0], + ResolutionWorkspace=self.resolution, + EnergyMin=self.e_min, + EnergyMax=self.e_max, + BinReductionFactor=self.num_bins, + DryRun=False, + Save=False, + Plot=False) # Test FuryFit Sequential furyfitSeq_ws = furyfitMult(fury_ws.getName(), @@ -1045,7 +1045,7 @@ class OSIRISFuryAndFuryFitMulti(ISISIndirectInelasticFuryAndFuryFitMulti): def __init__(self): ISISIndirectInelasticFuryAndFuryFitMulti.__init__(self) - # Fury + # TransformToIqt self.samples = ['osi97935_graphite002_red.nxs'] self.resolution = 'osi97935_graphite002_res.nxs' self.e_min = -0.4 @@ -1070,7 +1070,7 @@ class IRISFuryAndFuryFitMulti(ISISIndirectInelasticFuryAndFuryFitMulti): def __init__(self): ISISIndirectInelasticFuryAndFuryFitMulti.__init__(self) - # Fury + # TransformToIqt self.samples = ['irs53664_graphite002_red.nxs'] self.resolution = 'irs53664_graphite002_res.nxs' self.e_min = -0.4 diff --git a/Code/Mantid/docs/source/algorithms/Fury-v1.rst b/Code/Mantid/docs/source/algorithms/Fury-v1.rst deleted file mode 100644 index a82a566e5ec784ab5326137903881925e7dee98c..0000000000000000000000000000000000000000 --- a/Code/Mantid/docs/source/algorithms/Fury-v1.rst +++ /dev/null @@ -1,24 +0,0 @@ -.. algorithm:: - -.. summary:: - -.. alias:: - -.. properties:: - -Description ------------ - -The model that is being fitted is that of a delta-function (elastic component) of amplitude :math:`A(0)` and Lorentzians of amplitude :math:`A(j)` and HWHM :math:`W(j)` where :math:`j=1,2,3`. The whole function is then convolved with the resolution function. The -function and Lorentzians are intrinsically -normalised to unity so that the amplitudes represent their integrated areas. - -For a Lorentzian, the Fourier transform does the conversion: :math:`1/(x^{2}+\delta^{2}) \Leftrightarrow exp[-2\pi(\delta k)]`. -If :math:`x` is identified with energy :math:`E` and :math:`2\pi k` with :math:`t/\hbar` where t is time then: :math:`1/[E^{2}+(\hbar / \tau )^{2}] \Leftrightarrow exp[-t /\tau]` and :math:`\sigma` is identified with :math:`\hbar / \tau`. -The program estimates the quasielastic components of each of the groups of spectra and requires the resolution file and optionally the normalisation file created by ResNorm. - -For a Stretched Exponential, the choice of several Lorentzians is replaced with a single function with the shape : :math:`\psi\beta(x) \Leftrightarrow exp[-2\pi(\sigma k)\beta]`. This, in the energy to time FT transformation, is :math:`\psi\beta(E) \Leftrightarrow exp[-(t/\tau)\beta]`. So \sigma is identified with :math:`(2\pi)\beta\hbar/\tau`. -The model that is fitted is that of an elastic component and the stretched exponential and the program gives the best estimate for the :math:`\beta` parameter and the width for each group of spectra. - -This routine was originally part of the MODES package. - -.. categories:: diff --git a/Code/Mantid/docs/source/algorithms/TransformToIqt-v1.rst b/Code/Mantid/docs/source/algorithms/TransformToIqt-v1.rst new file mode 100644 index 0000000000000000000000000000000000000000..83480d11785c64b0edfd40982bb5bcdf0ad8006d --- /dev/null +++ b/Code/Mantid/docs/source/algorithms/TransformToIqt-v1.rst @@ -0,0 +1,112 @@ +.. algorithm:: + +.. summary:: + +.. alias:: + +.. properties:: + +Description +----------- + +This algorithm transforms either a reduced (*_red*) or S(Q, w) (*_sqw*) +workspace to a I(Q, t) workspace. + +Theory +------ + +The measured spectrum :math:`I(Q, \omega)` is proportional to the four +dimensional convolution of the scattering law :math:`S(Q, \omega)` with the +resolution function :math:`R(Q, \omega)` of the spectrometer via :math:`I(Q, +\omega) = S(Q, \omega) ⊗ R(Q, \omega)`, so :math:`S(Q, \omega)` can be obtained, +in principle, by a deconvolution in :math:`Q` and :math:`\omega`. The method +employed here is based on the Fourier Transform (FT) technique [6,7]. On Fourier +transforming the equation becomes :math:`I(Q, t) = S(Q, t) x R(Q, t)` where the +convolution in :math:`\omega`-space is replaced by a simple multiplication in +:math:`t`-space. The intermediate scattering law :math:`I(Q, t)` is then +obtained by simple division and the scattering law :math:`S(Q, \omega)` itself +can be obtained by back transformation. The latter however is full of pitfalls +for the unwary. The advantage of this technique over that of a fitting procedure +such as SWIFT is that a functional form for :math:`I(Q, t)` does not have to be +assumed. On IRIS the resolution function is close to a Lorentzian and the +scattering law is often in the form of one or more Lorentzians. The FT of a +Lorentzian is a decaying exponential, :math:`exp(-\alpha t)` , so that plots of +:math:`ln(I(Q, t))` against t would be straight lines thus making interpretation +easier. + +In general, the origin in energy for the sample run and the resolution run need +not necessarily be the same or indeed be exactly zero in the conversion of the +RAW data from time-of-flight to energy transfer. This will depend, for example, +on the sample and vanadium shapes and positions and whether the analyser +temperature has changed between the runs. The procedure takes this into account +automatically, without using an arbitrary fitting procedure, in the following +way. From the general properties of the FT, the transform of an offset +Lorentzian has the form :math:`(cos(\omega_{0}t) + isin(\omega_{0}t))exp(-\Gamma +t)` , thus taking the modulus produces the exponential :math:`exp(-\Gamma t)` +which is the required function. If this is carried out for both sample and +resolution, the difference in the energy origin is automatically removed. The +results of this procedure should however be treated with some caution when +applied to more complicated spectra in which it is possible for :math:`I(Q, t)` +to become negative, for example, when inelastic side peaks are comparable in +height to the elastic peak. + +The interpretation of the data must also take into account the propagation of +statistical errors (counting statistics) in the measured data as discussed by +Wild et al [1]. If the count in channel :math:`k` is :math:`X_{k}` , then +:math:`X_{k}=<X_{k}>+\Delta X_{k}` where :math:`<X_{k}>` is the mean value and +:math:`\Delta X_{k}` the error. The standard deviation for channel :math:`k` is +:math:`\sigma k` :math:`2=<\Delta X_{k}>2` which is assumed to be given by +:math:`\sigma k=<X_{k}>`. The FT of :math:`X_{k}` is defined by +:math:`X_{j}=<X_{j}>+\Delta X_{j}` and the real and imaginary parts denoted by +:math:`X_{j} I` and :math:`X_{j} I` respectively. The standard deviations on +:math:`X_{j}` are then given by :math:`\sigma 2(X_{j} R)=1/2 X0 R + 1/2 X2j R` +and :math:`\sigma 2(X_{j} I)=1/2 X0 I - 1/2 X2j I`. + +Note that :math:`\sigma 2(X_{0} R) = X_{0} R` and from the properties of FT +:math:`X_{0} R = X_{k}`. Thus the standard deviation of the first coefficient +of the FT is the square root of the integrated intensity of the spectrum. In +practice, apart from the first few coefficients, the error is nearly constant +and close to :math:`X_{0} R`. A further point to note is that the errors make +the imaginary part of :math:`I(Q, t)` non-zero and that, although these will be +distributed about zero, on taking the modulus of :math:`I(Q, t)`, they become +positive at all times and are distributed about a non-zero positive value. When +:math:`I(Q, t)` is plotted on a log-scale the size of the error bars increases +with time (coefficient) and for the resolution will reach a point where the +error on a coefficient is comparable to its value. This region must therefore be +treated with caution. For a true deconvolution by back transforming, the data +would be truncated to remove this poor region before back transforming. If the +truncation is severe the back transform may contain added ripples, so an +automatic back transform is not provided. + +References +---------- + +1. U P Wild, R Holzwarth & H P Good, Rev Sci Instr 48 1621 (1977) + +Usage +----- + +**Example - TransformToIqt with IRIS data.** + +.. testcode:: exTransformToIqtIRIS + + sample = Load('irs26176_graphite002_red.nxs') + can = Load('irs26173_graphite002_red.nxs') + + params, iqt = TransformToIqt(SampleWorkspace=sample, + ResolutionWorkspace=can, + EnergyMin=-0.5, + EnergyMax=0.5, + BinReductionFactor=10) + + print 'Number of output bins: %d' % (params.cell('SampleOutputBins', 0)) + print 'Resolution bins: %d' % (params.cell('ResolutionBins', 0)) + +Output: + +.. testoutput:: exTransformToIqtIRIS + + Number of output bins: 172 + Resolution bins: 6 + +.. categories:: diff --git a/Code/Mantid/docs/source/interfaces/Indirect_DataAnalysis.rst b/Code/Mantid/docs/source/interfaces/Indirect_DataAnalysis.rst index 30201258338fd85aa81809fbd695c9791c640b9f..604af290896c8db370d5f459624f1e31f1f7b1e1 100644 --- a/Code/Mantid/docs/source/interfaces/Indirect_DataAnalysis.rst +++ b/Code/Mantid/docs/source/interfaces/Indirect_DataAnalysis.rst @@ -144,7 +144,7 @@ Fury :widget: tabFury Given sample and resolution inputs, carries out a fit as per the theory detailed -below. +in the :ref:`TransformToIqt <algm-TransformToIqt>` algorithm. Options ~~~~~~~ @@ -194,76 +194,6 @@ ResolutionBins Number of bins in the resolution after rebinning, typically this should be at least 5 and a warning will be shown if it is less. -Theory -~~~~~~ - -The measured spectrum :math:`I(Q, \omega)` is proportional to the four -dimensional convolution of the scattering law :math:`S(Q, \omega)` with the -resolution function :math:`R(Q, \omega)` of the spectrometer via :math:`I(Q, -\omega) = S(Q, \omega) ⊗ R(Q, \omega)`, so :math:`S(Q, \omega)` can be obtained, -in principle, by a deconvolution in :math:`Q` and :math:`\omega`. The method -employed here is based on the Fourier Transform (FT) technique [6,7]. On Fourier -transforming the equation becomes :math:`I(Q, t) = S(Q, t) x R(Q, t)` where the -convolution in :math:`\omega`-space is replaced by a simple multiplication in -:math:`t`-space. The intermediate scattering law :math:`I(Q, t)` is then -obtained by simple division and the scattering law :math:`S(Q, \omega)` itself -can be obtained by back transformation. The latter however is full of pitfalls -for the unwary. The advantage of this technique over that of a fitting procedure -such as SWIFT is that a functional form for :math:`I(Q, t)` does not have to be -assumed. On IRIS the resolution function is close to a Lorentzian and the -scattering law is often in the form of one or more Lorentzians. The FT of a -Lorentzian is a decaying exponential, :math:`exp(-\alpha t)` , so that plots of -:math:`ln(I(Q, t))` against t would be straight lines thus making interpretation -easier. - -In general, the origin in energy for the sample run and the resolution run need -not necessarily be the same or indeed be exactly zero in the conversion of the -RAW data from time-of-flight to energy transfer. This will depend, for example, -on the sample and vanadium shapes and positions and whether the analyser -temperature has changed between the runs. The procedure takes this into account -automatically, without using an arbitrary fitting procedure, in the following -way. From the general properties of the FT, the transform of an offset -Lorentzian has the form :math:`(cos(\omega_{0}t) + isin(\omega_{0}t))exp(-\Gamma -t)` , thus taking the modulus produces the exponential :math:`exp(-\Gamma t)` -which is the required function. If this is carried out for both sample and -resolution, the difference in the energy origin is automatically removed. The -results of this procedure should however be treated with some caution when -applied to more complicated spectra in which it is possible for :math:`I(Q, t)` -to become negative, for example, when inelastic side peaks are comparable in -height to the elastic peak. - -The interpretation of the data must also take into account the propagation of -statistical errors (counting statistics) in the measured data as discussed by -Wild et al [1]. If the count in channel :math:`k` is :math:`X_{k}` , then -:math:`X_{k}=<X_{k}>+\Delta X_{k}` where :math:`<X_{k}>` is the mean value and -:math:`\Delta X_{k}` the error. The standard deviation for channel :math:`k` is -:math:`\sigma k` :math:`2=<\Delta X_{k}>2` which is assumed to be given by -:math:`\sigma k=<X_{k}>`. The FT of :math:`X_{k}` is defined by -:math:`X_{j}=<X_{j}>+\Delta X_{j}` and the real and imaginary parts denoted by -:math:`X_{j} I` and :math:`X_{j} I` respectively. The standard deviations on -:math:`X_{j}` are then given by :math:`\sigma 2(X_{j} R)=1/2 X0 R + 1/2 X2j R` -and :math:`\sigma 2(X_{j} I)=1/2 X0 I - 1/2 X2j I`. - -Note that :math:`\sigma 2(X_{0} R) = X_{0} R` and from the properties of FT -:math:`X_{0} R = X_{k}`. Thus the standard deviation of the first coefficient -of the FT is the square root of the integrated intensity of the spectrum. In -practice, apart from the first few coefficients, the error is nearly constant -and close to :math:`X_{0} R`. A further point to note is that the errors make -the imaginary part of :math:`I(Q, t)` non-zero and that, although these will be -distributed about zero, on taking the modulus of :math:`I(Q, t)`, they become -positive at all times and are distributed about a non-zero positive value. When -:math:`I(Q, t)` is plotted on a log-scale the size of the error bars increases -with time (coefficient) and for the resolution will reach a point where the -error on a coefficient is comparable to its value. This region must therefore be -treated with caution. For a true deconvolution by back transforming, the data -would be truncated to remove this poor region before back transforming. If the -truncation is severe the back transform may contain added ripples, so an -automatic back transform is not provided. - -References: - -1. U P Wild, R Holzwarth & H P Good, Rev Sci Instr 48 1621 (1977) - Fury Fit -------- diff --git a/Code/Mantid/scripts/Inelastic/IndirectDataAnalysis.py b/Code/Mantid/scripts/Inelastic/IndirectDataAnalysis.py index c258965efba5ec46a5ac556cd70b6135b829669d..a1d11b69033a13cadda975757e3775e6e857fbc1 100644 --- a/Code/Mantid/scripts/Inelastic/IndirectDataAnalysis.py +++ b/Code/Mantid/scripts/Inelastic/IndirectDataAnalysis.py @@ -288,7 +288,7 @@ def furyfitMult(inputWS, function, ftype, startx, endx, spec_min=0, spec_max=Non if Plot != 'None': furyfitPlotSeq(result_workspace, Plot) - EndTime('FuryFit Multi') + EndTime('TransformToIqtFit Multi') return result_workspace