示例#1
0
    def SNRcalc(self, pulsar, pop):
        """Calculate the S/N ratio of a given pulsar in the survey"""
        # if not in region, S/N = 0

        # if we have a list of pointings, use this bit of code
        # haven't tested yet, but presumably a lot slower
        # (loops over the list of pointings....)
 

        # otherwise check if pulsar is in entire region
        if self.inRegion(pulsar):
            # If pointing list is provided, check how close nearest 
            # pointing is
            if self.pointingslist is not None:
                # convert offset from degree to arcmin
                offset = self.inPointing(pulsar) * 60.0

            else:
                # calculate offset as a random offset within FWHM/2
                offset = self.fwhm * math.sqrt(random.random()) / 2.0
        else:
            return -2

        # Get degfac depending on self.gainpat
        if self.gainpat == 'airy':
            conv    = math.pi/(60*180.)         # Conversion arcmins -> radians
            eff_diam = 3.0e8/(self.freq*self.fwhm*conv*1.0e6)  # Also MHz -> Hz
            a       = eff_diam/2.               # Effective radius of telescope
            lamda   = 3.0e8/(self.freq*1.0e6)   # Obs. wavelength
            kasin   = (2*math.pi*a/lamda)*np.sin(offset*conv)
            degfac = 4*(j1(kasin)/kasin)**2
        else:
            #### NOTE! HERE I WANT TO CHECK UNITS OF FWHM (ARCMIN???)
            degfac = math.exp(-2.7726 * offset * offset / (self.fwhm *self.fwhm))

        # Dunc's code here uses a ^-2.6 to convert frequencies
        # don't think I need to do this - I'm using the frequency in call
        Ttot = self.tsys + self.tskypy(pulsar)

        # calc dispersion smearing across single channel
        tdm = self._dmsmear(pulsar)

        # calculate bhat et al scattering time (inherited from GalacticOps)
        # in units of ms
        tscat = go.scatter_bhat(pulsar.dm, pulsar.scindex, self.freq)

        # Calculate the effective width
        weff_ms = math.sqrt(pulsar.width_ms()**2 + self.tsamp**2 + tdm**2 + tscat**2)

        # calculate duty cycle (period is in ms)
        delt = weff_ms / pulsar.period
        #print weff_ms, pulsar.period

        # if pulse is smeared out, return -1.0
        if delt > 1.0:
            #print weff_ms, tscat, pulsar.dm, pulsar.gl, pulsar.gb, pulsar.dtrue
            return -1
        else:
            return self._SNfac(pulsar, pop.ref_freq, degfac, Ttot) \
                                  * math.sqrt((1.0 -delt)/delt)
示例#2
0
文件: survey.py 项目: kmjc/PsrPopPy2
    def scint(self, psr, snr):
        """ Add scintillation effects and modify the pulsar's S/N"""

        # calculate the scintillation strength (commonly "u")
        # first, calculate scint BW, assume Kolmogorov, C=1.16
        if hasattr(psr, 't_scatter'):
            tscat = go.scale_bhat(psr.t_scatter, self.freq, psr.scindex)
        else:
            tscat = go.scatter_bhat(psr.dm, psr.scindex, self.freq)
        # convert to seconds
        tscat /= 1000.

        scint_bandwidth = 1.16 / 2.0 / math.pi / tscat  # BW in Hz
        scint_bandwidth /= 1.0E6  # convert to MHz (self.freq is in MHz)

        scint_strength = math.sqrt(self.freq / scint_bandwidth)

        if scint_strength < 1.0:
            # weak scintillation
            # modulation index
            u_term = math.pow(scint_strength, 1.666666)
            mod_indx = math.sqrt(u_term)

        else:
            # strong scintillation

            # m^2 = m_riss^2 + m_diss^2 + m_riss * m_diss
            # e.g. Lorimer and Kramer ~eq 4.44
            m_riss = math.pow(scint_strength, -0.33333)

            # lorimer & kramer eq 4.44
            kappa = 0.15  # taking this as avrg for now

            # calculate scintillation timescale
            scint_ts, scint_bw = go.ne2001_scint_time_bw(
                psr.dtrue, psr.gl, psr.gb, self.freq)

            # calc n_t and n_f
            if scint_ts is None:
                n_t = 1.
            else:
                n_t = self._calc_n_t(kappa, scint_ts)

            if scint_bw is None:
                n_f = 1.
            else:
                n_f = self._calc_n_f(kappa, scint_bw)

            # finally calc m_diss
            m_diss = 1. / math.sqrt(n_t * n_f)

            m_tot_sq = m_diss * m_diss + m_riss * m_riss + m_riss * m_diss

            # modulation index for strong scintillation
            mod_indx = math.sqrt(m_tot_sq)

        return self._modulate_flux_scint(snr, mod_indx)
示例#3
0
    def scint(self, psr, snr):
        """ Add scintillation effects and modify the pulsar's S/N"""

        # calculate the scintillation strength (commonly "u")
        # first, calculate scint BW, assume Kolmogorov, C=1.16
        if hasattr(psr, "t_scatter"):
            tscat = go.scale_bhat(psr.t_scatter, self.freq, psr.scindex)
        else:
            tscat = go.scatter_bhat(psr.dm, psr.scindex, self.freq)
        # convert to seconds
        tscat /= 1000.0

        scint_bandwidth = 1.16 / 2.0 / math.pi / tscat  # BW in Hz
        scint_bandwidth /= 1.0e6  # convert to MHz (self.freq is in MHz)

        scint_strength = math.sqrt(self.freq / scint_bandwidth)

        if scint_strength < 1.0:
            # weak scintillation
            # modulation index
            u_term = math.pow(scint_strength, 1.666666)
            mod_indx = math.sqrt(u_term)

        else:
            # strong scintillation

            # m^2 = m_riss^2 + m_diss^2 + m_riss * m_diss
            # e.g. Lorimer and Kramer ~eq 4.44
            m_riss = math.pow(scint_strength, -0.33333)

            # lorimer & kramer eq 4.44
            kappa = 0.15  # taking this as avrg for now

            # calculate scintillation timescale
            scint_ts, scint_bw = go.ne2001_scint_time_bw(psr.dtrue, psr.gl, psr.gb, self.freq)

            # calc n_t and n_f
            if scint_ts is None:
                n_t = 1.0
            else:
                n_t = self._calc_n_t(kappa, scint_ts)

            if scint_bw is None:
                n_f = 1.0
            else:
                n_f = self._calc_n_f(kappa, scint_bw)

            # finally calc m_diss
            m_diss = 1.0 / math.sqrt(n_t * n_f)

            m_tot_sq = m_diss * m_diss + m_riss * m_riss + m_riss * m_diss

            # modulation index for strong scintillation
            mod_indx = math.sqrt(m_tot_sq)

        return self._modulate_flux_scint(snr, mod_indx)
示例#4
0
def calc_delta(pulsar):
    bw_chan = 3.0  # MHz
    freq = 1374.0  # MHz
    # calc dispersion smearing across single channel
    tdm = 8.3E6 * pulsar.dm * bw_chan / math.pow(freq, 3.0)  # ms
    tsamp = 0.25  # ms

    # calculate bhat et al scattering time (inherited from GalacticOps)
    # in units of ms
    if hasattr(pulsar, 't_scatter'):
        tscat = go.scale_bhat(pulsar.t_scatter, freq, pulsar.scindex)
    else:
        tscat = go.scatter_bhat(pulsar.dm, pulsar.scindex, freq)

    # Calculate the effective width
    width_ms = pulsar.width_degree * pulsar.period / 360.0
    weff_ms = math.sqrt(width_ms**2 + tsamp**2 + tdm**2 + tscat**2)

    # calculate duty cycle (period is in ms)
    pulsar.delta = weff_ms / pulsar.period
示例#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:
            # 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
示例#6
0
文件: survey.py 项目: kmjc/PsrPopPy2
    def SNRcalc(self,
                pulsar,
                pop,
                accelsearch=False,
                jerksearch=False,
                rratssearch=False):
        """Calculate the S/N ratio of a given pulsar in the survey"""
        # if not in region, S/N = 0

        # if we have a list of pointings, use this bit of code
        # haven't tested yet, but presumably a lot slower
        # (loops over the list of pointings....)
        if rratssearch:
            if pulsar.br is None:
                print "Population doesn't have a burst rate"
                print "Use populate with --singlepulse"
                sys.exit()
            pulsar.pop_time = np.random.poisson(pulsar.br * self.tobs)

        if pulsar.dead:
            return 0.

        # otherwise check if pulsar is in entire region
        if self.inRegion(pulsar):
            # If pointing list is provided, check how close nearest
            # pointing is
            if self.pointingslist is not None:
                # convert offset from degree to arcmin
                offset = self.inPointing_new(pulsar) * 60.0

            else:
                # calculate offset as a random offset within FWHM/2
                offset = self.fwhm * math.sqrt(random.random()) / 2.0
        else:
            return -2

        if rratssearch == True and pulsar.pop_time < 1.0:
            return -3

        # Get degfac depending on self.gainpat
        if self.gainpat == 'airy':
            conv = math.pi / (60 * 180.)  # Conversion arcmins -> radians
            eff_diam = 3.0e8 / (self.freq * self.fwhm * conv * 1.0e6
                                )  # Also MHz -> Hz
            a = eff_diam / 2.  # Effective radius of telescope
            lamda = 3.0e8 / (self.freq * 1.0e6)  # Obs. wavelength
            kasin = (2 * math.pi * a / lamda) * np.sin(offset * conv)
            degfac = 4 * (j1(kasin) / kasin)**2
        else:
            degfac = math.exp(-2.7726 * offset * offset /
                              (self.fwhm * self.fwhm))

        # calc dispersion smearing across single channel
        tdm = self._dmsmear(pulsar)

        # calculate bhat et al scattering time (inherited from GalacticOps)
        # in units of ms
        if hasattr(pulsar, 't_scatter'):
            tscat = go.scale_bhat(pulsar.t_scatter, self.freq, pulsar.scindex)
        else:
            tscat = go.scatter_bhat(pulsar.dm, pulsar.scindex, self.freq)

        # Calculate the effective width
        width_ms = pulsar.width_degree * pulsar.period / 360.0
        weff_ms = math.sqrt(width_ms**2 + self.tsamp**2 + tdm**2 + tscat**2)

        # calculate duty cycle (period is in ms)
        delta = weff_ms / pulsar.period

        # if pulse is smeared out, return -1.0
        if delta > 1.0:  #and pulsar.pop_time >= 1.0:
            # print width_ms, self.tsamp, tdm, tscat
            return -1

        # radiometer signal to noise
        if rratssearch == False:
            sig_to_noise = rad.calcSNR(self.calcflux(pulsar, pop.ref_freq),
                                       self.beta, self.tsys,
                                       self.tskypy(pulsar), self.gain,
                                       self.npol, self.tobs, self.bw, delta)
        else:
            #find number of times the pulse will pop up!
            #pop_time=int(pulsar.br*self.tobs)
            if pulsar.pop_time >= 1.0:
                pulse_snr = np.zeros(pulsar.pop_time)
                fluxes = np.zeros(pulsar.pop_time)
                lums = []
                mu = math.log10(pulsar.lum_inj_mu)
                sig = mu / pulsar.lum_sig
                # Draw from luminosity dist.
                for burst_times in range(pulsar.pop_time):
                    pulsar.lum_1400 = dist.drawlnorm(mu, sig)
                    lums.append(pulsar.lum_1400)
                    flux = self.calcflux(pulsar, pop.ref_freq)
                    fluxes[burst_times] = flux
                    pulse_snr[burst_times] = rad.single_pulse_snr(
                        self.npol, self.bw, weff_ms * 1e-3,
                        (self.tsys + self.tskypy(pulsar)), self.gain, flux,
                        self.beta)
                pulsar.lum_1400 = np.max(lums)
                sig_to_noise = np.max(pulse_snr)
                if sig_to_noise >= self.SNRlimit:
                    pulsar.det_pulses = fluxes[pulse_snr >= self.SNRlimit]
                    pulsar.det_nos = len(pulsar.det_pulses)
                else:
                    pulsar.det_pulses = None
                    pulsar.det_nos = 0
            else:
                return -3
        # account for aperture array, if needed
        if self.AA and sig_to_noise > 0.0:
            sig_to_noise *= self._AA_factor(pulsar)

        # account for binary motion
        if pulsar.is_binary:
            # print "the pulsar is a binary!"
            if jerksearch:
                print "jerk"
                gamma = degradation.gamma3(pulsar, self.tobs, 1)
            elif accelsearch:
                print "accel"
                gamma = degaadation.gamma2(pulsar, self.tobs, 1)
            else:
                print "norm"
                gamma = degradation.gamma1(pulsar, self.tobs, 1)

                print "gamma harm1 = ", gamma

                gamma = degradation.gamma1(pulsar, self.tobs, 2)

                print "gamma harm2 = ", gamma
                gamma = degradation.gamma1(pulsar, self.tobs, 3)

                print "gamma harm3 = ", gamma
                gamma = degradation.gamma1(pulsar, self.tobs, 4)
                print "gamma harm4 = ", gamma

        # return the S/N accounting for beam offset
        return sig_to_noise * degfac
示例#7
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
示例#8
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
示例#9
0
def generate(ngen,
             surveyList=None,
             age_max=1.0E9,
             pDistPars=[0.3, 0.15],
             pDistType = 'norm' ,           # P distirbution for MSPs (Lorimer et al. 2015)
             bFieldPars=[12.65, 0.55],
             birthVPars=[0.0, 180.],
             siDistPars=[-1.6, 0.35],
             alignModel='orthogonal',
             lumDistType='fk06',
             lumDistPars=[-1.5, 0.5],
             alignTime=None,
             spinModel='fk06',
             beamModel='tm98',
             birthVModel='gaussian',
             electronModel='ne2001',
             braking_index=0,
             zscale=0.05,
             duty=5.,
             scindex=-3.86,
             widthModel=None,
             nodeathline=False,
             efficiencycut=None,
             nostdout=False,
             nospiralarms=False,
             keepdead=False,
             dosurveyList = None,
             makepop=False):

    pop = Population()

    # set the parameters in the population object

    pop.pmean, pop.psigma = pDistPars
    pop.bmean, pop.bsigma = bFieldPars

    if lumDistType == 'pow':
        try:
            pop.lummin, pop.lummax, pop.lumpow = \
                lumDistPars[0], lumDistPars[1], lumDistPars[2]
        except ValueError:
            raise EvolveException('Not enough lum distn parameters for "pow"')

    elif lumDistType == 'fk06':
        pop.lumPar1, pop.lumPar2 = lumDistPars[0], lumDistPars[1]
        if len(lumDistPars) == 3:
            pop.lumPar3 = lumDistPars[2]
        else:
            pop.lumPar3 = 0.18

    else:
        pop.lumPar1, pop.lumPar2 = lumDistPars

    pop.simean, pop.sisigma = siDistPars
    pop.birthvmean, pop.birthvsigma = birthVPars

    pop.alignModel = alignModel
    pop.alignTime = alignTime
    pop.spinModel = spinModel
    pop.beamModel = beamModel
    pop.birthVModel = birthVModel
    pop.electronModel = electronModel

    pop.braking_index = braking_index
    pop.deathline = not nodeathline
    pop.nospiralarms = nospiralarms

    pop.zscale = zscale

    if widthModel == 'kj07':
        print "\tLoading KJ07 models...."
        kj_p_vals, kj_pdot_vals, kj_dists = beammodels.load_kj2007_models()
        print "\tDone\n"

    if not nostdout:
        print "\tGenerating evolved pulsars with parameters:"
        print "\t\tngen = {0}".format(ngen)
        print "\t\tUsing electron distn model {0}".format(
                                        pop.electronModel)
        print "\n\t\tPeriod mean, sigma = {0}, {1}".format(
                                                    pop.pmean,
                                                    pop.psigma)
        print "\t\tLuminosity mean, sigma = {0}, {1}".format(
                                                    pop.lummean,
                                                    pop.lumsigma)
        print "\t\tSpectral index mean, sigma = {0}, {1}".format(
                                                    pop.simean,
                                                    pop.sisigma)
        print "\t\tGalactic z scale height = {0} kpc".format(
                                                    pop.zscale)
        if widthModel is None:
            print "\t\tWidth {0}% ".format(duty)
        else:
            print "\t\tUsing Karastergiou & Johnston beam width model"

        # set up progress bar for fun :)
        prog = ProgressBar(min_value=0,
                           max_value=ngen,
                           width=65,
                           mode='dynamic')

    # create survey objects here and put them in a list
    if surveyList is not None:
        surveys = [Survey(s) for s in surveyList]
    else:
        # make an empty list here - makes some code just a little
        # simpler - can still loop over an empty list (ie zero times)
        surveys = []

    # initialise these counters to zero
    for surv in surveys:
        surv.ndet = 0  # number detected
        surv.nout = 0  # number outside survey region
        surv.nsmear = 0  # number smeared out
        surv.ntf = 0  # number too faint

    # create dosurvey objects here and put them in a list
    if dosurveyList is not None:
        dosurveys = [Survey(s) for s in dosurveyList]
        # initialise these counters to zero
        for surv in dosurveys:
            surv.ndet = 0  # number detected
            surv.nout = 0  # number outside survey region
            surv.nsmear = 0  # number smeared out
            surv.ntf = 0  # number too faint

            # surv.gainpat=pattern
    else:
        # make an empty list here - makes some code just a little
        # simpler - can still loop over an empty list (ie zero times)
        dosurveys = []

    # this is the nitty-gritty loop for generating the pulsars
    ntot = 0   #total number of pulsars generated by the while loop (including dead, and the ones not beaming towards us)
    n_alive = 0  #total number of pulsars which are alive (beaming + not beaming towards Earth)
    n_alive_beam = 0 #total number of alive pulsars beaming towards Earth    
    while pop.ndet < ngen:
        pulsar = Pulsar()

        # initial age for pulsar
        pulsar.age = random.random() * age_max
        # initial period
        pulsar.p0 = -1.
        while (pulsar.p0 <= 0.):
          if(pDistType == 'norm'):
            pulsar.p0 = random.gauss(pop.pmean, pop.psigma)
          elif(pDistType == 'drl15'):
            L_p0 = np.random.lognormal(mean = pop.pmean, sigma = pop.psigma)  
            pulsar.p0 = np.exp(L_p0)/1000         # period in seconds
        # initial magnetic field (in Gauss)
        pulsar.bfield_init = 10**random.gauss(pop.bmean, pop.bsigma)

        # aligment angle
        alignpulsar(pulsar, pop)

        # braking index
        if pop.braking_index == 0:
            pulsar.braking_index = 2.5 + 0.5 * random.random()
        else:
            pulsar.braking_index = float(pop.braking_index)

        # apply relevant spin down model
        pulsar.dead = False  # pulsar should start alive!

        if pop.spinModel == 'fk06':
            spindown_fk06(pulsar)

            # apply deathline if relevant
            if pop.deathline:
                bhattacharya_deathperiod_92(pulsar)

        elif pop.spinModel == 'tk01':
            spindown_tk01(pulsar)

            # apply deathline if relevant
            if pop.deathline:
                bhattacharya_deathperiod_92(pulsar)
 
        elif pop.spinModel == 'cs06':
            # contopoulos and spitkovsky
            spindown_cs06(pulsar, pop)

        # if period > 10 seconds, just try a new one
        if pulsar.period > 10000.0 or pulsar.period < 1.5:
            continue
        # cut on pdot too - this doesn't help
        if pulsar.pdot > 1.e-11 or pulsar.pdot < 1.e-21:
            continue

        # define pulse width (default = 6% = 18 degrees)
        if widthModel is None:
            width = (float(duty)/100.) * pulsar.period**0.9
            width = math.log10(width)
            width = dists.drawlnorm(width, 0.3)
        elif widthModel == 'kj07':
            # Karastergiou & Johnston beam model

            # find closest p, pdot in the kj lists
            logp = math.log10(pulsar.period)
            logpdot = math.log10(pulsar.pdot)

            p_idx = (np.abs(kj_p_vals - logp)).argmin()
            pd_idx = (np.abs(kj_pdot_vals - logpdot)).argmin()

            # pick a width from relevant model
            dist = kj_dists[p_idx][pd_idx][2]
            width = np.random.choice(dist)

            """
            width = beammodels.kj2007_width(pulsar)
            no_width = 0
            while width  == 0.0:
                no_width+=1
                width = beammodels.kj2007_width(pulsar)

                # if we get to five, then try a new pulsar
                if no_width == 5:
                    no_width = 0
                    continue
            """

        else:
            print "Undefined width model!"
            sys.exit()
        # print width
        # print pulsar.period, width, pulsar.pdot
        if width == 0.0:
            # some kj2007 models make many zero-width sources. Skip!
            continue
        pulsar.width_degree = 360. * width / pulsar.period

        # incrementing the total number of physical pulsars generated by
        # the model after the unphysical ones are removed
        ntot += 1
        # plough on - only if the pulsar isn't dead!
        if not pulsar.dead or keepdead:
            n_alive+=1
            # is the pulsar beaming?
            pulsar_beaming(pulsar, pop.beamModel)
            # if not, then skip onto next pulsar
            if not pulsar.beaming:
                continue

            # position of the pulsar
            galacticDistribute(pulsar, pop)
            # birthvelocity
            birthVelocity(pulsar, pop)

            # model the xyz velocity
            go.vxyz(pulsar)

            # luminosity
            if lumDistType == 'fk06':
                luminosity_fk06(pulsar,
                                alpha=pop.lumPar1,
                                beta=pop.lumPar2,
                                gamma=pop.lumPar3)

            elif lumDistType == 'lnorm':
                pulsar.lum_1400 = dists.drawlnorm(pop.lumPar1, pop.lumPar2)

            elif lumDistType == 'pow':
                pulsar.lum_1400 = dists.powerlaw(pop.lummin,
                                                 pop.lummax,
                                                 pop.lumpow)
            else:
                # something's wrong!
                raise EvolveException('Invalid luminosity distn selected')

            # apply efficiency cutoff
            if efficiencycut is not None:
                if pulsar.efficiency() > efficiencycut:
                    pulsar.dead = True
                    if not keepdead:
                        continue

            # spectral index
            pulsar.spindex = random.gauss(pop.simean, pop.sisigma)

            # calculate galactic coords and distance
            pulsar.gl, pulsar.gb = go.xyz_to_lb(pulsar.galCoords)
            pulsar.dtrue = go.calc_dtrue(pulsar.galCoords)

            # then calc DM  using fortran libs
            if pop.electronModel == 'ne2001':
                pulsar.dm = go.ne2001_dist_to_dm(pulsar.dtrue,
                                                 pulsar.gl,
                                                 pulsar.gb)
            elif pop.electronModel == 'lmt85':
                pulsar.dm = go.lmt85_dist_to_dm(pulsar.dtrue,
                                                pulsar.gl,
                                                pulsar.gb)
            else:
                raise EvolveException('Invalid electron dist model selected')

            pulsar.scindex = scindex
            pulsar.t_scatter = go.scatter_bhat(pulsar.dm,
                                               pulsar.scindex)

            # if surveys are given, check if pulsar detected or not
            # in ANY of the surveys
            if surveyList is not None:
                detect_int = 0  # just a flag if pulsar is detected
                for surv in surveys:
                    SNR = surv.SNRcalc(pulsar, pop)

                    if SNR > surv.SNRlimit:
                        # SNR is over threshold
                        # increment the flag
                        # and survey ndetected
                        detect_int += 1
                        surv.ndet += 1
                        continue

                    elif SNR == -1:
                        # pulse is smeared out
                        surv.nsmear += 1
                        continue

                    elif SNR == -2:
                        # pulsar is outside survey region
                        surv.nout += 1
                        continue

                    else:
                        # pulsar is just too faint
                        surv.ntf += 1
                        continue

                # if detected, increment ndet (for whole population)
                # and redraw the progress bar
                if detect_int:
                    pop.ndet += 1
                    # update the counter
                    if not nostdout:
                        prog.increment_amount()
                        print prog, '\r',
                        sys.stdout.flush()

            else:
                # no survey list, just add the pulsar to population,
                # and increment number of pulsars
                pop.ndet += 1
                # update the counter
                if not nostdout:
                    prog.increment_amount()
                    print prog, '\r',
                    sys.stdout.flush()

            # increment the total number of alive pulsars beaming towards Earth
            # should be different from n_alive (as the loop was stopped if pulsar
            # was found to not beam towards Earth)
            # is incremented only when pulsar was beaming towards us
            n_alive_beam += 1            
            
            # pulsar isn't dead, and makepop True, add the pulsar to population!
            if makepop == True:
                pop.population.append(pulsar)

            # if dosurveys are given, check if pulsar detected or not
            # in each of the surveys or any of the survey
            # just a flag to increment if pulsar is detected
            if dosurveyList is not None:
                for surv in dosurveys:
                    SNR = surv.SNRcalc(pulsar, pop)

                    if SNR > surv.SNRlimit:
                        # SNR is over threshold
                        # increment survey ndetected
                        surv.ndet += 1
                        continue

                    elif SNR == -1:
                        # pulse is smeared out
                        surv.nsmear += 1
                        continue

                    elif SNR == -2:
                        # pulsar is outside survey region
                        surv.nout += 1
                        continue

                    else:
                        # pulsar is just too faint
                        surv.ntf += 1
                        continue

        else:
            # pulsar is dead. If no survey list,
            # just increment number of pulsars
            if surveyList is None:
                pop.ndet = ntot 
                # update the counter
                if not nostdout:
                    prog.increment_amount()
                    print prog, '\r',
                    sys.stdout.flush()

    if not nostdout:
        print "\n\n"
#        print "  Total pulsars = {0}".format(len(pop.population))
#        print "  Total detected = {0}".format(pop.ndet)
        print "  Total pulsars generated = {0}".format(ntot)
        print "  Total living pulsars = {0}".format(n_alive)
        print "  Total living pulsars beaming towards Earth = {0}".format(n_alive_beam)

        if surveyList is not None:
            print "  Total detected by all surveys = {0}".format(pop.ndet)


        for surv in surveys:
            print "\n  Results for survey '{0}'".format(surv.surveyName)
            print "    Number detected = {0}".format(surv.ndet)
            print "    Number too faint = {0}".format(surv.ntf)
            print "    Number smeared = {0}".format(surv.nsmear)
            print "    Number outside survey area = {0}".format(surv.nout)

        for surv in dosurveys:
            print "\n  Dosurvey Results for survey '{0}'".format(surv.surveyName)
            print "    Number detected = {0}".format(surv.ndet)
            print "    Number too faint = {0}".format(surv.ntf)
            print "    Number smeared = {0}".format(surv.nsmear)
            print "    Number outside survey area = {0}".format(surv.nout)

    dosurvey_result = []
    for surv in dosurveys:
        dosurvey_result.append([surv.surveyName, surv.ndet, surv.ntf, surv.nsmear, surv.nout])

    # save list of arguments into the pop
    #try:
    #    argspec = inspect.getargspec(generate)
    #    key_values = [(arg, locals()[arg]) for arg in argspec.args]
    #    pop.arguments = {key: value for (key, value) in key_values}
    #except SyntaxError:
     #   pass

    return pop, dosurvey_result
示例#10
0
    def SNRcalc(self, pulsar, pop, accelsearch=False, jerksearch=False):
        """Calculate the S/N ratio of a given pulsar in the survey"""
        # if not in region, S/N = 0

        # if we have a list of pointings, use this bit of code
        # haven't tested yet, but presumably a lot slower
        # (loops over the list of pointings....)

        if pulsar.dead:
            return 0.
        # otherwise check if pulsar is in entire region
        if self.inRegion(pulsar):
            # If pointing list is provided, check how close nearest
            # pointing is
            if self.pointingslist is not None:
                # convert offset from degree to arcmin
                offset = self.inPointing_new(pulsar) * 60.0

            else:
                # calculate offset as a random offset within FWHM/2
                offset = self.fwhm * math.sqrt(random.random()) / 2.0
        else:
            return -2

        # Get degfac depending on self.gainpat
        if self.gainpat == 'airy':
            conv = math.pi / (60 * 180.)  # Conversion arcmins -> radians
            eff_diam = 3.0e8 / (self.freq * self.fwhm * conv * 1.0e6
                                )  # Also MHz -> Hz
            a = eff_diam / 2.  # Effective radius of telescope
            lamda = 3.0e8 / (self.freq * 1.0e6)  # Obs. wavelength
            kasin = (2 * math.pi * a / lamda) * np.sin(offset * conv)
            degfac = 4 * (j1(kasin) / kasin)**2
        else:
            degfac = math.exp(-2.7726 * offset * offset /
                              (self.fwhm * self.fwhm))

        # calc dispersion smearing across single channel
        tdm = self._dmsmear(pulsar)

        # calculate bhat et al scattering time (inherited from GalacticOps)
        # in units of ms
        if hasattr(pulsar, 't_scatter'):
            tscat = go.scale_bhat(pulsar.t_scatter, self.freq, pulsar.scindex)
        else:
            tscat = go.scatter_bhat(pulsar.dm, pulsar.scindex, self.freq)

        # Calculate the effective width
        width_ms = pulsar.width_degree * pulsar.period / 360.0
        weff_ms = math.sqrt(width_ms**2 + self.tsamp**2 + tdm**2 + tscat**2)

        # calculate duty cycle (period is in ms)
        delta = weff_ms / pulsar.period

        # if pulse is smeared out, return -1.0
        if delta > 1.0:
            #print width_ms, self.tsamp, tdm, tscat
            return -1

        #radiometer signal to noise
        sig_to_noise = rad.calcSNR(self.calcflux(pulsar,
                                                 pop.ref_freq), self.beta,
                                   self.tsys, self.tskypy(pulsar), self.gain,
                                   self.npol, self.tobs, self.bw, delta)

        # account for aperture array, if needed
        if self.AA:
            sig_to_noise *= self._AA_factor(pulsar)

        # account for binary motion
        if pulsar.is_binary:
            #print "the pulsar is a binary!"
            if jerksearch:
                print "jerk"
                gamma = degradation.gamma3(pulsar, self.tobs, 1)
            elif accelsearch:
                print "accel"
                gamma = degradation.gamma2(pulsar, self.tobs, 1)
            else:
                print "norm"
                gamma = degradation.gamma1(pulsar, self.tobs, 1)

                print "gamma harm1 = ", gamma

                gamma = degradation.gamma1(pulsar, self.tobs, 2)

                print "gamma harm2 = ", gamma
                gamma = degradation.gamma1(pulsar, self.tobs, 3)

                print "gamma harm3 = ", gamma
                gamma = degradation.gamma1(pulsar, self.tobs, 4)
                print "gamma harm4 = ", gamma

        # return the S/N accounting for beam offset
        return sig_to_noise * degfac
示例#11
0
文件: survey.py 项目: samb8s/PsrPopPy
    def SNRcalc(self,
                pulsar,
                pop,
                accelsearch=False,
                jerksearch=False):
        """Calculate the S/N ratio of a given pulsar in the survey"""
        # if not in region, S/N = 0

        # if we have a list of pointings, use this bit of code
        # haven't tested yet, but presumably a lot slower
        # (loops over the list of pointings....)

        if pulsar.dead:
            return 0.
        # otherwise check if pulsar is in entire region
        if self.inRegion(pulsar):
            # If pointing list is provided, check how close nearest
            # pointing is
            if self.pointingslist is not None:
                # convert offset from degree to arcmin
                offset = self.inPointing_new(pulsar) * 60.0

            else:
                # calculate offset as a random offset within FWHM/2
                offset = self.fwhm * math.sqrt(random.random()) / 2.0
        else:
            return -2

        # Get degfac depending on self.gainpat
        if self.gainpat == 'airy':
            conv = math.pi/(60*180.)         # Conversion arcmins -> radians
            eff_diam = 3.0e8/(self.freq*self.fwhm*conv*1.0e6)  # Also MHz -> Hz
            a = eff_diam/2.               # Effective radius of telescope
            lamda = 3.0e8/(self.freq*1.0e6)   # Obs. wavelength
            kasin = (2*math.pi*a/lamda)*np.sin(offset*conv)
            degfac = 4*(j1(kasin)/kasin)**2
        else:
            degfac = math.exp(
                -2.7726 * offset * offset / (self.fwhm * self.fwhm))

        # calc dispersion smearing across single channel
        tdm = self._dmsmear(pulsar)

        # calculate bhat et al scattering time (inherited from GalacticOps)
        # in units of ms
        if hasattr(pulsar, 't_scatter'):
            tscat = go.scale_bhat(pulsar.t_scatter,
                                  self.freq,
                                  pulsar.scindex)
        else:
            tscat = go.scatter_bhat(pulsar.dm, pulsar.scindex, self.freq)

        # Calculate the effective width
        width_ms = pulsar.width_degree * pulsar.period / 360.0
        weff_ms = math.sqrt(width_ms**2 + self.tsamp**2 + tdm**2 + tscat**2)

        # calculate duty cycle (period is in ms)
        delta = weff_ms / pulsar.period

        # if pulse is smeared out, return -1.0
        if delta > 1.0:
            # print width_ms, self.tsamp, tdm, tscat
            return -1

        # radiometer signal to noise
        sig_to_noise = rad.calcSNR(self.calcflux(pulsar, pop.ref_freq),
                                   self.beta,
                                   self.tsys,
                                   self.tskypy(pulsar),
                                   self.gain,
                                   self.npol,
                                   self.tobs,
                                   self.bw,
                                   delta)

        # account for aperture array, if needed
        if self.AA:
            sig_to_noise *= self._AA_factor(pulsar)

        # account for binary motion
        if pulsar.is_binary:
            # print "the pulsar is a binary!"
            if jerksearch:
                print "jerk"
                gamma = degradation.gamma3(pulsar,
                                           self.tobs,
                                           1)
            elif accelsearch:
                print "accel"
                gamma = degradation.gamma2(pulsar,
                                           self.tobs,
                                           1)
            else:
                print "norm"
                gamma = degradation.gamma1(pulsar,
                                           self.tobs,
                                           1)

                print "gamma harm1 = ", gamma

                gamma = degradation.gamma1(pulsar,
                                           self.tobs,
                                           2)

                print "gamma harm2 = ", gamma
                gamma = degradation.gamma1(pulsar,
                                           self.tobs,
                                           3)

                print "gamma harm3 = ", gamma
                gamma = degradation.gamma1(pulsar,
                                           self.tobs,
                                           4)
                print "gamma harm4 = ", gamma

        # return the S/N accounting for beam offset
        return sig_to_noise * degfac
示例#12
0
文件: evolve.py 项目: samb8s/PsrPopPy
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
示例#13
0
    def SNRcalc(self,
                pulsar,
                pop,
                accelsearch=False,
                jerksearch=False,
                rratssearch=False,
                giantpulse=False):
        """Calculate the S/N ratio of a given pulsar in the survey"""
        # if not in region, S/N = 0

        # if we have a list of pointings, use this bit of code
        # haven't tested yet, but presumably a lot slower
        # (loops over the list of pointings....)
        if rratssearch:
            if pulsar.br is None:
                print("Population doesn't have a burst rate")
                print("Use populate with --singlepulse")
                sys.exit()
            pulsar.pop_time = np.random.poisson(pulsar.br * self.tobs)

        if pulsar.dead:
            return 0.

        # otherwise check if pulsar is in entire region
        if self.inRegion(pulsar):
            # If pointing list is provided, check how close nearest
            # pointing is
            if self.pointingslist is not None:
                # convert offset from degree to arcmin
                offset = self.inPointing_new(pulsar) * 60.0

            else:
                # calculate offset as a random offset within FWHM/2
                offset = self.fwhm * math.sqrt(random.random()) / 2.0
        else:
            return -2

        if rratssearch == True and pulsar.pop_time < 1.0:
            return -3

        # Get degfac depending on self.gainpat
        if self.gainpat == 'airy':
            conv = math.pi / (60 * 180.)  # Conversion arcmins -> radians
            eff_diam = 3.0e8 / (self.freq * self.fwhm * conv * 1.0e6
                                )  # Also MHz -> Hz
            a = eff_diam / 2.  # Effective radius of telescope
            lamda = 3.0e8 / (self.freq * 1.0e6)  # Obs. wavelength
            kasin = (2 * math.pi * a / lamda) * np.sin(offset * conv)
            degfac = 4 * (j1(kasin) / kasin)**2
        else:
            degfac = math.exp(-2.7726 * offset * offset /
                              (self.fwhm * self.fwhm))

        # calc dispersion smearing across single channel
        tdm = self._dmsmear(pulsar)

        # calculate bhat et al scattering time (inherited from GalacticOps)
        # in units of ms
        if hasattr(pulsar, 't_scatter'):
            tscat = go.scale_bhat(pulsar.t_scatter, self.freq, pulsar.scindex)
        else:
            tscat = go.scatter_bhat(pulsar.dm, pulsar.scindex, self.freq)

        # Calculate the effective width
        width_ms = pulsar.width_degree * pulsar.period / 360.0
        weff_ms = math.sqrt(width_ms**2 + self.tsamp**2 + tdm**2 + tscat**2)

        # calculate duty cycle (period is in ms)
        delta = weff_ms / pulsar.period

        # if pulse is smeared out, return -1.0
        #don't really get smearing with giant pulse or rrat search right?
        if (delta > 1.0) & (not giantpulse) & (
                not rratssearch):  #and pulsar.pop_time >= 1.0:
            # print width_ms, self.tsamp, tdm, tscat
            return -1

        # radiometer signal to noise
        if (rratssearch == False) & (giantpulse == False):
            if self.surveyName == 'CHIME':
                #print('CHIME')
                sig_to_noise = rad.single_pulse_snr(
                    self.npol, self.bw, weff_ms * 1e3,
                    (self.tsys + self.tskypy(pulsar)), self.gain,
                    self.calcflux(pulsar, pop.ref_freq), self.beta)
            else:
                sig_to_noise = rad.calcSNR(self.calcflux(pulsar, pop.ref_freq),
                                           self.beta, self.tsys,
                                           self.tskypy(pulsar), self.gain,
                                           self.npol, self.tobs, self.bw,
                                           delta)
        elif giantpulse:
            #check how many times it burst
            #use 0.001 as the fraction of periods to emit a GP for now - place holder
            #values here currently taken from Popov et al 2007
            if pulsar.period < 100:
                pulses = 0.001 * (self.tobs / (1e-3 * pulsar.period))
                GP_flux = np.zeros(int(pulses))
                GP_lum = np.zeros(int(pulses))
                GP_snr = np.zeros(int(pulses))
                if pulses > 1:
                    for i in range(int(pulses)):
                        #parameters needs to be changed for later
                        #working in units of Jy us
                        fluence = dist.power_law_dual(1000, 11000, 2000, 200,
                                                      -3.2, -1.9)
                        #use pulse width of 55ms for now
                        #the flux calculated here is for the Crab, so we'll have to use a different distance measure.
                        average_flux = fluence / (55)
                        #2 kpc away to get luminosity at 1400Mhz from 1200 Mhz, hard code this for now
                        lum_1400 = average_flux * (2**2) * (
                            1400 / 1200)**pulsar.spindex
                        #scale down/up to survey frequency
                        flux = self._GPFlux(pulsar, lum_1400, 1400)
                        GP_lum[i] = lum_1400
                        GP_flux[i] = flux
                        GP_snr[i] = rad.single_pulse_snr(
                            self.npol, self.bw, weff_ms * 1e3,
                            (self.tsys + self.tskypy(pulsar)), self.gain, flux,
                            self.beta)
                    pulsar.lum_1400 = np.max(GP_lum)
                    sig_to_noise = np.max(GP_snr)
                    if sig_to_noise >= self.SNRlimit:
                        pulsar.det_pulses = GP_flux[GP_snr >= self.SNRlimit]
                        pulsar.det_nos = len(pulsar.det_pulses)
                    else:
                        pulsar.det_pulses = None
                        pulsar.det_nos = 0
                else:
                    return -3
            else:
                return -3
        elif rratssearch:
            #find number of times the pulse will pop up!
            #pop_time=int(pulsar.br*self.tobs)
            #Need to optimise this code...
            if pulsar.pop_time >= 1.0:
                pulse_snr = np.zeros(pulsar.pop_time)
                fluxes = np.zeros(pulsar.pop_time)
                lums = []
                mu = math.log10(pulsar.lum_inj_mu)
                sig = mu / pulsar.lum_sig
                # Draw from luminosity dist.
                #ADAM EDIT it would be nice to make this run on multiple cores... chime has so much observation time
                for burst_times in range(pulsar.pop_time):
                    pulsar.lum_1400 = dist.drawlnorm(mu, sig)
                    lums.append(pulsar.lum_1400)
                    flux = self.calcflux(pulsar, pop.ref_freq)
                    fluxes[burst_times] = flux
                    #ADAM EDIT: width changed to seconds instead of miliseconds???
                    pulse_snr[burst_times] = rad.single_pulse_snr(
                        self.npol, self.bw, weff_ms * 1e3,
                        (self.tsys + self.tskypy(pulsar)), self.gain, flux,
                        self.beta)
                pulsar.lum_1400 = np.max(lums)
                sig_to_noise = np.max(pulse_snr)
                if sig_to_noise >= self.SNRlimit:
                    pulsar.det_pulses = fluxes[pulse_snr >= self.SNRlimit]
                    pulsar.det_nos = len(pulsar.det_pulses)
                else:
                    pulsar.det_pulses = None
                    pulsar.det_nos = 0
            else:
                return -3
        # account for aperture array, if needed
        if self.AA and sig_to_noise > 0.0:
            sig_to_noise *= self._AA_factor(pulsar)

        # account for binary motion
        if pulsar.is_binary:
            # print "the pulsar is a binary!"
            if jerksearch:
                #print "jerk"
                gamma = degradation.gamma3(pulsar, self.tobs, 1)
            elif accelsearch:
                #print "accel"
                #Adam fix bug
                gamma = degradation.gamma2(pulsar, self.tobs, 1)
            else:
                #print "norm"
                gamma = degradation.gamma1(pulsar, self.tobs, 1)

                #print "gamma harm1 = ", gamma

                gamma = degradation.gamma1(pulsar, self.tobs, 2)

                #print "gamma harm2 = ", gamma
                gamma = degradation.gamma1(pulsar, self.tobs, 3)

                #print "gamma harm3 = ", gamma
                gamma = degradation.gamma1(pulsar, self.tobs, 4)
                #print "gamma harm4 = ", gamma

        # return the S/N accounting for beam offset

        return sig_to_noise * degfac