def ok(self): """ Checks for silly parameter values. Runnning this before chisq could save time and disaster """ return self.vcheck('q', 0.001, 100.) and self.vcheck('iangle', 0., 90.) and \ self.vcheck('r1',0.,1.) and \ (float(self['r2'][0]) <= 0. or self.vcheck('r2',0.,1-roche.xl1(float(self['q'][0])))) and \ self.vcheck('cphi3',0.,0.25) and self.vcheck('cphi4',float(self['cphi3'][0]),0.25) and \ self.vcheck('t1',0.,1.e6) and self.vcheck('t2',-1.e6,1.e6) and \ self.vcheck('ldc1_1',-20.,20.) and self.vcheck('ldc1_2',-20.,20.) and \ self.vcheck('ldc1_3',-20.,20.) and self.vcheck('ldc1_4',-20.,20.) and \ self.vcheck('ldc2_1',-20.,20.) and self.vcheck('ldc2_2',-20.,20.) and \ self.vcheck('ldc2_3',-20.,20.) and self.vcheck('ldc2_3',-20.,20.) and \ self.vcheck('period',0.,100.) and self.vcheck('gravity_dark1',0.,1.) and \ self.vcheck('gravity_dark2',0.,1.) and \ (self['add_disc'][0] == '0' or \ ((float(self['rdisc1'][0]) <= 0. or self.vcheck('rdisc1',float(self['r1'][0]),1.0)) \ and (float(self['rdisc2'][0]) <= 0. or \ self.vcheck('rdisc2',float(self['rdisc1'][0]),1.)) and \ self.vcheck('temp_disc',0.,1.e6) and self.vcheck('texp_disc',-10.,10.))) and \ (self['add_spot'][0] == '0' or \ (self.vcheck('radius_spot',0.,0.85*roche.xl1(float(self['q'][0]))) and \ self.vcheck('length_spot',0.,10.) and \ self.vcheck('expon_spot',0.,30.) and self.vcheck('temp_spot',0.,1.e6) and \ self.vcheck('cfrac_spot',0.,1.) and self.vcheck('epow_spot',0.,10.)))
def ln_prior(pars): lnp = 0.0 # mass ratio - be loose (B12 says about 0.15) prior = Prior("uniform", 0.02, 0.3) lnp += prior.ln_prob(pars[0]) # r1_a (B12) prior = Prior("gaussPos", 0.0213, 0.0015) lnp += prior.ln_prob(pars[1]) # limb darkening prior = Prior("gaussPos", 0.32, 0.03) lnp += prior.ln_prob(pars[2]) # size of donor (B12) prior = Prior("gaussPos", 0.113, 0.02) # is donor bigger than roche lobe? if pars[0] <= 0 or pars[3] > 1.0 - roche.xl1(pars[0]): lnp += -np.inf else: lnp += prior.ln_prob(pars[3]) # inclination (B12) prior = Prior("gaussPos", 85.9, 1.0) if pars[4] >= 90.0: lnp += -np.inf else: lnp += prior.ln_prob(pars[4]) # wd flux prior = Prior("uniform", 0.01, 0.05) lnp += prior.ln_prob(pars[5]) # donor flux prior = Prior("uniform", 0.00, 0.01) lnp += prior.ln_prob(pars[6]) # phase offset prior = Prior("uniform", -0.01, 0.01) lnp += prior.ln_prob(pars[7]) return lnp
def solve(input_data,baseDir): q,dphi,rw,twd,p = input_data # Kepler's law gives a quantity related to wd mass and separation, a # scaled_mass = a**3/M_wd. I call this the scaled mass. scaled_mass = const.G * (1+q) * p**2 / 4.0 / np.pi**2 # convert white dwarf radius to units of separation, rw/a xl1_a = roche.xl1(q) rw_a = rw*xl1_a solved = True try: # try wood models mw = find_wdmass(twd,scaled_mass,rw_a,baseDir,model='wood') except: # try panei models (usually for masses above 1 Msun) try: mw = find_wdmass(twd,scaled_mass,rw_a,baseDir,model='panei') except: # try hamada models (for masses less than 0.4 or more than 1.2 Msun) try: mw=find_wdmass(twd,scaled_mass,rw_a,baseDir,model='hamada') except: solved = False # do nothing if none of the models yielded a solution # otherwise, if solved: # donor star mass mr = mw*q # from this wd mass and scaled mass, find a a3 = scaled_mass*mw a = a3**(1./3.) a = a.to(units.R_sun) # inc inc = roche.findi(q,dphi) sini = np.sin(np.radians(inc)) # radial velocities kw = (2.0*np.pi*sini*q*a/(1+q)/p).to(units.km/units.s) kr = kw/q #secondary radius #use from Warner 1995 (eggleton) #radius of sphere with same volume as Roche Lobe... r2 = 0.49*a*q**(2.0/3.0) r2 /= 0.6 * q**(2.0/3.0) + np.log(1.0+q**(1.0/3.0)) # need to be a little careful here for different versions of astropy data = (q,mw,rw_a*a,mr,r2,a,kw,kr,inc) if not quantitySupport: data = [getval(datum) for datum in data] return data else: return None
def ok(self): """ Checks for silly parameter values. Runnning this before chisq could save time and disaster. """ return ( self.vcheck('q', 0.001, 100.) and self.vcheck('iangle', 0., 90.) and self.vcheck('r1', 0., 1.) and (float(self['r2'][0]) <= 0. or self.vcheck('r2', 0., 1 - roche.xl1(float(self['q'][0])))) and self.vcheck('cphi3', 0., 0.25) and self.vcheck('cphi4', float(self['cphi3'][0]), 0.25) and self.vcheck('t1', 0., 1.e6) and self.vcheck('t2', -1.e6, 1.e6) and self.vcheck('ldc1_1', -50., 50.) and self.vcheck('ldc1_2', -50., 50.) and self.vcheck('ldc1_3', -50., 50.) and self.vcheck('ldc1_4', -50., 50.) and self.vcheck('ldc2_1', -50., 50.) and self.vcheck('ldc2_2', -50., 50.) and self.vcheck('ldc2_3', -50., 50.) and self.vcheck('ldc2_3', -50., 50.) and self.vcheck('period', 0., 100.) and self.vcheck('gravity_dark1', 0., 5.) and self.vcheck('gravity_dark2', 0., 5.) and (self['add_disc'][0] == '0' or ((float(self['rdisc1'][0]) <= 0. or self.vcheck('rdisc1', float(self['r1'][0]), 1.0)) and (float(self['rdisc2'][0]) <= 0. or self.vcheck('rdisc2', float(self['rdisc1'][0]), 1.)) and self.vcheck('temp_disc', 0., 1.e6) and self.vcheck('texp_disc', -10., 10.))) and (self['add_spot'][0] == '0' or (self.vcheck('radius_spot', 0., 0.85 * roche.xl1( float(self['q'][0]))) and self.vcheck('length_spot', 0., 10.) and self.vcheck('expon_spot', 0., 30.) and self.vcheck( 'temp_spot', 0., 1.e6) and self.vcheck('cfrac_spot', 0., 1.) and self.vcheck('epow_spot', 0., 10.))))
def solve(input_data, baseDir): q, dphi, rw, twd, p = input_data # Kepler's law gives a quantity related to wd mass and separation, a # scaled_mass = a**3/M_wd. I call this the scaled mass. scaled_mass = const.G * (1 + q) * p**2 / 4.0 / np.pi**2 # convert white dwarf radius to units of separation, rw/a xl1_a = roche.xl1(q) rw_a = rw * xl1_a solved = True try: # try wood models mw = find_wdmass(twd, scaled_mass, rw_a, baseDir, model='wood') except: # try panei models (usually for masses above 1 Msun) try: mw = find_wdmass(twd, scaled_mass, rw_a, baseDir, model='panei') except: # try hamada models (for masses less than 0.4 or more than 1.2 Msun) try: mw = find_wdmass(twd, scaled_mass, rw_a, baseDir, model='hamada') except: solved = False # do nothing if none of the models yielded a solution # otherwise, if solved: # donor star mass mr = mw * q # from this wd mass and scaled mass, find a a3 = scaled_mass * mw a = a3**(1. / 3.) a = a.to(units.R_sun) # inc inc = roche.findi(q, dphi) sini = np.sin(np.radians(inc)) # radial velocities kw = (2.0 * np.pi * sini * q * a / (1 + q) / p).to(units.km / units.s) kr = kw / q #secondary radius #use from Warner 1995 (eggleton) #radius of sphere with same volume as Roche Lobe... r2 = 0.49 * a * q**(2.0 / 3.0) r2 /= 0.6 * q**(2.0 / 3.0) + np.log(1.0 + q**(1.0 / 3.0)) # need to be a little careful here for different versions of astropy data = (q, mw, rw_a * a, mr, r2, a, kw, kr, inc) if not quantitySupport: data = [getval(datum) for datum in data] return data else: return None
def ln_prior(self,verbose=False): """Returns the natural log of the prior probability of this model. Certain parameters (dphi, rdisc, scale, az) need to be treated as special cases, as the model contains more prior information than included in the parameter priors""" # Use of the super function allows abstract class in model.py to be referenced # Here the ln_prior function is referenced retVal = super(LCModel,self).ln_prior() # Remaining part of this function deals with special cases # dphi tol = 1.0e-6 try: # Uses getParam function from model.py to get the objects of variable parameters q = self.getParam('q') dphi = self.getParam('dphi') # maxphi is dphi when i = 90 maxphi = roche.findphi(q.currVal,90.0) # dphi cannot be greater than (or within a certain tolerance of) maxphi if dphi.currVal > maxphi-tol: if verbose: print('Combination of q and dphi is invalid') retVal += -np.inf except: # We get here when roche.findphi raises error - usually invalid q retVal += -np.inf if verbose: print('Combination of q and dphi is invalid') # rdisc try: xl1 = roche.xl1(q.currVal) # xl1/a maxrdisc = 0.46/xl1 # Maximum size disc can reach before precessing # rdisc is unique to each eclipse, so have to use slightly different method to # obtain its object, compared to q and dphi which are shared parameters rdiscTemplate = 'rdisc_{0}' for iecl in range(self.necl): rdisc = self.getParam(rdiscTemplate.format(iecl)) # rdisc cannot be greater than maxrdisc if rdisc.currVal > maxrdisc: retVal += -np.inf except: # We get here when roche.findphi raises error - usually invalid q if verbose: print('Rdisc and q imply disc does not hit stream') retVal += -np.inf #BS scale rwd = self.getParam('rwd') minscale = rwd.currVal/3 # Minimum BS scale equal to 1/3 of rwd maxscale = rwd.currVal*3 # Maximum BS scale equal to 3x rwd scaleTemplate = 'scale_{0}' for iecl in range(self.necl): scale = self.getParam(scaleTemplate.format(iecl)) # BS scale must be within allowed range if scale.currVal < minscale or scale.currVal > maxscale: retVal += -np.inf if verbose: print('BS Scale is not between 1/3 and 3 times WD size') #BS az slope = 80.0 try: # Find position of bright spot where it hits disc azTemplate = 'az_{0}' for iecl in range(self.necl): rdisc = self.getParam(rdiscTemplate.format(iecl)) rd_a = rdisc.currVal*xl1 # rdisc/a az = self.getParam(azTemplate.format(iecl)) # Does stream miss disc? (rdisc/a < 0.2 or rdisc/a > 0.65 ) # If yes, Tom's code will fail # Calculate position of BS x,y,vx,vy = roche.bspot(q.currVal,rd_a) # Find tangent to disc at this point alpha = np.degrees(np.arctan2(y,x)) # Alpha is between -90 and 90. If negative, spot lags disc (i.e. alpha > 90) if alpha < 0: alpha = 90 - alpha tangent = alpha + 90 # Disc tangent # Calculate minimum and maximum az values using tangent and slope minaz = max(0,tangent-slope) maxaz = min(178,tangent+slope) # BS az must be within allowed range if az.currVal < minaz or az.currVal > maxaz: retVal += -np.inf except: if verbose: print('Stream does not hit disc, or az is outside 80 degree tolerance') # We get here when roche.findphi raises error - usually invalid q retVal += -np.inf if complex: # BS exponential parameters # Total extent of bright spot is scale*(e1/e2)**(1/e2) # Limit this to half an inner lagrangian distance scaleTemplate = 'scale_{0}' exp1Template = 'exp1_{0}' exp2Template = 'exp2_{0}' for iecl in range(self.necl): sc = self.getParam(scaleTemplate.format(iecl)) e1 = self.getParam(exp1Template.format(iecl)) e2 = self.getParam(exp2Template.format(iecl)) if sc.currVal*(e1.currVal/e2.currVal)**(1.0/e2.currVal) > 0.5: retVal += -np.inf return retVal
from __future__ import print_function import matplotlib.pyplot as plt import numpy as np from trm import roche import sys import lfit import time import os phi = np.linspace(-0.15,0.2,1000,endpoint=False) width = np.mean(np.diff(phi))*np.ones_like(phi)/2. q = 0.1 inc = 85.9 xl1 = roche.xl1(q) dphi = roche.findphi(q,inc) rwd = 0.01 rdisc = 0.6 rexp = 0.2 az = 157.0 frac = 0.2 scale = 0.039 exp1 = 2.0 exp2 = 1.0 tilt = 120.0 yaw = 1.0 start = time.clock() w = lfit.PyWhiteDwarf(rwd,0.4)
import numpy as np from trm import roche import sys import lfit import time import commands import os q = 0.1 inc = 86.9 phi = np.linspace(-0.5, 0.5, 1000) width = np.mean(np.diff(phi)) * np.ones_like(phi) / 2.0 xl1 = roche.xl1(q) dphi = roche.findphi(q, inc) rwd = 0.01 # r1_a w = lfit.PyWhiteDwarf(rwd / xl1, 0.4) rdisc = 0.6 rexp = 0.2 d = lfit.PyDisc(q, rwd / xl1, rdisc, rexp, 1000) az = 157.0 frac = 0.2 scale = 0.039 exp1 = 2.0 exp2 = 1.0 tilt = 120.0 yaw = 1.0
def ln_prior_base(pars): lnp = 0.0 #Wd flux prior = Prior('uniform',0.001,2) lnp += prior.ln_prob(pars[0]) #Disc flux prior = Prior('uniform',0.001,2) lnp += prior.ln_prob(pars[1]) #BS flux prior = Prior('uniform',0.001,2) lnp += prior.ln_prob(pars[2]) #Donor flux prior = Prior('uniform',0.0,2) lnp += prior.ln_prob(pars[3]) #Mass ratio prior = Prior('uniform',0.001,3.5) lnp += prior.ln_prob(pars[4]) #Wd eclipse width, dphi tol = 1.0e-6 try: maxphi = roche.findphi(pars[4],90.0) #dphi when i is slightly less than 90 prior = Prior('uniform',0.001,maxphi-tol) lnp += prior.ln_prob(pars[5]) except: # we get here when roche.findphi raises error - usually invalid q lnp += -np.inf #Disc radius (XL1) try: xl1 = roche.xl1(pars[4]) # xl1/a prior = Prior('uniform',0.25,0.46/xl1) # maximum size disc can be without precessing lnp += prior.ln_prob(pars[6]) except: # we get here when roche.findphi raises error - usually invalid q lnp += -np.inf #Limb darkening prior = Prior('gauss',0.39,0.005) lnp += prior.ln_prob(pars[7]) #Wd radius (XL1) prior = Prior('uniform',0.0001,0.1) lnp += prior.ln_prob(pars[8]) #BS scale (XL1) rwd = pars[8] prior = Prior('log_uniform',rwd/3.,rwd*3.) lnp += prior.ln_prob(pars[9]) #BS az slop=40.0 try: # find position of bright spot where it hits disc # will fail if q invalid xl1 = roche.xl1(pars[4]) # xl1/a rd_a = pars[6]*xl1 # Does stream miss disc? (disc/a < 0.2 or > 0.65 ) # if so, Tom's code will fail x,y,vx,vy = roche.bspot(pars[4],rd_a) # find tangent to disc at this point alpha = np.degrees(np.arctan2(y,x)) # alpha is between -90 and 90. if negative spot lags disc ie alpha > 90 if alpha < 0: alpha = 90-alpha tangent = alpha + 90 # disc tangent prior = Prior('uniform',max(0,tangent-slop),min(178,tangent+slop)) lnp += prior.ln_prob(pars[10]) except: lnp += -np.inf #BS isotropic fraction prior = Prior('uniform',0.001,0.9) lnp += prior.ln_prob(pars[11]) #Disc exponent prior = Prior('uniform',0.0001,2.5) lnp += prior.ln_prob(pars[12]) #Phase offset prior = Prior('uniform',-0.1,0.1) lnp += prior.ln_prob(pars[13]) if len(pars) > 14: #BS exp1 prior = Prior('uniform',0.01,4.0) lnp += prior.ln_prob(pars[14]) #BS exp2 prior = Prior('uniform',0.9,3.0) lnp += prior.ln_prob(pars[15]) #BS tilt angle prior = Prior('uniform',0.0,165.0) lnp += prior.ln_prob(pars[16]) #BS yaw angle prior = Prior('uniform',-90,90.0) lnp += prior.ln_prob(pars[17]) return lnp