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)
Exemplo n.º 3
0
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)
Exemplo n.º 4
0
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