def isregistered(function): status, msg = True, "" try: FunctionFactory.createFunction(function) except RuntimeError as exc: status, msg = False, 'Could not create {} function: {}'.format(function, str(exc)) return status, msg
def initByName(self, name, *args, **kwargs): """ intialise composite function of named type. E.g. "ProductFunction" This function would be protected in c++ and should not be called directly except by :meth:`__init__` functions of this class and subclasses. :param name: name of class calling this. :param args: names of functions in composite function :param kwargs: any parameters or attributes that must be passed to the composite function itself. """ if len(args) == 1 and not isinstance(args[0], FunctionWrapper): # We have a composite function to wrap self.fun = args[0] else: self.fun = FunctionFactory.createCompositeFunction(name) # Add the functions, checking for Composite & Product functions for a in args: if not isinstance(a, int): if isinstance(a, CompositeFunctionWrapper): if self.pureAddition: self.pureAddition = a.pureAddition if self.pureMultiplication: self.pureMultiplication = a.pureMultiplication functionToAdd = FunctionFactory.createInitialized(a.fun.__str__()) self.fun.add(functionToAdd) self.init_paramgeters_and_attributes(**kwargs)
def test_members_can_be_added(self): func = CompositeFunction() f1 = FunctionFactory.createInitialized('name=FlatBackground,A0=1') f2 = FunctionFactory.createInitialized('name=FlatBackground,A0=2') f3 = FunctionFactory.createInitialized('name=FlatBackground,A0=3') func.add(f1) func.add(f2) func.add(f3) self.assertEqual(len(func), 3) self.assertEqual(str(func[0]), 'name=FlatBackground,A0=1') self.assertEqual(str(func[1]), 'name=FlatBackground,A0=2') self.assertEqual(str(func[2]), 'name=FlatBackground,A0=3')
def is_registered(function_name): """ Check whether the function with the specified name has been registered. :param function_name: The name of the function to check for registration. :return: A tuple of the status (True if function is registered, false otherwise) and the error message (empty if the function is registered). """ try: FunctionFactory.createFunction(function_name) except RuntimeError as exc: return False, 'Could not create {} function: {}'.format(function_name, str(exc)) return True, ""
def skip(self): """ Override and return a string depending on whether the directive should be skipped. If empty then the directive should be processed otherwise the string should contain the error message The default is to skip (and warn) if the algorithm is not known. Returns: str: Return error mesage string if the directive should be skipped """ from mantid.api import AlgorithmFactory, FunctionFactory name, version = self.algorithm_name(), self.algorithm_version() msg = "" if version is None: # it is a fit function if name in FunctionFactory.getFunctionNames(): return "" else: msg = "No fit function '%s', skipping directive" % name else: if AlgorithmFactory.exists(name, version): return "" else: msg = "No algorithm '%s' version '%d', skipping directive" % (name, version) # warn the user if len(msg) > 0: env = self.state.document.settings.env env.app.verbose(msg) return msg
def test_parameters_can_be_get_and_set(self): func = FunctionFactory.createInitialized('name=FlatBackground,A0=1;name=FlatBackground,A0=2') self.assertEqual(func.getParameterValue('f0.A0'), 1.0) self.assertEqual(func.getParameterValue('f1.A0'), 2.0) func.setParameter('f0.A0', 10.0) self.assertEqual(func.getParameterValue('f0.A0'), 10.0) func.setParameter('f1.A0', 20.0) self.assertEqual(func.getParameterValue('f1.A0'), 20.0)
def test_nested_functions(self): s = 'name=FlatBackground,A0=1;(name=FlatBackground,A0=2;name=FlatBackground,A0=3)' func = FunctionFactory.createInitialized(s) self.assertEqual(len(func), 2) self.assertFalse(isinstance(func[0], CompositeFunction)) self.assertTrue(isinstance(func[1], CompositeFunction)) self.assertEqual(len(func[1]), 2) self.assertEqual(func.getParameterValue('f0.A0'), 1.0) self.assertEqual(func.getParameterValue('f1.f0.A0'), 2.0) self.assertEqual(func.getParameterValue('f1.f1.A0'), 3.0) self.assertEqual(func.nParams(), 3)
def create_mantid_ifunction(self, function_name): """ Create and initiializes a Mantid IFunction. Args: function_name (str): The name of the function to use. Returns: ifunction: An instance of a Mantid IFunction """ from mantid.api import FunctionFactory return FunctionFactory.createFunction(function_name)
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)
def __init__(self, name, **kwargs): """ Called when creating an instance :param name: name of fitting function to create or an Ifunction object to wrap. :param kwargs: standard argument for initializing fit function """ if not isinstance(name, str): self.fun = name else: self.fun = FunctionFactory.createFunction(name) self.init_paramgeters_and_attributes(**kwargs)
# 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 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)
# 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 PCRmagnetfnorm(IFunction1D): def category(self): return "Muon\\MuonSpecific" def init(self): self.declareParameter("A0", 0.2, 'Amplitude') self.declareParameter("SigmaOverW", 0.1, 'Normalised relaxation rate') self.declareParameter("H0", 3.0, 'Local magnetic field') self.declareParameter("Toff", 0.1, 'Time offset') def function1D(self, x): A0 = self.getParameterValue("A0") sigma = self.getParameterValue("SigmaOverW") 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(- (sigma * w * x) ** 2 / 2) * np.cos(w * x)) FunctionFactory.subscribe(PCRmagnetfnorm)
# 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)
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)
# 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 class StretchedKT(IFunction1D): def category(self): return "Muon\\MuonGeneric" def init(self): self.declareParameter("A0", 1) self.declareParameter("Beta", 1) self.declareParameter("Sigma", 0.1) def function1D(self, x): A0 = self.getParameterValue("A0") beta = self.getParameterValue("Beta") Sigma = self.getParameterValue("Sigma") product = Sigma * x A = (2./3.) * (1 - product ** beta) B = np.exp(- product ** beta / beta) return A0*(1./3. + A * B) FunctionFactory.subscribe(StretchedKT)
---------- 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)
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)
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=no-init,invalid-name ''' @author Spencer Howells, ISIS @date December 05, 2013 ''' 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)
def setUp(self): context = setup_context() self.model = BasicFittingModel(context, context.fitting_context) self.dataset_names = ["EMU20884; Group; fwd; Asymmetry", "EMU20884; Group; top; Asymmetry"] self.fit_function = FunctionFactory.createFunction("FlatBackground") self.single_fit_functions = [self.fit_function.clone(), self.fit_function.clone()]
# Mantid Repository : https://github.com/mantidproject/mantid # # Copyright © 2018 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 import numpy as np from scipy import special as sp class Bessel(IFunction1D): def category(self): return "Muon" def init(self): self.declareParameter("A0", 1, 'Amplitude') self.declareParameter("Phi", 0.1, 'Phase(rad)') self.declareParameter("Nu", 0.1, 'Frequency(MHz)') def function1D(self, x): A0 = self.getParameterValue("A0") Phi = self.getParameterValue("Phi") Nu = self.getParameterValue("Nu") return A0 * sp.j0(2 * np.pi * Nu * x + Phi) FunctionFactory.subscribe(Bessel)
self.declareParameter("FreqD", 0.2, 'Anisotropic hyperfine coupling constant (MHz)') self.declareParameter("FCut", 1.0, 'Frequency cut (MHz)') self.declareParameter("Phi", 0.0, 'Phase') self.addConstraints("FreqA > 0") self.addConstraints("FreqD > 0") self.addConstraints("FCut > 0") def function1D(self, x): A0 = self.getParameterValue("A0") FreqA = self.getParameterValue("FreqA") FreqD = self.getParameterValue("FreqD") Fcut = self.getParameterValue("FCut") Phi = self.getParameterValue("Phi") W1 = 2 * np.pi * (FreqA - FreqD) W2 = 2 * np.pi * (FreqA + FreqD / 2) W3 = 3 * np.pi * FreqD if Fcut > 0: A1 = 1 / (1 + (W1 / (2 * np.pi * Fcut))**2) A2 = 2 / (1 + (W2 / (2 * np.pi * Fcut))**2) A3 = 2 / (1 + (W3 / (2 * np.pi * Fcut))**2) else: A1 = 1 A2 = 2 A3 = 2 return A0 * (A1 * np.cos(W1 * x + Phi) + A2 * np.cos(W2 * x + Phi) + A3 * np.cos(W3 * x + Phi)) / 6 FunctionFactory.subscribe(ZFMuonium)
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)
# # Copyright © 2018 ISIS Rutherford Appleton Laboratory UKRI, # NScD Oak Ridge National Laboratory, European Spallation Source, # Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS # 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 CombGaussLorentzKT(IFunction1D): def category(self): return "Muon\\MuonGeneric" def init(self): self.declareParameter("A0", 0.5, 'Amplitude') self.declareParameter("Lambda", 0.1, 'Exponential decay rate') self.declareParameter("Sigma", 0.2, 'KuboToyabe decay rate') def function1D(self, x): A0 = self.getParameterValue("A0") Lambda = self.getParameterValue("Lambda") Sigma = self.getParameterValue("Sigma") return A0 * ((1. / 3.) + (2. / 3.) * (1. - (Sigma * x)**2 - Lambda * x) * np.exp(-0.5 * (Sigma * x)**2 - Lambda * x)) FunctionFactory.subscribe(CombGaussLorentzKT)
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)
#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)
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)
class StandardSC(IFunction1D): def category(self): return "Muon\\MuonGeneric" def init(self): self.declareParameter( "A0", 0.16, 'Amplitude of interal field oscillation') self.declareParameter("Sigma", 0.2, 'Gaussian decay rate') self.declareParameter("FieldSC", 300.0, 'Internal Field (G)') self.declareParameter("FieldBG", 300.0, 'External Field (G)') self.declareParameter("Phi", 0.0, 'Phase') self.declareParameter( "Abg", 0.1, 'Amplitude of external field oscillation') def function1D(self, x): A0 = self.getParameterValue("A0") sigma = self.getParameterValue("Sigma") FieldSC = self.getParameterValue("FieldSC") FieldBG = self.getParameterValue("FieldBG") phi = self.getParameterValue("Phi") Abg = self.getParameterValue("Abg") omegaSC = FieldSC * 0.1355 * 2 * np.pi omegaBG = FieldBG * 0.1355 * 2 * np.pi return A0 * np.exp(- 0.5 * sigma * sigma * x * x) * np.cos(omegaSC * x + phi) + Abg * np.cos(omegaBG * x + phi) FunctionFactory.subscribe(StandardSC)
F(E) is normalized: \int_{-infty}^{infty} dE F(E) = 1 """ parms, de, energies, fourier = function1Dcommon( self, xvals, **optparms) if parms is None: return fourier #return zeros if parameters not valid transform = parms['Height'] * np.interp(xvals - parms['Centre'], energies, fourier) return transform @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(StretchedExpFT)
def setUp(self): self.dataset_names = ["Name1", "Name2"] self.current_dataset_index = 0 self.start_x = 0.0 self.end_x = 15.0 self.fit_status = "success" self.chi_squared = 1.5 self.function_name = "FlatBackground" self.minimizer = "Levenberg-Marquardt" self.evaluation_type = "eval type" self.fit_to_raw = True self.plot_guess = True self.simultaneous_fitting_mode = True self.simultaneous_fit_by = "Group/Pair" self.simultaneous_fit_by_specifier = "fwd" self.global_parameters = ["A0"] self.fit_function = FunctionFactory.createFunction("FlatBackground") self.single_fit_functions = [ self.fit_function.clone(), self.fit_function.clone() ] self._setup_mock_view() self._setup_mock_model() self._setup_presenter() self.mock_view_minimizer.assert_called_once_with() self.mock_view_evaluation_type.assert_called_once_with() self.mock_view_fit_to_raw.assert_called_once_with() self.mock_view_simultaneous_fit_by.assert_called_once_with() self.mock_view_simultaneous_fit_by_specifier.assert_called_once_with() self.mock_view_global_parameters.assert_called_once_with() self.mock_model_minimizer.assert_called_once_with(self.minimizer) self.mock_model_evaluation_type.assert_called_once_with( self.evaluation_type) self.mock_model_fit_to_raw.assert_called_once_with(self.fit_to_raw) self.mock_model_simultaneous_fit_by.assert_called_once_with( self.simultaneous_fit_by) self.mock_model_simultaneous_fit_by_specifier.assert_called_once_with( self.simultaneous_fit_by_specifier) self.mock_model_global_parameters.assert_called_once_with( self.global_parameters) self.assertEqual( self.view.set_slot_for_fit_generator_clicked.call_count, 1) self.assertEqual(self.view.set_slot_for_fit_button_clicked.call_count, 1) self.assertEqual(self.view.set_slot_for_undo_fit_clicked.call_count, 1) self.assertEqual(self.view.set_slot_for_plot_guess_changed.call_count, 1) self.assertEqual(self.view.set_slot_for_fit_name_changed.call_count, 1) self.assertEqual( self.view.set_slot_for_function_structure_changed.call_count, 1) self.assertEqual( self.view.set_slot_for_function_parameter_changed.call_count, 1) self.assertEqual(self.view.set_slot_for_start_x_updated.call_count, 1) self.assertEqual(self.view.set_slot_for_end_x_updated.call_count, 1) self.assertEqual(self.view.set_slot_for_minimizer_changed.call_count, 1) self.assertEqual( self.view.set_slot_for_evaluation_type_changed.call_count, 1) self.assertEqual(self.view.set_slot_for_use_raw_changed.call_count, 1) self.assertEqual(self.view.set_slot_for_dataset_changed.call_count, 1) self.assertEqual( self.view.set_slot_for_fitting_mode_changed.call_count, 1) self.assertEqual( self.view.set_slot_for_simultaneous_fit_by_changed.call_count, 1) self.assertEqual( self.view.set_slot_for_simultaneous_fit_by_specifier_changed. call_count, 1)
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) / 6) 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) / 6) jacobian.set(i, 0, e) jacobian.set(i, 1, -((x**2) / 6) * e * height) i += 1 # Required to have Mantid recognise the new function FunctionFactory.subscribe(MsdGauss)
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)
def test_get_Gaussian(self): name = "Gaussian" func = FunctionFactory.createFunction(name) self.assertTrue(func.name() == name) self.assertTrue(len(func.__repr__()) > len(name)) self.assertTrue("Peak" in func.categories())
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")
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)
def test_category_override_returns_overridden_result(self): FunctionFactory.subscribe(Times2) func = FunctionFactory.createFunction("Times2") self.assertEquals("SimpleFunction", func.category()) FunctionFactory.unsubscribe("Times2")
""" 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)
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)
""" 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)
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)
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)
import numpy as np class HighTFMuonium(IFunction1D): def category(self): return "Muon\\MuonSpecific" def init(self): self.declareParameter("A0", 0.1) self.declareParameter("Field", 100, "Magnetic field (G)") self.declareParameter("Freq", 0.2, 'Isotropic hyperfine coupling constant (MHz)') self.declareParameter("Phi", 0.0, 'Phi (rad)') def function1D(self, x): A0 = self.getParameterValue("A0") Field = self.getParameterValue("Field") Freq = self.getParameterValue("Freq") Phi = self.getParameterValue("Phi") gmu = 0.01355342 ge = 2.8024 OmegaMinus = (ge - gmu) * Field * np.pi Omega = 2 * np.pi * \ (np.sqrt(Freq ** 2 + ((ge + gmu) * Field) ** 2) / 2 - Freq / 2) Omega2 = Omega - OmegaMinus Omega1 = Omega2 + Freq * 2 * np.pi return A0 * 0.5 * (np.cos(Omega1 * x + Phi) + np.cos(Omega2 * x + Phi)) FunctionFactory.subscribe(HighTFMuonium)
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)
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)
------- 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): func = FunctionFactory.createInitialized( 'name=FlatBackground;name=FlatBackground') self.assertTrue(isinstance(func, CompositeFunction)) self.assertEqual(len(func), 2) self.assertEqual(func.nParams(), 2)
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)')
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)
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)
# 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)
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)
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)
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)
from matplotlib.lines import Line2D from mantid.plots import MantidAxes from mantid.simpleapi import CreateSampleWorkspace from mantidqt.widgets.fitpropertybrowser import FitPropertyBrowser from mantidqt.widgets.fitpropertybrowser.fitpropertybrowserplotinteraction import FitPropertyBrowserPlotInteraction from mantid.api import AnalysisDataService, FunctionFactory, WorkspaceFactory import matplotlib matplotlib.use('AGG') # noqa X_COLUMN_LABEL = 'x_column' Y_COLUMN_LABEL = 'y_column' FULL_FUNCTION = FunctionFactory.createInitialized("name=FlatBackground,A0=1;name=LinearBackground,A0=1," "A1=2;name=GausOsc,A=0.2,Sigma=0.2,Frequency=0.1,Phi=0") FUNCTION_1 = FunctionFactory.createInitialized("name=FlatBackground,A0=1") FUNCTION_2 = FunctionFactory.createInitialized("name=LinearBackground,A0=1,A1=2") FUNCTION_3 = FunctionFactory.createInitialized("name=GausOsc,A=0.2,Sigma=0.2,Frequency=0.1,Phi=0") class FitPropertyBrowserPlotInteractionTest(unittest.TestCase): def setup_mock_fit_browser(self, workspace_creator, workspace_name, function, function_prefix): workspace_creator(workspace_name) self.fit_browser.workspaceName = Mock(return_value=workspace_name) self.fit_browser.currentHandler.return_value = self.create_mock_handler(function, function_prefix) def create_table_workspace(self, table_name): table = WorkspaceFactory.createTable() table.addColumn('double', X_COLUMN_LABEL, 1)