def get_data(): """Get the population data.""" # Construct population pop = CosmicPopulation(n_srcs=SIZE, n_days=1, name='standard_candle') pop.set_dist(model='sfr', z_max=2.5, H_0=67.74, W_m=0.3089, W_v=0.6911) pop.set_dm_host(model='constant', value=100) pop.set_dm_igm(model='ioka', slope=1000, std=None) pop.set_dm_mw(model='ne2001') pop.set_emission_range(low=10e6, high=10e9) pop.set_lum(model='constant', value=1e36) pop.set_w(model='constant', value=1.) pop.set_si(model='constant', value=0) pop.generate() # Survey population pops = {} for b in BEAMPATTERNS: pprint(f'Surveying with {b} beampattern') n_s = 0 bp = b if b.startswith('airy'): bp, n_s = b.split('-') n_s = int(n_s) survey = Survey(name='perfect-small') # Prevent beam from getting larger than the sky survey.set_beam(model=bp, n_sidelobes=n_s, size=10) surv_pop = SurveyPopulation(pop, survey) print(surv_pop.source_rate) pops[b] = surv_pop return pops
def set_up_surveys(self): """Set up surveys.""" surveys = [] for name in self.survey_names: survey = Survey(name=name) survey.set_beam(model='airy', n_sidelobes=1) if name in ('chime-frb', 'wsrt-apertif', 'parkes-htru'): survey.set_beam(model=name) surveys.append(survey) return surveys
def complex_rates(remake=REMAKE, alphas=ALPHAS, size=SIZE, surveys=SURVEYS): """Calculate expected rates for a complex populations.""" rates = defaultdict(list) # Don't always regenerate a population if remake is False: for alpha in alphas: for s in surveys: surv_rates = unpickle(f'complex_alpha_{alpha}_{s}').source_rate pprint(f'Alpha:{alpha:.2}, Survey: {s}, Det: {surv_rates.det}') rate = (surv_rates.det / surv_rates.days) rates[s].append(rate) else: pops = [] for alpha in alphas: if alpha <= -1.0 and ADAPTATIVE_SCALING: size = 1e7 if alpha <= -1.5 and ADAPTATIVE_SCALING: size = 1e8 pop = CosmicPopulation.complex(size) pop.set_dist(model='vol_co', z_max=2.5, alpha=alpha, H_0=67.74, W_m=0.3089, W_v=0.6911) pop.set_lum(model='powerlaw', low=1e40, high=1e45, power=-1) pop.name = f'complex_alpha_{alpha}' pops.append(pop) # Set up surveys ss = [] for s in surveys: survey = Survey(name=s) survey.set_beam(model='airy', n_sidelobes=1) ss.append(survey) surv_pops = LargePopulation(pop, *ss).pops for i, s in enumerate(surveys): surv_rates = surv_pops[i].source_rate pprint(f'Alpha:{alpha:.2}, Survey: {s}, Det: {surv_rates.det}') rate = (surv_rates.det / surv_rates.days) rates[s].append(rate) # Scale rates to first survey in list for s in surveys: if s != surveys[0]: norm = [] for i, r in enumerate(rates[s]): norm.append(r / rates[surveys[0]][i]) rates[s] = norm rates[surveys[0]] = [r / r for r in rates[surveys[0]]] return rates
def simple_rates(remake=REMAKE, alphas=ALPHAS, size=SIZE, surveys=SURVEYS): """Calculate expected rates for a simple populations.""" rates = defaultdict(list) # Don't always regenerate a population if remake is False: for alpha in alphas: for s in surveys: surv_rates = unpickle(f'simple_alpha_{alpha}_{s}').source_rate pprint(f'Alpha:{alpha:.2}, Survey: {s}, Det: {surv_rates.det}') rate = (surv_rates.det / surv_rates.days) rates[s].append(rate) else: pops = [] for alpha in alphas: pop = CosmicPopulation.simple(size) pop.set_dist(alpha=alpha) pop.name = f'simple_alpha_{alpha}' pops.append(pop) # Set up surveys ss = [] for s in surveys: survey = Survey(name=s) survey.set_beam(model='perfect', n_sidelobes=0.5) ss.append(survey) surv_pops = LargePopulation(pop, *ss).pops for i, s in enumerate(surveys): surv_rates = surv_pops[i].source_rate pprint(f'Alpha:{alpha:.2}, Survey: {s}, Det: {surv_rates.det}') rate = (surv_rates.det / surv_rates.days) rates[s].append(rate) # Scale rates to HTRU for s in surveys: if s != 'parkes-htru': norm = [] for i, r in enumerate(rates[s]): norm.append(r/rates['parkes-htru'][i]) rates[s] = norm rates['parkes-htru'] = [r/r for r in rates['parkes-htru']] return rates
def iter_run(i): r = CosmicPopulation(N_SRCS, n_days=N_DAYS, repeaters=True) r.set_dist(model='vol_co', z_max=1.0) r.set_dm_host(model='gauss', mean=100, std=200) r.set_dm_igm(model='ioka', slope=1000, std=None) r.set_dm(mw=True, igm=True, host=True) r.set_emission_range(low=100e6, high=10e9) r.set_lum(model='powerlaw', per_source='different', low=1e40, high=1e45, power=0) r.set_si(model='gauss', mean=-1.4, std=1) r.set_w(model='lognormal', per_source='different', mean=0.1, std=1) rate = lognormal(RATE, 2, N_SRCS) if LARGE_POP: rate = lognormal(RATE, 2, int(MAX_SIZE)) # Not completely kosher r.set_time(model='poisson', rate=rate) # Set up survey s = Survey('chime-frb', n_days=N_DAYS) s.set_beam(model='chime-frb') s.gen_pointings() # To ensure each sub pop has the same pointings # Only generate FRBs in CHIME's survey region r.set_direction(model='uniform', min_ra=s.ra_min, max_ra=s.ra_max, min_dec=s.dec_min, max_dec=s.dec_max) if LARGE_POP: surv_pop = LargePopulation(r, s, max_size=MAX_SIZE).pops[0] else: r.generate() surv_pop = SurveyPopulation(r, s) surv_pop.name = f'cosmic_chime_longer_{i}' surv_pop.save() print(surv_pop.source_rate) print(surv_pop.burst_rate) pprint(f'i: {i}') pprint(f'# one-offs: {surv_pop.n_one_offs()}') pprint(f'# repeaters: {surv_pop.n_repeaters()}')
def analytical_rates(surveys=SURVEYS, alphas=ALPHAS): """Use a analytical model to scale detection rates to various alphas.""" rates = {} for surv in surveys: # Get survey parameters surv1 = Survey(surv) surv1.set_beam('perfect', n_sidelobes=0.5) surv2 = Survey(surveys[0]) surv2.set_beam('perfect', n_sidelobes=0.5) # Calculate rate per alpha rate = [] for alpha in alphas: rate.append(compare_surveys(surv1, surv2, alpha)) rates[surv] = rate return rates
def get_data(): """Get survey populations.""" # Don't always regenerate a population if REMAKE is False: # Check where a possible population would be located path = '' surv_pops = [] for telescope in TELESCOPES: survey = telescope if telescope == 'askap': survey = 'askap-fly' if telescope == 'parkes': survey = 'parkes-htru' name = f'{survey}' path = paths.populations() + f'complex_{name}.p' surv_pops.append(unpickle(path)) return surv_pops cosmic_pop = CosmicPopulation.complex(SIZE, generate=False) surveys = [] for telescope in TELESCOPES: pattern = 'airy' if telescope == 'parkes': pattern = 'parkes-htru' s = telescope if telescope == 'askap': s = 'askap-fly' survey = Survey(s) survey.set_beam(model=pattern, n_sidelobes=1) surveys.append(survey) return LargePopulation(cosmic_pop, *surveys).pops
from obs_rep_frac import calc_rep_frac init_surv_time_frac = 0.05 MAKE = False PLOT_CHIME = False N_SRCS = 3.6e4 N_DAYS = 100 RATE = 9 # per day # Chime started in Aug 2018. Assuming 2/day for one-offs. # Total of 9 repeaters published on 9 Aug 2019. = ~year N_CHIME = {'rep': 9, 'one-offs': 365 * 2, 'time': 365} # Set up survey chime = Survey('chime-frb', n_days=N_DAYS) chime.set_beam(model='chime-frb') if MAKE: r = CosmicPopulation(N_SRCS, n_days=N_DAYS, repeaters=True) r.set_dist(model='vol_co', z_max=1.0) r.set_dm_host(model='gauss', mean=100, std=200) r.set_dm_igm(model='ioka', slope=1000, std=None) r.set_dm(mw=True, igm=True, host=True) r.set_emission_range(low=100e6, high=10e9) r.set_lum(model='powerlaw', per_source='different', low=1e40, high=1e45, power=0) r.set_si(model='gauss', mean=-1.4, std=1)
from frbpoppy import CosmicPopulation, Survey import frbpoppy.gen_dists as gd # Set up a population cosmic_pop = CosmicPopulation(1e4, generate=False) # ... or adapt the population per parameter, e.g. cosmic_pop.set_dist(z_max=2.5) # Or to adapt the luminosity cosmic_pop.set_lum(model='powerlaw', low=1e44, high=1e45) # Generate the population cosmic_pop.generate() # Setup a survey survey = Survey('wsrt-apertif') # and adapt the survey with survey.set_beam('airy', n_sidelobes=2) survey.snr_limit = 2 # For a full list of available arguments or parameters check the classes as # defined in /frbpoppy/*.py # Some more difficult examples # Use a convolution of two distributions cosmic_pop = CosmicPopulation.simple(n_srcs=1e4, repeaters=True) # Draw the mean value per source from a normal distribution mean_dist = gd.trunc_norm(mean=1, std=2, shape=int(1e4)) # And use those means as a _means_ to generate from a new Gaussian # distribution per source cosmic_pop.set_w(model='gauss', per_source='different',
pop.set_dist(model='sfr', z_max=2.5, H_0=67.74, W_m=0.3089, W_v=0.6911) pop.set_dm_igm(model='ioka', slope=1200, std=0) pop.set_dm(mw=False, host=False, igm=True) pop.set_emission_range(low=10e6, high=10e9) pop.set_lum(model='constant', value=1e36) pop.set_w(model='constant', value=1) pop.set_si(model='constant', value=0) pop.generate() pop_obs = {} survey = Survey('perfect-small') for pattern in BEAMPATTERNS: survey.set_beam(model=pattern, n_sidelobes=0, size=90) # Observe populations pop_obs[pattern] = SurveyPopulation(pop, survey) pop_obs[pattern].name = f'obs-{pattern}' pop_obs[pattern].source_rate print(pop_obs[pattern].source_rate) pop_obs[pattern].save() plot_aa_style() f, (ax1) = plt.subplots(1, 1) for p in BEAMPATTERNS: pop = pop_obs[p] limit = 1e-9
import numpy as np import matplotlib.pyplot as plt from tqdm import tqdm from frbpoppy import CosmicPopulation, Survey, SurveyPopulation, hist from tests.convenience import plot_aa_style, rel_path from alpha_real import EXPECTED, poisson_interval N_DAYS = 1 # Not used in eventual result SCALE_TO = 'parkes-htru' pop = CosmicPopulation.complex(n_srcs=1e5, n_days=N_DAYS) pop.generate() apertif = Survey('wsrt-apertif', n_days=N_DAYS) apertif.set_beam(model='apertif_real') if SCALE_TO == 'parkes-htru': htru = Survey('parkes-htru', n_days=N_DAYS) htru.set_beam(model='parkes') if SCALE_TO == 'askap': askap = Survey('askap-fly', n_days=N_DAYS) askap.set_beam(model='gaussian', n_sidelobes=0.5) days_per_frbs = [] for i in tqdm(range(2000), desc='Survey Run'): apertif_pop = SurveyPopulation(pop, apertif, mute=True) if SCALE_TO == 'parkes-htru': htru_pop = SurveyPopulation(pop, htru, mute=True)
r.set_dm_igm(model='ioka', slope=1000, std=None) r.set_dm(mw=True, igm=True, host=True) r.set_emission_range(low=100e6, high=10e9) r.set_lum(model='powerlaw', per_source='different', low=1e40, high=1e45, power=0) r.set_si(model='gauss', mean=-1.4, std=1) r.set_w(model='lognormal', per_source='different', mean=0.1, std=1) rate = lognormal(ra, 1, int(n)) r.set_time(model='poisson', rate=rate) # Set up survey s = Survey('chime-frb', n_days=N_DAYS) s.set_beam(model='chime-frb') # Only generate FRBs in CHIME's survey region r.set_direction(model='uniform', min_ra=s.ra_min, max_ra=s.ra_max, min_dec=s.dec_min, max_dec=s.dec_max) r.generate() surv_pop = SurveyPopulation(r, s) surv_pop.name = 'cosmic_chime' print(surv_pop.source_rate) print(surv_pop.burst_rate) pprint(f'# one-offs: {surv_pop.n_one_offs()}')
linestyle = self.lz[pop.z_max] colour = self.colours[int(i % (len(pops)/2))] label = '_'.join(pop.name.split('_')[0:-1]) if i > (len(pops)/2 - 1): # Turn off some line labels label = f'_{label}' ax.step(*self.calc_cum_hist(pop), where='mid', label=rf'{label}', linestyle=linestyle, color=colour) def calc_cum_hist(self, pop): # Bin up parameter in a cumulative bin edges, values = hist(pop.frbs.snr, bin_type='log') if isinstance(edges, float): return np.nan, np.nan n_gt_s = np.cumsum(values[::-1])[::-1] # Normalise to S/N of 10^5 log_diff = (np.log10(edges[0]) - np.log10(1e0)) edges = 10**(np.log10(edges) - log_diff) return edges, n_gt_s if __name__ == '__main__': for s in SURVEYS: survey = Survey(s) survey.set_beam('gaussian') if s == 'perfect': survey.set_beam('perfect') Flattening(SIZE, survey)
# Generate population with standard candles pop = CosmicPopulation(n_srcs=5e5, n_days=1, name='standard') pop.set_dist(model='sfr', z_max=2.5, H_0=67.74, W_m=0.3089, W_v=0.6911) pop.set_dm_igm(model='ioka', slope=1200, std=0) pop.set_dm(mw=False, host=False, igm=True) pop.set_emission_range(low=10e6, high=10e9) pop.set_lum(model='constant', value=1e36) pop.set_w(model='constant', value=1) pop.set_si(model='constant', value=0) pop.generate() pop_obs = {} survey = Survey('perfect-small') survey.beam_size_at_fwhm = 10. survey.set_beam(model='airy') for sidelobe in SIDELOBES: survey.set_beam(model='airy', n_sidelobes=sidelobe) # Observe populations pop_obs[sidelobe] = SurveyPopulation(pop, survey) pop_obs[sidelobe].name = f'obs-{sidelobe}' pop_obs[sidelobe].source_rate pop_obs[sidelobe].save() plot_aa_style() f, (ax1) = plt.subplots(1, 1) for p in SIDELOBES:
def generate(parallel=False): from joblib import Parallel, delayed from frbpoppy import CosmicPopulation, Survey, pprint from frbpoppy import SurveyPopulation from tqdm import tqdm # Set up rate dataframe paras = [ALPHAS, LIS, SIS] vals = np.array(np.meshgrid(*paras)).T.reshape(-1, len(paras)) cols = ['alpha', 'li', 'si'] df = pd.DataFrame(vals, columns=cols) # Set up surveys surveys = [] for name in SURVEY_NAMES: survey = Survey(name=name) survey.set_beam(model='airy', n_sidelobes=1) surveys.append(survey) df[name] = np.nan def iter_alpha(i, surveys=surveys, parallel=None): alpha = ALPHAS[i] pop = CosmicPopulation.complex(SIZE) pop.set_dist(model='vol_co', z_max=1.0, alpha=alpha) pop.set_lum(model='powerlaw', low=1e40, high=1e45, power=-1) pop.generate() for li in LIS: pop.set_lum(model='powerlaw', low=1e40, high=1e45, power=li) pop.gen_lum() for si in SIS: pop.set_si(model='constant', value=si) pop.gen_si() pop.name = f'complex_alpha_{alpha}_lum_{li}_si_{si}' for survey in surveys: surv_pop = SurveyPopulation(pop, survey) print(surv_pop.name) surv_pop.save() sr = surv_pop.source_rate rate = sr.det / sr.days mask = (df.alpha == alpha) & (df.li == li) & (df.si == si) if parallel is not None: i = df[mask].index j = SURVEY_NAMES.index(survey.name) parallel[i, j] = rate else: df.loc[mask, survey.name] = rate if parallel: n_cpu = min([3, os.cpu_count() - 1]) pprint(f'{os.cpu_count()} CPUs available') r = range(len(ALPHAS)) temp_path = ('./temp.mmap') # Make a temp memmap to have a sharedable memory object temp = np.memmap(temp_path, dtype=np.float64, shape=(len(vals), len(SURVEY_NAMES)), mode='w+') Parallel(n_jobs=n_cpu)(delayed(iter_alpha)(i, parallel=temp) for i in tqdm(r)) for name in SURVEY_NAMES: col = SURVEY_NAMES.index(name) df[name] = temp[:, col] else: for i in tqdm(range(len(ALPHAS)), desc='Alphas'): iter_alpha(i) df.to_csv(CSV_PATH)
"""Generate a repeater population and split into repeaters and one-offs.""" import numpy as np from frbpoppy import CosmicPopulation, Survey, SurveyPopulation from frbpoppy import split_pop, pprint, plot DAYS = 1 r = CosmicPopulation.simple(int(1e4), n_days=DAYS, repeaters=True) r.set_time(model='regular', rate=2) r.set_lum(model='powerlaw', low=1e40, high=1e45, per_source='different') r.generate() survey = Survey('chime-frb', n_days=DAYS) survey.set_beam(model='perfect') surv_pop = SurveyPopulation(r, survey) # Split population into seamingly one-off and repeater populations mask = ((~np.isnan(surv_pop.frbs.time)).sum(1) > 1) pop_ngt1, pop_nle1 = split_pop(surv_pop, mask) pop_ngt1.name += ' (> 1 burst)' pop_nle1.name += ' (1 burst)' pops = [pop_nle1, pop_ngt1] pprint(f'{surv_pop.n_sources()} sources detected') pprint(f'{surv_pop.n_bursts()} bursts detected') plot(surv_pop)
import numpy as np import matplotlib.pyplot as plt from matplotlib.colors import LogNorm from matplotlib.lines import Line2D from frbpoppy import Survey, int_pro_fixed from tests.convenience import plot_aa_style, rel_path T_OBS = 60 * 60 # seconds OBJ_OFFSET = 1 # deg INTENSITY_LIMIT = 1e-8 # Set up survey survey = Survey('chime-frb', n_days=0.99) survey.set_beam('chime-frb') # Get beam properties beam_array = survey.beam_array pattern = survey.beam_pattern pixel_scale = np.float64(survey.pixel_scale) latitude = survey.latitude mount_type = survey.mount_type # Limit extent of intensity for plotting reasons beam_array[beam_array < INTENSITY_LIMIT] = INTENSITY_LIMIT # Set pointings survey.gen_pointings() pointings = survey.pointings
r.set_dist(z_max=2) r.set_lum(model='powerlaw', low=1e35, high=1e45, power=-1.7, per_source='different') r.set_time(model='poisson', rate=3) r.set_dm_igm(model='ioka', slope=1000, std=0) r.set_dm(mw=False, igm=True, host=False) r.set_w('constant', value=1) r.generate() # Set up survey survey = Survey('chime-frb', n_days=DAYS) survey.set_beam(model='chime-frb') survey.snr_limit = 1e-13 surv_pop = SurveyPopulation(r, survey) pprint(f'{r.n_bursts()}:{surv_pop.n_bursts()}') pprint(f'{surv_pop.n_sources()} sources detected') if r.n_bursts() < PLOTTING_LIMIT_N_SRCS: pprint('Not sufficient FRB sources for plotting') exit() # Split population into seamingly one-off and repeater populations mask = ((~np.isnan(surv_pop.frbs.time)).sum(1) > 1) pop_rep, pop_one = split_pop(surv_pop, mask) pop_rep.name += ' (> 1 burst)'
"""Short example of how frbpoppy works. The first time you run frbpoppy, a series of cosmological databases will be constructed to set up subsequent runs. This first run can take ~2h on a 4 core machine. Subsequent runs will take mere seconds. """ from frbpoppy import CosmicPopulation, Survey, SurveyPopulation, plot # Set up an FRB population of one-offs # Add repeaters=True to turn into an FRB population of repeaters cosmic_pop = CosmicPopulation.complex(1e5, n_days=0.01) # Generate your FRB population cosmic_pop.generate() # Setup a survey survey = Survey('parkes-htru') survey.set_beam(model='parkes-htru') # Observe the FRB population survey_pop = SurveyPopulation(cosmic_pop, survey) # Check the detection rates print(survey_pop.source_rate) # Plot populations in a browser plot(cosmic_pop, survey_pop, tns='parkes')
def gen_survey(self, name): survey = Survey(name) survey.set_beam('gaussian') return survey
in_surv_region = np.sum(mask) tot_region = len(mask) area_sky = 4 * np.pi * (180 / np.pi)**2 # In sq. degrees f_area = (survey.beam_size / area_sky) * (tot_region / in_surv_region) surv_f_area[name] = f_area print(f'{name} covers {f_area*100}% of the sky') surv_pops = [] for name in SURVEYS: # Set up survey survey = Survey(name) if name in ('parkes-htru', 'wsrt-apertif'): survey.set_beam(model=name) # Set up CosmicPopulation pop = CosmicPopulation.optimal(SIZE, generate=False) # Only generate FRBs in the survey region pop.set_direction(model='uniform', min_ra=survey.ra_min, max_ra=survey.ra_max, min_dec=survey.dec_min, max_dec=survey.dec_max) # Parkes also has galactic limits: if name == 'parkes-htru': pop.gen_index() pop.gen_dist()