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))
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
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
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)
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
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
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 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)
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
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.')
def _update_from_comment(observation, phangs_name, headers): # From ER: 04-03-21 # COMMENT Produced with PHANGS-ALMA pipeline version 4.0 Build 935 # - Provenance.version # COMMENT Galaxy properties from PHANGS sample table version 1.6 # COMMENT Calibration Level 4 (ANALYSIS_PRODUCT) # - Calibration level (either 3 or 4) # COMMENT PHANGS-ALMA Public Release 1 # - Provenance.project = PHANGS-ALMA # COMMENT Generated by the Physics at High Angular resolution # COMMENT in nearby GalaxieS (PHANGS) collaboration # - Provenance.organization = PHANGS # COMMENT Canonical Reference: Leroy et al. (2021), ApJ, Submitted # - Update to reference when accepted # COMMENT Release generated at 2021-03-04T07:28:10.245340 # - Provenance.lastExecuted # COMMENT Data from ALMA Proposal ID: 2017.1.00886.L # - Proposal.proposalID # COMMENT ALMA Proposal PI: Schinnerer, Eva # - Proposal.pi_name # COMMENT Observed in MJD interval [58077.386275,58081.464121] # COMMENT Observed in MJD interval [58290.770032,58365.629222] # COMMENT Observed in MJD interval [58037.515807,58047.541173] # COMMENT Observed in MJD interval [58353.589805,58381.654757] # COMMENT Observed in MJD interval [58064.3677,58072.458597] # COMMENT Observed in MJD interval [58114.347649,58139.301879] chunk = None for plane in observation.planes.values(): if plane.product_id != phangs_name.product_id: continue if plane.provenance is None: plane.provenance = Provenance(name='PHANGS-ALMA pipeline') for artifact in plane.artifacts.values(): if artifact.uri != phangs_name.file_uri: continue for part in artifact.parts.values(): chunk = part.chunks[0] break for entry in headers[0].get('COMMENT'): if 'pipeline version ' in entry: plane.provenance.version = entry.split(' version ')[1] elif 'Calibration Level' in entry: level = entry.split()[2] if level == '4': plane.calibration_level = CalibrationLevel.ANALYSIS_PRODUCT elif 'PHANGS-ALMA Public Release' in entry: plane.provenance.project = 'PHANGS-ALMA' elif 'in nearby GalaxieS (PHANGS) collaboration' in entry: plane.provenance.organization = 'PHANGS' elif 'Release generated at ' in entry: plane.provenance.last_executed = mc.make_time_tz( entry.split(' at ')[1]) elif 'Data from ALMA Proposal ID:' in entry: observation.proposal = Proposal(entry.split(':')[1].strip()) elif 'Canonical Reference: ' in entry: plane.provenance.producer = entry.split(': ')[1] elif 'ALMA Proposal PI:' in entry: observation.proposal.pi_name = entry.split(': ')[1] elif 'Observed in MJD interval ' in entry: if chunk is not None: bits = entry.split()[4].split(',') start_ref_coord = RefCoord( 0.5, mc.to_float(bits[0].replace('[', ''))) end_ref_coord = RefCoord( 1.5, mc.to_float(bits[1].replace(']', ''))) sample = CoordRange1D(start_ref_coord, end_ref_coord) if chunk.time is None: coord_bounds = CoordBounds1D() axis = CoordAxis1D(axis=Axis('TIME', 'd')) chunk.time = TemporalWCS(axis, timesys='UTC') chunk.time.axis.bounds = coord_bounds chunk.time.axis.bounds.samples.append(sample)