Exemple #1
0
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=[-1, -1],
             doubleSpec=[-1, -1],
             nostdout=False,
             pattern='gaussian',
             orbits=False,
             dgf=None,
             singlepulse=False,
             giantpulse=False,
             dither=False,
             accelsearch=False,
             jerksearch=False,
             sig_factor=10.0,
             bns = False,
             orbparams = {'m': [1, 5], 'm1': [1.0, 2.4], 'm2': [0.2, 1e9], 'om': [0, 360.], 'inc': [0, 90], 'ec': [0., 1.], 'pod': [1e-3, 1e3]},
             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
    
    #Set whether system is BNS:
    pop.bns = bns
    pop.orbparams = orbparams

    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:
        if sys.version_info[0] > 3:
            argspec = inspect.getfullargspec(generate)
        else:
            argspec = inspect.getargspec(generate)
        lcl = locals()
        key_values = [(arg, lcl[arg]) for arg in argspec.args]
        #key_values = [(arg, locals()['argspec'][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 -1
            # 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!
            #Adam comment ,1 Kpc makes no sense here...
            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 pop.bns:
            
            assert isinstance(orbparams, dict), "Orbital parameter distribution limits should be a dictionary of form {'name of orb_param': [min, max]}"
            
            #These represents the range in which NN was trained. 
            #DO NOT GO OUTSIDE THESE BOUNDS!!
            default_orbparams = {'m': [1, 5], 'm1': [1.0, 2.4], 'm2': [0.2, 1e9], 'om': [0, 360.], 'inc': [0, 90], 'ec': [0., 1.], 'pod': [1e-3, 1e3]}
            
            if len(pop.orbparams) == 0: 
                print("Warning: Supplied orbparams dict is empty; Setting ranges to default")
                pop.orbparams = default_orbparams
            else:
                temp_opd = dict(default_orbparams)
                temp_opd.update(orbparams)
                pop.orbparams = temp_opd
            
            #Draw a value for each of the orbital parameters from a uniform distribution
            p.m = np.int(np.random.uniform(pop.orbparams['m'][0], pop.orbparams['m'][1], size = 1)) #Should typically fix this to one value!
            p.m1 = np.random.uniform(pop.orbparams['m1'][0], pop.orbparams['m1'][1], size = 1)
            p.m2 = np.random.uniform(pop.orbparams['m2'][0], pop.orbparams['m2'][1], size = 1)
            p.om = np.random.uniform(pop.orbparams['om'][0], pop.orbparams['om'][1], size = 1)
            p.inc = np.random.uniform(pop.orbparams['inc'][0], pop.orbparams['inc'][1], size = 1)
            p.ec = np.random.uniform(pop.orbparams['ec'][0], pop.orbparams['ec'][1], size = 1)
            p.pod = np.random.uniform(pop.orbparams['pod'][0], pop.orbparams['pod'][1], size = 1)
        
        #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
Exemple #2
0
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
Exemple #3
0
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 pDistType not in ['lnorm', 'norm', 'cc97', 'lorimer12', 'lorimer15']:
        print "Unsupported period distribution: {0}".format(pDistType)

    if radialDistType not in [
            'lfl06', 'yk04', 'isotropic', 'slab', 'disk', 'gauss'
    ]:
        print "Unsupported radial distribution: {0}".format(radialDistType)

    # Edited by Shi Dai, 2017/03/22
    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]
    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, absolute_importpattern) 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 = []

    Lorimer15 = np.loadtxt(
        '/Users/dai02a/Soft/psrpop/PsrPopPy/lib/python/lorimer15')
    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()
        elif pop.pDistType == 'lorimer15':
            #p.period = _lorimer2015_msp_periods()
            p.period = Lorimer15[pop.ndet]

        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)

        # Edited by Shi Dai, 2017/03/22
        # 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.electronModel == 'ne2001':
            p.dm = go.ne2001_dist_to_dm(p.dtrue, p.gl, p.gb)
            p.t_scatter = go.scatter_bhat(p.dm, p.scindex)
        elif pop.electronModel == 'lmt85':
            p.dm = go.lmt85_dist_to_dm(p.dtrue, p.gl, p.gb)
            p.t_scatter = go.scatter_bhat(p.dm, p.scindex)
        elif pop.electronModel == 'ymw16':
            p.dm, p.t_scatter = go.ymw16_dist_to_dm(p.dtrue, p.gl, p.gb)

        p.scindex = scindex
        # then calc scatter time

        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:
            calc_delta(p)
            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

            # added by Shi Dai, 2017/02/07
            #p.snr = SNR

            # 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