def mask_out_signal(self, niter=1): """ Sets the mask property of the SpectralCube associated with the noise object to exclude the noise through a (iterative) application of the Chauvenet rejection criterion (i.e., mask out all points outside of +/- N sigma of zero). Parameters ---------- niter : number Number of iterations used in estimating the separate components of the spatial and spectral noise variations. Default=1 """ # This needs reworking but is close. for count in range(niter): if self.spatial_norm is not None: noise = self.scale_cube snr = self.cube.filled_data[:].value / noise else: snr = self.cube.filled_data[:].value / self.scale # Include negatives in the signal mask or not? newmask = BooleanArrayMask( np.abs(snr) < sig_n_outliers(self.cube.size), self.cube.wcs) self.cube = self.cube.with_mask(newmask)
def test_spectralnorm(): cube = SpectralCube(data, wcs.WCS(h), mask=BooleanArrayMask(mask, wcs=wcs.WCS(h))) noiseobj = noise.Noise(cube) noiseobj.estimate_noise() expected = np.array([ 1.14898322, 0.71345272, 1.21989125]) assert np.allclose(noiseobj.spectral_norm, expected)
def to_object(self, data_or_subset, attribute=None): """ Convert a glue Data object to a SpectralCube object. Parameters ---------- data_or_subset : `glue.core.data.Data` or `glue.core.subset.Subset` The data to convert to a SpectralCube object attribute : `glue.core.component_id.ComponentID` The attribute to use for the SpectralCube data """ if data_or_subset.ndim > 0 and data_or_subset.ndim != 3: raise ValueError( 'Data object should have 3 dimensions in order to ' 'be converted to a SpectralCube object.') if isinstance(data_or_subset, Subset): data = data_or_subset.data subset_state = data_or_subset.subset_state else: data = data_or_subset subset_state = None if isinstance(data.coords, BaseLowLevelWCS): wcs = data.coords else: raise TypeError( 'data.coords should be an instance of BaseLowLevelWCS.') if isinstance(attribute, str): attribute = data.id[attribute] elif len(data.main_components) == 0: raise ValueError('Data object has no attributes.') elif attribute is None: if len(data.main_components) == 1: attribute = data.main_components[0] else: raise ValueError( "Data object has more than one attribute, so " "you will need to specify which one to use as " "the flux for the spectral cube using the " "attribute= keyword argument.") component = data.get_component(attribute) values = data.get_data(attribute) if subset_state is None: mask = None else: mask = data.get_mask(subset_state=subset_state) values = values.copy() values[~mask] = np.nan mask = BooleanArrayMask(mask, wcs=wcs) values = values * u.Unit(component.units) return SpectralCube(values, mask=mask, wcs=wcs)
def data_to_cube(self): """Glue Data -> SpectralCube""" if self.component_id is None: raise Exception("component_id was not provided.") wcs = self.get_glue_wcs() data_array = self.data[self.component_id] mask = BooleanArrayMask(mask=self.get_glue_mask(), wcs=wcs) return SpectralCube(data=data_array, wcs=wcs, mask=mask)
def test_spatialnorm(): cube = SpectralCube(data, wcs.WCS(h), mask=BooleanArrayMask(mask, wcs=wcs.WCS(h))) noiseobj = noise.Noise(cube) noiseobj.estimate_noise() print noiseobj.spatial_norm expected = np.array([[ 0.04430196, 0.78314449, 0.07475047, 0.5494684 , 0.05790756], [ 0.32931213, 0.76450342, 1.33944507, 1.06416389, 0.27999452], [ 0.65174339, 0.24128143, 0.27692018, 0.0244925 , 0.11167775], [ 0.60682872, 0.42536813, 0.20018275, 0.78523107, 0.95516435]]) assert np.allclose(noiseobj.spatial_norm, expected)
def smooth_mask(mask, wcs, diam): mask_np = np.asarray( mask.include() * 1 ) structure = np.ones((diam, diam, diam)) dist = ((np.indices((diam, diam)) - (diam - 1) / 2.)**2).sum(axis=0)**0.5 structure[dist > diam / 2.] = 0 mask_dilation = ndimage.binary_dilation(mask_np, structure=structure) mask_erosion = ndimage.binary_erosion(mask_np, structure=structure) mask_dilation_speccube = BooleanArrayMask(mask=mask_erosion, wcs=wcs) return mask_dilation_speccube
def data_to_cube(self, to_qcube=False): """ smooth_cube: Glue Data -> SpectralCube multi_threading_smooth: Glue Data -> QSpectralCube """ if self.component_id is None: raise Exception("component_id was not provided.") wcs = self.get_glue_wcs() data_array = self.data[self.component_id] mask = BooleanArrayMask(mask=self.get_glue_mask(), wcs=wcs) if to_qcube: return QSpectralCube(data=data_array, wcs=wcs, mask=mask) else: return SpectralCube(data=data_array, wcs=wcs, mask=mask)
def _compose_cube(self): """ Create a :class:`~spectral_cube.SpectralCube` from a Glue data component. """ if issubclass(self.data.__class__, Subset): wcs = self.data.data.coords.wcs data = self.data.data mask = self.data.to_mask() else: wcs = self.data.coords.wcs data = self.data mask = np.ones(data.shape).astype(bool) mask = BooleanArrayMask(mask=mask, wcs=wcs) return SpectralCube(data[self.component_id], wcs=wcs, mask=mask)
def measure_dendrogram_properties(dend=None, cube303=cube303, cube321=cube321, cube13co=cube13co, cube18co=cube18co, noise_cube=noise_cube, sncube=sncube, suffix="", last_index=None, plot_some=True, line='303', write=True): assert (cube321.shape == cube303.shape == noise_cube.shape == cube13co.shape == cube18co.shape == sncube.shape) assert sncube.wcs is cube303.wcs is sncube.mask._wcs metadata = {} metadata['data_unit'] = u.K metadata['spatial_scale'] = 7.2 * u.arcsec metadata['beam_major'] = 30 * u.arcsec metadata['beam_minor'] = 30 * u.arcsec metadata['wavelength'] = 218.22219*u.GHz metadata['velocity_scale'] = u.km/u.s metadata['wcs'] = cube303.wcs keys = [ 'density_chi2', 'expected_density', 'dmin1sig_chi2', 'dmax1sig_chi2', 'column_chi2', 'expected_column', 'cmin1sig_chi2', 'cmax1sig_chi2', 'temperature_chi2', 'expected_temperature', 'tmin1sig_chi2', 'tmax1sig_chi2', 'eratio321303', 'ratio321303', 'logh2column', 'elogh2column', 'logabundance', 'elogabundance', ] obs_keys = [ 'Stot303', 'Smin303', 'Smax303', 'Stot321', 'Smean303', 'Smean321', 'npix', 'e303', 'e321', 'r321303', 'er321303', '13cosum', 'c18osum', '13comean', 'c18omean', 's_ntotal', 'index', 'is_leaf', 'parent', 'root', 'lon', 'lat', 'vcen', 'higaldusttem', 'reff', 'dustmass', 'dustmindens', 'bad', #'tkin_turb', ] columns = {k:[] for k in (keys+obs_keys)} log.debug("Initializing dendrogram temperature fitting loop") # FORCE wcs to match # (technically should reproject here) cube13co._wcs = cube18co._wcs = cube303.wcs cube13co.mask._wcs = cube18co.mask._wcs = cube303.wcs if line == '303': maincube = cube303 elif line == '321': maincube = cube321 else: raise ValueError("Unrecognized line: {0}".format(line)) # Prepare an array to hold the fitted temperatures tcubedata = np.empty(maincube.shape, dtype='float32') tcubedata[:] = np.nan tcubeleafdata = np.empty(maincube.shape, dtype='float32') tcubeleafdata[:] = np.nan nbad = 0 catalog = ppv_catalog(dend, metadata) pb = ProgressBar(len(catalog)) for ii,row in enumerate(catalog): structure = dend[row['_idx']] assert structure.idx == row['_idx'] == ii dend_obj_mask = BooleanArrayMask(structure.get_mask(), wcs=cube303.wcs) dend_inds = structure.indices() view = (slice(dend_inds[0].min(), dend_inds[0].max()+1), slice(dend_inds[1].min(), dend_inds[1].max()+1), slice(dend_inds[2].min(), dend_inds[2].max()+1),) #view2 = cube303.subcube_slices_from_mask(dend_obj_mask) submask = dend_obj_mask[view] #assert np.count_nonzero(submask.include()) == np.count_nonzero(dend_obj_mask.include()) sn = sncube[view].with_mask(submask) sntot = sn.sum().value #np.testing.assert_almost_equal(sntot, structure.values().sum(), decimal=0) c303 = cube303[view].with_mask(submask) c321 = cube321[view].with_mask(submask) co13sum = cube13co[view].with_mask(submask).sum().value co18sum = cube18co[view].with_mask(submask).sum().value if hasattr(co13sum,'__len__'): raise TypeError(".sum() applied to an array has yielded a non scalar.") npix = submask.include().sum() assert npix == structure.get_npix() Stot303 = c303.sum().value if np.isnan(Stot303): raise ValueError("NaN in cube. This can't happen: the data from " "which the dendrogram was derived can't have " "NaN pixels.") Smax303 = c303.max().value Smin303 = c303.min().value Stot321 = c321.sum().value if npix == 0: raise ValueError("npix=0. This is impossible.") Smean303 = Stot303/npix if Stot303 <= 0 and line=='303': raise ValueError("The 303 flux is <=0. This isn't possible because " "the dendrogram was derived from the 303 data with a " "non-zero threshold.") elif Stot303 <= 0 and line=='321': Stot303 = 0 Smean303 = 0 elif Stot321 <= 0 and line=='321': raise ValueError("The 321 flux is <=0. This isn't possible because " "the dendrogram was derived from the 321 data with a " "non-zero threshold.") if np.isnan(Stot321): raise ValueError("NaN in 321 line") Smean321 = Stot321/npix #error = (noise_cube[view][submask.include()]).sum() / submask.include().sum()**0.5 var = ((noise_cube[dend_obj_mask.include()]**2).sum() / npix**2) error = var**0.5 if np.isnan(error): raise ValueError("error is nan: this is impossible by definition.") if line == '321' and Stot303 == 0: r321303 = np.nan er321303 = np.nan elif Stot321 < 0: r321303 = error / Smean303 er321303 = (r321303**2 * (var/Smean303**2 + 1))**0.5 else: r321303 = Stot321 / Stot303 er321303 = (r321303**2 * (var/Smean303**2 + var/Smean321**2))**0.5 for c in columns: assert len(columns[c]) == ii columns['index'].append(row['_idx']) columns['s_ntotal'].append(sntot) columns['Stot303'].append(Stot303) columns['Smax303'].append(Smax303) columns['Smin303'].append(Smin303) columns['Stot321'].append(Stot321) columns['Smean303'].append(Smean303) columns['Smean321'].append(Smean321) columns['npix'].append(npix) columns['e303'].append(error) columns['e321'].append(error) columns['r321303'].append(r321303) columns['er321303'].append(er321303) columns['13cosum'].append(co13sum) columns['c18osum'].append(co18sum) columns['13comean'].append(co13sum/npix) columns['c18omean'].append(co18sum/npix) columns['is_leaf'].append(structure.is_leaf) columns['parent'].append(structure.parent.idx if structure.parent else -1) columns['root'].append(get_root(structure).idx) s_main = maincube._data[dend_inds] x,y,z = maincube.world[dend_inds] lon = ((z.value-(360*(z.value>180)))*s_main).sum()/s_main.sum() lat = (y*s_main).sum()/s_main.sum() vel = (x*s_main).sum()/s_main.sum() columns['lon'].append(lon) columns['lat'].append(lat.value) columns['vcen'].append(vel.value) mask2d = dend_obj_mask.include().max(axis=0)[view[1:]] logh2column = np.log10(np.nanmean(column_regridded.data[view[1:]][mask2d]) * 1e22) if np.isnan(logh2column): log.info("Source #{0} has NaNs".format(ii)) logh2column = 24 elogh2column = elogabundance columns['higaldusttem'].append(np.nanmean(dusttem_regridded.data[view[1:]][mask2d])) r_arcsec = row['radius']*u.arcsec reff = (r_arcsec*(8.5*u.kpc)).to(u.pc, u.dimensionless_angles()) mass = ((10**logh2column*u.cm**-2)*np.pi*reff**2*2.8*constants.m_p).to(u.M_sun) density = (mass/(4/3.*np.pi*reff**3)/constants.m_p/2.8).to(u.cm**-3) columns['reff'].append(reff.value) columns['dustmass'].append(mass.value) columns['dustmindens'].append(density.value) mindens = np.log10(density.value) if mindens < 3: mindens = 3 if (r321303 < 0 or np.isnan(r321303)) and line != '321': raise ValueError("Ratio <0: This can't happen any more because " "if either num/denom is <0, an exception is " "raised earlier") #for k in columns: # if k not in obs_keys: # columns[k].append(np.nan) elif (r321303 < 0 or np.isnan(r321303)) and line == '321': for k in keys: columns[k].append(np.nan) else: # Replace negatives for fitting if Smean321 <= 0: Smean321 = error mf.set_constraints(ratio321303=r321303, eratio321303=er321303, #ratio321322=ratio2, eratio321322=eratio2, logh2column=logh2column, elogh2column=elogh2column, logabundance=logabundance, elogabundance=elogabundance, taline303=Smean303, etaline303=error, taline321=Smean321, etaline321=error, mindens=mindens, linewidth=10) row_data = mf.get_parconstraints() row_data['ratio321303'] = r321303 row_data['eratio321303'] = er321303 for k in row_data: columns[k].append(row_data[k]) # Exclude bad velocities from cubes if row['v_cen'] < -80e3 or row['v_cen'] > 180e3: # Skip: there is no real structure down here nbad += 1 is_bad = True else: is_bad = False tcubedata[dend_obj_mask.include()] = row_data['expected_temperature'] if structure.is_leaf: tcubeleafdata[dend_obj_mask.include()] = row_data['expected_temperature'] columns['bad'].append(is_bad) width = row['v_rms']*u.km/u.s lengthscale = reff #REMOVED in favor of despotic version done in dendrograms.py # we use the analytic version here; the despotic version is # computed elsewhere (with appropriate gcor factors) #columns['tkin_turb'].append(heating.tkin_all(10**row_data['density_chi2']*u.cm**-3, # width, # lengthscale, # width/lengthscale, # columns['higaldusttem'][-1]*u.K, # crir=0./u.s)) if len(set(len(c) for k,c in columns.items())) != 1: print("Columns are different lengths. This is not allowed.") import ipdb; ipdb.set_trace() for c in columns: assert len(columns[c]) == ii+1 if plot_some and not is_bad and (ii-nbad % 100 == 0 or ii-nbad < 50): try: log.info("T: [{tmin1sig_chi2:7.2f},{expected_temperature:7.2f},{tmax1sig_chi2:7.2f}]" " R={ratio321303:8.4f}+/-{eratio321303:8.4f}" " Smean303={Smean303:8.4f} +/- {e303:8.4f}" " Stot303={Stot303:8.2e} npix={npix:6d}" .format(Smean303=Smean303, Stot303=Stot303, npix=npix, e303=error, **row_data)) pl.figure(1) pl.clf() mf.denstemplot() pl.savefig(fpath("dendrotem/diagnostics/{0}_{1}.png".format(suffix,ii))) pl.figure(2).clf() mf.parplot1d_all(levels=[0.68268949213708585]) pl.savefig(fpath("dendrotem/diagnostics/1dplot{0}_{1}.png".format(suffix,ii))) pl.draw() pl.show() except Exception as ex: print ex pass else: pb.update(ii+1) if last_index is not None and ii >= last_index: break if last_index is not None: catalog = catalog[:last_index+1] for k in columns: if k not in catalog.keys(): catalog.add_column(table.Column(name=k, data=columns[k])) for mid,lo,hi,letter in (('expected_temperature','tmin1sig_chi2','tmax1sig_chi2','t'), ('expected_density','dmin1sig_chi2','dmax1sig_chi2','d'), ('expected_column','cmin1sig_chi2','cmax1sig_chi2','c')): catalog.add_column(table.Column(name='elo_'+letter, data=catalog[mid]-catalog[lo])) catalog.add_column(table.Column(name='ehi_'+letter, data=catalog[hi]-catalog[mid])) if write: catalog.write(tpath('PPV_H2CO_Temperature{0}.ipac'.format(suffix)), format='ascii.ipac') # Note that there are overlaps in the catalog, which means that ORDER MATTERS # in the above loop. I haven't yet checked whether large scale overwrites # small or vice-versa; it may be that both views of the data are interesting. tcube = SpectralCube(data=tcubedata, wcs=cube303.wcs, mask=cube303.mask, meta={'unit':'K'}, header=cube303.header, ) tcubeleaf = SpectralCube(data=tcubeleafdata, wcs=cube303.wcs, mask=cube303.mask, meta={'unit':'K'}, header=cube303.header, ) if write: log.info("Writing TemperatureCube") outpath = 'TemperatureCube_DendrogramObjects{0}.fits' tcube.write(hpath(outpath.format(suffix)), overwrite=True) outpath_leaf = 'TemperatureCube_DendrogramObjects{0}_leaves.fits' tcubeleaf.write(hpath(outpath_leaf.format(suffix)), overwrite=True) return catalog, tcube
cube = SpectralCube.read(hpath(ftemplate.format(smooth))) if weight: wcube = (SpectralCube.read( hpath('APEX_H2CO_303_202_smooth_bl.fits')) if 'smooth' in smooth else SpectralCube.read( hpath('APEX_H2CO_303_202_bl.fits'))) mcube = (SpectralCube.read( hpath('APEX_H2CO_303_202_smooth_bl_mask.fits')) if 'smooth' in smooth else SpectralCube.read( hpath('APEX_H2CO_303_202_bl_mask.fits'))) if cube.shape != wcube.shape: log.info("Not weighting {0}".format(fn)) continue weighted = copy.copy(cube) weighted._data = wcube._data * cube._data mask = (wcube.mask & cube.mask & BooleanArrayMask( mcube._data == 1, mcube.wcs)) weighted = weighted.with_mask(mask) wcube = wcube.with_mask(mask) pv1 = weighted.sum(axis=1) pv2 = wcube.sum(axis=1) pv = pv1 / pv2 # Hack to prevent unmatched celestial axis error pv1.wcs.wcs.ctype[0] = 'OFFSET' pv2.wcs.wcs.ctype[0] = 'OFFSET' hdu = copy.copy(pv1.hdu) hdu.data = pv.value else: tproj = cube.mean(axis=1) tproj.wcs.wcs.ctype[0] = 'OFFSET' hdu = tproj.hdu
width = 7 * u.MHz print(f'Per-pixel mask width: {width}') #shellcube=sc(data=shell,wcs=wcs).with_spectral_axis('Hz') print('Begin masking procedure') for y in range(spatdims[0]): print(f'Start Row {y}') for x in range(spatdims[1]): dopplershift = mom1[y, x] #print(f'dopplershift from reference: {dopplershift}') v_shifted = v0 + dopplershift z_shifted = v_shifted / c freq_shifted = restfreq / (1 + z_shifted) #print(f'shifted frequency: {freq_shifted}') tempmask = np.logical_and(spectraxis < (freq_shifted + width), spectraxis > (freq_shifted - width)) shell[:, y, x] = tempmask shellmaskcube = BooleanArrayMask(mask=shell, wcs=wcs) maskedcube = datacube.with_mask(shellmaskcube) print('Saving') datacube.write('unmaskedspw08-7slab.fits', overwrite=True) maskedcube.write(f'{width.value}mhzmasked_spw08-7slab.fits', overwrite=True) shellmaskcube.write(f'{width.value}mhz8-7mask.fits', overwrite=True) print('Done.') #maskedcube.to_ds9('7f000001:41898') #condition=restfreq+(0.77*u.km/u.s)#and minus
# dendro_temperature but *much* faster for sm,cubeA,cubeB,objects in zip(("","_smooth",), (cube303,cube303sm,), (cube321,cube321sm,), (dend,dendsm,),): # reset data tcubedata = np.empty(cubeA.shape) tcubedata[:] = np.nan rcubedata = np.empty(cubeA.shape) rcubedata[:] = np.nan pb = ProgressBar(len(objects)) for ii,structure in enumerate(objects): dend_obj_mask = BooleanArrayMask(structure.get_mask(), wcs=cubeA.wcs) view = cubeA.subcube_slices_from_mask(dend_obj_mask) submask = dend_obj_mask[view] assert submask.include().sum() == dend_obj_mask.include().sum() c303 = cubeA[view].with_mask(submask) c321 = cubeB[view].with_mask(submask) npix = submask.include().sum() Stot303 = c303.sum().value Stot321 = c321.sum().value if npix == 0: raise ValueError("npix=0. This is impossible.") Smean303 = Stot303/npix Smean321 = Stot321/npix try:
logabundance=logabundance, elogabundance=elogabundance, taline303=ta303.value, etaline303=err, taline321=ta321.value, etaline321=err, linewidth=linewidth) row_data = mf.get_parconstraints() tcube[z, y, x] = row_data['temperature_chi2'] row_data['ratio303321'] = rat row_data['eratio303321'] = erat if ii % 100 == 0 or ii < 50: log.info( "T: [{tmin1sig_chi2:7.2f},{temperature_chi2:7.2f},{tmax1sig_chi2:7.2f}] R={ratio303321:6.2f}+/-{eratio303321:6.2f}" .format(**row_data)) else: pb.update(ii) tcube.flush() else: pb.update(ii) tcube[tcube == 0] = np.nan tCube = SpectralCube(tcube, cube303.wcs, mask=BooleanArrayMask(np.isfinite(tcube), wcs=cube303.wcs)) tCube.write(hpath('chi2_temperature_cube.fits'), overwrite=True) print()
def test_scalegen(): cube = SpectralCube(data, wcs.WCS(h), mask=BooleanArrayMask(mask, wcs=wcs.WCS(h))) noiseobj = noise.Noise(cube) assert np.isclose(noiseobj.scale, 1.1382529312849043)
from pvextractor import extract_pv_slice from pvextractor.geometry import Path from spectral_cube import SpectralCube, BooleanArrayMask from astropy.io import fits from astropy.wcs import WCS import numpy as np import matplotlib.pyplot as p # Start with the full COMPLETE Perseus cube # Missing end card in the header, so we have to manually open it hdu = fits.open( "/srv/astro/erickoch/enzo_sims/complete/PerA_13coFCRAO_F_xyv.fits", ignore_missing_end=True) mask = BooleanArrayMask(mask=np.isfinite(hdu[0].data), wcs=WCS(hdu[0].header)) sc = SpectralCube(data=hdu[0].data, wcs=WCS(hdu[0].header), mask=mask) # Select the region of interest sc_small = sc[120:300, 156:346, 677:958] # Ends for the PV slice # ends = [(107, 74), (151, 76), (220, 54)] ends = [(105, 70), (145, 80), (227, 28), (238, 1)] xy = Path(ends, width=10) pv = extract_pv_slice(sc_small, xy) p.subplot(121)
return mask_array cube303 = SpectralCube.read( hpath('APEX_H2CO_303_202_bl.fits')).with_spectral_unit( u.km / u.s, velocity_convention='radio') cube321 = SpectralCube.read( hpath('APEX_H2CO_321_220_bl.fits')).with_spectral_unit( u.km / u.s, velocity_convention='radio') maskarr = mask_out_region( fits.getdata(hpath('APEX_H2CO_303_202_bl_mask.fits')).astype('bool'), cube303) mask = (maskarr & cube303.mask.include(cube303, cube303.wcs) & cube321.mask.include(cube321, cube321.wcs)) bmask = BooleanArrayMask(mask, cube303.wcs) cube303m = cube303.with_mask(bmask) cube321m = cube321.with_mask(bmask) cube303sm = SpectralCube.read( hpath('APEX_H2CO_303_202_smooth_bl.fits')).with_spectral_unit( u.km / u.s, velocity_convention='radio') cube321sm = SpectralCube.read( hpath('APEX_H2CO_321_220_smooth_bl.fits')).with_spectral_unit( u.km / u.s, velocity_convention='radio') smmaskarr = mask_out_region( fits.getdata( hpath('APEX_H2CO_303_202_smooth_bl_mask.fits')).astype('bool'), cube303sm) masksm = (smmaskarr & cube303sm.mask.include(cube303sm, cube303sm.wcs) & cube321sm.mask.include(cube321sm, cube321sm.wcs))
# ---------------- # # Build the masks. # # ---------------- # # The masked data and their corresponding masks are returned as dictionaries. # Mask where NaNs are TRUE trueMask = np.ma.masked_where(data==0,data) # Mask where NaNs are FALSE falseMask = np.ma.masked_where(data!=0,data) # Mask the profile range. NaNs are TRUE profileMask = maskProfile(data=trueMask,xarr=vels, minProfIdx=minProfIdx,maxProfIdx=maxProfIdx) # Build mask with a WCS that is compatible with SpectralCube. # NaNs are FALSE. cubeMask = BooleanArrayMask(np.ma.getmask(falseMask),pacsWcs) if nFluxes > 350: mid = 200 else: mid = 100 # Make an array of coordinates for the valid spaxels validPixels = findValidPixels((nCols,nRows),np.ma.getmask(trueMask[mid,:,:])) # --------------------------------------------------- # # Find the (col,row) min/max limits of valid spaxels. # # Min/max will be used to crop the data and the WCS. # # --------------------------------------------------- #
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: from taskinit import ia 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: data = ia.getchunk() # CASA stores validity of data as a mask if not skipvalid: valid = ia.getchunk(getmask=True) # transpose is dealt with within the cube object # read in coordinate system object casa_cs = ia.coordsys() wcs = wcs_casa2astropy(casa_cs) # 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} mask = BooleanArrayMask(wcs, np.logical_not(valid)) cube = SpectralCube(data, wcs, mask, meta=meta) return cube
noisehdr = fits.getheader(noise_fn) sm_noise = fits.getdata( mpath('APEX_H2CO_merge_high_plait_all_smooth_noise.fits')) sm_noise[nhits < 20] = np.nan sm_noise_cube = as_strided(sm_noise, shape=cube303msm.shape, strides=(0, ) + sm_noise.strides) # Cubes masked with noise cube == OK # (can I make this lazier?) noisefinite = np.isfinite(noise) # stride length changes for bools? sm_noisefinite = np.isfinite(sm_noise) cube303nm = cube303.with_mask( BooleanArrayMask( as_strided(noisefinite, shape=cube303.shape, strides=(0, ) + noisefinite.strides), cube303.wcs)) cube303nmsm = cube303sm.with_mask( BooleanArrayMask( as_strided(sm_noisefinite, shape=cube303sm.shape, strides=(0, ) + sm_noisefinite.strides), cube303sm.wcs)) cube321nm = cube321.with_mask( BooleanArrayMask( as_strided(noisefinite, shape=cube321.shape, strides=(0, ) + noisefinite.strides), cube321.wcs)) cube321nmsm = cube321sm.with_mask( BooleanArrayMask( as_strided(sm_noisefinite,
im2 = fits.getdata(hpath('H2CO_321220_to_303202_bl_integ_temperature_dens1e4.fits')) im3 = fits.getdata(hpath('H2CO_321220_to_303202_bl_integ_weighted_temperature_dens1e4_masked.fits')) tcube = tcube_direct tcube_mean = tcube.mean(axis=0) wcube = SpectralCube.read(hpath('APEX_H2CO_303_202_bl.fits')) mcube = SpectralCube.read(hpath('APEX_H2CO_303_202_bl_mask.fits')) if tcube.shape != wcube.shape: raise weighted = copy.copy(tcube) weighted._data = wcube._data * tcube._data mask = (wcube.mask & tcube.mask & BooleanArrayMask(weighted.filled_data[...] != 0, weighted.wcs) & BooleanArrayMask(wcube.filled_data[...] != 0, wcube.wcs) & BooleanArrayMask(mcube._data==1, mcube.wcs) ) weighted = weighted.with_mask(mask) wcube = wcube.with_mask(mask) tcube_wmean = tcube.mean(axis=0) pl.figure(14, figsize=(12,20)).clf() pl.subplot(5,1,1).imshow(im1) pl.subplot(5,1,2).imshow(im2) pl.subplot(5,1,3).imshow(im3) pl.subplot(5,1,4).imshow(tcube_mean.value) pl.subplot(5,1,5).imshow(tcube_wmean.value)
# .with_spectral_unit(u.km/u.s, # velocity_convention='radio', # rest_value=restfreqs[mol]) # for mol in molecules} cubes = { mol: SpectralCube.read( 'feathered/Feathered_{0}.fits'.format(mol)).with_spectral_unit( u.km / u.s, velocity_convention='radio', rest_value=restfreqs[mol]).spectral_slab(-20 * u.km / u.s, 137 * u.km / u.s) for mol in molecules } hc3nmean = cubes['HC3N'].mean(axis=(1, 2)) bad = np.abs(hc3nmean) > 1 mhc3n = cubes['HC3N'].with_mask( BooleanArrayMask(~bad[:, None, None], cubes['HC3N'].wcs)) cubes['HC3N'] = mhc3n for cube in cubes.values(): cube._data -= cube.mean(axis=0).value ytcubes = {mol: cubes[mol][::2, ::2, ::2].to_yt() for mol in molecules} for ytc in ytcubes.values(): ytc.dataset.periodicity = (True, ) * 3 try: os.mkdir("IsoSurfs") except: pass #for ii,(level,transparency) in enumerate(zip((2, 3, 4), (0.1,0.3,0.6))):
molecules = ('HNC','HC3N','HCOp','HCN',) molecules = ('HC3N',) colors = {'HNC': red, 'HCN': green, 'HC3N': brown, 'HCOp': blue, } cubes = {mol: SpectralCube.read('Feathered_{0}.fits'.format(mol)) .with_spectral_unit(u.km/u.s, velocity_convention='radio') for mol in molecules} hc3nmean = cubes['HC3N'].mean(axis=(1,2)) bad = np.abs(hc3nmean)>1 mh3cn = cubes['HC3N'].with_mask(BooleanArrayMask(bad[:,None,None], cubes['HC3N'].wcs)) cubes['HC3N'] = mh3cn ytcubes = {mol: cubes[mol].to_yt() for mol in molecules} try: os.mkdir("ChemMovie") except: pass def ramp(vals, minval, maxval): v = (vals)**0.25 return (v - v.min())/(v.max() - v.min()) nframes = 60 size = 512
print(fn, cube) m0 = cube.moment0(axis=0) max = cube.max(axis=0) m0.hdu.writeto('moment0/{0}_moment0.fits'.format(pfx), clobber=True) max.hdu.writeto('max/{0}_max.fits'.format(pfx), clobber=True) std = cube.std(axis=0) mask = cube > std mcube = cube.with_mask(mask) m0mask = mcube.moment0(axis=0) m1mask = mcube.moment1(axis=0) m0mask.hdu.writeto('moment0/{0}_moment0_mask.fits'.format(pfx), clobber=True) m1mask.hdu.writeto('moment1/{0}_moment1_mask.fits'.format(pfx), clobber=True) if False: rendermask_arr = std.value < np.percentile(std.ravel(), 75) rendermask = BooleanArrayMask(rendermask_arr, mcube.wcs, mcube.shape) rcube = mcube.with_mask(rendermask).minimal_subcube() print("Minimal rendering cube: ", fn, rcube) ytc = rcube.to_yt() ytc.quick_isocontour( level=3 * np.nanmean(std.value), title='Sgr B2 12mTC {0}'.format(pfx), description='ALMA observations of Sgr B2. File {0}'.format(pfx), filename=pfx + ".ply") del mask del cube
def to_object(self, data_or_subset, attribute=None): """ Convert a glue Data object to a SpectralCube object. Parameters ---------- data_or_subset : `glue.core.data.Data` or `glue.core.subset.Subset` The data to convert to a SpectralCube object attribute : `glue.core.component_id.ComponentID` The attribute to use for the SpectralCube data """ if data_or_subset.ndim > 0 and data_or_subset.ndim != 3 and data_or_subset.ndim != 4: raise ValueError('Data object should have 3 or 4 dimensions in order to ' 'be converted to a SpectralCube object.') if isinstance(data_or_subset, Subset): data = data_or_subset.data subset_state = data_or_subset.subset_state else: data = data_or_subset subset_state = None if isinstance(data.coords, BaseLowLevelWCS): wcs = data.coords else: raise TypeError('data.coords should be an instance of BaseLowLevelWCS.') if isinstance(attribute, str): attribute = data.id[attribute] elif len(data.main_components) == 0: raise ValueError('Data object has no attributes.') elif attribute is None: if len(data.main_components) == 1: attribute = data.main_components[0] else: raise ValueError("Data object has more than one attribute, so " "you will need to specify which one to use as " "the flux for the spectral cube using the " "attribute= keyword argument.") component = data.get_component(attribute) values = data.get_data(attribute) if subset_state is None: mask = None else: mask = data.get_mask(subset_state=subset_state) values = values.copy() mask = BooleanArrayMask(mask, wcs=wcs) values = values * u.Unit(component.units) # Drop Stokes axis if there is one for FITS WCS if isinstance(wcs, WCS) and wcs.sub([WCSSUB_STOKES]).naxis > 0: types = [axistype['coordinate_type'] for axistype in wcs.get_axis_types()] # For now we only ever get the first stokes element. We could in # principle allow this to be customized, or return a StokesSpectralCube slc = tuple([0 if tp == 'stokes' else slice(None) for tp in types]) subkeep = tuple([index + 1 for index, tp in enumerate(types) if tp != 'stokes']) values = values[slc[::-1]] wcs = wcs.sub(subkeep) return SpectralCube(values, mask=mask, wcs=wcs, meta=data.meta)
), ( dend, dendsm, ), ): # reset data tcubedata = np.empty(cubeA.shape) tcubedata[:] = np.nan rcubedata = np.empty(cubeA.shape) rcubedata[:] = np.nan pb = ProgressBar(len(objects)) for ii, structure in enumerate(objects): dend_obj_mask = BooleanArrayMask(structure.get_mask(), wcs=cubeA.wcs) view = cubeA.subcube_slices_from_mask(dend_obj_mask) submask = dend_obj_mask[view] assert submask.include().sum() == dend_obj_mask.include().sum() c303 = cubeA[view].with_mask(submask) c321 = cubeB[view].with_mask(submask) npix = submask.include().sum() Stot303 = c303.sum().value Stot321 = c321.sum().value if npix == 0: raise ValueError("npix=0. This is impossible.") Smean303 = Stot303 / npix Smean321 = Stot321 / npix try:
def measure_dendrogram_properties(dend=None, cube303=cube303, cube321=cube321, cube13co=cube13co, cube18co=cube18co, noise_cube=noise_cube, sncube=sncube, suffix="", last_index=None, plot_some=True, line='303', write=True): assert (cube321.shape == cube303.shape == noise_cube.shape == cube13co.shape == cube18co.shape == sncube.shape) assert sncube.wcs is cube303.wcs is sncube.mask._wcs metadata = {} metadata['data_unit'] = u.K metadata['spatial_scale'] = 7.2 * u.arcsec metadata['beam_major'] = 30 * u.arcsec metadata['beam_minor'] = 30 * u.arcsec metadata['wavelength'] = 218.22219 * u.GHz metadata['velocity_scale'] = u.km / u.s metadata['wcs'] = cube303.wcs keys = [ 'density_chi2', 'expected_density', 'dmin1sig_chi2', 'dmax1sig_chi2', 'column_chi2', 'expected_column', 'cmin1sig_chi2', 'cmax1sig_chi2', 'temperature_chi2', 'expected_temperature', 'tmin1sig_chi2', 'tmax1sig_chi2', 'eratio321303', 'ratio321303', 'logh2column', 'elogh2column', 'logabundance', 'elogabundance', ] obs_keys = [ 'Stot303', 'Smin303', 'Smax303', 'Stot321', 'Smean303', 'Smean321', 'npix', 'e303', 'e321', 'r321303', 'er321303', '13cosum', 'c18osum', '13comean', 'c18omean', 's_ntotal', 'index', 'is_leaf', 'parent', 'root', 'lon', 'lat', 'vcen', 'higaldusttem', 'reff', 'dustmass', 'dustmindens', 'bad', #'tkin_turb', ] columns = {k: [] for k in (keys + obs_keys)} log.debug("Initializing dendrogram temperature fitting loop") # FORCE wcs to match # (technically should reproject here) cube13co._wcs = cube18co._wcs = cube303.wcs cube13co.mask._wcs = cube18co.mask._wcs = cube303.wcs if line == '303': maincube = cube303 elif line == '321': maincube = cube321 else: raise ValueError("Unrecognized line: {0}".format(line)) # Prepare an array to hold the fitted temperatures tcubedata = np.empty(maincube.shape, dtype='float32') tcubedata[:] = np.nan tcubeleafdata = np.empty(maincube.shape, dtype='float32') tcubeleafdata[:] = np.nan nbad = 0 catalog = ppv_catalog(dend, metadata) pb = ProgressBar(len(catalog)) for ii, row in enumerate(catalog): structure = dend[row['_idx']] assert structure.idx == row['_idx'] == ii dend_obj_mask = BooleanArrayMask(structure.get_mask(), wcs=cube303.wcs) dend_inds = structure.indices() view = ( slice(dend_inds[0].min(), dend_inds[0].max() + 1), slice(dend_inds[1].min(), dend_inds[1].max() + 1), slice(dend_inds[2].min(), dend_inds[2].max() + 1), ) #view2 = cube303.subcube_slices_from_mask(dend_obj_mask) submask = dend_obj_mask[view] #assert np.count_nonzero(submask.include()) == np.count_nonzero(dend_obj_mask.include()) sn = sncube[view].with_mask(submask) sntot = sn.sum().value #np.testing.assert_almost_equal(sntot, structure.values().sum(), decimal=0) c303 = cube303[view].with_mask(submask) c321 = cube321[view].with_mask(submask) co13sum = cube13co[view].with_mask(submask).sum().value co18sum = cube18co[view].with_mask(submask).sum().value if hasattr(co13sum, '__len__'): raise TypeError( ".sum() applied to an array has yielded a non scalar.") npix = submask.include().sum() assert npix == structure.get_npix() Stot303 = c303.sum().value if np.isnan(Stot303): raise ValueError("NaN in cube. This can't happen: the data from " "which the dendrogram was derived can't have " "NaN pixels.") Smax303 = c303.max().value Smin303 = c303.min().value Stot321 = c321.sum().value if npix == 0: raise ValueError("npix=0. This is impossible.") Smean303 = Stot303 / npix if Stot303 <= 0 and line == '303': raise ValueError( "The 303 flux is <=0. This isn't possible because " "the dendrogram was derived from the 303 data with a " "non-zero threshold.") elif Stot303 <= 0 and line == '321': Stot303 = 0 Smean303 = 0 elif Stot321 <= 0 and line == '321': raise ValueError( "The 321 flux is <=0. This isn't possible because " "the dendrogram was derived from the 321 data with a " "non-zero threshold.") if np.isnan(Stot321): raise ValueError("NaN in 321 line") Smean321 = Stot321 / npix #error = (noise_cube[view][submask.include()]).sum() / submask.include().sum()**0.5 var = ((noise_cube[dend_obj_mask.include()]**2).sum() / npix**2) error = var**0.5 if np.isnan(error): raise ValueError("error is nan: this is impossible by definition.") if line == '321' and Stot303 == 0: r321303 = np.nan er321303 = np.nan elif Stot321 < 0: r321303 = error / Smean303 er321303 = (r321303**2 * (var / Smean303**2 + 1))**0.5 else: r321303 = Stot321 / Stot303 er321303 = (r321303**2 * (var / Smean303**2 + var / Smean321**2))**0.5 for c in columns: assert len(columns[c]) == ii columns['index'].append(row['_idx']) columns['s_ntotal'].append(sntot) columns['Stot303'].append(Stot303) columns['Smax303'].append(Smax303) columns['Smin303'].append(Smin303) columns['Stot321'].append(Stot321) columns['Smean303'].append(Smean303) columns['Smean321'].append(Smean321) columns['npix'].append(npix) columns['e303'].append(error) columns['e321'].append(error) columns['r321303'].append(r321303) columns['er321303'].append(er321303) columns['13cosum'].append(co13sum) columns['c18osum'].append(co18sum) columns['13comean'].append(co13sum / npix) columns['c18omean'].append(co18sum / npix) columns['is_leaf'].append(structure.is_leaf) columns['parent'].append( structure.parent.idx if structure.parent else -1) columns['root'].append(get_root(structure).idx) s_main = maincube._data[dend_inds] x, y, z = maincube.world[dend_inds] lon = ((z.value - (360 * (z.value > 180))) * s_main).sum() / s_main.sum() lat = (y * s_main).sum() / s_main.sum() vel = (x * s_main).sum() / s_main.sum() columns['lon'].append(lon) columns['lat'].append(lat.value) columns['vcen'].append(vel.value) mask2d = dend_obj_mask.include().max(axis=0)[view[1:]] logh2column = np.log10( np.nanmean(column_regridded.data[view[1:]][mask2d]) * 1e22) if np.isnan(logh2column): log.info("Source #{0} has NaNs".format(ii)) logh2column = 24 elogh2column = elogabundance columns['higaldusttem'].append( np.nanmean(dusttem_regridded.data[view[1:]][mask2d])) r_arcsec = row['radius'] * u.arcsec reff = (r_arcsec * (8.5 * u.kpc)).to(u.pc, u.dimensionless_angles()) mass = ((10**logh2column * u.cm**-2) * np.pi * reff**2 * 2.8 * constants.m_p).to(u.M_sun) density = (mass / (4 / 3. * np.pi * reff**3) / constants.m_p / 2.8).to( u.cm**-3) columns['reff'].append(reff.value) columns['dustmass'].append(mass.value) columns['dustmindens'].append(density.value) mindens = np.log10(density.value) if mindens < 3: mindens = 3 if (r321303 < 0 or np.isnan(r321303)) and line != '321': raise ValueError("Ratio <0: This can't happen any more because " "if either num/denom is <0, an exception is " "raised earlier") #for k in columns: # if k not in obs_keys: # columns[k].append(np.nan) elif (r321303 < 0 or np.isnan(r321303)) and line == '321': for k in keys: columns[k].append(np.nan) else: # Replace negatives for fitting if Smean321 <= 0: Smean321 = error mf.set_constraints( ratio321303=r321303, eratio321303=er321303, #ratio321322=ratio2, eratio321322=eratio2, logh2column=logh2column, elogh2column=elogh2column, logabundance=logabundance, elogabundance=elogabundance, taline303=Smean303, etaline303=error, taline321=Smean321, etaline321=error, mindens=mindens, linewidth=10) row_data = mf.get_parconstraints() row_data['ratio321303'] = r321303 row_data['eratio321303'] = er321303 for k in row_data: columns[k].append(row_data[k]) # Exclude bad velocities from cubes if row['v_cen'] < -80e3 or row['v_cen'] > 180e3: # Skip: there is no real structure down here nbad += 1 is_bad = True else: is_bad = False tcubedata[ dend_obj_mask.include()] = row_data['expected_temperature'] if structure.is_leaf: tcubeleafdata[dend_obj_mask.include( )] = row_data['expected_temperature'] columns['bad'].append(is_bad) width = row['v_rms'] * u.km / u.s lengthscale = reff #REMOVED in favor of despotic version done in dendrograms.py # we use the analytic version here; the despotic version is # computed elsewhere (with appropriate gcor factors) #columns['tkin_turb'].append(heating.tkin_all(10**row_data['density_chi2']*u.cm**-3, # width, # lengthscale, # width/lengthscale, # columns['higaldusttem'][-1]*u.K, # crir=0./u.s)) if len(set(len(c) for k, c in columns.items())) != 1: print("Columns are different lengths. This is not allowed.") import ipdb ipdb.set_trace() for c in columns: assert len(columns[c]) == ii + 1 if plot_some and not is_bad and (ii - nbad % 100 == 0 or ii - nbad < 50): try: log.info( "T: [{tmin1sig_chi2:7.2f},{expected_temperature:7.2f},{tmax1sig_chi2:7.2f}]" " R={ratio321303:8.4f}+/-{eratio321303:8.4f}" " Smean303={Smean303:8.4f} +/- {e303:8.4f}" " Stot303={Stot303:8.2e} npix={npix:6d}".format( Smean303=Smean303, Stot303=Stot303, npix=npix, e303=error, **row_data)) pl.figure(1) pl.clf() mf.denstemplot() pl.savefig( fpath("dendrotem/diagnostics/{0}_{1}.png".format( suffix, ii))) pl.figure(2).clf() mf.parplot1d_all(levels=[0.68268949213708585]) pl.savefig( fpath("dendrotem/diagnostics/1dplot{0}_{1}.png".format( suffix, ii))) pl.draw() pl.show() except Exception as ex: print ex pass else: pb.update(ii + 1) if last_index is not None and ii >= last_index: break if last_index is not None: catalog = catalog[:last_index + 1] for k in columns: if k not in catalog.keys(): catalog.add_column(table.Column(name=k, data=columns[k])) for mid, lo, hi, letter in (('expected_temperature', 'tmin1sig_chi2', 'tmax1sig_chi2', 't'), ('expected_density', 'dmin1sig_chi2', 'dmax1sig_chi2', 'd'), ('expected_column', 'cmin1sig_chi2', 'cmax1sig_chi2', 'c')): catalog.add_column( table.Column(name='elo_' + letter, data=catalog[mid] - catalog[lo])) catalog.add_column( table.Column(name='ehi_' + letter, data=catalog[hi] - catalog[mid])) if write: catalog.write(tpath('PPV_H2CO_Temperature{0}.ipac'.format(suffix)), format='ascii.ipac') # Note that there are overlaps in the catalog, which means that ORDER MATTERS # in the above loop. I haven't yet checked whether large scale overwrites # small or vice-versa; it may be that both views of the data are interesting. tcube = SpectralCube( data=tcubedata, wcs=cube303.wcs, mask=cube303.mask, meta={'unit': 'K'}, header=cube303.header, ) tcubeleaf = SpectralCube( data=tcubeleafdata, wcs=cube303.wcs, mask=cube303.mask, meta={'unit': 'K'}, header=cube303.header, ) if write: log.info("Writing TemperatureCube") outpath = 'TemperatureCube_DendrogramObjects{0}.fits' tcube.write(hpath(outpath.format(suffix)), overwrite=True) outpath_leaf = 'TemperatureCube_DendrogramObjects{0}_leaves.fits' tcubeleaf.write(hpath(outpath_leaf.format(suffix)), overwrite=True) return catalog, tcube
# ---------------- # # Build the masks. # # ---------------- # # The masked data and their corresponding masks are returned as dictionaries. # Mask where NaNs are TRUE trueMask = maskTrue(data=data) # Mask where NaNs are FALSE falseMask = maskFalse(data=data) # Mask the profile range. NaNs are TRUE profileMask = maskProfile(data=trueMask['maskedData'], xarr=vels, minProfIdx=minProfIdx, maxProfIdx=maxProfIdx) # Build mask with a WCS that is compatible with SpectralCube. # NaNs are FALSE. cubeMask = BooleanArrayMask(falseMask['mask'], pacsWcs) # Make an array of coordinates for the valid spaxels validPixels = findValidPixels((nCols, nRows), trueMask['mask'][0, :, :]) # --------------------------------------------------- # # Find the (col,row) min/max limits of valid spaxels. # # Min/max will be used to crop the data and the WCS. # # --------------------------------------------------- # wcsMinMax = pixMinMax(validPixels) # ------------------------------------------------------------- # # Fit the continuum with a polynomial and subtract from fluxes. # # ------------------------------------------------------------- # # The edges of the spectrum and the velocity region # of the line profile is masked as TRUE. Data which
noise_flat = noise_cube[mask] var_flat = noise_flat**2 ratio303321 = cube321m.flattened().value / cube303m.flattened().value eratio303321 = ((ratio303321**2 * (var_flat / cube303m.flattened().value**2 + var_flat / cube321m.flattened().value**2))**0.5) ratioOK = ratio303321 > eratio303321 * 1 #ratioOK = cube303m.mask.include() data = np.zeros(cube303m.shape, dtype='float32') * np.nan mask[mask] = ratioOK data[mask] = ratio303321[ratioOK] ratiocube_303321 = SpectralCube(data, mask=BooleanArrayMask(np.isfinite(data), wcs=cube303m.wcs), wcs=cube303m.wcs) noise_flat_sm = sm_noise_cube[masksm] var_flat_sm = noise_flat_sm**2 ratio303321sm = cube321msm.flattened().value / cube303msm.flattened().value eratio303321sm = ((ratio303321sm**2 * (var_flat_sm / cube303msm.flattened().value**2 + var_flat_sm / cube321msm.flattened().value**2))**0.5) ratioOKsm = ratio303321sm > eratio303321sm * 1 #ratioOKsm = cube303msm.mask.include() datasm = np.zeros(cube303msm.shape, dtype='float32') * np.nan masksm[masksm] = ratioOKsm datasm[masksm] = ratio303321sm[ratioOKsm]
ratiocube_303321, ratiocubesm_303321), ('dend', 'dendsm', 'direct', 'directsm', 'ratio', 'ratiosm')): log.info("Starting {0} {1}".format(name, weight)) mask = (cube303sm > 0.2 if 'sm' in name else cube303 > 0.3) if weight: wcube = (cube303msm if 'sm' in name else cube303m) if tcube.shape != wcube.shape: log.info("Not weighting {0}".format(fn)) continue weighted = copy.copy(tcube).with_mask(mask) weighted._data = wcube._data * tcube._data mask = (wcube.mask & tcube.mask & mask & BooleanArrayMask( weighted.filled_data[...] != 0, weighted.wcs) & BooleanArrayMask(wcube.filled_data[...] != 0, wcube.wcs)) wcube = wcube.with_mask(mask) pv1 = weighted.sum(axis=1) pv2 = wcube.sum(axis=1) pv = pv1 / pv2 bmean = pv.value else: bmean = tcube.with_mask(mask).mean(axis=1) ds = 10 if 'sm' in name else 20 tcube_ds = tcube[::ds, :, :] # for the WCS tcube_ds.data = downsample.downsample_axis(tcube._data, ds, axis=0) bmeands = downsample.downsample_axis(bmean, ds, axis=0)