def test_fit(self): # test fit_scipy on its own a = Quantity("a") a.value = np.float_([1,3,5,6,7,9]) b = Quantity("b") b.value = np.float_([2.3,4,5.5,6,9.2,10.5]) c = Quantity("c") c.value = np.float_(1) d = Quantity("d") d.value = np.float_(1) f = a*c+d popt,perr = (sc.fit(a,b,f,[c,d])) small = 0.0001 self.assertTrue(abs(popt[0] - 1.05184) < small) self.assertTrue(abs(perr[0] - 0.1328) < small) self.assertTrue(abs(popt[1] - 0.81551) < small) self.assertTrue(abs(perr[1] - 0.7684) < small) # test fit command small = 0.001 p = Project() g = commands.Assignment("x") g.value = ["1","2","3"] g.value_unit = "A" g.execute(p) g = commands.Assignment("y") g.value = ["6","3","2.1"] g.value_unit = "C" g.error = ["1","1","2"] g.error_unit = "1e-1*C" g.execute(p) h = commands.Assignment("m") h.value = "1" h.value_unit = "s" h.execute(p) i = commands.Assignment("b") i.value = "1" i.value_unit = "C" i.execute(p) p.fit("m*x+b",("x","y"),["m","b"]) self.assertTrue(abs(p.data["m"].value - (-2.3)) < small) self.assertTrue(abs(p.data["m"].error - 0.7) < small) self.assertTrue(abs(p.data["b"].value - 8.06667) < small) self.assertTrue(abs(p.data["b"].error - 1.257) < small) p.fit("m*x+b",("x","y"),["m","b"],weighted=False) self.assertTrue(abs(p.data["m"].value - (-1.95)) < small) self.assertTrue(abs(p.data["m"].error - 0.6062) < small) self.assertTrue(abs(p.data["b"].value - 7.6) < small) self.assertTrue(abs(p.data["b"].error - 1.31) < small) p.data["y"].error = None self.assertRaises(RuntimeError,p.fit,"m*x+b",("x","y"),["m","b"],weighted=True)
def test_fit(self): # test fit_scipy on its own a = Quantity("a") a.value = np.float_([1, 3, 5, 6, 7, 9]) b = Quantity("b") b.value = np.float_([2.3, 4, 5.5, 6, 9.2, 10.5]) c = Quantity("c") c.value = np.float_(1) d = Quantity("d") d.value = np.float_(1) f = a * c + d popt, perr = (sc.fit(a, b, f, [c, d])) small = 0.0001 self.assertTrue(abs(popt[0] - 1.05184) < small) self.assertTrue(abs(perr[0] - 0.1328) < small) self.assertTrue(abs(popt[1] - 0.81551) < small) self.assertTrue(abs(perr[1] - 0.7684) < small) # test fit command small = 0.001 p = Project() g = commands.Assignment("x") g.value = ["1", "2", "3"] g.value_unit = "A" g.execute(p) g = commands.Assignment("y") g.value = ["6", "3", "2.1"] g.value_unit = "C" g.error = ["1", "1", "2"] g.error_unit = "1e-1*C" g.execute(p) h = commands.Assignment("m") h.value = "1" h.value_unit = "s" h.execute(p) i = commands.Assignment("b") i.value = "1" i.value_unit = "C" i.execute(p) p.fit("m*x+b", ("x", "y"), ["m", "b"]) self.assertTrue(abs(p.data["m"].value - (-2.3)) < small) self.assertTrue(abs(p.data["m"].error - 0.7) < small) self.assertTrue(abs(p.data["b"].value - 8.06667) < small) self.assertTrue(abs(p.data["b"].error - 1.257) < small) p.fit("m*x+b", ("x", "y"), ["m", "b"], weighted=False) self.assertTrue(abs(p.data["m"].value - (-1.95)) < small) self.assertTrue(abs(p.data["m"].error - 0.6062) < small) self.assertTrue(abs(p.data["b"].value - 7.6) < small) self.assertTrue(abs(p.data["b"].error - 1.31) < small) p.data["y"].error = None self.assertRaises(RuntimeError, p.fit, "m*x+b", ("x", "y"), ["m", "b"], weighted=True)
def fit(self, fit_function, xydata, parameters, weighted=None, plot=False, ignore_dim=False): """ fits function to data Args: fit_function: function to fit, e.g. "n*t**2 + m*t + b" xydata: pair of x-quantity and y-quantity of data to fit to, e.g. ["t","U"] parameters: list of parameters in fit function, e.g. ["n","m","b"] weighted: if True, will weight fit by errors (returns error if not possible) if False, will not weight fit by errors if None, will try to weight fit, but if at least one error is not given, will not weight it plot: Bool, if data and fit function should be plotted ignore_dim: if True, will ignore dimensions and just calculate in base units instead """ if self.config["fit_module"] == "scipy": import errorpro.fit_scipy as fit_module else: raise ValueError("no fit module called '%s'." % self.config["fit_module"]) # get parameter quantities parameters_obj = [] for p in parameters: if isinstance(p, str): if not p in self.data: self.data[p] = quantities.Quantity(p) self.data[p].dim = Dimension() parameters_obj.append(self.data[p]) elif isinstance(p, quantities.Quantity): parameters_obj.append(p) else: raise TypeError("parameters can only be strings or Quantity objects") # parse fit function fit_function = quantities.parse_expr(fit_function, self.data) # get data quantities x_data = quantities.parse_expr(xydata[0], self.data) # if x-data is an expression if not isinstance(x_data, quantities.Quantity): dummy = quantities.Quantity() fit_function = fit_function.subs(x_data,dummy) dummy.value = quantities.get_value(x_data) dummy.error = quantities.get_error(x_data)[0] dummy.dim = quantities.get_dimension(x_data) x_data = dummy y_data = quantities.parse_expr(xydata[1], self.data) # if y-data is an expression if not isinstance(y_data, quantities.Quantity): dummy = quantities.Quantity() dummy.value = quantities.get_value(y_data) dummy.error = quantities.get_error(y_data)[0] dummy.dim = quantities.get_dimension(y_data) y_data = dummy # check if dimension fits if not ignore_dim: try: dim_func = quantities.get_dimension(fit_function) except ValueError: dim_func = None if not dim_func == y_data.dim: # try to solve for dimensionless parameters known_dimensions = {x_data.name: x_data.dim} known_dimensions = dim_solve(fit_function, y_data.dim, known_dimensions) for q_name in known_dimensions: if q_name in self.data: if not self.data[q_name].dim == known_dimensions[q_name]: self.data[q_name].dim = known_dimensions[q_name] self.data[q_name].prefer_unit = None dim_func = quantities.get_dimension(fit_function) # if it still doesn't work, raise error if not dim_func == y_data.dim: raise RuntimeError("Finding dimensions of fit parameters was not sucessful.\n"\ "Check fit function or specify parameter units manually.\n"\ "This error will occur until dimensions are right.") # fit values, errors = fit_module.fit(x_data, y_data, fit_function, parameters_obj, weighted) # save results i = 0 for p in parameters_obj: p.value = values[i] p.value_formula = "fit" p.error = errors[i] p.error_formula = "fit" i += 1 # plot if plot: return plotting.plot([(x_data, y_data), (x_data, fit_function)], self.config, ignore_dim=ignore_dim) else: return self.table(*parameters_obj)
def fit(self, fit_function, xydata, parameters, weighted=None, plot=False, ignore_dim=False): """ fits function to data Args: fit_function: function to fit, e.g. "n*t**2 + m*t + b" xydata: pair of x-quantity and y-quantity of data to fit to, e.g. ["t","U"] parameters: list of parameters in fit function, e.g. ["n","m","b"] weighted: if True, will weight fit by errors (returns error if not possible) if False, will not weight fit by errors if None, will try to weight fit, but if at least one error is not given, will not weight it plot: Bool, if data and fit function should be plotted ignore_dim: if True, will ignore dimensions and just calculate in base units instead """ if self.config["fit_module"] == "scipy": import errorpro.fit_scipy as fit_module else: raise ValueError("no fit module called '%s'." % self.config["fit_module"]) # get parameter quantities parameters_obj = [] for p in parameters: if isinstance(p, str): if not p in self.data: self.data[p] = quantities.Quantity(p) self.data[p].dim = Dimension() parameters_obj.append(self.data[p]) elif isinstance(p, quantities.Quantity): parameters_obj.append(p) else: raise TypeError( "parameters can only be strings or Quantity objects") # parse fit function fit_function = quantities.parse_expr(fit_function, self.data) # get data quantities x_data = quantities.parse_expr(xydata[0], self.data) # if x-data is an expression if not isinstance(x_data, quantities.Quantity): dummy = quantities.Quantity() fit_function = fit_function.subs(x_data, dummy) dummy.value = quantities.get_value(x_data) dummy.error = quantities.get_error(x_data)[0] dummy.dim = quantities.get_dimension(x_data) x_data = dummy y_data = quantities.parse_expr(xydata[1], self.data) # if y-data is an expression if not isinstance(y_data, quantities.Quantity): dummy = quantities.Quantity() dummy.value = quantities.get_value(y_data) dummy.error = quantities.get_error(y_data)[0] dummy.dim = quantities.get_dimension(y_data) y_data = dummy # check if dimension fits if not ignore_dim: try: dim_func = quantities.get_dimension(fit_function) except ValueError: dim_func = None if not dim_func == y_data.dim: # try to solve for dimensionless parameters known_dimensions = {x_data.name: x_data.dim} known_dimensions = dim_solve(fit_function, y_data.dim, known_dimensions) for q_name in known_dimensions: if q_name in self.data: if not self.data[q_name].dim == known_dimensions[ q_name]: self.data[q_name].dim = known_dimensions[q_name] self.data[q_name].prefer_unit = None dim_func = quantities.get_dimension(fit_function) # if it still doesn't work, raise error if not dim_func == y_data.dim: raise RuntimeError("Finding dimensions of fit parameters was not sucessful.\n"\ "Check fit function or specify parameter units manually.\n"\ "This error will occur until dimensions are right.") # fit values, errors = fit_module.fit(x_data, y_data, fit_function, parameters_obj, weighted) # save results i = 0 for p in parameters_obj: p.value = values[i] p.value_formula = "fit" p.error = errors[i] p.error_formula = "fit" i += 1 # plot if plot: return plotting.plot([(x_data, y_data), (x_data, fit_function)], self.config, ignore_dim=ignore_dim) else: return self.table(*parameters_obj)