예제 #1
0
def extract_spectrum(input: str, output: str, start: float, end: float):
    """Extracts the given wavelength range from input and store it as output.

    Args:
        input: Input filename
        output: Output filename
        start: Wavelength start
        end: Wavelength end
    """

    # load spectrum
    with FitsSpectrum(input) as fs_in:
        # open spectrum to write
        with FitsSpectrum(output, 'w') as fs_out:
            # copy extracted spectrum
            fs_out.spectrum = fs_in.spectrum.extract(start, end)

            # loop all extensions:
            for ext in fs_in.hdu_names():
                # skip no name
                if ext.strip() == '':
                    continue

                # try to get hdu
                try:
                    # get hdu
                    hdu = fs_in[ext]

                    # need to create new hdu with primary=False, since that gets lost on extract
                    fs_out[ext] = SpectrumFitsHDU(spec=hdu.extract(start, end),
                                                  primary=False)

                except ValueError:
                    pass
예제 #2
0
    def _load_spectrum(self, filename: str) -> (Spectrum, np.ndarray):
        """Loads the given spectrum and its uncertainties and creates a mask.

        Args:
            filename: Name of file to load.

        Returns:
            Tuple of Spectrum and mask of valid pixels
        """

        # open file
        self.log.info("Loading file {0:s}.".format(filename))
        with FitsSpectrum(filename) as fs:
            # get spectrum
            self._spec = fs.spectrum

            # mask of good pixels
            self._valid = fs.good_pixels.astype(np.bool)

            # mask all NaNs
            self._valid &= ~np.isnan(self._spec.flux) & ~np.isnan(
                self._spec.wave)

            # add other masks
            for mask in self._masks:
                self._valid &= mask(fs.spectrum, filename=fs.filename)
예제 #3
0
def plot(spectra: list,
         output: str = None,
         results: bool = False,
         range: list = None,
         **kwargs):
    # if spectra not a list, make it a list
    if not isinstance(spectra, list):
        spectra = [spectra]

    # check output
    pdf = None
    if output:
        # want a PDF?
        if output.endswith('.pdf'):
            pdf = PdfPages(output)
        else:
            # if no pdf, we only allow for one spectrum to plot
            if len(spectra) > 1:
                raise ValueError(
                    'Plotting into a file other than a PDF works for a single spectrum only!'
                )

    # loop spectra
    for filename in sorted(spectra):
        # load spectrum
        with FitsSpectrum(filename) as fs:
            # get spectrum
            spec = fs[
                'NORMALIZED'] if 'NORMALIZED' in fs and results else fs.spectrum

            # and model
            model = fs.best_fit if results else None

            # get residuals
            residuals = fs.residuals if results else None

            # good pixels
            valid = fs.good_pixels

        # plot
        plot_spectrum(spec,
                      model,
                      residuals,
                      valid,
                      wave_range=range,
                      title=fs.filename)

        # show
        if output:
            pdf.savefig(papertype='a4', orientation='landscape')
            plt.close()
        else:
            plt.show()

    # close file
    if output:
        pdf.close()
예제 #4
0
    def write_results_to_file(self, fits_file: FitsSpectrum):
        """Write results of this component into a given SpectrumFile

        Args:
            fits_file: Opened FitsSpectrum to write results into
        """

        # get results object
        params = fits_file.results(self.prefix)

        # loop parameter names
        for name, param in self.parameters.items():
            # write results into results object
            vary = 'vary' not in param or param['vary'] is True
            params[name] = [param['value'], param['stderr'] if vary else None]
예제 #5
0
    def _write_results_to_file(self, filename: str, result: MinimizerResult,
                               best_fit: Spectrum, stats: dict):
        """Writes results of fit back to file.

        Args:
            filename: Name of file to write results into.
            result: Result from optimization.
            best_fit: Best fit model.
            stats: Fit statistics.
        """

        # Write fits results back to file
        self.log.info("Writing results to file.")
        with FitsSpectrum(filename, 'rw') as fs:
            # stats
            res = fs.results('SPEXXY')
            for x in stats:
                res[x] = stats[x]

            # loop all components
            for cmp in self._cmps:
                # write results
                cmp.write_results_to_file(fs)

            # tellurics
            if self._tellurics is not None:
                # molecular abundances
                self._tellurics.write_results_to_file(fs)

            # weights
            weights = fs.results("WEIGHTS")
            for cmp in self._cmps:
                weights[cmp.prefix] = cmp.weight

            # write spectra best fit, good pixels mask, residuals and
            # multiplicative polynomial
            if best_fit is not None:
                fs.best_fit = best_fit
                fs.residuals = self._spec.flux - best_fit.flux
            fs.good_pixels = self._valid
            fs.mult_poly = self._mult_poly.values

            # loop all components again to add spectra
            for cmp in self._cmps:
                # get spectrum
                tmp = cmp()
                tmp.mode(self._spec.wave_mode)
                tmp = tmp.resample(spec=self._spec)
                cmpspec = SpectrumFitsHDU(spec=tmp, primary=False)

                # set it
                fs['CMP_' + cmp.name] = cmpspec

            # tellurics spectrum
            if self._tellurics is not None:
                tmp = self._tellurics()
                tmp.mode(self._spec.wave_mode)
                tmp = tmp.resample(spec=self._spec)
                tell = SpectrumFitsHDU(spec=tmp, primary=False)

                # set it
                fs['TELLURICS'] = tell

            # covariance
            if hasattr(result, 'covar'):
                fs.covar = result.covar
예제 #6
0
파일: mean.py 프로젝트: bischoff94/spexxy
def run(args):
    """
    Takes a list of spectra and calculates the mean of the fitted tellurics.

    :param args:    argparse namespace with
                    .spectra:   List of files containing spectra.
                    .output:    Output file for mean tellurics
                                (default: tellurics.fits)
                    .snlimit:   Only calculate mean tellurics for spectra
                                with a S/N higher than the given number.
                    .weight:    If set, tellurics are weightes by the S/N
                                of their spectra.
    """

    # get all spectra
    filenames = []
    for s in args.spectra:
        if '*' in s:
            filenames.extend(glob.glob(s))
        else:
            filenames.append(s)

    # read headers
    logging.info('Reading all FITS headers...')
    headers = bulk_read_header(filenames, ['HIERARCH SPECTRUM SNRATIO'])

    # get all snr values
    logging.info('Extracting all S/N values...')
    snrs = {}
    for i, row in headers.iterrows():
        try:
            snrs[row['FILE']] = float(row['HIERARCH SPECTRUM SNRATIO'])
        except ValueError:
            continue

    # no snlimit given?
    if args.snlimit is not None:
        snlimit = args.snlimit
    else:
        tmp = sorted(snrs.values())
        logging.info('Calculating S/N limit from %.2f%% highest S/N values...',
                     args.snfrac)
        snlimit = tmp[-int(len(tmp) * args.snfrac / 100)]
    logging.info('Using S/N limit of %.2f...', snlimit)

    # filter by snlimit
    logging.info('Filtering spectra by S/N limit...')
    spectra = [filename for filename, snr in snrs.items() if snr > snlimit]

    # tellurics spectrum
    tellurics = None
    weights = None
    count = None
    wave_start, wave_step, wave_count = args.resample
    if wave_count is not None:
        wave_count = int(wave_count)

    # loop files
    logging.info('Processing %d spectra...', len(spectra))
    for i, spec in enumerate(spectra, 1):
        # open file
        with FitsSpectrum(spec, 'r') as fs:
            # get signal to noise
            snr = fs.header["HIERARCH SPECTRUM SNRATIO"]

            # print
            logging.info('(%d/%d) %s %-5.2f', i, len(spectra), spec, snr)

            # weight
            weight = snr if args.weight else 1.

            # some more info
            if wave_start is None:
                # WAVE extension or CRVAL/CDELT?
                if 'CRVAL1' in fs.header and 'CDELT1' in fs.header:
                    wave_start = fs.header["CRVAL1"]
                    wave_step = fs.header["CDELT1"]
                    if fs.header['CUNIT1'] == 'm':
                        wave_start *= 1e10
                        wave_step *= 1e10
                    wave_count = fs.header['NAXIS1']
                elif 'WAVE' in fs.header and fs.header['WAVE'] in fs:
                    logging.error(
                        'Combining tellurics on PIXTABLE spectra not allowed without resampling.'
                    )
                    continue
                else:
                    logging.error('Could not determine wavelength grid.')
                    continue

            # get tellurics
            tell = fs.tellurics
            if not tell:
                continue

            # resample
            tell = tell.resample(wave_start=wave_start,
                                 wave_step=wave_step,
                                 wave_count=wave_count)

            # tellurics exist? on first iteration we create the array.
            if tellurics is None:
                tellurics = np.zeros((wave_count))
                weights = np.zeros((wave_count))
                count = np.zeros((wave_count))

            # add to sum
            w = np.where(~np.isnan(tell.flux))
            tellurics[w] += weight * tell.flux[w]
            weights[w] += weight
            count[w] += 1

    # divide by sum
    w = np.where(~np.isnan(tellurics) & ~np.isnan(weights))
    tellurics[w] /= weights[w]

    # create spectrum for tellurics and save it
    tell_spec = SpectrumFits(flux=tellurics,
                             wave_start=wave_start,
                             wave_step=wave_step,
                             primary=True)
    tell_spec.save(args.output)

    # output
    logging.info("Finished successfully.")