Source code for xpipeline.setuputils.xnetworkselection

# -*- coding: utf-8 -*-
# Copyright (C) Scott Coughlin (2017)
#
# This file is part of XPypeline.
#
# GWpy is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# GWpy is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with GWpy.  If not, see <http://www.gnu.org/licenses/>.

"""This module provides the basis for selecting a valid network of detectors to use for an analysis based on some requiremnets for the quality of the on-source data 
"""
import numpy as np

[docs]def main(detectorList, centerTimesFile, timeOffsetsFile, cat1_segment_file, cat24_segment_file, output_file, verbosity, windowBeginOffset, windowEndOffset, transientTime, windowLength): """ detectors_considered cell array of ifos to be considered, e.g., ['H1' 'H2' 'L1'], size (1 * nIfo). centerTimes vector of segment center times, size (nJobs * 1). timeOffsets array of segment time offsets, size(nJobs * nIfo). cat1_seglist structure containing cat1 DQ segments (i.e., livetimes). cat1_seglist(nIfo).gpsStart() cat1_seglist(nIfo).duration() cat2_seglist Similar to cat1_seglist but containing cat2 veto segments (deadtime). verbosity string used to control verbosity of output, either 'verbose' or 'quiet'. output_file String. Name of file to which we will write the detector networks. windowBeginOffset String. Offset [sec] between start of on-source window and trigger time, e.g., -600. windowEndOffset String. Offset [sec] between end of on-source window and trigger time, e.g., 60. transientTime String. Length of time [sec] discarded at beginning and end of each analysis block, e.g., 4. windowLength String. 2*transientTime+jobsPerWindow*(blockTime-2*transientTime) XNETWORKSELECTION is a wrapper function for calling XAPPLYNETWORKTESTS. It is intended to be compiled, allowing it to be called from the command line or from python scripts such as grb.py. XNETWORKSELECTION takes in lists of event times and on-source windows, plus lists of science mode livetime and veto deadtime segment files. It uses XAPPLYNETWORKTESTS to determine which detectors satisfy the data quality criteria (defined in XAPPLYNETWORKTESTS) to be used for the analysis of each event. The list of acceptable detectors for each event is written to the file specified by the input argument output_file, with one line per event, of the form 'H1L1V1', or 'H1H2', etc. Our criteria for including an ifo in our network is as follows:w i) No deadtime incurred by category 1 flags in an interval [-128,+128]s about the GRB trigger time. X-pipeline requires 256s in order to estimate the PSD, category 1 flags raised within these 256s will lead to inaccurate/incorrect PSD estimation. ii) Less than 9s (5#) deadtime incurred by category 2 flags in the onsource, i.e., an interval [-120,+60]s about the GRB trigger time. We tune our glitch rejection cuts using calculation of the 90# UL on hrss amplitude. If we lose much more than 5# deadtime in our (dummy) onsource we may not be able to accurately estimate the hrss amplitude leading to 90# detection efficiency. iii) No deadtime incurred by category 2 flags in an interval [-5,+1]s about the GRB trigger time. Many GRB models predict similar arrival times of EM and GW emission from a GRB. We therefore require that inclusion of an ifo does not kill times close to the GRB trigger time. """ # ---- Number of jobs equals number of centerTimes pass_inited in. nJobs = len(centerTimes) # ---- Initially assume all ifos FAIL our criteria for all of # the jobs. # ---- Note that unlike other pass_init flags this has one element # per job (rather than one per trigger etc.). pass_init = np.zeros(nJobs,len(detectorList)) ############################################################################### # Apply network test. ############################################################################### # ---- Loop over jobs, each job represents a choice # of segment centerTimes and timeOffsets. for iJob in range(0,nJobs): # ---- Loop over ifos we are considering. for iIfo in range(0,len(detectorList)): ######################################################################### # Unslide centerTimes. ######################################################################### # ---- Before applying vetoSeg cuts we must unslide the triggers. unslidCenterTimes[iJob,iIfo] = centerTimes[iJob] + timeOffsets[iJob,iIfo] ######################################################################### # Check that we have cat1 flags raised in [-128,+128]s interval about # unslid centerTimes. ######################################################################### # ---- Define our [-128,+128]s interval about the (unslid) centerTimes. goodBefore = -windowBeginOffset+transientTime duration = windowLength # ---- Find intersections between cat1 segments and the [-128,+128]s # interval about unslid centerTimes. # ---- Passing the shorter list to Coincidence2 first # speeds it up. coincOut=Coincidence2(unslidCenterTimes(iJob,iIfo)-goodBefore,duration, cat1_seglist(iIfo).gpsStart, cat1_seglist(iIfo).duration) # ---- We require an info to have cat1 flags (i.e., be in science mode) # for the full duration of the [-128,+128]s. if ~isempty(coincOut): # ---- If our interval is completely contained within a cat1 segment # we should only have one intersection and it should have the # duration of our interval. if (size(coincOut,1) == 1) and (coincOut(1,2) == duration): pass_init[iJob,iIfo] = 1 if (verboseFlag == 1): print('#s has good cat 1 DQ for job #d \n'.format(detectors_considered[iIfo], iJob ), file=sys.stdout) ######################################################################### # Check for cat2 flags raised in [-5,+1]s interval about unslid # centerTimes. ######################################################################### # ---- Define our [-5,+1]s interval about the (unslid) centerTimes. goodBefore = 5 duration = 6 # ---- Find intersections between cat2 segments and the [-5,+1]s # interval about unslid centerTimes. # ---- Passing the shorter list to Coincidence2 first # speeds it up. coincOut=Coincidence2(unslidCenterTimes(iJob,iIfo)-goodBefore,duration, cat2_seglist(iIfo).gpsStart, cat2_seglist(iIfo).duration) # ---- If there were any coincidences between our interval and the # vetoSegs we must discard this job. We don't count # coincidences with zero duration (edge overlap) if not isempty(coincOut) and any(coincOut[:,2]>0): # ---- Setting pass_init for this job to zero. pass_init[iJob,iIfo] = 0 if (verboseFlag == 1): print('Time killed in [-#f,+#f]s interval about center time \n'.format(goodBefore,duration-goodBefore), file=sys.stdout) print('startTime stopTime\n', file=sys.stdout) print('--------------------------\n', file=sys.stdout) for iCoinc in range(0,len(coincOut[:,1])): print('#9.2f #9.2f \n'.format( coincOut(iCoinc,1), coincOut(iCoinc,1) + coincOut(iCoinc,2)), file=sys.stdout) print('Setting pass_init to zero \n', file=sys.stdout) ######################################################################### # Find deadtime in [-120,+60]s interval about unslid centerTime. ######################################################################### # ---- Define our [-120,+60]s interval about the (unslid) centerTimes. goodBefore = -windowBeginOffset duration = windowEndOffset-windowBeginOffset # ---- Allowed Threshold on deadtime in on source window is 5# killedThresh = 0.05*duration # ---- Find intersections between cat2 veto segs and our [-120,+60]s # on-source region. # ---- Passing the shorter list to Coincidence2 first # speeds it up coincOut=Coincidence2(unslidCenterTimes(iJob,iIfo)-goodBefore,duration, cat2_seglist(iIfo).gpsStart, cat2_seglist(iIfo).duration) # ---- Record times killed by segments. if isempty(coincOut): #killedTimes[iJob,iIfo] = [0,0] # ---- No times killed by cat2 veto segments. liveTimes[iJob,iIfo] = [unslidCenterTimes(iJob,iIfo)-goodBefore,duration] else: #killedTimes[iJob,iIfo] = [coincOut(:,1),coincOut(:,2)] # ---- Some times killed by cat2 veto segments. # If any one ifo has deadtime >= killedThresh # we will discard it straight away. # ---- Sum up duration of intersections to find deadtime. totDeadTime_cat2[iJob,iIfo] = sum(coincOut[:,2]) if totDeadTime_cat2[iJob,iIfo] >= killedThresh: pass_init[iJob,iIfo] = 0 liveTimes[iJob,iIfo] = ComplementSegmentList(coincOut[:,1],coincOut[:,2], unslidCenterTimes(iJob,iIfo)-goodBefore, unslidCenterTimes(iJob,iIfo)-goodBefore+duration) # ---- Resliding liveTimes in order to measure how much of # deadtime in our interval. # To do this we must SUBTRACT timeOffsets. reslidLiveTimes[iJob,iIfo] = [liveTimes[iJob,iIfo][:,1] - timeOffsets(iJob,iIfo), liveTimes[iJob,iIfo][:,2]] # ---- For current job, find intersection of reslid liveTimes from all ifos # that are still in our network. intersectReslidLiveTimes[iJob] = [0, Inf] for iIfo in range(0, len(detectors_considered)): # ---- We only care about the ifo's livetime if it is still in # our network. if pass_init(iJob,iIfo): coincOut = Coincidence2(intersectReslidLiveTimes[iJob][:,1], intersectReslidLiveTimes[iJob][:,2], reslidLiveTimes[iJob,iIfo][:,1], reslidLiveTimes[iJob,iIfo][:,2]) if isempty(coincOut): intersectReslidLiveTimes[iJob] = [0,0] else: intersectReslidLiveTimes[iJob] = [coincOut[:,1], coincOut[:,2]] # ---- For current job, find time killed by cat2 veto flags. finalKilledTimes[iJob] = ComplementSegmentList( intersectReslidLiveTimes[iJob][:,1], intersectReslidLiveTimes[iJob][:,2], centerTimes[iJob]-goodBefore,centerTimes[iJob]-goodBefore+duration) deadtime[iJob] = sum(finalKilledTimes[iJob][:,2]) ############################################################################ # Discard jobs with >=9s deadtime in [-120,+60]s interval # about centerTime. ############################################################################ if (verboseFlag == 1): print('Total time killed in [' + num2str(windowBeginOffset) + ',' + num2str(windowEndOffset) + ']s interval about centre time: #9.2f \n'.format(deadtime(iJob)), file=sys.stdout) print('startTime stopTime\n', file=sys.stdout) print('--------------------------\n', file=sys.stdout) for iCoinc in range(0, len(finalKilledTimes[iJob][:,1])): print('#9.2f #9.2f \n'.format( finalKilledTimes[iJob][iCoinc,1], finalKilledTimes[iJob][iCoinc,1] + finalKilledTimes[iJob][iCoinc,2]), file=sys.stdout) # ---- Check total duration of killed times if deadtime(iJob) >= killedThresh: warning(['Killing network due to cat2 flags in on-source. ' 'We should investigate this network further']) networkCell[iJob] = ['X'] for iIfo in range(0, len(detectors_considered)): if pass_init(iJob,iIfo): networkCell[iJob] = [networkCell[iJob], detectors_considered[iIfo]] pass_init[iJob,iIfo] = 0 if (verboseFlag == 1): print('More than #ds killed, setting pass_init to zero \n'.fromat(killedThresh), file=sys.stdout) else: networkCell[iJob] = [] ############################################################################# # Construct network cell array. ############################################################################# # ---- Loop over ifos we are considering. for iIfo in range(0,len(detectors_considered)): if pass_init[iJob,iIfo]: networkCell[iJob] = [networkCell[iJob], detectors_considered[iIfo]]