def test_harmonic_oscillator_errors(self): """ Make sure the errors produced by fitting ODE's are the same as when fitting an exact solution. """ x, v, t = sf.variables('x, v, t') k = sf.Parameter(name='k', value=100) m = 1 a = -k/m * x ode_model = sf.ODEModel({sf.D(v, t): a, sf.D(x, t): v}, initial={t: 0, v: 0, x: 1}) t_data = np.linspace(0, 10, 250) np.random.seed(2) noise = np.random.normal(1, 0.05, size=t_data.shape) x_data = ode_model(t=t_data, k=100).x * noise ode_fit = sf.Fit(ode_model, t=t_data, x=x_data) ode_result = ode_fit.execute() phi = 0 A = 1 model = sf.Model({x: A * sf.cos(sf.sqrt(k/m) * t + phi)}) fit = sf.Fit(model, t=t_data, x=x_data) result = fit.execute() self.assertAlmostEqual(result.value(k), ode_result.value(k), places=4) self.assertAlmostEqual(result.stdev(k) / ode_result.stdev(k), 1, 2) self.assertGreaterEqual(result.stdev(k), ode_result.stdev(k))
def test_harmonic_oscillator_errors(): """ Make sure the errors produced by fitting ODE's are the same as when fitting an exact solution. """ x, v, t = sf.variables('x, v, t') k = sf.Parameter(name='k', value=100) m = 1 a = -k/m * x ode_model = sf.ODEModel({sf.D(v, t): a, sf.D(x, t): v}, initial={t: 0, v: 0, x: 1}) t_data = np.linspace(0, 10, 250) np.random.seed(2) noise = np.random.normal(1, 0.05, size=t_data.shape) x_data = ode_model(t=t_data, k=100).x * noise ode_fit = sf.Fit(ode_model, t=t_data, x=x_data, v=None) ode_result = ode_fit.execute() phi = 0 A = 1 model = sf.Model({x: A * sf.cos(sf.sqrt(k/m) * t + phi)}) fit = sf.Fit(model, t=t_data, x=x_data) result = fit.execute() assert result.value(k) == pytest.approx(ode_result.value(k), 1e-4) assert result.stdev(k) == pytest.approx(ode_result.stdev(k), 1e-2) assert result.stdev(k) >= ode_result.stdev(k)
def fourier_series(x, f, n=0): # Make the parameter objects for all the terms a0, *A = parameters(','.join([f'a{i}' for i in range(0, n + 1)])) B = parameters(','.join([f'b{i}' for i in range(1, n + 1)])) # Construct the series series = a0 + sum(ai*cos(i*f*x) + bi*sin(i*f*x) for i, (ai, bi) in enumerate(zip(A, B), start=1)) return series
def Fourier_series(x, f, n = 0): """Construit la série de Fourier comme modèle de référence pour le fitting.""" a0, *cos_a = parameters(','.join(['a{}'.format(i) for i in range(0, n + 1)])) sin_b = parameters(','.join(['b{}'.format(i) for i in range(1, n + 1)])) series = a0 + sum(ai * cos(i * f * x) + bi * sin(i * f * x) for i, (ai, bi) in enumerate(zip(cos_a, sin_b), start=1)) return series
def fourier_series(self, x, f, n=2): a0, *cos_a = parameters(','.join( ['a{}'.format(i) for i in range(0, n + 1)])) sin_b = parameters(','.join(['b{}'.format(i) for i in range(1, n + 1)])) series = a0 + sum( ai * cos(i * f * x) + bi * sin(i * f * x) for i, (ai, bi) in enumerate(zip(cos_a, sin_b), start=1)) return series
def test_LogLikelihood_global(): """ This is a test for global likelihood fitting to multiple data sets. Based on SO question 56006357. """ # creating the data mu1, mu2 = .05, -.05 sigma1, sigma2 = 3.5, 2.5 n1, n2 = 80, 90 np.random.seed(42) x1 = np.random.vonmises(mu1, sigma1, n1) x2 = np.random.vonmises(mu2, sigma2, n2) n = 2 # number of components xs = variables('x,' + ','.join('x_{}'.format(i) for i in range(1, n + 1))) x, xs = xs[0], xs[1:] ys = variables(','.join('y_{}'.format(i) for i in range(1, n + 1))) mu, kappa = parameters('mu, kappa') kappas = parameters(','.join('k_{}'.format(i) for i in range(1, n + 1)), min=0, max=10) mu.min, mu.max = -np.pi, np.pi template = exp(kappa * cos(x - mu)) / (2 * pi * besseli(0, kappa)) model = Model({ y_i: template.subs({ kappa: k_i, x: x_i }) for y_i, x_i, k_i in zip(ys, xs, kappas) }) all_data = {xs[0]: x1, xs[1]: x2, ys[0]: None, ys[1]: None} all_params = {'mu': 1} all_params.update({k_i.name: 1 for k_i in kappas}) # Evaluate the loglikelihood and its jacobian and hessian logL = LogLikelihood(model, data=all_data) eval_numerical = logL(**all_params) jac_numerical = logL.eval_jacobian(**all_params) hess_numerical = logL.eval_hessian(**all_params) # Test the types and shapes of the components. assert isinstance(eval_numerical, float) assert isinstance(jac_numerical, np.ndarray) assert isinstance(hess_numerical, np.ndarray) assert eval_numerical.shape == tuple() # Empty tuple -> scalar assert jac_numerical.shape == (3, ) assert hess_numerical.shape == ( 3, 3, )
def fourier_series(x, f, n=0): """ Returns a symbolic fourier series of order `n`. :param n: Order of the fourier series. :param x: Independent variable :param f: Frequency of the fourier series """ # Make the parameter objects for all the terms a0, *cos_a = parameters(','.join(['a{}'.format(i) for i in range(0, n + 1)])) sin_b = parameters(','.join(['b{}'.format(i) for i in range(1, n + 1)])) # Construct the series series = a0 + sum(ai * cos(i * f * x) + bi * sin(i * f * x) for i, (ai, bi) in enumerate(zip(cos_a, sin_b), start=1)) return series
def run( self, angle=0.02472, pixel_to_micron_x=9.81e-8, beam_waist_xy=0.5e-6, beam_waist_z=2e-6, rbc_radius=4e-6, s=1, tau=0.001, ): # create parameters for symfit distances = self.data.keys() v = sf.parameters('v_', value=500, min=0, max=1000)[0] d = sf.parameters('D_', value=50, min=0, max=100)[0] y0_p = sf.parameters( self.create_distance_strings('y0'), min=0, max=1, ) b_p = sf.parameters( self.create_distance_strings('b'), value=50, min=0, max=100, ) # create variables for symfit x = sf.variables('x')[0] y_var = sf.variables(self.create_distance_strings('y')) # create model # pixel_to_micron_x model = sf.Model({ y: y0 + b * sf.exp(-(dst * pixel_to_micron_x - v * (sf.cos(angle)) * x)**2 / (beam_waist_xy + 0.5 * rbc_radius**2 + 4 * d * x)) * sf.exp(-(x**2) * (v * sf.sin(angle) - pixel_to_micron_x / tau)**2 / (beam_waist_xy + 0.5 * rbc_radius**2 + angle * d * x)) / (4 * d * x + beam_waist_xy + 0.5 * rbc_radius**2) for y, y0, b, dst in zip(y_var, y0_p, b_p, distances) }) # dependent variables dict data = {y.name: self.data[dst] for y, dst in zip(y_var, distances)} # independent variable x n_data_points = len(list(self.data.values())[0]) max_time = n_data_points * tau x_data = np.linspace(0, max_time, n_data_points) # fit fit = sf.Fit(model, x=x_data, **data) res = fit.execute() return res
def fourier_series(x, period_list): """ Returns a symbolic fourier series of order `n`. :param n: Order of the fourier series. :param x: Independent variable :param f: Frequency of the fourier series """ # Make the parameter objects for all the terms (a0, ) = parameters("a0") cos_a = parameters(",".join( ["a{}".format(i) for i in range2(len(period_list))])) sin_b = parameters(",".join( ["b{}".format(i) for i in range2(len(period_list))])) # Construct the series print(period_list) series = a0 + sum( ai * cos(2 * math.pi / tau * x) + bi * sin(2 * math.pi / tau * x) for (tau, ai, bi) in zip(period_list, cos_a, sin_b)) return series
def do_glob_fit(self): """this method performs global fit on the CCPS""" # create parameters for symfit dist = self.data.keys() v = sf.parameters('v_', value=500, min=0, max=1000)[0] d = sf.parameters('D_', value=50, min=0, max=100)[0] y0_p = sf.parameters(', '.join('y0_{}'.format(key) for key in self.data.keys()), min=0, max=1) b_p = sf.parameters(', '.join('b_{}'.format(key) for key in self.data.keys()), value=50, min=0, max=100) # create variables for symfit x = sf.variables('x')[0] y_var = sf.variables(', '.join('y_{}'.format(key) for key in self.data.keys())) # get fixed & shared params dx, a, w2, a2, tau, s, wz2 = self.get_params() # create model model = sf.Model({ y: y0 + b * sf.exp(-(dst * dx - v * (sf.cos(a)) * x)**2 / (w2 + 0.5 * a2 + 4 * d * x)) * sf.exp(-(x**2) * (v * sf.sin(a) - dx / tau)**2 / (w2 + 0.5 * a2 + a * d * x)) / (4 * d * x + w2 + 0.5 * a2) for y, y0, b, dst in zip(y_var, y0_p, b_p, dist) }) # dependent variables dict data = {y.name: self.data[dst] for y, dst in zip(y_var, dist)} # independent variable x max_time = len(self.data[20]) * tau x_data = np.linspace(0, max_time, len(self.data[20])) # fit fit = sf.Fit(model, x=x_data, **data) res = fit.execute() return res
def fourier_series(x, f, n=0): a0, *cos_a = parameters(",".join([f"a{i}" for i in range(n + 1)])) sin_b = parameters(",".join([f"b{i}" for i in range(1, n + 1)])) series = a0 + sum(ai * cos(i * f * x) + bi * sin(i * f * x) for i, (ai, bi) in enumerate(zip(cos_a, sin_b), start=1)) return series
def test_basinhopping_2d(): def func2d(x): f = np.cos(14.5 * x[0] - 0.3) + (x[1] + 0.2) * x[1] + (x[0] + 0.2) * x[0] df = np.zeros(2) df[0] = -14.5 * np.sin(14.5 * x[0] - 0.3) + 2. * x[0] + 0.2 df[1] = 2. * x[1] + 0.2 return f, df def func2d_symfit(x1, x2): f = np.cos(14.5 * x1 - 0.3) + (x2 + 0.2) * x2 + (x1 + 0.2) * x1 return f def jac2d_symfit(x1, x2): df = np.zeros(2) df[0] = -14.5 * np.sin(14.5 * x1 - 0.3) + 2. * x1 + 0.2 df[1] = 2. * x2 + 0.2 return df np.random.seed(555) minimizer_kwargs = {'method': 'BFGS', 'jac': True} x0 = [1.0, 1.0] res = basinhopping(func2d, x0, minimizer_kwargs=minimizer_kwargs, niter=200) np.random.seed(555) x1, x2 = parameters('x1, x2', value=x0) with pytest.raises(TypeError): fit = BasinHopping( func2d_symfit, [x1, x2], local_minimizer=NelderMead(func2d_symfit, [x1, x2], jacobian=jac2d_symfit) ) fit = BasinHopping( func2d_symfit, [x1, x2], local_minimizer=BFGS(func2d_symfit, [x1, x2], jacobian=jac2d_symfit) ) fit_result = fit.execute(niter=200) assert isinstance(fit.local_minimizer.jacobian, MinimizeModel) assert isinstance(fit.local_minimizer.jacobian.model, CallableNumericalModel) assert res.x[0] == fit_result.value(x1) assert res.x[1] == fit_result.value(x2) assert res.fun == fit_result.objective_value # Now compare with the symbolic equivalent np.random.seed(555) model = cos(14.5 * x1 - 0.3) + (x2 + 0.2) * x2 + (x1 + 0.2) * x1 fit = Fit(model, minimizer=BasinHopping) fit_result = fit.execute() assert res.x[0] == fit_result.value(x1) assert res.x[1] == fit_result.value(x2) assert res.fun == fit_result.objective_value assert isinstance(fit.minimizer.local_minimizer, BFGS) # Impose constrains np.random.seed(555) model = cos(14.5 * x1 - 0.3) + (x2 + 0.2) * x2 + (x1 + 0.2) * x1 fit = Fit(model, minimizer=BasinHopping, constraints=[Eq(x1, x2)]) fit_result = fit.execute() assert fit_result.value(x1) == fit_result.value(x2) assert isinstance(fit.minimizer.local_minimizer, SLSQP) # Impose bounds np.random.seed(555) x1.min = 0.0 model = cos(14.5 * x1 - 0.3) + (x2 + 0.2) * x2 + (x1 + 0.2) * x1 fit = Fit(model, minimizer=BasinHopping) fit_result = fit.execute() assert fit_result.value(x1) >= x1.min assert isinstance(fit.minimizer.local_minimizer, LBFGSB)
def test_basinhopping_2d(self): def func2d(x): f = np.cos(14.5 * x[0] - 0.3) + (x[1] + 0.2) * x[1] + (x[0] + 0.2) * x[0] df = np.zeros(2) df[0] = -14.5 * np.sin(14.5 * x[0] - 0.3) + 2. * x[0] + 0.2 df[1] = 2. * x[1] + 0.2 return f, df def func2d_symfit(x1, x2): f = np.cos(14.5 * x1 - 0.3) + (x2 + 0.2) * x2 + (x1 + 0.2) * x1 return f def jac2d_symfit(x1, x2): df = np.zeros(2) df[0] = -14.5 * np.sin(14.5 * x1 - 0.3) + 2. * x1 + 0.2 df[1] = 2. * x2 + 0.2 return df np.random.seed(555) minimizer_kwargs = {'method': 'BFGS', 'jac': True} x0 = [1.0, 1.0] res = basinhopping(func2d, x0, minimizer_kwargs=minimizer_kwargs, niter=200) np.random.seed(555) x1, x2 = parameters('x1, x2', value=x0) with self.assertRaises(TypeError): fit = BasinHopping( func2d_symfit, [x1, x2], local_minimizer=NelderMead(func2d_symfit, [x1, x2], jacobian=jac2d_symfit) ) fit = BasinHopping( func2d_symfit, [x1, x2], local_minimizer=BFGS(func2d_symfit, [x1, x2], jacobian=jac2d_symfit) ) fit_result = fit.execute(niter=200) self.assertIsInstance(fit.local_minimizer.jacobian, MinimizeModel) self.assertIsInstance(fit.local_minimizer.jacobian.model, CallableNumericalModel) self.assertEqual(res.x[0] / fit_result.value(x1), 1.0) self.assertEqual(res.x[1] / fit_result.value(x2), 1.0) self.assertEqual(res.fun, fit_result.objective_value) # Now compare with the symbolic equivalent np.random.seed(555) model = cos(14.5 * x1 - 0.3) + (x2 + 0.2) * x2 + (x1 + 0.2) * x1 fit = Fit(model, minimizer=BasinHopping) fit_result = fit.execute() self.assertEqual(res.x[0], fit_result.value(x1)) self.assertEqual(res.x[1], fit_result.value(x2)) self.assertEqual(res.fun, fit_result.objective_value) self.assertIsInstance(fit.minimizer.local_minimizer, BFGS) # Impose constrains np.random.seed(555) model = cos(14.5 * x1 - 0.3) + (x2 + 0.2) * x2 + (x1 + 0.2) * x1 fit = Fit(model, minimizer=BasinHopping, constraints=[Eq(x1, x2)]) fit_result = fit.execute() self.assertEqual(fit_result.value(x1), fit_result.value(x2)) self.assertIsInstance(fit.minimizer.local_minimizer, SLSQP) # Impose bounds np.random.seed(555) x1.min = 0.0 model = cos(14.5 * x1 - 0.3) + (x2 + 0.2) * x2 + (x1 + 0.2) * x1 fit = Fit(model, minimizer=BasinHopping) fit_result = fit.execute() self.assertGreaterEqual(fit_result.value(x1), x1.min) self.assertIsInstance(fit.minimizer.local_minimizer, LBFGSB)