示例#1
0
 def test_add_row_cannot_mask_column_raises_typeerror(self):
     t = QTable()
     t['a'] = [1, 2] * u.m
     t.add_row((3 * u.m,))  # No problem
     with pytest.raises(ValueError) as exc:
         t.add_row((3 * u.m,), mask=(True,))
     assert (exc.value.args[0].splitlines()
             == ["Unable to insert row because of exception in column 'a':",
                 "mask was supplied for column 'a' but it does not support masked values"])
示例#2
0
    def line_stats(self, x):
        """
        Calculate statistics over individual line profiles.

        Parameters
        ----------
        x : :class:`~u.Quantity`
            The input dispersion in either wavelength/frequency or velocity
            space.

        Returns
        -------
        tab : :class:`~astropy.table.QTable`
            A table detailing the calculated statistics.
        """
        tab = QTable(names=[
            'name', 'wave', 'col_dens', 'v_dop', 'delta_v', 'delta_lambda',
            'ew', 'dv90', 'fwhm'
        ],
                     dtype=('S10', 'f8', 'f8', 'f8', 'f8', 'f8', 'f8', 'f8',
                            'f8'))

        tab['wave'].unit = u.AA
        tab['v_dop'].unit = u.km / u.s
        tab['ew'].unit = u.AA
        tab['dv90'].unit = u.km / u.s
        tab['fwhm'].unit = u.AA
        tab['delta_v'].unit = u.km / u.s
        tab['delta_lambda'].unit = u.AA

        for line in self.lines:
            disp_equiv = u.spectral() + DOPPLER_CONVERT[
                self.velocity_convention](line.lambda_0.quantity)

            with u.set_enabled_equivalencies(disp_equiv):
                vel = x.to('km/s')
                wav = x.to('Angstrom')

            # Generate the spectrum1d object for this line profile
            ew = equivalent_width(wav, line(wav))
            dv90 = delta_v_90(vel, line(wav))
            fwhm = full_width_half_max(wav, line(wav))

            tab.add_row([
                line.name, line.lambda_0, line.column_density, line.v_doppler,
                line.delta_v, line.delta_lambda, ew, dv90, fwhm
            ])

        return tab
示例#3
0
def fits_1():
    """
    COSMOS2015v1.1:         length = 1182108
    pdz_cosmos2015_v1.3_t1: length =  606887
    FLAG_COSMOS:            length =  576762
    FLAG_HJMCC:             length =  606887
    FLAG_DEEP:              length =  227278
    FLAG_PETER:             length =  539706
    """

    data_full = fits.open('COSMOS2015v1.1.fits')[1].data
    data_phot = Table.read('pdz_cosmos2015_v1.3_t1.csv', format='ascii.csv')

    # print(data['FLAG_HJMCC'])
    # print(data['FLAG_DEEP'])
    # print(data['FLAG_COSMOS'])
    # print(data['FLAG_PETER'])
    # print(data['number'])

    ind_set = set()
    ind_dict = {}
    for i, ind in enumerate(data_phot['ID']):
        ind_set.add(ind)
        ind_dict[ind] = i

    max_ind = 1182108
    subset = 'FLAG_PETER'

    names = data_phot.colnames
    values = [[] for i in names]
    table = QTable(values, names=data_phot.colnames)
    for i in range(max_ind):
        if data_full[subset][i] == 0 and (i + 1) in ind_set:
            ind = ind_dict[i + 1]
            print(str(i + 1)[:2], end=' ')
            table.add_row(data_phot[ind])

    ascii.write(table, f'{subset}.csv', format='csv')
示例#4
0
    def region_stats(self, x, rest_wavelength, rel_tol=1e-2, abs_tol=1e-5):
        """
        Calculate statistics over arbitrary line regions given some tolerance
        from the continuum.

        Parameters
        ----------
        x : :class:`~u.Quantity`
            The input dispersion in either wavelength/frequency or velocity
            space.
        rest_wavelength : :class:`~u.Quantity`
            The rest frame wavelength used in conversions between wavelength/
            frequency and velocity space.
        rel_tol : float
            The relative tolerance parameter.
        abs_tol : float
            The absolute tolerance parameter.

        Returns
        -------
        tab : :class:`~astropy.table.QTable`
            A table detailing the calculated statistics.
        """
        y = self(x)

        if self.output_type == 'flux':
            y = self.continuum(x) - y
        else:
            y -= self.continuum(x)

        # Calculate the regions in the raw data
        # absolute(a - b) <= (atol + rtol * absolute(b))
        regions = {(reg[0], reg[1]): []
                   for reg in find_regions(y, rel_tol=rel_tol, abs_tol=abs_tol)
                   }
        tab = QTable(names=[
            'region_start', 'region_end', 'rest_wavelength', 'ew', 'dv90',
            'fwhm'
        ],
                     dtype=('f8', 'f8', 'f8', 'f8', 'f8', 'f8'))

        tab['region_start'].unit = x.unit
        tab['region_end'].unit = x.unit
        tab['rest_wavelength'].unit = u.AA
        tab['ew'].unit = u.AA
        tab['dv90'].unit = u.km / u.s
        tab['fwhm'].unit = u.AA

        for mn_bnd, mx_bnd in regions:
            mask = (x > x[mn_bnd]) & (x < x[mx_bnd])
            x_reg = x[mask]
            y_reg = y[mask]

            disp_equiv = u.spectral() + DOPPLER_CONVERT[
                self.velocity_convention](rest_wavelength)

            with u.set_enabled_equivalencies(disp_equiv):
                vel = x_reg.to('km/s')
                wav = x_reg.to('Angstrom')

            # Generate the spectrum1d object for this line profile
            ew = equivalent_width(wav, y_reg)
            dv90 = delta_v_90(vel, y_reg)
            fwhm = full_width_half_max(wav, y_reg)

            tab.add_row(
                [x[mn_bnd], x[mx_bnd], rest_wavelength, ew, dv90, fwhm])

        return tab
示例#5
0
文件: geom.py 项目: gammapy/gammapy
    def group_table(self, edges):
        """Compute bin groups table for the map axis, given coarser bin edges.

        Parameters
        ----------
        edges : `~astropy.units.Quantity`
            Group bin edges.

        Returns
        -------
        groups : `~astropy.table.Table`
            Map axis group table.
        """
        # TODO: try to simplify this code
        if not self.node_type == "edges":
            raise ValueError("Only edge based map axis can be grouped")

        edges_pix = self.coord_to_pix(edges)
        edges_pix = np.clip(edges_pix, -0.5, self.nbin - 0.5)
        edges_idx = np.round(edges_pix + 0.5) - 0.5
        edges_idx = np.unique(edges_idx)
        edges_ref = self.pix_to_coord(edges_idx) * self.unit

        groups = QTable()
        groups["{}_min".format(self.name)] = edges_ref[:-1]
        groups["{}_max".format(self.name)] = edges_ref[1:]

        groups["idx_min"] = (edges_idx[:-1] + 0.5).astype(int)
        groups["idx_max"] = (edges_idx[1:] - 0.5).astype(int)

        if len(groups) == 0:
            raise ValueError("No overlap between reference and target edges.")

        groups["bin_type"] = "normal   "

        edge_idx_start, edge_ref_start = edges_idx[0], edges_ref[0]
        if edge_idx_start > 0:
            underflow = {
                "bin_type": "underflow",
                "idx_min": 0,
                "idx_max": edge_idx_start,
                "{}_min".format(self.name): self.pix_to_coord(-0.5) * self.unit,
                "{}_max".format(self.name): edge_ref_start,
            }
            groups.insert_row(0, vals=underflow)

        edge_idx_end, edge_ref_end = edges_idx[-1], edges_ref[-1]

        if edge_idx_end < (self.nbin - 0.5):
            overflow = {
                "bin_type": "overflow",
                "idx_min": edge_idx_end + 1,
                "idx_max": self.nbin - 1,
                "{}_min".format(self.name): edge_ref_end,
                "{}_max".format(self.name): self.pix_to_coord(self.nbin - 0.5)
                * self.unit,
            }
            groups.add_row(vals=overflow)

        group_idx = Column(np.arange(len(groups)))
        groups.add_column(group_idx, name="group_idx", index=0)
        return groups
示例#6
0
文件: core.py 项目: gianninapr/sbpy
    def apply(self, data, name, unit=None):
        """Apply an arbitrarily shaped sequence as additional column to a
        `~sbpy.data.DataClass` object and reshape it accordingly.

        Parameters
        ----------
        data : list or iterable `~astropy.units.Quantity` object
            Data to be added in a new column in form of a one-dimensional
            list or a two-dimensional nested sequence. Each element in
            ``data``
            corresponds to one of the rows in the existing data table. If
            an element
            of ``data`` is a list, the corresponding data table row is
            repeated the same the number of times as there are elements in
            this sublist. If ``data`` is
            provided as a flat list and has the same length as the current
            data table, ``data`` will be simply added as a column to the data
            table and the length of the data table will not change. If
            ``data`` is provided as a `~astropy.units.Quantity` object (only
            possible for flat lists), its
            unit is adopted, unless ``unit`` is specified (not None).
        name : str
            Name of the new data column.
        unit : `~astropy.units` object or str, optional
            Unit to be applied to the new column. Default:
            `None`

        Returns
        -------
        None

        Note
        ----
        As a result of this method, the length of the underlying data table
        will be the same as the length of the flattened `data` parameter.

        Examples
        --------
        Imagine the following scenario: you obtain photometric measurements
        of the same asteroid over a number of nights. The following
        `~sbpy.data.Ephem` object summarizes the observations:

        >>> from sbpy.data import Ephem
        >>> import astropy.units as u
        >>> obs = Ephem.from_columns([[2451223, 2451224, 2451226]*u.d,
        ...                           [120.1, 121.3, 124.9]*u.deg,
        ...                           [12.4, 12.2, 10.8]*u.deg],
        ...                          names=('JD', 'RA', 'DEC'))
        >>> obs
        <QTable length=3>
            JD       RA     DEC
            d       deg     deg
         float64  float64 float64
        --------- ------- -------
        2451223.0   120.1    12.4
        2451224.0   121.3    12.2
        2451226.0   124.9    10.8

        After analyzing the observations, you would like to add the
        measured apparent V-band magnitudes to this object. You have
        one observation from the first night, two from the second night,
        and three from the third night. Instead of re-creating ``obs``,
        `~sbpy.data.DataClass.apply` offers a convenient way to
        supplement ``obs``:

        >>> obs.apply([[12.1], [12.5, 12.6], [13.5, 13.4, 13.5]],
        ...           name='V', unit='mag')
        >>> obs
        <QTable length=6>
            JD       RA     DEC      V
            d       deg     deg     mag
         float64  float64 float64 float64
        --------- ------- ------- -------
        2451223.0   120.1    12.4    12.1
        2451224.0   121.3    12.2    12.5
        2451224.0   121.3    12.2    12.6
        2451226.0   124.9    10.8    13.5
        2451226.0   124.9    10.8    13.4
        2451226.0   124.9    10.8    13.5

        Note how the data table has been re-arranged and rows have been
        duplicated in order to provide the expected shape.
        """
        _newtable = None

        # strip units off Quantity objects
        if isinstance(data, u.Quantity):
            unit = data.unit
            data = data.value

        if len(data) != len(self.table):
            raise DataClassError('Data parameter must have '
                                 'same length as self._table')

        _newcolumn = array([])
        for i, val in enumerate(data):
            if not isinstance(val, (list, tuple, ndarray)):
                val = [val]
            _newcolumn = hstack([_newcolumn, val])
            # add corresponding row from _table for each element in val
            for j in range(len(val)):
                # initialize new QTable object
                if _newtable is None:
                    _newtable = QTable(self.table[0])
                    continue
                _newtable.add_row(self.table[i])

        # add new column
        _newtable.add_column(Column(_newcolumn, name=name, unit=unit))

        self._table = _newtable
示例#7
0
class DataClass():
    """`~sbpy.data.DataClass` serves as the base class for all data
    container classes in `sbpy` in order to provide consistent
    functionality throughout all these classes.

    The core of `~sbpy.data.DataClass` is an `~astropy.table.QTable`
    object (referred to as the `data table` below) - a type of
    `~astropy.table.Table` object that supports the `~astropy.units`
    formalism on a per-column base - which already provides most of
    the required functionality. `~sbpy.data.DataClass` objects can be
    manually generated from dictionaries
    (`~sbpy.data.DataClass.from_dict`), `~numpy.array`-like
    (`~sbpy.data.DataClass.from_array`) objects, or directly from
    another `~astropy.table.QTable` object.

    A few high-level functions for table data access or modification
    are provided; other, more complex modifications can be applied to
    the underlying table object (`~sbpy.data.DataClass.table`) directly.

    """

    def __init__(self, data):
        self._table = QTable()
        # self.altkeys = {}  # dictionary for alternative column names

        if (len(data.items()) == 1 and 'table' in data.keys()):
            # single item provided named 'table' -> already Table object
            self._table = QTable(data['table'])
        else:
            # treat kwargs as dictionary
            for key, val in data.items():
                try:
                    unit = val.unit
                    val = val.value
                except AttributeError:
                    unit = None

                # check if val is already list-like
                try:
                    val[0]
                except (TypeError, IndexError):
                    val = [val]

                self._table[key] = Column(val, unit=unit)

    @classmethod
    def from_dict(cls, data):
        """Create `~sbpy.data.DataClass` object from dictionary or list of
        dictionaries.

        Parameters
        ----------
        data : `~collections.OrderedDict`, dictionary or list (or similar) of
             dictionaries Data that will be ingested in
             `~sbpy.data.DataClass` object.  Each dictionary creates a
             row in the data table. Dictionary keys are used as column
             names; corresponding values must be scalar (cannot be
             lists or arrays). If a list of dictionaries is provided,
             all dictionaries have to provide the same set of keys
             (and units, if used at all).

        Returns
        -------
        `DataClass` object

        Examples
        --------
        >>> import astropy.units as u
        >>> from sbpy.data import Orbit
        >>> orb = Orbit.from_dict({'a': 2.7674*u.au,
        ...                        'e': 0.0756,
        ...                        'i': 10.59321*u.deg})

        Since dictionaries have no specific order, the ordering of the
        column in the example above is not defined. If your data table
        requires a specific order, use an ``OrderedDict``:

        >>> from collections import OrderedDict
        >>> orb = Orbit.from_dict(OrderedDict([('a', 2.7674*u.au),
        ...                                    ('e', 0.0756),
        ...                                    ('i', 10.59321*u.deg)]))
        >>> print(orb)
        <QTable length=1>
           a       e       i
           AU             deg
        float64 float64 float64
        ------- ------- --------
         2.7674  0.0756 10.59321
        >>> print(orb.column_names) # doctest: +SKIP
        <TableColumns names=('a','e','i')>
        >>> print(orb.table['a', 'e', 'i'])
          a      e       i
          AU            deg
        ------ ------ --------
        2.7674 0.0756 10.59321

        """
        if isinstance(data, (dict, OrderedDict)):
            return cls(data)
        elif isinstance(data, (list, ndarray, tuple)):
            # build table from first dict and append remaining rows
            tab = cls(data[0])
            for row in data[1:]:
                tab.add_rows(row)
            return tab
        else:
            raise TypeError('this function requires a dictionary or a '
                            'list of dictionaries')

    @classmethod
    def from_array(cls, data, names):
        """Create `~sbpy.data.DataClass` object from list, `~numpy.ndarray`,
        or tuple.

        Parameters
        ----------
        data : list, `~numpy.ndarray`, or tuple
            Data that will be ingested in `DataClass` object. A one
            dimensional sequence will be interpreted as a single row. Each
            element that is itself a sequence will be interpreted as a
            column.
        names : list
            Column names, must have the same number of names as data columns.

        Returns
        -------
        `DataClass` object

        Examples
        --------
        >>> from sbpy.data import DataClass
        >>> import astropy.units as u
        >>> dat = DataClass.from_array([[1, 2, 3]*u.deg,
        ...                             [4, 5, 6]*u.km,
        ...                             ['a', 'b', 'c']],
        ...                            names=('a', 'b', 'c'))
        >>> print(dat.table)
         a   b   c
        deg  km
        --- --- ---
        1.0 4.0   a
        2.0 5.0   b
        3.0 6.0   c

        """

        if isinstance(data, (list, ndarray, tuple)):
            return cls.from_dict(OrderedDict(zip(names, data)))
        else:
            raise TypeError('this function requires a list, tuple or a '
                            'numpy array')

    @classmethod
    def from_table(cls, data):
        """Create `DataClass` object from `~astropy.table.Table` or
        `astropy.table.QTable` object.

        Parameters
        ----------
        data : astropy `Table` object, mandatory
             Data that will be ingested in `DataClass` object.

        Returns
        -------
        `DataClass` object

        Examples
        --------
        >>> from astropy.table import QTable
        >>> import astropy.units as u
        >>> from sbpy.data import DataClass
        >>> tab = QTable([[1,2,3]*u.kg,
        ...               [4,5,6]*u.m/u.s,],
        ...              names=['mass', 'velocity'])
        >>> dat = DataClass.from_table(tab)
        >>> print(dat.table)
        mass velocity
         kg   m / s
        ---- --------
         1.0      4.0
         2.0      5.0
         3.0      6.0
        """

        return cls({'table': data})

    @classmethod
    def from_file(cls, filename, **kwargs):
        """Create `DataClass` object from a file using
        `~astropy.table.Table.read`.

        Parameters
        ----------
        filename : str
             Name of the file that will be read and parsed.
        **kwargs : additional parameters
             Optional parameters that will be passed on to
             `~astropy.table.Table.read`.

        Returns
        -------
        `DataClass` object

        Notes
        -----
        This function is merely a wrapper around
        `~astropy.table.Table.read`. Please refer to the documentation of
        that function for additional information on optional parameters
        and data formats that are available. Furthermore, note that this
        function is not able to identify units. If you want to work with
        `~astropy.units` you have to assign them manually to the object
        columns.

        Examples
        --------
        >>> from sbpy.data import DataClass

        >>> dat = DataClass.from_file('data.txt',
        ...                           format='ascii') # doctest: +SKIP
        """

        data = QTable.read(filename, **kwargs)

        return cls({'table': data})

    def to_file(self, filename, format='ascii', **kwargs):
        """Write object to a file using
        `~astropy.table.Table.write`.

        Parameters
        ----------
        filename : str
             Name of the file that will be written.
        format : str, optional
             Data format in which the file should be written. Default:
             ``ASCII``
        **kwargs : additional parameters
             Optional parameters that will be passed on to
             `~astropy.table.Table.write`.

        Returns
        -------
        None

        Notes
        -----
        This function is merely a wrapper around
        `~astropy.table.Table.write`. Please refer to the
        documentation of that function for additional information on
        optional parameters and data formats that are
        available. Furthermore, note that this function is not able to
        write unit information to the file.

        Examples
        --------
        >>> from sbpy.data import DataClass
        >>> import astropy.units as u
        >>> dat = DataClass.from_array([[1, 2, 3]*u.deg,
        ...                             [4, 5, 6]*u.km,
        ...                             ['a', 'b', 'c']],
        ...                            names=('a', 'b', 'c'))
        >>> dat.to_file('test.txt')

        """

        self._table.write(filename, format=format, **kwargs)

    def __len__(self):
        """Get number of data elements in _table"""
        return len(self._table)

    def __getattr__(self, field):
        """Get attribute from ``self._table` (columns, rows); checks
        for and may use alternative field names."""

        if field in dir(self):
            return self.field
        else:
            try:
                field = self._translate_columns(field)[0]
                return self._table[field]
            except (KeyError, IndexError, AttributeError):
                raise AttributeError('Attribute {:s} not available.'.format(
                    field))

    def __repr__(self):
        """Return representation of the underlying data table
        (``self._table.__repr__()``)"""
        return self._table.__repr__()

    def __getitem__(self, ident):
        """Return columns or rows from data table (``self._table``); checks
        for and may use alternative field names."""

        # iterable
        if isinstance(ident, (list, tuple, ndarray)):
            if all([isinstance(i, str) for i in ident]):
                # list of column names
                self = self._convert_columns(ident)
                newkeylist = [self._translate_columns(i)[0] for i in ident]
                ident = newkeylist
                # return as new DataClass object
                return self.from_table(self._table[ident])
            # ignore lists of boolean (masks)
            elif all([isinstance(i, bool) for i in ident]):
                pass
            # ignore lists of integers
            elif all([isinstance(i, int) for i in ident]):
                pass
        # individual strings
        elif isinstance(ident, str):
            self = self._convert_columns(ident)
            ident = self._translate_columns(ident)[0]

        # return as element from self_table
        return self._table[ident]

    def __setitem__(self, *args):
        """Refer cls.__setitem__ to self._table"""
        self._table.__setitem__(*args)

    def _translate_columns(self, target_colnames):
        """Translate target_colnames to the corresponding column names
        present in this object's table. Returns a list of actual column
        names present in this object that corresponds to target_colnames
        (order is preserved). Raises KeyError if not all columns are
        present or one or more columns could not be translated.
        """

        if not isinstance(target_colnames, (list, ndarray, tuple)):
            target_colnames = [target_colnames]

        translated_colnames = deepcopy(target_colnames)
        for idx, colname in enumerate(target_colnames):
            # colname is already a column name in self.table
            if colname in self.column_names:
                continue
            # colname is an alternative column name
            elif colname in sum(conf.fieldnames, []):
                for alt in conf.fieldnames[conf.fieldname_idx[colname]]:
                    # translation available for colname
                    if alt in self.column_names:
                        translated_colnames[idx] = alt
                        break
            # colname is unknown, raise a KeyError
            else:
                raise KeyError('field {:s} not available.'.format(
                    colname))

        return translated_colnames

    def _convert_columns(self, target_colnames):
        """Convert target_colnames, if necessary. Converted columns will be
        added as columns to ``self`` using the field names provided in
        target_colnames. No error is returned by this function if a
        field could not be converted.
        """

        if not isinstance(target_colnames, (list, ndarray, tuple)):
            target_colnames = [target_colnames]

        for colname in target_colnames:
            # ignore, if colname is unknown (KeyError)
            try:
                # ignore if colname has already been converted
                if any([alt in self.column_names for alt
                        in conf.fieldnames[conf.fieldname_idx[colname]]]):
                    continue
                # consider alternative names for colname -> alt
                for alt in conf.fieldnames[conf.fieldname_idx[colname]]:
                    if alt in list(conf.field_eq.keys()):
                        # conversion identified
                        convname = self._translate_columns(
                            list(conf.field_eq[alt].keys())[0])[0]
                        convfunc = list(conf.field_eq[alt].values())[0]
                        if convname in self.column_names:
                            # create new column for the converted field
                            self.add_column(convfunc(self.table[convname]),
                                            colname)
                            break
            except KeyError:
                continue

        return self

    @property
    def table(self):
        """Return `~astropy.table.QTable` object containing all data."""
        return self._table

    @property
    def column_names(self):
        """Return a list of all column names in the data table."""
        return self._table.columns

    def add_rows(self, rows, join_type='inner'):
        """Append additional rows to the existing data table. An individual
        row can be provided in list, tuple, `~numpy.ndarray`, or
        dictionary form. Multiple rows can be provided in the form of
        a list, tuple, or `~numpy.ndarray` of individual
        rows. Multiple rows can also be provided in the form of a
        `~astropy.table.QTable` or another `~sbpy.data.DataClass`
        object. Parameter ``join_type`` defines which columns appear
        in the final output table: ``inner`` only keeps those columns
        that appear in both the original table and the rows to be
        added; ``outer`` will keep all columns and populate some with
        placeholders, if necessary. In case of a list, the list
        elements must be in the same order as the table columns. In
        either case, matching `~astropy.units` must be provided in
        ``rows`` if used in the data table.

        Parameters
        ----------
        rows : list, tuple, `~numpy.ndarray`, dict, or `~collections.OrderedDict`
            Data to be appended to the table; required to have the same
            length as the existing table, as well as the same units.
        join_type : str, optional
            Defines which columns are kept in the output table: ``inner``
            only keeps those columns that appear in both the original
            table and the rows to be added; ``outer`` will keep all
            columns and populate them with placeholders, if necessary.
            Default: ``inner``

        Returns
        -------
        n : int, the total number of rows in the data table

        Examples
        --------
        >>> from sbpy.data import DataClass
        >>> import astropy.units as u
        >>> dat = DataClass.from_array([[1, 2, 3]*u.Unit('m'),
        ...                             [4, 5, 6]*u.m/u.s,
        ...                             ['a', 'b', 'c']],
        ...                            names=('a', 'b', 'c'))
        >>> dat.add_rows({'a': 5*u.m, 'b': 8*u.m/u.s, 'c': 'e'})
        4
        >>> print(dat.table)
         a    b    c
         m  m / s
        --- ----- ---
        1.0   4.0   a
        2.0   5.0   b
        3.0   6.0   c
        5.0   8.0   e
        >>> dat.add_rows(([6*u.m, 9*u.m/u.s, 'f'],
        ...               [7*u.m, 10*u.m/u.s, 'g']))
        6
        >>> dat.add_rows(dat)
        12

        """
        if isinstance(rows, QTable):
            self._table = vstack([self._table, rows], join_type=join_type)
        if isinstance(rows, DataClass):
            self._table = vstack([self._table, rows.table],
                                 join_type=join_type)
        if isinstance(rows, (dict, OrderedDict)):
            try:
                newrow = [rows[colname] for colname in self._table.columns]
            except KeyError as e:
                raise ValueError('data for column {0} missing in row {1}'.
                                 format(e, rows))
            self.add_rows(newrow)
        if isinstance(rows, (list, ndarray, tuple)):
            if (not isinstance(rows[0], (u.quantity.Quantity, float)) and
                    isinstance(rows[0], (dict, OrderedDict,
                                         list, ndarray, tuple))):
                for subrow in rows:
                    self.add_rows(subrow)
            else:
                self._table.add_row(rows)
        return len(self._table)

    def add_column(self, data, name, **kwargs):
        """Append a single column to the current data table. The lenght of
        the input list, `~numpy.ndarray`, or tuple must match the current
        number of rows in the data table.

        Parameters
        ----------
        data : list, `~numpy.ndarray`, or tuple
            Data to be filled into the table; required to have the same
            length as the existing table's number rows.
        name : str
            Name of the new column; must be different from already existing
            column names.
        **kwargs : additional parameters
            Additional optional parameters will be passed on to
            `~astropy.table.Table.add_column`.

        Returns
        -------
        n : int, the total number of columns in the data table

        Examples
        --------
        >>> from sbpy.data import DataClass
        >>> import astropy.units as u
        >>> dat = DataClass.from_array([[1, 2, 3]*u.Unit('m'),
        ...                             [4, 5, 6]*u.m/u.s,
        ...                             ['a', 'b', 'c']],
        ...                            names=('a', 'b', 'c'))
        >>> dat.add_column([10, 20, 30]*u.kg, name='d')
        4
        >>> print(dat.table)
         a    b    c   d
         m  m / s      kg
        --- ----- --- ----
        1.0   4.0   a 10.0
        2.0   5.0   b 20.0
        3.0   6.0   c 30.0
        """

        self._table.add_column(Column(data, name=name), **kwargs)
        return len(self.column_names)
示例#8
0
def solve_pointing(filename, relax=False):
    tick = dt.utcnow()
    log.info(f"Analyzing {filename.name}")
    hdr = fits.getheader(filename)
    if not relax:
        if not hdr.get('PONAME').strip() == 'REF': return None
        if not float(hdr.get('RAOFF')) < 0.1: return None
        if not float(hdr.get('DECOFF')) < 0.1: return None
        if not hdr.get('OBJECT') in ['GuiderFlexureTest', 'MIRA PMFM 350', 'MIRA PMFM -350']: return None

    # Extract EL, SKYPA, ROTPPOSN, FILTER
    EL = float(hdr.get('EL')) * u.deg
    SKYPA1 = float(hdr.get('SKYPA1')) * u.deg
    SKYPA2 = float(hdr.get('SKYPA2')) * u.deg
    ROTPPOSN = float(hdr.get('ROTPPOSN')) * u.deg
    FILTER = hdr.get('FILTER')
    OBJECT = hdr.get('OBJECT')
    FCPA, FCEL = (hdr.get('FCPA_EL')).split(' ')

    # Solve image for astrometry
    astrometry_cmd = ['solve-field', '-O', '-p', '-z', '2', '-t', '2', f"{f}"]
#     astrometry_cmd = ['solve-field', '-O', '-p', '-z', '2', '-T', f"{f}"]
    log.info('  ' + ' '.join(astrometry_cmd[:-1]))
    output = subprocess.run(astrometry_cmd, stdout=subprocess.PIPE)
    solved_file = f.with_name(f.name.replace('.fits', '.solved'))
    new_file = f.with_name(f.name.replace('.fits', '.new'))
    if not solved_file.exists():
        log.error(f'  Astrometry solve failed for {filename.name}')
        return
    # Open Solved Image
    hdul = fits.open(new_file)

    # Extract Guider Pointing Info from Header
    PONAME = hdul[0].header.get('PONAME') # This should be REF
    POYPOS = hdul[0].header.get('POYPOS')
    POXPOS = hdul[0].header.get('POXPOS')
    POYOFF = hdul[0].header.get('POYOFF')
    POXOFF = hdul[0].header.get('POXOFF')
    TARGRA = hdul[0].header.get('TARGRA')
    TARGDE = hdul[0].header.get('TARGDE')
    TARGFR = hdul[0].header.get('TARGFR')
    ROTSTS = hdul[0].header.get('ROTSTS')
    ROTMOD = hdul[0].header.get('ROTMOD')
    RAOFF = float(hdul[0].header.get('RAOFF')) * u.arcsec
    DECOFF = float(hdul[0].header.get('DECOFF')) * u.arcsec
    RA = float(hdul[0].header.get('RA')) * u.deg
    DEC = float(hdul[0].header.get('DEC')) * u.deg

    guider_coord = SkyCoord(RA, DEC, frame='icrs')

    # Extract WCS from header
    center_coord = get_center_coord(hdul[0])
    
#     w = WCS(hdul[0].header)
#     nx, ny = hdul[0].data.shape
#     result = w.all_pix2world(np.array(nx/2), np.array(ny/2), 1)
#     center_coord = SkyCoord(result[0], result[1], frame='icrs', unit='deg')

    offset_pa = center_coord.position_angle(guider_coord).to(u.deg)
    offset_distance = center_coord.separation(guider_coord).to(u.arcsec)
    offset_angle = offset_pa.to(u.deg) - SKYPA2
    offset_angle.wrap_at(180*u.deg, inplace=True)

    tock = dt.utcnow()
    analysis_time = (tock-tick).total_seconds()
    log.info(f"  Solved {analysis_time:.0f} s: {offset_distance:.1f}, "\
             f"{offset_angle:.2f} at drive = {ROTPPOSN:.2f}")

    table_file = Path('ImageResults.txt').expanduser()
    if not table_file.exists():
        t = QTable()
        t['Filename'] = [f.name]
        t['EL'] = [EL.value]
        t['PA'] = [SKYPA2.value]
        t['RotAng'] = [ROTPPOSN.value]
        t['GuiderCoord'] = [guider_coord.to_string(style='hmsdms', sep=':', precision=2)]
        t['ImageCoord'] = [center_coord.to_string(style='hmsdms', sep=':', precision=2)]
        t['OffsetDistance'] = [offset_distance.value]
        t['OffsetAngle'] = [offset_angle.value]
        print(t)
    else:
        t = QTable.read(table_file, format='ascii.ecsv')
        row = {'Filename': f.name,
               'EL': EL.value,
               'PA': SKYPA2.value,
               'RotAng': ROTPPOSN.value,
               'GuiderCoord': guider_coord.to_string(style='hmsdms', sep=':', precision=2),
               'ImageCoord': center_coord.to_string(style='hmsdms', sep=':', precision=2),
               'OffsetDistance': offset_distance.value,
               'OffsetAngle': offset_angle.value,
              }
        t.add_row(vals=row)
    t.write(table_file, format='ascii.ecsv', overwrite=True)
示例#9
0
                  'FILE', 'JD', 'RA (deg)', 'DEC (deg)', 'EXP (s)', 'FILTER',
                  'AIRMASS'
              ])
# loop over the files
for imgfile in listfile:
    hdul = fits.open(imgfile)
    hdr = hdul[0].header
    # JD, the center coordinate (RA, Dec), exposure time, filter, airmass.
    JD = hdr['JD']
    RAcenter = hdr['CRVAL1']
    DEcenter = hdr['CRVAL2']
    exptime = hdr['EXPOSURE']
    filtr = hdr['FILTER']
    airmass = hdr['AIRMASS']
    data.add_row([
        '201' + imgfile.replace(prefix, '').lstrip(), JD, RAcenter, DEcenter,
        exptime, filtr, airmass
    ])
    t120.log.debug('File=' + imgfile + ' JD=' + str(JD) + ' RA=' +
                   str(RAcenter) + ' DE=' + str(DEcenter) + ' exp=' +
                   str(exptime) + ' fil=' + str(filtr) + ' airmass=' +
                   str(airmass))
# remove first row
data.remove_row(0)
# save log in file
ascii.write(data,
            fileout,
            format='fixed_width',
            delimiter=' ',
            formats={'JD': '%18.12f'},
            overwrite=True)
t120.log.info('There are ' + str(len(listfile)) + ' data saved in ' + fileout)
示例#10
0
    def calculate_one_night(self, night):
        """
        For a given night, return the file counts and other other information for each exposure taken on that night
        input: night
        output: a dictionary containing the statistics with expid as key name
        FLAVOR: FLAVOR of this exposure
        OBSTYPE: OBSTYPE of this exposure
        EXPTIME: Exposure time
        SPECTROGRAPHS: a list of spectrographs used
        n_spectrographs: number of spectrographs
        n_psf: number of PSF files
        n_ff:  number of fiberflat files
        n_frame: number of frame files
        n_sframe: number of sframe files
        n_cframe: number of cframe files
        n_sky: number of sky files
        """
        output_arc = {}
        output_flat = {}
        output_science = {}
        fileglob_arc = os.path.join(self.prod_dir, 'run/scripts/night',
                                    str(night), 'arc*.log')
        fileglob_flat = os.path.join(self.prod_dir, 'run/scripts/night',
                                     str(night), 'flat*.log')
        fileglob_science = os.path.join(self.prod_dir, 'run/scripts/night',
                                        str(night), 'science*.log')

        file_arc = sorted(glob.glob(fileglob_arc))
        file_flat = sorted(glob.glob(fileglob_flat))
        file_science = sorted(glob.glob(fileglob_science))
        table_output = QTable([[], [], [], [], []],
                              names=('night', 'flavor', 'jobid', 'expid',
                                     'time'),
                              dtype=('S10', 'S10', 'S10', 'S10', 'float'))
        for file_this in file_arc:
            jobid_this = file_this.split('.')[0].split('-')[-1]
            expid_this = file_this.split('-')[2]
            result = os.popen('sacct -j ' + jobid_this +
                              ' --format=Elapsed').read()
            time = result.split('\n')[-2].split(':')
            time_this = float(time[0]) * 60. + float(
                time[1]) + float(time[2]) / 60.
            table_output.add_row(
                [night, 'arc', jobid_this, expid_this, time_this])
            #output_arc[jobid_this]={'expid':expid_this,'time':time_this}

        for file_this in file_flat:
            jobid_this = file_this.split('.')[0].split('-')[-1]
            expid_this = file_this.split('-')[2]
            result = os.popen('sacct -j ' + jobid_this +
                              ' --format=Elapsed').read()
            time = result.split('\n')[-2].split(':')
            time_this = float(time[0]) * 60. + float(
                time[1]) + float(time[2]) / 60.
            table_output.add_row(
                [night, 'flat', jobid_this, expid_this, time_this])
            #output_flat[jobid_this]={'expid':expid_this,'time':time_this}

        for file_this in file_science:
            jobid_this = file_this.split('.')[0].split('-')[-1]
            expid_this = file_this.split('-')[2]
            result = os.popen('sacct -j ' + jobid_this +
                              ' --format=Elapsed').read()
            time = result.split('\n')[-2].split(':')
            time_this = float(time[0]) * 60. + float(
                time[1]) + float(time[2]) / 60.
            table_output.add_row(
                [night, 'science', jobid_this, expid_this, time_this])
            #output_science[jobid_this]={'expid':expid_this,'time':time_this}
        return (table_output)
示例#11
0
    # Return components' mass
    halo_mass = ComponentMass(sys.argv[file], 1.)
    disk_mass = ComponentMass(sys.argv[file], 2.)
    bulge_mass = ComponentMass(sys.argv[file], 3.)
    # Add to local group mass
    group_halo += halo_mass
    group_disk += disk_mass
    group_bulge += bulge_mass
    # Calculate galaxy total mass and baryon fraction
    galaxy_mass = halo_mass + disk_mass + bulge_mass
    baryon_frac = np.around((disk_mass + bulge_mass) / galaxy_mass, 3)
    # Add a row to the table
    galaxy = [
        galaxy_name, halo_mass, disk_mass, bulge_mass, galaxy_mass, baryon_frac
    ]
    gm_list.add_row(galaxy)

# Edit the row of local group: total mass and baryon fraction
group_mass = group_halo + group_disk + group_bulge
group_fbar = np.around((group_disk + group_bulge) / group_mass, 3)
galaxy_group = [
    "Galaxy Group", group_halo, group_disk, group_bulge, group_mass, group_fbar
]
gm_list.add_row(galaxy_group)

# Convert the units into 1e12 M_sun
gm_list[r'$M_{Halo}$'] = np.around(gm_list[r'$M_{Halo}$'].to(1e12 * u.solMass),
                                   3)
gm_list[r'$M_{Disk}$'] = np.around(gm_list[r'$M_{Disk}$'].to(1e12 * u.solMass),
                                   3)
gm_list[r'$M_{Bulge}$'] = np.around(
示例#12
0
def makeobslog(path,root=''):
    """Make a journal of an observation night.
    
    Parameters
    ----------
    path : string
        path where data are located.
    root : string, optional
        root of files to journal.
        Default is '', i.e. all files will be journaled.
    
    Returns
    -------
    None.
    
    """
    # set file name and pattern
    fileout = path+ 'journal' + root + '.log'
    pattern = path +  root + '*.fit*'
    # make list of files from pattern
    listfile = glob.glob(pattern)
    nfile = len(listfile)
    # check number of files
    if (nfile==0):
        msg = '*** WARNING: there is no file of type: '+pattern
        t120.log.error(msg)
        raise IOError(msg)
    t120.log.info('There are '+str(nfile)+' files of type '+pattern)
    # get common prefix to all files
    prefix = os.path.commonprefix(listfile)
    # create output table:
    # method 1: obsolete and dumb... make a first dummy row so astropy.table.QTable knows 'FILTER' is a string
    #data = QTable([['                                            '],['                    '],
    #            [0.0],[0.0],[0.0],[0.0],[' '],[0.0]],
    #            names=['FILE','TARGET','JD','RA (deg)','DEC (deg)','EXP (s)','FILTER','AIRMASS'])
    # method 2: declare types
    data = QTable(dtype=[object,object,float,float,float,float,object,float]
                names=['FILE','TARGET','JD','RA (deg)','DEC (deg)','EXP (s)','FILTER','AIRMASS'])
    # loop over the files
    for imgfile in listfile:
        hdul = fits.open(imgfile)
        hdr = hdul[0].header
        target_name = hdr['OBJECT']#.strip().upper().replace(' ','')
        # JD, the center coordinate (RA, Dec), exposure time, filter, airmass.
        JD = hdr['JD']
        try:
            RAcenter = hdr['CRVAL1']
            DEcenter = hdr['CRVAL2']
        except:
            t120.log.warning('There is no CRVAL keyword  in file '+imgfile)
            skycoo = SkyCoord(hdr['OBJCTRA'],hdr['OBJCTDEC'], unit=(u.hourangle, u.deg))
            RAcenter = skycoo.ra.to('deg').value
            DEcenter = skycoo.dec.to('deg').value
        exptime = hdr['EXPOSURE']
        filtr = hdr['FILTER']
        airmass = hdr['AIRMASS']
        data.add_row([imgfile.replace(prefix,'').lstrip(),target_name,JD,RAcenter,DEcenter,exptime,filtr,airmass])
        t120.log.debug('File='+imgfile+' TARGET'+target_name+' JD='+str(JD)+' RA='+str(RAcenter)+' DE='+str(DEcenter)+
                  ' exp='+str(exptime)+' fil='+str(filtr)+' airmass='+str(airmass))
    # remove first row : useful if method 1 is used: obsolete and dumb...
    #data.remove_row(0)
    # save log in file
    ascii.write(data,fileout,format='fixed_width',delimiter=' ',formats={'JD': '%18.12f'},overwrite=True)
    t120.log.info('There are '+str(len(listfile))+' data saved in '+fileout)
    return
示例#13
0
def proc_lmon_full(merged_summaries_file: str, inst_mode: str = 'FF', xline: str = 'Cu-Ka', 
    data_dir: str = "./", output_file: str = "output.csv",verbose: bool =True) -> pd.DataFrame:
    """
        Merge all lmon fit results for a given line and mode, for each CCD and the full RAWY range (1,200)

        Input Parameters:
            df : DataFrame
                Pandas DataFrame with the merged summaries, will be used to select the OBS_IDs for the `xmode`
            inst_mode : str
                The instrument mode, can be 'FF' or 'EFF'
            xline : str
                The label of the line, as in the output files from Michael, can be 'Cu-Ka', 'Mn-Ka' or 'Al-Ka'
            data_dir : str
                The absolute path to the monitoring results folder, for example "/xdata/xcaldata/XMM/PN/CTI/dat_0062_sci"
            output_file : str
                The absolute path to the output file where the results will be saved
            verbose : bool
                If True will print some verbose info
        Output:
            the merged results in a pandas DataFrame
    """
    #
    # lines of interest and their rest-frame energies in eV
    #
    lines0 = {'Cu-Ka': 8038.0, 'Mn-Ka': 5899.0, 'Al-Ka': 1486.0}
    #
    if (not os.path.isfile(merged_summaries_file)):
        print (f'File with merged summaries {merged_summaries_file} not found. Cannot continue.')
        return None
    #
    if (not os.path.isdir(data_dir)):
        print (f'Data dir {data_dir} not found. Cannot continue.')
        return None
    #
    if (xline not in lines0.keys()):
        print (f"Line {xline} not in list with rest-frame energy, please add it and run again.")
        return None
    #
    if (inst_mode == 'EFF'):
        select_mode = "PrimeFullWindowExtended"
    elif (inst_mode == 'FF'):
        select_mode = "PrimeFullWindow"
    else:
        print ('Only inst_mode=\'FF\' or \'EFF\' supported')
        return None
    df = QTable.read(merged_summaries_file)
    #
    df.sort('rev')
    #
    df = df[df['mode'] == select_mode]
    #
    nt = len(df)
    print (f"Will process {len(df)} {inst_mode} mode observations")
    print ("Doing line",xline)
    #
    all_cols = ['obsid','expo_name','rev','delta_time','omode','filter','expo_time','ccd', 'mipsel','maxmip','med_ndl','ndl','ndl_err']
    # from meanXY.txt file
    all_cols.extend(["rawx0","rawx1","rawy0","rawy1","rawx_mean","rawx_med","rawx_16","rawx_84",
                       "rawy_mean","rawy_med","rawy_16","rawy_84","nevents"])
    # feom lmon file
    all_cols.extend(["energy","energy_lo","energy_hi",
               "sigma","sigma_lo","sigma_hi","area","area_lo","area_hi",
               "pw_order","pw_slope","pw_slope_lo","pw_slope_hi","pw_norm","pw_norm_lo","pw_norm_hi",
               "fit_flag0","fit_flag1","fit_flag2","fit_flag3","fit_stat","dof"])
    #    
    bore_ccds = [1,4,7,10]
    # set up the CCD numbers and the corresponding quadrants
    quad = {1: '0', 2: '0', 3: '0', 
            4: '1', 5: '1', 6: '1', 
            7: '2', 8: '2', 9: '2', 
            10: '3', 11: '3', 12: '3',}
    #
    t = QTable(names=all_cols, dtype=[int, str, int, float, str, str, float, int, int, int, 
        float, float, float, int, int, int, int, float, float, float, 
        float, float, float, float, float, int, float, float, float, 
        float, float, float, float, float, float, float, float, float, 
        float, float, float, float, int, int, int, int, float, int])
    #print (t.colnames)
    #
    start_time = time.time()
    #
    for i in tqdm(range(nt),desc='Processing obs'):
        iobs = df['obsid'][i]
        irev = df['rev'][i]
        inexp = df['expid'][i]
        istart = df['tstart'][i]
        iexpo = df['texpo'][i]
        imode = df['mode'][i]
        ifilter = df['filt'][i]
        #
        stime = datetime.strptime(istart,"%Y-%m-%dT%H:%M:%S")
        delta_time = (stime-time0).total_seconds()/(365.0*24.0*3600.0) # in years
        #
        part1 = [iobs,inexp,irev,delta_time,imode,ifilter,iexpo]
        #
        part2 = []
        for iccd in np.arange(1,13):
            #
            part2 = part1.copy()
            resfile = f"{data_dir}/{iobs:010}/{iobs:010}{inexp}*lmonCCD{iccd:02}_{xline}.txt"
            xfile = glob.glob(resfile)
            # need to do this as there is inconsistency in the file names
            axline = xline.split('-')[0]
            # _meanXY.txt
            rawxy_file1 = f"{data_dir}/{iobs:010}/{iobs:010}{inexp}*lmonCCD{iccd:02}_{axline}_meanXY.txt"
            file_means = glob.glob(rawxy_file1)
            #
            # check if this CCD has results
            #
            if ((len(xfile) < 1) or (len(file_means) < 1)):
                print (f'No data for RAWY in (1,200) for CCD {iccd}, {iobs:010}')
                continue
            # now add quadrant specific parameters
            ndl = df[f'ndisclin_mean{quad[iccd]}'][i]
            med_ndl = df[f'ndisclin_med{quad[iccd]}'][i]
            ndl_err = df[f'ndisclin_std{quad[iccd]}'][i]
            mipsel = df[f'mipsel{quad[iccd]}'][i]
            maxmip = df[f'maxmip{quad[iccd]}'][i]
            #
            part2.extend([iccd,mipsel,maxmip,med_ndl,ndl,ndl_err])
            #
            # read the meanXY file as text
            #
            out1_line = []
            with open(file_means[0],'r') as mm:
                qlines = mm.readlines()
            for qline in qlines:
                qx = qline.split()
                if ((qx[2] == '1') and (qx[3] == '200')):
                    out1_line = qx
                    break
            # skip if no results for RAWY (1,200) are available
            if (len(out1_line) < 1):
                print (f'No meanXY data for RAWY in (1,200) for CCD {iccd}')
                continue
            #
            out2_line = []
            with open(xfile[0],'r') as mm:
                qlines = mm.readlines()
            for qline in qlines:
                qx = qline.split()
                if ((qx[2] == '1') and (qx[3] == '200')):
                    out2_line = qx
                    break
            #
            # skip if no results for RAWY (1,200) are available
            if (len(out2_line) < 1):
                print (f'No lmon data for RAWY in (1,200) for CCD {iccd}')
                continue
            #
            # now extend the array
            #
            out1_line.extend(out2_line[4:])
            part2.extend(out1_line)
            #
            t.add_row(part2)
            #
    tx = _convert_adu(t)
    #
    return t
示例#14
0
文件: geom.py 项目: vikasj78/gammapy
    def group_table(self, edges):
        """Compute bin groups table for the map axis, given coarser bin edges.

        Parameters
        ----------
        edges : `~astropy.units.Quantity`
            Group bin edges.

        Returns
        -------
        groups : `~astropy.table.Table`
            Map axis group table.
        """
        # TODO: try to simplify this code
        if not self.node_type == "edges":
            raise ValueError("Only edge based map axis can be grouped")

        edges_pix = self.coord_to_pix(edges)
        edges_pix = np.clip(edges_pix, -0.5, self.nbin - 0.5)
        edges_idx = np.round(edges_pix + 0.5) - 0.5
        edges_idx = np.unique(edges_idx)
        edges_ref = self.pix_to_coord(edges_idx)

        groups = QTable()
        groups[f"{self.name}_min"] = edges_ref[:-1]
        groups[f"{self.name}_max"] = edges_ref[1:]

        groups["idx_min"] = (edges_idx[:-1] + 0.5).astype(int)
        groups["idx_max"] = (edges_idx[1:] - 0.5).astype(int)

        if len(groups) == 0:
            raise ValueError("No overlap between reference and target edges.")

        groups["bin_type"] = "normal   "

        edge_idx_start, edge_ref_start = edges_idx[0], edges_ref[0]
        if edge_idx_start > 0:
            underflow = {
                "bin_type": "underflow",
                "idx_min": 0,
                "idx_max": edge_idx_start,
                f"{self.name}_min": self.pix_to_coord(-0.5),
                f"{self.name}_max": edge_ref_start,
            }
            groups.insert_row(0, vals=underflow)

        edge_idx_end, edge_ref_end = edges_idx[-1], edges_ref[-1]

        if edge_idx_end < (self.nbin - 0.5):
            overflow = {
                "bin_type": "overflow",
                "idx_min": edge_idx_end + 1,
                "idx_max": self.nbin - 1,
                f"{self.name}_min": edge_ref_end,
                f"{self.name}_max": self.pix_to_coord(self.nbin - 0.5),
            }
            groups.add_row(vals=overflow)

        group_idx = Column(np.arange(len(groups)))
        groups.add_column(group_idx, name="group_idx", index=0)
        return groups
示例#15
0
def table_pyoof_out(path_pyoof_out, order):
    """
    Auxiliary function to tabulate all data from a series of observations
    gathered in a common ``pyoof_out/`` directory.

    Note: Piston and tilt are not used in error calculations, the phase
    calculations will only be included if these are manually changed in
    ``core.py``.

    Parameters
    ----------
    path_pyoof_out : `list`
        set of paths to the directory ``pyoof_out/`` or where the output from
        the `~pyoof` package is located.
    order : `int`
        Order used for the Zernike circle polynomial, :math:`n`.

    Returns
    -------
    qt : `~astropy.table.table.QTable`
        `~astropy.table.table.QTable` with units of the most important
        quantities from the `~pyoof` package.
    """

    qt = QTable(names=[
        'name', 'tel_name', 'obs-object', 'obs-date', 'meanel', 'i_amp',
        'c_dB', 'q', 'phase-rms', 'e_rs', 'beam-snr-out-l', 'beam-snr-in',
        'beam-snr-out-r'
    ],
                dtype=[np.string_] * 4 + [np.float] * 9)

    for p, pyoof_out in enumerate(path_pyoof_out):
        with open(os.path.join(pyoof_out, 'pyoof_info.yml'), 'r') as inputfile:
            pyoof_info = yaml.load(inputfile, Loader=yaml.Loader)

        _phase = np.genfromtxt(os.path.join(pyoof_out,
                                            f'phase_n{order}.csv')) * apu.rad
        phase_rms = rms(_phase, circ=True)
        phase_e_rs = e_rs(_phase, circ=True)

        # random-surface-error efficiency error
        # cov = np.genfromtxt(os.path.join(pyoof_out, f'cov_n{order}.csv'))
        # idx = np.argwhere(cov[0, :].astype(int) > 5)

        params = Table.read(os.path.join(pyoof_out, f'fitpar_n{order}.csv'),
                            format='ascii')
        I_coeff = params['parfit'][:5]

        qt.add_row([
            pyoof_info['name'], pyoof_info['tel_name'],
            pyoof_info['obs_object'], pyoof_info['obs_date'],
            pyoof_info['meanel'], I_coeff[0], I_coeff[1], I_coeff[2],
            phase_rms, phase_e_rs
        ] + pyoof_info['snr'])

    # updating units
    qt['phase-rms'] *= apu.rad
    qt['meanel'] *= apu.deg
    qt['obs-date'] = Time(qt['obs-date'], format='isot', scale='utc')
    qt['c_dB'] *= apu.dB

    qt.meta = {'order': order}

    return qt
示例#16
0
文件: utils.py 项目: ntejos/linetools
def iontable_from_components(components, ztbl=None):
    """Generate a QTable from a list of components

    Method does *not* perform logic on redshifts or vlim.
    Includes rules for adding components of like ion
    Not ready for varying atomic mass (e.g. Deuterium)

    Parameters
    ----------
    components : list
      list of AbsComponent objects
    ztbl : float, optional
      Redshift for the table

    Returns
    -------
    iontbl : QTable
    """
    from collections import OrderedDict
    # Checks
    assert chk_components(components,chk_A_none=True)

    # Set z from mean
    if ztbl is None:
        ztbl = np.mean([comp.zcomp for comp in components])

    # Construct the QTable
    cols = OrderedDict()  # Keeps columns in order
    cols['Z']=int
    cols['ion']=int
    cols['A']=int
    cols['Ej']=float
    cols['z']=float
    cols['vmin']=float
    cols['vmax']=float
    cols['flag_N']=int
    cols['logN']=float
    cols['sig_logN']=float
    names = cols.keys()
    dtypes = [cols[key] for key in names]
    iontbl = QTable(names=names,dtype=dtypes)
    iontbl['vmin'].unit=u.km/u.s
    iontbl['vmax'].unit=u.km/u.s

    # Identify unique Zion, Ej (not ready for A)
    uZiE = np.array([comp.Zion[0]*1000000+comp.Zion[1]*10000+
                      comp.Ej.to('1/cm').value for comp in components])
    uniZi, auidx = np.unique(uZiE, return_index=True)

    # Loop
    for uidx in auidx:
        # Synthesize components with like Zion, Ej
        mtZiE = np.where(uZiE == uZiE[uidx])[0]
        comps = [components[ii] for ii in mtZiE]  # Need a list
        synth_comp = synthesize_components(comps, zcomp=ztbl)
        # Add a row to QTable
        row = dict(Z=synth_comp.Zion[0],ion=synth_comp.Zion[1],
                   z=ztbl,
                   Ej=synth_comp.Ej,vmin=synth_comp.vlim[0],
                   vmax=synth_comp.vlim[1],logN=synth_comp.logN,
                   flag_N=synth_comp.flag_N,sig_logN=synth_comp.sig_logN)
        iontbl.add_row(row)

    # Add zlim to metadata
    meta = OrderedDict()
    meta['zcomp'] = ztbl

    # Return
    return iontbl
示例#17
0
    def estimate_extreme_velocities(self,
                                    threshold,
                                    source_distance,
                                    plot=False,
                                    weak_quadrants=False,
                                    velocity_interval=None,
                                    channel_interval=None,
                                    writeto=None,
                                    debug=False):
        # initialize the data table
        table = QTable(names=('Position', 'Channel', 'Angular distance',
                              'Distance', 'Velocity'),
                       dtype=(int, int, u.Quantity, u.Quantity, u.Quantity))

        # estimate the extreme channels
        if velocity_interval is not None:
            if isinstance(velocity_interval, tuple):
                channel_interval = self._velocity_to_channel(velocity_interval)
            else:
                raise TypeError(
                    'The function estimate_extreme_velocities() can only handle a single velocity interval at a time but got {}!'
                    .format(velocity_interval))
            self.estimate_extreme_channels(threshold,
                                           plot=False,
                                           weak_quadrants=weak_quadrants,
                                           channel_interval=channel_interval)
        elif channel_interval is not None:
            self.estimate_extreme_channels(threshold,
                                           plot=False,
                                           weak_quadrants=weak_quadrants,
                                           channel_interval=channel_interval)
        else:
            self.estimate_extreme_channels(threshold,
                                           plot=False,
                                           weak_quadrants=weak_quadrants)

        # transfer the channels into physical units
        for position, channel in enumerate(self.channels):
            angular_distance = (
                position - self.position_reference) * self.position_resolution
            distance = self._angle_to_length(angular_distance, source_distance)
            velocity = (channel - self.vLSR_channel
                        ) * self.velocity_resolution + self.vLSR
            try:
                table.add_row([
                    position, channel, angular_distance.value, distance.value,
                    velocity.value
                ])
            except AttributeError:
                # print([position, channel, angular_distance, distance, velocity])
                pass
        table['Angular distance'] = table[
            'Angular distance'] * self.position_resolution.unit
        table['Distance'] = table['Distance'] * u.AU
        table['Velocity'] = table['Velocity'] * self.velocity_resolution.unit

        # plot
        if plot:
            plt.plot(table['Distance'], table['Velocity'], 'o', label='data')
            plt.xlabel('Position offest ({})'.format(table['Distance'].unit))
            plt.xlabel('Velocity ({})'.format(table['Velocity'].unit))
            plt.axhline(self.vLSR.value,
                        c='k',
                        ls='--',
                        label='$v_\mathrm{LSR}$')
            plt.grid()
            plt.legend()
            plt.show()
            plt.close()

        if debug:
            print('Estimates of extreme velocities:')
            print(table)

        if writeto:
            table.write(writeto, format='ascii.fixed_width', overwrite=True)

        return table