def test_specfit(rawdata, noise, error, params): for i in range(100): passed = True parameter_noise = [ params[0] + abs(np.random.randn()) * parameter_error_amplitude[0], params[1] + abs(np.random.randn()) * parameter_error_amplitude[1], params[2] + abs(np.random.randn()) * parameter_error_amplitude[2] ] guesses = np.array(params) + parameter_noise sp = Spectrum(xarr=xarr, data=rawdata + noise, error=error) # sp.plotter(axis=plt.gca(), errstyle='fill') sp.specfit(guesses=guesses) assertion = ((np.array(sp.specfit.fitter.mpp) - np.array(params)) / parameter_noise)**2 print('(mpp - params / param_noise )^2 = ', assertion) for j, result in enumerate(assertion): if strict_assertion: assert result < 2 if result >= 2: passed = False continue if passed: for j in range(3): passes['passes'][j] += 1 passes['avg_difference'][j] += abs(sp.specfit.fitter.mpp[j] - params[j]) else: for j in range(3): fails['fails'][j] += 1 fails['avg_difference'][j] += abs(sp.specfit.fitter.mpp[j] - params[j]) # plt.show() for i, j in enumerate(passes['avg_difference']): if passes['passes'][i]: passes['avg_difference'][i] = j / passes['passes'][i] for i, j in enumerate(fails['avg_difference']): if fails['fails'][i]: fails['avg_difference'][i] = j / fails['fails'][i] print('passes:', passes) print('fails:', fails)
def test_specfit(rawdata, noise, error, params): for i in range(100): passed = True parameter_noise = [ params[0] + abs(np.random.randn()) * parameter_error_amplitude[0], params[1] + abs(np.random.randn()) * parameter_error_amplitude[1], params[2] + abs(np.random.randn()) * parameter_error_amplitude[2], ] guesses = np.array(params) + parameter_noise sp = Spectrum(xarr=xarr, data=rawdata + noise, error=error) # sp.plotter(axis=plt.gca(), errstyle='fill') sp.specfit(guesses=guesses) assertion = ((np.array(sp.specfit.fitter.mpp) - np.array(params)) / parameter_noise) ** 2 print("(mpp - params / param_noise )^2 = ", assertion) for j, result in enumerate(assertion): if strict_assertion: assert result < 2 if result >= 2: passed = False continue if passed: for j in range(3): passes["passes"][j] += 1 passes["avg_difference"][j] += abs(sp.specfit.fitter.mpp[j] - params[j]) else: for j in range(3): fails["fails"][j] += 1 fails["avg_difference"][j] += abs(sp.specfit.fitter.mpp[j] - params[j]) # plt.show() for i, j in enumerate(passes["avg_difference"]): if passes["passes"][i]: passes["avg_difference"][i] = j / passes["passes"][i] for i, j in enumerate(fails["avg_difference"]): if fails["fails"][i]: fails["avg_difference"][i] = j / fails["fails"][i] print("passes:", passes) print("fails:", fails)
def test_moments(): xvals = np.linspace(-100, 100, 200) * u.km / u.s # Some models will fail without a center frequency and a velocity convention xarr = SpectroscopicAxis(xvals, velocity_convention='radio', center_frequency=100 * u.GHz) # creating the random data rawdata = np.random.randn(xarr.size) # creating a sample Spectrum from a .fits file sp = Spectrum('test.fits') for model_name in sp.specfit.Registry.multifitters.keys(): print('testing:', model_name) model = sp.specfit.Registry.multifitters[model_name] params = model.moments(xarr, rawdata, vheight=False) print('params from moments:', params) assert len(params) == model.npars # if this call does not raise an Exception then moments() produced # the correct number of parameters model.n_modelfunc(pars=params)(xarr)
def do_specfit(filename, lines=["NIIa + Halp + NIIb", "Hbet", "Hgam", "Hdel", "Ca H + Ca K", "Mg", "NaI", "OIIIa + OIIIb"], fix_lambda=True, smooth_size=3, verbose=False, verbose_print=True): ''' Given a FITS file, fit the specified lines to the spectra. ''' if verbose_print: print "Running on " + filename spec_file = fits.open(filename) flux = spec_file[1].data["flux"] # Correct for redshift lam_wav = 10**spec_file[1].data["loglam"] / (1 + spec_file[2].data["Z"]) # Correct for vacuum-to-air lam_wav = vac_to_air(lam_wav) # Optionally smooth the spectrum if smooth_size != 0: flux = median_filter(flux, smooth_size) spec = Spectrum(data=flux, xarr=lam_wav, header=spec_file[1].header, unit="", xarrkwargs={'unit': 'Angstroms'}) line_params = [] line_errs = [] for i, line in enumerate(lines): line_props = line_dict[line] num_lines = len(line_props) / 3 spec_line = spec.slice(start=line_props[1]-100, stop=line_props[-2]+100, units='Angstroms') if verbose: spec_line.plotter() spec_line.baseline(order=1, subract=False, annotate=False) # Estimate the amplitude of the line after background subtraction # using the peak of where the line is expected to be baseline_model = lambda x, p: p[1] + p[0]*x base_params = spec_line.baseline.baselinepars for i in range(num_lines): lam_line = find_nearest(lam_wav, line_props[3*i+1]) line_props[3*i] = float(flux[np.argwhere(lam_wav == lam_line)]) - \ baseline_model(lam_line, base_params) if fix_lambda: fix = [False, True, False] * num_lines else: fix = [False] * len(line_props) if num_lines > 1: multifit = True else: multifit = False try: spec_line.specfit(guesses=line_props, fixed=fix, fittype="gaussian", multifit=multifit) line_pars = spec_line.specfit.modelpars line_errors = spec_line.specfit.modelerrs except ValueError: line_pars = [0.0] * 3 * num_lines line_errors = [0.0] * 3 * num_lines except mpfitException: line_pars = [np.NaN] * 3 * num_lines line_errors = [np.NaN] * 3 * num_lines # For multifits, a bad fit for a line that isn't there increases the # error on a fit for a line that is. Remove # if num_lines > 1: # t_stats = [np.logical_and(np.abs(k)/j < 1, j != 0) # for k, j in zip(line_pars, line_errors)] # if np.any(t_stats): # posn = [f for f, j in enumerate(t_stats) if j] # bad_line = [] # for pos in posn: # for n in range(1, num_lines+1): # if pos < 3*i and pos > 3*(i-1): # bad_line.append(n) # break # # If they're both bad, just continue # if len(bad_line) == num_lines: # pass # else: # bad_line = np.sort(bad_line)[::-1] # for bad in bad_line: # bad = int(bad) - 1 # for p in range(3)[::-1]: # line_props.pop(3*bad + p) # fix.pop(3*bad + p) # if (num_lines - len(bad_line)) == 1: # multifit = False # spec_line.specfit(guesses=line_props, # fixed=fix, # fittype="gaussian", # multifit=multifit) # good_line = \ # np.asarray(list(set(range(1, num_lines+1)) & set(bad_line))) # good_line -= 1 # for good in good_line: # line_pars[3*(good-1):3*good] = spec_line.specfit.modelpars # line_errors[3*(good-1):3*good] = spec_line.specfit.modelerrs line_params.extend(line_pars) line_errs.extend(line_errors) if verbose: raw_input("Continue?") rows = len(line_params) / 3 line_params = np.array(line_params).reshape((rows, 3)) line_errs = np.array(line_errs).reshape((rows, 3)) # No point in saving lambda if it is fixed. if fix_lambda: line_params = np.hstack([line_params[:, 0], line_params[:, -1]]) line_errs = np.hstack([line_errs[:, 0], line_errs[:, -1]]) line_param_names = ['Amplitude', 'Width', 'Amplitude Error', 'Width Error'] line_names = [] for line in lines: line = line.split(" + ") if len(line) > 1: for l in line: line_names.append(l) else: line_names.append(line[0]) line_and_par_names = [] for par in line_param_names: for name in line_names: line_and_par_names.append(name+" "+par) # Return as a named series, which can be concatenated into a dataframe. ser = Series(np.hstack([line_params, line_errs]).ravel(), index=line_and_par_names) return ser