Exemple #1
0
def verify_unit(quantity, unit):
    """Verify unit of passed quantity and return it.

    Parameters:
        quantity: Quantity to be verified.
        unit: Equivalent unit, or string parsable by
              :py:class:`astropy.units.Unit`

    Raises:
        ValueError: Units are not equivalent.

    Returns:
        quantity parameter, unchanged.

    Example:
        .. code-block:: python

            def __init__(self, a):
                self.a = verify_unit(a, astropy.units.m)

    :type quantity: :py:class:`astropy.units.Quantity`
    :type unit: :py:class:`astropy.units.UnitBase`
    """
    if not isinstance(unit, Unit):
        unit = Unit(unit)

    if unit.is_equivalent((quantity * u.one).unit):
        return quantity
    else:
        raise ValueError(
            "Unit '{}' not equivalent to quantity '{}'.".format(unit, quantity))
Exemple #2
0
    def __init__(self, physical_unit=None, function_unit=None):
        if physical_unit is None:
            self._physical_unit = dimensionless_unscaled
        else:
            self._physical_unit = Unit(physical_unit)
            if (not isinstance(self._physical_unit, UnitBase) or
                self._physical_unit.is_equivalent(
                    self._default_function_unit)):
                raise ValueError("Unit {0} is not a physical unit."
                                 .format(self._physical_unit))

        if function_unit is None:
            self._function_unit = self._default_function_unit
        else:
            # any function unit should be equivalent to subclass default
            function_unit = Unit(getattr(function_unit, 'function_unit',
                                         function_unit))
            if function_unit.is_equivalent(self._default_function_unit):
                self._function_unit = function_unit
            else:
                raise ValueError("Cannot initialize '{0}' instance with "
                                 "function unit '{1}', as it is not "
                                 "equivalent to default function unit '{2}'."
                                 .format(self.__class__.__name__,
                                         function_unit,
                                         self._default_function_unit))
def verify_unit(quantity, unit):
    """Verify unit of passed quantity and return it.

    Parameters:
        quantity: :py:class:`~astropy.units.Quantity` to be verified. Bare
                  numbers are valid if the unit is dimensionless.
        unit: Equivalent unit, or string parsable by
              :py:class:`astropy.units.Unit`

    Raises:
        ValueError: Units are not equivalent.

    Returns:
        ``quantity`` unchanged. Bare numbers will be converted to a dimensionless
        :py:class:`~astropy.units.Quantity`.

    Example:
        .. code-block:: python

            def __init__(self, a):
                self.a = verify_unit(a, astropy.units.m)

    """
    if not isinstance(unit, UnitBase):
        unit = Unit(unit)

    q = quantity * u.one
    if unit.is_equivalent(q.unit):
        return q
    else:
        raise ValueError("Unit '{}' not equivalent to quantity '{}'.".format(unit, quantity))
Exemple #4
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 #5
0
def test_gps_scale(scale):
    u = Unit(scale[:-1])

    fig = pyplot.figure()
    ax = fig.gca(xscale=scale)
    if scale == 'years':
        x = numpy.arange(50)
    else:
        x = numpy.arange(1e2)
    ax.plot(x * u.decompose().scale, x)
    fig.canvas.draw()
    xscale = ax.get_xaxis()._scale
    assert xscale.get_unit() == Unit(scale[:-1])
    pyplot.close(fig)
def units_to_fits(unit):
    """ Convert an astropy unit to a FITS format string.

    uses the to_string() method built-in to astropy Unit()

    Notes
    -----
    The output will be the format defined in the FITS standard:
    http://fits.gsfc.nasa.gov/fits_standard.html

    A roundtrip from fits_to_units -> units_to_fits may not return
    the original string, as people often don't follow the standard.
    """
    if unit is None:
        unit = Unit('')
    return unit.to_string("fits").upper()
Exemple #7
0
def aspcapStar_loader(file_obj, **kwargs):
    """
    Loader for APOGEE aspcapStar files.

    Parameters
    ----------
    file_obj: str or file-like
        FITS file name or object (provided from name by Astropy I/O Registry).

    Returns
    -------
    data: Spectrum1D
        The spectrum that is represented by the data in this table.
    """
    if isinstance(file_obj, fits.hdu.hdulist.HDUList):
        close_hdulist = False
        hdulist = file_obj
    else:
        close_hdulist = True
        hdulist = fits.open(file_obj, **kwargs)

    header = hdulist[0].header
    meta = {'header': header}
    wcs = WCS(hdulist[1].header)

    data = hdulist[1].data  # spectrum in the first extension
    unit = def_unit('arbitrary units')

    uncertainty = StdDevUncertainty(hdulist[2].data)

    # dispersion from the WCS but convert out of logspace
    dispersion = 10**wcs.all_pix2world(np.arange(data.shape[0]), 0)[0]
    dispersion_unit = Unit('Angstrom')
    if close_hdulist:
        hdulist.close()

    return Spectrum1D(data=data * unit,
                      uncertainty=uncertainty,
                      spectral_axis=dispersion * dispersion_unit,
                      meta=meta,
                      wcs=wcs)
Exemple #8
0
    def __init__(self, value, uncertainty, unit=None):

        if isinstance(value, self.__class__):
            self._uncertainty = value.uncertainty

        else:
            if isinstance(value, Quantity):
                if unit is not None:
                    raise ValueError('cannot use the unit argument when '
                                     '`value` is a Quantity')

            else:
                self._unit = (dimensionless_unscaled
                              if unit is None else Unit(unit))

            if hasattr(uncertainty, 'unit'):

                if (uncertainty.unit != dimensionless_unscaled
                        and self._unit != dimensionless_unscaled):
                    try:
                        uncertainty = uncertainty.to(self._unit)
                    except:
                        raise UnitsError('cannot convert unit of uncertainty '
                                         'to unit of the `Data` instance')

                if (self._unit == dimensionless_unscaled
                        and uncertainty.unit != dimensionless_unscaled):
                    raise UnitsError('cannot assign an uncertainty with units '
                                     'to a `Data` instance without a unit')

                uncertainty = Uncertainty(uncertainty)

            else:
                uncertainty = Uncertainty(uncertainty, self._unit)

            if uncertainty.size != self.size:
                raise ValueError('uncertainty must have the same shape as '
                                 'the `Data` instance')

            self._uncertainty = uncertainty
            self._uncertainty.parent_data = self
Exemple #9
0
def crab_flux(energy=1, reference=CRAB_DEFAULT_REFERENCE):
    """Differential Crab flux.

    See the ``gammapy.spectrum.crab`` module docstring for a description
    of the available reference spectra.

    Parameters
    ----------
    energy : array_like
        Energy (TeV)
    reference : {{'hegra', 'hess_pl', 'hess_ecpl', 'meyer'}}
        Published Crab reference spectrum

    Returns
    -------
    flux : array
        Differential flux (cm^-2 s^-1 TeV^-1) at ``energy``
    """
    if reference == 'hegra':
        f = hegra['diff_flux']
        g = hegra['index']
        return f * energy**(-g)
    elif reference == 'hess_pl':
        f = hess_pl['diff_flux']
        g = hess_pl['index']
        return f * energy**(-g)
    elif reference == 'hess_ecpl':
        f = hess_ecpl['diff_flux']
        g = hess_ecpl['index']
        e_c = hess_ecpl['cutoff']
        return f * energy**(-g) * np.exp(-energy / e_c)
    elif reference == 'meyer':
        # Meyer et al., 2010arXiv1008.4524M, Appendix D
        p = np.array(
            [-0.00449161, 0, 0.0473174, -0.179475, -0.53616, -10.2708])
        log_energy = np.log10(np.asarray(energy))
        log_flux = np.poly1d(p)(log_energy)
        flux = 10**log_flux
        return Unit('erg').to('TeV') * flux / energy**2
    else:
        raise ValueError('Unknown reference: {0}'.format(reference))
Exemple #10
0
def get_wave_unit(tag, hdulist, idx=None):
    """ Attempt to pull wavelength unit from the Table
    Parameters
    ----------
    tag : str
     Tag used for wavelengths
    hdulist : fits header data unit list
    idx : int, optional
     Index of list for Table input

    Returns
    -------
    unit : astropy Unit
      Defaults to None
    """
    from astropy.units import Unit
    if idx is None:
        idx = 1
    # Use Table
    if isinstance(hdulist[idx], BinTableHDU):
        tab = Table(hdulist[idx].data)
        header = hdulist[idx].header
    else:
        # NEED HEADER INFO
        return None
    # Try table header (following VLT/X-Shooter here)
    keys = list(header)  # Python 3
    values = list(itervalues(header))  # Python 3
    hidx = values.index(tag)
    if keys[hidx][0:5] == 'TTYPE':
        try:
            tunit = header[keys[hidx].replace('TYPE', 'UNIT')]
        except KeyError:
            return None
        else:
            if tunit in ['Angstroem', 'Angstroms', 'ANGSTROMS']:
                tunit = 'Angstrom'
            unit = Unit(tunit)
            return unit
    else:
        return None
Exemple #11
0
    def fwhms(self):
        """
        This function ...
        :return:
        """

        # Initialize a list to contain the fwhm of the fitted stars
        fwhms = []

        # Loop over all stars
        for star in self.stars:

            # If the star contains a model, add the fwhm of that model to the list
            if star.has_model:
                fwhm_pix = star.fwhm * Unit("pix")
                fwhm_arcsec = fwhm_pix * self.frame.average_pixelscale.to(
                    "arcsec/pix")
                fwhms.append(fwhm_arcsec)

        # Return the list
        return fwhms
Exemple #12
0
def generic_spectrum1d_loader(file_name, **kwargs):
    name = os.path.basename(file_name.rstrip(os.sep)).rsplit('.', 1)[0]
    hdulist = fits.open(file_name, **kwargs)

    header = hdulist[0].header
    meta = {'header': header}
    wcs = WCS(hdulist[0].header)
    unit = Unit('Jy')
    uncertainty = StdDevUncertainty(hdulist[3].data)
    data = hdulist[1].data
    mask = hdulist[2].data

    hdulist.close()

    return MOSSpectrum2D(data=data,
                         name=name,
                         wcs=wcs,
                         uncertainty=uncertainty,
                         unit=unit,
                         meta=meta,
                         mask=mask)
Exemple #13
0
def project_azimuth_to_pa(azimuth, inclination):
    """
    This function ...
    :param azimuth:
    :param inclination:
    """

    # Get the azimuth angle and inclination in radians
    azimuth_radian = azimuth.to("radian").value
    i_radian = inclination.to("radian").value

    denominator = math.sqrt(
        math.cos(azimuth_radian)**2 * math.cos(i_radian)**2 +
        math.sin(azimuth_radian)**2)

    cos_pa = math.cos(azimuth_radian) * math.cos(i_radian) / denominator
    sin_pa = math.sin(azimuth_radian) / denominator

    pa_radian = math.atan2(sin_pa, cos_pa) * Unit("radian")

    return pa_radian.to("deg")
Exemple #14
0
    def _summary_flux_points(self):
        """Print flux point results"""
        d = self.data
        ss = '\n*** Flux points info ***\n\n'
        ss += 'Number of flux points: {}\n'.format(d['N_Flux_Points'])
        ss += 'Flux points table: \n\n\t'

        flux_points = self.flux_points['ENERGY', 'DIFF_FLUX', 'DIFF_FLUX_ERR_HI',
                                       'DIFF_FLUX_ERR_LO'][:int(d['N_Flux_Points'])]

        flux_points['ENERGY'].format = '.3f'

        flux_unit = Unit('1E-12 cm^-2 s^-1 TeV^-1')
        for _ in ['DIFF_FLUX', 'DIFF_FLUX_ERR_HI', 'DIFF_FLUX_ERR_LO']:
            flux_points[_] = flux_points[_].to(flux_unit)
            flux_points[_].format = '.3f'
            flux_points[_].unit = flux_unit

        # convert table to string
        ss += '\n\t'.join(flux_points.pformat(-1))
        return ss + '\n'
Exemple #15
0
 def __init__(self):
     path = os.path.dirname(pyfoxsi.__file__)
     for i in np.arange(3):
         path = os.path.dirname(path)
     path = os.path.join(path, 'data/')
     filename = 'shell_parameters.csv'
     params_file = os.path.join(path, filename)
     self.shell_params = pd.read_csv(params_file, index_col=0)
     the_units = [
         Unit(this_unit)
         for this_unit in self.shell_params.loc[np.nan].values
     ]
     self.units = {}
     for i, col in enumerate(self.shell_params):
         self.units.update({col: the_units[i]})
     self.shell_params.drop(self.shell_params.index[0], inplace=True)
     missing_shells = np.setdiff1d(self.shell_params.index,
                                   pyfoxsi.shell_ids)
     self.shell_params.drop(missing_shells)
     for col in self.shell_params.columns:
         self.shell_params[col] = self.shell_params[col].astype(float)
Exemple #16
0
def project_tilt_to_pa(tilt, inclination):
    """
    This function ...
    :param tilt:
    :param inclination:
    :return:
    """

    # Get the tilt angle and inclination in radians
    tilt_radian = tilt.to("radian").value
    i_radian = inclination.to("radian").value

    denominator = math.sqrt(
        math.sin(tilt_radian)**2 * math.sin(i_radian)**2 +
        math.cos(tilt_radian)**2)

    cos_pa = math.sin(tilt_radian) * math.sin(i_radian) / denominator
    sin_pa = math.cos(tilt_radian) / denominator

    pa_radian = math.atan2(sin_pa, cos_pa) * Unit("radian")

    return pa_radian.to("deg")
Exemple #17
0
    def __init__(
        self,
        default=None,
        description="",
        unit=None,
        ucd=None,
        dtype=None,
        type=None,
        ndim=None,
        allow_none=True,
        max_length=None,
    ):

        self.default = default
        self.description = description
        self.unit = Unit(unit) if unit is not None else None
        self.ucd = ucd
        self.dtype = np.dtype(dtype) if dtype is not None else None
        self.type = type
        self.ndim = ndim
        self.allow_none = allow_none
        self.max_length = max_length
Exemple #18
0
def deproject_pa_to_tilt(pa, inclination):
    """
    This function ...
    :param pa:
    :param inclination:
    :return:
    """

    # Get the PA and inclination in radians
    pa_radian = pa.to("radian").value
    i_radian = inclination.to("radian").value

    denominator = math.sqrt(
        math.sin(pa_radian)**2 * math.sin(i_radian)**2 +
        math.cos(pa_radian)**2)

    cos_tilt = math.sin(pa_radian) * math.sin(i_radian) / denominator
    sin_tilt = math.cos(pa_radian) / denominator

    tilt_radian = math.atan2(sin_tilt, cos_tilt) * Unit("radian")

    return tilt_radian.to("deg")
Exemple #19
0
def test_make_psf_map():
    psf = fake_psf3d(0.3 * u.deg)

    pointing = SkyCoord(0, 0, unit="deg")
    energy_axis = MapAxis(nodes=[0.2, 0.7, 1.5, 2.0, 10.0],
                          unit="TeV",
                          name="energy")
    rad_axis = MapAxis(nodes=np.linspace(0.0, 1.0, 51),
                       unit="deg",
                       name="theta")

    geom = WcsGeom.create(skydir=pointing,
                          binsz=0.2,
                          width=5,
                          axes=[rad_axis, energy_axis])

    psfmap = make_psf_map(psf, pointing, geom, 3 * u.deg)

    assert psfmap.psf_map.geom.axes[0] == rad_axis
    assert psfmap.psf_map.geom.axes[1] == energy_axis
    assert psfmap.psf_map.unit == Unit("sr-1")
    assert psfmap.psf_map.data.shape == (4, 50, 25, 25)
Exemple #20
0
    def to_image_hdu(self):
        """
        Convert image to a `~astropy.io.fits.PrimaryHDU`.

        Returns
        -------
        hdu : `~astropy.io.fits.PrimaryHDU`
            Primary image hdu object.
        """
        if self.wcs is not None:
            header = self.wcs.to_header()
        else:
            header = fits.Header()

        # Add meta data
        header.update(self.meta)
        if self.unit is not None:
            header['BUNIT'] = Unit(self.unit).to_string('fits')
        if self.name is not None:
            header['EXTNAME'] = self.name
            header['HDUNAME'] = self.name
        return fits.PrimaryHDU(data=self.data, header=header)
Exemple #21
0
def simple_generic_loader(file_name, **kwargs):
    """
    Basic FITS file loader

    Presumption is the primary data is a table with columns 'flux'
    and 'err'.  The dispersion information is encoded in the FITS
    header keywords.

    Parameters
    ----------
    file_name: str
        The path to the FITS file

    Returns
    -------
    data: Spectrum1DRef
        The data.
    """
    name = os.path.basename(file_name.rstrip(os.sep)).rsplit('.', 1)[0]
    hdulist = fits.open(file_name, **kwargs)

    header = hdulist[0].header

    tab = Table.read(file_name)

    meta = {'header': header}
    wcs = WCS(hdulist[0].header)
    unit = Unit('Jy')
    uncertainty = StdDevUncertainty(tab["err"])
    data = tab["flux"]

    hdulist.close()

    return Spectrum1DRef(data=data,
                         name=name,
                         wcs=wcs,
                         uncertainty=uncertainty,
                         unit=unit,
                         meta=meta)
Exemple #22
0
    def unit(self, value):
        """
        The unit should be set to a value consistent with the parent NDData
        unit and the uncertainty type.
        """
        if value is not None:
            # Check the hidden attribute below, not the property. The property
            # raises an exception if there is no parent_nddata.
            if self._parent_nddata is not None:
                parent_unit = self.parent_nddata.unit
                try:
                    # Check for consistency with the unit of the parent_nddata
                    self._data_unit_to_uncertainty_unit(parent_unit).to(value)
                except UnitConversionError:
                    raise UnitConversionError("Unit {} is incompatible "
                                              "with unit {} of parent "
                                              "nddata".format(
                                                  value, parent_unit))

            self._unit = Unit(value)
        else:
            self._unit = value
Exemple #23
0
    def calculate_attenuation(self):
        """
        This function ...
        :return:
        """

        # Inform the user
        log.info("Calculating the attenuations ...")

        # The wavelength of the V band
        v_band_wavelength = 0.55 * Unit("micron")

        # Calculate the attenuations of the dust in star-forming regions
        #self.attenuation_sfr = AttenuationCurve()
        # Find the V-band attenuation for the SFR dust
        #v_band_attenuation_sfr = self.attenuation_sfr.attenuation_at(v_band_wavelength)

        # Calculate the attenuations of the diffuse dust component
        self.attenuation_diffuse = AttenuationCurve.from_seds(
            self.total_sed, self.transparent_sed)

        # Find the V-band attenuation for the diffuse dust component
        v_band_attenuation_diffuse = self.attenuation_diffuse.attenuation_at(
            v_band_wavelength)

        # Normalize the attenuation curve to the V-band attenuation
        self.attenuation_diffuse.normalize_at(v_band_wavelength)

        # SED of transparent + delta flux mappings
        #transparent_sfr_sed = self.transparent_sed + delta_flux_mappings

        # Calculate the attenuations for all the dust
        #self.attenuation_total = AttenuationCurve.from_seds(self.total_sed, transparent_sfr_sed)
        # Find the total V-band attenuation
        #v_band_attenuation_total = self.attenuation_total.attenuation_at(v_band_wavelength)

        #print(' V band attenuation from star-forming regions:   ' + str(att_mappings_V))
        print(' V band attenuation from diffuse dust: ' +
              str(v_band_attenuation_diffuse))
Exemple #24
0
    def to_psf3d(self, rad):
        """Create a PSF3D from an analytical PSF.

        Parameters
        ----------
        rad : `~astropy.units.Quantity` or `~astropy.coordinates.Angle`
            the array of position errors (rad) on which the PSF3D will be defined

        Returns
        -------
        psf3d : `~gammapy.irf.PSF3D`
            the PSF3D. It will be defined on the same energy and offset values than the input psf.
        """
        offsets = self.theta
        energy = self.energy
        energy_lo = self.energy_lo
        energy_hi = self.energy_hi
        rad_lo = rad[:-1]
        rad_hi = rad[1:]

        psf_values = np.zeros((rad_lo.shape[0], offsets.shape[0],
                               energy_lo.shape[0])) * Unit("sr-1")

        for i, offset in enumerate(offsets):
            psftable = self.to_energy_dependent_table_psf(offset)
            psf_values[:, i, :] = psftable.evaluate(energy,
                                                    0.5 * (rad_lo + rad_hi)).T

        return PSF3D(
            energy_lo,
            energy_hi,
            offsets,
            rad_lo,
            rad_hi,
            psf_values,
            self.energy_thresh_lo,
            self.energy_thresh_hi,
        )
Exemple #25
0
    def from_image_hdu(cls, image_hdu):
        """
        Create image from ImageHDU.

        Parameters
        ----------
        image_hdu : `astropy.io.fits.ImageHDU`
            Source image HDU.

        Examples
        --------
        >>> from astropy.io import fits
        >>> from gammapy.image import SkyImage
        >>> hdu_list = fits.open('data.fits')
        >>> image = SkyImage.from_image_hdu(hdu_list['myimage'])
        """
        data = image_hdu.data
        header = image_hdu.header
        wcs = WCS(image_hdu.header)

        name = header.get('HDUNAME')
        if name is None:
            name = header.get('EXTNAME')
        try:
            # Validate unit string
            unit = Unit(header['BUNIT'], format='fits').to_string()
        except (KeyError, ValueError):
            unit = None

        meta = OrderedDict(header)

        # parse astropy.io.fits.header._HeaderCommentaryCards as strings
        if 'HISTORY' in meta:
            meta['HISTORY'] = str(meta['HISTORY'])
        if 'COMMENT' in meta:
            meta['COMMENT'] = str(meta['COMMENT'])

        return cls(name, data, wcs, unit, meta)
Exemple #26
0
    def lightcurve(self):
        """Lightcurve (`~gammapy.time.LightCurve`).
        """
        flux = self.data['Flux_History']

        # Flux error is given as asymmetric high/low
        flux_err_lo = self.data['Unc_Flux_History'][:, 0]
        flux_err_hi = self.data['Unc_Flux_History'][:, 1]

        # TODO: Change lightcurve class to support this,
        # then fill appropriately here
        # for now, we just use the mean
        flux_err = 0.5 * (-flux_err_lo + flux_err_hi)
        flux_unit = Unit('cm-2 s-1')

        # Really the time binning is stored in a separate HDU in the FITS
        # catalog file called `Hist_Start`, with a single column `Hist_Start`
        # giving the time binning in MET (mission elapsed time)
        # This is not available here for now.
        # TODO: read that info in `SourceCatalog3FGL` and pass it down to the
        # `SourceCatalogObject3FGL` object somehow.

        # For now, we just hard-code the start and stop time and assume
        # equally-spaced time intervals. This is roughly correct,
        # for plotting the difference doesn't matter, only for analysis
        time_start = Time('2008-08-02T00:33:19')
        time_end = Time('2012-07-31T22:45:47')

        n_points = len(flux)
        time_step = (time_end - time_start) / n_points
        time_bounds = time_start + np.arange(n_points + 1) * time_step
        table = QTable()
        table['TIME_MIN'] = time_bounds[:-1]
        table['TIME_MAX'] = time_bounds[1:]
        table['FLUX'] = flux * flux_unit
        table['FLUX_ERR'] = flux_err * flux_unit
        lc = LightCurve(table)
        return lc
Exemple #27
0
    def _map_transforms_from_table_header(self, table_name):
        """
        create any transforms needed to "undo" ones in the writer
        """
        tab = self._tables[table_name]
        attrs = tab.attrs._f_list()
        for attr in attrs:
            if attr.endswith("_UNIT"):
                colname = attr[:-5]
                tr = QuantityColumnTransform(unit=Unit(tab.attrs[attr]))
                self.add_column_transform(table_name, colname, tr)

            elif attr.endswith("_ENUM"):
                colname = attr[:-5]
                tr = EnumColumnTransform(tab.attrs[attr])
                self.add_column_transform(table_name, colname, tr)

            elif attr.endswith("_TIME_SCALE"):
                colname, _, _ = attr.rpartition("_TIME_SCALE")
                scale = tab.attrs[attr]
                time_format = get_hdf5_attr(tab.attrs,
                                            colname + "_TIME_FORMAT", "mjd")
                transform = TimeColumnTransform(scale=scale,
                                                format=time_format)
                self.add_column_transform(table_name, colname, transform)

            elif attr.endswith("_TRANSFORM_SCALE"):
                colname, _, _ = attr.rpartition("_TRANSFORM_SCALE")
                tr = FixedPointColumnTransform(
                    scale=tab.attrs[attr],
                    offset=get_hdf5_attr(tab.attrs,
                                         colname + "_TRANSFORM_OFFSET", 0),
                    source_dtype=get_hdf5_attr(tab.attrs,
                                               colname + "_TRANSFORM_DTYPE",
                                               "float32"),
                    target_dtype=tab.dtype[colname].base,
                )
                self.add_column_transform(table_name, colname, tr)
Exemple #28
0
	def integrate_psf(self, integration_time, hdu=None):
		"""Integrates psf frames over the input time.

		Args:
			integration_time (Quantity):
				This is used for computing the number of frames 'n_frames', via floor division by the 'timestep'
				attribute.
			hdu (int, str, optional):
				Specifier of the HD Default is None for the first HD
		"""

		# Check input parameters
		if isinstance(integration_time, (int, float)):
			logger.warning(f"Interpreting scalar type integration_time as {integration_time} s")
			integration_time = integration_time * Unit('s')
		elif not isinstance(integration_time, Quantity):
			raise SpecklepyTypeError('integrate_psf', 'integration_time', type(integration_time), 'Quantity')

		if integration_time < self.timestep:
			raise ValueError(f"integrate_psf received integration time {integration_time} shorter than the time "
							 f"resolution of the psf source ({self.timestep})!")

		n_frames = int(integration_time / self.timestep)

		# Read PSF frames from source file
		data = fits.getdata(self.psf_source, hdu)

		self.psf_frame += 1
		if self.psf_frame + n_frames < data.shape[0]:
			self.psf = np.sum(data[self.psf_frame : self.psf_frame+n_frames], axis=0)
		else:
			self.psf = np.sum(data[self.psf_frame : ], axis=0)
			self.psf += np.sum(data[ : (self.psf_frame+n_frames) % data.shape[0]], axis=0)
		self.psf_frame += n_frames - 1
		self.psf_frame = self.psf_frame % data.shape[0]

		# Normalize the integrated PSF
		self.psf = self.normalize(self.psf)
Exemple #29
0
    def spectral_axis(self):
        """
        Returns a Quantity array with the values of the spectral axis.

        *PROBLEM*: THIS IS EXPENSIVE! How do we make this not evaluate each
        time?  Cache?
        """

        spectral_wcs = self.spectral_wcs

        # Lim: What if I have wavelength arrays and I don't want WCS
        # conversion?
        # Tom: this is beyond the scope of the prototype work, your question is
        # more how to make a WCS object that contains a wavelength array. The
        # mixin is for NDData which assumes a WCS has been created (not
        # necessarily a *FITS* WCS, just some transformation object).
        # Adam: We are now assuming that lookup tables ARE WCSes and WCSes
        # can be generated from arrays

        if spectral_wcs.naxis == 0:
            raise TypeError('WCS has no spectral axis')

        # TODO: make pix_to_world wrapper that does this
        # (i.e., make sure fits-wcs and gwcs have same API)
        spectral_axis = spectral_wcs.pix2world(
            np.arange(self._spectral_axis_len), 0)[0]

        # Try to get the dispersion unit information
        try:
            # Where does gwcs store this?
            spectral_unit = self.wcs.wcs.cunit[self.wcs.wcs.spec]
        except AttributeError:
            logging.warning("No spectral_axis unit information in WCS.")
            spectral_unit = Unit("")

        spectral_axis = spectral_axis * spectral_unit

        return spectral_axis
Exemple #30
0
def update_missing_channel_params(channel, **kwargs):
    """Update empty channel parameters using the given input

    This method will only set parameters in the channel if the target
    parameter is `None`.

    Parameters
    ----------
    channel : `~gwpy.detector.Channel`
        channel to update
    **kwargs
        `(key, value)` pairs to set
    """
    target = get_channel(str(channel))
    if isinstance(channel, Channel):
        for param in ['unit', 'sample_rate', 'frametype']:
            if getattr(target, param) is None or (param == 'unit' and getattr(
                    target, param) is Unit('undef')):
                setattr(target, param, getattr(channel, param))
    for param in kwargs:
        if getattr(target, param) is None:
            setattr(target, param, kwargs[param])
    return target
Exemple #31
0
    def __new__(cls, value, unit=None, dtype=None, copy=True, order=None,
                subok=False, ndmin=0):

        if unit is not None:
            # Convert possible string input to a (function) unit.
            unit = Unit(unit)

        if not isinstance(unit, FunctionUnitBase):
            # By default, use value's physical unit.
            value_unit = getattr(value, 'unit', None)
            if value_unit is None:
                # if iterable, see if first item has a unit
                # (mixed lists fail in super call below).
                try:
                    value_unit = getattr(value[0], 'unit')
                except Exception:
                    pass
            physical_unit = getattr(value_unit, 'physical_unit', value_unit)
            unit = cls._unit_class(physical_unit, function_unit=unit)

        # initialise!
        return super().__new__(cls, value, unit, dtype=dtype, copy=copy,
                               order=order, subok=subok, ndmin=ndmin)
Exemple #32
0
def sixdfgs_tabular_fits_loader(file_obj, **kwargs):
    """
    Load the tabular variant of a 6dF Galaxy Survey (6dFGS) file.

    6dFGS used the Six-degree Field instrument on the UK Schmidt Telescope
    (UKST) at the Siding Spring Observatory (SSO) near Coonabarabran,
    Australia. Further details can be found at http://www.6dfgs.net/, or
    https://docs.datacentral.org.au/6dfgs/. Catalogues and spectra were
    produced, with the spectra being provided as both fits tables and as fits
    images. This loads the tabular variant of the spectra. Note that this does
    not include uncertainties - uncertainties are only provided in the image
    variants.

    Parameters
    ----------
    file_obj: str, file-like or HDUList
         FITS file name, object (provided from name by Astropy I/O Registry),
         or HDUList (as resulting from astropy.io.fits.open()).

    Returns
    -------
    data: Spectrum1D
        The 6dF spectrum that is represented by the data in this table.
    """

    with read_fileobj_or_hdulist(file_obj, **kwargs) as hdulist:
        header = hdulist[0].header
        table = Table.read(hdulist)

    flux = Quantity(table["FLUX"])
    wavelength = Quantity(table["WAVE"])

    if flux.unit == COUNTS_PER_SECOND:
        flux._unit = Unit("count/s")
    meta = {"header": header}

    return Spectrum1D(flux=flux, spectral_axis=wavelength, meta=meta)
Exemple #33
0
def loudest_event_metric_factory(column):
    column = column.lower()

    @_use_dqflag
    def loudest_event(segments, before, after=None):
        """Percentage reduction in the amplitude of the loudest event by %s

        Parameters
        ----------
        segments : `DataQualityFlag`, `~glue.segments.segmentlist`
            the set of segments to test
        before : `~glue.ligolw.table.Table`
            the event trigger table to test
        after : `~glue.ligolw.table.Table`, optional
            the remaining triggers after vetoes.
            This is calculated is not given

        Returns
        ------
        reduction : `float`
            the percentage reduction in the amplitude of the loudest event
        """
        if after is None:
            after = before.veto(segments.active)
        try:
            brank = before[column].max()
        except ValueError:  # no triggers to start with
            return 0
        try:
            arank = after[column].max()
        except ValueError:  # no triggers after veto
            return 100
        return (brank - arank) / brank * 100

    loudest_event.__doc__ %= column
    return register_metric(
        Metric(loudest_event, 'Loudest event by %s' % column, unit=Unit('%')))
Exemple #34
0
    def __ilshift__(self, other):
        try:
            other = Unit(other)
        except UnitTypeError:
            return NotImplemented

        if not isinstance(other, self._unit_class):
            return NotImplemented

        try:
            factor = self.unit.physical_unit._to(other.physical_unit)
        except UnitConversionError:
            # Maybe via equivalencies?  Now we do make a temporary copy.
            try:
                value = self._to_value(other)
            except UnitConversionError:
                return NotImplemented

            self.view(np.ndarray)[...] = value
        else:
            self.view(np.ndarray)[...] += self.unit.from_physical(factor)

        self._set_unit(other)
        return self
Exemple #35
0
    def calculate_residuals(self):
        """Calculate residuals and residual errors

        Based on `~gammapy.spectrum.results.SpectrumFitResult` and
        `~gammapy.spectrum.results.FluxPoints`

        Returns
        -------
        residuals : `~astropy.units.Quantity`
            Residuals
        residuals_err : `~astropy.units.Quantity`
            Residual errors
        """
        func = self.fit.to_sherpa_model()
        x = self.points['energy'].quantity
        y = self.points['flux'].quantity
        y_err = self.points['flux_err_hi'].quantity

        func_y = func(x.to('keV').value) * Unit('s-1 cm-2 keV-1')
        residuals = (y - func_y) / y
        # Todo: add correct formular (butterfly)
        residuals_err = y_err / y

        return residuals.decompose(), residuals_err.decompose()
Exemple #36
0
    def __init__(self, array=None, copy=True, unit=None):
        if isinstance(array, NDUncertainty):
            # Given an NDUncertainty class or subclass check that the type
            # is the same.
            if array.uncertainty_type != self.uncertainty_type:
                raise IncompatibleUncertaintiesException
            # Check if two units are given and take the explicit one then.
            if (unit is not None and unit != array._unit):
                # TODO : Clarify it (see NDData.init for same problem)?
                log.info("overwriting Uncertainty's current "
                         "unit with specified unit.")
            elif array._unit is not None:
                unit = array.unit
            array = array.array

        elif isinstance(array, Quantity):
            # Check if two units are given and take the explicit one then.
            if (unit is not None and array.unit is not None
                    and unit != array.unit):
                log.info("overwriting Quantity's current "
                         "unit with specified unit.")
            elif array.unit is not None:
                unit = array.unit
            array = array.value

        if unit is None:
            self._unit = None
        else:
            self._unit = Unit(unit)

        if copy:
            array = deepcopy(array)
            unit = deepcopy(unit)

        self.array = array
        self.parent_nddata = None  # no associated NDData - until it is set!
Exemple #37
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 #38
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 #39
0
 def to_tree(cls, node, ctx):
     if isinstance(node, six.string_types):
         node = Unit(node, format='vounit', parse_strict='warn')
     if isinstance(node, UnitBase):
         return node.to_string(format='vounit')
     raise TypeError("'{0}' is not a valid unit".format(node))
Exemple #40
0
class FunctionUnitBase(metaclass=ABCMeta):
    """Abstract base class for function units.

    Function units are functions containing a physical unit, such as dB(mW).
    Most of the arithmetic operations on function units are defined in this
    base class.

    While instantiation is defined, this class should not be used directly.
    Rather, subclasses should be used that override the abstract properties
    `_default_function_unit` and `_quantity_class`, and the abstract methods
    `from_physical`, and `to_physical`.

    Parameters
    ----------
    physical_unit : `~astropy.units.Unit` or `string`
        Unit that is encapsulated within the function unit.
        If not given, dimensionless.

    function_unit :  `~astropy.units.Unit` or `string`
        By default, the same as the function unit set by the subclass.
    """
    # ↓↓↓ the following four need to be set by subclasses
    # Make this a property so we can ensure subclasses define it.
    @property
    @abstractmethod
    def _default_function_unit(self):
        """Default function unit corresponding to the function.

        This property should be overridden by subclasses, with, e.g.,
        `~astropy.unit.MagUnit` returning `~astropy.unit.mag`.
        """

    # This has to be a property because the function quantity will not be
    # known at unit definition time, as it gets defined after.
    @property
    @abstractmethod
    def _quantity_class(self):
        """Function quantity class corresponding to this function unit.

        This property should be overridden by subclasses, with, e.g.,
        `~astropy.unit.MagUnit` returning `~astropy.unit.Magnitude`.
        """

    @abstractmethod
    def from_physical(self, x):
        """Transformation from value in physical to value in function units.

        This method should be overridden by subclasses.  It is used to
        provide automatic transformations using an equivalency.
        """

    @abstractmethod
    def to_physical(self, x):
        """Transformation from value in function to value in physical units.

        This method should be overridden by subclasses.  It is used to
        provide automatic transformations using an equivalency.
        """
    # ↑↑↑ the above four need to be set by subclasses

    # have priority over arrays, regular units, and regular quantities
    __array_priority__ = 30000

    def __init__(self, physical_unit=None, function_unit=None):
        if physical_unit is None:
            self._physical_unit = dimensionless_unscaled
        else:
            self._physical_unit = Unit(physical_unit)
            if (not isinstance(self._physical_unit, UnitBase) or
                self._physical_unit.is_equivalent(
                    self._default_function_unit)):
                raise ValueError("Unit {0} is not a physical unit."
                                 .format(self._physical_unit))

        if function_unit is None:
            self._function_unit = self._default_function_unit
        else:
            # any function unit should be equivalent to subclass default
            function_unit = Unit(getattr(function_unit, 'function_unit',
                                         function_unit))
            if function_unit.is_equivalent(self._default_function_unit):
                self._function_unit = function_unit
            else:
                raise ValueError("Cannot initialize '{0}' instance with "
                                 "function unit '{1}', as it is not "
                                 "equivalent to default function unit '{2}'."
                                 .format(self.__class__.__name__,
                                         function_unit,
                                         self._default_function_unit))

    def _copy(self, physical_unit=None):
        """Copy oneself, possibly with a different physical unit."""
        if physical_unit is None:
            physical_unit = self.physical_unit
        return self.__class__(physical_unit, self.function_unit)

    @property
    def physical_unit(self):
        return self._physical_unit

    @property
    def function_unit(self):
        return self._function_unit

    @property
    def equivalencies(self):
        """List of equivalencies between function and physical units.

        Uses the `from_physical` and `to_physical` methods.
        """
        return [(self, self.physical_unit,
                 self.to_physical, self.from_physical)]

    # ↓↓↓ properties/methods required to behave like a unit
    def decompose(self, bases=set()):
        """Copy the current unit with the physical unit decomposed.

        For details, see `~astropy.units.UnitBase.decompose`.
        """
        return self._copy(self.physical_unit.decompose(bases))

    @property
    def si(self):
        """Copy the current function unit with the physical unit in SI."""
        return self._copy(self.physical_unit.si)

    @property
    def cgs(self):
        """Copy the current function unit with the physical unit in CGS."""
        return self._copy(self.physical_unit.cgs)

    def _get_physical_type_id(self):
        """Get physical type corresponding to physical unit."""
        return self.physical_unit._get_physical_type_id()

    @property
    def physical_type(self):
        """Return the physical type of the physical unit (e.g., 'length')."""
        return self.physical_unit.physical_type

    def is_equivalent(self, other, equivalencies=[]):
        """
        Returns `True` if this unit is equivalent to ``other``.

        Parameters
        ----------
        other : unit object or string or tuple
            The unit to convert to. If a tuple of units is specified, this
            method returns true if the unit matches any of those in the tuple.

        equivalencies : list of equivalence pairs, optional
            A list of equivalence pairs to try if the units are not
            directly convertible.  See :ref:`unit_equivalencies`.
            This list is in addition to the built-in equivalencies between the
            function unit and the physical one, as well as possible global
            defaults set by, e.g., `~astropy.units.set_enabled_equivalencies`.
            Use `None` to turn off any global equivalencies.

        Returns
        -------
        bool
        """
        if isinstance(other, tuple):
            return any(self.is_equivalent(u, equivalencies=equivalencies)
                       for u in other)

        other_physical_unit = getattr(other, 'physical_unit', (
            dimensionless_unscaled if self.function_unit.is_equivalent(other)
            else other))

        return self.physical_unit.is_equivalent(other_physical_unit,
                                                equivalencies)

    def to(self, other, value=1., equivalencies=[]):
        """
        Return the converted values in the specified unit.

        Parameters
        ----------
        other : `~astropy.units.Unit` object, `~astropy.units.function.FunctionUnitBase` object or string
            The unit to convert to.

        value : scalar int or float, or sequence convertible to array, optional
            Value(s) in the current unit to be converted to the specified unit.
            If not provided, defaults to 1.0.

        equivalencies : list of equivalence pairs, optional
            A list of equivalence pairs to try if the units are not
            directly convertible.  See :ref:`unit_equivalencies`.
            This list is in meant to treat only equivalencies between different
            physical units; the build-in equivalency between the function
            unit and the physical one is automatically taken into account.

        Returns
        -------
        values : scalar or array
            Converted value(s). Input value sequences are returned as
            numpy arrays.

        Raises
        ------
        UnitsError
            If units are inconsistent.
        """
        # conversion to one's own physical unit should be fastest
        if other is self.physical_unit:
            return self.to_physical(value)

        other_function_unit = getattr(other, 'function_unit', other)
        if self.function_unit.is_equivalent(other_function_unit):
            # when other is an equivalent function unit:
            # first convert physical units to other's physical units
            other_physical_unit = getattr(other, 'physical_unit',
                                          dimensionless_unscaled)
            if self.physical_unit != other_physical_unit:
                value_other_physical = self.physical_unit.to(
                    other_physical_unit, self.to_physical(value),
                    equivalencies)
                # make function unit again, in own system
                value = self.from_physical(value_other_physical)

            # convert possible difference in function unit (e.g., dex->dB)
            return self.function_unit.to(other_function_unit, value)

        else:
            # when other is not a function unit
            return self.physical_unit.to(other, self.to_physical(value),
                                         equivalencies)

    def is_unity(self):
        return False

    def __eq__(self, other):
        return (self.physical_unit == getattr(other, 'physical_unit',
                                              dimensionless_unscaled) and
                self.function_unit == getattr(other, 'function_unit', other))

    def __ne__(self, other):
        return not self.__eq__(other)

    def __mul__(self, other):
        if isinstance(other, (str, UnitBase, FunctionUnitBase)):
            if self.physical_unit == dimensionless_unscaled:
                # If dimensionless, drop back to normal unit and retry.
                return self.function_unit * other
            else:
                raise UnitsError("Cannot multiply a function unit "
                                 "with a physical dimension with any unit.")
        else:
            # Anything not like a unit, try initialising as a function quantity.
            try:
                return self._quantity_class(other, unit=self)
            except Exception:
                return NotImplemented

    def __rmul__(self, other):
        return self.__mul__(other)

    def __div__(self, other):
        if isinstance(other, (str, UnitBase, FunctionUnitBase)):
            if self.physical_unit == dimensionless_unscaled:
                # If dimensionless, drop back to normal unit and retry.
                return self.function_unit / other
            else:
                raise UnitsError("Cannot divide a function unit "
                                 "with a physical dimension by any unit.")
        else:
            # Anything not like a unit, try initialising as a function quantity.
            try:
                return self._quantity_class(1./other, unit=self)
            except Exception:
                return NotImplemented

    def __rdiv__(self, other):
        if isinstance(other, (str, UnitBase, FunctionUnitBase)):
            if self.physical_unit == dimensionless_unscaled:
                # If dimensionless, drop back to normal unit and retry.
                return other / self.function_unit
            else:
                raise UnitsError("Cannot divide a function unit "
                                 "with a physical dimension into any unit")
        else:
            # Don't know what to do with anything not like a unit.
            return NotImplemented

    __truediv__ = __div__

    __rtruediv__ = __rdiv__

    def __pow__(self, power):
        if power == 0:
            return dimensionless_unscaled
        elif power == 1:
            return self._copy()

        if self.physical_unit == dimensionless_unscaled:
            return self.function_unit ** power

        raise UnitsError("Cannot raise a function unit "
                         "with a physical dimension to any power but 0 or 1.")

    def __pos__(self):
        return self._copy()

    def to_string(self, format='generic'):
        """
        Output the unit in the given format as a string.

        The physical unit is appended, within parentheses, to the function
        unit, as in "dB(mW)", with both units set using the given format

        Parameters
        ----------
        format : `astropy.units.format.Base` instance or str
            The name of a format or a formatter object.  If not
            provided, defaults to the generic format.
        """
        if format not in ('generic', 'unscaled', 'latex'):
            raise ValueError("Function units cannot be written in {0} format. "
                             "Only 'generic', 'unscaled' and 'latex' are "
                             "supported.".format(format))
        self_str = self.function_unit.to_string(format)
        pu_str = self.physical_unit.to_string(format)
        if pu_str == '':
            pu_str = '1'
        if format == 'latex':
            self_str += r'$\mathrm{{\left( {0} \right)}}$'.format(
                pu_str[1:-1])   # need to strip leading and trailing "$"
        else:
            self_str += '({0})'.format(pu_str)
        return self_str

    def __str__(self):
        """Return string representation for unit."""
        self_str = str(self.function_unit)
        pu_str = str(self.physical_unit)
        if pu_str:
            self_str += '({0})'.format(pu_str)
        return self_str

    def __repr__(self):
        # By default, try to give a representation using `Unit(<string>)`,
        # with string such that parsing it would give the correct FunctionUnit.
        if callable(self.function_unit):
            return 'Unit("{0}")'.format(self.to_string())

        else:
            return '{0}("{1}"{2})'.format(
                self.__class__.__name__, self.physical_unit,
                "" if self.function_unit is self._default_function_unit
                else ', unit="{0}"'.format(self.function_unit))

    def _repr_latex_(self):
        """
        Generate latex representation of unit name.  This is used by
        the IPython notebook to print a unit with a nice layout.

        Returns
        -------
        Latex string
        """
        return self.to_string('latex')

    def __hash__(self):
        return hash((self.function_unit, self.physical_unit))
Exemple #41
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 #42
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 #43
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 #44
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
Exemple #45
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)