Exemple #1
0
    def _process_spectrum_from_fits(self, data_product):
        flux, header = fits.getdata(data_product.data.name, header=True)

        try:
            flux_constant = Unit(header['BUNIT'])
            flux_constant.to(DEFAULT_FLUX_CONSTANT)
        except:
            flux_constant = DEFAULT_FLUX_CONSTANT
        date_obs = header.get('DATE-OBS', datetime.now())

        header['CUNIT1'] = 'Angstrom'
        wcs = WCS(header=header)
        flux = flux[0].squeeze() * flux_constant

        spectrum = Spectrum1D(flux=flux, wcs=wcs)

        return spectrum, Time(date_obs).to_datetime()
Exemple #2
0
def _create(wlk, root, session):
    query = session.query(DatabaseEntry)
    for key, value in root.attrs.iteritems():
        typ = key[0]
        if typ == 'tag':
            criterion = TableTag.name.in_([value])
            # `key[1]` is here the `inverted` attribute of the tag. That means
            # that if it is True, the given tag must not be included in the
            # resulting entries.
            if key[1]:
                query = query.filter(~DatabaseEntry.tags.any(criterion))
            else:
                query = query.filter(DatabaseEntry.tags.any(criterion))
        elif typ == 'fitsheaderentry':
            key, val, inverted = value
            key_criterion = TableFitsHeaderEntry.key == key
            value_criterion = TableFitsHeaderEntry.value == val
            if inverted:
                query = query.filter(not_(and_(
                    DatabaseEntry.fits_header_entries.any(key_criterion),
                    DatabaseEntry.fits_header_entries.any(value_criterion))))
            else:
                query = query.filter(and_(
                    DatabaseEntry.fits_header_entries.any(key_criterion),
                    DatabaseEntry.fits_header_entries.any(value_criterion)))
        elif typ == 'download time':
            start, end, inverted = value
            if inverted:
                query = query.filter(
                    ~DatabaseEntry.download_time.between(start, end))
            else:
                query = query.filter(
                    DatabaseEntry.download_time.between(start, end))
        elif typ == 'path':
            path, inverted = value
            if inverted:
                query = query.filter(or_(
                    DatabaseEntry.path != path, DatabaseEntry.path == None))
            else:
                query = query.filter(DatabaseEntry.path == path)
        elif typ == 'wave':
            min_, max_, unit = value
            waveunit = Unit(unit)
            # convert min_ and max_ to nm from the unit `waveunit`
            wavemin = waveunit.to(nm, min_, equivalencies.spectral())
            wavemax = waveunit.to(nm, max_, equivalencies.spectral())
            query = query.filter(and_(
                DatabaseEntry.wavemin >= wavemin,
                DatabaseEntry.wavemax <= wavemax))
        elif typ == 'time':
            start, end, near = value
            query = query.filter(and_(
                DatabaseEntry.observation_time_start < end,
                DatabaseEntry.observation_time_end > start))
        else:
            query = query.filter_by(**{typ: value})
    return query.all()
Exemple #3
0
def entries_from_file(file, default_waveunit=None):
    """Use the headers of a FITS file to generate an iterator of
    :class:`sunpy.database.tables.DatabaseEntry` instances. Gathered
    information will be saved in the attribute `fits_header_entries`. If the
    key INSTRUME, WAVELNTH or DATE-OBS / DATE_OBS is available, the attribute
    `instrument`, `wavemin` and `wavemax` or `observation_time_start` is set,
    respectively. If the wavelength unit can be read, the values of `wavemin`
    and `wavemax` are converted to nm (nanometres). The value of the `file`
    parameter is used to set the attribute `path` of each generated database
    entry.

    Parameters
    ----------
    file : str or file-like object
        Either a path pointing to a FITS file or a an opened file-like object.
        If an opened file object, its mode must be one of the following rb,
        rb+, or ab+.

    default_waveunit : str, optional
        The wavelength unit that is used for a header if it cannot be
        found.

    Raises
    ------
    sunpy.database.WaveunitNotFoundError
        If `default_waveunit` is not given and the wavelength unit cannot
        be found in one of the FITS headers

    sunpy.WaveunitNotConvertibleError
        If a wavelength unit could be found but cannot be used to create an
        instance of the type ``astropy.units.Unit``. This can be the case
        for example if a FITS header has the key `WAVEUNIT` with the value
        `nonsense`.

    Examples
    --------
    >>> entries = list(entries_from_file(sunpy.data.sample.SWAP_LEVEL1_IMAGE))
    >>> len(entries)
    1
    >>> entry = entries.pop()
    >>> entry.instrument
    'SWAP'
    >>> entry.observation_time_start, entry.observation_time_end
    (datetime.datetime(2012, 1, 1, 0, 16, 7, 836000), None)
    >>> entry.wavemin, entry.wavemax
    (17.400000000000002, 17.400000000000002)
    >>> len(entry.fits_header_entries)
    112

    """
    headers = fits.get_header(file)
    if isinstance(file, (str, unicode)):
        filename = file
    else:
        filename = getattr(file, "name", None)
    for header in headers:
        entry = DatabaseEntry(path=filename)
        for key, value in header.iteritems():
            # Yes, it is possible to have an empty key in a FITS file.
            # Example: sunpy.data.sample.EIT_195_IMAGE
            # Don't ask me why this could be a good idea.
            if key == "":
                value = str(value)
            elif key == "KEYCOMMENTS":
                for k, v in value.iteritems():
                    entry.fits_key_comments.append(FitsKeyComment(k, v))
                continue
            entry.fits_header_entries.append(FitsHeaderEntry(key, value))
        waveunit = fits.extract_waveunit(header)
        if waveunit is None:
            waveunit = default_waveunit
        unit = None
        if waveunit is not None:
            try:
                unit = Unit(waveunit)
            except ValueError:
                raise WaveunitNotConvertibleError(waveunit)
        for header_entry in entry.fits_header_entries:
            key, value = header_entry.key, header_entry.value
            if key == "INSTRUME":
                entry.instrument = value
            elif key == "WAVELNTH":
                if unit is None:
                    raise WaveunitNotFoundError(file)
                # use the value of `unit` to convert the wavelength to nm
                entry.wavemin = entry.wavemax = unit.to(nm, value, equivalencies.spectral())
            # NOTE: the key DATE-END or DATE_END is not part of the official
            # FITS standard, but many FITS files use it in their header
            elif key in ("DATE-END", "DATE_END"):
                entry.observation_time_end = parse_time(value)
            elif key in ("DATE-OBS", "DATE_OBS"):
                entry.observation_time_start = parse_time(value)
        yield entry
Exemple #4
0
    def _from_query_result_block(cls, qr_block, default_waveunit=None):
        """Make a new :class:`DatabaseEntry` instance from a VSO query result
        block. The values of :attr:`wavemin` and :attr:`wavemax` are converted
        to nm (nanometres).

        Parameters
        ----------
        qr_block : suds.sudsobject.QueryResponseBlock
            A query result block is usually not created directly; instead,
            one gets instances of ``suds.sudsobject.QueryResponseBlock`` by
            iterating over a VSO query result.
        default_waveunit : str, optional
            The wavelength unit that is used if it cannot be found in the
            `qr_block`.

        Examples
        --------
        >>> from sunpy.net import vso
        >>> client = vso.VSOClient()
        >>> qr = client.query(
        ...     vso.attrs.Time('2001/1/1', '2001/1/2'),
        ...     vso.attrs.Instrument('eit'))
        >>> entry = DatabaseEntry.from_query_result_block(qr[0])
        >>> entry.source
        'SOHO'
        >>> entry.provider
        'SDAC'
        >>> entry.physobs
        'intensity'
        >>> entry.fileid
        '/archive/soho/private/data/processed/eit/lz/2001/01/efz20010101.010014'
        >>> entry.observation_time_start, entry.observation_time_end
        (datetime.datetime(2001, 1, 1, 1, 0, 14), datetime.datetime(2001, 1, 1, 1, 0, 21))
        >>> entry.instrument
        'EIT'
        >>> entry.size
        2059.0
        >>> entry.wavemin, entry.wavemax
        (17.1, 17.1)

        """
        time_start = timestamp2datetime("%Y%m%d%H%M%S", qr_block.time.start)
        time_end = timestamp2datetime("%Y%m%d%H%M%S", qr_block.time.end)
        wave = qr_block.wave
        unit = None
        if wave.waveunit is None:
            if default_waveunit is not None:
                unit = Unit(default_waveunit)
        else:
            # some query response blocks store the unit "kev",
            # but AstroPy only understands "keV". See issue #766.
            waveunit = wave.waveunit
            if waveunit == "kev":
                waveunit = "keV"
            unit = Unit(waveunit)
        if wave.wavemin is None:
            wavemin = None
        else:
            if unit is None:
                raise WaveunitNotFoundError(qr_block)
            wavemin = unit.to(nm, float(wave.wavemin), equivalencies.spectral())
        if wave.wavemax is None:
            wavemax = None
        else:
            if unit is None:
                raise WaveunitNotFoundError(qr_block)
            wavemax = unit.to(nm, float(wave.wavemax), equivalencies.spectral())
        source = str(qr_block.source) if qr_block.source is not None else None
        provider = str(qr_block.provider) if qr_block.provider is not None else None
        fileid = str(qr_block.fileid) if qr_block.fileid is not None else None
        instrument = str(qr_block.instrument) if qr_block.instrument is not None else None
        physobs = getattr(qr_block, "physobs", None)
        if physobs is not None:
            physobs = str(physobs)
        return cls(
            source=source,
            provider=provider,
            physobs=physobs,
            fileid=fileid,
            observation_time_start=time_start,
            observation_time_end=time_end,
            instrument=instrument,
            size=qr_block.size,
            wavemin=wavemin,
            wavemax=wavemax,
        )
Exemple #5
0
def entries_from_file(file,
                      default_waveunit=None,
                      time_string_parse_format=None):
    """Use the headers of a FITS file to generate an iterator of
    :class:`sunpy.database.tables.DatabaseEntry` instances. Gathered
    information will be saved in the attribute `fits_header_entries`. If the
    key INSTRUME, WAVELNTH or DATE-OBS / DATE_OBS is available, the attribute
    `instrument`, `wavemin` and `wavemax` or `observation_time_start` is set,
    respectively. If the wavelength unit can be read, the values of `wavemin`
    and `wavemax` are converted to nm (nanometres). The value of the `file`
    parameter is used to set the attribute `path` of each generated database
    entry.

    Parameters
    ----------
    file : str or file-like object
        Either a path pointing to a FITS file or a an opened file-like object.
        If an opened file object, its mode must be one of the following rb,
        rb+, or ab+.

    default_waveunit : str, optional
        The wavelength unit that is used for a header if it cannot be
        found.

    time_string_parse_format : str, optional
        Fallback timestamp format which will be passed to
        `~datetime.datetime.strftime` if `sunpy.time.parse_time` is unable to
        automatically read the `date-obs` metadata.

    Raises
    ------
    sunpy.database.WaveunitNotFoundError
        If `default_waveunit` is not given and the wavelength unit cannot
        be found in one of the FITS headers

    sunpy.WaveunitNotConvertibleError
        If a wavelength unit could be found but cannot be used to create an
        instance of the type ``astropy.units.Unit``. This can be the case
        for example if a FITS header has the key `WAVEUNIT` with the value
        `nonsense`.

    Examples
    --------
    >>> from sunpy.database.tables import entries_from_file
    >>> import sunpy.data.sample  # doctest: +REMOTE_DATA
    >>> entries = list(entries_from_file(sunpy.data.sample.SWAP_LEVEL1_IMAGE))  # doctest: +REMOTE_DATA
    >>> len(entries)  # doctest: +REMOTE_DATA
    1
    >>> entry = entries.pop()  # doctest: +REMOTE_DATA
    >>> entry.instrument  # doctest: +REMOTE_DATA
    'SWAP'
    >>> entry.observation_time_start, entry.observation_time_end  # doctest: +REMOTE_DATA
    (datetime.datetime(2011, 6, 7, 6, 33, 29, 759000), None)
    >>> entry.wavemin, entry.wavemax  # doctest: +REMOTE_DATA
    (17.400000000000002, 17.400000000000002)
    >>> len(entry.fits_header_entries)  # doctest: +REMOTE_DATA
    111

    """
    headers = fits.get_header(file)
    if isinstance(file, (str, six.text_type)):
        filename = file
    else:
        filename = getattr(file, 'name', None)
    for header in headers:
        entry = DatabaseEntry(path=filename)
        for key, value in six.iteritems(header):
            # Yes, it is possible to have an empty key in a FITS file.
            # Example: sunpy.data.sample.EIT_195_IMAGE
            # Don't ask me why this could be a good idea.
            if key == '':
                value = str(value)
            elif key == 'KEYCOMMENTS':
                for k, v in six.iteritems(value):
                    entry.fits_key_comments.append(FitsKeyComment(k, v))
                continue
            entry.fits_header_entries.append(FitsHeaderEntry(key, value))
        waveunit = fits.extract_waveunit(header)
        entry.hdu_index = headers.index(header)
        if waveunit is None:
            waveunit = default_waveunit
        unit = None
        if waveunit is not None:
            try:
                unit = Unit(waveunit)
            except ValueError:
                raise WaveunitNotConvertibleError(waveunit)
        for header_entry in entry.fits_header_entries:
            key, value = header_entry.key, header_entry.value
            if key == 'INSTRUME':
                entry.instrument = value
            elif key == 'WAVELNTH':
                if unit is None:
                    raise WaveunitNotFoundError(file)
                # use the value of `unit` to convert the wavelength to nm
                entry.wavemin = entry.wavemax = unit.to(
                    nm, value, equivalencies.spectral())
            # NOTE: the key DATE-END or DATE_END is not part of the official
            # FITS standard, but many FITS files use it in their header
            elif key in ('DATE-END', 'DATE_END'):
                entry.observation_time_end = parse_time(
                    value, _time_string_parse_format=time_string_parse_format)
            elif key in ('DATE-OBS', 'DATE_OBS'):
                entry.observation_time_start = parse_time(
                    value, _time_string_parse_format=time_string_parse_format)
        yield entry
Exemple #6
0
    def _from_fido_search_result_block(cls, sr_block, default_waveunit=None):
        """
        Make a new :class:`DatabaseEntry` instance from a Fido search
        result block.

        Parameters
        ----------
        sr_block : `sunpy.net.dataretriever.client.QueryResponseBlock`
            A query result block is usually not created directly; instead,
            one gets instances of
            ``sunpy.net.dataretriever.client.QueryResponseBlock`` by iterating
            over each element of a Fido search result.
        default_waveunit : `str`, optional
            The wavelength unit that is used if it cannot be found in the
            `sr_block`.
        """
        # All attributes of DatabaseEntry that are not in QueryResponseBlock
        # are set as None for now.
        source = getattr(sr_block, 'source', None)
        provider = getattr(sr_block, 'provider', None)
        physobs = getattr(sr_block, 'physobs', None)
        if physobs is not None:
            physobs = str(physobs)
        instrument = getattr(sr_block, 'instrument', None)
        time_start = sr_block.time.start
        time_end = sr_block.time.end

        wavelengths = getattr(sr_block, 'wave', None)
        wavelength_temp = {}
        if isinstance(wavelength_temp, tuple):
            # Tuple of values
            wavelength_temp['wavemin'] = wavelengths[0]
            wavelength_temp['wavemax'] = wavelengths[1]
        else:
            # Single Value
            wavelength_temp['wavemin'] = wavelength_temp[
                'wavemax'] = wavelengths

        final_values = {}
        for key, val in wavelength_temp.items():
            if isinstance(val, quantity.Quantity):
                unit = getattr(val, 'unit', None)
                if unit is None:
                    if default_waveunit is not None:
                        unit = Unit(default_waveunit)
                    else:
                        raise WaveunitNotFoundError(sr_block)
                final_values[key] = unit.to(nm, float(val.value),
                                            equivalencies.spectral())
            elif val is None or np.isnan(val):
                final_values[key] = val

        wavemin = final_values['wavemin']
        wavemax = final_values['wavemax']

        # sr_block.url of a QueryResponseBlock attribute is stored in fileid
        fileid = str(sr_block.url) if sr_block.url is not None else None
        size = None
        return cls(source=source,
                   provider=provider,
                   physobs=physobs,
                   fileid=fileid,
                   observation_time_start=time_start,
                   observation_time_end=time_end,
                   instrument=instrument,
                   size=size,
                   wavemin=wavemin,
                   wavemax=wavemax)
Exemple #7
0
    def _from_query_result_block(cls, qr_block, default_waveunit=None):
        """Make a new :class:`DatabaseEntry` instance from a VSO query result
        block. The values of :attr:`wavemin` and :attr:`wavemax` are converted
        to nm (nanometres).

        Parameters
        ----------
        qr_block : suds.sudsobject.QueryResponseBlock
            A query result block is usually not created directly; instead,
            one gets instances of ``suds.sudsobject.QueryResponseBlock`` by
            iterating over a VSO query result.
        default_waveunit : str, optional
            The wavelength unit that is used if it cannot be found in the
            `qr_block`.

        Examples
        --------
        >>> from sunpy.net import vso
        >>> from sunpy.database.tables import DatabaseEntry
        >>> client = vso.VSOClient()  # doctest: +REMOTE_DATA
        >>> qr = client.search(
        ...     vso.attrs.Time('2001/1/1', '2001/1/2'),
        ...     vso.attrs.Instrument('eit'))  # doctest: +REMOTE_DATA
        >>> entry = DatabaseEntry._from_query_result_block(qr[0])  # doctest: +REMOTE_DATA
        >>> entry.source  # doctest: +REMOTE_DATA
        SOHO
        >>> entry.provider  # doctest: +REMOTE_DATA
        SDAC
        >>> entry.physobs  # doctest: +REMOTE_DATA
        'intensity'
        >>> entry.fileid  # doctest: +REMOTE_DATA
        /archive/soho/private/data/processed/eit/lz/2001/01/efz20010101.000042
        >>> entry.observation_time_start, entry.observation_time_end  # doctest: +REMOTE_DATA
        (datetime.datetime(2001, 1, 1, 0, 0, 42), datetime.datetime(2001, 1, 1, 0, 0, 54))
        >>> entry.instrument  # doctest: +REMOTE_DATA
        EIT
        >>> entry.size  # doctest: +REMOTE_DATA
        2059.0
        >>> entry.wavemin, entry.wavemax  # doctest: +REMOTE_DATA
        (19.5, 19.5)

        """
        time_start = timestamp2datetime('%Y%m%d%H%M%S', qr_block.time.start)
        if not qr_block.time.end:
            qr_block.time.end = qr_block.time.start
        time_end = timestamp2datetime('%Y%m%d%H%M%S', qr_block.time.end)
        wave = qr_block.wave
        unit = None
        if wave.waveunit is None:
            if default_waveunit is not None:
                unit = Unit(default_waveunit)
        else:
            # some query response blocks store the unit "kev",
            # but Astropy only understands "keV". See issue #766.
            waveunit = wave.waveunit
            if waveunit == "kev":
                waveunit = "keV"
            unit = Unit(waveunit)
        if wave.wavemin is None:
            wavemin = None
        else:
            if unit is None:
                raise WaveunitNotFoundError(qr_block)
            wavemin = unit.to(nm, float(wave.wavemin),
                              equivalencies.spectral())
        if wave.wavemax is None:
            wavemax = None
        else:
            if unit is None:
                raise WaveunitNotFoundError(qr_block)
            wavemax = unit.to(nm, float(wave.wavemax),
                              equivalencies.spectral())
        source = getattr(qr_block, 'source', None)
        provider = getattr(qr_block, 'provider', None)
        fileid = getattr(qr_block, 'fileid', None)
        instrument = getattr(qr_block, 'instrument', None)
        size = getattr(qr_block, 'size', -1)
        physobs = getattr(qr_block, 'physobs', None)
        if physobs is not None:
            physobs = str(physobs)
        return cls(source=source,
                   provider=provider,
                   physobs=physobs,
                   fileid=fileid,
                   observation_time_start=time_start,
                   observation_time_end=time_end,
                   instrument=instrument,
                   size=size,
                   wavemin=wavemin,
                   wavemax=wavemax)
Exemple #8
0
    def _from_fido_search_result_block(cls, sr_block, default_waveunit=None):
        """
        Make a new :class:`DatabaseEntry` instance from a Fido search
        result block.

        Parameters
        ----------
        sr_block : `sunpy.net.dataretriever.client.QueryResponseBlock`
            A query result block is usually not created directly; instead,
            one gets instances of
            ``sunpy.net.dataretriever.client.QueryResponseBlock`` by iterating
            over each element of a Fido search result.
        default_waveunit : `str`, optional
            The wavelength unit that is used if it cannot be found in the
            `sr_block`.

        Examples
        --------
        >>> from sunpy.net import Fido, attrs
        >>> from sunpy.database.tables import DatabaseEntry
        >>> sr = Fido.search(attrs.Time("2012/1/1", "2012/1/2"),
        ...    attrs.Instrument('lyra'))
        >>> entry = DatabaseEntry._from_fido_search_result_block(sr[0][0])
        >>> entry.source
        'Proba2'
        >>> entry.provider
        'esa'
        >>> entry.physobs
        'irradiance'
        >>> entry.fileid
        'http://proba2.oma.be/lyra/data/bsd/2012/01/01/lyra_20120101-000000_lev2_std.fits'
        >>> entry.observation_time_start, entry.observation_time_end
        (datetime.datetime(2012, 1, 1, 0, 0), datetime.datetime(2012, 1, 2, 0, 0))
        >>> entry.instrument
        'lyra'

        """
        # All attributes of DatabaseEntry that are not in QueryResponseBlock
        # are set as None for now.
        source = getattr(sr_block, 'source', None)
        provider = getattr(sr_block, 'provider', None)
        physobs = getattr(sr_block, 'physobs', None)
        if physobs is not None:
            physobs = str(physobs)
        instrument = getattr(sr_block, 'instrument', None)
        time_start = sr_block.time.start
        time_end = sr_block.time.end

        wavelengths = getattr(sr_block, 'wave', None)
        wavelength_temp = {}
        if isinstance(wavelength_temp, tuple):
            # Tuple of values
            wavelength_temp['wavemin'] = wavelengths[0]
            wavelength_temp['wavemax'] = wavelengths[1]
        else:
            # Single Value
            wavelength_temp['wavemin'] = wavelength_temp['wavemax'] = wavelengths

        final_values = {}
        for key, val in wavelength_temp.items():
            if isinstance(val, quantity.Quantity):
                unit = getattr(val, 'unit', None)
                if unit is None:
                    if default_waveunit is not None:
                        unit = Unit(default_waveunit)
                    else:
                        raise WaveunitNotFoundError(sr_block)
                final_values[key] = unit.to(nm, float(val.value), equivalencies.spectral())
            elif val is None or np.isnan(val):
                final_values[key] = val

        wavemin = final_values['wavemin']
        wavemax = final_values['wavemax']

        # sr_block.url of a QueryResponseBlock attribute is stored in fileid
        fileid = str(sr_block.url) if sr_block.url is not None else None
        size = None
        return cls(
            source=source, provider=provider, physobs=physobs, fileid=fileid,
            observation_time_start=time_start, observation_time_end=time_end,
            instrument=instrument, size=size,
            wavemin=wavemin, wavemax=wavemax)
Exemple #9
0
def _create(wlk, root, session):
    query = session.query(DatabaseEntry)
    for key, value in root.attrs.iteritems():
        typ = key[0]
        if typ == "tag":
            criterion = TableTag.name.in_([value])
            # `key[1]` is here the `inverted` attribute of the tag. That means
            # that if it is True, the given tag must not be included in the
            # resulting entries.
            if key[1]:
                query = query.filter(~DatabaseEntry.tags.any(criterion))
            else:
                query = query.filter(DatabaseEntry.tags.any(criterion))
        elif typ == "fitsheaderentry":
            key, val, inverted = value
            key_criterion = TableFitsHeaderEntry.key == key
            value_criterion = TableFitsHeaderEntry.value == val
            if inverted:
                query = query.filter(
                    not_(
                        and_(
                            DatabaseEntry.fits_header_entries.any(key_criterion),
                            DatabaseEntry.fits_header_entries.any(value_criterion),
                        )
                    )
                )
            else:
                query = query.filter(
                    and_(
                        DatabaseEntry.fits_header_entries.any(key_criterion),
                        DatabaseEntry.fits_header_entries.any(value_criterion),
                    )
                )
        elif typ == "download time":
            start, end, inverted = value
            if inverted:
                query = query.filter(~DatabaseEntry.download_time.between(start, end))
            else:
                query = query.filter(DatabaseEntry.download_time.between(start, end))
        elif typ == "path":
            path, inverted = value
            if inverted:
                query = query.filter(or_(DatabaseEntry.path != path, DatabaseEntry.path == None))
            else:
                query = query.filter(DatabaseEntry.path == path)
        elif typ == "wave":
            min_, max_, unit = value
            waveunit = Unit(unit)
            # convert min_ and max_ to nm from the unit `waveunit`
            wavemin = waveunit.to(nm, min_, equivalencies.spectral())
            wavemax = waveunit.to(nm, max_, equivalencies.spectral())
            query = query.filter(and_(DatabaseEntry.wavemin >= wavemin, DatabaseEntry.wavemax <= wavemax))
        elif typ == "time":
            start, end, near = value
            query = query.filter(
                and_(DatabaseEntry.observation_time_start < end, DatabaseEntry.observation_time_end > start)
            )
        else:
            if typ.lower() not in SUPPORTED_SIMPLE_VSO_ATTRS.union(SUPPORTED_NONVSO_ATTRS):
                raise NotImplementedError("The attribute {0!r} is not yet supported to query a database.".format(typ))
            query = query.filter_by(**{typ: value})
    return query.all()
Exemple #10
0
    def _from_fido_search_result_block(cls, sr_block, default_waveunit=None):
        """
        Make a new :class:`DatabaseEntry` instance from a Fido search
        result block.

        Parameters
        ----------
        sr_block : `sunpy.net.dataretriever.client.QueryResponseBlock`
            A query result block is usually not created directly; instead,
            one gets instances of
            ``sunpy.net.dataretriever.client.QueryResponseBlock`` by iterating
            over each element of a Fido search result.
        default_waveunit : `str`, optional
            The wavelength unit that is used if it cannot be found in the
            `sr_block`.
        """
        # All attributes of DatabaseEntry that are not in QueryResponseBlock
        # are set as None for now.
        source = getattr(sr_block, 'source', None)
        provider = getattr(sr_block, 'provider', None)
        physobs = getattr(sr_block, 'physobs', None)
        if physobs is not None:
            physobs = str(physobs)
        instrument = getattr(sr_block, 'instrument', None)
        time_start = sr_block.time.start
        time_end = sr_block.time.end

        wavelengths = getattr(sr_block, 'wave', None)
        wavelength_temp = {}
        if isinstance(wavelength_temp, tuple):
            # Tuple of values
            wavelength_temp['wavemin'] = wavelengths[0]
            wavelength_temp['wavemax'] = wavelengths[1]
        else:
            # Single Value
            wavelength_temp['wavemin'] = wavelength_temp['wavemax'] = wavelengths

        final_values = {}
        for key, val in wavelength_temp.items():
            if isinstance(val, quantity.Quantity):
                unit = getattr(val, 'unit', None)
                if unit is None:
                    if default_waveunit is not None:
                        unit = Unit(default_waveunit)
                    else:
                        raise WaveunitNotFoundError(sr_block)
                final_values[key] = unit.to(nm, float(val.value), equivalencies.spectral())
            elif val is None or np.isnan(val):
                final_values[key] = val

        wavemin = final_values['wavemin']
        wavemax = final_values['wavemax']

        # sr_block.url of a QueryResponseBlock attribute is stored in fileid
        fileid = str(sr_block.url) if sr_block.url is not None else None
        size = None
        return cls(
            source=source, provider=provider, physobs=physobs, fileid=fileid,
            observation_time_start=time_start, observation_time_end=time_end,
            instrument=instrument, size=size,
            wavemin=wavemin, wavemax=wavemax)
Exemple #11
0
    def _from_query_result_block(cls, qr_block, default_waveunit=None):
        """Make a new :class:`DatabaseEntry` instance from a VSO query result
        block. The values of :attr:`wavemin` and :attr:`wavemax` are converted
        to nm (nanometres).

        Parameters
        ----------
        qr_block : suds.sudsobject.QueryResponseBlock
            A query result block is usually not created directly; instead,
            one gets instances of ``suds.sudsobject.QueryResponseBlock`` by
            iterating over a VSO query result.
        default_waveunit : str, optional
            The wavelength unit that is used if it cannot be found in the
            `qr_block`.

        Examples
        --------
        >>> from sunpy.net import vso
        >>> from sunpy.database.tables import DatabaseEntry
        >>> client = vso.VSOClient()  # doctest: +REMOTE_DATA
        >>> qr = client.search(
        ...     vso.attrs.Time('2001/1/1', '2001/1/2'),
        ...     vso.attrs.Instrument('eit'))  # doctest: +REMOTE_DATA
        >>> entry = DatabaseEntry._from_query_result_block(qr[0])  # doctest: +REMOTE_DATA
        >>> entry.source  # doctest: +REMOTE_DATA
        SOHO
        >>> entry.provider  # doctest: +REMOTE_DATA
        SDAC
        >>> entry.physobs  # doctest: +REMOTE_DATA
        'intensity'
        >>> entry.fileid  # doctest: +REMOTE_DATA
        /archive/soho/private/data/processed/eit/lz/2001/01/efz20010101.000042
        >>> entry.observation_time_start, entry.observation_time_end  # doctest: +REMOTE_DATA
        (datetime.datetime(2001, 1, 1, 0, 0, 42), datetime.datetime(2001, 1, 1, 0, 0, 54))
        >>> entry.instrument  # doctest: +REMOTE_DATA
        EIT
        >>> entry.size  # doctest: +REMOTE_DATA
        2059.0
        >>> entry.wavemin, entry.wavemax  # doctest: +REMOTE_DATA
        (19.5, 19.5)

        """
        time_start = timestamp2datetime('%Y%m%d%H%M%S', qr_block.time.start)
        if not qr_block.time.end:
            qr_block.time.end = qr_block.time.start
        time_end = timestamp2datetime('%Y%m%d%H%M%S', qr_block.time.end)
        wave = qr_block.wave
        unit = None
        if wave.waveunit is None:
            if default_waveunit is not None:
                unit = Unit(default_waveunit)
        else:
            # some query response blocks store the unit "kev",
            # but Astropy only understands "keV". See issue #766.
            waveunit = wave.waveunit
            if waveunit == "kev":
                waveunit = "keV"
            unit = Unit(waveunit)
        if wave.wavemin is None:
            wavemin = None
        else:
            if unit is None:
                raise WaveunitNotFoundError(qr_block)
            wavemin = unit.to(nm, float(wave.wavemin),
                              equivalencies.spectral())
        if wave.wavemax is None:
            wavemax = None
        else:
            if unit is None:
                raise WaveunitNotFoundError(qr_block)
            wavemax = unit.to(nm, float(wave.wavemax),
                              equivalencies.spectral())
        source = getattr(qr_block, 'source', None)
        provider = getattr(qr_block, 'provider', None)
        fileid = getattr(qr_block, 'fileid', None)
        instrument = getattr(qr_block, 'instrument', None)
        size = getattr(qr_block, 'size', -1)
        physobs = getattr(qr_block, 'physobs', None)
        if physobs is not None:
            physobs = str(physobs)
        return cls(
            source=source, provider=provider, physobs=physobs, fileid=fileid,
            observation_time_start=time_start, observation_time_end=time_end,
            instrument=instrument, size=size,
            wavemin=wavemin, wavemax=wavemax)
Exemple #12
0
    def _from_query_result_block(cls, qr_block, default_waveunit=None):
        """Make a new :class:`DatabaseEntry` instance from a VSO query result
        block. The values of :attr:`wavemin` and :attr:`wavemax` are converted
        to nm (nanometres).

        Parameters
        ----------
        qr_block : suds.sudsobject.QueryResponseBlock
            A query result block is usually not created directly; instead,
            one gets instances of ``suds.sudsobject.QueryResponseBlock`` by
            iterating over a VSO query result.
        default_waveunit : str, optional
            The wavelength unit that is used if it cannot be found in the
            `qr_block`.

        Examples
        --------
        >>> from sunpy.net import vso
        >>> client = vso.VSOClient()
        >>> qr = client.query(
        ...     vso.attrs.Time('2001/1/1', '2001/1/2'),
        ...     vso.attrs.Instrument('eit'))
        >>> entry = DatabaseEntry.from_query_result_block(qr[0])
        >>> entry.source
        'SOHO'
        >>> entry.provider
        'SDAC'
        >>> entry.physobs
        'intensity'
        >>> entry.fileid
        '/archive/soho/private/data/processed/eit/lz/2001/01/efz20010101.010014'
        >>> entry.observation_time_start, entry.observation_time_end
        (datetime.datetime(2001, 1, 1, 1, 0, 14), datetime.datetime(2001, 1, 1, 1, 0, 21))
        >>> entry.instrument
        'EIT'
        >>> entry.size
        2059.0
        >>> entry.wavemin, entry.wavemax
        (17.1, 17.1)

        """
        time_start = timestamp2datetime('%Y%m%d%H%M%S', qr_block.time.start)
        time_end = timestamp2datetime('%Y%m%d%H%M%S', qr_block.time.end)
        wave = qr_block.wave
        unit = None
        if wave.waveunit is None:
            if default_waveunit is not None:
                unit = Unit(default_waveunit)
        else:
            # some query response blocks store the unit "kev",
            # but AstroPy only understands "keV". See issue #766.
            waveunit = wave.waveunit
            if waveunit == "kev":
                waveunit = "keV"
            unit = Unit(waveunit)
        if wave.wavemin is None:
            wavemin = None
        else:
            if unit is None:
                raise WaveunitNotFoundError(qr_block)
            wavemin = unit.to(nm, float(wave.wavemin),
                              equivalencies.spectral())
        if wave.wavemax is None:
            wavemax = None
        else:
            if unit is None:
                raise WaveunitNotFoundError(qr_block)
            wavemax = unit.to(nm, float(wave.wavemax),
                              equivalencies.spectral())
        source = str(qr_block.source) if qr_block.source is not None else None
        provider = str(
            qr_block.provider) if qr_block.provider is not None else None
        fileid = str(qr_block.fileid) if qr_block.fileid is not None else None
        instrument = str(
            qr_block.instrument) if qr_block.instrument is not None else None
        physobs = getattr(qr_block, 'physobs', None)
        if physobs is not None:
            physobs = str(physobs)
        return cls(source=source,
                   provider=provider,
                   physobs=physobs,
                   fileid=fileid,
                   observation_time_start=time_start,
                   observation_time_end=time_end,
                   instrument=instrument,
                   size=qr_block.size,
                   wavemin=wavemin,
                   wavemax=wavemax)
Exemple #13
0
def _create(wlk, root, session):
    query = session.query(DatabaseEntry)
    for key, value in root.attrs.iteritems():
        typ = key[0]
        if typ == 'tag':
            criterion = TableTag.name.in_([value])
            # `key[1]` is here the `inverted` attribute of the tag. That means
            # that if it is True, the given tag must not be included in the
            # resulting entries.
            if key[1]:
                query = query.filter(~DatabaseEntry.tags.any(criterion))
            else:
                query = query.filter(DatabaseEntry.tags.any(criterion))
        elif typ == 'fitsheaderentry':
            key, val, inverted = value
            key_criterion = TableFitsHeaderEntry.key == key
            value_criterion = TableFitsHeaderEntry.value == val
            if inverted:
                query = query.filter(
                    not_(
                        and_(
                            DatabaseEntry.fits_header_entries.any(
                                key_criterion),
                            DatabaseEntry.fits_header_entries.any(
                                value_criterion))))
            else:
                query = query.filter(
                    and_(
                        DatabaseEntry.fits_header_entries.any(key_criterion),
                        DatabaseEntry.fits_header_entries.any(
                            value_criterion)))
        elif typ == 'download time':
            start, end, inverted = value
            if inverted:
                query = query.filter(
                    ~DatabaseEntry.download_time.between(start, end))
            else:
                query = query.filter(
                    DatabaseEntry.download_time.between(start, end))
        elif typ == 'path':
            path, inverted = value
            if inverted:
                query = query.filter(
                    or_(DatabaseEntry.path != path,
                        DatabaseEntry.path == None))
            else:
                query = query.filter(DatabaseEntry.path == path)
        elif typ == 'wave':
            min_, max_, unit = value
            waveunit = Unit(unit)
            # convert min_ and max_ to nm from the unit `waveunit`
            wavemin = waveunit.to(nm, min_, equivalencies.spectral())
            wavemax = waveunit.to(nm, max_, equivalencies.spectral())
            query = query.filter(
                and_(DatabaseEntry.wavemin >= wavemin,
                     DatabaseEntry.wavemax <= wavemax))
        elif typ == 'time':
            start, end, near = value
            query = query.filter(
                and_(DatabaseEntry.observation_time_start < end,
                     DatabaseEntry.observation_time_end > start))
        else:
            if typ.lower() not in SUPPORTED_SIMPLE_VSO_ATTRS.union(
                    SUPPORTED_NONVSO_ATTRS):
                raise NotImplementedError(
                    "The attribute {0!r} is not yet supported to query a database."
                    .format(typ))
            query = query.filter_by(**{typ: value})
    return query.all()
Exemple #14
0
def entries_from_file(file, default_waveunit=None,
                      time_string_parse_format=''):
    # Note: time_string_parse_format='' so that None won't be passed to Time.strptime
    # (which would make strptime freak out, if I remember correctly).
    """Use the headers of a FITS file to generate an iterator of
    :class:`sunpy.database.tables.DatabaseEntry` instances. Gathered
    information will be saved in the attribute `fits_header_entries`. If the
    key INSTRUME, WAVELNTH or DATE-OBS / DATE_OBS is available, the attribute
    `instrument`, `wavemin` and `wavemax` or `observation_time_start` is set,
    respectively. If the wavelength unit can be read, the values of `wavemin`
    and `wavemax` are converted to nm (nanometres). The value of the `file`
    parameter is used to set the attribute `path` of each generated database
    entry.

    Parameters
    ----------
    file : str or file-like object
        Either a path pointing to a FITS file or a an opened file-like object.
        If an opened file object, its mode must be one of the following rb,
        rb+, or ab+.

    default_waveunit : str, optional
        The wavelength unit that is used for a header if it cannot be
        found.

    time_string_parse_format : str, optional
        Fallback timestamp format which will be passed to
        `~astropy.time.Time.strptime` if `sunpy.time.parse_time` is unable to
        automatically read the `date-obs` metadata.

    Raises
    ------
    sunpy.database.WaveunitNotFoundError
        If `default_waveunit` is not given and the wavelength unit cannot
        be found in one of the FITS headers

    sunpy.WaveunitNotConvertibleError
        If a wavelength unit could be found but cannot be used to create an
        instance of the type ``astropy.units.Unit``. This can be the case
        for example if a FITS header has the key `WAVEUNIT` with the value
        `nonsense`.

    Examples
    --------
    >>> from sunpy.database.tables import entries_from_file
    >>> import sunpy.data.sample  # doctest: +REMOTE_DATA
    >>> entries = list(entries_from_file(sunpy.data.sample.SWAP_LEVEL1_IMAGE))  # doctest: +REMOTE_DATA
    >>> len(entries)  # doctest: +REMOTE_DATA
    1
    >>> entry = entries.pop()  # doctest: +REMOTE_DATA
    >>> entry.instrument  # doctest: +REMOTE_DATA
    'SWAP'
    >>> entry.observation_time_start, entry.observation_time_end  # doctest: +REMOTE_DATA
    (datetime.datetime(2011, 6, 7, 6, 33, 29, 759000), None)
    >>> entry.wavemin, entry.wavemax  # doctest: +REMOTE_DATA
    (17.400000000000002, 17.400000000000002)
    >>> len(entry.fits_header_entries)  # doctest: +REMOTE_DATA
    111

    """
    headers = fits.get_header(file)

    # This just checks for blank default headers
    # due to compression.
    for header in headers:
        if header == DEFAULT_HEADER:
            headers.remove(header)

    if isinstance(file, str):
        filename = file
    else:
        filename = getattr(file, 'name', None)
    for header in headers:
        entry = DatabaseEntry(path=filename)
        for key, value in header.items():
            # Yes, it is possible to have an empty key in a FITS file.
            # Example: sunpy.data.sample.EIT_195_IMAGE
            # Don't ask me why this could be a good idea.
            if key == '':
                value = str(value)
            elif key == 'KEYCOMMENTS':
                for k, v in value.items():
                    entry.fits_key_comments.append(FitsKeyComment(k, v))
                continue
            entry.fits_header_entries.append(FitsHeaderEntry(key, value))
        waveunit = fits.extract_waveunit(header)
        entry.hdu_index = headers.index(header)
        if waveunit is None:
            waveunit = default_waveunit
        unit = None
        if waveunit is not None:
            try:
                unit = Unit(waveunit)
            except ValueError:
                raise WaveunitNotConvertibleError(waveunit)
        for header_entry in entry.fits_header_entries:
            key, value = header_entry.key, header_entry.value
            if key == 'INSTRUME':
                entry.instrument = value
            elif key == 'WAVELNTH':
                if unit is None:
                    raise WaveunitNotFoundError(file)
                # use the value of `unit` to convert the wavelength to nm
                entry.wavemin = entry.wavemax = unit.to(
                    nm, value, equivalencies.spectral())
            # NOTE: the key DATE-END or DATE_END is not part of the official
            # FITS standard, but many FITS files use it in their header
            elif key in ('DATE-END', 'DATE_END'):
                try:
                    dt = parse_time(value).datetime
                except ValueError:
                    dt = Time.strptime(value, time_string_parse_format).datetime
                entry.observation_time_end = dt
            elif key in ('DATE-OBS', 'DATE_OBS'):
                try:
                    dt = parse_time(value).datetime
                except ValueError:
                    dt = Time.strptime(value, time_string_parse_format).datetime
                entry.observation_time_start = dt
        yield entry