28LIGO Light-Weight XML coincidence analysis front end.
36from lal
import LIGOTimeGPS
38import igwn_segments
as segments
41from .
import offsetvector
45__author__ =
"Kipp Cannon <kipp.cannon@ligo.org>"
46from .git_version
import date
as __date__
47from .git_version
import version
as __version__
61 Parse a LAL cache file named filename into a list of
62 lal.utils.CacheEntry objects. If filename is None then input
is
66 print("reading %s ..." % (filename
or "stdin"), file=sys.stderr)
67 if filename
is not None:
71 return [CacheEntry(line)
for line
in f]
76 Construct a coalesced segmentlistdict object from a list of
77 lal.utils.CacheEntry objects.
79 s = segments.segmentlistdict()
81 s |= c.segmentlistdict
96 Convert the times in a segmentlist dictionary to floats relative to
97 origin. The purpose is to allow segment lists stored
as
98 LIGOTimeGPS times to be manipulated more quickly without loss of
99 precision. The modification
is done
in place.
101 for seglist in seglistdict.itervalues():
102 seglist[:] = (segments.segment(float(seg[0] - origin), float(seg[1] - origin)) for seg
in seglist)
107 Compute the segments for which data is required in order to perform
108 a complete coincidence analysis given the segments for which data
109 is available and the list of offset vectors to be applied to the
110 data during the coincidence analysis.
112 seglistdict is a segmentlistdict object defining the instruments
113 and times for which data is available. offset_vectors is a list of
114 offset vectors to be applied to the data --- dictionaries of
115 instrument/offset pairs.
117 The offset vectors
in offset_vectors are applied to the input
118 segments one by one
and the interesection of the shifted segments
119 is computed. The segments surviving the intersection are unshifted
120 to their original positions
and stored. The
return value
is the
121 union of the results of this operation.
123 In all cases all pair-wise intersections are computed, that
is if
124 an offset vector lists three instruments then this function returns
125 the times when any two of those isntruments are on, including times
126 when all three are on.
128 For example, let us say that
"input" is a segmentlistdict object
129 containing segment lists
for three instruments,
"H1",
"H2" and
130 "L1". And let us say that
"slides" is a list of dictionaries,
and
131 is equal to [{
"H1":0,
"H2":0,
"L1":0}, {
"H1":0,
"H2":10}]. Then
if
135 output will contain,
for each of the three instruments, the
136 segments (
or parts thereof)
from the original lists that are
137 required
in order to perform a triple-
and double-coincident
138 analyses at zero lag
with the three instruments, *
and* a
139 double-coincident analysis between H1
and H2
with H2 offset by 10
142 The segmentlistdict object returned by this function has its
143 offsets set to those of the input segmentlistdict.
145 # don't modify original
146 seglistdict = seglistdict.copy()
147 all_instruments = set(seglistdict)
149 # save original offsets
150 origoffsets = dict(seglistdict.offsets)
153 coincseglists = segments.segmentlistdict()
154 for offset_vector in offsetvector.component_offsetvectors(offset_vectors, 2):
155 if set(offset_vector).issubset(all_instruments):
156 seglistdict.offsets.update(offset_vector)
157 intersection = seglistdict.extract_common(offset_vector.keys())
158 intersection.offsets.clear()
159 coincseglists |= intersection
162 coincseglists.offsets.update(origoffsets)
170 The opposite of segmentlistdict_normalize(), restores the times in
171 a segmentlist dictionary to absolute times. The modification is
174 for seglist in seglistdict.itervalues():
175 seglist[:] = (segments.segment(origin + seg[0], origin + seg[1]) for seg
in seglist)
189 Subclass of the packing.Bin class representing a LAL file cache.
190 The files contained in the bin are available in the .objects
191 attribute, which is a list of lal.utils.CacheEntry objects. The
192 .size attribute holds a igwn_segments.segmentlistdict object giving
193 the times spanned by the files in the bin. The .extent attribute
194 holds the result of running .extent_all() on the .size attribute.
197 packing.Bin.__init__(self)
201 def add(self, cache_entry):
202 packing.Bin.add(self, cache_entry, cache_entry.segmentlistdict)
207 packing.Bin.__iadd__(self, *args)
212 return self.
extent < other.extent
215 return self.
extent <= other.extent
218 return self.
extent == other.extent
221 return self.
extent != other.extent
224 return self.
extent >= other.extent
227 return self.
extent > other.extent
230 return "\n".join(map(str, self.
objects))
235 Packing algorithm implementing the ligolw_cafe file list packing
240 Set the list of offset vectors to be considered when
241 deciding the bins in which each file belongs. Must be
242 called before packing any files. The input
is a list of
243 dictionaries, each mapping instruments to offsets.
251 self.
offset_vectors.sort(key =
lambda offset_vector: sorted(offset_vector.items()))
258 min_offset =
min(
min(offset_vector.values())
for offset_vector
in offset_vectors)
259 max_offset =
max(
max(offset_vector.values())
for offset_vector
in offset_vectors)
263 def pack(self, cache_entry):
265 Find all bins in which this lal.utils.CacheEntry instance
266 belongs, merge them,
and add this cache entry to the
267 result. Create a new bin
for this cache entry
if it does
268 not belong
in any of the existing bins.
270 The cache entry
"belongs" in a bin
if after each of the
272 method)
is applied to both the contents of a bin
and the
273 cache entry, any of the segment lists of the bin
and cache
274 entry are found to intersect. When checking
for
275 intersection, only the segment lists whose instrument names
276 are listed
in the offset vector are compared.
293 for n
in range(len(self.
bins) - 1, -1, -1):
295 if bin.extent[1] < new.extent[0] - self.
max_gap:
298 new.size.offsets.update(offset_vector)
299 bin.size.offsets.update(offset_vector)
300 if bin.size.is_coincident(new.size, keys = offset_vector.keys()):
301 matching_bins.append(n)
303 bin.size.offsets.clear()
304 new.size.offsets.clear()
310 if not matching_bins:
327 dest = self.
bins[matching_bins.pop(-1)]
329 for n
in matching_bins:
330 dest += self.
bins.pop(n)
340def split_bins(cafepacker, extentlimit, verbose = False):
342 Split bins in CafePacker so that each bin has an extent no longer
351 for idx
in range(len(cafepacker.bins) - 1, -1, -1):
356 origbin = cafepacker.bins[idx]
363 n = int(math.ceil(float(abs(origbin.extent)) / extentlimit))
372 extents = [origbin.extent[0]] + [LIGOTimeGPS(origbin.extent[0] + i * float(abs(origbin.extent)) / n)
for i
in range(1, n)] + [origbin.extent[1]]
374 print(
"\tsplitting cache spanning %s at %s" % (str(origbin.extent),
", ".join(str(extent)
for extent
in extents[1:-1])), file=sys.stderr)
375 extents = [segments.segment(*bounds)
for bounds
in zip(extents[:-1], extents[1:])]
382 for extent
in extents:
393 extent_plus_max_gap = extent.protract(cafepacker.max_gap)
394 for cache_entry
in origbin.objects:
399 if cache_entry.segment.disjoint(extent_plus_max_gap):
406 cache_entry_segs = cache_entry.segmentlistdict
407 for offset_vector
in cafepacker.offset_vectors:
408 cache_entry_segs.offsets.update(offset_vector)
414 if cache_entry_segs.intersects_segment(extent):
420 newbins[-1].add(cache_entry)
427 newbins[-1].extent = extent
433 cafepacker.bins[idx:idx+1] = newbins
452 pattern =
"%%s%%0%dd.cache" % int(math.log10(len(bins)) + 1)
453 for n, bin
in enumerate(bins):
454 filename = pattern % (base, n)
455 filenames.append(filename)
457 print(
"writing %s ..." % filename, file=sys.stderr)
458 f = open(filename,
"w")
459 for cacheentry
in bin.objects:
460 if instruments
is None or (instruments & set(cacheentry.segmentlistdict)):
461 print(str(cacheentry), file=f)
466 for instrument
in instruments:
467 write_caches(
"%s%s_" % (base, instrument), bins, set([instrument]), verbose)
479def ligolw_cafe(cache, offset_vectors, verbose = False, extentlimit = None):
481 Transform a LAL cache into a list of caches each of whose contents
482 can be subjected to a coincidence analysis independently of the
483 contents of the other caches, assuming the coincidence analyses
484 will involve the application of the given offset vectors.
486 cache is a sequence (e.g., list, tuple, etc.) of
487 lal.utils.CacheEntry objects. offset_vectors is a sequence of
488 instrument/offset dictionaries describing the offset vectors to
489 consider. Set verbose to
True for verbosity.
491 The output
is a two-element tuple. The first element
is a
492 igwn_segments.segmentlistdict object describing the times
for which
493 coincident data
is available (derived
from the segment metadata of
494 the input cache). The second element
is a list of LALCacheBin
495 objects, providing the file groups.
498 # Construct a segment list dictionary from the cache
502 print("computing segment list ...", file=sys.stderr)
510 epoch =
min([
min(seg[0]
for seg
in seglist)
for seglist
in seglists.values()
if seglist]
or [
None])
525 print(
"filtering input cache ...", file=sys.stderr)
526 cache = [c
for c
in cache
if seglists.intersects_all(c.segmentlistdict)]
534 print(
"sorting input cache ...", file=sys.stderr)
535 cache.sort(key =
lambda x: x.segment)
545 packer.set_offset_vectors(offset_vectors)
547 print(
"packing files (considering %s offset vectors) ..." % len(offset_vectors), file=sys.stderr)
548 for n, cacheentry
in enumerate(cache):
549 if verbose
and not n % 13:
550 print(
"\t%.1f%%\t(%d files, %d caches)\r" % (100.0 * n / len(cache), n + 1, len(outputcaches)), end=
' ', file=sys.stderr)
551 packer.pack(cacheentry)
553 print(
"\t100.0%%\t(%d files, %d caches)" % (len(cache), len(outputcaches)), file=sys.stderr)
559 if extentlimit
is not None:
561 print(
"splitting caches with extent greater than %g s ..." % extentlimit, file=sys.stderr)
562 split_bins(packer, extentlimit, verbose = verbose)
564 print(
"\t\t(%d files, %d caches)" % (len(cache), len(outputcaches)), file=sys.stderr)
571 print(
"sorting output caches ...", file=sys.stderr)
572 for cache
in outputcaches:
579 return seglists, outputcaches
static double max(double a, double b)
static double min(double a, double b)
Packing algorithm implementing the ligolw_cafe file list packing algorithm.
def pack(self, cache_entry)
Find all bins in which this lal.utils.CacheEntry instance belongs, merge them, and add this cache ent...
def set_offset_vectors(self, offset_vectors)
Set the list of offset vectors to be considered when deciding the bins in which each file belongs.
Subclass of the packing.Bin class representing a LAL file cache.
def add(self, cache_entry)
Add the object, whose size is as given, to the bin.
def __iadd__(self, *args)
Add the contents of another Bin object to this one.
Bin object for use in packing algorithm implementations.
Parent class for packing algorithms.
def split_bins(cafepacker, extentlimit, verbose=False)
Split bins in CafePacker so that each bin has an extent no longer than extentlimit.
def segmentlistdict_normalize(seglistdict, origin)
Convert the times in a segmentlist dictionary to floats relative to origin.
def load_cache(filename, verbose=False)
Parse a LAL cache file named filename into a list of lal.utils.CacheEntry objects.
def write_caches(base, bins, instruments=None, verbose=False)
def get_coincident_segmentlistdict(seglistdict, offset_vectors)
Compute the segments for which data is required in order to perform a complete coincidence analysis g...
def segmentlistdict_unnormalize(seglistdict, origin)
The opposite of segmentlistdict_normalize(), restores the times in a segmentlist dictionary to absolu...
def cache_to_seglistdict(cache)
Construct a coalesced segmentlistdict object from a list of lal.utils.CacheEntry objects.
def write_single_instrument_caches(base, bins, instruments, verbose=False)
def ligolw_cafe(cache, offset_vectors, verbose=False, extentlimit=None)
Transform a LAL cache into a list of caches each of whose contents can be subjected to a coincidence ...