def test_function_existing_function_can_be_unsubscribed(self): FunctionFactory.subscribe(TestFunctionCorrectForm) nfuncs_before = len(FunctionFactory.getFunctionNames()) FunctionFactory.unsubscribe("TestFunctionCorrectForm") available_functions = FunctionFactory.getFunctionNames() self.assertEquals(nfuncs_before - 1, len(available_functions)) self.assertTrue("TestFunctionCorrectForm" not in available_functions)
def test_function_subscription(self): nfuncs_orig = len(FunctionFactory.getFunctionNames()) FunctionFactory.subscribe(TestFunction) new_funcs = FunctionFactory.getFunctionNames() self.assertEquals(nfuncs_orig+1, len(new_funcs)) self.assertTrue("TestFunction" in new_funcs) FunctionFactory.unsubscribe("TestFunction") new_funcs = FunctionFactory.getFunctionNames() self.assertEquals(nfuncs_orig, len(new_funcs)) self.assertTrue("TestFunction" not in new_funcs)
# Get the trial values f_trial = self.function1D(xvals) # Now return to the orignial for i in range(self.numParams()): self.setParameter(i, c[i]) return f_trial # Construction the Jacobian (df) for the function def functionDeriv1D(self, xvals, jacobian, eps=1.e-3): f_int = self.function1D(xvals) # Fetch parameters into array c c = np.zeros(self.numParams()) for i in range(self.numParams()): c[i] = self.getParamValue(i) nc = np.prod(np.shape(c)) for k in range(nc): dc = np.zeros(nc) if k == 1 or k == 2: epsUse = 1.e-3 else: epsUse = eps dc[k] = max(epsUse, epsUse * c[k]) f_new = self.function1DDiffParams(xvals, c + dc) for i, dF in enumerate(f_new - f_int): jacobian.set(i, k, dF / dc[k]) FunctionFactory.subscribe(BivariateGaussian)
c = np.zeros(self.numParams()) for i in range(self.numParams()): c[i] = self.getParamValue(i) self.setParameter(i, trialc[i]) # Get the trial values f_trial = self.function1D(xvals) # Now return to the orignial for i in range(self.numParams()): self.setParameter(i, c[i]) return f_trial # Construction the Jacobian (df) for the function def functionDeriv1D(self, xvals, jacobian, eps=1.e-3): f_int = self.function1D(xvals) #Fetch parameters into array c c = np.zeros(self.numParams()) for i in range(self.numParams()): c[i] = self.getParamValue(i) nc = np.prod(np.shape(c)) for k in range(nc): dc = np.zeros(nc) dc[k] = max(eps,eps*c[k]) f_new = self.function1DDiffParams(xvals,c+dc) for i,dF in enumerate(f_new-f_int): jacobian.set(i,k,dF/dc[k]) FunctionFactory.subscribe(IkedaCarpenterConvoluted)
# NScD Oak Ridge National Laboratory, European Spallation Source # & Institut Laue - Langevin # SPDX - License - Identifier: GPL - 3.0 + # pylint: disable=invalid-name, anomalous-backslash-in-string, attribute-defined-outside-init from mantid.api import IFunction1D, FunctionFactory import numpy as np import scipy.special as sp class ModOsc(IFunction1D): def category(self): return "Muon\\MuonSpecific" def init(self): self.declareParameter("A0", 0.2) self.declareParameter("Freq", 1.0, 'Oscillation Frequency (MHz)') self.declareParameter("ModFreq", 0.1, 'Modulation Frequency (MHz)') self.declareParameter("Phi", 0.0, 'Phase') def function1D(self, x): A0 = self.getParameterValue("A0") Freq = self.getParameterValue("Freq") ModFreq = self.getParameterValue("ModFreq") phi = self.getParameterValue("Phi") return A0 * np.cos(2 * np.pi * Freq * x + phi) * sp.j0(2 * np.pi * ModFreq * x + phi) FunctionFactory.subscribe(ModOsc)
------- numpy.ndarray Function values """ zs = self.getParameterValue('R') * np.asarray(xvals) return self.getParameterValue('A') * np.square(3 * self.vecbessel(zs)) def functionDeriv1D(self, xvals, jacobian): r"""Calculate the partial derivatives Parameters ---------- xvals : sequence of floats The domain where to evaluate the function jacobian: 2D array partial derivatives of the function with respect to the fitting parameters, evaluated at the domain. """ amplitude = self.getParameterValue('A') radius = self.getParameterValue('R') i = 0 for x in xvals: z = radius * x j = j1(z)/z jacobian.set(i, 0, np.square(3 * j)) jacobian.set(i,1, amplitude * 2 * 9 * j * (j1d(z) - j) / radius) i += 1 # Required to have Mantid recognise the new function FunctionFactory.subscribe(EISFDiffSphere)
def test_instance_can_be_created_from_factory(self): FunctionFactory.subscribe(Times2) func_name = Times2.__name__ func = FunctionFactory.createFunction(func_name) self.assertTrue(isinstance(func, IFunction1D)) FunctionFactory.unsubscribe(func_name)
N = int(emax / de) dt = (float(N) / (2 * N + 1)) * (self._h / emax) # extent to negative times and t==0 sampled_times = dt * np.arange(-N, N + 1) # len( sampled_times ) < 64000 exponent = -(np.abs(sampled_times) / p["tau"]) ** p["beta"] freqs = de * np.arange(-N, N + 1) fourier = p["height"] * np.abs(scipy.fftpack.fft(np.exp(exponent)).real) fourier = np.concatenate((fourier[N + 1 :], fourier[0 : N + 1])) interpolator = scipy.interpolate.interp1d(freqs, fourier) fourier = interpolator(xvals - p["Origin"]) return fourier def functionDeriv1D(self, xvals, jacobian): """Numerical derivative""" p = self.validateParams() f0 = self.function1D(xvals) dp = {} for (key, val) in p.items(): dp[key] = 0.1 * val # modify by ten percent if val == 0.0: dp[key] = 1e-06 # some small, supposedly, increment for name in self._parmset: pp = copy.copy(p) pp[name] += dp[name] df = (self.function1D(xvals, **pp) - f0) / dp[name] ip = self._parm2index[name] for ix in range(len(xvals)): jacobian.set(ix, ip, df[ix]) FunctionFactory.subscribe(StretchedExpFT) # Required to have Mantid recognise the new function
height = self.getParameterValue("Height") msd = self.getParameterValue("MSD") sigma = self.getParameterValue("Sigma") xvals = np.array(xvals) i1 = np.exp(-1.0 / (6.0 * xvals**2 * msd)) i2 = 1.0 + (np.power(xvals, 4) * sigma / 72.0) intensity = height * i1 * i2 return intensity def functionDeriv1D(self, xvals, jacobian): height = self.getParameterValue("Height") msd = self.getParameterValue("MSD") sigma = self.getParameterValue("Sigma") for i, x in enumerate(xvals): q = msd * x**2 f1 = math.exp(-1.0 / (6.0 * q)) df1 = f1 / (6.0 * x * q) x4 = math.pow(x, 4) f2 = 1.0 + (x4 * sigma / 72.0) df2 = x4 / 72.0 jacobian.set(i, 0, f1 * f2) jacobian.set(i, 1, height * df1 * f2) jacobian.set(i, 2, height * f1 * df2) # Required to have Mantid recognise the new function FunctionFactory.subscribe(MsdYi)
xvals = np.array(xvals) i1 = 1.0 + (msd * xvals**2 / (6.0 * beta)) i2 = np.power(i1, beta) intensity = height / i2 return intensity def functionDeriv1D(self, xvals, jacobian): height = self.getParameterValue("Height") msd = self.getParameterValue("Msd") beta = self.getParameterValue("Beta") for i, x in enumerate(xvals): x_sq = x**2 q = msd * x_sq q6 = q / 6 a1 = 1.0 + q6 / beta a = 1.0 / math.pow(a1, beta) b1 = q6 * x / beta + 1 b = -(x_sq / 6) * math.pow(b1, (-beta - 1)) cqx = q6 + beta c1 = math.pow((cqx / beta), -beta) c2 = q6 - cqx * math.log(cqx / beta) c = c1 * c2 / cqx jacobian.set(i, 0, a) jacobian.set(i, 1, b * height) jacobian.set(i, 2, c * height) # Required to have Mantid recognise the new function FunctionFactory.subscribe(MsdPeters)
import numpy as np from scipy.special import kn from mantid.api import IFunction1D, FunctionFactory import numpy as np class DiluteSpheres(IFunction1D): def category(self): return "SESANS" def init(self): self.declareParameter("Radius", 1.0) self.declareParameter("Const", 0.003) def function1D(self, x): R = self.getParameterValue("Radius") C = self.getParameterValue("Const") z = np.array(x/R, dtype=np.complex128) first = np.sqrt(1-(z/2)**2)*(1+1/8.0*z**2) second = 0.5*z**2*(1-(z/4)**2)*np.log(z/(2+np.sqrt(4-z**2))) return C*np.array(np.real(first+second-1), dtype=np.float64) FunctionFactory.subscribe(DiluteSpheres)
#Get the trial values f_trial = self.function1D(xvals) #Now return to the orignial for i in range(self.numParams()): self.setParameter(i, c[i]) return f_trial # Construction the Jacobian (df) for the function def functionDeriv1D(self, xvals, jacobian, eps=1.e-3): f_int = self.function1D(xvals) #Fetch parameters into array c c = np.zeros(self.numParams()) for i in range(self.numParams()): c[i] = self.getParamValue(i) nc = np.prod(np.shape(c)) for k in range(nc): dc = np.zeros(nc) if k == 1 or k == 2: epsUse = 1.e-3 else: epsUse = eps dc[k] = max(epsUse,epsUse*c[k]) f_new = self.function1DDiffParams(xvals,c+dc) for i,dF in enumerate(f_new-f_int): jacobian.set(i,k,dF/dc[k]) FunctionFactory.subscribe(BivariateGaussian)
Parameters ---------- xvals : sequence of floats The domain where to evaluate the function jacobian: 2D array partial derivative of the function with respect to the fitting parameters evaluated at the domain. Returns ------- numpy.ndarray Function values """ radius = self.getParameterValue('R') length = self.getParameterValue('L') x = np.asarray(xvals) # Q values z = length * np.outer(x, self.cos_theta) # EISF along cylinder Z-axis a = np.square(np.where(z < 1e-9, 1 - z * z / 6, np.sin(z) / z)) z = radius * np.outer(x, self.sin_theta) # EISF on cylinder cross-section (diffusion on a disc) b = np.square(np.where(z < 1e-6, 1 - z * z / 10, 3 * (np.sin(z) - z * np.cos(z)) / (z * z * z))) # integrate in theta eisf = self.d_theta * np.sum(self.sin_theta * a * b, axis=1) return self.getParameterValue('A') * eisf # Required to have Mantid recognise the new function FunctionFactory.subscribe(EISFDiffCylinder)
return "QuasiElastic" def init(self): # Active fitting parameters self.declareParameter("Tau", 1.0, 'Residence time') self.declareParameter("L", 0.2, 'Jump length') def function1D(self, xvals): tau = self.getParameterValue("Tau") l = self.getParameterValue("L") xvals = np.array(xvals) hwhm = (1.0 - np.exp( -l * xvals * xvals )) / tau return hwhm def functionDeriv1D(self, xvals, jacobian): tau = self.getParameterValue("Tau") l = self.getParameterValue("L") i = 0 for x in xvals: ex = math.exp(-l*x*x) h = (1.0-ex)/tau jacobian.set(i,0,-h/tau); jacobian.set(i,1,x*x*ex/tau); i += 1 # Required to have Mantid recognise the new function FunctionFactory.subscribe(SingwiSjolander)
def test_category_with_no_override_returns_default_category(self): FunctionFactory.subscribe(NoCatgeoryFunction) func = FunctionFactory.createFunction("NoCatgeoryFunction") self.assertEquals("General", func.category()) FunctionFactory.unsubscribe("NoCatgeoryFunction")
boundaries = (xvals[1:] + xvals[:-1]) / 2 # internal bin boundaries boundaries = np.insert(boundaries, 0, 2 * xvals[0] - boundaries[0]) # external lower boundary boundaries = np.append(boundaries, 2 * xvals[-1] - boundaries[-1]) # external upper boundary primitive = np.cumsum(fourier) * (denergies / (rf * de)) # running Riemann sum transform = np.interp(boundaries[1:] - parms['Centre'], energies, primitive) - \ np.interp(boundaries[:-1] - parms['Centre'], energies, primitive) return transform * parms['Height'] @surrogate def fillJacobian(self, xvals, jacobian, partials): """Fill the jacobian object with the dictionary of partial derivatives :param xvals: domain where the derivatives are to be calculated :param jacobian: jacobian object :param partials: dictionary with partial derivates with respect to the fitting parameters """ pass @surrogate def functionDeriv1D(self, xvals, jacobian): """Numerical derivative except for Height parameter""" # partial derivatives with respect to the fitting parameters pass # Required to have Mantid recognise the new function FunctionFactory.subscribe(PrimStretchedExpFT)
def test_category_override_returns_overridden_result(self): FunctionFactory.subscribe(Times2) func = FunctionFactory.createFunction("Times2") self.assertEquals("SimpleFunction", func.category()) FunctionFactory.unsubscribe("Times2")
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? # Required to have Mantid recognize the new function #pylint: disable=unused-import try: import dsfinterp FunctionFactory.subscribe(DSFinterp1DFit) except ImportError: logger.debug('Failed to subscribe fit function DSFinterp1DFit. '+\ 'Python package dsfinterp may be missing (https://pypi.python.org/pypi/dsfinterp)')
def category(self): return "SANS" def init(self): # Active fitting parameters self.declareParameter("Scale", 1.0, 'Scale') self.declareParameter("Rg", 60.0, 'Radius of gyration') def function1D(self, xvals): """ Evaluate the model @param xvals: numpy array of q-values """ return self.getParameterValue("Scale") * np.exp(-(self.getParameterValue('Rg')*xvals)**2/3.0 ) def functionDeriv1D(self, xvals, jacobian): """ Evaluate the first derivatives @param xvals: numpy array of q-values @param jacobian: Jacobian object """ i = 0 rg = self.getParameterValue('Rg') for x in xvals: jacobian.set(i,0, math.exp(-(rg*x)**2/3.0 ) ) jacobian.set(i,1, -self.getParameterValue("Scale") * math.exp(-(rg*x)**2/3.0 )*2.0/3.0*rg*x*x ) i += 1 # Required to have Mantid recognise the new function FunctionFactory.subscribe(Guinier)
def category(self): return "QuasiElastic" def init(self): # Active fitting parameters self.declareParameter("Height", 1.0, 'Height') self.declareParameter("MSD", 0.05, 'Mean square displacement') def function1D(self, xvals): height = self.getParameterValue("Height") msd = self.getParameterValue("MSD") xvals = np.array(xvals) intensity = height * np.exp(-msd * xvals**2) return intensity def functionDeriv1D(self, xvals, jacobian): height = self.getParameterValue("Height") msd = self.getParameterValue("MSD") for i, x in enumerate(xvals): e = math.exp(-msd * x**2) jacobian.set(i, 0, e) jacobian.set(i, 1, -(x**2) * e * height) i += 1 # Required to have Mantid recognise the new function FunctionFactory.subscribe(MsdGauss)
class ZFelectronDipole(IFunction1D): def category(self): return "Muon\\MuonSpecific" def init(self): self.declareParameter("A0", 0.2) self.declareParameter("Radius", 10, 'Radius (Angstrom)') self.declareParameter("LambdaTrans", 0.2, 'Lambda-Trans (MHz)') self.addConstraints("Radius > 0") self.addConstraints("LambdaTrans > 0") def function1D(self, x): A0 = self.getParameterValue("A0") radius = self.getParameterValue("Radius") LambdaTrans = self.getParameterValue("LambdaTrans") gmu = 2 * np.pi * 0.01355342 if radius > 0: B = 8290 / (radius**3) else: B = 0 Omega = gmu * B return A0 * (1. / 6) * (1 + np.exp(-LambdaTrans * x) * (np.cos(Omega * x) + 2 * np.cos(1.5 * Omega * x) + 2 * np.cos(0.5 * Omega * x))) FunctionFactory.subscribe(ZFelectronDipole)
return "Muon\\MuonSpecific" def init(self): self.declareParameter("A0", 0.2, 'Asymmetry') self.declareParameter( "Width", 0.1, 'Half-width half maximum of the local field Lorentzian Distribution' ) self.declareParameter("Nu", 1, 'Rate of Markovian modulation') self.declareParameter("Q", 0.1, 'Order Parameter') self.addConstraints("Nu > 0") self.addConstraints("0 < Q < 1") def function1D(self, x): A0 = self.getParameterValue("A0") a = self.getParameterValue("Width") nu = self.getParameterValue("Nu") q = self.getParameterValue("Q") x = x[1:np.size(x)] term1 = 4 * (a**2) * (1 - q) * x / nu term2 = q * (a**2) * (x**2) term13 = np.exp(-np.sqrt(term1)) term23 = (1 - (term2 / np.sqrt(term1 + term2))) * \ np.exp(- np.sqrt(term1 + term2)) SpinGlass = A0 * ((1. / 3.) * term13 + (2. / 3.) * term23) SpinGlass = np.insert(SpinGlass, 0, A0) return SpinGlass FunctionFactory.subscribe(SpinGlass)
# Mantid Repository : https://github.com/mantidproject/mantid # # Copyright © 2019 ISIS Rutherford Appleton Laboratory UKRI, # NScD Oak Ridge National Laboratory, European Spallation Source # & Institut Laue - Langevin # SPDX - License - Identifier: GPL - 3.0 + # pylint: disable=invalid-name, anomalous-backslash-in-string, attribute-defined-outside-init from mantid.api import IFunction1D, FunctionFactory class Redfield(IFunction1D): def category(self): return "Muon\\MuonModelling" def init(self): self.declareParameter("A0", 1) self.declareParameter("Hloc", 0.1, "Local magnetic field (G)") self.declareParameter("Tau", 0.1, "Correlation time of muon spins (microsec)") def function1D(self, x): A0 = self.getParameterValue("A0") Hloc = self.getParameterValue("Hloc") tau = self.getParameterValue("Tau") gmu = 0.01355342 return A0 * 2 * (gmu * Hloc)**2 * tau / (1 + (gmu * x * tau)**2) FunctionFactory.subscribe(Redfield)
class FmuF(IFunction1D): def category(self): return "Muon\\MuonSpecific" def init(self): self.declareParameter("A0", 0.5, 'Amplitude') self.declareParameter("FreqD", 0.2, 'Dipolar interaction frequency (MHz)') self.declareParameter("Lambda", 0.1, 'Exponential decay rate') self.declareParameter("Sigma", 0.2, 'Gaussian decay rate') def function1D(self, x): A0 = self.getParameterValue("A0") FreqD = self.getParameterValue("FreqD") Lambda = self.getParameterValue("Lambda") Sigma = self.getParameterValue("Sigma") OmegaD = FreqD * 2 * np.pi Gauss = np.exp(-(Sigma * x)**2 / 2) Lor = np.exp(-Lambda * x) term1 = np.cos(np.sqrt(3) * OmegaD * x) term2 = (1 - 1 / np.sqrt(3)) * \ np.cos(0.5 * (3 - np.sqrt(3)) * OmegaD * x) term3 = (1 + 1 / np.sqrt(3)) * \ np.cos(0.5 * (3 + np.sqrt(3)) * OmegaD * x) G = (3 + term1 + term2 + term3) / 6 return A0 * Gauss * Lor * G FunctionFactory.subscribe(FmuF)
import numpy as np from scipy.special import kn from mantid.api import IFunction1D, FunctionFactory import numpy as np class BesselFunction(IFunction1D): def category(self): return "SESANS" def init(self): self.declareParameter("length_scale", 0.2) self.declareParameter("Const", 1) def function1D(self, x): c = self.getParameterValue("length_scale") C = self.getParameterValue("Const") kappa = c*x**2 return C*kappa*kn(1, kappa) FunctionFactory.subscribe(BesselFunction)
# SPDX - License - Identifier: GPL - 3.0 + # pylint: disable=invalid-name, anomalous-backslash-in-string, attribute-defined-outside-init from mantid.api import IFunction1D, FunctionFactory import numpy as np class GauBroadGauKT(IFunction1D): def category(self): return "Muon\\MuonSpecific" def init(self): self.declareParameter("A0", 0.2) self.declareParameter("R", 0.1, 'Broadening ratio') self.declareParameter("Delta0", 0.1, 'Central Field width') self.addConstraints("Delta0 >= 0") def function1D(self, x): A0 = self.getParameterValue("A0") R = self.getParameterValue("R") Delta = self.getParameterValue("Delta0") omega = R * Delta DeltaEff = np.sqrt(Delta**2 + omega**2) denom = 1 + R**2 + R**2 * DeltaEff**2 * x**2 term1 = (DeltaEff * x)**2 / denom return A0 * (1. / 3. + 2. / 3. * ((1 + R**2) / denom)**1.5 * (1 - term1) * np.exp(-term1 / 2)) FunctionFactory.subscribe(GauBroadGauKT)
return "QuasiElastic" def init(self): # Active fitting parameters self.declareParameter("Tau", 1.0, 'Residence time') self.declareParameter("L", 1.5, 'Jump length') def function1D(self, xvals): tau = self.getParameterValue("Tau") length = self.getParameterValue("L") xvals = np.array(xvals) with np.errstate(divide='ignore'): hwhm = self.hbar*(1.0 - np.sin(xvals * length) / (xvals * length))/tau return hwhm def functionDeriv1D(self, xvals, jacobian): tau = self.getParameterValue("Tau") length = self.getParameterValue("L") for i, x in enumerate(xvals, start=0): s = 1.0 - np.sinc(x*length/np.pi) hwhm = self.hbar*s/tau jacobian.set(i, 0, -hwhm/tau) jacobian.set(i, 1, (math.cos(x*length)-s)/(length*tau)) # Required to have Mantid recognise the new function FunctionFactory.subscribe(ChudleyElliot)
Nmax = 16000 # increase short-times resolution, increase the resolution of the structure factor tail while ( emax / de ) < Nmax: emax = 2 * emax N = int( emax / de ) dt = ( float(N) / ( 2 * N + 1 ) ) * (self._h / emax) # extent to negative times and t==0 sampled_times = dt * np.arange(-N, N+1) # len( sampled_times ) < 64000 exponent = -(np.abs(sampled_times)/p['tau'])**p['beta'] freqs = de * np.arange(-N, N+1) fourier = p['height']*np.abs( scipy.fftpack.fft( np.exp(exponent) ).real ) fourier = np.concatenate( (fourier[N+1:],fourier[0:N+1]) ) interpolator = scipy.interpolate.interp1d(freqs, fourier) fourier = interpolator(xvals) return fourier def functionDeriv1D(self, xvals, jacobian): '''Numerical derivative''' p = self.validateParams() f0 = self.function1D(xvals) dp = {} for (key,val) in p.items(): dp[key] = 0.1 * val #modify by ten percent for name in self._parmset: pp = copy.copy(p) pp[name] += dp[name] df = (self.function1D(xvals, **pp) - f0) / dp[name] ip = self._parm2index[name] for ix in range(len(xvals)): jacobian.set(ix, ip, df[ix]) # Required to have Mantid recognise the new function FunctionFactory.subscribe(StretchedExpFT)
N = int(emax / de) dt = (float(N) / (2 * N + 1)) * (self._h / emax) # extent to negative times and t==0 sampled_times = dt * np.arange(-N, N + 1) # len( sampled_times ) < 64000 exponent = -(np.abs(sampled_times) / p['tau']) ** p['beta'] freqs = de * np.arange(-N, N + 1) fourier = p['height'] * np.abs(scipy.fftpack.fft(np.exp(exponent)).real) fourier = np.concatenate((fourier[N + 1:], fourier[0:N + 1])) interpolator = scipy.interpolate.interp1d(freqs, fourier) fourier = interpolator(xvals - p['Origin']) return fourier def functionDeriv1D(self, xvals, jacobian): """Numerical derivative""" p = self.validateParams() f0 = self.function1D(xvals) dp = {} for (key, val) in p.items(): dp[key] = 0.1 * val # modify by ten percent if val == 0.0: dp[key] = 1E-06 # some small, supposedly, increment for name in self._parmset: pp = copy.copy(p) pp[name] += dp[name] df = (self.function1D(xvals, **pp) - f0) / dp[name] ip = self._parm2index[name] for ix in range(len(xvals)): jacobian.set(ix, ip, df[ix]) FunctionFactory.subscribe(StretchedExpFT) # Required to have Mantid recognise the new function
c = np.zeros(self.numParams()) for i in range(self.numParams()): c[i] = self.getParamValue(i) self.setParameter(i, trialc[i]) # Get the trial values f_trial = self.function1D(xvals) # Now return to the orignial for i in range(self.numParams()): self.setParameter(i, c[i]) return f_trial # Construction the Jacobian (df) for the function def functionDeriv1D(self, xvals, jacobian, eps=1.e-3): f_int = self.function1D(xvals) # Fetch parameters into array c c = np.zeros(self.numParams()) for i in range(self.numParams()): c[i] = self.getParamValue(i) nc = np.prod(np.shape(c)) for k in range(nc): dc = np.zeros(nc) dc[k] = max(eps, eps*c[k]) f_new = self.function1DDiffParams(xvals, c+dc) for i, dF in enumerate(f_new-f_int): jacobian.set(i, k, dF/dc[k]) FunctionFactory.subscribe(IkedaCarpenterConvoluted)
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? # Required to have Mantid recognize the new function #pylint: disable=unused-import try: import dsfinterp # noqa FunctionFactory.subscribe(DSFinterp1DFit) except ImportError: logger.debug( 'Failed to subscribe fit function DSFinterp1DFit. ' + 'Python package dsfinterp may be missing (https://pypi.python.org/pypi/dsfinterp)' )
def init(self): # Active fitting parameters self.declareParameter("Scale", 1.0, 'Scale') self.declareParameter("Length", 50.0, 'Length') self.declareParameter("Background", 0.0, 'Background') def function1D(self, xvals): """ Evaluate the model @param xvals: numpy array of q-values """ return self.getParameterValue("Scale") / (1.0 + np.power(xvals*self.getParameterValue('Length'), 2)) + self.getParameterValue('Background') def functionDeriv1D(self, xvals, jacobian): """ Evaluate the first derivatives @param xvals: numpy array of q-values @param jacobian: Jacobian object """ i = 0 for x in xvals: jacobian.set(i,0, 1.0 / (1.0 + np.power(x*self.getParameterValue('Length'), 2))) denom = math.pow(1.0 + math.pow(x*self.getParameterValue('Length'), 2), -2) jacobian.set(i,1, -2.0 * self.getParameterValue("Scale") * x * x * self.getParameterValue('Length') * denom) jacobian.set(i,2, 1.0) i += 1 # Required to have Mantid recognise the new function FunctionFactory.subscribe(Lorentz)
# SPDX - License - Identifier: GPL - 3.0 + # pylint: disable=invalid-name, anomalous-backslash-in-string, attribute-defined-outside-init from mantid.api import IFunction1D, FunctionFactory import numpy as np class PCRmagnetZFKT(IFunction1D): def category(self): return "Muon\\MuonSpecific" def init(self): self.declareParameter("A0", 0.2) self.declareParameter("Delta", 0.1) self.declareParameter("H0", 10) self.declareParameter("Toff", 0.1) def function1D(self, x): A0 = self.getParameterValue("A0") delta = self.getParameterValue("Delta") H0 = self.getParameterValue("H0") Toff = self.getParameterValue("Toff") gmu = 2 * np.pi * 0.01355342 w = H0 * gmu x = x - Toff return A0 * (1. / 3 + 2. / 3 * np.exp(-(delta * x)**2 / 2) * (np.cos(w * x) - (delta)**2 * x / w * np.sin(w * x))) FunctionFactory.subscribe(PCRmagnetZFKT)
return "SANS" def init(self): # Active fitting parameters self.declareParameter("Scale", 1.0, 'Scale') self.declareParameter("Background", 0.0, 'Background') def function1D(self, xvals): """ Evaluate the model @param xvals: numpy array of q-values """ return self.getParameterValue("Scale") * np.power( xvals, -4) + self.getParameterValue('Background') def functionDeriv1D(self, xvals, jacobian): """ Evaluate the first derivatives @param xvals: numpy array of q-values @param jacobian: Jacobian object """ i = 0 for x in xvals: jacobian.set(i, 0, math.pow(x, -4)) jacobian.set(i, 1, 1.0) i += 1 # Required to have Mantid recognise the new function FunctionFactory.subscribe(Porod)
# pylint: disable=invalid-name, anomalous-backslash-in-string, attribute-defined-outside-init from mantid.api import IFunction1D, FunctionFactory import numpy as np class RFresonance(IFunction1D): def category(self): return "Muon\\MuonSpecific" def init(self): self.declareParameter("A0", 0.2) self.declareParameter("Boffset", 10, 'Relaxation rate (G)') self.declareParameter("B1", 10, 'Fluctuation (G)') self.declareParameter("B1GauWidth", 0.2, 'Width of resonance (MHz)') def function1D(self, x): A0 = self.getParameterValue("A0") Bcentre = self.getParameterValue("Boffset") B = self.getParameterValue("B1") width = self.getParameterValue("B1GauWidth") gmu = 0.0135538817 * 2 * np.pi Beff = np.sqrt(Bcentre**2 + B**2) RelAmp = (B / Beff)**2 return A0 * ( 1 + (np.cos(Beff * gmu * x) * np.exp(-(width * x)**2) - 1) * RelAmp) FunctionFactory.subscribe(RFresonance)
along with this program. If not, see <http://www.gnu.org/licenses/>. File change history is stored at: <https://github.com/mantidproject/mantid> Code Documentation is available at: <http://doxygen.mantidproject.org> ''' from __future__ import (absolute_import, division, print_function) from mantid.api import IFunction1D, FunctionFactory class FickDiffusion(IFunction1D): def category(self): return "QuasiElastic" def init(self): # Active fitting parameters self.declareParameter("D", 1.0, 'Diffusion constant') def function1D(self, xvals): return self.getParameterValue("D")*xvals*xvals def functionDeriv1D(self, xvals, jacobian): i = 0 for x in xvals: jacobian.set(i,0,2.0*x) i += 1 # Required to have Mantid recognise the new function FunctionFactory.subscribe(FickDiffusion)
# Active fitting parameters self.declareParameter("Tau", 1.0, 'Residence time') self.declareParameter("L", 0.2, 'Jump length') def function1D(self, xvals): tau = self.getParameterValue("Tau") l = self.getParameterValue("L") l = l**2 / 2 xvals = np.array(xvals) hwhm = (1.0 - np.exp( -l * xvals * xvals )) / tau return hwhm def functionDeriv1D(self, xvals, jacobian): tau = self.getParameterValue("Tau") l = self.getParameterValue("L") l = l**2 / 2 i = 0 for x in xvals: ex = math.exp(-l*x*x) h = (1.0-ex)/tau jacobian.set(i,0,-h/tau) jacobian.set(i,1,x*x*ex/tau) i += 1 # Required to have Mantid recognise the new function FunctionFactory.subscribe(HallRoss)
def fwhm(self): """ Return what should be considered the 'fwhm' of this function. """ return 2.0*math.sqrt(2.0*math.log(2.0))*self.getParameterValue("Sigma") def setCentre(self, new_centre): """ Called by an external entity, probably a GUI, in response to a mouse click that gives a guess at the centre. """ self.setParameter("PeakCentre",new_centre) def setHeight(self, new_height): """ Called by an external entity, probably a GUI, in response to a user guessing the height. """ self.setParameter("Height", new_height) def setFwhm(self, new_fwhm): """ Called by an external entity, probably a GUI, in response to a user guessing the height. """ sigma = new_fwhm/(2.0*math.sqrt(2.0*math.log(2.0))) self.setParameter("Sigma",sigma) # Required to have Mantid recognise the new function FunctionFactory.subscribe(ExamplePeakFunction)
""" def category(self): return "SANS" def init(self): # Active fitting parameters self.declareParameter("Scale", 1.0, 'Scale') self.declareParameter("Background", 0.0, 'Background') def function1D(self, xvals): """ Evaluate the model @param xvals: numpy array of q-values """ return self.getParameterValue("Scale") * np.power(xvals, -4) + self.getParameterValue('Background') def functionDeriv1D(self, xvals, jacobian): """ Evaluate the first derivatives @param xvals: numpy array of q-values @param jacobian: Jacobian object """ i = 0 for x in xvals: jacobian.set(i,0, math.pow(x, -4)) jacobian.set(i,1, 1.0) i += 1 # Required to have Mantid recognise the new function FunctionFactory.subscribe(Porod)
# SPDX - License - Identifier: GPL - 3.0 + # pylint: disable=invalid-name, anomalous-backslash-in-string, attribute-defined-outside-init from mantid.api import IFunction1D, FunctionFactory import numpy as np class PCRmagRedfield(IFunction1D): def category(self): return "Muon\\MuonSpecific" def init(self): self.declareParameter("A0", 0.2, 'Amplitude') self.declareParameter("Delta", 0.2) self.declareParameter("Nu", 0.2) def function1D(self, x): A0 = self.getParameterValue("A0") Delta = self.getParameterValue("Delta") Nu = self.getParameterValue("Nu") W = 2 * np.pi * Delta Q = (Nu**2 + Delta**2) * Nu if Q > 0: Lambda = Delta**4 / Q else: Lambda = 0 return A0 * (1. / 3 + 2. / 3 * np.exp(-Lambda * x) * np.cos(W * x)) FunctionFactory.subscribe(PCRmagRedfield)
def init(self): # Active fitting parameters self.declareParameter("Tau", 1.0, 'Residence time') self.declareParameter("L", 1.5, 'Jump length') def function1D(self, xvals): tau = self.getParameterValue("Tau") length = self.getParameterValue("L") length = length**2 xvals = np.array(xvals) hwhm = xvals * xvals * length / (tau * (1 + xvals * xvals * length)) return hwhm def functionDeriv1D(self, xvals, jacobian): tau = self.getParameterValue("Tau") length = self.getParameterValue("L") length = length**2 i = 0 for x in xvals: h = x*x*length/(tau*(1+x*x*length)) jacobian.set(i,0,-h/tau) jacobian.set(i,1,h*(1.0-h*tau)/length) i += 1 # Required to have Mantid recognise the new function FunctionFactory.subscribe(TeixeiraWater)
# pylint: disable=invalid-name, anomalous-backslash-in-string, attribute-defined-outside-init from mantid.api import IFunction1D, FunctionFactory import numpy as np class MuMinusExpTF(IFunction1D): def category(self): return "Muon\\MuonSpecific" def init(self): self.declareParameter("A", 1) self.declareParameter("Lambda", 0.1, 'Decay rate of oscillating term') self.declareParameter("N0", 1) self.declareParameter("Tau", 5.0) self.declareParameter("Phi", 0.3, 'Phase') self.declareParameter("Nu", 0.2, 'Oscillating frequency (MHz)') def function1D(self, x): A = self.getParameterValue("A") Lambda = self.getParameterValue("Lambda") N0 = self.getParameterValue("N0") tau = self.getParameterValue("Tau") phi = self.getParameterValue("Phi") nu = self.getParameterValue("Nu") return N0 * np.exp(-x / tau) * ( 1 + A * np.exp(-Lambda * x) * np.cos(2 * np.pi * nu * x + phi)) FunctionFactory.subscribe(MuMinusExpTF)
self.declareParameter("A0", 0.2, 'Amplitude') self.declareParameter("Freq", 2, 'ZF Frequency (MHz)') self.declareParameter( "Angle", 50, 'Angle of internal field w.r.t. to applied field (degrees)') self.declareParameter("Field", 10, 'Applied Field (G)') self.declareParameter("Phi", 0.0, 'Phase (rad)') def function1D(self, x): A0 = self.getParameterValue("A0") Freq = self.getParameterValue("Freq") theta = self.getParameterValue("Angle") B = self.getParameterValue("Field") phi = self.getParameterValue("Phi") FreqInt = Freq FreqExt = 0.01355 * B theta = np.pi / 180 * theta omega1 = 2 * np.pi * \ np.sqrt(FreqInt ** 2 + FreqExt ** 2 + 2 * FreqInt * FreqExt * np.cos(theta)) omega2 = 2 * np.pi * \ np.sqrt(FreqInt ** 2 + FreqExt ** 2 - 2 * FreqInt * FreqExt * np.cos(theta)) a1 = (FreqInt * np.sin(theta)) ** 2 / ((FreqExt + FreqInt * np.cos(theta)) ** 2 + (FreqInt * np.sin(theta)) ** 2) a2 = (FreqInt * np.sin(theta)) ** 2 / ((FreqExt - FreqInt * np.cos(theta)) ** 2 + (FreqInt * np.sin(theta)) ** 2) return A0 * ((1 - a1) + a1 * np.cos(omega1 * x + phi) + (1 - a2) + a2 * np.cos(omega2 * x + phi)) / 2 FunctionFactory.subscribe(AFMLF)
def test_function_with_expected_attrs_subscribes_successfully(self): nfuncs_orig = len(FunctionFactory.getFunctionNames()) FunctionFactory.subscribe(TestFunctionCorrectForm) new_funcs = FunctionFactory.getFunctionNames() self.assertEquals(nfuncs_orig + 1, len(new_funcs)) self.assertTrue("TestFunctionCorrectForm" in new_funcs)
""" Evaluate the model @param xvals: numpy array of q-values """ # parameters scale = self.getParameterValue('Scale') bgd = self.getParameterValue('Background') output = np.zeros(len(xvals), dtype=float) for i in range(len(xvals)): output[i] = scale * self._guinier_porod_core(xvals[i]) + bgd return output def functionDeriv1D(self, xvals, jacobian): """ Evaluate the first derivatives @param xvals: numpy array of q-values @param jacobian: Jacobian object """ i = 0 for x in xvals: jacobian.set(i,0, self._guinier_porod_core(x)) jacobian.set(i,1, self._first_derivative_dim(x)) jacobian.set(i,2, self._first_derivative_rg(x)) jacobian.set(i,3, self._first_derivative_m(x)) jacobian.set(i,4, 1.0) i += 1 # Required to have Mantid recognise the new function FunctionFactory.subscribe(GuinierPorod)
# pylint: disable=invalid-name, anomalous-backslash-in-string, attribute-defined-outside-init from mantid.api import IFunction1D, FunctionFactory import numpy as np class ZFdipole(IFunction1D): def category(self): return "Muon\\MuonSpecific" def init(self): self.declareParameter("A0", 0.2) self.declareParameter("BDip", 10) self.declareParameter("LambdaTrans", 0.2, 'Lambda-Trans (MHz)') self.addConstraints("BDip > 0") self.addConstraints("LambdaTrans > 0") def function1D(self, x): A0 = self.getParameterValue("A0") BDip = self.getParameterValue("BDip") LambdaTrans = self.getParameterValue("LambdaTrans") gmu = 2 * np.pi * 0.01355342 Omega = gmu * BDip return A0 * (1. / 6) * (1 + np.exp(-LambdaTrans * x) * (np.cos(Omega * x) + 2 * np.cos(1.5 * Omega * x) + 2 * np.cos(0.5 * Omega * x))) FunctionFactory.subscribe(ZFdipole)
from mantid.api import IFunction1D, FunctionFactory import numpy as np class MuH(IFunction1D): def category(self): return "Muon\\MuonSpecific" def init(self): self.declareParameter("A0", 0.5, 'Amplitude') self.declareParameter("NuD", 0.5, 'Oscillating Frequency (MHz)') self.declareParameter("Lambda", 0.3, 'Exponential decay rate') self.declareParameter("Sigma", 0.05, 'Gaussian decay rate') self.declareParameter("Phi", 0.0, 'Phase (rad)') def function1D(self, x): A0 = self.getParameterValue("A0") NuD = self.getParameterValue("NuD") Lambda = self.getParameterValue("Lambda") sigma = self.getParameterValue("Sigma") phi = self.getParameterValue("Phi") OmegaD = NuD * 2 * np.pi gau = np.exp(-0.5 * (x * sigma)**2) Lor = np.exp(-Lambda * x) return A0 * gau * Lor * (1 + np.cos(OmegaD * x + phi) + 2 * np.cos(0.5 * OmegaD * x + phi) + 2 * np.cos(1.5 * OmegaD * x + phi)) / 6 FunctionFactory.subscribe(MuH)
See ExamplePeakFunction for more on attributes """ # Active fitting parameters self.declareParameter("A0") self.declareParameter("A1") def function1D(self, xvals): """ Computes the function on the set of values given and returns the answer as a numpy array of floats """ return self.getParameterValue("A0") + self.getParameterValue("A1")*xvals def functionDeriv1D(self, xvals, jacobian): """ Computes the partial derivatives of the function on the set of values given and the sets these values in the given jacobian. The Jacobian is essentially a matrix where jacobian.set(iy,ip,value) takes 3 parameters: iy = The index of the data value whose partial derivative this corresponds to ip = The index of the parameter value whose partial derivative this corresponds to value = The value of the derivative """ i = 0 for x in xvals: jacobian.set(i,0,1); jacobian.set(i,1,x); i += 1 # Required to have Mantid recognise the new function FunctionFactory.subscribe(Example1DFunction)
class ZFprotonDipole(IFunction1D): def category(self): return "Muon\\MuonSpecific" def init(self): self.declareParameter("A0", 0.5) self.declareParameter("Radius", 2, 'Radius (Angstrom)') self.declareParameter("LambdaTrans", 0.2, 'Lambda-Trans (MHz)') self.addConstraints("Radius > 0") self.addConstraints("LambdaTrans > 0") def function1D(self, x): A0 = self.getParameterValue("A0") radius = self.getParameterValue("Radius") LambdaTrans = self.getParameterValue("LambdaTrans") gmu = 2 * np.pi * 0.01355342 proton_moment = 2.792847351 nuclear_moment = 5.05088370 if radius > 0: B = 2 * proton_moment * nuclear_moment / (radius**3) else: B = 0 Omega = gmu * B return A0 * (1. / 6) * (1 + np.exp(-LambdaTrans * x) * (np.cos(Omega * x) + 2 * np.cos(1.5 * Omega * x) + 2 * np.cos(0.5 * Omega * x))) FunctionFactory.subscribe(ZFprotonDipole)
def category(self): return "QuasiElastic" def init(self): # Active fitting parameters self.declareParameter("Tau", 1.0, 'Residence time') self.declareParameter("L", 1.5, 'Jump length') def function1D(self, xvals): tau = self.getParameterValue("Tau") length = self.getParameterValue("L") xvals = np.array(xvals) hwhm = (1.0 - np.sin(xvals * length) / (xvals * length)) / tau return hwhm def functionDeriv1D(self, xvals, jacobian): tau = self.getParameterValue("Tau") length = self.getParameterValue("L") i = 0 for x in xvals: s = math.sin(x*length)/(x*length) h = (1.0-s)/tau jacobian.set(i,0,-h/tau); jacobian.set(i,1,(math.cos(x*length)-s)/(length*tau)); i += 1 # Required to have Mantid recognise the new function FunctionFactory.subscribe(ChudleyElliot)
def function1D(self, xvals): height = self.getParameterValue("Height") msd = self.getParameterValue("Msd") sigma = self.getParameterValue("Sigma") xvals = np.array(xvals) i1 = np.exp((-1.0 / 6.0) * xvals * xvals * msd) i2 = 1.0 + (np.power(xvals, 4) * sigma / 72.0) intensity = height * i1 * i2 return intensity def functionDeriv1D(self, xvals, jacobian): height = self.getParameterValue("Height") msd = self.getParameterValue("Msd") sigma = self.getParameterValue("Sigma") for i, x in enumerate(xvals): f1 = math.exp((-1.0 / 6.0) * x * x * msd) df1 = -f1 * ((2.0 / 6.0) * x * msd) x4 = math.pow(x, 4) f2 = 1.0 + (x4 * sigma / 72.0) df2 = x4 / 72.0 jacobian.set(i, 0, f1 * f2) jacobian.set(i, 1, height * df1 * f2) jacobian.set(i, 2, height * f1 * df2) # Required to have Mantid recognise the new function FunctionFactory.subscribe(MsdYi)
def category(self): return "SANS" def init(self): # Active fitting parameters self.declareParameter("Scale", 1.0, 'Scale') self.declareParameter("Rg", 60.0, 'Radius of gyration') def function1D(self, xvals): """ Evaluate the model @param xvals: numpy array of q-values """ return self.getParameterValue("Scale") * np.exp(-(self.getParameterValue('Rg')*xvals)**2/3.0 ) def functionDeriv1D(self, xvals, jacobian): """ Evaluate the first derivatives @param xvals: numpy array of q-values @param jacobian: Jacobian object """ i = 0 rg = self.getParameterValue('Rg') for x in xvals: jacobian.set(i,0, math.exp(-(rg*x)**2/3.0 ) ) jacobian.set(i,1, -self.getParameterValue("Scale") * math.exp(-(rg*x)**2/3.0 )*2.0/3.0*rg*x*x ); i += 1 # Required to have Mantid recognise the new function FunctionFactory.subscribe(Guinier)
def test_function_with_expected_attrs_subscribes_successfully(self): nfuncs_orig = len(FunctionFactory.getFunctionNames()) FunctionFactory.subscribe(TestFunctionCorrectForm) new_funcs = FunctionFactory.getFunctionNames() self.assertEquals(nfuncs_orig+1, len(new_funcs)) self.assertTrue("TestFunctionCorrectForm" in new_funcs)