tdanalysis 1.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- tdanalysis/__init__.py +0 -0
- tdanalysis/_compat.py +173 -0
- tdanalysis/covariance/covariance_calc.py +811 -0
- tdanalysis/covariance/psd.py +987 -0
- tdanalysis/data/acorrs/A1_aplus_acorr_4s_4096.npy +0 -0
- tdanalysis/data/acorrs/A1_aplus_acorr_8s_4096.npy +0 -0
- tdanalysis/data/acorrs/CE20_1p0MW_Aplus_acorr_4s_4096.npy +0 -0
- tdanalysis/data/acorrs/CE20_1p0MW_Aplus_acorr_8s_4096.npy +0 -0
- tdanalysis/data/acorrs/CE20_1p0MW_aLIGO_acorr_4s_4096.npy +0 -0
- tdanalysis/data/acorrs/CE20_1p0MW_aLIGO_acorr_8s_4096.npy +0 -0
- tdanalysis/data/acorrs/CE20_1p5MW_Aplus_acorr_4s_4096.npy +0 -0
- tdanalysis/data/acorrs/CE20_1p5MW_Aplus_acorr_8s_4096.npy +0 -0
- tdanalysis/data/acorrs/CE20_1p5MW_aLIGO_acorr_4s_4096.npy +0 -0
- tdanalysis/data/acorrs/CE20_1p5MW_aLIGO_acorr_8s_4096.npy +0 -0
- tdanalysis/data/acorrs/CE20_gwforge_default_acorr_4s_4096.npy +0 -0
- tdanalysis/data/acorrs/CE20_gwforge_default_acorr_8s_4096.npy +0 -0
- tdanalysis/data/acorrs/CE40_1p0MW_Aplus_acorr_4s_4096.npy +0 -0
- tdanalysis/data/acorrs/CE40_1p0MW_Aplus_acorr_8s_4096.npy +0 -0
- tdanalysis/data/acorrs/CE40_1p0MW_aLIGO_acorr_4s_4096.npy +0 -0
- tdanalysis/data/acorrs/CE40_1p0MW_aLIGO_acorr_8s_4096.npy +0 -0
- tdanalysis/data/acorrs/CE40_1p5MW_Aplus_acorr_4s_4096.npy +0 -0
- tdanalysis/data/acorrs/CE40_1p5MW_Aplus_acorr_8s_4096.npy +0 -0
- tdanalysis/data/acorrs/CE40_1p5MW_aLIGO_acorr_4s_4096.npy +0 -0
- tdanalysis/data/acorrs/CE40_1p5MW_aLIGO_acorr_8s_4096.npy +0 -0
- tdanalysis/data/acorrs/CE40_gwforge_default_acorr_4s_4096.npy +0 -0
- tdanalysis/data/acorrs/CE40_gwforge_default_acorr_8s_4096.npy +0 -0
- tdanalysis/data/acorrs/ET1ET2ET3_ET_D_acorr_4s_4096.npy +0 -0
- tdanalysis/data/acorrs/ET1ET2ET3_ET_D_acorr_8s_4096.npy +0 -0
- tdanalysis/data/acorrs/ET1ET2ET3_cryo_10km_acorr_4s_4096.npy +0 -0
- tdanalysis/data/acorrs/ET1ET2ET3_cryo_10km_acorr_8s_4096.npy +0 -0
- tdanalysis/data/acorrs/ET1ET2ET3_cryo_15km_acorr_4s_4096.npy +0 -0
- tdanalysis/data/acorrs/ET1ET2ET3_cryo_15km_acorr_8s_4096.npy +0 -0
- tdanalysis/data/acorrs/PROVENANCE.md +1143 -0
- tdanalysis/data/acorrs/half_A1_aplus_acorr_4s_4096.npy +0 -0
- tdanalysis/data/acorrs/half_A1_aplus_acorr_8s_4096.npy +0 -0
- tdanalysis/data/acorrs/half_CE20_1p0MW_Aplus_acorr_4s_4096.npy +0 -0
- tdanalysis/data/acorrs/half_CE20_1p0MW_Aplus_acorr_8s_4096.npy +0 -0
- tdanalysis/data/acorrs/half_CE20_1p0MW_aLIGO_acorr_4s_4096.npy +0 -0
- tdanalysis/data/acorrs/half_CE20_1p0MW_aLIGO_acorr_8s_4096.npy +0 -0
- tdanalysis/data/acorrs/half_CE20_1p5MW_Aplus_acorr_4s_4096.npy +0 -0
- tdanalysis/data/acorrs/half_CE20_1p5MW_Aplus_acorr_8s_4096.npy +0 -0
- tdanalysis/data/acorrs/half_CE20_1p5MW_aLIGO_acorr_4s_4096.npy +0 -0
- tdanalysis/data/acorrs/half_CE20_1p5MW_aLIGO_acorr_8s_4096.npy +0 -0
- tdanalysis/data/acorrs/half_CE20_gwforge_default_acorr_4s_4096.npy +0 -0
- tdanalysis/data/acorrs/half_CE20_gwforge_default_acorr_8s_4096.npy +0 -0
- tdanalysis/data/acorrs/half_CE40_1p0MW_Aplus_acorr_4s_4096.npy +0 -0
- tdanalysis/data/acorrs/half_CE40_1p0MW_Aplus_acorr_8s_4096.npy +0 -0
- tdanalysis/data/acorrs/half_CE40_1p0MW_aLIGO_acorr_4s_4096.npy +0 -0
- tdanalysis/data/acorrs/half_CE40_1p0MW_aLIGO_acorr_8s_4096.npy +0 -0
- tdanalysis/data/acorrs/half_CE40_1p5MW_Aplus_acorr_4s_4096.npy +0 -0
- tdanalysis/data/acorrs/half_CE40_1p5MW_Aplus_acorr_8s_4096.npy +0 -0
- tdanalysis/data/acorrs/half_CE40_1p5MW_aLIGO_acorr_4s_4096.npy +0 -0
- tdanalysis/data/acorrs/half_CE40_1p5MW_aLIGO_acorr_8s_4096.npy +0 -0
- tdanalysis/data/acorrs/half_CE40_gwforge_default_acorr_4s_4096.npy +0 -0
- tdanalysis/data/acorrs/half_CE40_gwforge_default_acorr_8s_4096.npy +0 -0
- tdanalysis/data/acorrs/half_ET1ET2ET3_ET_D_acorr_4s_4096.npy +0 -0
- tdanalysis/data/acorrs/half_ET1ET2ET3_ET_D_acorr_8s_4096.npy +0 -0
- tdanalysis/data/acorrs/half_ET1ET2ET3_cryo_10km_acorr_4s_4096.npy +0 -0
- tdanalysis/data/acorrs/half_ET1ET2ET3_cryo_10km_acorr_8s_4096.npy +0 -0
- tdanalysis/data/acorrs/half_ET1ET2ET3_cryo_15km_acorr_4s_4096.npy +0 -0
- tdanalysis/data/acorrs/half_ET1ET2ET3_cryo_15km_acorr_8s_4096.npy +0 -0
- tdanalysis/data/detectors/A1.interferometer +13 -0
- tdanalysis/data/detectors/CE20.ifo +11 -0
- tdanalysis/data/detectors/CE40.ifo +11 -0
- tdanalysis/data/detectors/ET.ifo +12 -0
- tdanalysis/data/detectors/PROVENANCE.md +230 -0
- tdanalysis/data/noise_curves/CE20-asd.txt +1000 -0
- tdanalysis/data/noise_curves/CE20km_1p0MW_Aplus_coat_strain.txt +1000 -0
- tdanalysis/data/noise_curves/CE20km_1p0MW_aLIGO_coat_strain.txt +1000 -0
- tdanalysis/data/noise_curves/CE20km_1p5MW_Aplus_coat_strain.txt +1000 -0
- tdanalysis/data/noise_curves/CE20km_1p5MW_aLIGO_coat_strain.txt +1000 -0
- tdanalysis/data/noise_curves/CE40-asd.txt +1000 -0
- tdanalysis/data/noise_curves/CE40km_1p0MW_Aplus_coat_strain.txt +1000 -0
- tdanalysis/data/noise_curves/CE40km_1p0MW_aLIGO_coat_strain.txt +1000 -0
- tdanalysis/data/noise_curves/CE40km_1p5MW_Aplus_coat_strain.txt +1000 -0
- tdanalysis/data/noise_curves/CE40km_1p5MW_aLIGO_coat_strain.txt +1000 -0
- tdanalysis/data/noise_curves/ET-psd.txt +3000 -0
- tdanalysis/data/noise_curves/ET_cryo_10km_psd.txt +3000 -0
- tdanalysis/data/noise_curves/ET_cryo_15km_psd.txt +3000 -0
- tdanalysis/data/noise_curves/PROVENANCE.md +130 -0
- tdanalysis/data/noise_curves/aplus.txt +3000 -0
- tdanalysis/detectors/__init__.py +89 -0
- tdanalysis/detectors/xg.py +1040 -0
- tdanalysis/dtypes.py +75 -0
- tdanalysis/exe/config.py +129 -0
- tdanalysis/exe/runner.py +755 -0
- tdanalysis/exe/tdpipe.py +72 -0
- tdanalysis/fitting_factor.py +908 -0
- tdanalysis/forms/cd.py +81 -0
- tdanalysis/forms/gs.py +200 -0
- tdanalysis/forms/gs_batched.py +66 -0
- tdanalysis/forms/invld.py +105 -0
- tdanalysis/forms/llt.py +122 -0
- tdanalysis/forms/pcg.py +362 -0
- tdanalysis/gpu/gpu_matrix_multiplier.py +215 -0
- tdanalysis/gpu/kernels.py +14 -0
- tdanalysis/inference/nr_injection.py +178 -0
- tdanalysis/likelihoods/comparison/discriminators.py +218 -0
- tdanalysis/likelihoods/multi/consistency_test.py +232 -0
- tdanalysis/likelihoods/multi/pe.py +442 -0
- tdanalysis/likelihoods/reduced_batch.py +203 -0
- tdanalysis/likelihoods/single/consistency_test.py +443 -0
- tdanalysis/likelihoods/single/pe.py +2424 -0
- tdanalysis/priors/bbh.py +215 -0
- tdanalysis/priors/bilby.py +67 -0
- tdanalysis/utils/bilby.py +480 -0
- tdanalysis/utils/conditioning.py +128 -0
- tdanalysis/utils/io.py +117 -0
- tdanalysis/utils/plotting.py +434 -0
- tdanalysis/utils/serialize.py +62 -0
- tdanalysis/waveforms/__init__.py +9 -0
- tdanalysis/waveforms/nraasur.py +575 -0
- tdanalysis-1.0.0.dist-info/METADATA +174 -0
- tdanalysis-1.0.0.dist-info/RECORD +118 -0
- tdanalysis-1.0.0.dist-info/WHEEL +4 -0
- tdanalysis-1.0.0.dist-info/entry_points.txt +2 -0
- tdanalysis-1.0.0.dist-info/licenses/LICENSE +203 -0
- tdanalysis-1.0.0.dist-info/licenses/NOTICE.md +133 -0
|
@@ -0,0 +1,811 @@
|
|
|
1
|
+
from os import listdir
|
|
2
|
+
from sys import prefix
|
|
3
|
+
import numpy as np
|
|
4
|
+
from gwpy.timeseries import TimeSeries
|
|
5
|
+
from waveformtools.waveformtools import message, progressbar, roll
|
|
6
|
+
import os
|
|
7
|
+
from os.path import isfile
|
|
8
|
+
import pickle
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
import dask
|
|
11
|
+
import h5py
|
|
12
|
+
import scipy
|
|
13
|
+
from tqdm import tqdm
|
|
14
|
+
|
|
15
|
+
class CovarianceCalculator:
|
|
16
|
+
"""Carry out time-domain analysis of data.
|
|
17
|
+
|
|
18
|
+
Given a gps reference time, this allows
|
|
19
|
+
|
|
20
|
+
1. Computation of the autocorrelation function of specified length.
|
|
21
|
+
This will be computed as either the median or mean over `n_cov`
|
|
22
|
+
auto-correlation frames.
|
|
23
|
+
2. Construction of the covariance matrix from the autocorrelation function
|
|
24
|
+
assuming a symmetric toeplitz form.
|
|
25
|
+
3. Inference over the given priors `priors` and `n_live` number of live
|
|
26
|
+
points with a specified model.
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
def __init__(
|
|
32
|
+
self,
|
|
33
|
+
ref_gps_time,
|
|
34
|
+
sampling_frequency=4096,
|
|
35
|
+
correlation_duration=4,
|
|
36
|
+
n_cov=10,
|
|
37
|
+
noise_sampling_range=100,
|
|
38
|
+
gps_time_exclusion_duration=8,
|
|
39
|
+
auto_corr_method="mean",
|
|
40
|
+
detector="L1",
|
|
41
|
+
channel="GDS-CALIB_STRAIN_CLEAN",
|
|
42
|
+
analysis_duration=1,
|
|
43
|
+
data_type="open",
|
|
44
|
+
backend="dask",
|
|
45
|
+
chunks=10000,
|
|
46
|
+
window=None,
|
|
47
|
+
segment_choice="disjoint",
|
|
48
|
+
resample_method='gwpy',
|
|
49
|
+
direct_data_path=None,
|
|
50
|
+
):
|
|
51
|
+
self._sampling_frequency = sampling_frequency
|
|
52
|
+
self._correlation_duration = correlation_duration
|
|
53
|
+
self._n_cov = n_cov
|
|
54
|
+
self._noise_sampling_range = noise_sampling_range
|
|
55
|
+
self._ref_gps_time = ref_gps_time
|
|
56
|
+
self._gps_time_exclusion_duration = gps_time_exclusion_duration
|
|
57
|
+
self._auto_corr_method = auto_corr_method
|
|
58
|
+
self._detector = detector
|
|
59
|
+
self.channel = channel
|
|
60
|
+
self.data_type = data_type
|
|
61
|
+
self.backend = backend
|
|
62
|
+
self.chunks = chunks
|
|
63
|
+
self.window = window
|
|
64
|
+
self.resample_method = resample_method
|
|
65
|
+
|
|
66
|
+
if resample_method=='gwpy':
|
|
67
|
+
self.resample_data = self.resample_data_gwpy
|
|
68
|
+
elif resample_method=='scipy':
|
|
69
|
+
self.resample_data = self.resample_data_scipy
|
|
70
|
+
else:
|
|
71
|
+
raise ValueError(f"Unknown resampling method {self.resample_method}")
|
|
72
|
+
|
|
73
|
+
self.direct_data_path = direct_data_path
|
|
74
|
+
|
|
75
|
+
if self.data_type == "open":
|
|
76
|
+
self.load_channel = self.detector
|
|
77
|
+
self.get_data = TimeSeries.fetch_open_data
|
|
78
|
+
|
|
79
|
+
elif self.data_type == "server":
|
|
80
|
+
self.load_channel = f"{self.detector}:{self.channel}"
|
|
81
|
+
self.get_data = TimeSeries.get
|
|
82
|
+
|
|
83
|
+
elif self.data_type == "file":
|
|
84
|
+
self.load_channel = f"{self.detector}:{self.channel}"
|
|
85
|
+
self.get_data = self.get_data_from_file
|
|
86
|
+
|
|
87
|
+
else:
|
|
88
|
+
self.load_channel = None
|
|
89
|
+
|
|
90
|
+
self._all_moments = {}
|
|
91
|
+
self._N = self.sampling_frequency * self.correlation_duration
|
|
92
|
+
self._analysis_duration = analysis_duration
|
|
93
|
+
self._N_analysis = int(self.sampling_frequency * self.analysis_duration)
|
|
94
|
+
self._nothing_todo = False
|
|
95
|
+
self._compute_Cij = True
|
|
96
|
+
self._download = True
|
|
97
|
+
self._compute_moments = True
|
|
98
|
+
self.setup_backend()
|
|
99
|
+
# self.initialize()
|
|
100
|
+
|
|
101
|
+
if self.auto_corr_method == "mean":
|
|
102
|
+
self.estimator = np.mean
|
|
103
|
+
elif self.auto_corr_method == "median":
|
|
104
|
+
self.estimator = np.median
|
|
105
|
+
else:
|
|
106
|
+
raise KeyError(f"Unknown estimator {self.auto_corr_method}")
|
|
107
|
+
|
|
108
|
+
if self.backend == "numpy":
|
|
109
|
+
self.Cij_extn = "npy"
|
|
110
|
+
else:
|
|
111
|
+
self.Cij_extn = "h5"
|
|
112
|
+
|
|
113
|
+
if window is not None:
|
|
114
|
+
if window=='tukey':
|
|
115
|
+
self.window = scipy.signal.windows.tukey(self.sampling_frequency*self.correlation_duration, alpha=0.2)
|
|
116
|
+
elif window=='hann':
|
|
117
|
+
self.window = scipy.signal.windows.hann(self.sampling_frequency*self.correlation_duration)
|
|
118
|
+
else:
|
|
119
|
+
self.window = 1
|
|
120
|
+
|
|
121
|
+
self.N_acorr = 2*(self.N-1) + 1
|
|
122
|
+
N_axis_minus = np.arange(1, self.N)
|
|
123
|
+
N_axis_plus = np.arange(1, self.N+1)[::-1]
|
|
124
|
+
self.acorr_N_axis = np.concatenate((N_axis_minus, N_axis_plus))
|
|
125
|
+
|
|
126
|
+
self.segment_choice = segment_choice
|
|
127
|
+
if segment_choice=="disjoint":
|
|
128
|
+
self.compute_effective_noise_segment_gps_times = self.compute_effective_noise_segment_gps_times_disjoint
|
|
129
|
+
elif segment_choice=="random":
|
|
130
|
+
self.compute_effective_noise_segment_gps_times = self.compute_effective_noise_segment_gps_times_random
|
|
131
|
+
elif segment_choice=="overlapping":
|
|
132
|
+
self.compute_effective_noise_segment_gps_times = self.compute_effective_noise_segment_gps_times_overlapping
|
|
133
|
+
|
|
134
|
+
else:
|
|
135
|
+
raise KeyError(f"Unknown segment choice {segment_choice}")
|
|
136
|
+
|
|
137
|
+
self.max_n_acorr = int((self.noise_sampling_range - self.gps_time_exclusion_duration)/self.correlation_duration)
|
|
138
|
+
|
|
139
|
+
if self.n_cov > self.max_n_acorr:
|
|
140
|
+
message(f"Max number of segments possible is {self.max_n_acorr}. Defaulting to that", message_verbosity=0)
|
|
141
|
+
self._n_cov = self.max_n_acorr
|
|
142
|
+
|
|
143
|
+
self.signal_start = self.ref_gps_time - int(self.gps_time_exclusion_duration / 2)
|
|
144
|
+
self.signal_end = self.ref_gps_time + int(self.gps_time_exclusion_duration / 2)
|
|
145
|
+
|
|
146
|
+
@property
|
|
147
|
+
def sampling_frequency(self):
|
|
148
|
+
return self._sampling_frequency
|
|
149
|
+
|
|
150
|
+
@property
|
|
151
|
+
def correlation_duration(self):
|
|
152
|
+
return self._correlation_duration
|
|
153
|
+
|
|
154
|
+
@property
|
|
155
|
+
def n_cov(self):
|
|
156
|
+
return self._n_cov
|
|
157
|
+
|
|
158
|
+
@property
|
|
159
|
+
def noise_sampling_range(self):
|
|
160
|
+
return self._noise_sampling_range
|
|
161
|
+
|
|
162
|
+
@property
|
|
163
|
+
def ref_gps_time(self):
|
|
164
|
+
return self._ref_gps_time
|
|
165
|
+
|
|
166
|
+
@property
|
|
167
|
+
def noise_segments(self):
|
|
168
|
+
return self._noise_segments
|
|
169
|
+
|
|
170
|
+
@property
|
|
171
|
+
def N(self):
|
|
172
|
+
return self._N
|
|
173
|
+
|
|
174
|
+
@property
|
|
175
|
+
def N_analysis(self):
|
|
176
|
+
return self._N_analysis
|
|
177
|
+
|
|
178
|
+
@property
|
|
179
|
+
def est_auto_corr(self):
|
|
180
|
+
return self._est_auto_corr
|
|
181
|
+
|
|
182
|
+
@property
|
|
183
|
+
def gps_time_exclusion_duration(self):
|
|
184
|
+
"""The duration of the time segment to exclude
|
|
185
|
+
from analysis. This is specified as a single
|
|
186
|
+
integer number. The segment is assumed to be
|
|
187
|
+
centered at `gps_time`"""
|
|
188
|
+
|
|
189
|
+
return self._gps_time_exclusion_duration
|
|
190
|
+
|
|
191
|
+
@property
|
|
192
|
+
def auto_corr_method(self):
|
|
193
|
+
return self._auto_corr_method
|
|
194
|
+
|
|
195
|
+
@property
|
|
196
|
+
def detector(self):
|
|
197
|
+
return self._detector
|
|
198
|
+
|
|
199
|
+
@property
|
|
200
|
+
def entire_segment_gps_start_time(self):
|
|
201
|
+
return self._entire_segment_gps_start_time
|
|
202
|
+
|
|
203
|
+
@property
|
|
204
|
+
def entire_segment_gps_end_time(self):
|
|
205
|
+
return self._entire_segment_gps_end_time
|
|
206
|
+
|
|
207
|
+
@property
|
|
208
|
+
def entire_noise_ts(self):
|
|
209
|
+
return self._entire_noise_ts
|
|
210
|
+
|
|
211
|
+
@property
|
|
212
|
+
def data_file_name(self):
|
|
213
|
+
return self._data_file_name
|
|
214
|
+
|
|
215
|
+
@property
|
|
216
|
+
def all_auto_corr(self):
|
|
217
|
+
return self._all_auto_corr
|
|
218
|
+
|
|
219
|
+
@property
|
|
220
|
+
def Cij(self):
|
|
221
|
+
return self._Cij
|
|
222
|
+
|
|
223
|
+
@property
|
|
224
|
+
def Cij_file_name(self):
|
|
225
|
+
return self._Cij_file_name
|
|
226
|
+
|
|
227
|
+
@property
|
|
228
|
+
def all_moments(self):
|
|
229
|
+
return self._all_moments
|
|
230
|
+
|
|
231
|
+
@property
|
|
232
|
+
def analysis_duration(self):
|
|
233
|
+
return self._analysis_duration
|
|
234
|
+
|
|
235
|
+
@property
|
|
236
|
+
def nothing_todo(self):
|
|
237
|
+
return self._nothing_todo
|
|
238
|
+
|
|
239
|
+
@property
|
|
240
|
+
def moments_file_name(self):
|
|
241
|
+
return self._moments_file_name
|
|
242
|
+
|
|
243
|
+
@property
|
|
244
|
+
def compute_Cij(self):
|
|
245
|
+
return self._compute_Cij
|
|
246
|
+
|
|
247
|
+
@property
|
|
248
|
+
def download(self):
|
|
249
|
+
return self._download
|
|
250
|
+
|
|
251
|
+
@property
|
|
252
|
+
def compute_moments(self):
|
|
253
|
+
return self._compute_moments
|
|
254
|
+
|
|
255
|
+
def setup_backend(self):
|
|
256
|
+
|
|
257
|
+
if self.backend == "numpy":
|
|
258
|
+
from numpy import mean, median, sqrt, dot
|
|
259
|
+
|
|
260
|
+
self.zeros = np.zeros
|
|
261
|
+
self.array = np.array
|
|
262
|
+
|
|
263
|
+
self.mean = np.mean
|
|
264
|
+
self.median = np.median
|
|
265
|
+
self.sqrt = np.sqrt
|
|
266
|
+
self.dot = np.dot
|
|
267
|
+
|
|
268
|
+
elif self.backend == "dask":
|
|
269
|
+
from functools import partial
|
|
270
|
+
import dask.array
|
|
271
|
+
|
|
272
|
+
self.zeros = partial(dask.array.wrap.zeros, chunks=self.chunks)
|
|
273
|
+
self.array = partial(dask.array.from_array, chunks=self.chunks)
|
|
274
|
+
|
|
275
|
+
self.mean = dask.array.reductions.mean
|
|
276
|
+
self.median = dask.array.reductions.median
|
|
277
|
+
self.sqrt = dask.array.ufunc.sqrt
|
|
278
|
+
self.dot = dask.array.routines.dot
|
|
279
|
+
|
|
280
|
+
else:
|
|
281
|
+
raise KeyError(f"Unknown backend {self.backend}")
|
|
282
|
+
|
|
283
|
+
def initialize(self):
|
|
284
|
+
|
|
285
|
+
message("Initializing")
|
|
286
|
+
message("\tParsing GPS times...")
|
|
287
|
+
|
|
288
|
+
self._Cij_file_name = f"Cij_gpsT{self.ref_gps_time}_R{self.noise_sampling_range}_D{self.correlation_duration}_S{self.sampling_frequency}_A{self.analysis_duration}_N{self.n_cov}"
|
|
289
|
+
self._moments_file_name = f"moments_gpsT{self.ref_gps_time}_R{self.noise_sampling_range}_D{self.correlation_duration}_S{self.sampling_frequency}_A{self.analysis_duration}_N{self.n_cov}.pkl"
|
|
290
|
+
self.acorr_file_name = f"rho_gpsT{self.ref_gps_time}_R{self.noise_sampling_range}_D{self.correlation_duration}_S{self.sampling_frequency}_A{self.analysis_duration}_N{self.n_cov}"
|
|
291
|
+
|
|
292
|
+
self._entire_segment_gps_start_time = (
|
|
293
|
+
self.ref_gps_time - self.noise_sampling_range - self.correlation_duration
|
|
294
|
+
)
|
|
295
|
+
self._entire_segment_gps_end_time = (
|
|
296
|
+
self.ref_gps_time + self.noise_sampling_range + self.correlation_duration
|
|
297
|
+
)
|
|
298
|
+
|
|
299
|
+
if self.data_type == "open" or self.data_type == "server":
|
|
300
|
+
self.setup_online_data()
|
|
301
|
+
elif self.data_type == "file":
|
|
302
|
+
self.read_data_from_file()
|
|
303
|
+
|
|
304
|
+
else:
|
|
305
|
+
# self.find_data_segment()
|
|
306
|
+
# self.load_data_propreitery()
|
|
307
|
+
# self._data_file_name = f"Entire_noise_ts_{self.data_type}_gpsTref{self.ref_gps_time}_{self.entire_segment_gps_start_time}_{self._entire_segment_gps_end_time}_S{self.sampling_frequency}_A{self.analysis_duration}.txt"
|
|
308
|
+
raise NotImplementedError
|
|
309
|
+
|
|
310
|
+
def setup_online_data(self):
|
|
311
|
+
"""Download, and read in open data"""
|
|
312
|
+
self._entire_segment_gps_start_time = (
|
|
313
|
+
self.ref_gps_time - self.noise_sampling_range - self.correlation_duration
|
|
314
|
+
)
|
|
315
|
+
|
|
316
|
+
self._entire_segment_gps_end_time = (
|
|
317
|
+
self.ref_gps_time + self.noise_sampling_range + self.correlation_duration
|
|
318
|
+
)
|
|
319
|
+
message("\tSetting file names...")
|
|
320
|
+
self._data_file_name = f"Entire_noise_ts_{self.data_type}_gpsT{self.ref_gps_time}_R{self.noise_sampling_range}_D{self.correlation_duration}_S{self.sampling_frequency}_A{self.analysis_duration}.txt"
|
|
321
|
+
|
|
322
|
+
message("Obtaining data")
|
|
323
|
+
if self.check_file_exists(self.data_file_name):
|
|
324
|
+
message("\tLoading data from disk", message_verbosity=1)
|
|
325
|
+
self.load_entire_time_segment()
|
|
326
|
+
self._download = False
|
|
327
|
+
|
|
328
|
+
if self.check_file_exists(f"{self.Cij_file_name}.{self.Cij_extn}"):
|
|
329
|
+
message("Loading Cij from disk", message_verbosity=1)
|
|
330
|
+
self.load_Cij()
|
|
331
|
+
self._compute_Cij = False
|
|
332
|
+
|
|
333
|
+
if self.check_file_exists(self.moments_file_name):
|
|
334
|
+
self.load_stat_moments()
|
|
335
|
+
self._compute_moments = False
|
|
336
|
+
self._nothing_todo = True
|
|
337
|
+
|
|
338
|
+
else:
|
|
339
|
+
message("\tDownloading data")
|
|
340
|
+
self.download_full_data()
|
|
341
|
+
self.resample_data()
|
|
342
|
+
message("\t Saving data to disk")
|
|
343
|
+
self.save_entire_time_segment()
|
|
344
|
+
|
|
345
|
+
def read_data_from_file(self):
|
|
346
|
+
|
|
347
|
+
try:
|
|
348
|
+
entire_noise_ts = TimeSeries.read(self.direct_data_path, self.load_channel, verbose=True)
|
|
349
|
+
|
|
350
|
+
except Exception as excep:
|
|
351
|
+
message(excep)
|
|
352
|
+
entire_noise_ts = None
|
|
353
|
+
raise FileNotFoundError
|
|
354
|
+
|
|
355
|
+
entire_noise_ts = self.demean_ts(entire_noise_ts)
|
|
356
|
+
self.entire_noise_ts_time_axis = entire_noise_ts.times
|
|
357
|
+
self._entire_noise_ts = entire_noise_ts
|
|
358
|
+
|
|
359
|
+
def resample_data_scipy(self):
|
|
360
|
+
|
|
361
|
+
original_sampling_f = self.entire_noise_ts.sample_rate
|
|
362
|
+
|
|
363
|
+
if int(self.sampling_frequency) != int(original_sampling_f.value):
|
|
364
|
+
message("Resampling using cubic spline", message_verbosity=2)
|
|
365
|
+
from scipy.interpolate import interp1d
|
|
366
|
+
new_dt = 1 / self.sampling_frequency
|
|
367
|
+
#print(new_dt)
|
|
368
|
+
new_time_axis = np.arange(
|
|
369
|
+
self.entire_noise_ts_time_axis[0].value,
|
|
370
|
+
self.entire_noise_ts_time_axis[-1].value,
|
|
371
|
+
new_dt,
|
|
372
|
+
)
|
|
373
|
+
new_entire_noise_ts = interp1d(
|
|
374
|
+
self.entire_noise_ts_time_axis, self.entire_noise_ts, kind="cubic"
|
|
375
|
+
)(new_time_axis)
|
|
376
|
+
|
|
377
|
+
self._entire_noise_ts = TimeSeries(
|
|
378
|
+
data=new_entire_noise_ts, times=new_time_axis
|
|
379
|
+
)
|
|
380
|
+
self.entire_noise_ts_time_axis = new_time_axis
|
|
381
|
+
|
|
382
|
+
def resample_data_gwpy(self):
|
|
383
|
+
|
|
384
|
+
original_sampling_f = self.entire_noise_ts.sample_rate
|
|
385
|
+
|
|
386
|
+
if int(self.sampling_frequency) != int(original_sampling_f.value):
|
|
387
|
+
message("Resampling using gwpy", message_verbosity=2)
|
|
388
|
+
|
|
389
|
+
new_entire_noise_ts = self.entire_noise_ts.resample(self.sampling_frequency)
|
|
390
|
+
|
|
391
|
+
self._entire_noise_ts = new_entire_noise_ts
|
|
392
|
+
self.entire_noise_ts_time_axis = new_entire_noise_ts.times.value
|
|
393
|
+
|
|
394
|
+
def compute_effective_noise_segment_gps_times_random(self):
|
|
395
|
+
"""Get the noise segment GPS time endpoints of correlation duration
|
|
396
|
+
that do not include the gps_time_exclusion duration.
|
|
397
|
+
Returns a dict.
|
|
398
|
+
"""
|
|
399
|
+
|
|
400
|
+
message("Computing noise segment GPS times")
|
|
401
|
+
noise_segments = {}
|
|
402
|
+
for seg_ind in range(self.n_cov):
|
|
403
|
+
not_found = True
|
|
404
|
+
|
|
405
|
+
while not_found:
|
|
406
|
+
seg_centre = np.random.randint(
|
|
407
|
+
self.ref_gps_time - self.noise_sampling_range,
|
|
408
|
+
self.ref_gps_time + self.noise_sampling_range,
|
|
409
|
+
)
|
|
410
|
+
seg_start = seg_centre - self.correlation_duration / 2
|
|
411
|
+
seg_end = seg_centre + self.correlation_duration / 2
|
|
412
|
+
|
|
413
|
+
if (self.signal_start > seg_end) or (self.signal_end < seg_start):
|
|
414
|
+
not_found = False
|
|
415
|
+
|
|
416
|
+
noise_segments.update(
|
|
417
|
+
{
|
|
418
|
+
seg_ind: (
|
|
419
|
+
seg_start,
|
|
420
|
+
seg_end,
|
|
421
|
+
)
|
|
422
|
+
}
|
|
423
|
+
)
|
|
424
|
+
|
|
425
|
+
self._noise_segments = noise_segments
|
|
426
|
+
|
|
427
|
+
def compute_effective_noise_segment_gps_times_disjoint(self):
|
|
428
|
+
"""Get the noise segment GPS time endpoints of correlation duration
|
|
429
|
+
that do not include the gps_time_exclusion duration.
|
|
430
|
+
Returns a dict.
|
|
431
|
+
"""
|
|
432
|
+
message("Computing noise segment GPS times")
|
|
433
|
+
noise_segments = {}
|
|
434
|
+
|
|
435
|
+
for seg_ind in range(self.n_cov):
|
|
436
|
+
not_found = True
|
|
437
|
+
|
|
438
|
+
while not_found:
|
|
439
|
+
seg_centre = self.ref_gps_time - self.noise_sampling_range + (seg_ind+0.5)*self.correlation_duration
|
|
440
|
+
seg_start = seg_centre - self.correlation_duration / 2
|
|
441
|
+
seg_end = seg_centre + self.correlation_duration / 2
|
|
442
|
+
|
|
443
|
+
if (self.signal_start > seg_end) or (self.signal_end < seg_start):
|
|
444
|
+
not_found = False
|
|
445
|
+
|
|
446
|
+
noise_segments.update(
|
|
447
|
+
{
|
|
448
|
+
seg_ind: (
|
|
449
|
+
seg_start,
|
|
450
|
+
seg_end,
|
|
451
|
+
)
|
|
452
|
+
}
|
|
453
|
+
)
|
|
454
|
+
|
|
455
|
+
self._noise_segments = noise_segments
|
|
456
|
+
|
|
457
|
+
def compute_effective_noise_segment_gps_times_overlapping(self):
|
|
458
|
+
"""Get the noise segment GPS time endpoints of correlation duration
|
|
459
|
+
that do not include the gps_time_exclusion duration.
|
|
460
|
+
Returns a dict.
|
|
461
|
+
"""
|
|
462
|
+
|
|
463
|
+
message("Computing noise segment GPS times")
|
|
464
|
+
noise_segments = {}
|
|
465
|
+
|
|
466
|
+
for seg_ind in range(self.n_cov):
|
|
467
|
+
not_found = True
|
|
468
|
+
|
|
469
|
+
while not_found:
|
|
470
|
+
seg_centre = self.ref_gps_time - self.noise_sampling_range + (seg_ind+0.5)*self.correlation_duration/2
|
|
471
|
+
seg_start = seg_centre - self.correlation_duration / 2
|
|
472
|
+
seg_end = seg_centre + self.correlation_duration / 2
|
|
473
|
+
|
|
474
|
+
if (self.signal_start > seg_end) or (self.signal_end < seg_start):
|
|
475
|
+
not_found = False
|
|
476
|
+
|
|
477
|
+
noise_segments.update(
|
|
478
|
+
{
|
|
479
|
+
seg_ind: (
|
|
480
|
+
seg_start,
|
|
481
|
+
seg_end,
|
|
482
|
+
)
|
|
483
|
+
}
|
|
484
|
+
)
|
|
485
|
+
|
|
486
|
+
self._noise_segments = noise_segments
|
|
487
|
+
|
|
488
|
+
|
|
489
|
+
def get_segment_gps_times(self, segment_number):
|
|
490
|
+
|
|
491
|
+
return self.noise_segments[segment_number]
|
|
492
|
+
|
|
493
|
+
def fetch_data_array(self, segment_number):
|
|
494
|
+
|
|
495
|
+
if self.check_array_exists(self.entire_noise_ts):
|
|
496
|
+
message("Fetching saved data", message_verbosity=3)
|
|
497
|
+
# print(self.get_segment_gps_times(segment_number))
|
|
498
|
+
seg_gps_start, seg_gps_end = self.get_segment_gps_times(segment_number)
|
|
499
|
+
ind_start = int((
|
|
500
|
+
seg_gps_start - self.entire_segment_gps_start_time
|
|
501
|
+
) * self.sampling_frequency)
|
|
502
|
+
ind_end = int((
|
|
503
|
+
seg_gps_end - self.entire_segment_gps_start_time
|
|
504
|
+
) * self.sampling_frequency)
|
|
505
|
+
noise_ts = self.entire_noise_ts[ind_start:ind_end]
|
|
506
|
+
|
|
507
|
+
else:
|
|
508
|
+
try:
|
|
509
|
+
noise_ts = self.get_data(
|
|
510
|
+
self.channel,
|
|
511
|
+
*self.get_segment_gps_times(segment_number),
|
|
512
|
+
verbose=True,
|
|
513
|
+
)
|
|
514
|
+
|
|
515
|
+
except Exception as excep:
|
|
516
|
+
message(excep)
|
|
517
|
+
|
|
518
|
+
return self.demean_ts(noise_ts)
|
|
519
|
+
|
|
520
|
+
def get_data_from_file(self, channel, seg_start=None, seg_end=None, verbose=False):
|
|
521
|
+
|
|
522
|
+
return TimeSeries.read(self.direct_data_path, self.load_channel)
|
|
523
|
+
|
|
524
|
+
def check_array_exists(self, array):
|
|
525
|
+
|
|
526
|
+
# if self.backend=='numpy':
|
|
527
|
+
return not (np.array(self.entire_noise_ts) == np.array(None)).all()
|
|
528
|
+
# elif self.backend=='dask':
|
|
529
|
+
# return not (self.entire_noise_ts == None).all().compute()
|
|
530
|
+
# else:
|
|
531
|
+
# raise KeyError(f"Unknown backend {self.backend}")
|
|
532
|
+
|
|
533
|
+
def estimate_auto_corr(self):
|
|
534
|
+
"""Estimate the auto-correaltion function using all
|
|
535
|
+
the noise segments"""
|
|
536
|
+
|
|
537
|
+
message("Computing autocorrelations...\n", message_verbosity=1)
|
|
538
|
+
|
|
539
|
+
#all_auto_corr = np.zeros((self.n_cov, self.N_analysis))
|
|
540
|
+
all_auto_corr = np.zeros((self.n_cov, self.N_acorr))
|
|
541
|
+
|
|
542
|
+
for seg_ind in tqdm(range(self.n_cov)):
|
|
543
|
+
noise_ts = self.window*np.array(self.fetch_data_array(seg_ind))
|
|
544
|
+
one_set_of_moments = self.compute_stat_moments(noise_ts)
|
|
545
|
+
self._all_moments.update({seg_ind: one_set_of_moments})
|
|
546
|
+
noise_ts = self.demean_ts(noise_ts)
|
|
547
|
+
auto_corr_i = self.auto_coorelate(noise_ts)
|
|
548
|
+
all_auto_corr[seg_ind, :] = auto_corr_i
|
|
549
|
+
#progressbar(seg_ind + 1, self.n_cov)
|
|
550
|
+
|
|
551
|
+
self._all_auto_corr = all_auto_corr
|
|
552
|
+
|
|
553
|
+
self.save_array(f"all_{self.acorr_file_name}", self.all_auto_corr)
|
|
554
|
+
#est_auto_corr = np.array(
|
|
555
|
+
# [self.estimator(all_auto_corr[:, ind]) for ind in range(self.N_acorr)]
|
|
556
|
+
#)
|
|
557
|
+
est_auto_corr = self.estimator(all_auto_corr, axis=0)
|
|
558
|
+
|
|
559
|
+
#self._est_auto_corr = est_auto_corr
|
|
560
|
+
self._est_auto_corr = est_auto_corr
|
|
561
|
+
message("\n", message_verbosity=1)
|
|
562
|
+
|
|
563
|
+
def estimate_symm_toeplitz_Cij(self, N=None):
|
|
564
|
+
"""Construct a symmetric Toeplez cross correlation
|
|
565
|
+
matrix from a given a noise time series"""
|
|
566
|
+
|
|
567
|
+
start = self.N_acorr//2
|
|
568
|
+
|
|
569
|
+
if N is None:
|
|
570
|
+
end=start+self.N_analysis
|
|
571
|
+
else:
|
|
572
|
+
end=start+N
|
|
573
|
+
|
|
574
|
+
message("\nComputing the cross correlation matrix", message_verbosity=1)
|
|
575
|
+
auto_corr = self.est_auto_corr[start:end]
|
|
576
|
+
#auto_corr_pos = self.est_auto_corr[auto_corr.size//2:N]
|
|
577
|
+
#N = self.N_analysis
|
|
578
|
+
#Cij = self.zeros((N, N))
|
|
579
|
+
#count = 0
|
|
580
|
+
#total_num_entries = N * (N + 1) / 2
|
|
581
|
+
#num_unique_entries = len(auto_corr)
|
|
582
|
+
|
|
583
|
+
self._Cij = scipy.linalg.toeplitz(auto_corr)
|
|
584
|
+
|
|
585
|
+
#if self.backend == "numpy":
|
|
586
|
+
# row_idx, col_idx = np.indices(Cij.shape)
|
|
587
|
+
#elif self.backend == "dask":
|
|
588
|
+
# row_idx, col_idx = dask.array.indices(Cij.shape)
|
|
589
|
+
#else:
|
|
590
|
+
# raise KeyError(f"Unknown backend {self.backend}")
|
|
591
|
+
|
|
592
|
+
#for rel_idx, acor_val in enumerate(auto_corr):
|
|
593
|
+
# Cij[abs(row_idx - col_idx) == rel_idx] = acor_val
|
|
594
|
+
# count += 1
|
|
595
|
+
# print(f"Progress: {100*count/num_unique_entries:.2f}%", end="\r")
|
|
596
|
+
|
|
597
|
+
|
|
598
|
+
# for row_ind in range(N):
|
|
599
|
+
# for col_ind in range(row_ind, N):
|
|
600
|
+
# rel_ind = abs(col_ind - row_ind)
|
|
601
|
+
# Cij[row_ind, col_ind] = auto_corr[rel_ind]
|
|
602
|
+
# if row_ind != col_ind:
|
|
603
|
+
# Cij[col_ind, row_ind] = Cij[row_ind, col_ind]
|
|
604
|
+
# count += 1
|
|
605
|
+
# print(f"Progress: {count/total_num_entries}%", end='\r')
|
|
606
|
+
|
|
607
|
+
# if count % 1000 == 0:
|
|
608
|
+
# progressbar(count, total_num_entries)
|
|
609
|
+
|
|
610
|
+
#self._Cij = Cij
|
|
611
|
+
|
|
612
|
+
def run(self):
|
|
613
|
+
|
|
614
|
+
if not self.nothing_todo:
|
|
615
|
+
self.compute_effective_noise_segment_gps_times()
|
|
616
|
+
|
|
617
|
+
if self.compute_moments:
|
|
618
|
+
self.estimate_auto_corr()
|
|
619
|
+
self.save_auto_corr()
|
|
620
|
+
self.save_stat_moments()
|
|
621
|
+
|
|
622
|
+
if self.compute_Cij:
|
|
623
|
+
self.estimate_symm_toeplitz_Cij()
|
|
624
|
+
self.save_Cij()
|
|
625
|
+
|
|
626
|
+
|
|
627
|
+
def download_full_data(self):
|
|
628
|
+
"""Fetch the entire noise stream for the required duration"""
|
|
629
|
+
|
|
630
|
+
message("Downloading data...", message_verbosity=1)
|
|
631
|
+
gps0 = self.ref_gps_time - self.noise_sampling_range - self.correlation_duration
|
|
632
|
+
gps1 = self.ref_gps_time + self.noise_sampling_range + self.correlation_duration
|
|
633
|
+
|
|
634
|
+
try:
|
|
635
|
+
entire_noise_ts = self.get_data(self.load_channel, gps0, gps1, verbose=True)
|
|
636
|
+
|
|
637
|
+
except Exception as excep:
|
|
638
|
+
message(excep)
|
|
639
|
+
entire_noise_ts = None
|
|
640
|
+
|
|
641
|
+
entire_noise_ts = self.demean_ts(entire_noise_ts)
|
|
642
|
+
self.entire_noise_ts_time_axis = entire_noise_ts.times.value
|
|
643
|
+
self._entire_noise_ts = entire_noise_ts
|
|
644
|
+
|
|
645
|
+
def demean_ts(self, time_series):
|
|
646
|
+
# if isinstance(time_series, TimeSeries):
|
|
647
|
+
if self.backend == "numpy" or isinstance(time_series, np.ndarray):
|
|
648
|
+
return time_series - np.mean(time_series)
|
|
649
|
+
# elif isinstance(self, da.array):
|
|
650
|
+
elif self.backend == "dask" and isinstance(time_series, da.array):
|
|
651
|
+
return time_series - self.mean(time_series).compute()
|
|
652
|
+
|
|
653
|
+
def find_data_segment(self):
|
|
654
|
+
dir_suffix = int(self.ref_gps_time / 10000000)
|
|
655
|
+
|
|
656
|
+
assert (
|
|
657
|
+
dir_suffix > 99 and dir_suffix < 1000
|
|
658
|
+
), f"The prefix dir could not be computed properly from the reference time {dir_suffix}"
|
|
659
|
+
|
|
660
|
+
self.data_file_dir = Path(
|
|
661
|
+
f"/cvmfs/ligo.storage.igwn.org/igwn/ligo/frames/O4/hoft_C00/{self.detector}/{self.detector[0]}-{self.detector}_HOFT_C00-{dir_suffix}"
|
|
662
|
+
)
|
|
663
|
+
self._data_file_name = self.get_dataframe_name_containing_reference_time(
|
|
664
|
+
self.data_file_dir
|
|
665
|
+
)
|
|
666
|
+
self.data_file_path = self.data_file_dir / self.data_file_name
|
|
667
|
+
|
|
668
|
+
def load_data_propreitery(self):
|
|
669
|
+
"""Download propreitery LIGO data from cvmfs.
|
|
670
|
+
|
|
671
|
+
Find the segment that contains the trigger time
|
|
672
|
+
Usually aggregated data a large. It should be enough
|
|
673
|
+
for PSD estimation"""
|
|
674
|
+
|
|
675
|
+
entire_ts = TimeSeries.read(
|
|
676
|
+
self.data_file_path, f"{self.detector}:{self.channel}"
|
|
677
|
+
)
|
|
678
|
+
entire_ts = self.demean_ts(entire_ts)
|
|
679
|
+
self.entire_noise_ts_time_axis = self.entire_noise_ts.times
|
|
680
|
+
self._entire_noise_ts = entire_ts
|
|
681
|
+
self._entire_segment_gps_start_time = self.entire_noise_ts_time_axis[0]
|
|
682
|
+
self._entire_segment_gps_end_time = self.entire_noise_ts_time_axis[-1]
|
|
683
|
+
|
|
684
|
+
def get_dataframe_name_containing_reference_time(self, data_file_dir):
|
|
685
|
+
"""Get available gps times"""
|
|
686
|
+
|
|
687
|
+
files = os.listdir(data_file_dir)
|
|
688
|
+
files = [item for item in files if ".gwf" in item]
|
|
689
|
+
self.available_gps_times = np.array([int(item[14:24]) for item in files])
|
|
690
|
+
data_file_idx = np.argmin(abs(self.available_gps_times - self.ref_gps_time))
|
|
691
|
+
data_file_name = files[data_file_idx]
|
|
692
|
+
|
|
693
|
+
return data_file_name
|
|
694
|
+
|
|
695
|
+
def save_entire_time_segment(self):
|
|
696
|
+
|
|
697
|
+
entire_noise_ts = TimeSeries(
|
|
698
|
+
data=self.entire_noise_ts, times=self.entire_noise_ts_time_axis
|
|
699
|
+
)
|
|
700
|
+
entire_noise_ts.write(self.data_file_name)
|
|
701
|
+
|
|
702
|
+
def load_entire_time_segment(self):
|
|
703
|
+
entire_noise_ts = TimeSeries.read(self.data_file_name)
|
|
704
|
+
self.entire_noise_ts_time_axis = entire_noise_ts.times
|
|
705
|
+
self._entire_noise_ts = entire_noise_ts
|
|
706
|
+
|
|
707
|
+
def check_file_exists(self, file_path):
|
|
708
|
+
flag = isfile(file_path)
|
|
709
|
+
return flag
|
|
710
|
+
|
|
711
|
+
def auto_coorelate(self, ts):
|
|
712
|
+
"""Autocorrelate a astretch of data"""
|
|
713
|
+
|
|
714
|
+
#autocorr = []
|
|
715
|
+
#for index in range(0, self.N_analysis):
|
|
716
|
+
# # print(index/N)
|
|
717
|
+
# ts2 = roll(np.array(ts), index)
|
|
718
|
+
# autocorr.append(np.dot(np.array(ts), np.array(ts2)) / self.N)
|
|
719
|
+
#print(len(ts))
|
|
720
|
+
autocorr = np.correlate(np.array(ts), np.array(ts), mode='full')/self.N#/self.acorr_N_axis
|
|
721
|
+
|
|
722
|
+
return autocorr#[autocorr.size//2:autocorr.size//2+self.N_analysis]
|
|
723
|
+
|
|
724
|
+
def save_Cij(self):
|
|
725
|
+
"""Save the covariance matrix"""
|
|
726
|
+
|
|
727
|
+
message("Saving the covariance matrix", message_verbosity=2)
|
|
728
|
+
|
|
729
|
+
if isfile(self.Cij_file_name):
|
|
730
|
+
raise FileExistsError(f"{self.Cij_file_name} File already exists!")
|
|
731
|
+
|
|
732
|
+
else:
|
|
733
|
+
self.save_array(self.Cij_file_name, self.Cij)
|
|
734
|
+
def save_auto_corr(self):
|
|
735
|
+
if isfile(self.acorr_file_name):
|
|
736
|
+
raise FileExistsError(f"{self.acorr_file_name} File already exists!")
|
|
737
|
+
|
|
738
|
+
else:
|
|
739
|
+
self.save_array(self.acorr_file_name, self.est_auto_corr)
|
|
740
|
+
|
|
741
|
+
def load_Cij(self):
|
|
742
|
+
if self.backend == "numpy":
|
|
743
|
+
self._Cij = np.load(f"{self.Cij_file_name}.npy")
|
|
744
|
+
elif self.backend == "dask":
|
|
745
|
+
fd = h5py.File(f"{self.Cij_file_name}.h5")["/Cij"]
|
|
746
|
+
self._Cij = dask.array.from_array(fd)
|
|
747
|
+
|
|
748
|
+
def save_array(self, file_name, array, dset_name='/Cij'):
|
|
749
|
+
|
|
750
|
+
if isinstance(array, np.ndarray):
|
|
751
|
+
np.save(f"{file_name}.npy", array)
|
|
752
|
+
|
|
753
|
+
elif isinstance(self, dask.array.core.Array):
|
|
754
|
+
return array.to_hdf5(f"{file_name}.h5", dset_name)
|
|
755
|
+
|
|
756
|
+
def compute_stat_moments(self, noise_ts):
|
|
757
|
+
|
|
758
|
+
noise_array = np.array(noise_ts)
|
|
759
|
+
# Mean
|
|
760
|
+
noise_array_mean = np.mean(noise_array)
|
|
761
|
+
# Variance
|
|
762
|
+
noise_array_variance = np.mean((noise_array - noise_array_mean) ** 2)
|
|
763
|
+
noise_array_std = self.sqrt(noise_array_variance)
|
|
764
|
+
moments = [noise_array_mean, noise_array_variance]
|
|
765
|
+
# Higher moments
|
|
766
|
+
for mindex in range(3, 13):
|
|
767
|
+
df = self.double_factorial(mindex - 1)
|
|
768
|
+
moments.append(
|
|
769
|
+
np.mean(((noise_array - noise_array_mean) / noise_array_std) ** mindex)
|
|
770
|
+
/ df
|
|
771
|
+
)
|
|
772
|
+
|
|
773
|
+
return moments
|
|
774
|
+
|
|
775
|
+
def save_stat_moments(self):
|
|
776
|
+
|
|
777
|
+
with open(self.moments_file_name, "wb") as f:
|
|
778
|
+
pickle.dump(self.all_moments, f)
|
|
779
|
+
|
|
780
|
+
def load_stat_moments(self):
|
|
781
|
+
|
|
782
|
+
with open(self.moments_file_name, "rb") as f:
|
|
783
|
+
self._all_moments = pickle.load(f)
|
|
784
|
+
|
|
785
|
+
def get_nth_moment(self, n):
|
|
786
|
+
|
|
787
|
+
nth_moment = [self.all_moments[ind][n] for ind in self.all_moments.keys()]
|
|
788
|
+
return nth_moment
|
|
789
|
+
|
|
790
|
+
def plot_moments(self):
|
|
791
|
+
|
|
792
|
+
import matplotlib.pyplot as plt
|
|
793
|
+
fig, ax = plt.subplots(nrows=4, ncols=3, figsize=(18, 12))
|
|
794
|
+
|
|
795
|
+
for mxind in range(4):
|
|
796
|
+
for myind in range(3):
|
|
797
|
+
|
|
798
|
+
mn = mxind * 3 + myind
|
|
799
|
+
ax[mxind, myind].scatter(
|
|
800
|
+
self.all_moments.keys(), self.get_nth_moment(mn - 1)
|
|
801
|
+
)
|
|
802
|
+
ax[mxind, myind].set_title(f"Moment {mn+1}")
|
|
803
|
+
|
|
804
|
+
plt.show()
|
|
805
|
+
|
|
806
|
+
def double_factorial(self, n):
|
|
807
|
+
|
|
808
|
+
if n == 0 or n == 1:
|
|
809
|
+
return 1
|
|
810
|
+
else:
|
|
811
|
+
return n * self.double_factorial(n - 2)
|