def test_phasecenter(self): phasecenter_str = '15:30:0 -10.30.00 J2000' phasecenter_rec = imagewriter.parse_phasecenter(phasecenter_str) self.result = phasecenter_rec lonstr, latstr, ref = phasecenter_str.split() qa = casa.CreateCasaQuantity() me = casa.CreateCasaMeasure() lon = qa.convert(qa.quantity(lonstr), 'rad') # to make value in ranges [-pi, pi] pi = qa.constants('pi')['value'] lon['value'] = (lon['value'] + pi) % (2 * pi) - pi lat = qa.quantity(latstr) print(lon) print(lat) print(phasecenter_str) self.assertEqual(me.gettype(phasecenter_rec), 'Direction') self.assertEqual(me.getref(phasecenter_rec), ref) phasecenter_value = me.getvalue(phasecenter_rec) actual_lon = qa.convert(phasecenter_rec['m0'], 'rad')['value'] expected_lon = qa.convert(lon, 'rad')['value'] diff = abs((actual_lon - expected_lon) / expected_lon) eps = 1.0e-15 self.assertLess(diff, eps) self.assertTrue(qa.eq(lat, phasecenter_value['m1']))
def _get_lsr_frequency(self, times, data_desc_ids, field_ids): # sanity check # - consistency of chunk data length assert len(times) == len(data_desc_ids) assert len(times) == len(field_ids) me = casa.CreateCasaMeasure() qa = casa.CreateCasaQuantity() # position measure -- observatory position of ALMA me.doframe(me.observatory('ALMA')) nchunk = len(times) lsr_frequency = {} lsr_width = {} for i in range(nchunk): ddid = data_desc_ids[i] field_id = field_ids[i] spwid = self.dd_spw_map[ddid] freq_ref = self.freq_ref[spwid] chan_freq = self.chan_freq[spwid] chan_width = self.chan_width[spwid] nchan = len(chan_freq) lsr_freq_edge = numpy.empty(nchan + 1, dtype=numpy.float64) lsr_freq_edge[:nchan] = chan_freq - chan_width / 2.0 lsr_freq_edge[nchan] = chan_freq[-1] + chan_width[-1] / 2.0 if freq_ref == 'LSRK': # frequency is in LSRK, no conversion is needed pass else: # require conversion to LSRK # time measure epoch = qa.quantity(times[i], 's') mepoch = me.epoch('utc', epoch) me.doframe(mepoch) # direction measure field_dir = self.field_dir[field_id][:, 0] lon = qa.quantity(field_dir[0], 'rad') lat = qa.quantity(field_dir[1], 'rad') mdirection = me.direction(self.field_ref, lon, lat) me.doframe(mdirection) # frequency measure frequency = qa.quantity(0.0, 'Hz') mfrequency = me.frequency(freq_ref, frequency) for ichan in range(nchan): mfrequency['m0']['value'] = lsr_freq_edge[ ichan] #chan_freq[ichan] - 0.5 * chan_width[ichan] #print 'LOG mfrequency = {0}'.format(mfrequency) # convert converted = me.measure(mfrequency, 'LSRK') lsr_freq_edge[ichan] = converted['m0']['value'] mfrequency['m0']['value'] = lsr_freq_edge[ nchan] #chan_freq[nchan-1] + 0.5 * chan_width[nchan-1] converted = me.measure(mfrequency, 'LSRK') lsr_freq_edge[nchan] = converted['m0']['value'] lsr_frequency[i] = lsr_freq_edge #print 'LOG native = {0}'.format(chan_freq) #print 'LOG converted = {0}'.format(lsr_frequency[i]) #return lsr_frequency, lsr_width return lsr_frequency
def parse_phasecenter(phasecenter_str): qa = casa.CreateCasaQuantity() me = casa.CreateCasaMeasure() if len(phasecenter_str) == 0: # defualt value '0:0:0 0.0.0 J2000' lat = qa.quantity(0.0, 'rad') lon = qa.quantity(0.0, 'rad') ref = 'J2000' else: # expected format: "longitude latitude [ref]" s = phasecenter_str.split() ref = 'J2000' # default reference is J2000 if len(s) == 3: lat = qa.quantity(s[1]) lon = qa.quantity(s[0]) ref = s[2] elif len(s) == 2: lat = qa.quantity(s[1]) lon = qa.quantity(s[0]) else: raise ValueError( 'Invalid phasecenter: "{0}"'.format(phasecenter_str)) #print 'DEBUG rf={0} lon={1} lat={2}'.format(ref, lon, lat) direction = me.direction(rf=ref, v0=lon, v1=lat) return direction
def width(self, value): qa = casa.CreateCasaQuantity() if isinstance(value, str): self._width = qa.quantity(value) elif isinstance(value, dict): self._width = value else: # should be numeric value that # are expected to be channel self._width = value
def rest_frequency(self, value): qa = casa.CreateCasaQuantity() if isinstance(value, str): if len(value) > 0: self._rest_frequency = qa.quantity(value) else: self._rest_frequency = qa.quantity(1.0e9, 'Hz') elif isinstance(value, dict): self._rest_frequency = value else: # should be numeric self._rest_frequency = qa.quantity(value, 'Hz')
def _uv_from_pixel(self, px, py, uvw, lsr_freq): qa = casa.CreateCasaQuantity() nx = self.imageparam.imsize[0] ny = self.imageparam.imsize[1] dx = qa.convert(self.imageparam.cell[0], 'rad')['value'] dy = qa.convert(self.imageparam.cell[1], 'rad')['value'] wx = nx * dx wy = ny * dy offx = int(nx) // 2 offy = int(ny) // 2 fcenter = (lsr_freq.min() + lsr_freq.max()) / 2.0 c = qa.convert(qa.constants('c'), 'm/s')['value'] lcenter = c / fcenter uvw[0] = lcenter * (px - offx) / wx uvw[1] = lcenter * (py - offy) / wy
def phasecenter_string(self): value = '' me = casa.CreateCasaMeasure() if isinstance(self.phasecenter, str): value = self.phasecenter elif me.ismeasure(self.phasecenter): pdir = self.phasecenter qa = casa.CreateCasaQuantity() ra = qa.formxxx(pdir['m0'], 'hms', prec=8) dec = qa.formxxx(pdir['m1'], 'dms', prec=8) phase_direction = '{0} {1} {2}'.format(ra, dec, pdir['refer']) value = phase_direction else: value = str(self.phasecenter) return value
def suggest_imaging_param(visparam): vis = visparam.vis msselect = visparam.as_msselection() with casa.OpenMS(vis) as ms: ms.msselect(msselect, onlyparse=False) data = ms.getdata(['uvw', 'data_desc_id', 'antenna1', 'antenna2']) uvw = data['uvw'] ddid = data['data_desc_id'] antenna1 = data['antenna1'] antenna2 = data['antenna2'] observing_frequency = ImageConfigurationHelper.get_observing_frequency( vis) antenna_diameter = ImageConfigurationHelper.get_antenna_diameter(vis) # maximum antenna primary beam size [arcsec] min_freq = min(observing_frequency.values()) * 1e-9 # Hz -> GHz min_diameter = min(antenna_diameter) primary_beam = ImageConfigurationHelper.calc_primary_beam( min_diameter, min_freq) qa = casa.CreateCasaQuantity() c = qa.convert(qa.constants('c'), 'm/s')['value'] nrow = len(ddid) umax = 0.0 vmax = 0.0 for irow in range(nrow): f = observing_frequency[ddid[irow]] u = uvw[0, irow] / c * f v = uvw[1, irow] / c * f umax = max(umax, u) vmax = max(vmax, v) rad2arcsec = 180.0 / numpy.pi * 3600.0 dl = 1.0 / (2 * umax) * rad2arcsec # rad -> arcsec dm = 1.0 / (2 * vmax) * rad2arcsec # rad -> arcsec M = int(numpy.ceil(primary_beam / dl)) + 12 N = int(numpy.ceil(primary_beam / dm)) + 12 suggested = { 'cell': ['{}arcsec'.format(dl), '{}arcsec'.format(dm)], 'imsize': [M, N] } return suggested
def get_default_imageparam(self): qa = casa.CreateCasaQuantity() phasecenter = '9:00:00 -60.00.00 J2000' #phasecenter_rec = imagewriter.parse_phasecenter(phasecenter_str) start = qa.quantity('101GHz') width = qa.quantity('1MHz') nchan = 3 imsize = [10, 9] cell = '1arcsec' imageparam = paramcontainer.ImageParamContainer( imagename=self.imagename, phasecenter=phasecenter, imsize=imsize, cell=cell, start=start, width=width, nchan=nchan, outframe='LSRK', stokes='I') return imageparam
def _convert(self, timestamp, field_id, mfr, chan_freq): me = casa.CreateCasaMeasure() qa = casa.CreateCasaQuantity() vis = self.vis with casa.OpenTableForRead(os.path.join(vis, 'FIELD')) as tb: reference_dir = tb.getcell('PHASE_DIR', field_id)[:, 0] reference_frame = 'J2000' # hard coded lon = qa.quantity(reference_dir[0], 'rad') lat = qa.quantity(reference_dir[1], 'rad') mdirection = me.direction(rf=reference_frame, v0=lon, v1=lat) mepoch = me.epoch(rf='UTC', v0=qa.quantity(timestamp, 's')) mposition = me.observatory('ALMA') me.doframe(mdirection) me.doframe(mepoch) me.doframe(mposition) lsr_freq = numpy.empty_like(chan_freq) for ichan in range(len(lsr_freq)): mfrequency = me.frequency(rf=mfr, v0=qa.quantity(chan_freq[ichan], 'Hz')) converted = me.measure(mfrequency, rf='LSRK') lsr_freq[ichan] = converted['m0']['value'] return lsr_freq
def uvgridconfig(self): if not hasattr(self, '_uvgridconfig'): qa = casa.CreateCasaQuantity() cellx = qa.quantity(self.cell[0]) celly = qa.quantity(self.cell[1]) nu = self.imsize[0] nv = self.imsize[1] wx = nu * qa.convert(cellx, 'rad')['value'] wy = nv * qa.convert(celly, 'rad')['value'] cellu = 1 / wx cellv = 1 / wy # offset must always be pixel center even if nu and/or nv # is even (which causes offset value to be non-integer) offsetu = int(nu) // 2 # make sure integer operation offsetv = int(nv) // 2 # make sure integer operation self._uvgridconfig = datacontainer.UVGridConfig(cellu=cellu, cellv=cellv, nu=nu, nv=nv, offsetu=offsetu, offsetv=offsetv) return self._uvgridconfig
def _run_test(self, imageparam, arr, imagemeta=None): qa = casa.CreateCasaQuantity() writer = imagewriter.ImageWriter(imageparam, arr, imagemeta) if imagemeta is None: # default image metadata imagemeta = paramcontainer.ImageMetaInfoContainer() status = writer.write(overwrite=True) self.assertTrue(status) self.assertTrue(os.path.exists(self.imagename)) self.result = self.imagename ia = casa.CreateCasaImageAnalysis() ia.open(self.imagename) try: # image shape expected_shape = (imageparam.imsize[0], imageparam.imsize[1], imageparam.nchan, 1) self.assertTrue(numpy.all(expected_shape == ia.shape())) csys = ia.coordsys() # direction coordinate dirref = csys.referencecode(type='direction')[0] self.assertEqual(dirref, 'J2000') refpix = self._get_reference(csys, 'referencepixel', 'direction') refval = self._get_reference(csys, 'referencevalue', 'direction') incr = self._get_reference(csys, 'increment', 'direction') self.assertEqual(len(refpix), 2) self.assertEqual(refpix[0], 0.5 * (imageparam.imsize[0] - 1)) self.assertEqual(refpix[1], 0.5 * (imageparam.imsize[1] - 1)) phasecenter_rec = imagewriter.parse_phasecenter( imageparam.phasecenter) center_x = qa.convert(phasecenter_rec['m0'], 'rad')['value'] center_y = qa.convert(phasecenter_rec['m1'], 'rad')['value'] #print center_x, center_y eps = 1.0e-11 self.assertClose(refval[0], center_x, eps) self.assertClose(refval[1], center_y, eps) cellx = -qa.convert(qa.quantity(imageparam.cell[0]), 'rad')['value'] celly = qa.convert(qa.quantity(imageparam.cell[1]), 'rad')['value'] #print cellx, celly self.assertClose(incr[0], cellx, eps) self.assertClose(incr[1], celly, eps) # spectral coordinate specref = csys.referencecode(type='spectral')[0] self.assertEqual(specref, 'LSRK') refpix = self._get_reference(csys, 'referencepixel', 'spectral') refval = self._get_reference(csys, 'referencevalue', 'spectral') incr = self._get_reference(csys, 'increment', 'spectral') self.assertEqual(refpix, 0.0) #self.assertEqual(refval, qa.convert(start, 'Hz')['value']) #self.assertEqual(incr, qa.convert(width, 'Hz')['value']) self.assertEqual(refval, qa.convert(imageparam.start, 'Hz')['value']) self.assertEqual(incr, qa.convert(imageparam.width, 'Hz')['value']) # stokes coordinate refpix = self._get_reference(csys, 'referencepixel', 'stokes') refval = self._get_reference(csys, 'referencevalue', 'stokes') incr = self._get_reference(csys, 'increment', 'stokes') self.assertEqual(refpix, 0.0) self.assertEqual(refval, 1.0) self.assertEqual(incr, 1.0) # verify image meta data self.assertEqual(csys.observer(), imagemeta.observer) self.assertEqual(csys.telescope(), imagemeta.telescope) self.assertTrue( qa.eq(csys.restfrequency(), imagemeta.rest_frequency)) epoch = csys.epoch() obsdate = imagemeta.observing_date self.assertEqual(epoch['refer'], obsdate['refer']) self.assertClose(epoch['m0']['value'], obsdate['m0']['value']) # image data chunk = ia.getchunk() imageshape = chunk.shape self.assertEqual(imageshape, expected_shape) shaped_chunk = chunk[:, :, :, 0] print(shaped_chunk.shape, arr.shape) self.assertTrue(numpy.allclose(arr, shaped_chunk), msg='expected {0} actual {1} (maxdiff {2})'.format( arr, shaped_chunk, abs(arr - shaped_chunk).max())) finally: ia.done()
def fill_uvw(self, ws, chunk, lsr_edge_frequency): """ Fill UV coordinate ws -- working set to be filled chunk -- input data chunk lsr_edge_frequency -- channel edge frequency (LSRK) """ phasecenter = self.imageparam.phasecenter self._check_phasecenter(phasecenter) #self._warn_refocus() qa = casa.CreateCasaQuantity() speed_of_light = qa.constants('c') c = qa.convert(speed_of_light, 'm/s')['value'] data_shape = chunk['data'].shape nrow = data_shape[2] nchan = data_shape[1] uvw = chunk['uvw'] data_desc_ids = chunk['data_desc_id'] uvgrid = self.imageparam.uvgridconfig delta_u = uvgrid.cellu delta_v = uvgrid.cellv offset_u = uvgrid.offsetu offset_v = uvgrid.offsetv # UVW conversion u = sakura.empty_aligned((nrow, nchan), dtype=uvw.dtype) v = sakura.empty_like_aligned(u) for irow in range(nrow): # TODO: phase rotation if image phasecenter is different from # the reference direction of the observation pass # conversion from physical baseline length to the value # normalized by observing wavelength u0 = uvw[0, irow] v0 = uvw[1, irow] spw_id = data_desc_ids[irow] #chan_freq = lsr_frequency #chan_width = (lsr_edge_frequency[1:] - lsr_edge_frequency[:-1]).mean() #freq_start = chan_freq[0] - chan_width / 2 #freq_end = chan_freq[-1] + chan_width / 2 #freq_start = lsr_edge_frequency[0] #freq_end = lsr_edge_frequency[-1] #center_freq = (freq_start + freq_end) / 2 center_freq = numpy.fromiter( (numpy.mean(lsr_edge_frequency[i:i + 2]) for i in range(nchan)), dtype=numpy.float64) u[irow] = u0 * center_freq / c # divided by wavelength v[irow] = v0 * center_freq / c # divided by wavelength # TODO?: refocus UVW if distance to the source is known pass # project uv-coordinate value onto gridding pixel plane # pixel size is determined by an inverse of image extent # along x (RA) and y (DEC) direction # # v # nv-1|(nmin,vmax) (umax,vmax) # .| # .| # .| # .| # nv/2| (0,0) # .| # .| # 2| # 1| # 0|(umin,vmin) (umax,vmin) # |__________________________ # 0 1 2 ......nu/2...nu-1 u u[irow] = u[irow] / delta_u + offset_u # Sign of v must be inverted so that MFISTA routine generates # proper image. Otherwise, image will be flipped in the vertical # axis. v[irow] = -v[irow] / delta_v + offset_v ws.u = u ws.v = v
def fill_data(self, ws, chunk, lsr_edge_frequency): qa = casa.CreateCasaQuantity() lsr_frequency = (lsr_edge_frequency[1:] + lsr_edge_frequency[:-1]) / 2.0 # info from chunk field_id = chunk['field_id'][0] data_desc_id = chunk['data_desc_id'][0] # get spectral channel selection parameter start = self.imageparam.start width = self.imageparam.width nchan = self.imageparam.nchan npol = chunk['data'].shape[0] nrow = chunk['data'].shape[2] qstart = qa.quantity(start) qwidth = qa.quantity(width) qnchan = qa.quantity(nchan) start_unit = qa.getunit(qstart) width_unit = qa.getunit(qwidth) frequency_pattern = re.compile('^(G|k|M|T)?Hz$') wavelength_pattern = re.compile('^(k|c|m|n)?m$') velocity_pattern = re.compile( wavelength_pattern.pattern.replace('$', '/s$')) match_with = lambda pattern: pattern.match(start_unit) is not None and \ pattern.match(width_unit) is not None image_freq = numpy.empty(nchan, dtype=numpy.float64) image_width = 0.0 # get image LSRK frequency # start, width, and nchan are defined as follows: # # start=<center frequency of first image channel> # | # |-------|-------|-------| nchan=3 # |<----->| # width=<constant channel width of image channel> # if len(start_unit) == 0 and len(width_unit) == 0: # channel selection # use nominal LSRK frequency for image (channel boundary) nominal_lsr_frequency = self.nominal_lsr_frequency[field_id][ data_desc_id] #nominal_lsr_width = self.nominal_lsr_width[field_id][data_desc_id] if nchan == 1 and width == -1: # this is special setting that maps all visibility channels into # single image channel image_freq[0] = (nominal_lsr_frequency[-1] + nominal_lsr_frequency[0]) / 2.0 image_width = nominal_lsr_frequency[ -1] - nominal_lsr_frequency[0] else: for ichan in range(nchan): # left boundary of start channel channel_start = int( qstart['value']) + ichan * int(qwidth['value']) # right boundary of end channel channel_end = channel_start + int(qwidth['value']) # center frequency of the range image_freq[ichan] = ( nominal_lsr_frequency[channel_start] + nominal_lsr_frequency[channel_end]) / 2.0 image_width = (nominal_lsr_frequency[1] - nominal_lsr_frequency[0]) \ * int(qwidth['value']) elif match_with(frequency_pattern): # frequency selection for ichan in range(nchan): image_freq[ichan] = qa.convert( qa.add(qstart, qa.mul(qwidth, ichan)), 'Hz')['value'] image_width = qa.convert(qwidth, 'Hz')['value'] elif match_with(wavelength_pattern): # wavelength selection -- not supported yet raise NotImplementedError( 'wavelength selection is not implemented yet') elif match_with(velocity_pattern): # velocity selection -- not supported yet raise NotImplementedError( 'velocity selection is not implemented yet') else: # invalid or mixed selection raise ValueError( 'image channel selection is invalid or not supported') # map/interpolate data_desc_ids = chunk['data_desc_id'] nchunk = len(data_desc_ids) spwid = self.dd_spw_map[data_desc_id] chan_width = self.chan_width[spwid][0] # chunk holds WEIGHT column, which should store channelized weight, # 2 * df * dt (which equals 2 * EFFECTIVE_BW[0] * INTEVAL) so that # weight scaling factor is 1.0 by default weight_factor = 1.0 #print 'LOG: SPW {0} chan_width * 2 = {1}, image_width = {2}'.format( # spwid, chan_width * 2, image_width) if abs(image_width) < 1.99 * abs(chan_width): #print 'LOG: do interpolation' # interpolation # TODO: array shape (order) should be compatible with sakura gridding function ws_shape = ( nrow, 1, nchan, ) ws_shape2 = ( nrow, nchan, ) real = sakura.empty_aligned(ws_shape, dtype=numpy.float32) imag = sakura.empty_aligned(ws_shape, dtype=numpy.float32) flag = sakura.empty_aligned(ws_shape, dtype=numpy.bool) weight = sakura.empty_aligned(ws_shape2, dtype=numpy.float32) row_flag = sakura.empty_aligned((nrow, ), dtype=numpy.bool) channel_map = sakura.empty_aligned((nchan, ), dtype=numpy.int32) channel_map[:] = numpy.arange(nchan, dtype=numpy.int32) # real, image: linear interpolation #print 'LOG: lsr_frequency length {0} real.shape {1}'.format( # len(lsr_frequency), chunk['data'].shape) if chunk['data'].shape[1] > 1: data_interp = interpolate.interp1d(lsr_frequency, chunk['data'], kind='linear', axis=1, fill_value='extrapolate') _data = data_interp(image_freq) # flag: nearest interpolation flag_interp = interpolate.interp1d(lsr_frequency, chunk['flag'], kind='nearest', axis=1, fill_value='extrapolate') _flag = flag_interp(image_freq) else: _data = chunk['data'] _flag = chunk['flag'] _weight = chunk['weight'] self._to_stokesI(_data, _flag, _weight, weight_factor, real, imag, flag, weight) else: #print 'LOG: do channel mapping' # channel mapping # if chunk frequency for i goes into image frequency cell for k, # i maps into k image_freq_boundary = numpy.empty(nchan + 1, dtype=numpy.float64) image_freq_boundary[:-1] = image_freq - 0.5 * image_width image_freq_boundary[-1] = image_freq[-1] + 0.5 * image_width image_freq_min = image_freq_boundary.min() image_freq_max = image_freq_boundary.max() in_range = numpy.where( numpy.logical_and(image_freq_min <= lsr_frequency, lsr_frequency <= image_freq_max))[0] nvischan = len(in_range) # accumulate N channels improves weight factor by N weight_factor *= float(nvischan) # TODO: array shape (order) should be compatible with sakura gridding function ws_shape = ( nrow, 1, nvischan, ) ws_shape2 = ( nrow, nvischan, ) real = sakura.empty_aligned(ws_shape, dtype=numpy.float32) imag = sakura.empty_aligned(ws_shape, dtype=numpy.float32) flag = sakura.empty_aligned(ws_shape, dtype=numpy.bool) weight = sakura.empty_aligned(ws_shape2, dtype=numpy.float32) row_flag = sakura.empty_aligned((nrow, ), dtype=numpy.bool) channel_map = sakura.empty_aligned((nvischan, ), dtype=numpy.int32) for ichan, chan_chunk in enumerate(in_range): # fill in channel_map f = lsr_frequency[chan_chunk] for chan_image in range(nchan): b0 = image_freq_boundary[chan_image] b1 = image_freq_boundary[chan_image + 1] if b0 > b1: tmp = b1 b1 = b0 b0 = tmp if b0 <= f and f <= b1: channel_map[ichan] = chan_image break # fill in data _data = chunk['data'][:, chan_chunk:chan_chunk + 1, :] _flag = chunk['flag'][:, chan_chunk:chan_chunk + 1, :] _weight = chunk['weight'] self._to_stokesI(_data, _flag, _weight, weight_factor, real[:, :, ichan:ichan + 1], imag[:, :, ichan:ichan + 1], flag[:, :, ichan:ichan + 1], weight[:, ichan:ichan + 1]) # row_flag row_flag[:] = numpy.all(flag == True, axis=( 1, 2, )) # invert flag # reader definition: # True: INVALID # False: *VALID* # working set definition: # True: *VALID* # False: INVALID numpy.logical_not(row_flag, row_flag) numpy.logical_not(flag, flag) ws.rdata = real ws.idata = imag ws.flag = flag ws.row_flag = row_flag ws.weight = weight ws.channel_map = channel_map
def _setup_coordsys(self): csys = casa.CreateCasaCoordSys() me = casa.CreateCasaMeasure() qa = casa.CreateCasaQuantity() c = csys.newcoordsys(direction=True, spectral=True, stokes=self.imageparam.stokes) # direction coordinate phasecenter = self.imageparam.phasecenter print('DEBUG phasecenter={0}'.format(phasecenter)) refframe = me.getref(phasecenter) refpix = [int(x) // 2 for x in self.imageparam.imsize] center = me.getvalue(phasecenter) refval = [center['m0']['value'], center['m1']['value']] q2s = lambda x: '{0} {1}'.format(x['value'], x['unit']) srefval = list(map(q2s, [center['m0'], center['m1']])) incr = list(map(qa.quantity, self.imageparam.cell)) # increment of horizontal axis should be negative incr[0] = qa.mul(-1.0, incr[0]) sincr = list(map(q2s, incr)) projection = self.imageparam.projection print('DEBUG refpix={0}, refval={1}'.format(refpix, refval)) c.setdirection(refcode=refframe, proj=projection, refpix=refpix, refval=srefval, incr=sincr) # spectral coordinate refframe = 'LSRK' print('start {0} width {1}'.format(self.imageparam.start, self.imageparam.width)) start = qa.convert(self.imageparam.start, 'Hz') width = qa.convert(self.imageparam.width, 'Hz') nchan = self.imageparam.nchan f = numpy.fromiter( (start['value'] + i * width['value'] for i in range(nchan)), dtype=numpy.float64) print('f = {0}'.format(f)) frequencies = qa.quantity(f, 'Hz') veldef = 'radio' if len(f) > 1: c.setspectral(refcode=refframe, frequencies=frequencies, doppler=veldef) else: print('set increment for spectral axis: {0}'.format(width)) #c.setreferencepixel(value=0, type='spectral') #c.setreferencevalue(value=start, type='spectral') #c.setincrement(value=width, type='spectral') r = c.torecord() if 'spectral2' in r: key = 'spectral2' elif 'spectral1' in r: key = 'spectral1' r[key]['wcs']['crpix'] = 0.0 r[key]['wcs']['crval'] = start['value'] r[key]['wcs']['cdelt'] = width['value'] c.fromrecord(r) # Stokes coordinate # currently only 'I' image is supported #c.setstokes('I') #c.setincrement(value=1, type='stokes') # Meta info c.setobserver(self.imagemeta.observer) c.settelescope(self.imagemeta.telescope) c.setepoch(self.imagemeta.observing_date) rest_frequency = self.imagemeta.rest_frequency if isinstance(rest_frequency, str) and len(rest_frequency) == 0: f = frequencies['value'] nchan = len(f) if nchan % 2 == 0: c1 = (nchan - 1) // 2 c2 = c1 + 1 rest_frequency = qa.quantity(0.5 * (f[c1] + f[c2]), frequencies['unit']) else: c1 = (nchan - 1) // 2 rest_frequency = qa.quantity(f[c1], frequencies['unit']) print('rest_frequency={0}'.format(rest_frequency)) c.setrestfrequency(rest_frequency) print(c.summary(list=False)[0]) return c