def PyExec(self): # Check congruence of workspaces workspaces = self.getProperty('Workspaces').value fvalues = self.getProperty('ParameterValues').value if len(workspaces) != len(fvalues): mesg = 'Number of Workspaces and ParameterValues should be the same' #logger.error(mesg) raise IndexError(mesg) for workspace in workspaces[1:]: if not self.areWorkspacesCompatible(mantid.mtd[workspaces[0]], mantid.mtd[workspace]): mesg = 'Workspace {0} incompatible with {1}'.format( workspace, workspaces[0]) logger.error(mesg) raise ValueError(mesg) # Load the workspaces into a group of dynamic structure factors from dsfinterp.dsf import Dsf from dsfinterp.dsfgroup import DsfGroup from dsfinterp.channelgroup import ChannelGroup dsfgroup = DsfGroup() for idsf in range(len(workspaces)): dsf = Dsf() dsf.Load(mantid.mtd[workspaces[idsf]]) if not self.getProperty('LoadErrors').value: dsf.errors = None # do not incorporate error data dsf.SetFvalue(fvalues[idsf]) dsfgroup.InsertDsf(dsf) # Create the intepolator if not instantiated before if not self.channelgroup: self.channelgroup = ChannelGroup() self.channelgroup.InitFromDsfGroup(dsfgroup) localregression = self.getProperty('LocalRegression').value if localregression: regressiontype = self.getProperty('RegressionType').value windowlength = self.getProperty('RegressionWindow').value self.channelgroup.InitializeInterpolator( running_regr_type=regressiontype, windowlength=windowlength) else: self.channelgroup.InitializeInterpolator(windowlength=0) # Invoke the interpolator and generate the output workspaces targetfvalues = self.getProperty('TargetParameters').value for targetfvalue in targetfvalues: if targetfvalue < min(fvalues) or targetfvalue > max(fvalues): mesg = 'Target parameters should lie in [{0}, {1}]'.format( min(fvalues), max(fvalues)) logger.error(mesg) raise ValueError(mesg) outworkspaces = self.getProperty('OutputWorkspaces').value if len(targetfvalues) != len(outworkspaces): mesg = 'Number of OutputWorkspaces and TargetParameters should be the same' logger.error(mesg) raise IndexError(mesg) for i in range(len(targetfvalues)): dsf = self.channelgroup(targetfvalues[i]) outws = mantid.simpleapi.CloneWorkspace( mantid.mtd[workspaces[0]], OutputWorkspace=outworkspaces[i]) dsf.Save(outws) # overwrite dataY and dataE
class DSFinterp1DFit(IFunction1D): _RegressionTypes = None _minWindow = None _InputWorkspaces = None _LoadErrors = None _WorkspaceIndex = None _ParameterValues = None _fmin = None _fmax = None _LocalRegression = None _RegressionType = None _RegressionWindow = None _xvalues = None _channelgroup = None def category(self): return 'QuasiElastic' def init(self): '''Declare parameters and attributes that participate in the fitting''' # Active fitting parameters self.declareParameter('Intensity', 1.0, 'Intensity') self.declareParameter( 'TargetParameter', 1.0, 'Target value of the structure factor parameter') self.declareAttribute('InputWorkspaces', '') self.declareAttribute('LoadErrors', False) self.declareAttribute('WorkspaceIndex', 0) self.declareAttribute('ParameterValues', '') self.declareAttribute('LocalRegression', True) self.declareAttribute('RegressionType', 'quadratic') self.declareAttribute('RegressionWindow', 6) # "private" attributes associated to the declare function attributes self._InputWorkspaces = None self._LoadErrors = None self._WorkspaceIndex = None self._ParameterValues = None self._fmin = None self._fmax = None self._LocalRegression = None self._RegressionType = None self._RegressionTypes = set(['linear', 'quadratic' ]) #valid syntaxfor python >= 2.6 self._RegressionWindow = None self._minWindow = {'linear': 3, 'quadratic': 4} # channelgroup to interpolate values self._channelgroup = None self._xvalues = None #energies of the channels def setAttributeValue(self, name, value): if name == "InputWorkspaces": self._InputWorkspaces = value.split() if ',' in value: self._InputWorkspaces = [x.strip() for x in value.split(',')] elif name == 'LoadErrors': self._LoadErrors = bool(value) elif name == 'WorkspaceIndex': self._WorkspaceIndex = int(value) elif name == 'ParameterValues': self._ParameterValues = [] self._fmin = 0.0 self._fmax = 0.0 if value: self._ParameterValues = [float(f) for f in value.split()] self._fmin = min(self._ParameterValues) self._fmax = max(self._ParameterValues) elif name == 'LocalRegression': self._LocalRegression = bool(value) elif name == 'RegressionType': self._RegressionType = value.lower() elif name == 'RegressionWindow': self._RegressionWindow = value def validateParams(self): '''Check parameters within expected range''' intensity = self.getParameterValue('Intensity') if intensity <= 0: message = 'Parameter Intensity in DSFinterp1DFit must be positive. Got {0} instead'.format( intensity) logger.error(message) return None f = self.getParameterValue('TargetParameter') if f < self._fmin or f > self._fmax: message = 'TargetParameter {0} is out of bounds [{1}, {2}]. Applying penalty...'.format( f, self._fmin, self._fmax) logger.error(message) return None return {'Intensity': intensity, 'TargetParameter': f} def function1D(self, xvals): ''' Fit using the interpolated structure factor ''' p = self.validateParams() if not p: return numpy.zeros( len(xvals), dtype=float) # return zeros if parameters not valid # The first time the function is called requires initialization of the interpolator if self._channelgroup is None: # Check consistency of the input # check InputWorkspaces have at least the workspace index for w in self._InputWorkspaces: if mtd[w].getNumberHistograms() <= self._WorkspaceIndex: message = 'Numer of histograms in Workspace {0} does not allow for workspace index {1}'.format( w, self._WorkspaceIndex) logger.error(message) raise IndexError(message) # check number of input workspaces and parameters is the same if len(self._ParameterValues) != len(self._InputWorkspaces): message = 'Number of InputWorkspaces and ParameterValues should be the same.'+\ ' Found {0} and {1}, respectively'.format(len(self._InputWorkspaces), len(self._ParameterValues)) logger.error(message) raise ValueError(message) # check the regression type is valid if self._RegressionType not in self._RegressionTypes: message = 'Regression type {0} not implemented. choose one of {1}'.format( self._RegressionType, ', '.join(self._RegressionTypes)) logger.error(message) raise NotImplementedError(message) # check the regression window is appropriate for the regression type selected if self._RegressionWindow < self._minWindow[self._RegressionType]: message = 'RegressionWindow must be equal or bigger than '+\ '{0} for regression type {1}'.format(self._minWindow[self._RegressionType], self._RegressionType) logger.error(message) raise ValueError(message) # Initialize the energies of the channels with the first of the input workspaces self._xvalues = numpy.copy(mtd[self._InputWorkspaces[0]].dataX( self._WorkspaceIndex)) if len(self._xvalues) == 1 + len( mtd[self._InputWorkspaces[0]].dataY(self._WorkspaceIndex)): self._xvalues = (self._xvalues[1:] + self._xvalues[:-1] ) / 2.0 # Deal with histogram data # Initialize the channel group nf = len(self._ParameterValues) # Load the InputWorkspaces into a group of dynamic structure factors from dsfinterp.dsf import Dsf from dsfinterp.dsfgroup import DsfGroup dsfgroup = DsfGroup() for idsf in range(nf): dsf = Dsf() dsf.SetIntensities(mtd[self._InputWorkspaces[idsf]].dataY( self._WorkspaceIndex)) dsf.errors = None # do not incorporate error data if self._LoadErrors: dsf.SetErrors(mtd[self._InputWorkspaces[idsf]].dataE( self._WorkspaceIndex)) dsf.SetFvalue(self._ParameterValues[idsf]) dsfgroup.InsertDsf(dsf) # Create the interpolator from dsfinterp.channelgroup import ChannelGroup self._channelgroup = ChannelGroup() self._channelgroup.InitFromDsfGroup(dsfgroup) if self._LocalRegression: self._channelgroup.InitializeInterpolator( running_regr_type=self._RegressionType, windowlength=self._RegressionWindow) else: self._channelgroup.InitializeInterpolator(windowlength=0) # channel group has been initialized, so evaluate the interpolator dsf = self._channelgroup(p['TargetParameter']) # Linear interpolation between the energies of the channels and the xvalues we require # NOTE: interpolator evaluates to zero for any of the xvals outside of the domain defined by self._xvalues intensities_interpolator = scipy.interpolate.interp1d(self._xvalues, p['Intensity'] * dsf.intensities, kind='linear') return intensities_interpolator(xvals) # can we pass by reference?
def function1D(self, xvals): ''' Fit using the interpolated structure factor ''' p = self.validateParams() if not p: return numpy.zeros( len(xvals), dtype=float) # return zeros if parameters not valid # The first time the function is called requires initialization of the interpolator if self._channelgroup is None: # Check consistency of the input # check InputWorkspaces have at least the workspace index for w in self._InputWorkspaces: if mtd[w].getNumberHistograms() <= self._WorkspaceIndex: message = 'Numer of histograms in Workspace {0} does not allow for workspace index {1}'.format( w, self._WorkspaceIndex) logger.error(message) raise IndexError(message) # check number of input workspaces and parameters is the same if len(self._ParameterValues) != len(self._InputWorkspaces): message = 'Number of InputWorkspaces and ParameterValues should be the same.'+\ ' Found {0} and {1}, respectively'.format(len(self._InputWorkspaces), len(self._ParameterValues)) logger.error(message) raise ValueError(message) # check the regression type is valid if self._RegressionType not in self._RegressionTypes: message = 'Regression type {0} not implemented. choose one of {1}'.format( self._RegressionType, ', '.join(self._RegressionTypes)) logger.error(message) raise NotImplementedError(message) # check the regression window is appropriate for the regression type selected if self._RegressionWindow < self._minWindow[self._RegressionType]: message = 'RegressionWindow must be equal or bigger than '+\ '{0} for regression type {1}'.format(self._minWindow[self._RegressionType], self._RegressionType) logger.error(message) raise ValueError(message) # Initialize the energies of the channels with the first of the input workspaces self._xvalues = numpy.copy(mtd[self._InputWorkspaces[0]].dataX( self._WorkspaceIndex)) if len(self._xvalues) == 1 + len( mtd[self._InputWorkspaces[0]].dataY(self._WorkspaceIndex)): self._xvalues = (self._xvalues[1:] + self._xvalues[:-1] ) / 2.0 # Deal with histogram data # Initialize the channel group nf = len(self._ParameterValues) # Load the InputWorkspaces into a group of dynamic structure factors from dsfinterp.dsf import Dsf from dsfinterp.dsfgroup import DsfGroup dsfgroup = DsfGroup() for idsf in range(nf): dsf = Dsf() dsf.SetIntensities(mtd[self._InputWorkspaces[idsf]].dataY( self._WorkspaceIndex)) dsf.errors = None # do not incorporate error data if self._LoadErrors: dsf.SetErrors(mtd[self._InputWorkspaces[idsf]].dataE( self._WorkspaceIndex)) dsf.SetFvalue(self._ParameterValues[idsf]) dsfgroup.InsertDsf(dsf) # Create the interpolator from dsfinterp.channelgroup import ChannelGroup self._channelgroup = ChannelGroup() self._channelgroup.InitFromDsfGroup(dsfgroup) if self._LocalRegression: self._channelgroup.InitializeInterpolator( running_regr_type=self._RegressionType, windowlength=self._RegressionWindow) else: self._channelgroup.InitializeInterpolator(windowlength=0) # channel group has been initialized, so evaluate the interpolator dsf = self._channelgroup(p['TargetParameter']) # Linear interpolation between the energies of the channels and the xvalues we require # NOTE: interpolator evaluates to zero for any of the xvals outside of the domain defined by self._xvalues intensities_interpolator = scipy.interpolate.interp1d(self._xvalues, p['Intensity'] * dsf.intensities, kind='linear') return intensities_interpolator(xvals) # can we pass by reference?
class DSFinterp(PythonAlgorithm): channelgroup = None def category(self): return "Transforms\\Smoothing" def name(self): return 'DSFinterp' def summary(self): return 'Given a set of parameter values {Ti} and corresponding structure factors S(Q,E,Ti), this algorithm '\ 'interpolates S(Q,E,T) for any value of parameter T within the range spanned by the {Ti} set.' def PyInit(self): arrvalidator = StringArrayMandatoryValidator() lrg='Input' self.declareProperty(StringArrayProperty('Workspaces', values=[], validator=arrvalidator,\ direction=Direction.Input), doc='list of input workspaces') self.declareProperty('LoadErrors', True, direction=Direction.Input,\ doc='Do we load error data contained in the workspaces?') self.declareProperty(FloatArrayProperty('ParameterValues', values=[],\ validator=FloatArrayMandatoryValidator(),direction=Direction.Input), doc='list of input parameter values') self.setPropertyGroup('Workspaces', lrg) self.setPropertyGroup('LoadErrors', lrg) self.setPropertyGroup('ParameterValues', lrg) self.declareProperty('LocalRegression', True, direction=Direction.Input, doc='Perform running local-regression?') condition = EnabledWhenProperty("LocalRegression", PropertyCriterion.IsDefault) self.declareProperty('RegressionWindow', 6, direction=Direction.Input, doc='window size for the running local-regression') self.setPropertySettings("RegressionWindow", condition) regtypes = [ 'linear', 'quadratic'] self.declareProperty('RegressionType', 'quadratic', StringListValidator(regtypes),\ direction=Direction.Input, doc='type of local-regression; linear and quadratic are available') self.setPropertySettings("RegressionType", condition) lrg = 'Running Local Regression Options' self.setPropertyGroup('LocalRegression', lrg) self.setPropertyGroup('RegressionWindow', lrg) self.setPropertyGroup('RegressionType', lrg) lrg='Output' self.declareProperty(FloatArrayProperty('TargetParameters', values=[], ), doc="Parameters to interpolate the structure factor") self.declareProperty(StringArrayProperty('OutputWorkspaces', values=[], validator=arrvalidator),\ doc='list of output workspaces to save the interpolated structure factors') self.setPropertyGroup('TargetParameters', lrg) self.setPropertyGroup('OutputWorkspaces', lrg) self.channelgroup = None def areWorkspacesCompatible(self, a, b): sizeA = a.blocksize() * a.getNumberHistograms() sizeB = b.blocksize() * b.getNumberHistograms() return sizeA == sizeB def PyExec(self): # Check congruence of workspaces workspaces = self.getProperty('Workspaces').value fvalues = self.getProperty('ParameterValues').value if len(workspaces) != len(fvalues): mesg = 'Number of Workspaces and ParameterValues should be the same' #logger.error(mesg) raise IndexError(mesg) for workspace in workspaces[1:]: if not self.areWorkspacesCompatible(mantid.mtd[workspaces[0]],mantid.mtd[workspace]): mesg = 'Workspace {0} incompatible with {1}'.format(workspace, workspaces[0]) logger.error(mesg) raise ValueError(mesg) # Load the workspaces into a group of dynamic structure factors from dsfinterp.dsf import Dsf from dsfinterp.dsfgroup import DsfGroup from dsfinterp.channelgroup import ChannelGroup dsfgroup = DsfGroup() for idsf in range(len(workspaces)): dsf = Dsf() dsf.Load( mantid.mtd[workspaces[idsf]] ) if not self.getProperty('LoadErrors').value: dsf.errors = None # do not incorporate error data dsf.SetFvalue( fvalues[idsf] ) dsfgroup.InsertDsf(dsf) # Create the intepolator if not instantiated before if not self.channelgroup: self.channelgroup = ChannelGroup() self.channelgroup.InitFromDsfGroup(dsfgroup) localregression = self.getProperty('LocalRegression').value if localregression: regressiontype = self.getProperty('RegressionType').value windowlength = self.getProperty('RegressionWindow').value self.channelgroup.InitializeInterpolator(running_regr_type=regressiontype, windowlength=windowlength) else: self.channelgroup.InitializeInterpolator(windowlength=0) # Invoke the interpolator and generate the output workspaces targetfvalues = self.getProperty('TargetParameters').value for targetfvalue in targetfvalues: if targetfvalue < min(fvalues) or targetfvalue > max(fvalues): mesg = 'Target parameters should lie in [{0}, {1}]'.format(min(fvalues),max(fvalues)) logger.error(mesg) raise ValueError(mesg) outworkspaces = self.getProperty('OutputWorkspaces').value if len(targetfvalues) != len(outworkspaces): mesg = 'Number of OutputWorkspaces and TargetParameters should be the same' logger.error(mesg) raise IndexError(mesg) for i in range(len(targetfvalues)): dsf = self.channelgroup( targetfvalues[i] ) outws = mantid.simpleapi.CloneWorkspace( mantid.mtd[workspaces[0]], OutputWorkspace=outworkspaces[i]) dsf.Save(outws) # overwrite dataY and dataE