def test_linear_fit(self): ''' Test of plotting fit ''' X = e.MeasurementArray([1, 2, 3, 4, 5], [0.1]) Y = e.MeasurementArray([3, 5, 7, 9, 11], [0.05]) figure = p.MakePlot(xdata=X, ydata=Y) slope, intercept = figure.fit('linear', print_results=False) self.assertEqual(slope, 2) self.assertEqual(intercept, 1)
def test5(): ''' Test of plotting fit ''' X = e.MeasurementArray([1, 2, 3, 4, 5], [0.1]) Y = e.MeasurementArray([3, 5, 7, 9, 11], [0.05]) figure = p.Plot(X, Y) figure.fit('linear') intercept, slope = figure.fit_parameters assert slope.mean == 2 assert intercept.mean == 1
def test_delete(self): '''Tests inserting new values into a MeasurementArray. ''' x = e.MeasurementArray([3, 2, 1], 1) x = x.delete(1) self.assertEqual(len(x), 2)
def test_array_elementary(self): '''Tests elementary operations on Measurement objects ''' x = e.MeasurementArray([4, 9, 2], error=[0.1, 0.2, 0.3]) y = e.MeasurementArray([2, 3, 3], error=0.1) self.assertListEqual((x + y).means.tolist(), [6, 12, 5]) self.assertListEqual((y + x).means.tolist(), [6, 12, 5]) self.assertListEqual((x - y).means.tolist(), [2, 6, -1]) self.assertListEqual((y - x).means.tolist(), [-2, -6, 1]) self.assertListEqual((x * y).means.tolist(), [8, 27, 6]) self.assertListEqual((y * x).means.tolist(), [8, 27, 6]) self.assertListEqual((x / y).means.tolist(), [2, 3, 2 / 3]) self.assertListEqual((y / x).means.tolist(), [0.5, 1 / 3, 3 / 2]) self.assertListEqual((x**y).means.tolist(), [16, 729, 8]) self.assertListEqual((y**x).means.tolist(), [16, 19683, 9])
def test_insert(self): '''Tests inserting new values into a MeasurementArray. ''' x = e.MeasurementArray([3, 1], 1) x = x.insert(1, 2) to_insert = e.Measurement(4, 1) x = x.insert(2, to_insert) self.assertEqual(x[1], 2) self.assertEqual(x[2], to_insert)
def test_append(self): '''Tests appending new values to a MeasurementArray. ''' x = e.MeasurementArray([3, 2], 1) x = x.append(1) to_append = e.Measurement(4, 1) x = x.append(to_append) self.assertEqual(x[2], 1) self.assertEqual(x[3], to_append)
def test_array_functions(self): '''Tests mathematical functions on Measurement objects ''' x = e.MeasurementArray([4, 9, 2], error=[0.1, 0.2, 0.3]) y = e.MeasurementArray([0.3, 0.56, 0.2], error=0.01) self.assertEqual(e.sin(x).means.tolist(), np.sin(x.means).tolist()) self.assertEqual(e.cos(x).means.tolist(), np.cos(x.means).tolist()) self.assertEqual(e.tan(x).means.tolist(), np.tan(x.means).tolist()) self.assertEqual( e.csc(x).means.tolist(), (1 / np.sin(x.means)).tolist()) self.assertEqual( e.sec(x).means.tolist(), (1 / np.cos(x.means)).tolist()) self.assertEqual( e.cot(x).means.tolist(), (1 / np.tan(x.means)).tolist()) self.assertEqual(e.exp(x).means.tolist(), np.exp(x.means).tolist()) self.assertEqual(e.log(x).means.tolist(), np.log(x.means).tolist()) self.assertEqual(e.asin(y).means.tolist(), np.arcsin(y.means).tolist()) self.assertEqual(e.acos(y).means.tolist(), np.arccos(y.means).tolist()) self.assertEqual(e.atan(x).means.tolist(), np.arctan(x.means).tolist())
def test_polynomial_fit(self): ''' Test of plotting fit ''' X = e.MeasurementArray([-2, -1, 0, 1, 2], [0.1]) Y = 3 * X**2 + 2 * X + 1 figure = p.MakePlot(xdata=X, ydata=Y) figure.fit('pol2', print_results=False) par0 = figure.get_dataset().xyfitter[0].fit_pars[0] par1 = figure.get_dataset().xyfitter[0].fit_pars[1] par2 = figure.get_dataset().xyfitter[0].fit_pars[2] self.assertAlmostEqual(par0, 1, places=7) self.assertAlmostEqual(par1, 2, places=7) self.assertAlmostEqual(par2, 3, places=7)
def test_gaussian_fit(self): ''' Test of plotting fit ''' X = e.MeasurementArray([-1, -1 / 3, 1 / 3, 1], [0.1]) mean = 0.1 std = 0.5 norm = .5 Y = norm * (2 * m.pi * std**2)**(-0.5) * np.exp(-0.5 * (X - mean)**2 / std**2) figure = p.MakePlot(xdata=X, ydata=Y) figure.fit('gauss', print_results=False) par0 = figure.get_dataset().xyfitter[0].fit_pars[0] par1 = figure.get_dataset().xyfitter[0].fit_pars[1] par2 = figure.get_dataset().xyfitter[0].fit_pars[2] self.assertAlmostEqual(par0, mean, places=7) self.assertAlmostEqual(par1, std, places=7) self.assertAlmostEqual(par2, norm, places=7)
def test_measurement_array(self): '''Tests creating a MeasurementArray from multiple measurements ''' x = e.MeasurementArray([9, 10, 11], error=1) self.assertEqual(x.mean, 10) self.assertEqual(x.std(), 1)
def __init__(self, xdata, ydata=None, xerr=None, yerr=None, data_name=None, xname=None, xunits=None, yname=None, yunits=None, is_histogram=False, bins=50): '''Use MeasurementArray() to initialize a dataset''' if (data_name is None): self.name = "dataset{}".format(XYDataSet.unnamed_data_counter) '''A string of the name of the dataset. .. code-block:: python x = q.MeasurementArray([1, 2, 3, 4], error=0.5) y = q.MeasurementArray([5, 6.2, 7, 7.8], error=0.1) data = q.XYDataSet(x, y) data.name = 'x vs. y' print('Name:', data.name) .. nboutput:: ipython3 Name = x vs. y ''' XYDataSet.unnamed_data_counter += 1 else: self.name = data_name if ydata is None and not is_histogram: print( "Error, if ydata is not given, explicitly specify that this is a histogram" ) elif ydata is None: #this is a histogram self.hist_data = xdata hist, edges = np.histogram(xdata, bins=bins) self.hist_bins = edges _xdata = edges[:-1] _xerr = np.zeros(_xdata.size) _ydata = hist _yerr = np.sqrt(hist) else: _xdata = xdata _xerr = xerr _ydata = ydata _yerr = yerr self.x = qe.MeasurementArray(_xdata, error=_xerr, name=xname, units=xunits) self.xdata = self.x.means self.xerr = self.x.stds self.xunits = self.x.get_units_str() self.xname = self.x.name self.y = qe.MeasurementArray(_ydata, error=_yerr, name=yname, units=yunits) self.ydata = self.y.means self.yerr = self.y.stds self.yunits = self.y.get_units_str() self.yname = self.y.name self.is_histogram = is_histogram self.bins = bins if self.x.size != self.y.size: print("Error: x and y data should have the same number of points") #TODO raise an error! else: self.npoints = self.x.size self.xyfitter = [] self.fit_pars = [] #stored as Measurement_Array self.fit_pcov = [] self.fit_pcorr = [] self.fit_function = [] self.fit_function_name = [] self.fit_npars = [] self.fit_yres = [] self.fit_chi2 = [] self.fit_ndof = [] self.fit_color = [] self.nfits = 0
def fit(self, dataset, fit_range=None, fit_count=0, name=None): ''' Perform a fit of the fit_function to a data set. :param dataset: The dataset to be fit. :type dataset: XYDataSet :param fit_range: The range to plot the fit on. :type fit_range: list :param fit_count: The number of the fit. :type fit_count: int :param name: The name of the fit function. :type name: str :returns: The parameters of the fit. :rtype: Measurement_Array ''' if self.fit_function is None: print("Error: fit function not set!") return #Grab the data xdata = dataset.xdata ydata = dataset.ydata xerr = dataset.xerr yerr = dataset.yerr nz = np.count_nonzero(yerr) if nz < ydata.size and nz != 0: print( "Warning: some errors on data are zero, switching to MC errors" ) dataset.y.error_method = "MC" yerr = dataset.y.stds #now, check again nz = np.count_nonzero(yerr) if nz < ydata.size and nz != 0: yerr[yerr == 0] = ydata[yerr == 0] / 1000000 #We're ok, modify the errors in the dataset to be the MC ones else: dataset.yerr = yerr #If user specified a fit range, reduce the data: if type(fit_range) in ARRAY and len(fit_range) is 2: indices = np.where( np.logical_and(xdata >= fit_range[0], xdata <= fit_range[1])) xdata = xdata[indices] ydata = ydata[indices] xerr = xerr[indices] yerr = yerr[indices] #if the x errors are not zero, convert them to equivalent errors in y #TODO: check the math on this... #The maximum number of function evaluations maxfev = 200 * (xdata.size + 1) if q.settings[ "fit_max_fcn_calls"] == -1 else q.settings["fit_max_fcn_calls"] try: warns = [] with warnings.catch_warnings(record=True) as w: warnings.simplefilter("always", sp.OptimizeWarning) self.fit_pars, self.fit_pcov = sp.curve_fit(self.fit_function, xdata, ydata, sigma=yerr, p0=self.parguess, maxfev=maxfev) warns = w if len(warns) > 0 and (self.fit_function == Rlinear or self.fit_function == Rpolynomial): p, V = np.polyfit(x=xdata, y=ydata, deg=self.fit_npars - 1, cov=True, w=1 / yerr) self.fit_pars = p[::-1] self.fit_pcov = np.flipud(np.fliplr(V)) self.fit_pars_err = np.sqrt(np.diag(self.fit_pcov)) except RuntimeError: print( "Error: Fit could not converge; are the y errors too small? Is the function defined?" ) print("Is the parameter guess good?") return None # Use derivative method to factor x error into fit if xerr.nonzero()[0].size: yerr_eff = np.sqrt((yerr**2 + np.multiply( xerr, num_der(lambda x: self.fit_function(x, *self.fit_pars), xdata)) **2)) try: warns = [] with warnings.catch_warnings(record=True) as w: warnings.simplefilter("always", sp.OptimizeWarning) self.fit_pars, self.fit_pcov = sp.curve_fit( self.fit_function, xdata, ydata, sigma=yerr_eff, p0=self.parguess, maxfev=maxfev) warns = w if len(warns) == 1 and (self.fit_function == Rlinear or self.fit_function == Rpolynomial): p, V = np.polyfit(x=xdata, y=ydata, deg=self.fit_npars - 1, cov=True, w=1 / yerr) self.fit_pars = p[::-1] self.fit_pcov = np.flipud(np.fliplr(V)) self.fit_pars_err = np.sqrt(np.diag(self.fit_pcov)) except RuntimeError: print( "Error: Fit could not converge; are the y errors too small? Is the function defined?" ) print("Is the parameter guess good?") return None #this should already be true, but let's be sure: self.fit_npars = self.fit_pars.size #This is to catch the case of scipy.optimize failing to determin #the covariance matrix for i in range(self.fit_npars): if self.fit_pars_err[i] == float( 'inf') or self.fit_pars_err[i] == float('nan'): #print("Warning: Error for fit parameter",i,"cannot be trusted") self.fit_pars_err[i] = 0 for j in range(self.fit_npars): if self.fit_pcov[i][j] == float( 'inf') or self.fit_pcov[i][j] == float('nan'): #print("Warning: Covariance between parameters",i,j,"cannot be trusted") self.fit_pcov[i][j] = 0. parnames = dataset.name + "_" + self.fit_function_name + "_fit{}".format( fit_count) + "_fitpars" self.fit_parameters = qe.MeasurementArray(self.fit_npars, name=parnames) for i in range(self.fit_npars): if self.fit_function_name is 'gaussian': if i is 0: name = 'mean' elif i is 1: name = 'sigma' elif i == 2: name = 'normalization' elif self.fit_function_name is 'linear': if i is 0: name = 'intercept' elif i is 1: name = 'slope' elif self.fit_function_name is 'exponential': if i is 0: name = 'amplitude' elif i is 1: name = 'decay-constant' else: name = 'par%d' % (i) name = parnames + "_" + name self.fit_parameters[i] = qe.Measurement(self.fit_pars[i], self.fit_pars_err[i], name=name) for i in range(self.fit_npars): for j in range(i + 1, self.fit_npars): self.fit_parameters[i].set_covariance(self.fit_parameters[j], self.fit_pcov[i][j]) #Calculate the residuals: yfit = self.fit_function(dataset.xdata, *self.fit_pars) self.fit_yres = qe.MeasurementArray((dataset.ydata - yfit), dataset.yerr) #Calculate the chi-squared: self.fit_chi2 = 0 for i in range(xdata.size): if self.fit_yres[i].std != 0: self.fit_chi2 += (self.fit_yres[i].mean / self.fit_yres[i].std)**2 self.fit_ndof = self.fit_yres.size - self.fit_npars - 1 return self.fit_parameters
def __init__(self, xdata, ydata=None, xerr=None, yerr=None, data_name=None, xname=None, xunits=None, yname=None, yunits=None, is_histogram=False, bins=50): '''Use MeasurementArray() to initialize a dataset''' if (data_name is None): self.name = "dataset{}".format(XYDataSet.unnamed_data_counter) XYDataSet.unnamed_data_counter += 1 else: self.name = data_name if ydata is None and not is_histogram: print( "Error, if ydata is not given, explicitly specify that this is a histogram" ) elif ydata is None: #this is a histogram self.hist_data = xdata hist, edges = np.histogram(xdata, bins=bins) self.hist_bins = edges _xdata = edges[:-1] _xerr = np.zeros(_xdata.size) _ydata = hist _yerr = np.sqrt(hist) else: _xdata = xdata _xerr = xerr _ydata = ydata _yerr = yerr self.x = qe.MeasurementArray(_xdata, error=_xerr, name=xname, units=xunits) self.xdata = self.x.get_means() self.xerr = self.x.get_stds() self.xunits = self.x.get_units_str() self.xname = self.x.name self.y = qe.MeasurementArray(_ydata, error=_yerr, name=yname, units=yunits) self.ydata = self.y.get_means() self.yerr = self.y.get_stds() self.yunits = self.y.get_units_str() self.yname = self.y.name self.is_histogram = is_histogram if self.x.size != self.y.size: print("Error: x and y data should have the same number of points") #TODO raise an error! else: self.npoints = self.x.size self.xyfitter = [] self.fit_pars = [] #stored as Measurement_Array self.fit_pcov = [] self.fit_pcorr = [] self.fit_function = [] self.fit_function_name = [] self.fit_npars = [] self.fit_yres = [] self.fit_chi2 = [] self.fit_ndof = [] self.fit_color = [] self.nfits = 0