def test_function(self): # Polarization function 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 function with naxis=1 naxis = int(1) delta = float(2.5) ref_coord = wcs.RefCoord(float(1.0), float(2.0)) axis_1d.function = CoordFunction1D(naxis, delta, ref_coord) polarization = PolarizationWCS(axis_1d) wcsvalidator._validate_polarization_wcs(polarization) # Polarization axis function with naxis>1 naxis = int(3) delta = float(2.5) ref_coord = wcs.RefCoord(float(1.0), float(2.0)) axis_1d.function = CoordFunction1D(naxis, delta, ref_coord) polarization = PolarizationWCS(axis_1d) wcsvalidator._validate_polarization_wcs(polarization) # Polarization axis function with invalid naxis=0 naxis = int(0) delta = float(2.5) ref_coord = wcs.RefCoord(float(1.0), float(2.0)) axis_1d.function = CoordFunction1D(naxis, delta, ref_coord) polarization = PolarizationWCS(axis_1d) with pytest.raises(InvalidWCSError) as ex: wcsvalidator._validate_polarization_wcs(polarization) assert ('Invalid Polarization WCS' in str(ex.value)) assert ('Invalid naxis value' in str(ex.value))
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
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.')
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)
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.')
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.')
def bad_delta(): axis_1d = wcs.CoordAxis1D(wcs.Axis("UTC", "d")) temporal_wcs = chunk.TemporalWCS(axis_1d) # delta == 0.0 is bad ref_coord = wcs.RefCoord(float(1.0), float(2.0)) temporal_wcs.axis.function = CoordFunction1D(int(100), 0.0, ref_coord) return temporal_wcs
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
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)
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))
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)
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.')
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.')
def get_test_function(ctype, unit, px, sx, nx, ds): axis_1d = CoordAxis1D(wcs.Axis(ctype, unit)) ref_coord = RefCoord(px, sx) axis_1d.function = CoordFunction1D(nx, ds, ref_coord) custom_wcs = chunk.CustomWCS(axis_1d) return custom_wcs