Пример #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=[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
Пример #2
0
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
Пример #3
0
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
Пример #4
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,
             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
Пример #5
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:
            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
Пример #6
0
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