def generate(ngen, surveyList=None, pDistType='lnorm', radialDistType='lfl06', radialDistPars=7.5, electronModel='ne2001', pDistPars=[2.7, -0.34], siDistPars=[-1.6, 0.35], lumDistType='lnorm', lumDistPars=[-1.1, 0.9], zscaleType='exp', zscale=0.33, duty_percent=6., scindex=-3.86, gpsArgs=[None, None], doubleSpec=[None, None], nostdout=False, pattern='gaussian', orbits=False): """ Generate a population of pulsars. Keyword args: ngen -- the number of pulsars to generate (or detect) surveyList -- a list of surveys you want to use to try and detect the pulsars pDistType -- the pulsar period distribution model to use (def=lnorm) radialDistType -- radial distribution model electronModel -- mode to use for Galactic electron distribution pDistPars -- parameters to use for period distribution siDistPars -- parameters to use for spectral index distribution lumDistPars -- parameters to use for luminosity distribution radialDistPars -- parameters for radial distribution zscale -- if using exponential z height, set it here (in kpc) scindex -- spectral index of the scattering model gpsArgs -- add GPS-type spectrum sources doubleSpec -- add double-spectrum type sources nostdout -- (bool) switch off stdout """ pop = Population() # check that the distribution types are supported.... if lumDistType not in ['lnorm', 'pow']: print "Unsupported luminosity distribution: {0}".format(lumDistType) if pDistType not in ['lnorm', 'norm', 'cc97', 'lorimer12']: print "Unsupported period distribution: {0}".format(pDistType) if radialDistType not in ['lfl06', 'yk04', 'isotropic', 'slab', 'disk', 'gauss']: print "Unsupported radial distribution: {0}".format(radialDistType) if electronModel not in ['ne2001', 'lmt85']: print "Unsupported electron model: {0}".format(electronModel) if pattern not in ['gaussian', 'airy']: print "Unsupported gain pattern: {0}".format(pattern) if duty_percent < 0.: print "Unsupported value of duty cycle: {0}".format(duty_percent) # need to use properties in this class so they're get/set-type props pop.pDistType = pDistType pop.radialDistType = radialDistType pop.electronModel = electronModel pop.lumDistType = lumDistType pop.rsigma = radialDistPars pop.pmean, pop.psigma = pDistPars pop.simean, pop.sisigma = siDistPars pop.gpsFrac, pop.gpsA = gpsArgs pop.brokenFrac, pop.brokenSI = doubleSpec if pop.lumDistType == 'lnorm': pop.lummean, pop.lumsigma = \ lumDistPars[0], lumDistPars[1] else: try: pop.lummin, pop.lummax, pop.lumpow = \ lumDistPars[0], lumDistPars[1], lumDistPars[2] except ValueError: raise PopulateException('Not enough lum distn parameters') pop.zscaleType = zscaleType pop.zscale = zscale # store the dict of arguments inside the model. Could be useful. try: argspec = inspect.getargspec(generate) key_values = [(arg, locals()[arg]) for arg in argspec.args] pop.arguments = {key: value for (key, value) in key_values} except SyntaxError: pass if not nostdout: print "\tGenerating pulsars with parameters:" param_string_list = [] for key, value in key_values: s = ": ".join([key, str(value)]) param_string_list.append(s) # join this list of strings, and print it s = "\n\t\t".join(param_string_list) print "\t\t{0}".format(s) # set up progress bar for fun :) prog = ProgressBar(min_value=0, max_value=ngen, width=65, mode='dynamic') # create survey objects here and put them in a list if surveyList is not None: surveys = [Survey(s, pattern) for s in surveyList] # initialise these counters to zero for surv in surveys: surv.ndet = 0 # number detected surv.nout = 0 # number outside survey region surv.nsmear = 0 # number smeared out surv.ntf = 0 # number too faint # surv.gainpat=pattern else: # make an empty list here - makes some code just a little # simpler - can still loop over an empty list (ie zero times) surveys = [] while pop.ndet < ngen: # Declare new pulsar object p = Pulsar() # period, alpha, rho, width distribution calls # Start creating the pulsar! if pop.pDistType == 'lnorm': p.period = dists.drawlnorm(pop.pmean, pop.psigma) elif pop.pDistType == 'norm': p.period = random.gauss(pop.pmean, pop.psigma) elif pop.pDistType == 'cc97': p.period = _cc97() elif pop.pDistType == 'gamma': print "Gamma function not yet supported" sys.exit() elif pop.pDistType == 'lorimer12': p.period = _lorimer2012_msp_periods() if duty_percent > 0.: # use a simple duty cycle for each pulsar # with a log-normal scatter width = (float(duty_percent)/100.) * p.period**0.9 width = math.log10(width) width = dists.drawlnorm(width, 0.3) p.width_degree = width*360./p.period else: # use the model to caculate if beaming p.alpha = _genAlpha() p.rho, p.width_degree = _genRhoWidth(p) if p.width_degree == 0.0 and p.rho == 0.0: continue # is pulsar beaming at us? If not, move on! p.beaming = _beaming(p) if not p.beaming: continue # Spectral index stuff here # suppose it might be nice to be able to have GPS sources # AND double spectra. But for now I assume only have one or # none of these types. if random.random() > pop.gpsFrac: # This will evaluate true when gpsArgs[0] is NoneType # might have to change in future p.gpsFlag = 0 else: p.gpsFlag = 1 p.gpsA = pop.gpsA if random.random() > pop.brokenFrac: p.brokenFlag = 0 else: p.brokenFlag = 1 p.brokenSI = pop.brokenSI p.spindex = random.gauss(pop.simean, pop.sisigma) # get galactic position # first, Galactic distribution models if pop.radialDistType == 'isotropic': # calculate gl and gb randomly p.gb = math.degrees(math.asin(random.random())) if random.random() < 0.5: p.gb = 0.0 - p.gb p.gl = random.random() * 360.0 # use gl and gb to compute galactic coordinates # pretend the pulsar is at distance of 1kpc # not sure why, ask Dunc! p.galCoords = go.lb_to_xyz(p.gl, p.gb, 1.0) elif pop.radialDistType == 'slab': p.galCoords = go.slabDist() p.gl, p.gb = go.xyz_to_lb(p.galCoords) elif pop.radialDistType == 'disk': p.galCoords = go.diskDist() p.gl, p.gb = go.xyz_to_lb(p.galCoords) else: # we want to use exponential z and a radial dist if pop.radialDistType == 'lfl06': p.r0 = go.lfl06() elif pop.radialDistType == 'yk04': p.r0 = go.ykr() elif pop.radialDistType == 'gauss': # guassian of mean 0 # and stdDev given by parameter (kpc) p.r0 = random.gauss(0., pop.rsigma) # then calc xyz,distance, l and b if pop.zscaleType == 'exp': zheight = go._double_sided_exp(zscale) else: zheight = random.gauss(0., zscale) gx, gy = go.calcXY(p.r0) p.galCoords = gx, gy, zheight p.gl, p.gb = go.xyz_to_lb(p.galCoords) p.dtrue = go.calc_dtrue(p.galCoords) # then calc DM using fortran libs if pop.electronModel == 'ne2001': p.dm = go.ne2001_dist_to_dm(p.dtrue, p.gl, p.gb) elif pop.electronModel == 'lmt85': p.dm = go.lmt85_dist_to_dm(p.dtrue, p.gl, p.gb) p.scindex = scindex # then calc scatter time p.t_scatter = go.scatter_bhat(p.dm, p.scindex) if pop.lumDistType == 'lnorm': p.lum_1400 = dists.drawlnorm(pop.lummean, pop.lumsigma) else: p.lum_1400 = dists.powerlaw(pop.lummin, pop.lummax, pop.lumpow) # add in orbital parameters if orbits: orbitalparams.test_1802_2124(p) print p.gb, p.gl # if no surveys, just generate ngen pulsars if surveyList is None: pop.population.append(p) pop.ndet += 1 if not nostdout: prog.increment_amount() print prog, '\r', sys.stdout.flush() # if surveys are given, check if pulsar detected or not # in ANY of the surveys else: # just a flag to increment if pulsar is detected detect_int = 0 for surv in surveys: # do SNR calculation SNR = surv.SNRcalc(p, pop) if SNR > surv.SNRlimit: # SNR is over threshold # increment the flag # and survey ndetected detect_int += 1 surv.ndet += 1 continue elif SNR == -1: # pulse is smeared out surv.nsmear += 1 continue elif SNR == -2: # pulsar is outside survey region surv.nout += 1 continue else: # pulsar is just too faint surv.ntf += 1 continue # add the pulsar to the population pop.population.append(p) # if detected, increment ndet (for whole population) # and redraw the progress bar if detect_int: pop.ndet += 1 if not nostdout: prog.increment_amount() print prog, '\r', sys.stdout.flush() # print info to stdout if not nostdout: print "\n" print " Total pulsars = {0}".format(len(pop.population)) print " Total detected = {0}".format(pop.ndet) # print " Number not beaming = {0}".format(surv.nnb) for surv in surveys: print "\n Results for survey '{0}'".format(surv.surveyName) print " Number detected = {0}".format(surv.ndet) print " Number too faint = {0}".format(surv.ntf) print " Number smeared = {0}".format(surv.nsmear) print " Number outside survey area = {0}".format(surv.nout) return pop
def generate(ngen, surveyList=None, age_max=1.0E9, pDistPars=[.3, .15], bFieldPars=[12.65, 0.55], birthVPars=[0.0, 180.], siDistPars=[-1.6, 0.35], alignModel='orthogonal', lumDistType='fk06', lumDistPars=[-1.5, 0.5], alignTime=None, spinModel='fk06', beamModel='tm98', birthVModel='gaussian', electronModel='ne2001', braking_index=0, zscale=0.05, duty=5., scindex=-3.86, widthModel=None, nodeathline=False, efficiencycut=None, nostdout=False, nospiralarms=False, keepdead=False): pop = Population() # set the parameters in the population object pop.pmean, pop.psigma = pDistPars pop.bmean, pop.bsigma = bFieldPars if lumDistType == 'pow': try: pop.lummin, pop.lummax, pop.lumpow = \ lumDistPars[0], lumDistPars[1], lumDistPars[2] except ValueError: raise EvolveException('Not enough lum distn parameters for "pow"') elif lumDistType == 'fk06': pop.lumPar1, pop.lumPar2 = lumDistPars[0], lumDistPars[1] if len(lumDistPars) == 3: pop.lumPar3 = lumDistPars[2] else: pop.lumPar3 = 0.18 else: pop.lumPar1, pop.lumPar2 = lumDistPars pop.simean, pop.sisigma = siDistPars pop.birthvmean, pop.birthvsigma = birthVPars pop.alignModel = alignModel pop.alignTime = alignTime pop.spinModel = spinModel pop.beamModel = beamModel pop.birthVModel = birthVModel pop.electronModel = electronModel pop.braking_index = braking_index pop.deathline = not nodeathline pop.nospiralarms = nospiralarms pop.zscale = zscale if widthModel == 'kj07': print "\tLoading KJ07 models...." kj_p_vals, kj_pdot_vals, kj_dists = beammodels.load_kj2007_models() print "\tDone\n" if not nostdout: print "\tGenerating evolved pulsars with parameters:" print "\t\tngen = {0}".format(ngen) print "\t\tUsing electron distn model {0}".format( pop.electronModel) print "\n\t\tPeriod mean, sigma = {0}, {1}".format( pop.pmean, pop.psigma) print "\t\tLuminosity mean, sigma = {0}, {1}".format( pop.lummean, pop.lumsigma) print "\t\tSpectral index mean, sigma = {0}, {1}".format( pop.simean, pop.sisigma) print "\t\tGalactic z scale height = {0} kpc".format( pop.zscale) if widthModel is None: print "\t\tWidth {0}% ".format(duty) else: print "\t\tUsing Karastergiou & Johnston beam width model" # set up progress bar for fun :) prog = ProgressBar(min_value=0, max_value=ngen, width=65, mode='dynamic') # create survey objects here and put them in a list if surveyList is not None: surveys = [Survey(s) for s in surveyList] else: # make an empty list here - makes some code just a little # simpler - can still loop over an empty list (ie zero times) surveys = [] # initialise these counters to zero for surv in surveys: surv.ndet = 0 # number detected surv.nout = 0 # number outside survey region surv.nsmear = 0 # number smeared out surv.ntf = 0 # number too faint # this is the nitty-gritty loop for generating the pulsars while pop.ndet < ngen: pulsar = Pulsar() # initial age for pulsar pulsar.age = random.random() * age_max # initial period pulsar.p0 = -1. while pulsar.p0 <= 0.: pulsar.p0 = random.gauss(pop.pmean, pop.psigma) # initial magnetic field (in Gauss) pulsar.bfield_init = 10**random.gauss(pop.bmean, pop.bsigma) # aligment angle alignpulsar(pulsar, pop) # braking index if pop.braking_index == 0: pulsar.braking_index = 2.5 + 0.5 * random.random() else: pulsar.braking_index = float(pop.braking_index) # apply relevant spin down model pulsar.dead = False # pulsar should start alive! if pop.spinModel == 'fk06': spindown_fk06(pulsar) # apply deathline if relevant if pop.deathline: bhattacharya_deathperiod_92(pulsar) elif pop.spinModel == 'cs06': # contopoulos and spitkovsky spindown_cs06(pulsar, pop) # if period > 10 seconds, just try a new one if pulsar.period > 10000.0 or pulsar.period < 10.: continue # cut on pdot too - this doesn't help if pulsar.pdot > 1.e-11 or pulsar.pdot < 1.e-18: continue # define pulse width (default = 6% = 18 degrees) if widthModel is None: width = (float(duty)/100.) * pulsar.period**0.9 width = math.log10(width) width = dists.drawlnorm(width, 0.3) elif widthModel == 'kj07': # Karastergiou & Johnston beam model # find closest p, pdot in the kj lists logp = math.log10(pulsar.period) logpdot = math.log10(pulsar.pdot) p_idx = (np.abs(kj_p_vals - logp)).argmin() pd_idx = (np.abs(kj_pdot_vals - logpdot)).argmin() # pick a width from relevant model dist = kj_dists[p_idx][pd_idx][2] width = np.random.choice(dist) """ width = beammodels.kj2007_width(pulsar) no_width = 0 while width == 0.0: no_width+=1 width = beammodels.kj2007_width(pulsar) # if we get to five, then try a new pulsar if no_width == 5: no_width = 0 continue """ else: print "Undefined width model!" sys.exit() # print width # print pulsar.period, width, pulsar.pdot if width == 0.0: # some kj2007 models make many zero-width sources. Skip! continue pulsar.width_degree = 360. * width / pulsar.period # plough on - only if the pulsar isn't dead! if not pulsar.dead or keepdead: # is the pulsar beaming? pulsar_beaming(pulsar, pop.beamModel) # if not, then skip onto next pulsar if not pulsar.beaming: continue # position of the pulsar galacticDistribute(pulsar, pop) # birthvelocity birthVelocity(pulsar, pop) # model the xyz velocity go.vxyz(pulsar) # luminosity if lumDistType == 'fk06': luminosity_fk06(pulsar, alpha=pop.lumPar1, beta=pop.lumPar2, gamma=pop.lumPar3) elif lumDistType == 'lnorm': pulsar.lum_1400 = dists.drawlnorm(pop.lumPar1, pop.lumPar2) elif lumDistType == 'pow': pulsar.lum_1400 = dists.powerlaw(pop.lummin, pop.lummax, pop.lumpow) else: # something's wrong! raise EvolveException('Invalid luminosity distn selected') # apply efficiency cutoff if efficiencycut is not None: if pulsar.efficiency() > efficiencycut: pulsar.dead = True if not keepdead: continue # spectral index pulsar.spindex = random.gauss(pop.simean, pop.sisigma) # calculate galactic coords and distance pulsar.gl, pulsar.gb = go.xyz_to_lb(pulsar.galCoords) pulsar.dtrue = go.calc_dtrue(pulsar.galCoords) # then calc DM using fortran libs if pop.electronModel == 'ne2001': pulsar.dm = go.ne2001_dist_to_dm(pulsar.dtrue, pulsar.gl, pulsar.gb) elif pop.electronModel == 'lmt85': pulsar.dm = go.lmt85_dist_to_dm(pulsar.dtrue, pulsar.gl, pulsar.gb) else: raise EvolveException('Invalid electron dist model selected') pulsar.scindex = scindex pulsar.t_scatter = go.scatter_bhat(pulsar.dm, pulsar.scindex) # if surveys are given, check if pulsar detected or not # in ANY of the surveys if surveyList is not None: detect_int = 0 # just a flag if pulsar is detected for surv in surveys: SNR = surv.SNRcalc(pulsar, pop) if SNR > surv.SNRlimit: # SNR is over threshold # increment the flag # and survey ndetected detect_int += 1 surv.ndet += 1 continue elif SNR == -1: # pulse is smeared out surv.nsmear += 1 continue elif SNR == -2: # pulsar is outside survey region surv.nout += 1 continue else: # pulsar is just too faint surv.ntf += 1 continue # if detected, increment ndet (for whole population) # and redraw the progress bar if detect_int: pop.ndet += 1 # update the counter if not nostdout: prog.increment_amount() print prog, '\r', sys.stdout.flush() else: # no survey list, just add the pulsar to population, # and increment number of pulsars pop.ndet += 1 # update the counter if not nostdout: prog.increment_amount() print prog, '\r', sys.stdout.flush() # pulsar isn't dead, add to population! pop.population.append(pulsar) else: # pulsar is dead. If no survey list, # just increment number of pulsars if surveyList is None: pop.ndet += 1 # update the counter if not nostdout: prog.increment_amount() print prog, '\r', sys.stdout.flush() if not nostdout: print "\n\n" print " Total pulsars = {0}".format(len(pop.population)) print " Total detected = {0}".format(pop.ndet) for surv in surveys: print "\n Results for survey '{0}'".format(surv.surveyName) print " Number detected = {0}".format(surv.ndet) print " Number too faint = {0}".format(surv.ntf) print " Number smeared = {0}".format(surv.nsmear) print " Number outside survey area = {0}".format(surv.nout) # save list of arguments into the pop try: argspec = inspect.getargspec(generate) key_values = [(arg, locals()[arg]) for arg in argspec.args] pop.arguments = {key: value for (key, value) in key_values} except SyntaxError: pass return pop
def generate(ngen, surveyList=None, age_max=1.0E9, pDistPars=[.3, .15], bFieldPars=[12.65, 0.55], birthVPars=[0.0, 180.], siDistPars= [-1.6,0.35], alignModel='orthogonal', lumDistType='fk06', lumDistPars=[-1.5, 0.5], alignTime=None, spinModel = 'fk06', beamModel = 'tm98', birthVModel = 'gaussian', electronModel='ne2001', braking_index=0, zscale=0.33, duty=5., nodeathline=False, nostdout=False, nospiralarms=False): pop = Population() # set the parameters in the population object pop.pmean, pop.psigma = pDistPars pop.bmean, pop.bsigma = bFieldPars if lumDistType=='pow': try: pop.lummin, pop.lummax, pop.lumpow = \ lumDistPars[0], lumDistPars[1], lumDistPars[2] except ValueError: raise EvolveException('Not enough lum distn parameters') else: pop.lumPar1, pop.lumPar2 = lumDistPars pop.simean, pop.sisigma = siDistPars pop.birthvmean, pop.birthvsigma = birthVPars pop.alignModel = alignModel pop.alignTime= alignTime pop.spinModel = spinModel pop.beamModel = beamModel pop.birthVModel = birthVModel pop.electronModel = electronModel pop.braking_index = braking_index pop.nodeathline = nodeathline pop.nospiralarms = nospiralarms pop.zscale = zscale if not nostdout: print "\tGenerating evolved pulsars with parameters:" print "\t\tngen = {0}".format(ngen) print "\t\tUsing electron distn model {0}".format( pop.electronModel) print "\n\t\tPeriod mean, sigma = {0}, {1}".format( pop.pmean, pop.psigma) print "\t\tLuminosity mean, sigma = {0}, {1}".format( pop.lummean, pop.lumsigma) print "\t\tSpectral index mean, sigma = {0}, {1}".format( pop.simean, pop.sisigma) print "\t\tGalactic z scale height = {0} kpc".format( pop.zscale) print "\t\tWidth {0}% ".format(duty) # set up progress bar for fun :) prog = ProgressBar(min_value = 0, max_value=ngen, width=65, mode='dynamic') # create survey objects here and put them in a list if surveyList is not None: surveys = [Survey(s) for s in surveyList] else: # make an empty list here - makes some code just a little # simpler - can still loop over an empty list (ie zero times) surveys=[] # initialise these counters to zero for surv in surveys: surv.ndet =0 # number detected surv.nout=0 # number outside survey region surv.nsmear=0 # number smeared out surv.ntf=0 # number too faint # this is the nitty-gritty loop for generating the pulsars while pop.ndet < ngen: pulsar = Pulsar() # initial age for pulsar pulsar.age = random.random() * age_max # initial period pulsar.p0 = -1. while pulsar.p0 <= 0.: pulsar.p0 = random.gauss(pop.pmean, pop.psigma) # initial magnetic field (in Gauss) pulsar.bfield_init = 10**random.gauss(pop.bmean, pop.bsigma) # aligment angle alignpulsar(pulsar, pop) # braking index if pop.braking_index == 0: pulsar.braking_index = 2.5 + 0.5 * random.random() else: pulsar.braking_index = float(pop.braking_index) #apply relevant spin down model pulsar.dead = False # pulsar should start alive! if pop.spinModel == 'fk06': spindown_fk06(pulsar) # apply deathline if relevant if not pop.nodeathline: bhattacharya_deathperiod_92(pulsar) elif pop.spinModel == 'cs06': # contopoulos and spitkovsky spindown_cs06(pulsar, pop) # define pulse width (default = 5% = 18 degrees) pulsar.width_degree = 360. * duty /100. # plough on - only if the pulsar isn't dead! if not pulsar.dead: # is the pulsar beaming? pulsar_beaming(pulsar, pop.beamModel) # if not, then skip onto next pulsar if not pulsar.beaming: continue # position of the pulsar galacticDistribute(pulsar, pop) # birthvelocity birthVelocity(pulsar, pop) # model the xyz velocity go.vxyz(pulsar) # luminosity if lumDistType == 'fk06': luminosity_fk06(pulsar, alpha=pop.lumPar1, beta=pop.lumPar2) elif lumDistType == 'lnorm': pulsar.lum_1400 = populate._drawlnorm(pop.lumPar1, pop.lumPar2) elif lumDistType == 'pow': pulsar.lum_1400 = populate._powerlaw(pop.lummin, pop.lummax, pop.lumpow) else: # something's wrong! raise EvolveException('Invalid luminosity distn selected') # spectral index pulsar.spindex = random.gauss(pop.simean, pop.sisigma) # calculate galactic coords and distance pulsar.gl, pulsar.gb = go.xyz_to_lb(pulsar.galCoords) pulsar.dtrue = go.calc_dtrue(pulsar.galCoords) # then calc DM using fortran libs if pop.electronModel == 'ne2001': pulsar.dm = go.ne2001_dist_to_dm(pulsar.dtrue, pulsar.gl, pulsar.gb) elif pop.electronModel == 'lmt85': pulsar.dm = go.lmt85_dist_to_dm(pulsar.dtrue, pulsar.gl, pulsar.gb) # if surveys are given, check if pulsar detected or not # in ANY of the surveys if surveyList is not None: detect_int = 0 # just a flag if pulsar is detected for surv in surveys: SNR = surv.SNRcalc(pulsar, pop) if SNR > surv.SNRlimit: # SNR is over threshold # increment the flag # and survey ndetected detect_int += 1 surv.ndet += 1 continue elif SNR == -1: # pulse is smeared out surv.nsmear += 1 continue elif SNR == -2: # pulsar is outside survey region surv.nout += 1 continue else: #pulsar is just too faint surv.ntf += 1 continue # if detected, increment ndet (for whole population) # and redraw the progress bar if detect_int: pop.ndet += 1 # update the counter if not nostdout: prog.increment_amount() print prog, '\r', sys.stdout.flush() else: # no survey list, just add the pulsar to population, # and increment number of pulsars pop.ndet +=1 # update the counter if not nostdout: prog.increment_amount() print prog, '\r', sys.stdout.flush() # pulsar isn't dead, add to population! pop.population.append(pulsar) else: # pulsar is dead. If no survey list, # just increment number of pulsars if surveyList is None: pop.ndet += 1 # update the counter if not nostdout: prog.increment_amount() print prog, '\r', sys.stdout.flush() if not nostdout: print "\n\n" print " Total pulsars = {0}".format(len(pop.population)) print " Total detected = {0}".format(pop.ndet) for surv in surveys: print "\n Results for survey '{0}'".format(surv.surveyName) print " Number detected = {0}".format(surv.ndet) print " Number too faint = {0}".format(surv.ntf) print " Number smeared = {0}".format(surv.nsmear) print " Number outside survey area = {0}".format(surv.nout) return pop
def generate(ngen, surveyList=None, pDistType='lnorm', radialDistType='lfl06', radialDistPars=7.5, electronModel='ne2001', pDistPars=[2.7, -0.34], siDistPars=[-1.6, 0.35], lumDistType='lnorm', lumDistPars=[-1.1, 0.9], zscaleType='exp', zscale=0.33, duty_percent=6., scindex=-3.86, gpsArgs=[None, None], doubleSpec=[None, None], nostdout=False, pattern='gaussian', orbits=False, dgf=None, singlepulse=False, dither=False, accelsearch=False, jerksearch=False, sig_factor=10.0, brDistType='log_unif'): """ Generate a population of pulsars. Keyword args: ngen -- the number of pulsars to generate (or detect) surveyList -- a list of surveys you want to use to try and detect the pulsars pDistType -- the pulsar period distribution model to use (def=lnorm) radialDistType -- radial distribution model electronModel -- mode to use for Galactic electron distribution pDistPars -- parameters to use for period distribution siDistPars -- parameters to use for spectral index distribution lumDistPars -- parameters to use for luminosity distribution radialDistPars -- parameters for radial distribution zscale -- if using exponential z height, set it here (in kpc) scindex -- spectral index of the scattering model gpsArgs -- add GPS-type spectrum sources doubleSpec -- add double-spectrum type sources nostdout -- (bool) switch off stdout """ pop = Population() # check that the distribution types are supported.... if 'd_g' in (pDistType, lumDistType, zscaleType, radialDistType, brDistType) and dgf is None: print "Provide the distribution generation file" sys.exit() elif dgf != None: try: f = open(dgf, 'rb') except IOError: print "Could not open file {0}.".format(dgf) sys.exit() dgf_pop_load = cPickle.load(f) f.close() if lumDistType not in ['lnorm', 'pow', 'log_unif', 'd_g', 'log_st']: print "Unsupported luminosity distribution: {0}".format(lumDistType) if brDistType not in ['log_unif', 'd_g']: print "Unsupported burst rate distribution: {0}".format(brDistType) if pDistType not in ['lnorm', 'norm', 'cc97', 'lorimer12', 'unif', 'd_g']: print "Unsupported period distribution: {0}".format(pDistType) if radialDistType not in [ 'lfl06', 'yk04', 'isotropic', 'slab', 'disk', 'unif', 'gauss', 'd_g', 'gamma' ]: print "Unsupported radial distribution: {0}".format(radialDistType) if electronModel not in ['ne2001', 'lmt85', 'ymw16']: print "Unsupported electron model: {0}".format(electronModel) if pattern not in ['gaussian', 'airy']: print "Unsupported gain pattern: {0}".format(pattern) if duty_percent < 0.: print "Unsupported value of duty cycle: {0}".format(duty_percent) # need to use properties in this class so they're get/set-type props pop.pDistType = pDistType pop.radialDistType = radialDistType pop.electronModel = electronModel pop.lumDistType = lumDistType pop.rsigma = radialDistPars pop.pmean, pop.psigma = pDistPars pop.simean, pop.sisigma = siDistPars pop.gpsFrac, pop.gpsA = gpsArgs pop.brokenFrac, pop.brokenSI = doubleSpec if pop.lumDistType == 'lnorm': pop.lummean, pop.lumsigma = \ lumDistPars[0], lumDistPars[1] elif pop.lumDistType == 'log_unif': pop.lumlow, pop.lumhigh = \ lumDistPars[0], lumDistPars[1] elif pop.lumDistType == 'log_st': try: pop.lumlow, pop.lumhigh, pop.lumslope = \ lumDistPars[0], lumDistPars[1], lumDistPars[2] except ValueError: raise PopulateException('Not enough lum distn parameters') elif pop.lumDistType == 'd_g': pass else: try: pop.lummin, pop.lummax, pop.lumpow = \ lumDistPars[0], lumDistPars[1], lumDistPars[2] except ValueError: raise PopulateException('Not enough lum distn parameters') pop.zscaleType = zscaleType pop.zscale = zscale # store the dict of arguments inside the model. Could be useful. try: argspec = inspect.getargspec(generate) key_values = [(arg, locals()[arg]) for arg in argspec.args] #pop.arguments = {key: value for (key, value) in key_values} except SyntaxError: pass if not nostdout: print "\tGenerating pulsars with parameters:" param_string_list = [] for key, value in key_values: s = ": ".join([key, str(value)]) param_string_list.append(s) # join this list of strings, and print it s = "\n\t\t".join(param_string_list) print "\t\t{0}".format(s) # set up progress bar for fun :) prog = ProgressBar(min_value=0, max_value=ngen, width=65, mode='dynamic') # create survey objects here and put them in a list if surveyList is not None: surveys = [Survey(s, pattern) for s in surveyList] # initialise these counters to zero for surv in surveys: surv.ndet = 0 # number detected surv.nout = 0 # number outside survey region surv.nsmear = 0 # number smeared out surv.ntf = 0 # number too faint surv.nbr = 0 #number didn't burst # surv.gainpat=pattern else: # make an empty list here - makes some code just a little # simpler - can still loop over an empty list (ie zero times) surveys = [] while pop.ndet < ngen: # Declare new pulsar object p = Pulsar() # period, alpha, rho, width distribution calls # Start creating the pulsar! if pop.pDistType == 'lnorm': p.period = dists.drawlnorm(pop.pmean, pop.psigma) elif pop.pDistType == 'unif': p.period = dists.uniform(pop.pmean, pop.psigma) elif pop.pDistType == 'norm': p.period = random.gauss(pop.pmean, pop.psigma) elif pop.pDistType == 'cc97': p.period = _cc97() elif pop.pDistType == 'gamma': print "Gamma function not yet supported" sys.exit() elif pop.pDistType == 'd_g': Pbin_num = dists.draw1d(dgf_pop_load['pHist']) Pmin = dgf_pop_load['pBins'][0] Pmax = dgf_pop_load['pBins'][-1] p.period = Pmin + (Pmax - Pmin) * ( Pbin_num + random.random()) / len(dgf_pop_load['pHist']) # p.period = dg.gen_nos(dgf_pop_load['pHist'],dgf_pop_load['pBins']) elif pop.pDistType == 'lorimer12': p.period = _lorimer2012_msp_periods() if duty_percent > 0.: # use a simple duty cycle for each pulsar # with a log-normal scatter width = (float(duty_percent) / 100.) * p.period**0.9 width = math.log10(width) width = dists.drawlnorm(width, 0.3) # following are the numbers for the RRATs # from the period pulse width relation if singlepulse: width = 1000 while width > 100: A1 = random.gauss(0.49986684, 0.13035004) A2 = random.gauss(-0.77626305, 0.4222085) width = 10**(A1 * math.log10(p.period) + A2) p.width_degree = width * 360. / p.period else: # use the model to caculate if beaming p.alpha = _genAlpha() p.rho, p.width_degree = _genRhoWidth(p) if p.width_degree == 0.0 and p.rho == 0.0: continue # is pulsar beaming at us? If not, move on! p.beaming = _beaming(p) if not p.beaming: continue # Spectral index stuff here # suppose it might be nice to be able to have GPS sources # AND double spectra. But for now I assume only have one or # none of these types. if random.random() > pop.gpsFrac: # This will evaluate true when gpsArgs[0] is NoneType # might have to change in future p.gpsFlag = 0 else: p.gpsFlag = 1 p.gpsA = pop.gpsA if random.random() > pop.brokenFrac: p.brokenFlag = 0 else: p.brokenFlag = 1 p.brokenSI = pop.brokenSI p.spindex = random.gauss(pop.simean, pop.sisigma) # get galactic position # first, Galactic distribution models if pop.radialDistType == 'isotropic': # calculate gl and gb randomly p.gb = math.degrees(math.asin(random.random())) if random.random() < 0.5: p.gb = 0.0 - p.gb p.gl = random.random() * 360.0 # use gl and gb to compute galactic coordinates # pretend the pulsar is at distance of 1kpc # not sure why, ask Dunc! p.galCoords = go.lb_to_xyz(p.gl, p.gb, 1.0) elif pop.radialDistType == 'slab': p.galCoords = go.slabdist() p.gl, p.gb = go.xyz_to_lb(p.galCoords) elif pop.radialDistType == 'disk': p.galCoords = go.diskdist() p.gl, p.gb = go.xyz_to_lb(p.galCoords) else: if pop.radialDistType == 'lfl06': p.r0 = go.lfl06() elif pop.radialDistType == 'gamma': fit_alpha, fit_loc, fit_beta = 1050.312227, -8.12315263841, 0.00756010693478 p.r0 = 8.5 * stats.gamma.rvs( fit_alpha, loc=fit_loc, scale=fit_beta, size=1) + 8.5 elif pop.radialDistType == 'd_g': Rbin_num = dists.draw1d(dgf_pop_load['RHist']) Rmin = dgf_pop_load['RBins'][0] Rmax = dgf_pop_load['RBins'][-1] #p.r0 = dists.yet_another_try(dgf_pop_load['RHist'], dgf_pop_load['RBins']) p.r0 = Rmin + (Rmax - Rmin) * ( Rbin_num + random.random()) / len(dgf_pop_load['RHist']) elif pop.radialDistType == 'yk04': p.r0 = go.ykr() elif pop.radialDistType == 'unif': p.r0 = random.uniform(0, 12.3) elif pop.radialDistType == 'gauss': # guassian of mean 0 # and stdDev given by parameter (kpc) p.r0 = random.gauss(0., pop.rsigma) # then calc xyz,distance, l and b if pop.zscaleType == 'exp': zheight = go._double_sided_exp(zscale) elif pop.zscaleType == 'unif': zheight = random.uniform(-1.06489765758, 1.91849552866) elif pop.zscaleType == 'd_g': zbin_num = dists.draw1d(dgf_pop_load['ZHist']) logzmin = dgf_pop_load['ZBins'][0] logzmax = dgf_pop_load['ZBins'][-1] logz = logzmin + (logzmax - logzmin) * ( zbin_num + random.random()) / len(dgf_pop_load['ZHist']) zheight = logz #zheight = dg.gen_nos(dgf_pop_load['ZHist'],dgf_pop_load['ZBins']) else: zheight = random.gauss(0., zscale) gx, gy = go.calcXY(p.r0) p.galCoords = gx, gy, zheight p.gl, p.gb = go.xyz_to_lb(p.galCoords) p.dtrue = go.calc_dtrue(p.galCoords) if pop.lumDistType == 'lnorm': p.lum_1400 = dists.drawlnorm(pop.lummean, pop.lumsigma) elif pop.lumDistType == 'pow': p.lum_1400 = dists.powerlaw(pop.lummin, pop.lummax, pop.lumpow) elif pop.lumDistType == 'log_st': low_lim = pop.lumlow upr_lim = pop.lumhigh slope = pop.lumslope #-0.10227965 p.lum_1400 = 10.0**(low_lim + dists.st_line(slope, (upr_lim - low_lim))) elif pop.lumDistType == 'log_unif': p.lum_1400 = 10.0**dists.uniform(pop.lumlow, pop.lumhigh) elif pop.lumDistType == 'd_g': lbin_num = dists.draw1d(dgf_pop_load['lHist']) lmin = dgf_pop_load['lBins'][0] lmax = dgf_pop_load['lBins'][-1] logl = lmin + (lmax - lmin) * (lbin_num + random.random()) / len( dgf_pop_load['lHist']) p.lum_1400 = 10.0**logl p.lum_inj_mu = p.lum_1400 # add in orbital parameters if orbits: orbitalparams.test_1802_2124(p) print p.gb, p.gl #dither the distance if dither: # find flux flux = p.lum_inj_mu / (p.dtrue**2) # dithered distance p.dold = p.dtrue p.dtrue += random.gauss(0.0, 0.2 * p.dtrue) # new luminosity p.lum_1400 = flux * p.dtrue**2 p.lum_inj_mu = p.lum_1400 # new R and z p.galCoords = go.lb_to_xyz(p.gl, p.gb, p.dtrue) p.r0 = np.sqrt(p.galCoords[0]**2 + p.galCoords[1]**2) #define a burst rate if single pulse option is on if singlepulse: if brDistType == 'd_g': brbin_num = dists.draw1d(dgf_pop_load['brHist']) brmin = dgf_pop_load['brBins'][0] brmax = dgf_pop_load['brBins'][-1] p.br = 10**(brmin + (brmax - brmin) * (brbin_num + random.random()) / len(dgf_pop_load['brHist'])) else: p.br = _burst() p.lum_sig = sig_factor p.det_nos = 0 else: p.br = None p.det_nos = None # then calc DM using fortran libs if pop.electronModel == 'ne2001': p.dm = go.ne2001_dist_to_dm(p.dtrue, p.gl, p.gb) elif pop.electronModel == 'lmt85': p.dm = go.lmt85_dist_to_dm(p.dtrue, p.gl, p.gb) elif pop.electronModel == 'ymw16': p.dm = go.ymw16_dist_to_dm(p.dtrue, p.gl, p.gb) p.scindex = scindex # then calc scatter time p.t_scatter = go.scatter_bhat(p.dm, p.scindex) # if no surveys, just generate ngen pulsars if surveyList is None: pop.population.append(p) pop.ndet += 1 if not nostdout: prog.increment_amount() print prog, '\r', sys.stdout.flush() # if surveys are given, check if pulsar detected or not # in ANY of the surveys else: # just a flag to increment if pulsar is detected detect_int = 0 for surv in surveys: # do SNR calculation if singlepulse: #pop_time = int(p.br*surv.tobs) #if pop_time >= 1.0: SNR = surv.SNRcalc(p, pop, rratssearch=True) #else: # SNR = -3 elif accelsearch: SNR = surv.SNRcalc(p, pop, accelsearch=True) elif jerksearch: SNR = surv.SNRcalc(p, pop, jerksearch=True) else: SNR = surv.SNRcalc(p, pop, rratssearch=False) if SNR > surv.SNRlimit: # SNR is over threshold # increment the flag # and survey ndetected detect_int += 1 surv.ndet += 1 continue elif SNR == -1: # pulse is smeared out surv.nsmear += 1 continue elif SNR == -2: # pulsar is outside survey region surv.nout += 1 continue elif SNR == -3: # rrat didn't burst surv.nbr += 1 continue else: # pulsar is just too faint surv.ntf += 1 continue # add the pulsar to the population pop.population.append(p) # if detected, increment ndet (for whole population) # and redraw the progress bar if detect_int: pop.ndet += 1 if not nostdout: prog.increment_amount() print prog, '\r', sys.stdout.flush() # print info to stdout if not nostdout: print "\n" print " Total pulsars = {0}".format(len(pop.population)) print " Total detected = {0}".format(pop.ndet) # print " Number not beaming = {0}".format(surv.nnb) for surv in surveys: print "\n Results for survey '{0}'".format(surv.surveyName) print " Number detected = {0}".format(surv.ndet) print " Number too faint = {0}".format(surv.ntf) print " Number smeared = {0}".format(surv.nsmear) print " Number outside survey area = {0}".format(surv.nout) if singlepulse: print " Number didn't burst = {0}".format(surv.nbr) return pop
def generate(ngen, surveyList=None, pDistType='lnorm', radialDistType='lfl06', radialDistPars=7.5, electronModel='ne2001', pDistPars=[2.7, -0.34], siDistPars= [-1.6,0.35], lumDistType='lnorm', lumDistPars=[-1.1, 0.9], zscaleType='exp', zscale=0.33, duty_percent=6., scindex=-3.86, gpsArgs=[None, None], doubleSpec=[None, None], nostdout=False, pattern='gaussian', orbits=False): """ Generate a population of pulsars. Keyword args: ngen -- the number of pulsars to generate (or detect) surveyList -- a list of surveys you want to use to try and detect the pulsars pDistType -- the pulsar period distribution model to use (def=lnorm) radialDistType -- radial distribution model electronModel -- mode to use for Galactic electron distribution pDistPars -- parameters to use for period distribution siDistPars -- parameters to use for spectral index distribution lumDistPars -- parameters to use for luminosity distribution radialDistPars -- parameters for radial distribution zscale -- if using exponential z height, set it here (in kpc) scindex -- spectral index of the scattering model gpsArgs -- add GPS-type spectrum sources doubleSpec -- add double-spectrum type sources nostdout -- (bool) switch off stdout """ pop = Population() # check that the distribution types are supported.... if lumDistType not in ['lnorm', 'pow']: print "Unsupported luminosity distribution: {0}".format(lumDistType) if pDistType not in ['lnorm', 'norm', 'cc97', 'lorimer12']: print "Unsupported period distribution: {0}".format(pDistType) if radialDistType not in ['lfl06', 'yk04', 'isotropic', 'slab', 'disk', 'gauss']: print "Unsupported radial distribution: {0}".format(radialDistType) if electronModel not in ['ne2001', 'lmt85']: print "Unsupported electron model: {0}".format(electronModel) if pattern not in ['gaussian','airy']: print "Unsupported gain pattern: {0}".format(pattern) if duty_percent<0.: print "Unsupported value of duty cycle: {0}".format(duty_percent) # need to use properties in this class so they're get/set-type props pop.pDistType = pDistType pop.radialDistType = radialDistType pop.electronModel = electronModel pop.lumDistType = lumDistType pop.rsigma = radialDistPars pop.pmean, pop.psigma = pDistPars pop.simean, pop.sisigma = siDistPars pop.gpsFrac, pop.gpsA = gpsArgs pop.brokenFrac, pop.brokenSI = doubleSpec if pop.lumDistType == 'lnorm': pop.lummean, pop.lumsigma = \ lumDistPars[0], lumDistPars[1] else: try: pop.lummin, pop.lummax, pop.lumpow = \ lumDistPars[0], lumDistPars[1], lumDistPars[2] except ValueError: raise PopulateException('Not enough lum distn parameters') pop.zscaleType = zscaleType pop.zscale = zscale # store the dict of arguments inside the model. Could be useful. try: argspec = inspect.getargspec(generate) key_values = [(arg, locals()[arg]) for arg in argspec.args] pop.arguments = {key: value for (key,value) in key_values} except SyntaxError: pass if not nostdout: print "\tGenerating pulsars with parameters:" param_string_list = [] for key, value in key_values: s = ": ".join([key, str(value)]) param_string_list.append(s) # join this list of strings, and print it s = "\n\t\t".join(param_string_list) print "\t\t{0}".format(s) # set up progress bar for fun :) prog = ProgressBar(min_value = 0, max_value=ngen, width=65, mode='dynamic') # create survey objects here and put them in a list if surveyList is not None: surveys = [Survey(s,pattern) for s in surveyList] # initialise these counters to zero for surv in surveys: surv.ndet =0 # number detected surv.nout=0 # number outside survey region surv.nsmear=0 # number smeared out surv.ntf=0 # number too faint #surv.gainpat=pattern else: # make an empty list here - makes some code just a little # simpler - can still loop over an empty list (ie zero times) surveys=[] while pop.ndet < ngen: # Declare new pulsar object p = Pulsar() # period, alpha, rho, width distribution calls # Start creating the pulsar! if pop.pDistType == 'lnorm': p.period = dists.drawlnorm(pop.pmean, pop.psigma) elif pop.pDistType == 'norm': p.period = random.gauss(pop.pmean, pop.psigma) elif pop.pDistType == 'cc97': p.period = _cc97() elif pop.pDistType == 'gamma': print "Gamma function not yet supported" sys.exit() elif pop.pDistType == 'lorimer12': p.period = _lorimer2012_msp_periods() if duty_percent>0.: # use a simple duty cycle for each pulsar # with a log-normal scatter width = (float(duty_percent)/100.) * p.period**0.9 width = math.log10(width) width = dists.drawlnorm(width, 0.3) p.width_degree = width*360./p.period else: # use the model to caculate if beaming p.alpha = _genAlpha() p.rho, p.width_degree = _genRhoWidth(p) if p.width_degree == 0.0 and p.rho ==0.0: continue # is pulsar beaming at us? If not, move on! p.beaming = _beaming(p) if not p.beaming: continue # Spectral index stuff here # suppose it might be nice to be able to have GPS sources # AND double spectra. But for now I assume only have one or # none of these types. if random.random() > pop.gpsFrac: # This will evaluate true when gpsArgs[0] is NoneType # might have to change in future p.gpsFlag = 0 else: p.gpsFlag = 1 p.gpsA = pop.gpsA if random.random() > pop.brokenFrac: p.brokenFlag=0 else: p.brokenFlag=1 p.brokenSI = pop.brokenSI p.spindex = random.gauss(pop.simean, pop.sisigma) # get galactic position # first, Galactic distribution models if pop.radialDistType == 'isotropic': # calculate gl and gb randomly p.gb = math.degrees(math.asin(random.random())) if random.random() < 0.5: p.gb = 0.0 - p.gb p.gl = random.random() * 360.0 # use gl and gb to compute galactic coordinates # pretend the pulsar is at distance of 1kpc # not sure why, ask Dunc! p.galCoords = go.lb_to_xyz(p.gl, p.gb, 1.0) elif pop.radialDistType == 'slab': p.galCoords= go.slabDist() p.gl, p.gb = go.xyz_to_lb(p.galCoords) elif pop.radialDistType == 'disk': p.galCoords = go.diskDist() p.gl, p.gb = go.xyz_to_lb(p.galCoords) else: # we want to use exponential z and a radial dist if pop.radialDistType == 'lfl06': p.r0 = go.lfl06() elif pop.radialDistType == 'yk04': p.r0 = go.ykr() elif pop.radialDistType == 'gauss': # guassian of mean 0 # and stdDev given by parameter (kpc) p.r0 = random.gauss(0., pop.rsigma) # then calc xyz,distance, l and b if pop.zscaleType == 'exp': zheight = go._double_sided_exp(zscale) else: zheight = random.gauss(0., zscale) gx,gy = go.calcXY(p.r0) p.galCoords = gx, gy, zheight p.gl, p.gb = go.xyz_to_lb(p.galCoords) p.dtrue = go.calc_dtrue(p.galCoords) # then calc DM using fortran libs if pop.electronModel == 'ne2001': p.dm = go.ne2001_dist_to_dm(p.dtrue, p.gl, p.gb) elif pop.electronModel == 'lmt85': p.dm = go.lmt85_dist_to_dm(p.dtrue, p.gl, p.gb) p.scindex = scindex # then calc scatter time p.t_scatter = go.scatter_bhat(p.dm, p.scindex) if pop.lumDistType == 'lnorm': p.lum_1400 = dists.drawlnorm(pop.lummean, pop.lumsigma) else: p.lum_1400 = dists.powerlaw(pop.lummin, pop.lummax, pop.lumpow) # add in orbital parameters if orbits: orbitalparams.test_1802_2124(p) print p.gb, p.gl # if no surveys, just generate ngen pulsars if surveyList is None: pop.population.append(p) pop.ndet += 1 if not nostdout: prog.increment_amount() print prog, '\r', sys.stdout.flush() # if surveys are given, check if pulsar detected or not # in ANY of the surveys else: detect_int = 0 # just a flag to increment if pulsar is detected for surv in surveys: # do SNR calculation SNR = surv.SNRcalc(p, pop) if SNR > surv.SNRlimit: # SNR is over threshold # increment the flag # and survey ndetected detect_int += 1 surv.ndet += 1 continue elif SNR == -1: # pulse is smeared out surv.nsmear += 1 continue elif SNR == -2: # pulsar is outside survey region surv.nout += 1 continue else: #pulsar is just too faint surv.ntf += 1 continue # add the pulsar to the population pop.population.append(p) # if detected, increment ndet (for whole population) # and redraw the progress bar if detect_int: pop.ndet += 1 if not nostdout: prog.increment_amount() print prog, '\r', sys.stdout.flush() # print info to stdout if not nostdout: print "\n" print " Total pulsars = {0}".format(len(pop.population)) print " Total detected = {0}".format(pop.ndet) #print " Number not beaming = {0}".format(surv.nnb) for surv in surveys: print "\n Results for survey '{0}'".format(surv.surveyName) print " Number detected = {0}".format(surv.ndet) print " Number too faint = {0}".format(surv.ntf) print " Number smeared = {0}".format(surv.nsmear) print " Number outside survey area = {0}".format(surv.nout) return pop
def generate(ngen, surveyList=None, age_max=1.0E9, pDistPars=[.3, .15], bFieldPars=[12.65, 0.55], birthVPars=[0.0, 180.], siDistPars=[-1.6, 0.35], alignModel='orthogonal', lumDistType='fk06', lumDistPars=[-1.5, 0.5], alignTime=None, spinModel='fk06', beamModel='tm98', birthVModel='gaussian', electronModel='ne2001', braking_index=0, zscale=0.05, duty=5., scindex=-3.86, widthModel=None, nodeathline=False, efficiencycut=None, nostdout=False, nospiralarms=False, keepdead=False): pop = Population() # set the parameters in the population object pop.pmean, pop.psigma = pDistPars pop.bmean, pop.bsigma = bFieldPars if lumDistType == 'pow': try: pop.lummin, pop.lummax, pop.lumpow = \ lumDistPars[0], lumDistPars[1], lumDistPars[2] except ValueError: raise EvolveException('Not enough lum distn parameters for "pow"') elif lumDistType == 'fk06': pop.lumPar1, pop.lumPar2 = lumDistPars[0], lumDistPars[1] if len(lumDistPars) == 3: pop.lumPar3 = lumDistPars[2] else: pop.lumPar3 = 0.18 else: pop.lumPar1, pop.lumPar2 = lumDistPars pop.simean, pop.sisigma = siDistPars pop.birthvmean, pop.birthvsigma = birthVPars pop.alignModel = alignModel pop.alignTime = alignTime pop.spinModel = spinModel pop.beamModel = beamModel pop.birthVModel = birthVModel pop.electronModel = electronModel pop.braking_index = braking_index pop.deathline = not nodeathline pop.nospiralarms = nospiralarms pop.zscale = zscale if widthModel == 'kj07': print "\tLoading KJ07 models...." kj_p_vals, kj_pdot_vals, kj_dists = beammodels.load_kj2007_models() print "\tDone\n" if not nostdout: print "\tGenerating evolved pulsars with parameters:" print "\t\tngen = {0}".format(ngen) print "\t\tUsing electron distn model {0}".format(pop.electronModel) print "\n\t\tPeriod mean, sigma = {0}, {1}".format( pop.pmean, pop.psigma) print "\t\tLuminosity mean, sigma = {0}, {1}".format( pop.lummean, pop.lumsigma) print "\t\tSpectral index mean, sigma = {0}, {1}".format( pop.simean, pop.sisigma) print "\t\tGalactic z scale height = {0} kpc".format(pop.zscale) if widthModel is None: print "\t\tWidth {0}% ".format(duty) else: print "\t\tUsing Karastergiou & Johnston beam width model" # set up progress bar for fun :) prog = ProgressBar(min_value=0, max_value=ngen, width=65, mode='dynamic') # create survey objects here and put them in a list if surveyList is not None: surveys = [Survey(s) for s in surveyList] else: # make an empty list here - makes some code just a little # simpler - can still loop over an empty list (ie zero times) surveys = [] # initialise these counters to zero for surv in surveys: surv.ndet = 0 # number detected surv.nout = 0 # number outside survey region surv.nsmear = 0 # number smeared out surv.ntf = 0 # number too faint # this is the nitty-gritty loop for generating the pulsars while pop.ndet < ngen: pulsar = Pulsar() # initial age for pulsar pulsar.age = random.random() * age_max # initial period pulsar.p0 = -1. while pulsar.p0 <= 0.: pulsar.p0 = random.gauss(pop.pmean, pop.psigma) # initial magnetic field (in Gauss) pulsar.bfield_init = 10**random.gauss(pop.bmean, pop.bsigma) # aligment angle alignpulsar(pulsar, pop) # braking index if pop.braking_index == 0: pulsar.braking_index = 2.5 + 0.5 * random.random() else: pulsar.braking_index = float(pop.braking_index) # apply relevant spin down model pulsar.dead = False # pulsar should start alive! if pop.spinModel == 'fk06': spindown_fk06(pulsar) # apply deathline if relevant if pop.deathline: bhattacharya_deathperiod_92(pulsar) elif pop.spinModel == 'cs06': # contopoulos and spitkovsky spindown_cs06(pulsar, pop) # if period > 10 seconds, just try a new one if pulsar.period > 10000.0 or pulsar.period < 10.: continue # cut on pdot too - this doesn't help if pulsar.pdot > 1.e-11 or pulsar.pdot < 1.e-18: continue # define pulse width (default = 6% = 18 degrees) if widthModel is None: width = (float(duty) / 100.) * pulsar.period**0.9 width = math.log10(width) width = dists.drawlnorm(width, 0.3) elif widthModel == 'kj07': # Karastergiou & Johnston beam model # find closest p, pdot in the kj lists logp = math.log10(pulsar.period) logpdot = math.log10(pulsar.pdot) p_idx = (np.abs(kj_p_vals - logp)).argmin() pd_idx = (np.abs(kj_pdot_vals - logpdot)).argmin() # pick a width from relevant model dist = kj_dists[p_idx][pd_idx][2] width = np.random.choice(dist) """ width = beammodels.kj2007_width(pulsar) no_width = 0 while width == 0.0: no_width+=1 width = beammodels.kj2007_width(pulsar) # if we get to five, then try a new pulsar if no_width == 5: no_width = 0 continue """ else: print "Undefined width model!" sys.exit() # print width # print pulsar.period, width, pulsar.pdot if width == 0.0: # some kj2007 models make many zero-width sources. Skip! continue pulsar.width_degree = 360. * width / pulsar.period # plough on - only if the pulsar isn't dead! if not pulsar.dead or keepdead: # is the pulsar beaming? pulsar_beaming(pulsar, pop.beamModel) # if not, then skip onto next pulsar if not pulsar.beaming: continue # position of the pulsar galacticDistribute(pulsar, pop) # birthvelocity birthVelocity(pulsar, pop) # model the xyz velocity go.vxyz(pulsar) # luminosity if lumDistType == 'fk06': luminosity_fk06(pulsar, alpha=pop.lumPar1, beta=pop.lumPar2, gamma=pop.lumPar3) elif lumDistType == 'lnorm': pulsar.lum_1400 = dists.drawlnorm(pop.lumPar1, pop.lumPar2) elif lumDistType == 'pow': pulsar.lum_1400 = dists.powerlaw(pop.lummin, pop.lummax, pop.lumpow) else: # something's wrong! raise EvolveException('Invalid luminosity distn selected') # apply efficiency cutoff if efficiencycut is not None: if pulsar.efficiency() > efficiencycut: pulsar.dead = True if not keepdead: continue # spectral index pulsar.spindex = random.gauss(pop.simean, pop.sisigma) # calculate galactic coords and distance pulsar.gl, pulsar.gb = go.xyz_to_lb(pulsar.galCoords) pulsar.dtrue = go.calc_dtrue(pulsar.galCoords) # then calc DM using fortran libs if pop.electronModel == 'ne2001': pulsar.dm = go.ne2001_dist_to_dm(pulsar.dtrue, pulsar.gl, pulsar.gb) elif pop.electronModel == 'lmt85': pulsar.dm = go.lmt85_dist_to_dm(pulsar.dtrue, pulsar.gl, pulsar.gb) else: raise EvolveException('Invalid electron dist model selected') pulsar.scindex = scindex pulsar.t_scatter = go.scatter_bhat(pulsar.dm, pulsar.scindex) # if surveys are given, check if pulsar detected or not # in ANY of the surveys if surveyList is not None: detect_int = 0 # just a flag if pulsar is detected for surv in surveys: SNR = surv.SNRcalc(pulsar, pop) if SNR > surv.SNRlimit: # SNR is over threshold # increment the flag # and survey ndetected detect_int += 1 surv.ndet += 1 continue elif SNR == -1: # pulse is smeared out surv.nsmear += 1 continue elif SNR == -2: # pulsar is outside survey region surv.nout += 1 continue else: # pulsar is just too faint surv.ntf += 1 continue # if detected, increment ndet (for whole population) # and redraw the progress bar if detect_int: pop.ndet += 1 # update the counter if not nostdout: prog.increment_amount() print prog, '\r', sys.stdout.flush() else: # no survey list, just add the pulsar to population, # and increment number of pulsars pop.ndet += 1 # update the counter if not nostdout: prog.increment_amount() print prog, '\r', sys.stdout.flush() # pulsar isn't dead, add to population! pop.population.append(pulsar) else: # pulsar is dead. If no survey list, # just increment number of pulsars if surveyList is None: pop.ndet += 1 # update the counter if not nostdout: prog.increment_amount() print prog, '\r', sys.stdout.flush() if not nostdout: print "\n\n" print " Total pulsars = {0}".format(len(pop.population)) print " Total detected = {0}".format(pop.ndet) for surv in surveys: print "\n Results for survey '{0}'".format(surv.surveyName) print " Number detected = {0}".format(surv.ndet) print " Number too faint = {0}".format(surv.ntf) print " Number smeared = {0}".format(surv.nsmear) print " Number outside survey area = {0}".format(surv.nout) # save list of arguments into the pop try: argspec = inspect.getargspec(generate) key_values = [(arg, locals()[arg]) for arg in argspec.args] pop.arguments = {key: value for (key, value) in key_values} except SyntaxError: pass return pop