def setUpClass(cls):
        gauss1 = funclib.gauss()
        pars = [-0.75, 1.0, 0.1, 1]
        gauss1.setup_parameters(values=pars)
        gauss2 = funclib.gauss()
        pars = [0.22, 1.0, 0.01, 0.0]
        vary = [True, True, True, False]
        gauss2.setup_parameters(values=pars, vary=vary)

        mymodel = fit.Model(functions=[gauss1, gauss2])

        np.random.seed(1111)
        x = np.linspace(0.5, 1.5, num=1000)
        y = mymodel.evaluate(x)
        noise = np.random.normal(0.0, 0.015, size=len(x))
        y = y + noise

        pars = [-0.70, 1.0, 0.11, 0.95]
        gauss1.setup_parameters(values=pars)
        pars = [0.27, 1.0, 0.005, 0.0]
        vary = [True, True, True, False]
        gauss2.setup_parameters(values=pars, vary=vary)

        cls.x = x
        cls.y = y
        cls.value1 = [-0.75, 1.0, 0.1, 1]
        cls.value2 = [0.22, 1.0, 0.01, 0.0]
        cls.fitModel = mymodel
 def setUpClass(cls):
     gauss1 = funclib.gauss()
     pars = [-0.75,1.0,0.1,1]
     gauss1.setup_parameters(values=pars)
     gauss2 = funclib.gauss()
     pars = [0.22,1.0,0.01,0.0]
     vary = [True, True, True, False]
     gauss2.setup_parameters(values=pars, vary=vary)
     
     mymodel = fit.Model(functions=[gauss1, gauss2])
     
     np.random.seed(1111)
     x = np.linspace(0.5,1.5, num=1000)
     y = mymodel.evaluate(x)
     noise = np.random.normal(0.0, 0.015, size=len(x))
     y = y+noise
     
     pars = [-0.70,1.0,0.11,0.95]
     gauss1.setup_parameters(values=pars)
     pars = [0.27,1.0,0.005,0.0]
     vary = [True, True, True, False]
     gauss2.setup_parameters(values=pars, vary=vary)
     
     cls.x = x
     cls.y = y
     cls.value1 = [-0.75,1.0,0.1,1]
     cls.value2 = [0.22,1.0,0.01,0.0]
     cls.fitModel = mymodel
Esempio n. 3
0
def fitLP(filename=None,lprof=None,theory=0,show=0,cfg='',convert_ms_kms=0,\
          vary_pars=['vexp'],i_vexp=15.0,i_gamma=1.0,do_gauss=0):
    '''
    Fit a line profile with a soft parabola, and a Gaussian component if 
    required. 
    
    The method automatically checks if a second component is needed (eg an 
    extra absorption component). An estimate of the expansion velocity (width 
    of the profile) and an improved guess of the vlsr are given. 
    
    A guess for the gas terminal velocity is returned, as well as its error and
    the fitted profile (sp/gaussian, and if applicable extra gaussian and the 
    full fit). 
    
    @keyword filename: The filename to the data file of the line profile. If 
                       None a line profile object is expected. 
                       
                       (default: None)
    @type filename: string
    @keyword lprof: A line profile object (LPDataReader or inheriting classes)
                    If None, a filename is expected! If not None, the results
                    are saved in this object as well as returned upon method 
                    call
                    
                    (default: None)
    @type lprof: LPDataReader()
    @keyword convert_ms_kms: Convert velocity grid from m/s to km/s.
    
                             (default: 0)
    @type convert_ms_kms: bool
    @keyword theory: If theoretical profile, and filename is given, set vlsr to
                     0 and read two columns. lprof not relevant if True.
                     
                     (default: 0)
    @type theory: bool
    @keyword vary_pars: The soft parabola parameters varied (can only be vexp
                        or gamma for now). The initial values for parameters
                        listed here are not used. If 'gamma' is requested, a 
                        reasonable guess for i_vexp when calling the method 
                        will improve the fitting results. This is done for the 
                        first guess only! If a Gaussian absorption is present
                        improving these first guesses won't make much of a 
                        difference. However, the first guess value for gamma
                        is still used. Vexp is always varied if absorption is 
                        present.
                        
                        (default: ['vexp'])                        
    @type vary_pars: list[string]
    @keyword i_vexp: The initial guess for the expansion velocity. Not relevant
                     if vexp is included in vary_pars.
                     
                     (default: 15.0)
    @type i_vexp: float
    @keyword i_gamma: The initial guess for the gamma parameter of soft parab.
                      Not relevant if gamma is included in vary_pars.
                      
                      (default: 1.0)
    @type i_gamma: float
    @keyword do_gauss: Force a Gaussian fit regardless of soft parabola fit 
                       results. Still does the soft parabola fit first to allow
                       for comparison of parameters.
                        
                       (default: 0)
    @type do_gauss: bool
    @keyword show: Show the results of the fit
                    
                   (default: 0)
    @type show: bool
    
    @return: dictionary including [vexp,evexp,gamma,egamma,fitprof,gaussian,\
             fullfit,dintint,fgintint] 
    @rtype: dict[float,float,float,float,funclib.Function(),\
                 funclib.Function(),funclib.Function()]
    
    '''

    print '*******************************************'
    if theory and filename <> None:
        d = DataIO.readCols(filename=filename)
        vel = d[0]
        flux = d[1]
        vlsr = 0.0
    else:
        if filename is None:
            filename = lprof.filename
        print '** Fitting line profile in %s.' % filename
        if lprof is None:
            lprof = readLineProfile(filename)
        vel = lprof.getVelocity()
        flux = lprof.getFlux()
        vel = vel[-np.isnan(flux)]
        flux = flux[-np.isnan(flux)]
        vlsr = lprof.getVlsr()

    if convert_ms_kms:
        vel = vel / 1000.
    #-- Initial values: [peak tmb,vlsr,vexp,gamma]
    #   For the central peak value, get a first guess from the data
    #   Attempt multiple vexp values and return the best fitting case.
    #   The initial values are given, with an arbitrary value for the vexp key
    i_mid = argmin(np.abs(vel - vlsr))
    peak = mean(flux[i_mid - 2:i_mid + 3])

    #-- Vary vexp or gamma if requested. If not requested i_vexp or i_gamma are
    #   used.
    #   Multiple values for gamma are tried and the best fitting model
    #   is then chosen based on the relative error of the fitted gamma.
    if 'gamma' in vary_pars:
        igammas = array([-0.5, -0.1, 0.1, 0.5, 1.0, 2.0, 4.0])
        firstguess = varyInitialFit(vel,flux,[peak,vlsr,i_vexp,0.0],index=3,\
                                    values=igammas,vary_window=1,vary=[1,1,1,1],\
                                    function=funclib.soft_parabola)
        i_gamma = firstguess.get_parameters()[0][3]
    #-- varyInitialFit adapts the velocity window itself. No more
    #   assumptions needed for the expansion velocity
    ivexps = array([50., 40., 30., 25., 20., 15., 10.])
    if 'vexp' in vary_pars:
        firstguess = varyInitialFit(vel,flux,[peak,vlsr,0.,i_gamma],index=2,\
                                    values=ivexps,vary_window=1,vary=[1,1,1,1],\
                                    function=funclib.soft_parabola)

    vexp = abs(firstguess.get_parameters()[0][2])
    window = 2.
    print 'First guess fit, using a soft parabola:'
    print firstguess.param2str(accuracy=5)

    #-- If vexp > 100, replace with 50. This value is unrealistic, and might be
    #   improved with an extra Gaussian. If not, it will be replaced with a
    #   full Gaussian fit anyway
    if vexp > 100: vexp = 50.
    #-- Check whether irregularities are present in the profile.
    #   Initial parameters for a gaussian are returned if true.
    #   For this, a broad selection is made of the profile, to allow for a
    #   decent noise determination outside the line profile
    keep = np.abs(vel - vlsr) <= (2 * window * vexp)
    velsel, fluxsel = vel[keep], flux[keep]
    include_gauss = checkLPShape(velsel,
                                 fluxsel,
                                 vlsr,
                                 vexp,
                                 window,
                                 show=show)

    #-- Do the fit of the line again, including an extra gaussian if
    #   irregularities are present.
    if include_gauss <> None:
        #-- fit soft para model + gaussian
        #   1. Set up new soft parabola for several guesses of vexp
        ivexps = list(ivexps)
        initial = [peak, vlsr, 0., i_gamma]
        all_init = [[p] * len(ivexps) for i, p in enumerate(initial) if i != 2]
        all_init.insert(2, ivexps)
        functions = [funclib.soft_parabola() for i in ivexps]
        [
            ff.setup_parameters(values=initi)
            for ff, initi in zip(functions, zip(*all_init))
        ]
        #   2. setup gaussian
        gaussians = [funclib.gauss() for ff in functions]
        #   initial guesses assuming an interstellar absorption line from the
        #   checkLPShape method
        [
            gg.setup_parameters(values=include_gauss,
                                vary=[True, True, True, False])
            for gg in gaussians
        ]
        #   3. combine soft para + gaussian, and minimize fit
        mymodels = [
            fit.Model(functions=[ff, gg])
            for ff, gg in zip(functions, gaussians)
        ]
        [fit.minimize(vel[np.abs(vel-vlsr)<=(init[2]*1.5)],\
                      flux[np.abs(vel-vlsr)<=(init[2]*1.5)],\
                      mymodel)
         for mymodel,init in zip(mymodels,zip(*all_init))]
        #   4. Select the best fitting result based on the error on vexp
        mymodels = [fg for fg in mymodels if fg.get_parameters()[1][2] != 0.]
        functions = [
            ff for fg, ff in zip(mymodels, functions)
            if fg.get_parameters()[1][2] != 0.
        ]
        gaussians = [
            gg for fg, gg in zip(mymodels, gaussians)
            if fg.get_parameters()[1][2] != 0.
        ]
        fitvalues = array([fg.get_parameters()[0][2] for fg in mymodels])
        fiterrors = array([fg.get_parameters()[1][2] for fg in mymodels])
        mymodel = mymodels[argmin(abs(fiterrors / fitvalues))]
        finalfit = functions[argmin(abs(fiterrors / fitvalues))]
        gaussian = gaussians[argmin(abs(fiterrors / fitvalues))]
        print 'Improved fit, including extra Gaussian:'
        print mymodel.param2str(accuracy=5)
    else:
        #-- if gamma is requested to be varied, allow another iteration on
        #   gamma with the best vexp guess we already have.
        if 'gamma' in vary_pars:
            finalfit = varyInitialFit(vel,flux,[peak,vlsr,vexp,0.0],\
                                      index=3,values=igammas,vary_window=1,\
                                      function=funclib.soft_parabola,\
                                      vary=[True,True,True,True])
            print 'Final fit with soft parabola, second gamma iteration:'
            print finalfit.param2str(accuracy=5)
        #-- firstguess is best we can do at the moment
        else:
            finalfit = firstguess

    #-- If the relative error on vexp is larger than 30%, usually something
    #   funky is going on in the emission line. Try a Gaussian instead.
    fvlsr = finalfit.get_parameters()[0][1]
    fevlsr = finalfit.get_parameters()[1][1]
    vexp = abs(finalfit.get_parameters()[0][2])
    evexp = abs(finalfit.get_parameters()[1][2])
    gamma = finalfit.get_parameters()[0][3]
    egamma = finalfit.get_parameters()[1][3]
    #-- Gamma has to be positive. If it isnt, dont bother with Gaussian
    #   (double peaked line profile will not be fitted well with a Gaussian!)
    if (evexp/vexp > 0.40 and gamma > 0) or (evexp/vexp > 0.20 and vexp> 30.) \
            or do_gauss:
        #-- Go back to default window to try a Gaussian fit
        #keep = np.abs(vel-vlsr)<=(80)
        #velselg,fluxselg = vel[keep],flux[keep]
        do_gauss = 1
        include_gauss = None
        #-- FWHM is twice vexp!
        sigmas = 2 * ivexps / (2. * sqrt(2. * log(2.)))
        finalfit = varyInitialFit(vel,flux,[peak,vlsr,0.,0.],index=2,\
                                  values=sigmas,function=funclib.gauss,\
                                  vary_window=1,vary=[True,True,True,False])
        vexp = abs(
            finalfit.get_parameters()[0][2]) * (2. * sqrt(2. * log(2.))) / 2.
        evexp = abs(
            finalfit.get_parameters()[1][2]) * (2. * sqrt(2. * log(2.))) / 2.
        fvlsr = finalfit.get_parameters()[0][1]
        fevlsr = finalfit.get_parameters()[1][1]
        gamma, egamma = None, None
        window = 3.
        print 'Improved fit, using a gaussian instead of soft parabola:'
        print finalfit.param2str(accuracy=5)

    #-- Compute numerical integrations.
    #   After fitting, window for integration should be 0.6*window. vexp is
    #   not expected to be too small anymore as in checkLPShape
    keep = np.abs(vel - vlsr) <= (0.6 * window * vexp)
    velsel = vel[keep]
    flux_first = firstguess.evaluate(velsel)
    flux_final = finalfit.evaluate(velsel)
    dimb = trapz(y=flux[keep], x=velsel)
    fi_final = trapz(y=flux_final, x=velsel)
    print('I_mb (emission line data): %f'\
          %dimb)
    print('I_mb (SP -- initial guess): %f'\
          %trapz(y=flux_first,x=velsel))
    print('I_mb (SP -- final guess): %f'\
          %fi_final)
    if include_gauss <> None:
        fitted_flux = mymodel.evaluate(velsel)
        print('I_mb (SP + Gauss fit): %f'\
              %trapz(y=fitted_flux,x=velsel))
    print('Final v_exp guess: %.4f +/- %.4f km/s' % (vexp, evexp))
    if gamma <> None:
        print('Final gamma guess: %.4f +/- %.4f' % (gamma, egamma))
    print('Final vlsr guess: %.4f +/- %.4f' % (fvlsr, fevlsr))
    fwhm = getLPDataFWHM(lprof)
    print('The FWHM is %.2f km/s.' % (fwhm))

    #-- plot
    if show or cfg:
        plt.clf()
        #-- improve velocity window for plotting
        keep = np.abs(vel - vlsr) <= (1.5 * window * vexp)
        velsel, fluxsel = vel[keep], flux[keep]
        vel_highres = np.linspace(velsel[0], velsel[-1], 10000)
        flux_final_highres = finalfit.evaluate(vel_highres)
        flux_first_highres = firstguess.evaluate(vel_highres)
        if include_gauss <> None:
            flux_full_highres = mymodel.evaluate(vel_highres)
        if show:
            plt.step(velsel,fluxsel,'-r',where='mid',lw=3,\
                     label='Observed profile')
            plt.plot(vel_highres,flux_first_highres,'b-',lw=3,\
                     label='First guess')
            plt.plot(vel_highres,flux_final_highres,'g--',lw=3,\
                     label='Improved guess')
            if include_gauss <> None:
                plt.plot(vel_highres,flux_full_highres,'g-',lw=2,\
                         label='Full fit (including Gaussian)')
            leg = plt.legend(loc='best', fancybox=True)
            leg.get_frame().set_alpha(0.5)
            plt.show()
        if cfg:
            pf = '%s_fitted_%s'%(do_gauss and 'gaussFit' or 'SPFit',\
                                 os.path.split(filename)[1])
            keytags = ['Observed profile', 'Improved guess']
            line_types = [
                '-r',
                '-b',
            ]
            x = [velsel, vel_highres]
            y = [fluxsel, flux_final_highres]
            if include_gauss <> None:
                line_types.append('g--')
                x.append(vel_highres)
                y.append(flux_full_highres)
                keytags.append('Full fit (including Gaussian)')
            pf = Plotting2.plotCols(x=x,y=y,filename=pf,cfg=cfg,linewidth=5,\
                                    yaxis='$T_\mathrm{mb}\ (\mathrm{K})$',\
                                    xaxis='$v (\mathrm{km}/\mathrm{s})$',\
                                    keytags=keytags,line_types=line_types,\
                                    histoplot=[0])
            print 'Your figure can be found at %s .' % pf
    #-- Collecting all relevant results and returning.
    results = dict()
    #-- If a Gaussian was used for the main profile fit
    results['do_gauss'] = do_gauss
    #-- Fitted parameters and errors
    results['vlsr'] = fvlsr
    results['evlsr'] = fevlsr
    results['vexp'] = vexp
    results['evexp'] = evexp
    results['fwhm'] = fwhm
    #-- Gamma is None if no soft parabola was fitted
    results['gamma'] = gamma
    results['egamma'] = egamma

    #-- Integrated line strengths: main line fit, data themselves, fit window
    results['fgintint'] = fi_final
    results['dintint'] = dimb
    results['intwindow'] = window * 0.6

    #-- Saving parameters for later evaluation. Full fit is accessible by
    #   making the functions separately and setting pars, then using fit.Model
    results['fitprof'] = (do_gauss and 'gauss' or 'soft_parabola',\
                          list(finalfit.get_parameters()[0]))
    if include_gauss <> None:
        results['fitabs'] = ('gauss', list(gaussian.get_parameters()[0]))
    else:
        results['fitabs'] = None

    return results
Esempio n. 4
0
def fitLP(
    filename=None,
    lprof=None,
    theory=0,
    show=0,
    cfg="",
    convert_ms_kms=0,
    vary_pars=["vexp"],
    i_vexp=15.0,
    i_gamma=1.0,
    do_gauss=0,
):

    """
    Fit a line profile with a soft parabola, and a Gaussian component if 
    required. 
    
    The method automatically checks if a second component is needed (eg an 
    extra absorption component). An estimate of the expansion velocity (width 
    of the profile) and an improved guess of the vlsr are given. 
    
    A guess for the gas terminal velocity is returned, as well as its error and
    the fitted profile (sp/gaussian, and if applicable extra gaussian and the 
    full fit). 
    
    @keyword filename: The filename to the data file of the line profile. If 
                       None a line profile object is expected. 
                       
                       (default: None)
    @type filename: string
    @keyword lprof: A line profile object (LPDataReader or inheriting classes)
                    If None, a filename is expected! If not None, the results
                    are saved in this object as well as returned upon method 
                    call
                    
                    (default: None)
    @type lprof: LPDataReader()
    @keyword convert_ms_kms: Convert velocity grid from m/s to km/s.
    
                             (default: 0)
    @type convert_ms_kms: bool
    @keyword theory: If theoretical profile, and filename is given, set vlsr to
                     0 and read two columns. lprof not relevant if True.
                     
                     (default: 0)
    @type theory: bool
    @keyword vary_pars: The soft parabola parameters varied (can only be vexp
                        or gamma for now). The initial values for parameters
                        listed here are not used. If 'gamma' is requested, a 
                        reasonable guess for i_vexp when calling the method 
                        will improve the fitting results. This is done for the 
                        first guess only! If a Gaussian absorption is present
                        improving these first guesses won't make much of a 
                        difference. However, the first guess value for gamma
                        is still used. Vexp is always varied if absorption is 
                        present.
                        
                        (default: ['vexp'])                        
    @type vary_pars: list[string]
    @keyword i_vexp: The initial guess for the expansion velocity. Not relevant
                     if vexp is included in vary_pars.
                     
                     (default: 15.0)
    @type i_vexp: float
    @keyword i_gamma: The initial guess for the gamma parameter of soft parab.
                      Not relevant if gamma is included in vary_pars.
                      
                      (default: 1.0)
    @type i_gamma: float
    @keyword do_gauss: Force a Gaussian fit regardless of soft parabola fit 
                       results. Still does the soft parabola fit first to allow
                       for comparison of parameters.
                        
                       (default: 0)
    @type do_gauss: bool
    @keyword show: Show the results of the fit
                    
                   (default: 0)
    @type show: bool
    
    @return: dictionary including [vexp,evexp,gamma,egamma,fitprof,gaussian,\
             fullfit,dintint,fgintint] 
    @rtype: dict[float,float,float,float,funclib.Function(),\
                 funclib.Function(),funclib.Function()]
    
    """

    print "*******************************************"
    if theory and filename <> None:
        d = DataIO.readCols(filename=filename)
        vel = d[0]
        flux = d[1]
        vlsr = 0.0
    else:
        if filename is None:
            filename = lprof.filename
        print "** Fitting line profile in %s." % filename
        if lprof is None:
            lprof = readLineProfile(filename)
        vel = lprof.getVelocity()
        flux = lprof.getFlux()
        vel = vel[-np.isnan(flux)]
        flux = flux[-np.isnan(flux)]
        vlsr = lprof.getVlsr()

    if convert_ms_kms:
        vel = vel / 1000.0
    # -- Initial values: [peak tmb,vlsr,vexp,gamma]
    #   For the central peak value, get a first guess from the data
    #   Attempt multiple vexp values and return the best fitting case.
    #   The initial values are given, with an arbitrary value for the vexp key
    i_mid = argmin(np.abs(vel - vlsr))
    peak = mean(flux[i_mid - 2 : i_mid + 3])

    # -- Vary vexp or gamma if requested. If not requested i_vexp or i_gamma are
    #   used.
    #   Multiple values for gamma are tried and the best fitting model
    #   is then chosen based on the relative error of the fitted gamma.
    if "gamma" in vary_pars:
        igammas = array([-0.5, -0.1, 0.1, 0.5, 1.0, 2.0, 4.0])
        firstguess = varyInitialFit(
            vel,
            flux,
            [peak, vlsr, i_vexp, 0.0],
            index=3,
            values=igammas,
            vary_window=1,
            vary=[1, 1, 1, 1],
            function=funclib.soft_parabola,
        )
        i_gamma = firstguess.get_parameters()[0][3]
    # -- varyInitialFit adapts the velocity window itself. No more
    #   assumptions needed for the expansion velocity
    ivexps = array([50.0, 40.0, 30.0, 25.0, 20.0, 15.0, 10.0])
    if "vexp" in vary_pars:
        firstguess = varyInitialFit(
            vel,
            flux,
            [peak, vlsr, 0.0, i_gamma],
            index=2,
            values=ivexps,
            vary_window=1,
            vary=[1, 1, 1, 1],
            function=funclib.soft_parabola,
        )

    vexp = abs(firstguess.get_parameters()[0][2])
    window = 2.0
    print "First guess fit, using a soft parabola:"
    print firstguess.param2str(accuracy=5)

    # -- If vexp > 100, replace with 50. This value is unrealistic, and might be
    #   improved with an extra Gaussian. If not, it will be replaced with a
    #   full Gaussian fit anyway
    if vexp > 100:
        vexp = 50.0
    # -- Check whether irregularities are present in the profile.
    #   Initial parameters for a gaussian are returned if true.
    #   For this, a broad selection is made of the profile, to allow for a
    #   decent noise determination outside the line profile
    keep = np.abs(vel - vlsr) <= (2 * window * vexp)
    velsel, fluxsel = vel[keep], flux[keep]
    include_gauss = checkLPShape(velsel, fluxsel, vlsr, vexp, window, show=show)

    # -- Do the fit of the line again, including an extra gaussian if
    #   irregularities are present.
    if include_gauss <> None:
        # -- fit soft para model + gaussian
        #   1. Set up new soft parabola for several guesses of vexp
        ivexps = list(ivexps)
        initial = [peak, vlsr, 0.0, i_gamma]
        all_init = [[p] * len(ivexps) for i, p in enumerate(initial) if i != 2]
        all_init.insert(2, ivexps)
        functions = [funclib.soft_parabola() for i in ivexps]
        [ff.setup_parameters(values=initi) for ff, initi in zip(functions, zip(*all_init))]
        #   2. setup gaussian
        gaussians = [funclib.gauss() for ff in functions]
        #   initial guesses assuming an interstellar absorption line from the
        #   checkLPShape method
        [gg.setup_parameters(values=include_gauss, vary=[True, True, True, False]) for gg in gaussians]
        #   3. combine soft para + gaussian, and minimize fit
        mymodels = [fit.Model(functions=[ff, gg]) for ff, gg in zip(functions, gaussians)]
        [
            fit.minimize(
                vel[np.abs(vel - vlsr) <= (init[2] * 1.5)], flux[np.abs(vel - vlsr) <= (init[2] * 1.5)], mymodel
            )
            for mymodel, init in zip(mymodels, zip(*all_init))
        ]
        #   4. Select the best fitting result based on the error on vexp
        mymodels = [fg for fg in mymodels if fg.get_parameters()[1][2] != 0.0]
        functions = [ff for fg, ff in zip(mymodels, functions) if fg.get_parameters()[1][2] != 0.0]
        gaussians = [gg for fg, gg in zip(mymodels, gaussians) if fg.get_parameters()[1][2] != 0.0]
        fitvalues = array([fg.get_parameters()[0][2] for fg in mymodels])
        fiterrors = array([fg.get_parameters()[1][2] for fg in mymodels])
        mymodel = mymodels[argmin(abs(fiterrors / fitvalues))]
        finalfit = functions[argmin(abs(fiterrors / fitvalues))]
        gaussian = gaussians[argmin(abs(fiterrors / fitvalues))]
        print "Improved fit, including extra Gaussian:"
        print mymodel.param2str(accuracy=5)
    else:
        # -- if gamma is requested to be varied, allow another iteration on
        #   gamma with the best vexp guess we already have.
        if "gamma" in vary_pars:
            finalfit = varyInitialFit(
                vel,
                flux,
                [peak, vlsr, vexp, 0.0],
                index=3,
                values=igammas,
                vary_window=1,
                function=funclib.soft_parabola,
                vary=[True, True, True, True],
            )
            print "Final fit with soft parabola, second gamma iteration:"
            print finalfit.param2str(accuracy=5)
        # -- firstguess is best we can do at the moment
        else:
            finalfit = firstguess

    # -- If the relative error on vexp is larger than 30%, usually something
    #   funky is going on in the emission line. Try a Gaussian instead.
    fvlsr = finalfit.get_parameters()[0][1]
    fevlsr = finalfit.get_parameters()[1][1]
    vexp = abs(finalfit.get_parameters()[0][2])
    evexp = abs(finalfit.get_parameters()[1][2])
    gamma = finalfit.get_parameters()[0][3]
    egamma = finalfit.get_parameters()[1][3]
    # -- Gamma has to be positive. If it isnt, dont bother with Gaussian
    #   (double peaked line profile will not be fitted well with a Gaussian!)
    if (evexp / vexp > 0.40 and gamma > 0) or (evexp / vexp > 0.20 and vexp > 30.0) or do_gauss:
        # -- Go back to default window to try a Gaussian fit
        # keep = np.abs(vel-vlsr)<=(80)
        # velselg,fluxselg = vel[keep],flux[keep]
        do_gauss = 1
        include_gauss = None
        # -- FWHM is twice vexp!
        sigmas = 2 * ivexps / (2.0 * sqrt(2.0 * log(2.0)))
        finalfit = varyInitialFit(
            vel,
            flux,
            [peak, vlsr, 0.0, 0.0],
            index=2,
            values=sigmas,
            function=funclib.gauss,
            vary_window=1,
            vary=[True, True, True, False],
        )
        vexp = abs(finalfit.get_parameters()[0][2]) * (2.0 * sqrt(2.0 * log(2.0))) / 2.0
        evexp = abs(finalfit.get_parameters()[1][2]) * (2.0 * sqrt(2.0 * log(2.0))) / 2.0
        fvlsr = finalfit.get_parameters()[0][1]
        fevlsr = finalfit.get_parameters()[1][1]
        gamma, egamma = None, None
        window = 3.0
        print "Improved fit, using a gaussian instead of soft parabola:"
        print finalfit.param2str(accuracy=5)

    # -- Compute numerical integrations.
    #   After fitting, window for integration should be 0.6*window. vexp is
    #   not expected to be too small anymore as in checkLPShape
    keep = np.abs(vel - vlsr) <= (0.6 * window * vexp)
    velsel = vel[keep]
    flux_first = firstguess.evaluate(velsel)
    flux_final = finalfit.evaluate(velsel)
    dimb = trapz(y=flux[keep], x=velsel)
    fi_final = trapz(y=flux_final, x=velsel)
    print ("I_mb (emission line data): %f" % dimb)
    print ("I_mb (SP -- initial guess): %f" % trapz(y=flux_first, x=velsel))
    print ("I_mb (SP -- final guess): %f" % fi_final)
    if include_gauss <> None:
        fitted_flux = mymodel.evaluate(velsel)
        print ("I_mb (SP + Gauss fit): %f" % trapz(y=fitted_flux, x=velsel))
    print ("Final v_exp guess: %.4f +/- %.4f km/s" % (vexp, evexp))
    if gamma <> None:
        print ("Final gamma guess: %.4f +/- %.4f" % (gamma, egamma))
    print ("Final vlsr guess: %.4f +/- %.4f" % (fvlsr, fevlsr))
    fwhm = getLPDataFWHM(lprof)
    print ("The FWHM is %.2f km/s." % (fwhm))

    # -- plot
    if show or cfg:
        plt.clf()
        # -- improve velocity window for plotting
        keep = np.abs(vel - vlsr) <= (1.5 * window * vexp)
        velsel, fluxsel = vel[keep], flux[keep]
        vel_highres = np.linspace(velsel[0], velsel[-1], 10000)
        flux_final_highres = finalfit.evaluate(vel_highres)
        flux_first_highres = firstguess.evaluate(vel_highres)
        if include_gauss <> None:
            flux_full_highres = mymodel.evaluate(vel_highres)
        if show:
            plt.step(velsel, fluxsel, "-r", where="mid", lw=3, label="Observed profile")
            plt.plot(vel_highres, flux_first_highres, "b-", lw=3, label="First guess")
            plt.plot(vel_highres, flux_final_highres, "g--", lw=3, label="Improved guess")
            if include_gauss <> None:
                plt.plot(vel_highres, flux_full_highres, "g-", lw=2, label="Full fit (including Gaussian)")
            leg = plt.legend(loc="best", fancybox=True)
            leg.get_frame().set_alpha(0.5)
            plt.show()
        if cfg:
            pf = "%s_fitted_%s" % (do_gauss and "gaussFit" or "SPFit", os.path.split(filename)[1])
            keytags = ["Observed profile", "Improved guess"]
            line_types = ["-r", "-b"]
            x = [velsel, vel_highres]
            y = [fluxsel, flux_final_highres]
            if include_gauss <> None:
                line_types.append("g--")
                x.append(vel_highres)
                y.append(flux_full_highres)
                keytags.append("Full fit (including Gaussian)")
            pf = Plotting2.plotCols(
                x=x,
                y=y,
                filename=pf,
                cfg=cfg,
                linewidth=5,
                yaxis="$T_\mathrm{mb}\ (\mathrm{K})$",
                xaxis="$v (\mathrm{km}/\mathrm{s})$",
                keytags=keytags,
                line_types=line_types,
                histoplot=[0],
            )
            print "Your figure can be found at %s ." % pf
    # -- Collecting all relevant results and returning.
    results = dict()
    # -- If a Gaussian was used for the main profile fit
    results["do_gauss"] = do_gauss
    # -- Fitted parameters and errors
    results["vlsr"] = fvlsr
    results["evlsr"] = fevlsr
    results["vexp"] = vexp
    results["evexp"] = evexp
    results["fwhm"] = fwhm
    # -- Gamma is None if no soft parabola was fitted
    results["gamma"] = gamma
    results["egamma"] = egamma

    # -- Integrated line strengths: main line fit, data themselves, fit window
    results["fgintint"] = fi_final
    results["dintint"] = dimb
    results["intwindow"] = window * 0.6

    # -- Saving parameters for later evaluation. Full fit is accessible by
    #   making the functions separately and setting pars, then using fit.Model
    results["fitprof"] = (do_gauss and "gauss" or "soft_parabola", list(finalfit.get_parameters()[0]))
    if include_gauss <> None:
        results["fitabs"] = ("gauss", list(gaussian.get_parameters()[0]))
    else:
        results["fitabs"] = None

    return results