Ejemplo n.º 1
0
    def _update_energy(self, chunk):
        """Create SpectralWCS information using FITS headers, if available. If
        the WLEN and BANDPASS keyword values are set to the defaults, there is
        no energy information."""
        self._logger.debug('Begin _update_energy')
        mc.check_param(chunk, Chunk)

        wlen = self._headers[0].get('WLEN')
        bandpass = self._headers[0].get('BANDPASS')
        if wlen is None or wlen < 0 or bandpass is None or bandpass < 0:
            chunk.energy = None
            chunk.energy_axis = None
            self._logger.debug(
                f'Setting chunk energy to None because WLEN {wlen} and '
                f'BANDPASS {bandpass}'
            )
        else:
            naxis = CoordAxis1D(Axis('WAVE', 'um'))
            start_ref_coord = RefCoord(0.5, self.get_start_ref_coord_val(0))
            end_ref_coord = RefCoord(1.5, self.get_end_ref_coord_val(0))
            naxis.range = CoordRange1D(start_ref_coord, end_ref_coord)
            chunk.energy = SpectralWCS(
                naxis,
                specsys='TOPOCENT',
                ssysobs='TOPOCENT',
                ssyssrc='TOPOCENT',
                bandpass_name=self._headers[0].get('FILTER'),
            )
            chunk.energy_axis = None
            self._logger.debug('Setting chunk energy range (CoordRange1D).')
Ejemplo n.º 2
0
def build_chunk_energy_range(chunk, filter_name, filter_md):
    """
    Set a range axis for chunk energy using central wavelength and FWHM.
    Units are Angstroms. Axis is set to 4.

    :param chunk: Chunk to add a CoordRange1D Axis to
    :param filter_name: string to set to bandpassName
    :param filter_md: dict with a 'cw' and 'fwhm' value
    """
    # If n_axis=1 (as I guess it will be for all but processes GRACES
    # spectra now?) that means crpix=0.5 and the corresponding crval would
    # central_wl - bandpass/2.0 (i.e. the minimum wavelength).   It is fine
    # if you instead change crpix to 1.0.   I guess since the ‘range’ of
    # one pixel is 0.5 to 1.5.

    cw = ac.FilterMetadataCache.get_central_wavelength(filter_md)
    fwhm = ac.FilterMetadataCache.get_fwhm(filter_md)
    if cw is not None and fwhm is not None:
        resolving_power = ac.FilterMetadataCache.get_resolving_power(filter_md)
        axis = CoordAxis1D(axis=Axis(ctype='WAVE', cunit='Angstrom'))
        ref_coord1 = RefCoord(0.5, cw - fwhm / 2.0)
        ref_coord2 = RefCoord(1.5, cw + fwhm / 2.0)
        axis.range = CoordRange1D(ref_coord1, ref_coord2)

        energy = SpectralWCS(axis=axis,
                             specsys='TOPOCENT',
                             ssyssrc=None,
                             ssysobs=None,
                             bandpass_name=filter_name,
                             resolving_power=resolving_power)
        chunk.energy = energy
Ejemplo n.º 3
0
def _build_chunk_energy(chunk, headers):
    # DB 18-09-19
    # NEOSSat folks wanted the min/max wavelengths in the BANDPASS keyword to
    # be used as the upper/lower wavelengths.  BANDPASS = ‘4000,9000’ so
    # ref_coord1 = RefCoord(0.5, 4000) and ref_coord2 = RefCoord(1.5, 9000).
    # The WAVELENG value is not used for anything since they opted to do it
    # this way.  They interpret WAVELENG as being the wavelengh of peak
    # throughput of the system I think.

    min_wl, max_wl = _get_energy(headers[0])
    axis = CoordAxis1D(axis=Axis(ctype='WAVE', cunit='um'))
    if min_wl is not None and max_wl is not None:
        ref_coord1 = RefCoord(0.5, min_wl)
        ref_coord2 = RefCoord(1.5, max_wl)
        axis.range = CoordRange1D(ref_coord1, ref_coord2)

        # DB 24-09-19
        # If FILTER not in header, set filter_name = ‘CLEAR’
        filter_name = headers[0].get('FILTER', 'CLEAR')

        # DB 24-09-19
        # if wavelength IS None, wl = 0.6 microns, and resolving_power is
        # always determined.
        resolving_power = None
        wavelength = headers[0].get('WAVELENG', 6000)
        wl = wavelength / 1e4  # everything in microns
        resolving_power = wl / (max_wl - min_wl)
        energy = SpectralWCS(axis=axis,
                             specsys='TOPOCENT',
                             ssyssrc='TOPOCENT',
                             ssysobs='TOPOCENT',
                             bandpass_name=filter_name,
                             resolving_power=resolving_power)
        chunk.energy = energy
Ejemplo n.º 4
0
def _build_chunk_position(chunk, headers, obs_id):
    # DB 18-08-19
    # Ignoring rotation for now:  Use CRVAL1 = RA from header, CRVAL2 = DEC
    # from header.  NAXIS1/NAXIS2 values gives number of pixels along RA/DEC
    # axes (again, ignoring rotation) and assume CRPIX1 = NAXIS1/2.0 and
    # CRPIX2 = NAXIS2/2.0 (i.e. in centre of image).   XBINNING/YBINNING
    # give binning values along RA/DEC axes.   CDELT1 (scale in
    # degrees/pixel; it’s 3 arcsec/unbinned pixel)= 3.0*XBINNING/3600.0
    # CDELT2 = 3.0*YBINNING/3600.0.  Set CROTA2=0.0
    header = headers[0]
    ra = get_ra(header)
    dec = get_dec(header)
    if ra is None or dec is None:
        logging.warning(f'No position information for {obs_id}')
        chunk.naxis = None
    else:
        header['CTYPE1'] = 'RA---TAN'
        header['CTYPE2'] = 'DEC--TAN'
        header['CUNIT1'] = 'deg'
        header['CUNIT2'] = 'deg'
        header['CRVAL1'] = ra
        header['CRVAL2'] = dec
        header['CRPIX1'] = get_position_axis_function_naxis1(header)
        header['CRPIX2'] = get_position_axis_function_naxis2(header)

        wcs_parser = WcsParser(header, obs_id, 0)
        if chunk is None:
            chunk = Chunk()
        wcs_parser.augment_position(chunk)

        x_binning = header.get('XBINNING')
        if x_binning is None:
            x_binning = 1.0
        cdelt1 = 3.0 * x_binning / 3600.0
        y_binning = header.get('YBINNING')
        if y_binning is None:
            y_binning = 1.0
        cdelt2 = 3.0 * y_binning / 3600.0

        objct_rol = header.get('OBJCTROL')
        if objct_rol is None:
            objct_rol = 0.0

        crota2 = 90.0 - objct_rol
        crota2_rad = math.radians(crota2)
        cd11 = cdelt1 * math.cos(crota2_rad)
        cd12 = abs(cdelt2) * _sign(cdelt1) * math.sin(crota2_rad)
        cd21 = -abs(cdelt1) * _sign(cdelt2) * math.sin(crota2_rad)
        cd22 = cdelt2 * math.cos(crota2_rad)

        dimension = Dimension2D(header.get('NAXIS1'), header.get('NAXIS2'))
        x = RefCoord(get_position_axis_function_naxis1(header), get_ra(header))
        y = RefCoord(get_position_axis_function_naxis2(header),
                     get_dec(header))
        ref_coord = Coord2D(x, y)
        function = CoordFunction2D(dimension, ref_coord, cd11, cd12, cd21,
                                   cd22)
        chunk.position.axis.function = function
        chunk.position_axis_1 = 1
        chunk.position_axis_2 = 2
Ejemplo n.º 5
0
def build_chunk_energy_bounds(wave, axis):
    import numpy as np  # limit the  effect on container content

    # caom2IngestEspadons.py, l698
    x = np.arange(1, wave.size + 1, dtype='float32')
    wavegrade = np.gradient(wave)
    waveinflect = wave[np.where(abs(wavegrade) > 0.01)]
    xinflect = x[np.where(abs(wavegrade) > 0.01)]
    # add start and finish pixels onto waveinflect and xinflect and these are
    # our list of sub-bounds.
    allxinflect = np.append(x[0], xinflect)
    allxinflect = np.append(allxinflect, x[-1])
    allwaveinflect = np.append(wave[0], waveinflect)
    allwaveinflect = np.append(allwaveinflect, wave[-1])
    numwaveschunk = int(len(allxinflect) / 2.0)

    bounds = CoordBounds1D()
    for jj in range(numwaveschunk):
        indexlo = jj * 2 + 0
        indexhi = indexlo + 1
        x1 = float(allxinflect[indexlo])
        x2 = float(allxinflect[indexhi])
        w1 = float(allwaveinflect[indexlo])
        w2 = float(allwaveinflect[indexhi])
        coord_range = CoordRange1D(RefCoord(x1, w1), RefCoord(x2, w2))
        bounds.samples.append(coord_range)

    return bounds
Ejemplo n.º 6
0
def _update_time(chunk, headers):
    """Create TemporalWCS information using FITS header information.
    This information should always be available from the file."""
    logging.debug('Begin _update_time.')
    mc.check_param(chunk, Chunk)

    mjd_start = headers[0].get('MJD_STAR')
    mjd_end = headers[0].get('MJD_END')
    if mjd_start is None or mjd_end is None:
        mjd_start, mjd_end = ac.find_time_bounds(headers)
    if mjd_start is None or mjd_end is None:
        chunk.time = None
        logging.debug('Cannot calculate mjd_start {} or mjd_end {}'.format(
            mjd_start, mjd_end))
    else:
        logging.debug('Calculating range with start {} and end {}.'.format(
            mjd_start, mjd_start))
        start = RefCoord(0.5, mjd_start)
        end = RefCoord(1.5, mjd_end)
        time_cf = CoordFunction1D(1, headers[0].get('TEFF'), start)
        time_axis = CoordAxis1D(Axis('TIME', 'd'), function=time_cf)
        time_axis.range = CoordRange1D(start, end)
        chunk.time = TemporalWCS(time_axis)
        chunk.time.exposure = headers[0].get('TEFF')
        chunk.time.resolution = 0.1
        chunk.time.timesys = 'UTC'
        chunk.time.trefpos = 'TOPOCENTER'
        chunk.time_axis = 4
    logging.debug('Done _update_time.')
Ejemplo n.º 7
0
 def bad_range_wcs():
     ctype = "RM"
     unit = "rad/m^2"
     error = None
     start = RefCoord(float(0.9), float(1.1))
     end = RefCoord(float(10.9), float(1.1))
     range = CoordRange1D(start, end)
     axis_1d = CoordAxis1D(wcs.Axis(ctype, unit), error, range)
     return chunk.CustomWCS(axis_1d)
Ejemplo n.º 8
0
 def get_test_function_with_range(ctype, unit, px, sx, nx, ds):
     error = None
     start = RefCoord(float(0.9), float(1.1))
     end = RefCoord(float(10.9), float(11.1))
     range = CoordRange1D(start, end)
     axis_1d = CoordAxis1D(wcs.Axis(ctype, unit), error, range)
     ref_coord = RefCoord(px, sx)
     axis_1d.function = CoordFunction1D(nx, ds, ref_coord)
     custom_wcs = chunk.CustomWCS(axis_1d)
     return custom_wcs
Ejemplo n.º 9
0
    def test_range(self):
        # Polarization range is None, should not produce an error
        axis = Axis("STOKES", "cunit")
        axis_1d = CoordAxis1D(axis)
        polarization = PolarizationWCS(axis_1d)
        wcsvalidator._validate_polarization_wcs(polarization)

        # Polarization axis range contains valid positive values
        start = RefCoord(float(0.9), float(1.1))
        end = RefCoord(float(9.9), float(10.1))
        p_range = CoordRange1D(start, end)
        axis_1d.range = p_range
        polarization = PolarizationWCS(axis_1d)
        wcsvalidator._validate_polarization_wcs(polarization)

        # Polarization axis range contains valid negative values
        start = RefCoord(float(-8.1), float(-7.9))
        end = RefCoord(float(-1.1), float(-0.9))
        n_range = CoordRange1D(start, end)
        axis_1d.range = n_range
        polarization = PolarizationWCS(axis_1d)
        wcsvalidator._validate_polarization_wcs(polarization)

        # Polarization axis range contains invalid positive values
        start = RefCoord(float(0.9), float(1.1))
        end = RefCoord(float(10.9), float(11.1))
        p_range = CoordRange1D(start, end)
        axis_1d.range = p_range
        polarization = PolarizationWCS(axis_1d)
        with pytest.raises(InvalidWCSError) as ex:
            wcsvalidator._validate_polarization_wcs(polarization)
        assert ('Invalid Polarization WCS' in str(ex.value))
        assert ('11' in str(ex.value))

        # Polarization axis range contains invalid negative values
        start = RefCoord(float(-9.1), float(-8.9))
        end = RefCoord(float(-1.1), float(-0.9))
        n_range = CoordRange1D(start, end)
        axis_1d.range = n_range
        polarization = PolarizationWCS(axis_1d)
        with pytest.raises(InvalidWCSError) as ex:
            wcsvalidator._validate_polarization_wcs(polarization)
        assert ('Invalid Polarization WCS' in str(ex.value))
        assert ('-9' in str(ex.value))

        # Polarization axis range contains an invalid value (0) within a range
        start = RefCoord(float(-8.1), float(-7.9))
        end = RefCoord(float(9.9), float(10.1))
        range = CoordRange1D(start, end)
        axis_1d.range = range
        polarization = PolarizationWCS(axis_1d)
        with pytest.raises(InvalidWCSError) as ex:
            wcsvalidator._validate_polarization_wcs(polarization)
        assert ('Invalid Polarization WCS' in str(ex.value))
        assert ('0' in str(ex.value))
Ejemplo n.º 10
0
 def bad_bounds_wcs():
     ctype = "RM"
     unit = "rad/m^2"
     error = None
     range = None
     c1 = RefCoord(float(0.9), float(1.1))
     c2 = RefCoord(float(10.9), float(1.1))
     bounds = CoordBounds1D()
     bounds.samples.append(CoordRange1D(c1, c2))
     axis_1d = CoordAxis1D(wcs.Axis(ctype, unit), error, range, bounds)
     return chunk.CustomWCS(axis_1d)
Ejemplo n.º 11
0
def _build_time(row):
    bounds = CoordBounds1D()
    start_date = ac.get_datetime(row[3].strip())
    end_date = ac.get_datetime(row[4].strip())
    start_date.format = 'mjd'
    end_date.format = 'mjd'
    exposure = float(ac.get_timedelta_in_s(row[5].strip()))
    start_ref_coord = RefCoord(0.5, start_date.value)
    end_ref_coord = RefCoord(1.5, end_date.value)
    bounds.samples.append(CoordRange1D(start_ref_coord, end_ref_coord))
    return bounds, exposure
Ejemplo n.º 12
0
    def _update_time_bounds(self, observation, storage_name):
        """Add chunk time bounds to the chunk from the first part, by
        referencing information from the second header."""

        lower_values = ''
        upper_values = ''
        with fits.open(storage_name.sources_names[0]) as fits_data:
            xtension = fits_data[1].header['XTENSION']
            extname = fits_data[1].header['EXTNAME']
            if 'BINTABLE' in xtension and 'PROVENANCE' in extname:
                for ii in fits_data[1].data[0]['STARTTIME']:
                    lower_values = f'{ii} {lower_values}'
                for ii in fits_data[1].data[0]['DURATION']:
                    upper_values = f'{ii} {upper_values} '
            else:
                raise mc.CadcException(
                    f'Opened a composite file that does not match the '
                    f'expected profile '
                    f'(XTENSION=BINTABLE/EXTNAME=PROVENANCE). '
                    f'{xtension} {extname}'
                )

        for plane in observation.planes:
            for artifact in observation.planes[plane].artifacts:
                parts = observation.planes[plane].artifacts[artifact].parts
                for p in parts:
                    if p == '0':
                        lower = lower_values.split()
                        upper = upper_values.split()
                        if len(lower) != len(upper):
                            raise mc.CadcException(
                                'Cannot make RefCoords with inconsistent '
                                'values.'
                            )
                        chunk = parts[p].chunks[0]
                        bounds = CoordBounds1D()
                        chunk.time.axis.bounds = bounds
                        for ii in range(len(lower)):
                            mjd_start, mjd_end = ac.convert_time(
                                mc.to_float(lower[ii]), mc.to_float(upper[ii])
                            )
                            lower_refcoord = RefCoord(0.5, mjd_start)
                            upper_refcoord = RefCoord(1.5, mjd_end)
                            r = CoordRange1D(lower_refcoord, upper_refcoord)
                            bounds.samples.append(r)
                        # if execution has gotten to this point, remove range
                        # if it exists, since only one of bounds or range
                        # should be provided, and bounds is more specific. PD,
                        # slack, 2018-07-16
                        if chunk.time.axis.range is not None:
                            chunk.time.axis.range = None
def _build_time(start, end, tos):
    bounds = CoordBounds1D()
    if start is not None and end is not None:
        start_date = ac.get_datetime(start)
        start_date.format = 'mjd'
        end_date = ac.get_datetime(end)
        end_date.format = 'mjd'
        start_ref_coord = RefCoord(0.5, start_date.value)
        end_ref_coord = RefCoord(1.5, end_date.value)
        bounds.samples.append(CoordRange1D(start_ref_coord, end_ref_coord))
    exposure = None
    if tos is not None:
        exposure = float(ac.get_timedelta_in_s(tos))
    return bounds, exposure
Ejemplo n.º 14
0
def build_temporal_wcs_append_sample(temporal_wcs, lower, upper):
    """All the CAOM entities for building a TemporalWCS instance with
    a bounds definition, or appending a sample, in one function.
    """
    if temporal_wcs is None:
        samples = TypedList(CoordRange1D, )
        bounds = CoordBounds1D(samples=samples)
        temporal_wcs = TemporalWCS(axis=CoordAxis1D(axis=Axis('TIME', 'd'),
                                                    bounds=bounds),
                                   timesys='UTC')
    start_ref_coord = RefCoord(pix=0.5, val=lower)
    end_ref_coord = RefCoord(pix=1.5, val=upper)
    sample = CoordRange1D(start_ref_coord, end_ref_coord)
    temporal_wcs.axis.bounds.samples.append(sample)
    return temporal_wcs
Ejemplo n.º 15
0
def build_energy():
    # units are nm
    min = 400
    max = 800
    central_wl = (min + max) / 2.0  # = 1200.0 / 2.0 == 600.0 nm
    fwhm = (max - min)
    ref_coord1 = RefCoord(0.5, central_wl - fwhm / 2.0)  # == 100.0 nm
    ref_coord2 = RefCoord(1.5, central_wl + fwhm / 2.0)  # == 500.0 nm
    axis = CoordAxis1D(axis=Axis(ctype='WAVE', cunit='nm'))
    axis.range = CoordRange1D(ref_coord1, ref_coord2)
    energy = SpectralWCS(axis=axis,
                         specsys='TOPOCENT',
                         ssyssrc='TOPOCENT',
                         ssysobs='TOPOCENT',
                         bandpass_name='CLEAR')
    return energy
Ejemplo n.º 16
0
def build_chunk_time(chunk, header, name):
    """

    :param chunk: CAOM2 Chunk instance for which to set time.
    :param header: FITS header with the keywords for value extraction.
    :param name: str  for logging information only.
    :return:
    """
    logging.debug(f'Begin build_chunk_time for {name}.')
    # DB 02-07-20
    # time metadata comes from MJD_OBS and EXPTIME, it's not
    # an axis requiring cutout support
    exp_time = header.get('EXPTIME')
    mjd_obs = header.get('MJD-OBS')
    if exp_time is None or mjd_obs is None:
        chunk.time = None
    else:
        if chunk.time is None:
            coord_error = CoordError(syser=1e-07, rnder=1e-07)
            time_axis = CoordAxis1D(axis=Axis('TIME', 'd'), error=coord_error)
            chunk.time = TemporalWCS(axis=time_axis, timesys='UTC')
        ref_coord = RefCoord(pix=0.5, val=mjd_obs)
        chunk.time.axis.function = CoordFunction1D(
            naxis=1, delta=mc.convert_to_days(exp_time), ref_coord=ref_coord)
        chunk.time.exposure = exp_time
        chunk.time.resolution = mc.convert_to_days(exp_time)
    logging.debug(f'End build_chunk_time.')
Ejemplo n.º 17
0
    def bad_delta():
        axis_1d = CoordAxis1D(wcs.Axis("RM", "rad/m**2"))
        # delta < 0.0 is bad
        ref_coord = RefCoord(float(1.0), float(2.0))
        axis_1d.function = CoordFunction1D(int(100), -0.01, ref_coord)

        return chunk.CustomWCS(axis_1d)
Ejemplo n.º 18
0
def _update_energy(chunk, header, filter_name, obs_id):
    logging.debug(f'Begin _update_energy for {obs_id}.')
    # because the type for the axes are 'LINEAR', which isn't an energy type,
    # so can't use the WcsParser from caom2utils.
    disp_axis = header.get('DISPAXIS')
    naxis = header.get('NAXIS')
    if disp_axis is not None and naxis is not None and disp_axis <= naxis:
        axis = Axis(ctype='WAVE', cunit='Angstrom')
        coord_axis_1d = CoordAxis1D(axis)
        ref_coord = RefCoord(
            pix=header.get(f'CRPIX{disp_axis}'),
            val=header.get(f'CRVAL{disp_axis}'),
        )
        fn = CoordFunction1D(
            naxis=header.get(f'NAXIS{disp_axis}'),
            delta=header.get(f'CD{disp_axis}_{disp_axis}'),
            ref_coord=ref_coord,
        )
        coord_axis_1d.function = fn
        energy = SpectralWCS(axis=coord_axis_1d, specsys='TOPOCENT')
        energy.bandpass_name = filter_name
        # DB 07-08-20
        # I think the best we can do is assume that a resolution element is 2
        # pixels wide. So resolving power is the absolute value of
        # approximately CRVAL3/(2 * CD3_3)
        energy.resolving_power = abs(
            header.get(f'CRVAL{disp_axis}') /
            (2 * header.get(f'CD{disp_axis}_{disp_axis}')))
        chunk.energy = energy
        chunk.energy_axis = disp_axis
    logging.debug('End _update_energy.')
Ejemplo n.º 19
0
 def bad_function_wcs():
     ctype = "RM"
     unit = "rad/m^2"
     error = None
     range = None
     c1 = RefCoord(float(0.9), float(1.1))
     c2 = RefCoord(float(10.9), float(1.1))
     bounds = CoordBounds1D()
     bounds.samples.append(CoordRange1D(c1, c2))
     naxis = 1
     delta = 0.0
     ref_coord = RefCoord(float(0.9), float(1.1))
     func = CoordFunction1D(naxis, delta, ref_coord)
     axis_1d = CoordAxis1D(wcs.Axis(ctype, unit), error, range, bounds,
                           func)
     return chunk.CustomWCS(axis_1d)
Ejemplo n.º 20
0
    def bad_range_wcs():
        px = float(0.5)
        sx = float(54321.0)
        nx = 200
        ds = float(0.01)
        axis_1d = wcs.CoordAxis1D(wcs.Axis("RM", "rad/m**2"))

        # divide into 2 samples with a gap between
        c1 = RefCoord(px, sx)
        c2 = RefCoord(0.0, 0.0)
        c3 = RefCoord(px + nx * 0.66, sx + nx * ds * 0.66)
        c4 = RefCoord(px + nx, sx + nx * ds)
        axis_1d.bounds = CoordBounds1D()
        axis_1d.bounds.samples.append(CoordRange1D(c1, c3))
        axis_1d.bounds.samples.append(CoordRange1D(c4, c2))

        return chunk.CustomWCS(axis_1d)
Ejemplo n.º 21
0
def build_time(seconds, microseconds):
    mjd_start = AstroTime(seconds, format='unix')
    mjd_start.format = 'mjd'
    start = RefCoord(0.5, mjd_start.value)

    end_ms = seconds + (microseconds / 1e7)
    mjd_end = AstroTime(end_ms, format='unix')
    mjd_end.format = 'mjd'
    end = RefCoord(1.5, mjd_end.value)

    axis = CoordAxis1D(axis=Axis(ctype='TIME', cunit='d'))
    axis.range = CoordRange1D(start, end)
    return TemporalWCS(axis=axis,
                       timesys='UTC',
                       trefpos=None,
                       mjdref=None,
                       exposure=(microseconds / 1e7),
                       resolution=None)
Ejemplo n.º 22
0
 def test_range1d_to_interval(self):
     # happy path
     wcs = CustomTestUtil.good_wcs()
     start = RefCoord(float(0.9), float(1.1))
     end = RefCoord(float(10.9), float(11.1))
     range_1d = CoordRange1D(start, end)
     actual_interval = wcs_util.CustomAxisUtil.range1d_to_interval(
         wcs, range_1d)
     expected_interval = Interval(1.1, 11.1)
     self.assertEqual(expected_interval.lower, actual_interval.lower)
     self.assertEqual(expected_interval.upper, actual_interval.upper)
     self.assertEqual(None, actual_interval.samples)
     # function_1d.delta == 0.0 && function_1d.naxis > 1
     start = RefCoord(float(0.9), float(1.1))
     end = RefCoord(float(10.9), float(1.1))
     range_1d = CoordRange1D(start, end)
     with pytest.raises(ValueError) as ex:
         wcs_util.CustomAxisUtil.range1d_to_interval(wcs, range_1d)
     assert ('Invalid CoordRange1D:' in str(ex.value))
Ejemplo n.º 23
0
 def test_val2pix(self):
     # happy path
     wcs = CustomTestUtil.good_wcs()
     naxis = int(100)
     delta = -0.01
     ref_coord = RefCoord(0.0, 0.0)
     func = CoordFunction1D(naxis, delta, ref_coord)
     val = 0.1
     pix = wcs_util.CustomAxisUtil.val2pix(wcs, func, val)
     expected_pix = -10.0
     self.assertEqual(pix, expected_pix)
Ejemplo n.º 24
0
def _update_ngvs_time(chunk, provenance, obs_id):
    logging.debug(f'Begin _update_ngvs_time for {obs_id}')
    if (chunk is not None and provenance is not None and
            len(provenance.inputs) > 0):
        # bounds = ctor
        config = mc.Config()
        config.get_executors()
        subject = mc.define_subject(config)
        client = CAOM2RepoClient(
            subject, config.logging_level, 'ivo://cadc.nrc.ca/ams')
        metrics = mc.Metrics(config)
        bounds = CoordBounds1D()
        min_date = 0
        max_date = sys.float_info.max
        exposure = 0
        for entry in provenance.inputs:
            ip_obs_id, ip_product_id = mc.CaomName.decompose_provenance_input(
                entry.uri)
            logging.info(f'Retrieving provenance metadata for {ip_obs_id}.')
            ip_obs = mc.repo_get(client, 'CFHT', ip_obs_id, metrics)
            if ip_obs is not None:
                ip_plane = ip_obs.planes.get(ip_product_id)
                if (ip_plane is not None and ip_plane.time is not None and
                        ip_plane.time.bounds is not None):
                    bounds.samples.append(CoordRange1D(
                        RefCoord(pix=0.5, val=ip_plane.time.bounds.lower),
                        RefCoord(pix=1.5, val=ip_plane.time.bounds.upper)))
                    min_date = min(ip_plane.time.bounds.lower, min_date)
                    max_date = max(ip_plane.time.bounds.upper, max_date)
                    exposure += ip_plane.time.exposure
        axis = Axis(ctype='TIME', cunit='d')
        time_axis = CoordAxis1D(axis=axis,
                                error=None,
                                range=None,
                                bounds=bounds,
                                function=None)
        temporal_wcs = TemporalWCS(axis=time_axis, timesys=None, trefpos=None,
                                   mjdref=None, exposure=mc.to_float(exposure),
                                   resolution=None)
        chunk.time = temporal_wcs
    logging.debug(f'End _update_ngvs_time.')
Ejemplo n.º 25
0
 def test_function1d_to_interval_happy_path(self):
     # happy path
     wcs = CustomTestUtil.good_wcs()
     naxis = int(100)
     delta = -0.2
     ref_coord = RefCoord(0.0, 0.0)
     function_1d = CoordFunction1D(naxis, delta, ref_coord)
     actual_interval = wcs_util.CustomAxisUtil.function1d_to_interval(
         wcs, function_1d)
     expected_interval = Interval(-502.5, -2.5)
     self.assertEqual(expected_interval.lower, actual_interval.lower)
     self.assertEqual(expected_interval.upper, actual_interval.upper)
     self.assertEqual(None, actual_interval.samples)
     # function_1d.delta == 0.0 && function_1d.naxis > 1
     naxis = int(100)
     delta = 0.0
     ref_coord = RefCoord(0.0, 0.0)
     function_1d = CoordFunction1D(naxis, delta, ref_coord)
     with pytest.raises(ValueError) as ex:
         wcs_util.CustomAxisUtil.function1d_to_interval(wcs, function_1d)
     assert ('Invalid CoordFunction1D:' in str(ex.value))
Ejemplo n.º 26
0
 def get_test_function_with_function(ctype, unit, px, sx, nx, ds):
     error = None
     range = None
     bounds = None
     naxis = int(1)
     delta = float(2.5)
     ref_coord = wcs.RefCoord(float(1.0), float(2.0))
     function = CoordFunction1D(naxis, delta, ref_coord)
     axis_1d = CoordAxis1D(wcs.Axis(ctype, unit), error, range, bounds,
                           function)
     ref_coord = RefCoord(px, sx)
     axis_1d.function = CoordFunction1D(nx, ds, ref_coord)
     custom_wcs = chunk.CustomWCS(axis_1d)
     return custom_wcs
Ejemplo n.º 27
0
    def _update_time(self, chunk, obs_id):
        """Create TemporalWCS information using FITS header information.
        This information should always be available from the file."""
        self._logger.debug('Begin _update_time.')
        mc.check_param(chunk, Chunk)

        mjd_start = self._headers[0].get('MJD_STAR')
        mjd_end = self._headers[0].get('MJD_END')
        if mjd_start is None or mjd_end is None:
            mjd_start, mjd_end = ac.find_time_bounds(self._headers)
        if mjd_start is None or mjd_end is None:
            chunk.time = None
            self._logger.debug(
                f'Cannot calculate MJD_STAR {mjd_start} or ' f'MDJ_END'
                f' {mjd_end}'
            )
        elif mjd_start == 'NaN' or mjd_end == 'NaN':
            raise mc.CadcException(
                f'Invalid time values MJD_STAR {mjd_start} or MJD_END '
                f'{mjd_end} for {obs_id}, stopping ingestion.'
            )
        else:
            self._logger.debug(
                f'Calculating range with start {mjd_start} and end {mjd_end}.'
            )
            start = RefCoord(0.5, mjd_start)
            end = RefCoord(1.5, mjd_end)
            time_cf = CoordFunction1D(1, self._headers[0].get('TEFF'), start)
            time_axis = CoordAxis1D(Axis('TIME', 'd'), function=time_cf)
            time_axis.range = CoordRange1D(start, end)
            chunk.time = TemporalWCS(time_axis)
            chunk.time.exposure = self._headers[0].get('TEFF')
            chunk.time.resolution = 0.1
            chunk.time.timesys = 'UTC'
            chunk.time.trefpos = 'TOPOCENTER'
            chunk.time_axis = None
        self._logger.debug('Done _update_time.')
Ejemplo n.º 28
0
def _update_time(part, chunk, header, obs_id):
    logging.debug(f'Begin _update_time for {obs_id} part {part.name}.')

    # DB 02-07-20
    # time metadata comes from MJD_OBS and EXPTIME, it's not
    # an axis requiring cutout support
    exp_time = header.get('EXPTIME')
    mjd_obs = header.get('MJD_OBS')
    if exp_time is None or mjd_obs is None:
        chunk.time = None
    else:
        if chunk.time is None:
            coord_error = CoordError(syser=1e-07, rnder=1e-07)
            time_axis = CoordAxis1D(axis=Axis('TIME', 'd'), error=coord_error)
            chunk.time = TemporalWCS(axis=time_axis, timesys='UTC')
        ref_coord = RefCoord(pix=0.5, val=mjd_obs)
        chunk.time.axis.function = CoordFunction1D(
            naxis=1, delta=mc.convert_to_days(exp_time), ref_coord=ref_coord)
        chunk.time.exposure = float(exp_time)
        chunk.time.resolution = mc.convert_to_days(exp_time)
    logging.debug(f'End _update_time.')
Ejemplo n.º 29
0
 def get_test_function_with_bounds_3_samples(ctype, unit, px, sx, nx, ds):
     error = None
     range = None
     start = RefCoord(float(0.8), float(1.1))
     end = RefCoord(float(10.8), float(11.1))
     b_range_1 = CoordRange1D(start, end)
     start = RefCoord(float(0.9), float(1.2))
     end = RefCoord(float(10.9), float(11.2))
     b_range_2 = CoordRange1D(start, end)
     start = RefCoord(float(-0.9), float(-1.2))
     end = RefCoord(float(0.6), float(0.2))
     b_range_3 = CoordRange1D(start, end)
     samples = caom_util.TypedList(CoordRange1D, b_range_1, b_range_2,
                                   b_range_3)
     bounds = CoordBounds1D(samples)
     axis_1d = wcs.CoordAxis1D(wcs.Axis(ctype, unit), error, range, bounds)
     ref_coord = wcs.RefCoord(px, sx)
     axis_1d.function = wcs.CoordFunction1D(nx, ds, ref_coord)
     custom_wcs = chunk.CustomWCS(axis_1d)
     return custom_wcs
Ejemplo n.º 30
0
    def test_bounds(self):
        # Polarization bounds is None, should not produce an error
        axis = Axis("STOKES", "cunit")
        axis_1d = CoordAxis1D(axis)
        polarization = PolarizationWCS(axis_1d)
        wcsvalidator._validate_polarization_wcs(polarization)

        # Polarization axis bounds contains one valid range
        start = RefCoord(float(0.9), float(1.1))
        end = RefCoord(float(9.9), float(10.1))
        p_range = CoordRange1D(start, end)
        samples = caom_util.TypedList(CoordRange1D, p_range)
        axis_1d.bounds = CoordBounds1D(samples)
        polarization = PolarizationWCS(axis_1d)
        wcsvalidator._validate_polarization_wcs(polarization)

        # Polarization axis bounds contains more than one valid range
        start = RefCoord(float(0.9), float(1.1))
        end = RefCoord(float(9.9), float(10.1))
        p_range = CoordRange1D(start, end)
        start = RefCoord(float(-8.1), float(-7.9))
        end = RefCoord(float(-1.1), float(-0.9))
        n_range = CoordRange1D(start, end)
        samples = caom_util.TypedList(CoordRange1D, p_range, n_range)
        axis_1d.bounds = CoordBounds1D(samples)
        polarization = PolarizationWCS(axis_1d)
        wcsvalidator._validate_polarization_wcs(polarization)

        # Polarization axis bounds contains one invalid range
        start = RefCoord(float(0.9), float(1.1))
        end = RefCoord(float(10.9), float(11.1))
        p_range = CoordRange1D(start, end)
        samples = caom_util.TypedList(CoordRange1D, p_range)
        axis_1d.bounds = CoordBounds1D(samples)
        polarization = PolarizationWCS(axis_1d)
        with pytest.raises(InvalidWCSError) as ex:
            wcsvalidator._validate_polarization_wcs(polarization)
        assert ('Invalid Polarization WCS' in str(ex.value))
        assert ('11' in str(ex.value))

        # Polarization axis bounds contains more than one invalid range
        start = RefCoord(float(0.9), float(1.1))
        end = RefCoord(float(9.9), float(10.1))
        p_range = CoordRange1D(start, end)
        start = RefCoord(float(-9.1), float(-8.9))
        end = RefCoord(float(-1.1), float(-0.9))
        n_range = CoordRange1D(start, end)
        samples = caom_util.TypedList(CoordRange1D, p_range, n_range)
        axis_1d.bounds = CoordBounds1D(samples)
        polarization = PolarizationWCS(axis_1d)
        with pytest.raises(InvalidWCSError) as ex:
            wcsvalidator._validate_polarization_wcs(polarization)
        assert ('Invalid Polarization WCS' in str(ex.value))
        assert ('-9' in str(ex.value))