Skip to content

Commit b5483fc

Browse files
pannaraleMarcoCusinato
authored andcommitted
Introducing syntax for vetoing injections in PyGRB and final version of pycbc_pygrb_plot_null_stats (gwastro#4947)
* Introducing a (mute) apply_vetoes_to_found_injs function in PyGRB * Version of pycbc_pygrb_plot_null_stats with vetoes (albeit with a mute apply_vetoes_to_found_injs for the time being) * Small cleanup * Addresing typos * Update bin/pygrb/pycbc_pygrb_plot_null_stats --------- Co-authored-by: Marco Cusinato <[email protected]>
1 parent 263cd2c commit b5483fc

File tree

2 files changed

+114
-74
lines changed

2 files changed

+114
-74
lines changed

bin/pygrb/pycbc_pygrb_plot_null_stats

+67-74
Original file line numberDiff line numberDiff line change
@@ -46,55 +46,6 @@ __program__ = "pycbc_pygrb_plot_null_stats"
4646
# =============================================================================
4747
# Functions
4848
# =============================================================================
49-
# Function to load trigger data
50-
def load_data(input_file, ifos, vetoes, opts, injections=False, slide_id=None):
51-
"""Load data from a trigger/injection file"""
52-
53-
null_stat_type = opts.y_variable
54-
55-
# Initialize the dictionary
56-
data = {}
57-
data['coherent'] = None
58-
data[null_stat_type] = None
59-
60-
if input_file:
61-
if injections:
62-
logging.info("Loading injections...")
63-
# This will eventually become ppu.load_injections()
64-
trigs_or_injs = \
65-
ppu.load_triggers(input_file, ifos, vetoes,
66-
rw_snr_threshold=opts.newsnr_threshold,
67-
slide_id=slide_id)
68-
else:
69-
logging.info("Loading triggers...")
70-
trigs_or_injs = \
71-
ppu.load_triggers(input_file, ifos, vetoes,
72-
rw_snr_threshold=opts.newsnr_threshold,
73-
slide_id=slide_id)
74-
75-
# Coherent SNR is always used
76-
data['coherent'] = trigs_or_injs['network/coherent_snr']
77-
78-
# The other SNR may vary
79-
if null_stat_type == 'null':
80-
data[null_stat_type] = \
81-
trigs_or_injs['network/%s_snr' % null_stat_type][:]
82-
elif null_stat_type == 'single':
83-
key = opts.ifo + '/snr'
84-
data[null_stat_type] = trigs_or_injs[key][:]
85-
elif null_stat_type == 'coincident':
86-
data[null_stat_type] = ppu.get_coinc_snr(trigs_or_injs)
87-
88-
# Count surviving points
89-
num_trigs_or_injs = len(trigs_or_injs['network/reweighted_snr'])
90-
if injections:
91-
logging.info("%d injections found.", num_trigs_or_injs)
92-
else:
93-
logging.info("%d triggers found.", num_trigs_or_injs)
94-
95-
return data
96-
97-
9849
# Function that produces the contrours to be plotted
9950
def calculate_contours(opts, new_snrs=None):
10051
"""Generate the contours to plot"""
@@ -153,20 +104,19 @@ trig_file = os.path.abspath(opts.trig_file)
153104
found_missed_file = os.path.abspath(opts.found_missed_file)\
154105
if opts.found_missed_file else None
155106
zoom_in = opts.zoom_in
156-
null_stat_type = opts.y_variable
157107

158108
# Prepare plot title and caption
159109
y_labels = {'null': "Null SNR",
160110
'coincident': "Coincident SNR"} # TODO: overwhitened
161111
if opts.plot_title is None:
162-
opts.plot_title = y_labels[null_stat_type] + " vs Coherent SNR"
112+
opts.plot_title = y_labels[opts.y_variable] + " vs Coherent SNR"
163113
if opts.plot_caption is None:
164114
opts.plot_caption = ("Blue crosses: background triggers. ")
165115
if found_missed_file:
166116
opts.plot_caption = opts.plot_caption +\
167117
("Red crosses: injections triggers. ")
168118

169-
if null_stat_type == 'coincident':
119+
if opts.y_variable == 'coincident':
170120
opts.plot_caption += ("Green line: coincident SNR = coherent SNR.")
171121
else:
172122
opts.plot_caption = opts.plot_caption +\
@@ -181,30 +131,76 @@ outdir = os.path.split(os.path.abspath(opts.output_file))[0]
181131
if not os.path.isdir(outdir):
182132
os.makedirs(outdir)
183133

184-
# Extract IFOs and vetoes
185-
ifos, vetoes = ppu.extract_ifos_and_vetoes(trig_file, opts.veto_files,
186-
opts.veto_category)
187-
188-
# Extract trigger data
189-
trig_data = load_data(trig_file, ifos, vetoes, opts,
190-
slide_id=opts.slide_id)
191-
192-
# Extract (or initialize) injection data
193-
inj_data = load_data(found_missed_file, ifos, vetoes, opts,
194-
injections=True, slide_id=0)
134+
# Extract IFOs
135+
ifos = ppu.extract_ifos(trig_file)
136+
137+
# Generate time-slides dictionary
138+
slide_dict = ppu.load_time_slides(trig_file)
139+
140+
# We will be looping over slide_dict below so here we reduce it if possible
141+
if opts.slide_id is not None:
142+
for key in list(slide_dict.keys()):
143+
if key != opts.slide_id:
144+
slide_dict.pop(key, None)
145+
146+
# Generate segments dictionary
147+
segment_dict = ppu.load_segment_dict(trig_file)
148+
149+
# Construct trials removing vetoed times
150+
trial_dict, total_trials = ppu.construct_trials(
151+
opts.seg_files,
152+
segment_dict,
153+
ifos,
154+
slide_dict,
155+
opts.veto_file
156+
)
157+
158+
# Load triggers/injections (apply reweighted SNR cut, not vetoes)
159+
trig_data = ppu.load_data(trig_file, ifos, data_tag='trigs',
160+
rw_snr_threshold=opts.newsnr_threshold,
161+
slide_id=opts.slide_id)
162+
inj_data = ppu.load_data(found_missed_file, ifos, data_tag='injs',
163+
rw_snr_threshold=opts.newsnr_threshold,
164+
slide_id=0)
165+
166+
# Extract needed trigger properties and store them as dictionaries
167+
# Based on trial_dict: if vetoes were applied, trig_* are the veto survivors
168+
# Coherent SNR is always used
169+
x_key = 'network/coherent_snr'
170+
# The other SNR may vary
171+
y_key = 'network/' + opts.y_variable + '_snr'
172+
found_trigs_slides = ppu.extract_trig_properties(
173+
trial_dict,
174+
trig_data,
175+
slide_dict,
176+
segment_dict,
177+
[x_key, y_key]
178+
)
179+
found_trigs = {}
180+
for key in [x_key, y_key]:
181+
found_trigs[key] = numpy.concatenate(
182+
[found_trigs_slides[key][slide_id][:] for slide_id in slide_dict]
183+
)
184+
185+
# Gather injections found surviving vetoes
186+
found_injs, *_ = ppu.apply_vetoes_to_found_injs(
187+
found_missed_file,
188+
inj_data,
189+
ifos,
190+
veto_file=opts.veto_file,
191+
keys=[x_key, y_key]
192+
)
195193

196194
# Generate plots
197195
logging.info("Plotting...")
198196

199197
# Contours
198+
cont_colors = ['g-']
200199
snr_vals = None
201-
cont_colors = None
202200
shade_cont_value = None
203-
x_max = None
204201
# Coincident SNR plot case: we want a coinc=coh diagonal line on the plot
205-
if null_stat_type == 'coincident':
206-
cont_colors = ['g-']
207-
x_max = plu.axis_max_value(trig_data['coherent'], inj_data['coherent'],
202+
if y_key == 'network/coincident_snr':
203+
x_max = plu.axis_max_value(found_trigs[x_key], found_injs[x_key],
208204
found_missed_file)
209205
snr_vals = [4, x_max]
210206
null_stat_conts = [[4, x_max]]
@@ -226,12 +222,9 @@ if not opts.y_lims and zoom_in:
226222
opts.y_lims = '0,30'
227223
# Get rcParams
228224
rc('font', size=14)
229-
# Set color for out-of-range values
230-
# Determine y-axis values of triggers and injections
231-
y_label = y_labels[null_stat_type]
232-
trigs = [trig_data['coherent'], trig_data[null_stat_type]]
233-
injs = [inj_data['coherent'], inj_data[null_stat_type]]
234-
plu.pygrb_plotter(trigs, injs, "Coherent SNR", y_label, opts,
225+
plu.pygrb_plotter([found_trigs[x_key], found_trigs[y_key]],
226+
[found_injs[x_key], found_injs[y_key]],
227+
"Coherent SNR", y_labels[opts.y_variable], opts,
235228
snr_vals=snr_vals, conts=null_stat_conts,
236229
shade_cont_value=shade_cont_value,
237230
colors=cont_colors, vert_spike=True,

pycbc/results/pygrb_postprocessing_utils.py

+47
Original file line numberDiff line numberDiff line change
@@ -368,6 +368,53 @@ def load_data(input_file, ifos, rw_snr_threshold=None, data_tag=None,
368368
return trigs_dict
369369

370370

371+
# =============================================================================
372+
# Function to apply vetoes to found injections
373+
# =============================================================================
374+
def apply_vetoes_to_found_injs(found_missed_file, found_injs, ifos,
375+
veto_file=None, keys=None):
376+
"""Separate injections surviving vetoes from vetoed injections.
377+
THIS IS ESSENTIALLY AN EMPTY PLACE HOLDER AT THE MOMENT: IT RETURNS
378+
THE INJECTIONS GIVEN IN INPUT, WITHOUT APPLYING VETOES.
379+
380+
Parameters
381+
----------
382+
found_missed_file: injections results File
383+
384+
found_injs: dictionary of found injections
385+
386+
ifos: list of interferometers to use in vetoing
387+
388+
veto_file: vetoed segments File (optional)
389+
390+
keys: list of desired dataset names (optional)
391+
392+
Return
393+
------
394+
found_after_vetoes: dictionary of injections surviving vetoes
395+
396+
missed_after_vetoes: dictionary of vetoed injections
397+
398+
found_idx: numpy.array of indices of surviving injections
399+
400+
veto_idx: numpy.array of indices of vetoed injections
401+
"""
402+
403+
keep_keys = keys if keys else found_injs.keys()
404+
405+
if not found_missed_file:
406+
return (dict.fromkeys(keep_keys, numpy.array([])),
407+
dict.fromkeys(keep_keys, numpy.array([])),
408+
None, None)
409+
410+
found_after_vetoes = found_injs
411+
missed_after_vetoes = dict.fromkeys(keep_keys, numpy.array([]))
412+
found_idx = numpy.arange(len(found_injs[ifos[0]+'/end_time'][:]))
413+
veto_idx = numpy.array([], dtype=numpy.int64)
414+
415+
return found_after_vetoes, missed_after_vetoes, found_idx, veto_idx
416+
417+
371418
# =============================================================================
372419
# Detector utils:
373420
# * Function to calculate the antenna response F+^2 + Fx^2

0 commit comments

Comments
 (0)