def generate(ngen, surveyList=None, age_max=1.0E9, pDistPars=[0.3, 0.15], pDistType = 'norm' , # P distirbution for MSPs (Lorimer et al. 2015) 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, dosurveyList = None, makepop=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 # create dosurvey objects here and put them in a list if dosurveyList is not None: dosurveys = [Survey(s) for s in dosurveyList] # initialise these counters to zero for surv in dosurveys: 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) dosurveys = [] # this is the nitty-gritty loop for generating the pulsars ntot = 0 #total number of pulsars generated by the while loop (including dead, and the ones not beaming towards us) n_alive = 0 #total number of pulsars which are alive (beaming + not beaming towards Earth) n_alive_beam = 0 #total number of alive pulsars beaming towards Earth 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.): if(pDistType == 'norm'): pulsar.p0 = random.gauss(pop.pmean, pop.psigma) elif(pDistType == 'drl15'): L_p0 = np.random.lognormal(mean = pop.pmean, sigma = pop.psigma) pulsar.p0 = np.exp(L_p0)/1000 # period in seconds # 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 == 'tk01': spindown_tk01(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 < 1.5: continue # cut on pdot too - this doesn't help if pulsar.pdot > 1.e-11 or pulsar.pdot < 1.e-21: 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 # incrementing the total number of physical pulsars generated by # the model after the unphysical ones are removed ntot += 1 # plough on - only if the pulsar isn't dead! if not pulsar.dead or keepdead: n_alive+=1 # 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() # increment the total number of alive pulsars beaming towards Earth # should be different from n_alive (as the loop was stopped if pulsar # was found to not beam towards Earth) # is incremented only when pulsar was beaming towards us n_alive_beam += 1 # pulsar isn't dead, and makepop True, add the pulsar to population! if makepop == True: pop.population.append(pulsar) # if dosurveys are given, check if pulsar detected or not # in each of the surveys or any of the survey # just a flag to increment if pulsar is detected if dosurveyList is not None: for surv in dosurveys: SNR = surv.SNRcalc(pulsar, pop) if SNR > surv.SNRlimit: # SNR is over threshold # increment survey ndetected 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 else: # pulsar is dead. If no survey list, # just increment number of pulsars if surveyList is None: pop.ndet = ntot # 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) print " Total pulsars generated = {0}".format(ntot) print " Total living pulsars = {0}".format(n_alive) print " Total living pulsars beaming towards Earth = {0}".format(n_alive_beam) if surveyList is not None: print " Total detected by all surveys = {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) for surv in dosurveys: print "\n Dosurvey 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) dosurvey_result = [] for surv in dosurveys: dosurvey_result.append([surv.surveyName, surv.ndet, surv.ntf, surv.nsmear, 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, dosurvey_result
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