Ejemplo n.º 1
0
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
Ejemplo n.º 2
0
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
Ejemplo n.º 3
0
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
Ejemplo n.º 4
0
                        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) +
Ejemplo n.º 5
0
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()
"""

Ejemplo n.º 6
0
# 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)
Ejemplo n.º 7
0
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)
Ejemplo n.º 8
0
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]
Ejemplo n.º 9
0
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