def get_profile(file,PA_disk,inc,d,padir,widir,dr): cube=imagecube(file,FOV=3) PAmin=padir-0.5*widir PAmax=padir+0.5*widir x,y,dy=cube.radial_profile(inc=inc, PA=PA_disk, dist=d, PA_min=PAmin,PA_max=PAmax,dr=dr, assume_correlated=False) return x,y,dy
def radial_profile_gofish(data, disk_inc, disk_pa, d, x0_off, y0_off, lim): cube = imagecube(data) xm, ym, dym = cube.radial_profile(inc=disk_inc, PA=disk_pa, dist=d, x0=x0_off, y0=y0_off) xm = xm * d ym = ym # mJy/beam dym = dym f = open("../alma_radial_profile_modeled.dat", "w") for (i, j, k) in zip(xm, ym, dym): if i <= lim: f.write("%.13e %.13e %.13e \n" % (i, j, k)) f.close() return None
def get_profile_from_fits(fname, clip=2.5, show_plots=False, inc=0, PA=0, z0=0.0, psi=0.0, beam=None, r_norm=None, norm=None, **kwargs): """Get radial profile from fits file. Reads a fits file and determines a radial profile with `imagecube` fname : str | path path to fits file clip : float clip the image at that many image units (usually arcsec) show_plots : bool if true: produce some plots for sanity checking inc, PA : float inclination and position angle used in the radial profile z0, psi : float the scale height at 1 arcse and the radial exponent used in the deprojection beam : None | tuple if None: will be determined by imgcube if 3-element tuple: assume this beam a, b, PA. r_norm : None | float if not None: normalize at this radius norm : None | float divide by this norm kwargs are passed to radial_profile Returns: x, y, dy: arrays radial grid, intensity (cgs), error (cgs) """ if norm is not None and r_norm is not None: raise ValueError('only norm or r_norm can be set, not both!') data = imagecube(fname, FOV=clip) if beam is not None: data.bmaj, data.bmin, data.bpa = beam data.beamarea_arcsec = data._calculate_beam_area_arcsec() data.beamarea_str = data._calculate_beam_area_str() x, y, dy = data.radial_profile(inc=inc, PA=PA, z0=z0, psi=psi, **kwargs) if data.bunit.lower() == 'jy/beam': y *= 1e-23 / data.beamarea_str dy *= 1e-23 / data.beamarea_str elif data.bunit.lower() == 'jy/pixel': y *= 1e-23 * data.pix_per_beam / data.beamarea_str dy *= 1e-23 * data.pix_per_beam / data.beamarea_str else: raise ValueError( 'unknown unit, please implement conversion to CGS here') if r_norm is not None: norm = np.interp(r_norm, x, y) y /= norm dy /= norm if norm is not None: y /= norm dy /= norm if show_plots: f, ax = plt.subplots() ax.semilogy(x, y) ax.fill_between(x, y - dy, y + dy, alpha=0.5) ax.set_ylim(bottom=1e-16) return x, y, dy
default='probable', type=str, help='Estimator to use for the debiasing. Either ' + '`probable` or `likelihood`.') parser.add_argument('-rms', type=float, help='RMS noise in the Stokes Q and U maps.') parser.add_argument('-overwrite', default=True, type=bool, help='Overwrite existing files with the same name.') args = parser.parse_args() # Read in the cubes. if args.Q is not None: cube_Q = imagecube(args.Q) else: raise ValueError("Must specify a Stokes Q cube.") if args.U is not None: cube_U = imagecube(args.U) else: raise ValueError("Must specify a Stokes U cube.") # Calculate the P_obs values. P_obs = np.hypot(cube_Q.data, cube_U.data) if args.rms is None and P_obs.ndim == 3: rms = np.mean( [cube_Q.estimate_RMS(args.N), cube_U.estimate_RMS(args.N)]) print("Estimated Q and U RMS noise based on the first and last " + "{} channels: ".format(args.N) +
import numpy as np import matplotlib.pyplot as plt from gofish import imagecube import sys import matplotlib.gridspec as gridspec cube = imagecube( '/Users/users/bportilla/Documents/first_project/scripts/PDS70/observations/PDS70_cont-final.fits', FOV=3) """ rvals, tvals, _ = cube.disk_coords(x0=0.0, y0=0.0, inc=49.7, PA=158.6) fig, ax = plt.subplots() im = ax.imshow(tvals, origin='lower', extent=cube.extent) cb = plt.colorbar(im, pad=0.02) ax.set_xlabel('Offset (arcsec)') ax.set_ylabel('Offset (arcsec)') cb.set_label('Polar Angle (radians)', rotation=270, labelpad=13) plt.show() sys.exit() """ """ xm, ym, dym = cube.radial_profile(inc=49.7,PA=158.6,dist=113.43,x0=0.0,y0=0.0) f=open("gofishdat.dat","w") for (i,j,k) in zip(xm,ym,dym): f.write("%.13e %.13e %.13e \n"%(i*113.43,j/np.nanmax(ym),k/np.nanmax(ym))) f.close() plt.errorbar(xm*113.43,ym/np.nanmax(ym),dym/np.nanmax(ym)) plt.show() """
# generate a spectrum dat = fits.open(mname+'/'+mname+'_co.fits') chanmaps = np.squeeze(dat[0].data) spec = np.sum(chanmaps, axis=(1,2)) print('integrated CO = %f Jy km/s' % \ (np.sum(spec * opars["velocity"]["velres"]))) plt.plot(np.arange(len(spec)), spec) plt.show() # generate and load 0th moment map (made with bettermoments) os.chdir(mname) os.system('bettermoments '+mname+'_co.fits -method zeroth -clip 0') cube = imagecube(mname+'_co_M0.fits') os.chdir('../') # extract radial profile x, y, dy = cube.radial_profile(inc=incl, PA=PA, x0=0.0, y0=0.0, z0=0.3, phi=1., PA_min=90, PA_max=270, abs_PA=True, exclude_PA=False) # integrated flux profile def fraction_curve(radius, intensity): intensity[np.isnan(intensity)] = 0 total =trapz(2*np.pi*radius*intensity, radius) cum = cumtrapz(2*np.pi*radius*intensity, radius)
import numpy as np import matplotlib.pyplot as plt from gofish import imagecube import sys import matplotlib.gridspec as gridspec ############################################################ # Load data cube=imagecube('../alma_model_rotated.fits') ############################################################ # Main routine def radial_cut(PA_disk,inc,d,padir,widir,dr,x_off,y_off): PAmin=padir-0.5*widir PAmax=padir+0.5*widir x,y,dy=cube.radial_profile(inc=inc, PA=PA_disk, dist=d, PA_min=PAmin,PA_max=PAmax,dr=dr, assume_correlated=False,x0=x_off,y0=y_off) return x,y,dy ############################################################ # Input parameters ddisk=113.43 # Distance (pc) drsample=0.02 # Step size (arcsec) padisk=158.6 # Disk position angle (deg) incdisk=49.7 # Disk inclination (deg) padir=118.4 # Direction of interest, w.r.t. red shifted semi-major axis (deg) widir=20.0 # width of the cone (deg)
def get_emission_surface(path, inc, PA, dx0=0.0, dy0=0.0, chans=None, rmax=None, threshold=0.95, smooth=2, detect_peaks_kwargs=None, verbose=True, auto_correct=True): """ Returns the emission height of the provided image cube following Pinte et al. (2018). Args: path (str): Path to the fits cube. inc (float): Inclination of the disk in [deg]. PA (float): Position angle of the disk in [deg]. dx0 (Optional[float]): Offset in Right-Ascenion in [arcsec]. dy0 (Optional[float]): Offset in delincation in [arcsec]. chans (Optional[list]): A list of the first and last channel to use. rmax (Optional[float]) Maximum radius to consider in [arcsec]. threshold (Optional[float]): At a given radius, remove all pixels below ``threshold`` times the azimuthally averaged peak intensity value. smooth (Optional[int]): Size of top hat kernel to smooth each column prior to finding the peak. detect_peaks_kwargs (Optional[dict]): Kwargs for ``detect_peaks``. verbose (Opional[bool]): Print out messages. auto_correct (Optional[bool]): Will check to see if the disk is the correct orientation for the code (rotated such that the far edge of the disk is to the top). If ``auto_correct=True``, will include an additional rotation of 180 [deg] to correct this. Returns: list: A list of the midplane radius [arcsec], height [arcsec] and flux density [Jy/beam] at that location. """ # Import dependencies. from scipy.interpolate import interp1d # Load up the image cube. cube = imagecube(path, FOV=2.2 * rmax) rmax = rmax if rmax is not None else cube.xaxis.max() # Determine the channels to fit. chans = [0, cube.data.shape[0] - 1] if chans is None else chans if len(chans) != 2: raise ValueError("`chans` must be a length 2 list of channels.") if chans[1] >= cube.data.shape[0]: raise ValueError("`chans` extends beyond the number of channels.") chans[0], chans[1] = int(min(chans)), int(max(chans)) data = cube.data[chans[0]:chans[1] + 1] if verbose: velo = [cube.velax[chans[0]] / 1e3, cube.velax[chans[1]] / 1e3] print( "Using {:.2f} km/s to {:.2f} km/s,".format(min(velo), max(velo)) + ' and 0" to {:.2f}".'.format(rmax)) # Shift and rotate the data. if dx0 != 0.0 or dy0 != 0.0: if verbose: print("Centering data cube...") data = shift_center(data, dx0 / cube.dpix, dy0 / cube.dpix) if verbose: print("Rotating data cube...") data = rotate_image(data, PA) # Check to see if the disk is tilted correctly. Tb = np.max(data, axis=0) median_top = np.nanmedian(Tb[int(Tb.shape[0] / 2):]) median_bottom = np.nanmedian(Tb[:int(Tb.shape[0] / 2)]) if median_bottom > median_top: if verbose: print("WARNING: " + "The far side of the disk looks like it is to the south.") if auto_correct: if verbose: print("\t Rotating the disk by 180 degrees...\n" + "\t To ignore this step, use `auto_correct=False`.") data = data[:, ::-1, ::-1] # Make a (smoothed) radial profile of the peak values and clip values. if verbose: print("Removing low SNR pixels...") rbins, _ = cube.radial_sampling() rvals = cube.disk_coords(x0=0.0, y0=0.0, inc=inc, PA=0.0)[0] Tb = Tb.flatten() ridxs = np.digitize(rvals.flatten(), rbins) avgTb = [] for r in range(1, rbins.size): avgTb_tmp = Tb[ridxs == r] avgTb += [np.mean(avgTb_tmp[avgTb_tmp > 0.0])] kernel = np.ones(np.ceil(cube.bmaj / cube.dpix).astype('int')) avgTb = np.convolve(avgTb, kernel / np.sum(kernel), mode='same') avgTb = interp1d(np.average([rbins[1:], rbins[:-1]], axis=0), threshold * avgTb, fill_value=np.nan, bounds_error=False)(rvals) data = np.where(data >= np.where(np.isfinite(avgTb), avgTb, 0.), data, 0.) # We convolve the profile to reduce some of the noise. smooth = np.ones(smooth) / smooth if smooth is not None else [1.0] # Default dicionary for kwargs. if detect_peaks_kwargs is None: detect_peaks_kwargs = {} # Find all the peaks and save the (r, z, Tb) value. peaks = [] if verbose: print("Detecting peaks...") for c_idx in range(data.shape[0]): for x_idx in range(data.shape[2]): x_c = cube.xaxis[x_idx] mpd = detect_peaks_kwargs.get('mpd', 0.05 * abs(x_c)) try: profile = np.convolve(data[c_idx, :, x_idx], smooth, mode='same') y_idx = detect_peaks(profile, mpd=mpd, **detect_peaks_kwargs) y_idx = y_idx[data[c_idx, y_idx, x_idx].argsort()] y_f, y_n = cube.yaxis[y_idx[-2:]] y_c = 0.5 * (y_f + y_n) r = np.hypot(x_c, (y_f - y_c) / np.cos(np.radians(inc))) z = y_c / np.sin(np.radians(inc)) Tb = data[c_idx, y_idx[-1], x_idx] v_idx = c_idx except (ValueError, IndexError): r, z, Tb, v_idx = np.nan, np.nan, np.nan, np.nan peaks += [[r, z, Tb, v_idx]] peaks = np.squeeze(peaks) # Remove any NaN values and sort them. r, z, Tb, v_idx = peaks[~np.any(np.isnan(peaks), axis=1)].T idx = np.argsort(r) r, z, Tb, v_idx = r[idx], z[idx], Tb[idx], v_idx[idx] idx = r <= rmax if verbose: print("Done!\n") return r[idx], z[idx], Tb[idx], v_idx[idx]
def logP(parameters, options, debug=False): # set the path to the radmc3d executable if getpass.getuser() == 'birnstiel': radmc3d_exec = Path('~/.bin/radmc3d').expanduser() else: radmc3d_exec = Path('~/bin/radmc3d').expanduser() # get the options set in the notebook PA = options['PA'] inc = options['inc'] dpc = options['distance'] clip = options['clip'] lam_mm = options['lam_mm'] mstar = options['mstar'] lstar = options['lstar'] tstar = options['tstar'] # get the mm observables x_mm_obs = options['x_mm_obs'] y_mm_obs = options['y_mm_obs'] dy_mm_obs = options['dy_mm_obs'] fname_mm_obs = options['fname_mm_obs'] # get options used in the scattered light image z0 = options['z0'] psi = options['psi'] lam_sca = options['lam_sca'] beam_sca = options['beam_sca'] fname_sca_obs = options['fname_sca_obs'] # get the scattered light data profiles_sca_obs = options['profiles_sca_obs'] # name of the opacities file fname_opac = options['fname_opac'] # get the disklab model parameters nr = options['nr'] rin = options['rin'] r_c = options['r_c'] rout = options['rout'] alpha = options['alpha'] # create a temporary folder in the current folder temp_directory = tempfile.TemporaryDirectory(dir='.') temp_path = temp_directory.name # ### make the disklab 2D model disk2d = make_disklab2d_model(parameters, mstar, lstar, tstar, nr, alpha, rin, rout, r_c, fname_opac, show_plots=debug) print( f'disk to star mass ratio = {disk2d.disk.mass / disk2d.disk.mstar:.2g}' ) # read the wavelength grid from the opacity file and write out radmc setup opac_dict = read_opacs(fname_opac) lam_opac = opac_dict['lam'] n_a = len(opac_dict['a']) write_radmc3d(disk2d, lam_opac, temp_path, show_plots=debug) # ## Calculate the mm continuum image fname_mm_sim = Path(temp_path) / 'image_mm.fits' disklab.radmc3d.radmc3d( f'image incl {inc} posang {PA-90} npix 500 lambda {lam_mm * 1e4} sizeau {2 * rout / au} secondorder setthreads 1', path=temp_path, executable=str(radmc3d_exec)) radmc_image = Path(temp_path) / 'image.out' if radmc_image.is_file(): im_mm_sim = image.readImage(str(radmc_image)) radmc_image.replace(Path(temp_path) / 'image_mm.out') im_mm_sim.writeFits(str(fname_mm_sim), dpc=dpc, coord='15h56m09.17658s -37d56m06.1193s') # Read in the fits files into imagecubes, and copy the beam information from the observation to the simulation. iq_mm_obs = imagecube(str(fname_mm_obs), clip=clip) iq_mm_sim = imagecube(str(fname_mm_sim), clip=clip) iq_mm_sim.bmaj, iq_mm_sim.bmin, iq_mm_sim.bpa = iq_mm_obs.beam iq_mm_sim.beamarea_arcsec = iq_mm_sim._calculate_beam_area_arcsec() iq_mm_sim.beamarea_str = iq_mm_sim._calculate_beam_area_str() x_mm_sim, y_mm_sim, dy_mm_sim = get_profile_from_fits(str(fname_mm_sim), clip=clip, inc=inc, PA=PA, z0=0.0, psi=0.0, beam=iq_mm_obs.beam, show_plots=debug) i_max = max(len(x_mm_obs), len(x_mm_sim)) x_mm_sim = x_mm_sim[:i_max] y_mm_sim = y_mm_sim[:i_max] dy_mm_sim = dy_mm_sim[:i_max] x_mm_obs = x_mm_obs[:i_max] y_mm_obs = y_mm_obs[:i_max] dy_mm_obs = dy_mm_obs[:i_max] if not np.allclose(x_mm_sim, x_mm_obs): try: from IPython import embed embed() except Exception: raise AssertionError( 'observed and simulated radial profile grids are not equal') # TODO: Calculate the log probability for the mm here # %% Scattered light image for i_grain in range(n_a): opacity.write_radmc3d_scatmat_file(i_grain, opac_dict, f'{i_grain}', path=temp_path) with open(Path(temp_path) / 'dustopac.inp', 'w') as f: write(f, '2 Format number of this file') write(f, '{} Nr of dust species'.format(n_a)) for i_grain in range(n_a): write( f, '============================================================================' ) write(f, '10 Way in which this dust species is read') write(f, '0 0=Thermal grain') write( f, '{} Extension of name of dustscatmat_***.inp file' .format(i_grain)) write( f, '----------------------------------------------------------------------------' ) # image calculation iq_sca_obs = imagecube(str(fname_sca_obs), clip=clip) disklab.radmc3d.radmc3d( f'image incl {inc} posang {PA-90} npix {iq_sca_obs.data.shape[0]} lambda {lam_sca / 1e-4} sizeau {2 * rout / au} setthreads 4', path=temp_path, executable=str(radmc3d_exec)) fname_sca_sim = Path(temp_path) / 'image_sca.fits' if (Path(temp_path) / 'image.out').is_file(): (Path(temp_path) / 'image.out').replace( fname_sca_sim.with_suffix('.out')) im = image.readImage(str(fname_sca_sim.with_suffix('.out'))) im.writeFits(str(fname_sca_sim), dpc=dpc, coord='15h56m09.17658s -37d56m06.1193s') iq_sca_sim = imagecube(str(fname_sca_sim), clip=clip) # set the "beam" for the two images such that the samplint happens identically for iq in [iq_sca_obs, iq_sca_sim]: iq.bmaj, iq.bmin, iq.bpa = beam_sca iq.beamarea_arcsec = iq._calculate_beam_area_arcsec() iq.beamarea_str = iq._calculate_beam_area_str() # %% get the scattered light profile profiles_sca_sim = get_normalized_profiles(str(fname_sca_sim), clip=clip, inc=inc, PA=PA, z0=z0, psi=psi, beam=beam_sca) try: assert np.allclose(profiles_sca_obs['B']['x'], profiles_sca_sim['B']['x']) except Exception: # raise AssertionError('observed and simulated radial profile grids are not equal') warnings.warn( 'observed and simulated radial profile grids are not equal') try: from IPython import embed embed() except Exception: pass # TODO: calculate logP from the four profiles logP = -np.inf if debug: debug_info = { 'profiles_sca_sim': profiles_sca_sim, 'profiles_sca_obs': profiles_sca_obs, 'x_mm_sim': x_mm_sim, 'y_mm_sim': y_mm_sim, 'dy_mm_sim': dy_mm_sim, 'x_mm_obs': x_mm_obs, 'y_mm_obs': y_mm_obs, 'dy_mm_obs': dy_mm_obs, 'iq_mm_obs': iq_mm_obs, 'iq_mm_sim': iq_mm_sim, 'iq_sca_obs': iq_sca_obs, 'iq_sca_sim': iq_sca_sim, 'disk2d': disk2d, 'fname_sca_sim': fname_sca_sim, 'temp_path': temp_path, } return logP, debug_info else: return logP