def Fit(self, data=None, resolution_fit_mode="gauss", fit_primary=False, return_resolution=False,
            adjust_wave="model", continuum_fit_order=7, wavelength_fit_order=3, air_wave=True,
            fit_source=False, source_fcn=None, source_args=None, source_kwargs=None):

        self.resolution_fit_mode = resolution_fit_mode
        self.fit_source = fit_primary
        self.fit_source = fit_source
        self.adjust_wave = adjust_wave
        self.continuum_fit_order = continuum_fit_order
        self.wavelength_fit_order = wavelength_fit_order
        self.return_resolution = return_resolution
        self.air_wave = air_wave

        #Check if the user gave data to fit
        if data != None:
            self.ImportData(data)
        elif self.data == None:
            raise AttributeError("\n\nError! Must supply data to fit\n\n!")

        # Set up the source function
        if source_fcn is not None:
            self.source_fcn = source_fcn
            self.fit_source = True
            
        if self.fit_source:
            if source_args is not None:
                self.source_args = source_args
            if source_kwargs is not None:
                self.source_kwargs = source_kwargs


        #Make sure resolution bounds are given (resolution is always fit)
        idx = self.parnames.index("resolution")
        if len(self.bounds[idx]) < 2 and self.resolution_fit_mode != "SVD":
            print("Must give resolution bounds!")
            inp = raw_input("Enter the lowest and highest possible resolution, separated by a space: ")
            self.resolution_bounds = [float(inp.split()[0]), float(inp.split()[1])]


        #Make fitpars array
        fitpars = []
        for i, const_par in enumerate(self.const_pars):
            if self.fitting[i]:
                fitpars.append(const_par)
                self.normalization[i] = const_par
        if len(fitpars) < 1:
            print("\n\nError! Must fit at least one variable!\n\n")
            return

        #Transform fitpars to the bounded equivalents
        i = 0
        for fitting, parameter, bound, norm in zip(self.fitting, self.const_pars, self.bounds, self.normalization):
            if fitting:
                if bound[1] < np.inf:
                    fitpars[i] = np.arcsin(2.0*(fitpars[i] - bound[0])/(bound[1] - bound[0]) - 1.0)
                else:
                    fitpars[i] = np.sqrt((fitpars[i] - bound[0] + 1)**2 - 1.0)
                fitpars[i] /= norm
                i += 1


        #Set up the fitting logfile and logging arrays
        self.parvals = [[] for i in range(len(self.parnames))]
        self.chisq_vals = []
        outfile = open("chisq_summary.dat", "a")
        outfile.write("\n\n\n\n")
        for i in range(len(self.parnames)):
            if self.fitting[i]:
                outfile.write("%s\t" % self.parnames[i])
        outfile.write("X^2\n")
        outfile.close()


        #Perform the fit
        self.first_iteration = True
        errfcn = lambda pars: np.sum(self.FitErrorFunction(pars)**2)
        bounds = [self.bounds[i] for i in range(len(self.parnames)) if self.fitting[i]]
        optdict = {"rhobeg": [1, 5, 1000.0]}
        optdict = {"eps": 5}
        bfgs_optdict = {'disp': 2, 'pgtol': 1e-8, 'epsilon': 1, 'approx_grad': True}
        slsqp_optdict = {'disp': 2, 'eps': 1e-1}
        output = leastsq(self.FitErrorFunction, fitpars, full_output=True, epsfcn=1e-1)

        fitpars = output[0]
        logging.debug("Fit Message: {}".format(output[3]))

        #Save the best-fit values
        idx = 0
        for i in range(len(self.parnames)):
            if self.fitting[i]:
                self.const_pars[i] = fitpars[idx]
                idx += 1


        #Finally, return the best-fit model and other things. Add the same x-units they gave in the data to the spectra we return!
        if self.fit_source:
            if return_resolution:
                source, model, R = self.GenerateModel(fitpars, separate_source=True, return_resolution=return_resolution)
                source.x *= u.nm.to(self.xunits)
                model.x *= u.nm.to(self.xunits)
                return source, model, R

            else:
                source, model = self.GenerateModel(fitpars, separate_source=True, return_resolution=return_resolution)
                source.x *= u.nm.to(self.xunits)
                model.x *= u.nm.to(self.xunits)
                return source, model
                
        else:
            if return_resolution:
                model, R = self.GenerateModel(fitpars, return_resolution=return_resolution)
                model.x *= u.nm.to(self.xunits)
                return model, R
            else:
                model = self.GenerateModel(fitpars, return_resolution=return_resolution)
                model.x *= u.nm.to(self.xunits)
                return model
            


        ### -----------------------------------------------
The main fitting function. Before calling this, the user MUST
dataset/ETHPy150Open kgullikson88/Telluric-Fitter/src/TelluricFitter.py/TelluricFitter.Fit