def get_psf_secondpeak_old(fn, neighborhood_size=5, threshold=0.01): from scipy import ndimage from scipy.ndimage import filters if fn.endswith('fits'): data = fits.getdata(fn) else: from casatools import image ia = image() ia.open(fn) data = ia.getchunk() ia.close() if data.ndim > 2: data = data.squeeze() if data.ndim > 2: data = data[0, :, :] data_max = filters.maximum_filter(data, neighborhood_size) maxima = (data == data_max) data_min = filters.minimum_filter(data, neighborhood_size) diff = ((data_max - data_min) > threshold) maxima[diff == 0] = 0 labeled, num_objects = ndimage.label(maxima) slices = ndimage.find_objects(labeled) pkval = [data[slc].max() for slc in slices] if len(pkval) >= 2: secondmax = sorted(pkval)[-2] return secondmax else: return np.nan
def assert_header_correct(casa_filename): fits_filename = tempfile.mktemp() # Use CASA to convert back to FITS and use that header as the reference ia = image() ia.open(casa_filename) ia.tofits(fits_filename, stokeslast=False) ia.done() ia.close() # Parse header with WCS - for the purposes of this function # we are not interested in keywords/values not in WCS reference_wcs = WCS(fits_filename) reference_header = reference_wcs.to_header() # Now use our wcs_casa2astropy function to create the header and compare # the results. desc = getdesc(casa_filename) actual_wcs = wcs_casa2astropy(desc['_keywords_']['coords']) actual_header = actual_wcs.to_header() assert sorted(actual_header) == sorted(reference_header) for key in reference_header: if isinstance(actual_header[key], str): assert actual_header[key] == reference_header[key] else: assert_allclose(actual_header[key], reference_header[key])
def data_vda_beams_image(tmp_path): d, h = prepare_adv_data() d, h = transpose(d, h, [2, 0, 1]) d, h = transpose(d, h, [2, 1, 0]) h['BUNIT'] = ' Jy / beam ' del h['BMAJ'], h['BMIN'], h['BPA'] beams = prepare_4_beams() hdul = fits.HDUList([fits.PrimaryHDU(data=d, header=h), beams]) hdul.writeto(tmp_path / 'vda_beams.fits') from casatools import image ia = image() ia.fromfits(infile=tmp_path / 'vda_beams.fits', outfile=tmp_path / 'vda_beams.image', overwrite=True) for (bmaj, bmin, bpa, chan, pol) in beams.data: ia.setrestoringbeam(major={ 'unit': 'arcsec', 'value': bmaj }, minor={ 'unit': 'arcsec', 'value': bmin }, pa={ 'unit': 'deg', 'value': bpa }, channel=chan, polarization=pol) ia.close() return tmp_path / 'vda_beams.image'
def make_casa_testimage(infile, outname): infile = str(infile) outname = str(outname) if not CASA_INSTALLED: raise Exception("Attempted to make a CASA test image in a non-CASA " "environment") ia = image() ia.fromfits(infile=infile, outfile=outname, overwrite=True) ia.unlock() ia.close() ia.done() cube = SpectralCube.read(infile) if isinstance(cube, VaryingResolutionSpectralCube): ia.open(outname) # populate restoring beam emptily ia.setrestoringbeam( major={ 'value': 1.0, 'unit': 'arcsec' }, minor={ 'value': 1.0, 'unit': 'arcsec' }, pa={ 'value': 90.0, 'unit': 'deg' }, channel=len(cube.beams) - 1, polarization=-1, ) # populate each beam (hard assumption of 1 poln) for channum, beam in enumerate(cube.beams): casabdict = { 'major': { 'value': beam.major.to(u.deg).value, 'unit': 'deg' }, 'minor': { 'value': beam.minor.to(u.deg).value, 'unit': 'deg' }, 'positionangle': { 'value': beam.pa.to(u.deg).value, 'unit': 'deg' } } ia.setrestoringbeam(beam=casabdict, channel=channum, polarization=0) ia.unlock() ia.close() ia.done()
def image_summary(image): """ Print image summary and returns data and headers """ ia = tools.image() ia.open(image) # summarize image dd = ia.summary() npixx, npixy, nch, npol = dd['shape'] print('Image shape: {0}'.format(dd['shape'])) imvals = ia.getchunk(0, int(npixx))[:, :, 0, 0] ra_inc = dd['incr'][0] * units.radian dec_inc = dd['incr'][1] * units.radian c = ia.coordmeasures() direction = c['measure']['direction'] az = direction['m0']['value'] el = direction['m1']['value'] co0 = coordinates.SkyCoord(ra=np.degrees(az), dec=np.degrees(el), unit=(units.deg, units.deg)) co0_str = co0.to_string('hmsdms') refpix = (dd['refpix'][0], dd['refpix'][1]) print(f'Coordinates at reference pixel {refpix} are {co0_str}') ra_inc = dd['incr'][0] * units.radian dec_inc = dd['incr'][1] * units.radian print( f'RA, Dec increment: {ra_inc.to(units.arcsecond).value}", {dec_inc.to(units.arcsecond).value}"' ) peakx, peaky = np.where(imvals.max() == imvals) peakx, peaky = peakx[0], peaky[0] print('Peak SNR at pix ({0},{1}) = {2}'.format(peakx, peaky, imvals.max() / imvals.std())) rapeak = co0.ra + (peakx - refpix[0]) * ra_inc decpeak = co0.dec + (peaky - refpix[1]) * dec_inc copeak = coordinates.SkyCoord(ra=rapeak, dec=decpeak).to_string('hmsdms') print(f'Rough coordinates of peak pixel are {copeak}') return imvals, dd, c ## Data summary # import sdmpy # file = '' # sdm = sdmpy.SDM(file, use_xsd=False) # scan = sdm.scan(1) # tab = sdm['SpectralWindow'] # for row in tab: # print(row.getchildren())
def estimate_noise(imagename, linefree_range, noise_function=np.nanstd): ''' Calculate the noise in a cube in line-free channels. Should be run on *non-*pb corrected images so the spatial noise is flat! Estimate will also skip empty channels that do not have any data. ''' if imagename.endswith(".image"): try: # CASA 6 import casatools ia = casatools.image() except ImportError: try: from taskinit import iatool iatool = iatool() except ImportError: raise ImportError("Could not import CASA (casac).") ia.open(imagename) data = ia.getchunk().squeeze() ia.close() ia.done() elif imagename.lower().endswith(".fits"): cube = SpectralCube.read(imagename) data = cube.filled_data[:].value del cube else: raise ValueError("Unsure what kind of file this is.") noise_data = np.empty((1,)) for chan_range in linefree_range: for chan in range(chan_range[0], chan_range[1]): if chan >= data.shape[-1]: continue # Skip empty channels if np.isnan(data[..., chan]).all(): continue if (data[..., chan] == 0.).all(): continue valid_mask = np.logical_and(data[..., chan] != 0., np.isfinite(data[..., chan])) noise_data = np.append(noise_data, data[..., chan][valid_mask]) return noise_function(noise_data)
def display(imname=None): """ Show an image """ im = tools.image() im.open(imname) data = im.getchunk() fig = plt.figure(figsize=(10, 8)) plt.imshow(data.squeeze(), origin='bottom', interpolation='nearest') plt.show()
def __init__(self): import os from casatools import image, synthesisimager, synthesisdeconvolver from casatools import synthesisnormalizer, iterbotsink from casatasks import casalog from casatasks.private.imagerhelpers.input_parameters import ImagerParameters self.ia = image() self.si = synthesisimager() self.sd = synthesisdeconvolver() self.sn = synthesisnormalizer() self.ib = iterbotsink() self.imagename = 'imtry' print("Initialize") os.system('rm -rf '+self.imagename+'.*') self.niter=100 self.cycleniter=10 self.itercount=0 self.finished=False self.stopcode=0 params = ImagerParameters( msname ='point.ms', spw='0:10', imagename=self.imagename, imsize=100, cell='5.0arcsec', specmode='mfs', gridder='standard', niter=self.niter, cycleniter=self.cycleniter, loopgain=0.05, deconvolver='hogbom' ) self.selpars = params.getSelPars()['ms0'] self.impars = params.getImagePars()['0'] self.gridpars = params.getGridPars()['0'] self.decpars = params.getDecPars()['0'] self.normpars = params.getNormPars()['0'] self.weightpars = params.getWeightPars() self.iterpars = params.getIterPars() self.iters=[] self.peaks=[] self.peaks_in_mask=[] self.fluxes=[] self.majcycle=[]
def test_wcs_casa2astropy_linear(tmp_path): # Test that things work properly when the WCS coordinates aren't set casa_filename = str(tmp_path / 'test.image') data = np.random.random((3, 4, 5, 6, 7)) ia = image() ia.fromarray(outfile=casa_filename, pixels=data, log=False) ia.close() assert_header_correct(casa_filename)
def test_casa_mask(data_adv, tmp_path): # This tests the make_casa_mask function which can be used to create a mask # file in an existing image. cube = SpectralCube.read(data_adv) mask_array = np.array([[True, False], [False, False], [True, True]]) bool_mask = BooleanArrayMask(mask=mask_array, wcs=cube._wcs, shape=cube.shape) cube = cube.with_mask(bool_mask) make_casa_mask(cube, str(tmp_path / 'casa.mask'), add_stokes=False, append_to_image=False, overwrite=True) ia = casatools.image() ia.open(str(tmp_path / 'casa.mask')) casa_mask = ia.getchunk() coords = ia.coordsys() ia.unlock() ia.close() ia.done() # Test masks # Mask array is broadcasted to the cube shape. Mimic this, switch to ints, # and transpose to match CASA image. compare_mask = np.tile(mask_array, (4, 1, 1)).astype('int16').T assert np.all(compare_mask == casa_mask) # Test WCS info # Convert back to an astropy wcs object so transforms are dealt with. casa_wcs = coordsys_to_astropy_wcs(coords.torecord()) header = casa_wcs.to_header() # Invokes transform # Compare some basic properties EXCLUDING the spectral axis assert_allclose(cube.wcs.wcs.crval[:2], casa_wcs.wcs.crval[:2]) assert_allclose(cube.wcs.wcs.cdelt[:2], casa_wcs.wcs.cdelt[:2]) assert np.all(list(cube.wcs.wcs.cunit)[:2] == list(casa_wcs.wcs.cunit)[:2]) assert np.all(list(cube.wcs.wcs.ctype)[:2] == list(casa_wcs.wcs.ctype)[:2]) assert_allclose(cube.wcs.wcs.crpix, casa_wcs.wcs.crpix)
def getimage(image): """ Loads and summarize the image, Peak SNR and position """ # load image ia = tools.image() ia.open(image) # summarize image dd = ia.summary() npixx, npixy, nch, npol = dd['shape'] print('Image shape: {0}'.format(dd['shape'])) imvals = ia.getchunk(0, int(npixx))[:, :, 0, 0] return imvals
def __init__(self): from casatasks.private.imagerhelpers.imager_base import PySynthesisImager from casatasks.private.imagerhelpers.input_parameters import ImagerParameters from casatools import image from casatasks import casalog import os self.ia = image() self.imagename = 'imtry' self.niter=100 self.cycleniter=10 self.itercount=0 print("Initialize") os.system('rm -rf '+self.imagename+'.*') ## (2) Set up Input Parameters paramList = ImagerParameters( msname ='point.ms', spw='0:10', imagename=self.imagename, imsize=100, cell='5.0arcsec', specmode='mfs', gridder='standard', niter=self.niter, cycleniter=self.cycleniter, loopgain=0.05, deconvolver='hogbom' ) ## (3) Construct the PySynthesisImager object, with all input parameters self.imager = PySynthesisImager(params=paramList) self.finished=False self.stopcode=0 self.iters=[] self.peaks=[] self.peaks_in_mask=[] self.fluxes=[] self.majcycle=[]
def test_getdminfo(tmp_path, shape): filename = str(tmp_path / 'test.image') data = np.random.random(shape) ia = image() ia.fromarray(outfile=filename, pixels=data, log=False) ia.close() tb = table() tb.open(filename) reference = tb.getdminfo() tb.close() actual = getdminfo(filename) # We include information about endian-ness in the dminfo but CASA doesn't actual['*1'].pop('BIGENDIAN') # The easiest way to compare the output is simply to compare the output # from pformat (checking for dictionary equality doesn't work because of # the Numpy arrays inside). assert pformat(actual) == pformat(reference)
import os.path # set up msname = 'sim_output.ms' conf_file = 'LWA352_coordinates_mod.cfg' if len(sys.argv) > 1: fitsimage = sys.argv[1] else: fitsimage = 'SKAMid_B2_8h_v3.fits' assert os.path.exists(fitsimage) assert 'fits' in fitsimage image = fitsimage.replace('.fits', '.image') if not os.path.exists(image): print('creating ms image to be used as sky model') im = casatools.image() im.fromfits(infile=fitsimage, outfile=image) # get antenna positions tabname = 'antenna_positions_' + conf_file.split('.cfg')[0] + '.tab' tb = casatools.table() tb.fromascii(tabname, conf_file, firstline=3, sep=' ', columnnames=['X', 'Y', 'Z', 'DIAM', 'NAME'], datatypes=['D', 'D', 'D', 'D', 'A']) xx = tb.getcol('X') yy = tb.getcol('Y') zz = tb.getcol('Z') diam = tb.getcol('DIAM')
def create_model(snu_ff, nu0, dust_ff_ratio, bandwidth=7.5, startfreq=35.0, offset_position=[0.0, 0.0], direction="J2000 10h00m00.0s -30d00m00.0s", modelname='skymodel_test'): ''' create an ms with a point source with the given spectrum. ''' from casatasks.private import simutil u = simutil.simutil() from casatools import quanta from casatools import componentlist from casatools import image from casatools import measures qa = quanta() cl = componentlist() me = measures() ia = image() obs_freq = np.linspace(startfreq, startfreq + bandwidth, 1000) ff_spect = calc_ff_spect(snu_ff, nu0, obs_freq) dust_spect = calc_dust_spect(snu_ff, nu0, dust_ff_ratio, obs_freq) comb_spect = ff_spect + dust_spect xx = u.direction_splitter(direction) qra = xx[1] qdec = xx[2] qra1 = qa.add(qra, str(offset_position[0]) + "arcsec") qdec1 = qa.add(qdec, str(offset_position[1]) + "arcsec") xx1 = xx[0] + " " + qa.formxxx(qra1, format='hms', prec=3) + " " + qa.formxxx( qdec1, format='dms', prec=4) cl.done() #close any open component list cl.addcomponent(flux=1.0, dir=xx1, shape='point') # tabularfreq in Hz # tabularflux in Jy obs_freq_Hz = obs_freq * 1e9 cl.setspectrum(which=0, type='tabular', tabularfreqs=obs_freq_Hz, tabularflux=comb_spect) filename = modelname + '.cl' if os.path.exists(filename): shutil.rmtree(filename) cl.rename(filename) # make a skymodel from the component list since simobserve # doesn't handle the component lists with frequency dependence. # Don't need header info. can set that in simobserve ia.done() filename = modelname + ".image" if os.path.exists(filename): shutil.rmtree(filename) ia.fromshape(filename, [300, 300, 1, len(obs_freq)], overwrite=True) cs = ia.coordsys() cs.setunits(['deg', 'deg', '', 'GHz']) cell_rad = qa.convert(qa.quantity("0.1arcsec"), "deg")['value'] cs.setincrement([-cell_rad, cell_rad], 'direction') cs.setreferencepixel(0, type='Spectral') cs.setreferencevalue(str(obs_freq[0]) + "GHz", 'Spectral') cs.setincrement("%.5fGHz" % np.diff(obs_freq)[0], 'spectral') tmp = cs.referencevalue(format='q') tmp['quantity']['*1'] = xx[1] tmp['quantity']['*2'] = xx[2] cs.setreferencevalue(value=tmp) ia.setcoordsys(cs.torecord()) ia.setbrightnessunit("Jy/pixel") ia.modify(cl.torecord(), subtract=False) ia.done() cl.done()
def makePB( vis="", field="", spw="", timerange="", uvrange="", antenna="", observation="", intent="", scan="", imtemplate="", outimage="", pblimit=0.2, stokes="", ): """ (modified from casarecipes.makepb to support multiple stokes) Make a PB image using the imager tool, onto a specified image coordinate system This function can be used along with tclean to make .pb images for gridders that do not already do it (i.e. other than mosaic, awproject) This script takes an image to use as a template coordinate system, attempts to set up an identical coordinate system with the old imager tool, makes a PB for the telescope listed in the MS observation subtable, and regrids it (just in case) to the target coordinate system). This can be used for single fields and mosaics. """ tb = casatools.table() im = casatools.imager() ia = casatools.image() me = casatools.measures() qa = casatools.quanta() print("MAKEPB : Making a PB image using the imager tool") tb.open(vis + "/OBSERVATION") tel = tb.getcol("TELESCOPE_NAME")[0] tb.close() tb.open(vis + "/SPECTRAL_WINDOW") mfreqref = tb.getcol("MEAS_FREQ_REF")[0] tb.close() if mfreqref == 64: print( "MAKEPB : This function is using old imager tool, Undefined frame may not be handled properly." ) print("MAKEPB : Making PB for ", tel) ia.open(imtemplate) csysa = ia.coordsys() csys = csysa.torecord() shp = ia.shape() ia.close() dirs = csys["direction0"] phasecenter = me.direction( dirs["system"], qa.quantity(dirs["crval"][0], dirs["units"][0]), qa.quantity(dirs["crval"][1], dirs["units"][1]), ) cellx = qa.quantity(fabs(dirs["cdelt"][0]), dirs["units"][0]) celly = qa.quantity(fabs(dirs["cdelt"][1]), dirs["units"][1]) nchan = shp[3] start = qa.quantity(csysa.referencevalue()["numeric"][3], csysa.units()[3]) # assumes refpix is zero mestart = me.frequency("LSRK", start) step = qa.quantity(csysa.increment()["numeric"][3], csysa.units()[3]) smode = "mfs" if nchan > 1: smode = "frequency" print("MAKEPB : Starting imager tool") im.open(vis) im.selectvis( field=field, spw=spw, time=timerange, intent=intent, scan=scan, uvrange=uvrange, baseline=antenna, observation=observation, ) im.defineimage( nx=shp[0], ny=shp[0], phasecenter=phasecenter, cellx=qa.tos(cellx), celly=qa.tos(celly), nchan=nchan, start=mestart, step=step, mode=smode, stokes=stokes, ) im.setvp(dovp=True, telescope=tel) im.makeimage(type="pb", image=outimage + ".tmp") im.close() if mfreqref == 64: # skip this step if the frame is 'Undefined' shutil.copytree(outimage + ".tmp", outimage) else: print("MAKEPB : Regrid to desired coordinate system") imregrid( imagename=outimage + ".tmp", template=imtemplate, output=outimage, overwrite=True, asvelocity=False, ) shutil.rmtree(outimage + ".tmp") print("MAKEPB : Set mask to pblimit") ia.open(outimage) ia.calcmask("'" + outimage + "'>" + str(pblimit)) ia.close()
def test_casa_masking(): with tempfile.TemporaryDirectory() as tmpdir: # SIMULATE SOME DATA SET # Define antennas diam = [25, 25, 25, 25, 25] xx = [50, 100, 150, 200, 250] yy = [2, -5, -20, -50, -100] zz = [-0.5, -1.0, -1.5, -2.0, -2.5] sm = simulator() sm.open(tmpdir + '/SIM.ms') # do configuration posvla = me.observatory('VLA') sm.setconfig(telescopename='VLA', x=xx, y=yy, z=zz, dishdiameter=diam, mount='alt-az', antname='VLA', coordsystem='local', referencelocation=posvla) # Initialize the spectral windows sm.setspwindow(spwname='CBand', freq='5GHz', deltafreq='50MHz', freqresolution='50MHz', nchannels=1, stokes='RR RL LR LL') # Initialize the source and calibrater sm.setfield(sourcename='My cal', sourcedirection=['J2000', '00h0m0.0', '+45.0.0.000'], calcode='A') sm.setfield(sourcename='My source', sourcedirection=['J2000', '01h0m0.0', '+47.0.0.000']) sm.setlimits(shadowlimit=0.001, elevationlimit='8.0deg') sm.setauto(autocorrwt=0.0) sm.settimes(integrationtime='10s', usehourangle=False, referencetime=me.epoch('utc', 'today')) sm.observe('My cal', 'CBand', starttime='720s', stoptime='1020s') sm.observe('My source', 'CBand', starttime='1030s', stoptime='1500s') sm.close() # Create mask to use during clean reg = EllipseSkyRegion(center=coordinates.SkyCoord(0.0 * u.deg, 45.0 * u.deg, frame='fk5'), width=1.0 * u.arcmin, height=2.0 * u.arcmin, angle=45 * u.deg) write_crtf([reg], tmpdir + '/SIM.crtf', 'fk5', '.6f', 'deg') # Image the dataset tclean(vis=tmpdir + '/SIM.ms', imagename=tmpdir + '/SIM', imsize=100, cell='5arcsec', niter=1, mask=tmpdir + '/SIM.crtf', interactive=False) ia = image() ia.open(tmpdir + '/SIM.mask') mask_array = ia.getregion() ia.close() with open('data/binary_mask.pkl', 'rb') as f: ref_mask = pickle.load(f) assert all(mask_array == ref_mask)
def load_casa_image(filename, skipdata=False, skipvalid=False, skipcs=False, **kwargs): """ Load a cube (into memory?) from a CASA image. By default it will transpose the cube into a 'python' order and drop degenerate axes. These options can be suppressed. The object holds the coordsys object from the image in memory. """ try: import casatools ia = casatools.image() except ImportError: try: from taskinit import iatool ia = iatool() except ImportError: raise ImportError("Could not import CASA (casac) and therefore cannot read CASA .image files") # use the ia tool to get the file contents ia.open(filename) # read in the data if not skipdata: # CASA data are apparently transposed. data = ia.getchunk().transpose() # CASA stores validity of data as a mask if not skipvalid: valid = ia.getchunk(getmask=True).transpose() # transpose is dealt with within the cube object # read in coordinate system object casa_cs = ia.coordsys() wcs = wcs_casa2astropy(casa_cs) unit = ia.brightnessunit() beam_ = ia.restoringbeam() if 'major' in beam_: beam = Beam(major=u.Quantity(beam_['major']['value'], unit=beam_['major']['unit']), minor=u.Quantity(beam_['minor']['value'], unit=beam_['minor']['unit']), pa=u.Quantity(beam_['positionangle']['value'], unit=beam_['positionangle']['unit']), ) elif 'beams' in beam_: bdict = beam_['beams'] if beam_['nStokes'] > 1: raise NotImplementedError() nbeams = len(bdict) assert nbeams == beam_['nChannels'] stokesidx = '*0' majors = [u.Quantity(bdict['*{0}'.format(ii)][stokesidx]['major']['value'], bdict['*{0}'.format(ii)][stokesidx]['major']['unit']) for ii in range(nbeams)] minors = [u.Quantity(bdict['*{0}'.format(ii)][stokesidx]['minor']['value'], bdict['*{0}'.format(ii)][stokesidx]['minor']['unit']) for ii in range(nbeams)] pas = [u.Quantity(bdict['*{0}'.format(ii)][stokesidx]['positionangle']['value'], bdict['*{0}'.format(ii)][stokesidx]['positionangle']['unit']) for ii in range(nbeams)] beams = Beams(major=u.Quantity(majors), minor=u.Quantity(minors), pa=u.Quantity(pas)) else: warnings.warn("No beam information found in CASA image.", BeamWarning) # don't need this yet # stokes = get_casa_axis(temp_cs, wanttype="Stokes", skipdeg=False,) # if stokes == None: # order = np.arange(self.data.ndim) # else: # order = [] # for ax in np.arange(self.data.ndim+1): # if ax == stokes: # continue # order.append(ax) # self.casa_cs = ia.coordsys(order) # This should work, but coordsys.reorder() has a bug # on the error checking. JIRA filed. Until then the # axes will be reversed from the original. # if transpose == True: # new_order = np.arange(self.data.ndim) # new_order = new_order[-1*np.arange(self.data.ndim)-1] # print new_order # self.casa_cs.reorder(new_order) # close the ia tool ia.close() meta = {'filename': filename, 'BUNIT': unit} if wcs.naxis == 3: mask = BooleanArrayMask(np.logical_not(valid), wcs) if 'beam' in locals(): cube = SpectralCube(data, wcs, mask, meta=meta, beam=beam) elif 'beams' in locals(): cube = VaryingResolutionSpectralCube(data, wcs, mask, meta=meta, beams=beams) else: cube = SpectralCube(data, wcs, mask, meta=meta) # we've already loaded the cube into memory because of CASA # limitations, so there's no reason to disallow operations cube.allow_huge_operations = True elif wcs.naxis == 4: data, wcs = cube_utils._split_stokes(data, wcs) mask = {} for component in data: data_, wcs_slice = cube_utils._orient(data[component], wcs) mask[component] = LazyMask(np.isfinite, data=data[component], wcs=wcs_slice) if 'beam' in locals(): data[component] = SpectralCube(data_, wcs_slice, mask[component], meta=meta, beam=beam) elif 'beams' in locals(): data[component] = VaryingResolutionSpectralCube(data_, wcs_slice, mask[component], meta=meta, beams=beams) else: data[component] = SpectralCube(data_, wcs_slice, mask[component], meta=meta) data[component].allow_huge_operations = True cube = StokesSpectralCube(stokes_data=data) return cube
def make_casa_mask(SpecCube, outname, append_to_image=True, img=None, add_stokes=True, stokes_posn=None, overwrite=False): ''' Outputs the mask attached to the SpectralCube object as a CASA image, or optionally appends the mask to a preexisting CASA image. Parameters ---------- SpecCube : SpectralCube SpectralCube object containing mask. outname : str Name of the outputted mask file. append_to_image : bool, optional Appends the mask to a given image. img : str, optional Image to be appended to. Must be specified if append_to_image is enabled. add_stokes: bool, optional Adds a Stokes axis onto the wcs from SpecCube. stokes_posn : int, optional Sets the position of the new Stokes axis. Defaults to the last axis. overwrite : bool, optional Overwrite the image and mask files if they exist? ''' try: from casatools import image ia = image() except ImportError: try: from taskinit import ia except ImportError: raise ImportError( "Cannot import casa. Must be run in a CASA environment.") # the 'mask name' is distinct from the mask _path_ maskname = os.path.split(outname)[1] maskpath = outname # Get the header info from the image # There's not wcs_astropy2casa (yet), so create a temporary file for # CASA to open. temp = tempfile.NamedTemporaryFile() # CASA is closing this file at some point so set it to manual delete. temp2 = tempfile.NamedTemporaryFile(delete=False) # Grab wcs # Optionally re-add on the Stokes axis if add_stokes: my_wcs = SpecCube.wcs if stokes_posn is None: stokes_posn = my_wcs.wcs.naxis new_wcs = add_stokes_axis_to_wcs(my_wcs, stokes_posn) header = new_wcs.to_header() # Transpose the shape so we're adding the axis at the place CASA will # recognize. Then transpose back. shape = SpecCube.shape[::-1] shape = shape[:stokes_posn] + (1, ) + shape[stokes_posn:] shape = shape[::-1] else: # Just grab the header from SpecCube header = SpecCube.header shape = SpecCube.shape hdu = fits.PrimaryHDU(header=header, data=np.empty(shape, dtype='int16')) hdu.writeto(temp.name) ia.fromfits(infile=temp.name, outfile=temp2.name, overwrite=overwrite) temp.close() cs = ia.coordsys() ia.close() temp2.close() mask_arr = SpecCube.mask.include() # Reshape mask with possible Stokes axis mask_arr = mask_arr.reshape(shape) # Transpose to match CASA axes mask_arr = mask_arr.T ia.newimagefromarray(outfile=maskpath, pixels=mask_arr.astype('int16'), overwrite=overwrite) ia.close() ia.open(maskpath) ia.setcoordsys(cs.torecord()) ia.close() if append_to_image: if img is None: raise TypeError( "img argument must be specified to append the mask.") ia.open(maskpath) ia.calcmask(maskname + ">0.5") ia.close() ia.open(img) ia.maskhandler('copy', [maskpath + ":mask0", maskname]) ia.maskhandler('set', maskname) ia.close()
import pylab as pl import os import time import numpy as np from astropy.io import fits from astropy import units as u from astropy.stats import mad_std import pylab as pl import radio_beam import glob from spectral_cube import SpectralCube, DaskSpectralCube from spectral_cube.lower_dimensional_structures import Projection from casatools import image ia = image() if os.getenv('NO_PROGRESSBAR') is None: from dask.diagnostics import ProgressBar pbar = ProgressBar() pbar.register() nthreads = 1 scheduler = 'synchronous' os.environ['TEMPDIR'] = '/blue/adamginsburg/adamginsburg/tmp/' if os.getenv('DASK_THREADS') is not None: try: nthreads = int(os.getenv('DASK_THREADS')) if nthreads > 1:
def fitimage(image, outname='tmp.', xmin=None, xmax=None, ymin=None, ymax=None, displaywindow=300, fitwindow=100, returnimfit=False, estimates=''): """ CASA imfit on the image. Reports peak RA, DEC and errors. """ # load image ia = tools.image() ia.open(image) # summarize image dd = ia.summary() npixx, npixy, nch, npol = dd['shape'] if xmin is None: xmin = 0 if xmax is None: xmax = npixx if ymin is None: ymin = 0 if ymax is None: ymax = npixy print('Image shape: {0}'.format(dd['shape'])) imvals = ia.getchunk(0, int(npixx))[xmin:xmax, ymin:ymax, 0, 0] peakx, peaky = np.where(imvals.max() == imvals) print('Peak SNR at ({0},{1}) = {2}'.format(peakx[0], peaky[0], imvals.max() / imvals.std())) # print('Beam shape: {0}'.format(ia.history()[1].split('\n')[10].split(':')[5])) # fit component and write residual image box = '{0},{1},{2},{3}'.format(xmin + peakx[0] - fitwindow // 2, ymin + peaky[0] - fitwindow // 2, xmin + peakx[0] + fitwindow // 2, ymin + peaky[0] + fitwindow // 2) imfit = ia.fitcomponents(box=box, residual=outname + 'fitresid', estimates=estimates) # report on fit if imfit['converged']: print('{0} element(s) fit'.format(imfit['results']['nelements'])) direction = imfit['results']['component0']['shape']['direction'] az = direction['m0']['value'] el = direction['m1']['value'] az_err = direction['error']['longitude']['value'] el_err = direction['error']['latitude']['value'] print(direction) co0 = coordinates.SkyCoord(ra=np.degrees(az), dec=np.degrees(el), unit=(units.deg, units.deg)) # peak_ra = qa.unit(qa.angle(qa.quantity(az, unitname='rad'), prec=13)[0], unitname='deg')['value'] # peak_dec = qa.unit(qa.angle(qa.quantity(el, unitname='rad'), prec=13)[0], unitname='deg')['value'] print('{0} +- {1}"'.format(co0.ra.degree, az_err)) print('{0} +- {1}"'.format(co0.dec.degree, el_err)) print('Fitpeak flux: {0} Jy'.format( imfit['results']['component0']['peak']['value'])) print(co0.to_string('hmsdms')) else: print('fitcomponents did not converge') # load residuals ia = tools.image() ia.open(outname + 'fitresid') dd = ia.summary() npixy, npixx, nch, npol = dd['shape'] residvals = ia.getchunk(0, int(npixx))[xmin:xmax, ymin:ymax, 0, 0] peakx_resid, peaky_resid = np.where(residvals.max() == residvals) print('Residual SNR at ({0},{1}) = {2}'.format( peakx_resid[0], peaky_resid[0], residvals.max() / residvals.std())) # show results plt.figure(figsize=(25, 15)) plt.subplot(131) plt.imshow(imvals.transpose() - imvals.min(), interpolation='nearest', origin='bottom') plt.colorbar() plt.subplot(132) plt.imshow( imvals[peakx[0] - displaywindow // 2:peakx[0] + displaywindow // 2, peaky[0] - displaywindow // 2:peaky[0] + displaywindow // 2].transpose(), interpolation='nearest', origin='bottom') plt.colorbar() plt.subplot(133) plt.imshow( residvals[peakx[0] - displaywindow // 2:peakx[0] + displaywindow // 2, peaky[0] - displaywindow // 2:peaky[0] + displaywindow // 2].transpose(), interpolation='nearest', origin='bottom') plt.colorbar() if returnimfit: return imfit else: return az, el, az_err, el_err
prefix = '/lustre/cv/users/rloomis/research_tickets/mod_pcwd/' filenames = [ prefix + 'r-2_c0.02_pcwdT.psf', prefix + 'r0_c0.02_pcwdT.psf', prefix + 'r0.5_c0.02_pcwdT.psf', prefix + 'r1_c0.02_pcwdT.psf', prefix + 'r2_c0.02_pcwdT.psf', prefix + 'r-2_c0.02_pcwdMOD.psf', prefix + 'r0_c0.02_pcwdMOD.psf', prefix + 'r0.5_c0.02_pcwdMOD.psf', prefix + 'r1_c0.02_pcwdMOD.psf', prefix + 'r2_c0.02_pcwdMOD.psf', prefix + 'r-2_c0.02_pcwdF.psf', prefix + 'r0_c0.02_pcwdF.psf', prefix + 'r0.5_c0.02_pcwdF.psf', prefix + 'r1_c0.02_pcwdF.psf', prefix + 'r2_c0.02_pcwdF.psf' ] #filenames=[prefix + 'r2_c0.02_pcwdF.psf'] ia = casatools.image() npix_window = 31 # ellipse fitting code from: nicky.vanforeest.com/misc/fitEllipse/fitEllipse.html # moded a number of typos from original source def fitEllipse(x, y): x = x[:, np.newaxis] y = y[:, np.newaxis] D = np.hstack((x * x, x * y, y * y, x, y, np.ones_like(x))) S = np.dot(D.T, D) C = np.zeros([6, 6]) C[0, 2] = C[2, 0] = 2 C[1, 1] = -1 E, V = linalg.eig(np.dot(linalg.inv(S), C)) n = np.argmax(E)
import pytest import numpy as np from numpy.testing import assert_allclose import os from astropy import units as u from ..io.casa_masks import make_casa_mask from ..io.casa_image import wcs_casa2astropy from .. import SpectralCube, BooleanArrayMask, VaryingResolutionSpectralCube from . import path try: import casatools ia = casatools.image() casaOK = True except ImportError: try: from taskinit import ia casaOK = True except ImportError: print("Run in CASA environment.") casaOK = False def make_casa_testimage(infile, outname): if not casaOK: raise Exception("Attempted to make a CASA test image in a non-CASA " "environment")
def test_casa_image_dask_reader(tmpdir, memmap, shape): # Unit tests for the low-level casa_image_dask_reader function which can # read a CASA image or mask to a Dask array. reference = np.random.random(shape).astype(np.float32) # CASA seems to have precision issues when computing masks with values # very close to e.g. 0.5 in >0.5. To avoid this, we filter out random # values close to the boundaries that we use below. reference[np.isclose(reference, 0.2)] += 0.05 reference[np.isclose(reference, 0.5)] += 0.05 reference[np.isclose(reference, 0.8)] += 0.05 os.chdir(tmpdir.strpath) # Start off with a simple example with no mask. Note that CASA requires # the array to be transposed in order to match what we would expect. ia = image() ia.fromarray('basic.image', pixels=reference.T, log=False) ia.close() array1 = casa_image_dask_reader('basic.image', memmap=memmap) assert array1.dtype == np.float32 assert_allclose(array1, reference) # Check slicing assert_allclose(array1[:2, :1, :3], reference[:2, :1, :3]) # Try and get a mask - this should fail since there isn't one. with pytest.raises(FileNotFoundError): casa_image_dask_reader('basic.image', mask=True, memmap=memmap) # Now create an array with a simple uniform mask. ia = image() ia.fromarray('scalar_mask.image', pixels=reference.T, log=False) ia.calcmask(mask='T') ia.close() array2 = casa_image_dask_reader('scalar_mask.image', memmap=memmap) assert_allclose(array2, reference) mask2 = casa_image_dask_reader('scalar_mask.image', mask=True, memmap=memmap) assert mask2.dtype is np.dtype('bool') assert mask2.shape == array2.shape assert np.all(mask2) # Check with a full 3-d mask ia = image() ia.fromarray('array_mask.image', pixels=reference.T, log=False) ia.calcmask(mask='array_mask.image>0.5') ia.close() array3 = casa_image_dask_reader('array_mask.image', memmap=memmap) assert_allclose(array3, reference) mask3 = casa_image_dask_reader('array_mask.image', mask=True, memmap=memmap) assert_allclose(mask3, reference > 0.5) # Check slicing assert_allclose(mask3[:2, :1, :3], (reference > 0.5)[:2, :1, :3]) # Test specifying the mask name ia = image() ia.fromarray('array_masks.image', pixels=reference.T, log=False) ia.calcmask(mask='array_masks.image>0.5') ia.calcmask(mask='array_masks.image>0.2') ia.calcmask(mask='array_masks.image>0.8', name='gt08') ia.close() array4 = casa_image_dask_reader('array_masks.image', memmap=memmap) assert_allclose(array4, reference) mask4 = casa_image_dask_reader('array_masks.image', mask=True, memmap=memmap) assert_allclose(mask4, reference > 0.5) mask5 = casa_image_dask_reader('array_masks.image', mask='mask0', memmap=memmap) assert_allclose(mask5, reference > 0.5) mask6 = casa_image_dask_reader('array_masks.image', mask='mask1', memmap=memmap) assert_allclose(mask6, reference > 0.2) mask7 = casa_image_dask_reader('array_masks.image', mask='gt08', memmap=memmap) assert_allclose(mask7, reference > 0.8) # Check that things still work if we write the array out with doubles reference = np.random.random(shape).astype(np.float64) ia = image() ia.fromarray('double.image', pixels=reference.T, type='d', log=False) ia.close() array8 = casa_image_dask_reader('double.image', memmap=memmap) assert array8.dtype == np.float64 assert_allclose(array8, reference)
def make_casa_mask(SpecCube, outname, append_to_image=True, img=None, add_stokes=True, stokes_posn=None, overwrite=False ): ''' Outputs the mask attached to the SpectralCube object as a CASA image, or optionally appends the mask to a preexisting CASA image. Parameters ---------- SpecCube : SpectralCube SpectralCube object containing mask. outname : str Name of the outputted mask file. append_to_image : bool, optional Appends the mask to a given image. img : str, optional Image to be appended to. Must be specified if append_to_image is enabled. add_stokes: bool, optional Adds a Stokes axis onto the wcs from SpecCube. stokes_posn : int, optional Sets the position of the new Stokes axis. Defaults to the last axis. overwrite : bool, optional Overwrite the image and mask files if they exist? ''' try: from casatools import image ia = image() except ImportError: try: from taskinit import ia except ImportError: raise ImportError("Cannot import casa. Must be run in a CASA environment.") # the 'mask name' is distinct from the mask _path_ maskname = os.path.split(outname)[1] maskpath = outname # Get the header info from the image # There's not wcs_astropy2casa (yet), so create a temporary file for # CASA to open. temp = tempfile.NamedTemporaryFile() # CASA is closing this file at some point so set it to manual delete. temp2 = tempfile.NamedTemporaryFile(delete=False) # Grab wcs # Optionally re-add on the Stokes axis if add_stokes: my_wcs = SpecCube.wcs if stokes_posn is None: stokes_posn = my_wcs.wcs.naxis new_wcs = add_stokes_axis_to_wcs(my_wcs, stokes_posn) header = new_wcs.to_header() # Transpose the shape so we're adding the axis at the place CASA will # recognize. Then transpose back. shape = SpecCube.shape[::-1] shape = shape[:stokes_posn] + (1,) + shape[stokes_posn:] shape = shape[::-1] else: # Just grab the header from SpecCube header = SpecCube.header shape = SpecCube.shape hdu = fits.PrimaryHDU(header=header, data=np.empty(shape, dtype='int16')) hdu.writeto(temp.name) ia.fromfits(infile=temp.name, outfile=temp2.name, overwrite=overwrite) temp.close() cs = ia.coordsys() ia.close() temp2.close() mask_arr = SpecCube.mask.include() # Reshape mask with possible Stokes axis mask_arr = mask_arr.reshape(shape) # Transpose to match CASA axes mask_arr = mask_arr.T ia.newimagefromarray(outfile=maskpath, pixels=mask_arr.astype('int16'), overwrite=overwrite) ia.close() ia.open(maskpath) ia.setcoordsys(cs.torecord()) ia.close() if append_to_image: if img is None: raise TypeError("img argument must be specified to append the mask.") ia.open(maskpath) ia.calcmask(maskname+">0.5") ia.close() ia.open(img) ia.maskhandler('copy', [maskpath+":mask0", maskname]) ia.maskhandler('set', maskname) ia.close()