Loading [MathJax]/extensions/TeX/AMSsymbols.js
LALBurst 2.0.7.1-b246709
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Macros Modules Pages
snglcluster.py
Go to the documentation of this file.
1# Copyright (C) 2009,2010,2016-2021 Kipp Cannon
2#
3# This program is free software; you can redistribute it and/or modify it
4# under the terms of the GNU General Public License as published by the
5# Free Software Foundation; either version 2 of the License, or (at your
6# option) any later version.
7#
8# This program is distributed in the hope that it will be useful, but
9# WITHOUT ANY WARRANTY; without even the implied warranty of
10# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
11# Public License for more details.
12#
13# You should have received a copy of the GNU General Public License along
14# with this program; if not, write to the Free Software Foundation, Inc.,
15# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16
17
18#
19# =============================================================================
20#
21# Preamble
22#
23# =============================================================================
24#
25
26
27from tqdm import tqdm
28
29
30from lal import iterutils
31import igwn_segments as segments
32
33
34__author__ = "Kipp Cannon <kipp.cannon@ligo.org>"
35from .git_version import date as __date__
36from .git_version import version as __version__
37
38
39#
40# =============================================================================
41#
42# Clustering Tools
43#
44# =============================================================================
45#
46
47
49 """
50 Return the smallest segment that contains both a and b.
51 """
52 return segments.segment(min(a[0], b[0]), max(a[1], b[1]))
53
54
55def weighted_average_seg(seg1, weight1, seg2, weight2):
56 """
57 Return the segment whose start and ends are the weighted arithmetic
58 means of the start and ends of the two input segments, using the
59 two weights given.
60
61 The arithmetic means are computed in a way that is safe for
62 LIGOTimeGPS objects.
63 """
64 return segments.segment(seg1[0] + weight2 * float(seg2[0] - seg1[0]) / (weight1 + weight2), seg1[1] + weight2 * float(seg2[1] - seg1[1]) / (weight1 + weight2))
65
66
67#
68# =============================================================================
69#
70# Clustering Loop
71#
72# =============================================================================
73#
74
75
76def cluster_events(events, testfunc, clusterfunc, sortkeyfunc = None, bailoutfunc = None, verbose = False):
77 """
78 Cluster the events in an event list. testfunc will be passed a
79 pair of events in random order, and must return 0 (or False) if
80 they should be clustered. clusterfunc will be passed a pair of
81 events in random order, and must return an event that is the
82 "cluster" of the two. clusterfunc is free to return a new events,
83 or modify one or the other of its parameters in place and return
84 it.
85
86 If sortkeyfunc and bailoutfunc are both not None (if one is
87 provided the other must be as well), the events will be sorted into
88 "increasing" order using sortkeyfunc as a sort key operator, and
89 then only pairs of events for which bailoutfunc returns 0 (or
90 False) will be considered for clustering.
91
92 The return value is True if the events in the event list were
93 modified, and False if they were not (although their order might
94 have changed).
95 """
96 # changed indicates if the event list has changed
97 changed = False
98 while 1:
99 with tqdm(desc = "clustering %d events" % len(events), total = len(events), disable = not verbose) as progress:
100 if sortkeyfunc is not None:
101 events.sort(key = sortkeyfunc)
102
103 # outer_did_cluster indicates if the event list changes on
104 # this pass
105 outer_did_cluster = False
106 i = 0
107 while i < len(events):
108 if events[i] is None:
109 # this event has been clustered away
110 i += 1
111 progress.update()
112 continue
113 # inner_did_cluster indicates if events[i] has
114 # changed
115 inner_did_cluster = False
116 for j, event_j in enumerate(events[i + 1:], i + 1):
117 if event_j is not None:
118 if not testfunc(events[i], event_j):
119 events[i] = clusterfunc(events[i], event_j)
120 events[j] = None
121 inner_did_cluster = True
122 elif (sortkeyfunc is not None) and bailoutfunc(events[i], event_j):
123 break
124 if inner_did_cluster:
125 outer_did_cluster = True
126 # don't advance until events[i] stops
127 # changing
128 else:
129 i += 1
130 progress.update()
131 # repeat until we do a pass without the listing changing
132 if not outer_did_cluster:
133 break
134 iterutils.inplace_filter(lambda event: event is not None, events)
135 changed = True
136 return changed
static double max(double a, double b)
Definition: EPFilters.c:43
static double min(double a, double b)
Definition: EPFilters.c:42
def cluster_events(events, testfunc, clusterfunc, sortkeyfunc=None, bailoutfunc=None, verbose=False)
Cluster the events in an event list.
Definition: snglcluster.py:95
def weighted_average_seg(seg1, weight1, seg2, weight2)
Return the segment whose start and ends are the weighted arithmetic means of the start and ends of th...
Definition: snglcluster.py:63
def smallest_enclosing_seg(a, b)
Return the smallest segment that contains both a and b.
Definition: snglcluster.py:51
dictionary bailoutfunc
dictionary clusterfunc