Ejemplo n.º 1
0
    def ConvolveSmooth(self, numiters=10, lowreject=2, highreject=3):
        done = False
        data = self.smoothing_data.copy()
        # data.y /= data.cont
        iterations = 0
        if self.window_size % 2 == 0:
            self.window_size += 1

        while not done and iterations < numiters:
            iterations += 1
            done = True
            y = FittingUtilities.savitzky_golay(data.y, self.window_size, 5)
            #s = np.r_[data.y[self.window_size/2:0:-1], data.y, data.y[-1:-self.window_size/2:-1]]
            #y = np.convolve(window/window.sum(), s, mode='valid')

            reduced = data.y / y
            sigma = np.std(reduced)
            mean = np.mean(reduced)
            badindices = \
            np.where(np.logical_or((reduced - mean) / sigma < -lowreject, (reduced - mean) / sigma > highreject))[0]
            if badindices.size > 0:
                done = False
                data.y[badindices] = y[badindices]

        return DataStructures.xypoint(x=self.smoothing_data.x, y=y / self.smoothing_data.cont)
Ejemplo n.º 2
0
def ReadFile(fname, blaze=None):
    try:
        orders = HelperFunctions.ReadFits(fname)
    except ValueError:
        orders = HelperFunctions.ReadFits(fname, errors=2)
    orders = orders[::-1]  # Reverse order so the bluest order is first

    #Need to blaze-correct the later data
    if int(os.path.split(fname)[1][2:7]) > 50400 and blaze is not None:
        print "\tBlaze correcting!"
        try:
            blaze_orders = HelperFunctions.ReadFits(blaze)
        except ValueError:
            blaze_orders = HelperFunctions.ReadFits(blaze, errors=2)
        blaze_orders = blaze_orders[::
                                    -1]  # Reverse order so the bluest order is first
        blazecorrect = True
    else:
        blazecorrect = False

    for i, order in enumerate(orders):
        if blazecorrect:
            b = blaze_orders[i].y / blaze_orders[i].y.mean()
            #plt.plot(order.x, b, 'g-', alpha=0.4)
            order.y /= b
        order.cont = FittingUtilities.Continuum(order.x,
                                                order.y,
                                                fitorder=2,
                                                lowreject=2,
                                                highreject=5)
        #plt.plot(order.x, order.y, 'k-', alpha=0.4)
        #plt.plot(order.x, order.cont, 'r-', alpha=0.4)
        orders[i] = order.copy()
    #plt.show()
    return orders
def fit_rv_shift(template, orders):
    template_lines = []
    order_lines = []
    for t, o in zip(template, orders):
        plt.plot(t.x, t.y/t.cont, 'k-', alpha=0.4)
        plt.plot(o.x, o.y/o.cont, 'r-', alpha=0.5)

        tlines = FittingUtilities.FindLines(t, tol=0.8)
        olines = FittingUtilities.FindLines(o, tol=0.8)
        if len(tlines) == 0 or len(tlines) != len(olines):
            continue
        template_lines.append(t.x[tlines])
        order_lines.append(o.x[olines])
    template_lines = np.hstack(template_lines)
    order_lines = np.hstack(order_lines)
    rv = (np.median(order_lines/template_lines) - 1.0)*c
    #plt.scatter(template_lines, order_lines)
    #plt.plot(plt.xlim(), plt.xlim(), 'r--')
    plt.scatter(template_lines, order_lines - template_lines*(1.+rv/c))
    plt.show()
    return rv
Ejemplo n.º 4
0
  def FitErrorFunction(self, fitpars):
    """
    The error function for the fitter. This should never be called directly!
    """
    if self.return_resolution:
      model, resolution = self.GenerateModel(fitpars, return_resolution=True)
    else:
      model = self.GenerateModel(fitpars)
    outfile = open("chisq_summary.dat", 'a')
    weights = 1.0 / self.data.err**2

    #Find the regions to use (ignoring the parts that were defined as bad)
    good = numpy.arange(self.data.x.size, dtype=numpy.int32)
    for region in self.ignore:
      x0 = min(region)
      x1 = max(region)
      tmp1 = [self.data.x[i] in self.data.x[good] for i in range(self.data.x.size)]
      tmp2 = numpy.logical_or(self.data.x<x0, self.data.x>x1)
      good = numpy.where(numpy.logical_and(tmp1, tmp2))[0]

    
    return_array = (self.data.y - self.data.cont*model.y)[good]**2 * weights[good]
    #Evaluate bound conditions and output the parameter value to the logfile.
    fit_idx = 0
    for i in range(len(self.bounds)):
      if self.fitting[i]:
        if len(self.bounds[i]) == 2:
          return_array += FittingUtilities.bound(self.bounds[i], fitpars[fit_idx])
        outfile.write("%.12g\t" %fitpars[fit_idx])
        self.parvals[i].append(fitpars[fit_idx])
        fit_idx += 1
      elif len(self.bounds[i]) == 2 and self.parnames[i] != "resolution":
        return_array += FittingUtilities.bound(self.bounds[i], self.const_pars[i])
    outfile.write("%g\n" %(numpy.sum(return_array)/float(weights.size)))
    
    self.chisq_vals.append(numpy.sum(return_array)/float(weights.size))
    print "X^2 = ", numpy.sum(return_array)/float(weights.size)
    outfile.close()
    
    return return_array
Ejemplo n.º 5
0
  def ResolutionFitError(self, resolution, data, model):
    """
    This function gets called by scipy.optimize.fminbound in FitResolution.
    Not meant to be called directly by the user!
    """
    resolution = max(1000.0, float(int(float(resolution) + 0.5)))
    if self.debug and self.debug_level >= 5:
      print "Saving inputs for R = ", resolution
      print " to Debug_ResFit.log and Debug_ResFit2.log"
      numpy.savetxt("Debug_ResFit.log", numpy.transpose((data.x, data.y, data.cont)))
      numpy.savetxt("Debug_Resfit2.log", numpy.transpose((model.x, model.y)))
    newmodel = FittingUtilities.ReduceResolution(model, resolution, extend=False)
    newmodel = FittingUtilities.RebinData(newmodel, data.x, synphot=False)

    #Find the regions to use (ignoring the parts that were defined as bad)
    good = numpy.arange(self.data.x.size, dtype=numpy.int32)
    for region in self.ignore:
      x0 = min(region)
      x1 = max(region)
      tmp1 = [self.data.x[i] in self.data.x[good] for i in range(self.data.x.size)]
      tmp2 = numpy.logical_or(self.data.x<x0, self.data.x>x1)
      good = numpy.where(numpy.logical_and(tmp1, tmp2))[0]

    weights = 1.0/data.err**2
    returnvec = (data.y - data.cont*newmodel.y)[good]**2 * weights[good] + FittingUtilities.bound(self.resolution_bounds, resolution)
    if self.debug:
      print "Resolution-fitting X^2 = ", numpy.sum(returnvec)/float(good.size), "at R = ", resolution
    if numpy.isnan(numpy.sum(returnvec**2)):
      print "Error! NaN found in ResolutionFitError!"
      outfile=open("ResolutionFitError.log", "a")
      outfile.write("#Error attempting R = %g\n" %(resolution))
      numpy.savetxt(outfile, numpy.transpose((data.x, data.y, data.cont, newmodel.x, newmodel.y)), fmt="%.10g")
      outfile.write("\n\n\n\n")
      numpy.savetxt(outfile, numpy.transpose((model.x, model.y)), fmt="%.10g")
      outfile.write("\n\n\n\n")
      outfile.close()
      raise ValueError
    return returnvec
Ejemplo n.º 6
0
            print "\n***************************\nFitting order %i: " % (i)
            order = orders[i]
            fitter.AdjustValue({
                "wavestart": order.x[0] - 20.0,
                "waveend": order.x[-1] + 20.0,
                "o2": 0.0,
                "h2o": humidity,
                "resolution": resolution
            })
            fitpars = [
                fitter.const_pars[j] for j in range(len(fitter.parnames))
                if fitter.fitting[j]
            ]
            order.cont = FittingUtilities.Continuum(order.x,
                                                    order.y,
                                                    fitorder=3,
                                                    lowreject=1.5,
                                                    highreject=10)
            fitter.ImportData(order)
            fitter.resolution_fit_mode = "gauss"
            fitter.fit_source = False
            fitter.fit_primary = False
            model = fitter.GenerateModel(fitpars,
                                         separate_source=False,
                                         return_resolution=False)

            # Find the best scale factor
            model.cont = np.ones(model.size())
            lines = FittingUtilities.FindLines(model, tol=0.95).astype(int)
            if len(lines) > 5:
                scale = np.median(
def make_matrices():
    # Find all the relevant files
    #allfiles = [f for f in os.listdir("./") if f.startswith("RV") and f.endswith("-0.fits")]
    allfiles = [f for f in os.listdir("./") if f.startswith("RV") and '-0' in f and f.endswith("corrected.fits")]

    # Read in the measured RV data
    bjd, rv = np.loadtxt("psi1draa_100_120_mcomb1.dat", usecols=(0,1), unpack=True)
    bjd2, vbary_arr = np.loadtxt("psi1draa_100p_28_37_ASW.dat", usecols=(0,5), unpack=True)

    # Put all the data in one giant list
    alldata = []
    print "Reading all data"
    for i, fname in enumerate(allfiles):
        header = fits.getheader(fname)
        jd = header['jd']
        #vbary = GenericSearch.HelCorr(header, observatory="McDonald")
        idx = np.argmin(abs(bjd2 - jd))
        bjd2_i = bjd2[idx]
        vbary = vbary_arr[idx] / 1000.0
        idx = np.argmin(abs(bjd - jd))
        bjd_i = bjd[idx]
        vstar = rv[idx]/1e3
        print(fname, vbary, vstar)
        vel = vbary - vstar  #Closest... but still not great
        #vel = -vbary + vstar  #NO
        #vel = vbary + vstar  #NO
        #vel = -vbary - vstar  #NO
        #vel = vstar  #NO
        #vel = -vstar #NO
        #vel = vbary  #Surprisingly not bad...
        orders = HelperFunctions.ReadExtensionFits(fname)[:-2]
        for j in badorders[::-1]:
            orders.pop(j)
        if i == 0:
            template = []
            for j, order in enumerate(orders):
                order.x *= (1.0+vel/c)
                orders[j] = order.copy()
                template.append(order.copy())
                alldata.append([order])
            #template = [o.copy() for o in orders]
        else:
            vel = fit_rv_shift_old(template, orders)
            print('RV adjustment = {}'.format(vel))
            for j, order in enumerate(orders):
                order.x *= (1.0+vel/c)
                orders[j] = order.copy()
                if i == 0:
                    alldata.append([order])
                    #template.append(order.copy())
                else:
                    alldata[j].append(order)
                    #plt.plot(order.x, order.y/order.cont, 'g-', alpha=0.5)
            #plt.show()


    # Interpolate each order to a single wavelength grid
    print "Interpolating to wavelength grid"
    xgrids = []
    c_cycler = itertools.cycle(('r', 'g', 'b', 'k'))
    ls_cycler = itertools.cycle(('-', '--', ':', '-.'))
    for i, order in enumerate(alldata):
        print "Order ", i+1
        firstwaves = [d.x[0] for d in order]
        lastwaves = [d.x[-1] for d in order]
        size = np.mean([d.size() for d in order])
        xgrid = np.linspace(max(firstwaves), min(lastwaves), size)
        for j, data in enumerate(order):
            tmp = FittingUtilities.RebinData(data, xgrid)
            order[j] = tmp.y/tmp.cont

            #if i == 20:
            #    col = c_cycler.next()
            #    if j%4 == 0:
            #        ls = ls_cycler.next()
            #    plt.plot(xgrid, order[j], color=col, ls=ls, alpha=0.8, label=allfiles[j])
            #plt.plot(xgrid, order[j], 'k-', alpha=0.2)
        alldata[i] = np.array(order)
        xgrids.append(xgrid)
    #plt.legend(loc='best')
    #plt.show()

    return allfiles, xgrids, alldata
Ejemplo n.º 8
0
def get_ccfs(T=4000,
             vsini=5,
             logg=4.5,
             metal=0.5,
             hdf_file='Cross_correlations/CCF.hdf5',
             xgrid=np.arange(-400, 400, 1),
             addmode='simple'):
    """
    Get the cross-correlation functions for the given parameters, for all stars
    """
    ccfs = []
    filenames = []
    rv_shift = {} if T > 6000 else pickle.load(open('rvs.pkl'))
    with h5py.File(hdf_file) as f:
        starname = 'psi1 Dra A'
        date_list = f[starname].keys()
        for date in date_list:
            datasets = f[starname][date].keys()
            for ds_name in datasets:
                ds = f[starname][date][ds_name]
                if (ds.attrs['T'] == T and ds.attrs['vsini'] == vsini
                        and ds.attrs['logg'] == logg
                        and ds.attrs['[Fe/H]'] == metal
                        and ds.attrs['addmode'] == addmode):
                    vel, corr = ds.value
                    #ccf = spline(vel[::-1]*-1, (1.0-corr[::-1]))
                    ccf = spline(vel[::-1] * -1, corr[::-1])
                    #ccf = spline(vel, corr)
                    fname = ds.attrs['fname']
                    vbary = get_rv_correction(fname)

                    #cont = FittingUtilities.Continuum(xgrid, ccf(xgrid-vbary), fitorder=2, lowreject=2.5, highreject=5)
                    #normed_ccf = ccf(xgrid-vbary)/cont
                    cont = FittingUtilities.Continuum(xgrid,
                                                      ccf(xgrid - vbary),
                                                      fitorder=2,
                                                      lowreject=5,
                                                      highreject=2.5)
                    normed_ccf = ccf(xgrid - vbary) - cont

                    if T <= 6000:
                        centroid = rv_shift[fname]
                        #centroid = xgrid[np.argmax(normed_ccf)]
                        #top = 1.0
                        #amp = 1.0 - min(normed_ccf)
                        top = 0.0
                        amp = max(normed_ccf)
                        #idx = np.argmin(np.abs(xgrid-centroid))
                        #amp = normed_ccfs[idx]
                    else:
                        gauss_pars = fit_gaussian(xgrid, normed_ccf)
                        centroid = gauss_pars[2]
                        amp = gauss_pars[1]
                        top = gauss_pars[0]
                        amp = 0.5
                    print(centroid, fname)

                    #cont = FittingUtilities.Continuum(xgrid, ccf(xgrid-vbary+centroid), fitorder=2, lowreject=2.5, highreject=5)
                    #normed_ccf = (ccf(xgrid-vbary+centroid) / cont - top)  * 0.5/abs(amp) + top
                    cont = FittingUtilities.Continuum(xgrid,
                                                      ccf(xgrid - vbary +
                                                          centroid),
                                                      fitorder=2,
                                                      lowreject=5,
                                                      highreject=2.5)
                    normed_ccf = (ccf(xgrid - vbary + centroid) -
                                  cont) * 0.5 / abs(amp)

                    filenames.append(fname)
                    ccfs.append(normed_ccf)
                    rv_shift[fname] = centroid

    if T > 6000:
        pickle.dump(rv_shift, open('rvs.pkl', 'w'))

    return np.array(ccfs), filenames
Ejemplo n.º 9
0
                orders.pop(numorders - 1 - i)
            else:
                order.cont = FittingUtilities.Continuum(order.x, order.y, lowreject=3, highreject=3)
                orders[numorders - 1 - i] = order.copy()

        """
        for i, order in enumerate(orders):
          plt.plot(order.x, order.y/order.cont+i)
          plt.show()
        sys.exit()
        """

        #Smooth data
        if smooth:
            for order in orders:
                order.y /= FittingUtilities.savitzky_golay(order.y, 91, 5)

        output_dir = "Cross_correlations/"
        outfilebase = fname.split(".fits")[0]
        if "/" in fname:
            dirs = fname.split("/")
            output_dir = ""
            outfilebase = dirs[-1].split(".fits")[0]
            for directory in dirs[:-1]:
                output_dir = output_dir + directory + "/"
            output_dir = output_dir + "Cross_correlations/"
        #Do the cross-correlation
        for vsini in [10, 20, 30, 40]:
            Correlate.PyCorr2(orders, resolution=60000, outdir=output_dir, models=model_data, stars=star_list,
                              temps=temp_list, gravities=gravity_list, metallicities=metal_list,
                              vsini=vsini * units.km.to(units.cm), debug=False, outfilebase=outfilebase)
Ejemplo n.º 10
0
    def MakeModel(self,
                  pressure=795.0,
                  temperature=283.0,
                  lowfreq=4000,
                  highfreq=4600,
                  angle=45.0,
                  humidity=50.0,
                  co2=368.5,
                  o3=3.9e-2,
                  n2o=0.32,
                  co=0.14,
                  ch4=1.8,
                  o2=2.1e5,
                  no=1.1e-19,
                  so2=1e-4,
                  no2=1e-4,
                  nh3=1e-4,
                  hno3=5.6e-4,
                  lat=30.6,
                  alt=2.1,
                  wavegrid=None,
                  resolution=None,
                  save=False,
                  libfile=None,
                  vac2air=True):
        """
        Here is the important function! All of the variables have default values,
          which you will want to override for any realistic use.

        :param pressure:       Pressure at telescope altitude (hPa)
        :param temperature:    Temperature at telescope altitude (Kelvin)
        :param lowfreq:        The starting wavenumber (cm^-1)
        :param highfreq:       The ending wavenumber (cm^-1)
        :param angle:          The zenith distance of the telescope (degrees). This is related to
                               the airmass (z) through z = sec(angle)
        :param humidity:       Percent relative humidity at the telescope altitude.
        :param co2:            Mixing ratio of this molecule (parts per million by volumne)
        :param o3:             Mixing ratio of this molecule (parts per million by volumne)
        :param n2o:            Mixing ratio of this molecule (parts per million by volumne)
        :param co:             Mixing ratio of this molecule (parts per million by volumne)
        :param ch4:            Mixing ratio of this molecule (parts per million by volumne)
        :param o2:             Mixing ratio of this molecule (parts per million by volumne)
        :param no:             Mixing ratio of this molecule (parts per million by volumne)
        :param so2:            Mixing ratio of this molecule (parts per million by volumne)
        :param no2:            Mixing ratio of this molecule (parts per million by volumne)
        :param nh3:            Mixing ratio of this molecule (parts per million by volumne)
        :param hno3:           Mixing ratio of this molecule (parts per million by volumne)
        :param lat:            The latitude of the observatory (degrees)
        :param alt:            The altitude of the observatory above sea level (km)
        :param wavegrid:       If given, the model will be resampled to this grid.
                               Should be a 1D np array
        :param resolution:     If given, it will reduce the resolution by convolving
                               with a gaussian of appropriate width. Should be a float
                               with R=lam/dlam
        :param save:           If true, the generated model is saved. The filename will be
                               printed to the screen.
        :param libfile:        Useful if generating a telluric library. The filename of the
                               saved file will be written to this filename. Should be a string
                               variable. Ignored if save==False
        :param vac2air:        If True (default), it converts the wavelengths from vacuum to air
        
        :return:               DataStructures.xypoint instance with the telluric model. The x-axis
                               is in nanometers and the y-axis is in fractional transmission.
        """

        self.FindWorkingDirectory()

        #Make the class variables local
        TelluricModelingDir = self.TelluricModelingDir
        debug = self.debug
        lock = self.lock
        layers = np.array(self.layers)
        ModelDir = self.ModelDir

        #Make a deep copy of atmosphere so that I don't repeatedly modify it
        Atmosphere = copy.deepcopy(self.Atmosphere)

        #Convert from relative humidity to concentration (ppm)
        h2o = humidity_to_ppmv(humidity, temperature, pressure)

        #Start by scaling the abundances from those at 'alt' km
        #  (linearly interpolate)
        keys = sorted(Atmosphere.keys())
        lower = max(0, np.searchsorted(keys, alt) - 1)
        upper = min(lower + 1, len(keys) - 1)
        if lower == upper:
            raise ZeroDivisionError(
                "Observatory altitude of %g results in the surrounding layers being the same!"
                % alt)
        scale_values = list(Atmosphere[lower])
        scale_values[2] = list(Atmosphere[lower][2])
        scale_values[0] = (Atmosphere[upper][0] - Atmosphere[lower][0]) / (
            keys[upper] - keys[lower]) * (alt -
                                          keys[lower]) + Atmosphere[lower][0]
        scale_values[1] = (Atmosphere[upper][1] - Atmosphere[lower][1]) / (
            keys[upper] - keys[lower]) * (alt -
                                          keys[lower]) + Atmosphere[lower][1]
        for mol in range(len(scale_values[2])):
            scale_values[2][mol] = (
                Atmosphere[upper][2][mol] -
                Atmosphere[lower][2][mol]) / (keys[upper] - keys[lower]) * (
                    alt - keys[lower]) + Atmosphere[lower][2][mol]

        #Do the actual scaling
        pressure_scalefactor = (scale_values[0] - pressure) * np.exp(
            -(layers - alt)**2 / (2.0 * 10.0**2))
        temperature_scalefactor = (scale_values[1] - temperature) * np.exp(
            -(layers - alt)**2 / (2.0 * 10.0**2))
        for i, layer in enumerate(layers):
            # Atmosphere[layer][0] -= pressure_scalefactor[i]
            Atmosphere[layer][0] *= pressure / scale_values[0]
            Atmosphere[layer][1] -= temperature_scalefactor[i]
            Atmosphere[layer][2][0] *= h2o / scale_values[2][0]
            Atmosphere[layer][2][1] *= co2 / scale_values[2][1]
            Atmosphere[layer][2][2] *= o3 / scale_values[2][2]
            Atmosphere[layer][2][3] *= n2o / scale_values[2][3]
            Atmosphere[layer][2][4] *= co / scale_values[2][4]
            Atmosphere[layer][2][5] *= ch4 / scale_values[2][5]
            Atmosphere[layer][2][6] *= o2 / scale_values[2][6]
            Atmosphere[layer][2][7] *= no / scale_values[2][7]
            Atmosphere[layer][2][8] *= so2 / scale_values[2][8]
            Atmosphere[layer][2][9] *= no2 / scale_values[2][9]
            Atmosphere[layer][2][10] *= nh3 / scale_values[2][10]
            Atmosphere[layer][2][11] *= hno3 / scale_values[2][11]

        #Now, Read in the ParameterFile and edit the necessary parameters
        parameters = MakeTape5.ReadParFile(parameterfile=TelluricModelingDir +
                                           "ParameterFile")
        parameters[48] = "%.1f" % lat
        parameters[49] = "%.1f" % alt
        parameters[51] = "%.5f" % angle
        parameters[17] = lowfreq
        freq, transmission = np.array([]), np.array([])

        #Need to run lblrtm several times if the wavelength range is too large.
        maxdiff = 1999.9
        if (highfreq - lowfreq > maxdiff):
            while lowfreq + maxdiff <= highfreq:
                parameters[18] = lowfreq + maxdiff

                MakeTape5.WriteTape5(parameters,
                                     output=TelluricModelingDir + "TAPE5",
                                     atmosphere=Atmosphere)

                #Run lblrtm
                cmd = "cd " + TelluricModelingDir + ";sh runlblrtm_v3.sh"
                try:
                    if self.print_lblrtm_output:
                        command = subprocess.check_call(cmd, shell=True)
                    if not self.print_lblrtm_output:
                        command = subprocess.check_call(
                            cmd,
                            shell=True,
                            stdout=subprocess.DEVNULL,
                            stderr=subprocess.DEVNULL)

                except subprocess.CalledProcessError:
                    raise subprocess.CalledProcessError(
                        "Error: Command '{}' failed in directory {}".format(
                            cmd, TelluricModelingDir))

                #Read in TAPE12, which is the output of LBLRTM
                freq, transmission = self.ReadTAPE12(TelluricModelingDir,
                                                     appendto=(freq,
                                                               transmission))
                lowfreq = lowfreq + 2000.00001
                parameters[17] = lowfreq

        parameters[18] = highfreq
        MakeTape5.WriteTape5(parameters,
                             output=TelluricModelingDir + "TAPE5",
                             atmosphere=Atmosphere)

        #Run lblrtm for the last time
        cmd = "cd " + TelluricModelingDir + ";sh runlblrtm_v3.sh"
        try:
            if self.print_lblrtm_output:
                command = subprocess.check_call(cmd, shell=True)
            if not self.print_lblrtm_output:
                command = subprocess.check_call(cmd,
                                                shell=True,
                                                stdout=subprocess.DEVNULL,
                                                stderr=subprocess.DEVNULL)

        except subprocess.CalledProcessError:
            raise subprocess.CalledProcessError(
                "Error: Command '{}' failed in directory {}".format(
                    cmd, TelluricModelingDir))

        #Read in TAPE12, which is the output of LBLRTM
        freq, transmission = self.ReadTAPE12(TelluricModelingDir,
                                             appendto=(freq, transmission))

        #Convert from frequency to wavelength units
        wavelength = units.cm.to(units.nm) / freq

        #Correct for index of refraction of air (use IAU standard conversion from
        #  Morton, D. C. 1991, ApJS, 77, 119
        if vac2air:
            wave_A = wavelength * units.nm.to(
                units.angstrom)  # Wavelength in angstroms
            n = 1.0 + 2.735182e-4 + 131.4182 / wave_A**2 + 2.76249e8 / wave_A**4
            wavelength /= n

        if save:
            #Output filename
            model_name = ModelDir + "transmission" + "-%.2f" % pressure + "-%.2f" % temperature + "-%.1f" % humidity + "-%.1f" % angle + "-%.2f" % (
                co2) + "-%.2f" % (o3 * 100) + "-%.2f" % ch4 + "-%.2f" % (co *
                                                                         10)
            logging.info(
                "All done! Output Transmission spectrum is located in the file below:\n\t\t{}"
                .format(model_name))

            np.savetxt(model_name,
                       np.transpose((wavelength[::-1], transmission[::-1])),
                       fmt="%.8g")
            if libfile != None:
                infile = open(libfile, "a")
                infile.write(model_name + "\n")
                infile.close()

        self.Cleanup()  #Un-lock the working directory

        if wavegrid != None:
            model = DataStructures.xypoint(x=wavelength[::-1],
                                           y=transmission[::-1])
            return FittingUtilities.RebinData(model, wavegrid)

        return DataStructures.xypoint(x=wavelength[::-1], y=transmission[::-1])
Ejemplo n.º 11
0
  def GenerateModel(self, pars, nofit=False, separate_primary=False, return_resolution=False):
    """
    This function does the actual work of generating a model with the given parameters,
    fitting the continuum, making sure the model and data are well aligned in
    wavelength, and fitting the detector resolution. In general, it is not meant to be
    called directly by the user. However, the 'nofit' keyword turns this into a wrapper
    to MakeModel.Modeler().MakeModel() with all the appropriate parameters.

    """
    data = self.data
    #Update self.const_pars to include the new values in fitpars
    #  I know, it's confusing that const_pars holds some non-constant parameters...
    fit_idx = 0
    for i in range(len(self.parnames)):
      if self.fitting[i]:
        self.const_pars[i] = pars[fit_idx]
        fit_idx += 1
    self.DisplayVariables(fitonly=True)
    
    #Extract parameters from pars and const_pars. They will have variable
    #  names set from self.parnames
    fit_idx = 0
    for i in range(len(self.parnames)):
      #Assign to local variables by the parameter name
      if self.fitting[i]:
        exec("%s = %g" %(self.parnames[i], pars[fit_idx]))
        fit_idx += 1
      else:
        exec("%s = %g" %(self.parnames[i], self.const_pars[i]))
      
      #Make sure everything is within its bounds
      if len(self.bounds[i]) > 0:
        lower = self.bounds[i][0]
        upper = self.bounds[i][1]
        exec("%s = %g if %s < %g else %s" %(self.parnames[i], lower, self.parnames[i], lower, self.parnames[i]))
        exec("%s = %g if %s > %g else %s" %(self.parnames[i], upper, self.parnames[i], upper, self.parnames[i]))

    
    wavenum_start = 1e7/waveend
    wavenum_end = 1e7/wavestart
    lat = self.observatory["latitude"]
    alt = self.observatory["altitude"]
    

    #Generate the model:
    model = self.Modeler.MakeModel(pressure, temperature, wavenum_start, wavenum_end, angle, h2o, co2, o3, n2o, co, ch4, o2, no, so2, no2, nh3, hno3, lat=lat, alt=alt, wavegrid=None, resolution=None)
    
    #Shift the x-axis, using the shift from previous iterations
    if self.debug:
      print "Shifting by %.4g before fitting model" %self.shift
    if self.adjust_wave == "data":
      data.x += self.shift
    elif self.adjust_wave == "model":
      model.x -= self.shift

    #Save each model if debugging
    if self.debug and self.debug_level >= 5:
      FittingUtilities.ensure_dir("Models/")
      model_name = "Models/transmission"+"-%.2f" %pressure + "-%.2f" %temperature + "-%.1f" %h2o + "-%.1f" %angle + "-%.2f" %(co2) + "-%.2f" %(o3*100) + "-%.2f" %ch4 + "-%.2f" %(co*10)
      numpy.savetxt(model_name, numpy.transpose((model.x, model.y)), fmt="%.8f")
      
    #Interpolate to constant wavelength spacing
    xgrid = numpy.linspace(model.x[0], model.x[-1], model.x.size)
    model = FittingUtilities.RebinData(model, xgrid)

    #Use nofit if you want a model with reduced resolution. Probably easier
    #  to go through MakeModel directly though...
    if data == None or nofit:
      return FittingUtilities.ReduceResolution(model, resolution)

    

    model_original = model.copy()
  
    #Reduce to initial guess resolution
    if (resolution - 10 < self.resolution_bounds[0] or resolution+10 > self.resolution_bounds[1]):
      resolution = numpy.mean(self.resolution_bounds)
    model = FittingUtilities.ReduceResolution(model, resolution)
    model = FittingUtilities.RebinData(model, data.x)
    
    
    #Shift the data (or model) by a constant offset. This gets the wavelength calibration close
    shift = FittingUtilities.CCImprove(data, model, tol=0.1)
    if self.adjust_wave == "data":
      data.x += shift
    elif self.adjust_wave == "model":
      model_original.x -= shift
      # In this case, we need to adjust the resolution again
      model = FittingUtilities.ReduceResolution(model_original.copy(), resolution)
      model = FittingUtilities.RebinData(model, data.x)
    else:
      sys.exit("Error! adjust_wave parameter set to invalid value: %s" %self.adjust_wave)
    self.shift += shift

    
    resid = data.y/model.y
    nans = numpy.isnan(resid)
    resid[nans] = data.cont[nans]
      
    #As the model gets better, the continuum will be less affected by
    #  telluric lines, and so will get better
    data.cont = FittingUtilities.Continuum(data.x, resid, fitorder=self.continuum_fit_order, lowreject=2, highreject=3)
    
    if separate_primary or self.fit_source:
      print "Generating Primary star model"
      primary_star = data.copy()
      primary_star.y = FittingUtilities.Iterative_SV(resid/data.cont, 61, 4, lowreject=2, highreject=3)
      data.cont *= primary_star.y



    
    if self.debug and self.debug_level >= 4:
      print "Saving data and model arrays right before fitting the wavelength"
      print "  and resolution to Debug_Output1.log"
      numpy.savetxt("Debug_Output1.log", numpy.transpose((data.x, data.y, data.cont, model.x, model.y)))

      
    #Fine-tune the wavelength calibration by fitting the location of several telluric lines
    modelfcn, mean = self.FitWavelength(data, model.copy(), fitorder=self.wavelength_fit_order)
      
    if self.adjust_wave == "data":
      test = data.x - modelfcn(data.x - mean)
      xdiff = [test[j] - test[j-1] for j in range(1, len(test)-1)]
      if min(xdiff) > 0 and numpy.max(numpy.abs(test - data.x)) < 0.1 and min(test) > 0:
        print "Adjusting data wavelengths by at most %.8g nm" %numpy.max(test - model.x)
        data.x = test.copy()
      else:
        print "Warning! Wavelength calibration did not succeed!"
    elif self.adjust_wave == "model":
      test = model_original.x + modelfcn(model_original.x - mean)
      test2 = model.x + modelfcn(model.x - mean)
      xdiff = [test[j] - test[j-1] for j in range(1, len(test)-1)]
      if min(xdiff) > 0 and numpy.max(numpy.abs(test2 - model.x)) < 0.1 and min(test) > 0 and abs(test[0] - data.x[0]) < 50 and abs(test[-1] - data.x[-1]) < 50:
        print "Adjusting wavelength calibration by at most %.8g nm" %max(test2 - model.x)
        model_original.x = test.copy()
        model.x = test2.copy()
      else:
        print "Warning! Wavelength calibration did not succeed!"
        
    else:
      sys.exit("Error! adjust_wave set to an invalid value: %s" %self.adjust_wave)

    if self.debug and self.debug_level >= 4:
      print "Saving data and model arrays after fitting the wavelength"
      print "  and before the resolution fit to Debug_Output2.log"
      numpy.savetxt("Debug_Output2.log", numpy.transpose((data.x, data.y, data.cont, model.x, model.y)))

      
    #Fit instrumental resolution
    done = False
    while not done:
      done = True
      if "SVD" in self.resolution_fit_mode and min(model.y) < 0.95:
        model, self.broadstuff = self.Broaden(data.copy(), model_original.copy(), full_output=True)
      elif "gauss" in self.resolution_fit_mode:
        model, resolution = self.FitResolution(data.copy(), model_original.copy(), resolution)
      else:
        done = False
        print "Resolution fit mode set to an invalid value: %s" %self.resolution_fit_mode
        self.resolution_fit_mode = raw_input("Enter a valid mode (SVD or guass): ")
    
    
    self.data = data
    self.first_iteration = False
    if separate_primary:
      if return_resolution:
        return primary_star, model, resolution
      else:
        return primary_star, model
    else:
      #if self.fit_source:
      #  data.cont /= primary_star.y
      if return_resolution:
        return model, resolution
      return model
Ejemplo n.º 12
0
def Filter(fname, vsini=100, numiters=100, lowreject=3, highreject=3):
    orders = FitsUtils.MakeXYpoints(fname, extensions=True, x="wavelength", y="flux", errors="error")
    column_list = []
    for i, order in enumerate(orders):
        smoothed = HelperFunctions.IterativeLowPass(
            order, vsini * units.km.to(units.cm), numiter=numiters, lowreject=lowreject, highreject=highreject
        )
        plt.plot(order.x, order.y)
        plt.plot(order.x, smoothed)
        plt.show()
        continue

        done = False
        x = order.x.copy()
        y = order.y.copy()
        indices = np.array([True] * x.size)
        iteration = 0
        while not done and iteration < numiters:
            done = True
            iteration += 1
            smoothed = FittingUtilities.savitzky_golay(y, window_size, smoothorder)
            residuals = y / smoothed
            if iteration == 1:
                # Save the first and last points, for interpolation
                first, last = smoothed[0], smoothed[-1]
            mean = residuals.mean()
            std = residuals.std()
            print residuals.size, x.size, y.size
            # plt.plot((residuals - mean)/std)
            # plt.show()
            badindices = np.where(
                np.logical_or((residuals - mean) / std > highreject, (residuals - mean) / std < -lowreject)
            )[0]
            if badindices.size > 1 and y.size - badindices.size > 2 * window_size and iteration < numiters:
                done = False
                x = np.delete(x, badindices)
                y = np.delete(y, badindices)

        print "iter = %i" % iteration
        if x[0] > order.x[0]:
            x = np.append(np.array([order.x[0]]), x)
            smoothed = np.append(np.array([first]), smoothed)
        if x[-1] < order.x[-1]:
            x = np.append(x, np.array([order.x[-1]]))
            smoothed = np.append(smoothed, np.array([last]))
        print x.size, y.size, smoothed.size
        smooth_fcn = interp(x, smoothed, k=1)
        smoothed = smooth_fcn(order.x)

        order.cont = FittingUtilities.Continuum(order.x, order.y)
        plt.figure(1)
        plt.plot(order.x, order.y / order.cont, "k-")
        plt.plot(order.x, smoothed / order.cont, "r-")
        # plt.figure(2)
        # plt.plot(order.x, order.y/smoothed)
        # plt.plot(order.x, smoothed)
        # orders[i].y /= smoothed
        column = {
            "wavelength": order.x,
            "flux": order.y / smoothed,
            "continuum": np.ones(order.x.size),
            "error": order.err,
        }
        column_list.append(column)
    plt.show()
    outfilename = "%s_smoothed.fits" % (fname.split(".fits")[0])
    print "Outputting to %s" % outfilename