def estimateCBResonances(s, r_max, m_max=5, l_max=5, bins=2500): """ Given pynbody snapshot star and gas SimArrays, computes the resonances of disk on binary as a function of period. Disk radius, in au, is convered to angular frequency which will then be used to compute corotation and inner/outer Lindblad resonances. Assumption: Assumes m_disk << m_bin which holds in general for simulations considered For reference: Kappa, omega computed in ~ 1/day intermediate units. Uses approximations from Artymowicz 1994 Inputs: stars,gas: Pynbody snapshot .star and .gas SimArrays (in au, Msol, etc) r_max: maximum disk radius for calculations (au) bins: number of radial bins to calculate over Output: Orbital frequency for corotation and inner/outer resonances as float and 2 arrays """ stars = s.stars #gas = s.gas #Compute binary angular frequency #Strip units from all inputs x1 = np.asarray(isaac.strip_units(stars[0]['pos'])) x2 = np.asarray(isaac.strip_units(stars[1]['pos'])) v1 = np.asarray(isaac.strip_units(stars[0]['vel'])) v2 = np.asarray(isaac.strip_units(stars[1]['vel'])) m1 = np.asarray(isaac.strip_units(stars[0]['mass'])) m2 = np.asarray(isaac.strip_units(stars[1]['mass'])) a = AddBinary.calcSemi(x1, x2, v1, v2, m1, m2) #omega_b = 2.0*np.pi/AddBinary.aToP(a,m1+m2 #Find corotation resonance where omega_d ~ omega_b r_c = a #m=1 case o_c = 2.0 * np.pi / AddBinary.aToP(r_c, m1 + m2) #Find inner lindblad resonances for m = [m_min,m_max] #Lindblad resonance: omega = omega_pattern +/- kappa/m for int m > 1 m_min = 1 l_min = 1 omega_Lo = np.zeros((m_max - m_min, l_max - l_min)) omega_Li = np.zeros((m_max - m_min, l_max - l_min)) #Find resonance radii, convert to angular frequency for m in range(m_min, m_max): for l in range(l_min, l_max): #oTmp = find_crit_radius(r,omega_d-(kappa/(float(m))),omega_b,bins) #outer LR oTmp = np.power(float(m + 1) / l, 2. / 3.) * a omega_Lo[m - m_min, l - l_min] = 2.0 * np.pi / AddBinary.aToP(oTmp, m1 + m2) #iTmp = find_crit_radius(r,omega_d+(kappa/(float(m))),omega_b,bins) #inner LR iTmp = np.power(float(m - 1) / l, 2. / 3.) * a omega_Li[m - m_min, l - l_min] = 2.0 * np.pi / AddBinary.aToP(iTmp, m1 + m2) return omega_Li, omega_Lo, o_c #return inner, outer, co angular frequencies
def estimateCBResonances(s,r_max,m_max=5,l_max=5,bins=2500): """ Given pynbody snapshot star and gas SimArrays, computes the resonances of disk on binary as a function of period. Disk radius, in au, is convered to angular frequency which will then be used to compute corotation and inner/outer Lindblad resonances. Assumption: Assumes m_disk << m_bin which holds in general for simulations considered For reference: Kappa, omega computed in ~ 1/day intermediate units. Uses approximations from Artymowicz 1994 Inputs: stars,gas: Pynbody snapshot .star and .gas SimArrays (in au, Msol, etc) r_max: maximum disk radius for calculations (au) bins: number of radial bins to calculate over Output: Orbital frequency for corotation and inner/outer resonances as float and 2 arrays """ stars = s.stars #gas = s.gas #Compute binary angular frequency #Strip units from all inputs x1 = np.asarray(isaac.strip_units(stars[0]['pos'])) x2 = np.asarray(isaac.strip_units(stars[1]['pos'])) v1 = np.asarray(isaac.strip_units(stars[0]['vel'])) v2 = np.asarray(isaac.strip_units(stars[1]['vel'])) m1 = np.asarray(isaac.strip_units(stars[0]['mass'])) m2 = np.asarray(isaac.strip_units(stars[1]['mass'])) a = AddBinary.calcSemi(x1, x2, v1, v2, m1, m2) #omega_b = 2.0*np.pi/AddBinary.aToP(a,m1+m2 #Find corotation resonance where omega_d ~ omega_b r_c = a #m=1 case o_c = 2.0*np.pi/AddBinary.aToP(r_c,m1+m2) #Find inner lindblad resonances for m = [m_min,m_max] #Lindblad resonance: omega = omega_pattern +/- kappa/m for int m > 1 m_min = 1 l_min = 1 omega_Lo = np.zeros((m_max-m_min,l_max-l_min)) omega_Li = np.zeros((m_max-m_min,l_max-l_min)) #Find resonance radii, convert to angular frequency for m in range(m_min,m_max): for l in range(l_min,l_max): #oTmp = find_crit_radius(r,omega_d-(kappa/(float(m))),omega_b,bins) #outer LR oTmp = np.power(float(m+1)/l,2./3.)*a omega_Lo[m-m_min,l-l_min] = 2.0*np.pi/AddBinary.aToP(oTmp,m1+m2) #iTmp = find_crit_radius(r,omega_d+(kappa/(float(m))),omega_b,bins) #inner LR iTmp = np.power(float(m-1)/l,2./3.)*a omega_Li[m-m_min,l-l_min] = 2.0*np.pi/AddBinary.aToP(iTmp,m1+m2) return omega_Li, omega_Lo, o_c #return inner, outer, co angular frequencies
def calc_LB_resonance(s,m_min=1,m_max=3,l_min=1,l_max=3): """ Computes the locations of various Lindblad Resonances in the disk as a function of binary pattern speed. Parameters ---------- s : Tipsy-format snapshot m_min, l_min : ints minimum orders of (m,l) LR m_max,l_max : ints maximum orders of (m,l) LR Returns ------- OLR, ILR, CR: numpy arrays location in AU of (m,l)th order Lindblad resonances """ #Compute binary angular frequency in 1/day x1 = s.stars[0]['pos'] x2 = s.stars[1]['pos'] v1 = s.stars[0]['vel'] v2 = s.stars[1]['vel'] m1 = s.stars[0]['mass'] m2 = s.stars[1]['mass'] omega_b = 2.0*np.pi/AddBinary.aToP(AddBinary.calcSemi(x1,x2,v1,v2,m1,m2),m1+m2) guess = 0.05 #fsolve initial guess parameter #Allocate space for arrays OLR = np.zeros((m_max,l_max)) ILR = np.zeros((m_max,l_max)) CR = np.zeros(l_max) #Define resonance functions def OLR_func(omega_d, *args): m = args[0] l = args[1] omega_b = args[2] return omega_d*(1.0 + float(l)/m) - omega_b #end function def ILR_func(omega_d, *args): m = args[0] l = args[1] omega_b = args[2] return omega_d*(1.0 - float(l)/m) - omega_b #end function def CR_func(omega_d, *args): l = args[0] omega_b = args[1] return omega_d - omega_b/float(l) #end function for m in range(m_min,m_max+1): for l in range(l_min,l_max+1): OLR[m-m_min,l-l_min] = fsolve(OLR_func,guess,args=(m,l,omega_b)) ILR[m-m_min,l-l_min] = fsolve(ILR_func,guess,args=(m,l,omega_b)) CR[l-l_min] = fsolve(CR_func,guess,args=(l,omega_b)) #Convert from 1/day -> au OLR = AddBinary.pToA(2.0*np.pi/OLR,m1+m2) ILR = AddBinary.pToA(2.0*np.pi/ILR,m1+m2) CR = AddBinary.pToA(2.0*np.pi/CR,m1+m2) return OLR, ILR, CR
def findCBResonances(s,r,r_min,r_max,m_max=4,l_max=4,bins=50): """ Given Tipsy snapshot, computes the resonances of disk on binary as a function of orbital angular frequency omega. Disk radius, in au, is convered to angular frequency which will then be used to compute corotation and inner/outer Lindblad resonances. Note: r given MUST correspond to r over which de/dt was calculated. Otherwise, scale gets all messed up !!! NOTE: This function is awful and deprecated --- do NOT use it. Instead, use calc_LB_resonance !!! Parameters ---------- s: Tipsy-format snapshot r: array radius array over which de/dt was calculated r_min,r_max: floats min/maximum disk radius for calculations (au) bins: int number of radial bins to calculate over m_max,l_max: ints maximum orders of (m,l) LR Returns ------- Orbital frequency: numpy array for corotation and inner/outer resonances and radii as float and numpy arrays """ stars = s.stars gas = s.gas m_min = 1 #m >=1 for LRs, CRs l_min = 1 #l >=1 for LRs, CRs #Compute binary angular frequency x1 = stars[0]['pos'] x2 = stars[1]['pos'] v1 = stars[0]['vel'] v2 = stars[1]['vel'] m1 = stars[0]['mass'] m2 = stars[1]['mass'] a = strip_units(AddBinary.calcSemi(x1, x2, v1, v2, m1, m2)) omega_b = 2.0*np.pi/AddBinary.aToP(a,m1+m2) #In units 1/day #Make r steps smaller for higher accuracy r_arr = np.linspace(r.min(),r.max(),len(r)*10) #Compute mass of disk interior to given r mask = np.zeros((len(gas),len(r_arr)),dtype=bool) m_disk = np.zeros(len(r_arr)) for i in range(0,len(r_arr)): mask[:,i] = gas['rxy'] < r_arr[i] m_disk[i] = np.sum(gas['mass'][mask[:,i]]) #Compute omega_disk in units 1/day (like omega_binary) omega_d = 2.0*np.pi/AddBinary.aToP(r_arr,m1+m2+m_disk) #Compute kappa (radial epicycle frequency = sqrt(r * d(omega^2)/dr + 4*(omega^2)) o2 = omega_d*omega_d dr = r_arr[1] - r_arr[0] #dr = (r.max()-r.min())/float(bins) #Assuming r has evenly spaced bins! drdo2 = np.gradient(o2,dr) #I mean d/dr(omega^2) kappa = np.sqrt(r_arr*drdo2 + 4.0*o2) #Allocate arrays for output omega_Lo = np.zeros((m_max,l_max)) omega_Li = np.zeros((m_max,l_max)) o_c = np.zeros(l_max) #Find resonance angular frequency for m in range(m_min,m_max+1): for l in range(l_min,l_max+1): outer = omega_d + (float(l)/m)*kappa inner = omega_d - (float(l)/m)*kappa omega_Lo[m-m_min,l-l_min] = omega_d[np.argmin(np.fabs(omega_b-outer))] omega_Li[m-m_min,l-l_min] = omega_d[np.argmin(np.fabs(omega_b-inner))] #Find corotation resonance where omega_d ~ omega_b o_c[l-l_min] = omega_d[np.argmin(np.fabs(omega_d-omega_b/float(l)))] #Rescale omega_d, kappa to be of length bins again omega_d = np.linspace(omega_d.min(),omega_d.max(),bins) kappa = np.linspace(kappa.min(),kappa.max(),bins) return omega_Li, omega_Lo, o_c, omega_d, kappa
def calc_LB_resonance(s, m_min=1, m_max=3, l_min=1, l_max=3): """ Computes the locations of various Lindblad Resonances in the disk as a function of binary pattern speed. Parameters ---------- s : Tipsy-format snapshot m_min, l_min : ints minimum orders of (m,l) LR m_max,l_max : ints maximum orders of (m,l) LR Returns ------- OLR, ILR, CR: numpy arrays location in AU of (m,l)th order Lindblad resonances """ #Compute binary angular frequency in 1/day x1 = s.stars[0]['pos'] x2 = s.stars[1]['pos'] v1 = s.stars[0]['vel'] v2 = s.stars[1]['vel'] m1 = s.stars[0]['mass'] m2 = s.stars[1]['mass'] omega_b = 2.0 * np.pi / AddBinary.aToP( AddBinary.calcSemi(x1, x2, v1, v2, m1, m2), m1 + m2) guess = 0.05 #fsolve initial guess parameter #Allocate space for arrays OLR = np.zeros((m_max, l_max)) ILR = np.zeros((m_max, l_max)) CR = np.zeros(l_max) #Define resonance functions def OLR_func(omega_d, *args): m = args[0] l = args[1] omega_b = args[2] return omega_d * (1.0 + float(l) / m) - omega_b #end function def ILR_func(omega_d, *args): m = args[0] l = args[1] omega_b = args[2] return omega_d * (1.0 - float(l) / m) - omega_b #end function def CR_func(omega_d, *args): l = args[0] omega_b = args[1] return omega_d - omega_b / float(l) #end function for m in range(m_min, m_max + 1): for l in range(l_min, l_max + 1): OLR[m - m_min, l - l_min] = fsolve(OLR_func, guess, args=(m, l, omega_b)) ILR[m - m_min, l - l_min] = fsolve(ILR_func, guess, args=(m, l, omega_b)) CR[l - l_min] = fsolve(CR_func, guess, args=(l, omega_b)) #Convert from 1/day -> au OLR = AddBinary.pToA(2.0 * np.pi / OLR, m1 + m2) ILR = AddBinary.pToA(2.0 * np.pi / ILR, m1 + m2) CR = AddBinary.pToA(2.0 * np.pi / CR, m1 + m2) return OLR, ILR, CR
def findCBResonances(s, r, r_min, r_max, m_max=4, l_max=4, bins=50): """ Given Tipsy snapshot, computes the resonances of disk on binary as a function of orbital angular frequency omega. Disk radius, in au, is convered to angular frequency which will then be used to compute corotation and inner/outer Lindblad resonances. Note: r given MUST correspond to r over which de/dt was calculated. Otherwise, scale gets all messed up !!! NOTE: This function is awful and deprecated --- do NOT use it. Instead, use calc_LB_resonance !!! Parameters ---------- s: Tipsy-format snapshot r: array radius array over which de/dt was calculated r_min,r_max: floats min/maximum disk radius for calculations (au) bins: int number of radial bins to calculate over m_max,l_max: ints maximum orders of (m,l) LR Returns ------- Orbital frequency: numpy array for corotation and inner/outer resonances and radii as float and numpy arrays """ stars = s.stars gas = s.gas m_min = 1 #m >=1 for LRs, CRs l_min = 1 #l >=1 for LRs, CRs #Compute binary angular frequency x1 = stars[0]['pos'] x2 = stars[1]['pos'] v1 = stars[0]['vel'] v2 = stars[1]['vel'] m1 = stars[0]['mass'] m2 = stars[1]['mass'] a = strip_units(AddBinary.calcSemi(x1, x2, v1, v2, m1, m2)) omega_b = 2.0 * np.pi / AddBinary.aToP(a, m1 + m2) #In units 1/day #Make r steps smaller for higher accuracy r_arr = np.linspace(r.min(), r.max(), len(r) * 10) #Compute mass of disk interior to given r mask = np.zeros((len(gas), len(r_arr)), dtype=bool) m_disk = np.zeros(len(r_arr)) for i in range(0, len(r_arr)): mask[:, i] = gas['rxy'] < r_arr[i] m_disk[i] = np.sum(gas['mass'][mask[:, i]]) #Compute omega_disk in units 1/day (like omega_binary) omega_d = 2.0 * np.pi / AddBinary.aToP(r_arr, m1 + m2 + m_disk) #Compute kappa (radial epicycle frequency = sqrt(r * d(omega^2)/dr + 4*(omega^2)) o2 = omega_d * omega_d dr = r_arr[1] - r_arr[0] #dr = (r.max()-r.min())/float(bins) #Assuming r has evenly spaced bins! drdo2 = np.gradient(o2, dr) #I mean d/dr(omega^2) kappa = np.sqrt(r_arr * drdo2 + 4.0 * o2) #Allocate arrays for output omega_Lo = np.zeros((m_max, l_max)) omega_Li = np.zeros((m_max, l_max)) o_c = np.zeros(l_max) #Find resonance angular frequency for m in range(m_min, m_max + 1): for l in range(l_min, l_max + 1): outer = omega_d + (float(l) / m) * kappa inner = omega_d - (float(l) / m) * kappa omega_Lo[m - m_min, l - l_min] = omega_d[np.argmin(np.fabs(omega_b - outer))] omega_Li[m - m_min, l - l_min] = omega_d[np.argmin(np.fabs(omega_b - inner))] #Find corotation resonance where omega_d ~ omega_b o_c[l - l_min] = omega_d[np.argmin( np.fabs(omega_d - omega_b / float(l)))] #Rescale omega_d, kappa to be of length bins again omega_d = np.linspace(omega_d.min(), omega_d.max(), bins) kappa = np.linspace(kappa.min(), kappa.max(), bins) return omega_Li, omega_Lo, o_c, omega_d, kappa
def findCBResonances(s, r, r_min, r_max, m_max=4, l_max=4, bins=50): """ Given Tipsy snapshot, computes the resonances of disk on binary as a function of orbital angular frequency omega. Disk radius, in au, is convered to angular frequency which will then be used to compute corotation and inner/outer Lindblad resonances. Note: r given MUST correspond to r over which de/dt was calculated. Otherwise, scale gets all messed up Parameters ---------- s: Tipsy-format snapshot r: array radius array over which de/dt was calculated r_min,r_max: floats min/maximum disk radius for calculations (au) bins: int number of radial bins to calculate over m_max,l_max: ints maximum orders of (m,l) LR Returns ------- Orbital frequency: numpy array for corotation and inner/outer resonances and radii as float and numpy arrays """ stars = s.stars m_min = 1 #m >=1 for LRs, CRs l_min = 1 #l >=1 for LRs, CRs #Compute binary angular frequency #Strip units from all inputs #x1 = np.asarray(isaac.strip_units(stars[0]['pos'])) #x2 = np.asarray(isaac.strip_units(stars[1]['pos'])) #v1 = np.asarray(isaac.strip_units(stars[0]['vel'])) #v2 = np.asarray(isaac.strip_units(stars[1]['vel'])) #m1 = np.asarray(isaac.strip_units(stars[0]['mass'])) #m2 = np.asarray(isaac.strip_units(stars[1]['mass'])) x1 = stars[0]['pos'] x2 = stars[1]['pos'] v1 = stars[0]['vel'] v2 = stars[1]['vel'] m1 = stars[0]['mass'] m2 = stars[1]['mass'] a = isaac.strip_units(AddBinary.calcSemi(x1, x2, v1, v2, m1, m2)) omega_b = 2.0 * np.pi / AddBinary.aToP(a, m1 + m2) #In units 1/day #Compute omega_disk in units 1/day (like omega_binary) omega_d = 2.0 * np.pi / AddBinary.aToP(r, m1 + m2) #Compute kappa (radial epicycle frequency = sqrt(r * d(omega^2)/dr + 4*(omega^2)) o2 = omega_d * omega_d dr = (r.max() - r.min()) / float(bins) #Assuming r has evenly spaced bins! drdo2 = np.gradient(o2, dr) #I mean d/dr(omega^2) kappa = np.sqrt(r * drdo2 + 4.0 * o2) #Allocate arrays for output omega_Lo = np.zeros((m_max, l_max)) omega_Li = np.zeros((m_max, l_max)) o_c = np.zeros(l_max) #Find resonance angular frequency for m in range(m_min, m_max + 1): for l in range(l_min, l_max + 1): outer = omega_d + (float(l) / m) * kappa inner = omega_d - (float(l) / m) * kappa omega_Lo[m - m_min, l - l_min] = omega_d[np.argmin(np.fabs(omega_b - outer))] omega_Li[m - m_min, l - l_min] = omega_d[np.argmin(np.fabs(omega_b - inner))] #Find corotation resonance where omega_d ~ omega_b o_c[l - l_min] = omega_d[np.argmin( np.fabs(omega_d - omega_b / float(l)))] return omega_Li, omega_Lo, o_c, omega_d, kappa
def findCBResonances(s,r,r_min,r_max,m_max=4,l_max=4,bins=50): """ Given Tipsy snapshot, computes the resonances of disk on binary as a function of orbital angular frequency omega. Disk radius, in au, is convered to angular frequency which will then be used to compute corotation and inner/outer Lindblad resonances. Note: r given MUST correspond to r over which de/dt was calculated. Otherwise, scale gets all messed up Parameters ---------- s: Tipsy-format snapshot r: array radius array over which de/dt was calculated r_min,r_max: floats min/maximum disk radius for calculations (au) bins: int number of radial bins to calculate over m_max,l_max: ints maximum orders of (m,l) LR Returns ------- Orbital frequency: numpy array for corotation and inner/outer resonances and radii as float and numpy arrays """ stars = s.stars m_min = 1 #m >=1 for LRs, CRs l_min = 1 #l >=1 for LRs, CRs #Compute binary angular frequency #Strip units from all inputs #x1 = np.asarray(isaac.strip_units(stars[0]['pos'])) #x2 = np.asarray(isaac.strip_units(stars[1]['pos'])) #v1 = np.asarray(isaac.strip_units(stars[0]['vel'])) #v2 = np.asarray(isaac.strip_units(stars[1]['vel'])) #m1 = np.asarray(isaac.strip_units(stars[0]['mass'])) #m2 = np.asarray(isaac.strip_units(stars[1]['mass'])) x1 = stars[0]['pos'] x2 = stars[1]['pos'] v1 = stars[0]['vel'] v2 = stars[1]['vel'] m1 = stars[0]['mass'] m2 = stars[1]['mass'] a = isaac.strip_units(AddBinary.calcSemi(x1, x2, v1, v2, m1, m2)) omega_b = 2.0*np.pi/AddBinary.aToP(a,m1+m2) #In units 1/day #Compute omega_disk in units 1/day (like omega_binary) omega_d = 2.0*np.pi/AddBinary.aToP(r,m1+m2) #Compute kappa (radial epicycle frequency = sqrt(r * d(omega^2)/dr + 4*(omega^2)) o2 = omega_d*omega_d dr = (r.max()-r.min())/float(bins) #Assuming r has evenly spaced bins! drdo2 = np.gradient(o2,dr) #I mean d/dr(omega^2) kappa = np.sqrt(r*drdo2 + 4.0*o2) #Allocate arrays for output omega_Lo = np.zeros((m_max,l_max)) omega_Li = np.zeros((m_max,l_max)) o_c = np.zeros(l_max) #Find resonance angular frequency for m in range(m_min,m_max+1): for l in range(l_min,l_max+1): outer = omega_d + (float(l)/m)*kappa inner = omega_d - (float(l)/m)*kappa omega_Lo[m-m_min,l-l_min] = omega_d[np.argmin(np.fabs(omega_b-outer))] omega_Li[m-m_min,l-l_min] = omega_d[np.argmin(np.fabs(omega_b-inner))] #Find corotation resonance where omega_d ~ omega_b o_c[l-l_min] = omega_d[np.argmin(np.fabs(omega_d-omega_b/float(l)))] return omega_Li, omega_Lo, o_c, omega_d, kappa