def fit_data(data, guess=10.0, use_err=False): x_data = data[:, 0] y_data = 1 - data[:, 1] if use_err: data_err = data[:, 2] x, y = sf.variables('x, y') pKa, n = sf.parameters('pKa, n') model = sf.Model({y: (10**(n * (pKa - x)) + 1)**-1.0}) pKa.value = guess n.value = 1 if use_err: fit = sf.Fit(model, x=x_data, y=y_data, sigma_y=data_err, minimizer=Powell, absolute_sigma=True) else: fit = sf.Fit(model, x=x_data, y=y_data, minimizer=Powell) result = fit.execute() print("pKa.....................................", result.value(pKa), '+/-', result.stdev(pKa)) print("n.......................................", result.value(n), '+/-', result.stdev(n)) print("Regression coefficent:................", result.r_squared, '\n') x_out = np.arange(min(x_data), max(x_data), 10**-3.0) y_out = fit.model(x=x_out, **result.params)[0] return x_out, y_out, result.value(pKa), result.stdev( pKa), result.r_squared, result.value(n), result.stdev(n)
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 fit_plane(xyz): """ Fit a plane to the point coordinates in xyz. Dev note: An alternative implementation is possible that omits the `f` variable, and thus has one fewer degree of freedom. This means the fit is easier and maybe more precise. This could be tested. The notebook req4.1_fit_plane.ipynb in the explore repository (https://github.com/sundial-pointcloud-geometry/explore) has some notes on this. The problem with those models where f is just zero and the named symfit model is created for one of x, y or z instead is that you have to divide by one of the a, b or c parameters respectively. If one of these turns out to be zero, symfit will not find a fit. A solution would be to actually create three models and try another if one of them fails to converge. """ a, b, c, d = sf.parameters('a, b, c, d') x, y, z, f = sf.variables('x, y, z, f') plane_model = {f: x * a + y * b + z * c + d} plane_fit = sf.Fit(plane_model, x=xyz[0], y=xyz[1], z=xyz[2], f=np.zeros_like(xyz[0]), constraints=[sf.Equality(a**2 + b**2 + c**2, 1)]) # keep plane normal a unit vector plane_fit_result = plane_fit.execute() return plane_fit_result
def test_ODE_stdev(): """ Make sure that parameters from ODEModels get standard deviations. """ x, v, t = sf.variables('x, v, t') k = sf.Parameter(name='k') k.min = 0 k.value = 10 a = -k * x model = sf.ODEModel({ sf.D(v, t): a, sf.D(x, t): v, }, initial={ v: 0, x: 1, t: 0 }) t_data = np.linspace(0, 10, 150) noise = np.random.normal(1, 0.05, t_data.shape) x_data = model(t=t_data, k=11).x * noise v_data = model(t=t_data, k=11).v * noise fit = sf.Fit(model, t=t_data, x=x_data, v=v_data) result = fit.execute() assert result.stdev(k) is not None assert np.isfinite(result.stdev(k))
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 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 generator_execute(self, *, k_start=0, **minimizer_kwargs): """ Hand over the rains to :mod:`symfit`, and regularize that inversion. Use this in case of a very expensive calculation, so the results can e.g. be written to disk. :param k_start: :param minimizer_kwargs: :return: generator over the subfits per data set, starting from dataset ``k_start``. """ # Select the symbols which depend on all the data sets global_symbols = [] local_symbols = {} for s in self.model.ordered_symbols: if isinstance(s, sf.MatrixSymbol) and N_sets in s.shape: global_symbols.append(s) # Turn into a vector local_symbols[s] = s.func(*s.args[:-1], 1) local_model = self.localize_model(local_symbols) for set_index in range(k_start, self.shapes[N_sets]): # Select the right component data = self.data.copy() for s in global_symbols: if s in data: # Select the component, but maintain shape data[s] = data[s][:, set_index][..., None] fit = sf.Fit(local_model, **key2str(data), **self.fit_options) fit_result = fit.execute(**minimizer_kwargs) model_ans = fit.model(**key2str(fit.independent_data), **fit_result.params) fit_result.model_ans = model_ans yield fit_result
['$B_0$']).setaxis('$B_0$', x_finer).set_units( '$B_0$', d.get_units('$B_0$')) plot(d, label='data') plot(guess_nddata, ':', label='guess') model = s.Model({y_var: dVoigt}) if interactive: guess = InteractiveGuess(model, y=d.data.real, B=d.getaxis('$B_0$'), n_points=500) guess.execute() logger.info(strm(guess)) y_var = s.Variable('y') logger.info(strm("about to run fit")) fit = s.Fit( model, d.getaxis('$B_0$'), d.data.real ) # really want to use minpack here, but gives "not proper array of floats fit_result = fit.execute() logger.info(strm("fit is done")) plt.figure() plt.title('data with fit') plot(d, '.', label='data') fit_nddata = nddata( fit.model(B=x_finer, **fit_result.params).y, [-1], ['$B_0$']).setaxis('$B_0$', x_finer) plot(fit_nddata, label='fit') logger.info(strm(fit_result)) conc_list.append(concentration) R_list.append(fit_result.params['R']) sigma_list.append(fit_result.params['sigma']) A_list.append(fit_result.params['A'])
t: 0.0, S: S_0, I: I_0, R: R_0, D: D_0 }) idx = sorted_data["country"] == country x = sorted_data[idx]["days_since_100_cases"].values y = sorted_data[idx]["cumulative_deaths"].values fit = sf.Fit( ode_model[country], t=x, S=None, I=None, R=None, D=y, minimizer=[DifferentialEvolution, BFGS], ) fit_result[country] = fit.execute(DifferentialEvolution={ "seed": 0, "tol": 1e-2, "maxiter": 5 }, BFGS={"tol": 1e-6}) print(fit_result[country]) logger.info("Inferencing...") n_days = 365 # Daily predictions
def fit_lanes(self, points_left, points_right, fit_globally=False) -> dict: """ Applies and returns a polynomial fit for given points along the left and right lane line. Both lanes are described by a second order polynomial x(y) = ay^2 + by + x0. In the `fit_globally` case, a and b are modeled as equal, making the lines perfectly parallel. Otherwise, each line is fit independent of the other. The parameters of the model are returned in a dictionary with keys 'al', 'bl', 'x0l' for the left lane parameters and 'ar', 'br', 'x0r' for the right lane. :param points_left: Two lists of the x and y positions along the left lane line. :param points_right: Two lists of the x and y positions along the right lane line. :param fit_globally: Set True to use the global, parallel line fit model. In practice this does not allays work. :return: fit_vals, a dictionary containing the fitting parameters for the left and right lane as above. """ xl, yl = points_left xr, yr = points_right fit_vals = {} if fit_globally: # Define global model to fit x_left, y_left, x_right, y_right = symfit.variables( 'x_left, y_left, x_right, y_right') a, b, x0_left, x0_right = symfit.parameters( 'a, b, x0_left, x0_right') model = symfit.Model({ x_left: a * y_left**2 + b * y_left + x0_left, x_right: a * y_right**2 + b * y_right + x0_right }) # Apply fit xl, yl = points_left xr, yr = points_right fit = symfit.Fit(model, x_left=xl, y_left=yl, x_right=xr, y_right=yr) fit = fit.execute() fit_vals.update({ 'ar': fit.value(a), 'al': fit.value(a), 'bl': fit.value(b), 'br': fit.value(b), 'x0l': fit.value(x0_left), 'x0r': fit.value(x0_right) }) else: # Fit lines independently x, y = symfit.variables('x, y') a, b, x0 = symfit.parameters('a, b, x0') model = symfit.Model({ x: a * y**2 + b * y + x0, }) # Apply fit on left fit = symfit.Fit(model, x=xl, y=yl) fit = fit.execute() fit_vals.update({ 'al': fit.value(a), 'bl': fit.value(b), 'x0l': fit.value(x0) }) # Apply fit on right fit = symfit.Fit(model, x=xr, y=yr) fit = fit.execute() fit_vals.update({ 'ar': fit.value(a), 'br': fit.value(b), 'x0r': fit.value(x0) }) return fit_vals