Loading [MathJax]/extensions/TeX/AMSsymbols.js
LAL 7.7.0.1-3a66518
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
series.py
Go to the documentation of this file.
1# Copyright (C) 2008 Kipp Cannon
2# 2015 Leo Singer
3#
4# Adapted from original pylal.series module to return SWIG lal datatypes
5# instead of pylal datatypes.
6#
7# This program is free software; you can redistribute it and/or modify it
8# under the terms of the GNU General Public License as published by the
9# Free Software Foundation; either version 2 of the License, or (at your
10# option) any later version.
11#
12# This program is distributed in the hope that it will be useful, but
13# WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
15# Public License for more details.
16#
17# You should have received a copy of the GNU General Public License along
18# with this program; if not, write to the Free Software Foundation, Inc.,
19# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20#
21"""
22Code to assist in reading and writing LAL time- and frequency series data
23encoded in LIGO Light-Weight XML format. The format recognized by the code
24in this module is the same as generated by the array-related functions in
25LAL's XML I/O code. The format is also very similar to the format used by
26the DMT to store time- and frequency-series data in XML files,
27"""
28
29
30from igwn_ligolw import ligolw
31import lal
32import numpy as np
33
34
35Attributes = ligolw.sax.xmlreader.AttributesImpl
36
37
38#
39# =============================================================================
40#
41# XML I/O
42#
43# =============================================================================
44#
45
46
47def _build_series(series, dim_names, comment, delta_name, delta_unit, encoding="Text"):
48 elem = ligolw.LIGO_LW(Attributes({u"Name": str(series.__class__.__name__)}))
49 if comment is not None:
50 elem.appendChild(ligolw.Comment()).pcdata = comment
51 elem.appendChild(ligolw.Time.from_gps(series.epoch, u"epoch"))
52 elem.appendChild(ligolw.Param.from_pyvalue(u"f0", series.f0, unit=u"s^-1"))
53 delta = getattr(series, delta_name)
54 if np.iscomplexobj(series.data.data):
55 data = np.vstack((np.arange(len(series.data.data)) * delta, series.data.data.real, series.data.data.imag))
56 else:
57 data = np.vstack((np.arange(len(series.data.data)) * delta, series.data.data))
58 a = ligolw.Array.build(series.name, data, dim_names=dim_names, encoding=encoding)
59 a.Unit = str(series.sampleUnits)
60 dim0 = a.getElementsByTagName(ligolw.Dim.tagName)[0]
61 dim0.Unit = delta_unit
62 dim0.Start = series.f0
63 dim0.Scale = delta
64 elem.appendChild(a)
65 return elem
66
67
68def _parse_series(elem, creatorfunc, delta_target_unit_string):
69 t, = elem.getElementsByTagName(ligolw.Time.tagName)
70 a, = elem.getElementsByTagName(ligolw.Array.tagName)
71 dims = a.getElementsByTagName(ligolw.Dim.tagName)
72 f0 = ligolw.Param.get_param(elem, u"f0")
73
74 if t.Type != u"GPS":
75 raise ValueError("epoch Type must be GPS")
76 epoch = t.pcdata
77
78 # Target units: inverse seconds
79 inverse_seconds_unit = lal.Unit("s^-1")
80
81 delta_target_unit = lal.Unit(delta_target_unit_string)
82
83 # Parse units of f0 field
84 f0_unit = lal.Unit(str(f0.Unit))
85
86 # Parse units of deltaF field
87 delta_unit = lal.Unit(str(dims[0].Unit))
88
89 # Parse units of data
90 sample_unit = lal.Unit(str(a.Unit))
91
92 # Initialize data structure
93 series = creatorfunc(
94 str(a.Name),
95 epoch,
96 f0.pcdata * float(f0_unit / inverse_seconds_unit),
97 dims[0].Scale * float(delta_unit / delta_target_unit),
98 sample_unit,
99 len(a.array.T)
100 )
101
102 # Assign data
103 if np.iscomplexobj(series.data.data):
104 series.data.data = a.array[1] + 1j * a.array[2]
105 else:
106 series.data.data = a.array[1]
107
108 # Done!
109 return series
110
111
112def build_REAL4FrequencySeries(series, comment=None, encoding="Text"):
113 assert isinstance(series, lal.REAL4FrequencySeries)
114 return _build_series(series, (u"Frequency,Real", u"Frequency"), comment, 'deltaF', 's^-1', encoding=encoding)
115
116
118 return _parse_series(elem, lal.CreateREAL4FrequencySeries, "s^-1")
119
120
121def build_REAL8FrequencySeries(series, comment=None, encoding="Text"):
122 assert isinstance(series, lal.REAL8FrequencySeries)
123 return _build_series(series, (u"Frequency,Real", u"Frequency"), comment, 'deltaF', 's^-1', encoding=encoding)
124
125
127 return _parse_series(elem, lal.CreateREAL8FrequencySeries, "s^-1")
128
129
130def build_COMPLEX8FrequencySeries(series, comment=None, encoding="Text"):
131 assert isinstance(series, lal.COMPLEX8FrequencySeries)
132 return _build_series(series, (u"Frequency,Real,Imaginary", u"Frequency"), comment, 'deltaF', 's^-1', encoding=encoding)
133
134
136 return _parse_series(elem, lal.CreateCOMPLEX8FrequencySeries, "s^-1")
137
138
139def build_COMPLEX16FrequencySeries(series, comment=None, encoding="Text"):
140 assert isinstance(series, lal.COMPLEX16FrequencySeries)
141 return _build_series(series, (u"Frequency,Real,Imaginary", u"Frequency"), comment, 'deltaF', 's^-1', encoding=encoding)
142
143
145 return _parse_series(elem, lal.CreateCOMPLEX16FrequencySeries, "s^-1")
146
147
148def build_REAL4TimeSeries(series, comment=None, encoding="Text"):
149 assert isinstance(series, lal.REAL4TimeSeries)
150 return _build_series(series, (u"Time,Real", u"Time"), comment, 'deltaT', 's', encoding=encoding)
151
152
154 return _parse_series(elem, lal.CreateREAL4TimeSeries, "s")
155
156
157def build_REAL8TimeSeries(series, comment=None, encoding="Text"):
158 assert isinstance(series, lal.REAL8TimeSeries)
159 return _build_series(series, (u"Time,Real", u"Time"), comment, 'deltaT', 's', encoding=encoding)
160
161
163 return _parse_series(elem, lal.CreateREAL8TimeSeries, "s")
164
165
166def build_COMPLEX8TimeSeries(series, comment=None, encoding="Text"):
167 assert isinstance(series, lal.COMPLEX8TimeSeries)
168 return _build_series(series, (u"Time,Real,Imaginary", u"Time"), comment, 'deltaT', 's', encoding=encoding)
169
170
172 return _parse_series(elem, lal.CreateCOMPLEX8TimeSeries, "s")
173
174
175def build_COMPLEX16TimeSeries(series, comment=None, encoding="Text"):
176 assert isinstance(series, lal.COMPLEX16TimeSeries)
177 return _build_series(series, (u"Time,Real,Imaginary", u"Time"), comment, 'deltaT', 's', encoding=encoding)
178
179
181 return _parse_series(elem, lal.CreateCOMPLEX16TimeSeries, "s")
182
183
184#
185# =============================================================================
186#
187# XML PSD I/O
188#
189# =============================================================================
190#
191
192
193def make_psd_xmldoc(psddict, xmldoc = None, root_name = u"psd", encoding="Text"):
194 """
195 Construct an XML document tree representation of a dictionary of
196 frequency series objects containing PSDs. See also read_psd_xmldoc()
197 for a function to parse the resulting XML documents.
198
199 If xmldoc is None (the default), then a new XML document is created and
200 the PSD dictionary added to it inside a LIGO_LW element. If xmldoc is
201 not None then the PSD dictionary is appended to the children of that
202 element inside a new LIGO_LW element. In both cases, the LIGO_LW
203 element's Name attribute is set to root_name. This will be looked for
204 by read_psd_xmldoc() when parsing the PSD document.
205 """
206 if xmldoc is None:
207 xmldoc = ligolw.Document()
208 lw = xmldoc.appendChild(ligolw.LIGO_LW(Attributes({u"Name": root_name})))
209 for instrument, psd in psddict.items():
210 fs = lw.appendChild(build_REAL8FrequencySeries(psd, encoding=encoding))
211 if instrument is not None:
212 fs.appendChild(ligolw.Param.from_pyvalue(u"instrument", instrument))
213 return xmldoc
214
215
216def read_psd_xmldoc(xmldoc, root_name = u"psd"):
217 """
218 Parse a dictionary of PSD frequency series objects from an XML
219 document. See also make_psd_xmldoc() for the construction of XML
220 documents from a dictionary of PSDs. Interprets an empty frequency
221 series for an instrument as None.
222
223 The XML document tree is searched for a LIGO_LW element whose Name
224 attribute is root_name (default is "psd"). If root_name is None all
225 REAL8Frequency series objects below xmldoc are included in the return
226 value.
227 """
228 if root_name is not None:
229 xmldoc, = (elem for elem in xmldoc.getElementsByTagName(ligolw.LIGO_LW.tagName) if elem.hasAttribute(u"Name") and elem.Name == root_name)
230 result = dict((ligolw.Param.get_param(elem, u"instrument").value, parse_REAL8FrequencySeries(elem)) for elem in xmldoc.getElementsByTagName(ligolw.LIGO_LW.tagName) if elem.hasAttribute(u"Name") and elem.Name == u"REAL8FrequencySeries")
231 # interpret empty frequency series as None
232 for instrument in result:
233 if len(result[instrument].data.data) == 0:
234 result[instrument] = None
235 return result
236
237
238class PSDContentHandler(ligolw.LIGOLWContentHandler):
239 """A content handler suitable for reading PSD documents. Use like this:
240
241 >>> from igwn_ligolw.utils import load_filename
242 >>> xmldoc = load_filename('psd.xml', contenthandler=PSDContentHandler)
243 >>> psds = read_psd_xmldoc(xmldoc)
244 """
def build_REAL4FrequencySeries(series, comment=None, encoding="Text")
Definition: series.py:112
def read_psd_xmldoc(xmldoc, root_name=u"psd")
Parse a dictionary of PSD frequency series objects from an XML document.
Definition: series.py:227
def parse_REAL4TimeSeries(elem)
Definition: series.py:153
def parse_COMPLEX16FrequencySeries(elem)
Definition: series.py:144
def build_COMPLEX16FrequencySeries(series, comment=None, encoding="Text")
Definition: series.py:139
Attributes
Definition: series.py:35
def build_REAL8FrequencySeries(series, comment=None, encoding="Text")
Definition: series.py:121
def parse_COMPLEX16TimeSeries(elem)
Definition: series.py:180
def make_psd_xmldoc(psddict, xmldoc=None, root_name=u"psd", encoding="Text")
Construct an XML document tree representation of a dictionary of frequency series objects containing ...
Definition: series.py:205
def build_COMPLEX8TimeSeries(series, comment=None, encoding="Text")
Definition: series.py:166
def parse_REAL8FrequencySeries(elem)
Definition: series.py:126
def parse_COMPLEX8TimeSeries(elem)
Definition: series.py:171
def build_REAL4TimeSeries(series, comment=None, encoding="Text")
Definition: series.py:148
def parse_REAL4FrequencySeries(elem)
Definition: series.py:117
def build_COMPLEX16TimeSeries(series, comment=None, encoding="Text")
Definition: series.py:175
def build_COMPLEX8FrequencySeries(series, comment=None, encoding="Text")
Definition: series.py:130
def parse_COMPLEX8FrequencySeries(elem)
Definition: series.py:135
def parse_REAL8TimeSeries(elem)
Definition: series.py:162
def build_REAL8TimeSeries(series, comment=None, encoding="Text")
Definition: series.py:157