Loading [MathJax]/extensions/TeX/AMSsymbols.js
LALPulsar 7.1.1.1-5e288d3
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
spec_avg_long.c
Go to the documentation of this file.
1/*
2* Copyright (C) 2007 Gregory Mendell
3* 2020-2025 Evan Goetz
4*
5* This program is free software; you can redistribute it and/or modify
6* it under the terms of the GNU General Public License as published by
7* the Free Software Foundation; either version 2 of the License, or
8* (at your option) any later version.
9*
10* This program is distributed in the hope that it will be useful,
11* but WITHOUT ANY WARRANTY; without even the implied warranty of
12* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13* GNU General Public License for more details.
14*
15* You should have received a copy of the GNU General Public License
16* along with with program; see the file COPYING. If not, write to the
17* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
18* MA 02110-1301 USA
19*/
20
21/**
22* \file
23* \ingroup lalpulsar_bin_fscan
24*/
25
26#include "config.h"
27
28#include <libgen.h>
29#include <unistd.h>
30#include <lal/LogPrintf.h>
31#include <lal/SFTfileIO.h>
32#include <lal/Date.h>
33#include <lal/LALDatatypes.h>
34#include <lal/LALStdio.h>
35#include <lal/UserInput.h>
36#include <lal/LALPulsarVCSInfo.h>
37
38#include "fscanutils.h"
39
40/*---------- DEFINES ----------*/
41#define POWER(x) (((REAL8)crealf(x)*(REAL8)crealf(x)) + ((REAL8)cimagf(x)*(REAL8)cimagf(x)))
42
43/*----- Macros ----- */
44
45/*---------- internal types ----------*/
46
47///////////EXTRA FXN DEFS//////////////
48LIGOTimeGPSVector *setup_epochs( const SFTCatalog *catalog, const INT4 persistAvgOpt, const BOOLEAN persistAvgOptWasSet, const INT4 persistAvgSeconds );
49int set_sft_avg_epoch( struct tm *utc, LIGOTimeGPS *epoch_start, const LIGOTimeGPS first_sft_epoch, const INT4 persistAvgOpt, const BOOLEAN persistAvgOptWasSet );
50int validate_line_freq( LALStringVector **line_freq, const REAL8 f0, const REAL8 deltaF, const UINT4 numBins );
52int rngmean( const REAL8Vector *input, const REAL8Vector *output, const INT4 blocksRngMean );
53int rngstd( const REAL8Vector *input, const REAL8Vector *means, const REAL8Vector *output, const INT4 blocksRngMean );
54int select_mean_std_from_vect( REAL8 *mean, REAL8 *std, const REAL8Vector *means, const REAL8Vector *stds, const UINT4 idx, const UINT4 nside );
55
56int main( int argc, char **argv )
57{
58 lalUserVarHelpBrief = "Arithmetic and noise-weighted averge spectrum and persistency from SFTs for Fscan";
59 lalUserVarHelpDescription = "Provide SFTs to this program for computing arithmetic and noise-weighted average spectra and persistency of frequency bins above background, optionally track frequency bins above threshold or specific frequency bins, saved as ASCII data files for use by Fscan";
60
61 FILE *SPECOUT = NULL, *WTOUT = NULL, *LINEOUT = NULL;
62 int fopenerr = 0;
63
64 SFTCatalog *catalog = NULL;
65 SFTConstraints XLAL_INIT_DECL( constraints );
66 LIGOTimeGPS startTime, endTime;
67 REAL8Vector *timeavg = NULL, *timeavgwt = NULL, *sumweight = NULL, *persistency = NULL;
68 REAL8 f0 = 0, deltaF = 0;
69 CHAR outbase[256], outfile0[512], outfile1[512], outfile2[512];
70
71 CHAR *SFTpatt = NULL, *IFO = NULL, *outputDir = NULL, *outputBname = NULL, *header = NULL;
72 INT4 startGPS = 0, endGPS = 0, blocksRngMean = 21;
73 REAL8 f_min = 0.0, f_max = 0.0, timebaseline = 0, persistSNRthresh = 3.0, auto_track;
74
75 LALStringVector *line_freq = NULL;
76 REAL8Vector *freq_vect = NULL;
77 INT4 persistAvgSeconds = 0;
78 INT4 persistAvgOpt;
79 REAL8Vector *this_epoch_avg = NULL, *this_epoch_avg_wt = NULL, *new_epoch_avg = NULL, *new_epoch_wt = NULL;
80 LIGOTimeGPSVector *epoch_gps_times = NULL;
81 REAL8VectorSequence *epoch_avg = NULL;
82
83 /* Default for output directory */
84 XLAL_CHECK_MAIN( ( outputDir = XLALStringDuplicate( "." ) ) != NULL, XLAL_EFUNC );
85
86 BOOLEAN allow_skipping = 0;
87
88 XLAL_CHECK_MAIN( XLALRegisterNamedUvar( &SFTpatt, "SFTs", STRING, 'p', REQUIRED, "SFT location/pattern. Possibilities are:\n"
89 " - '<SFT file>;<SFT file>;...', where <SFT file> may contain wildcards\n - 'list:<file containing list of SFT files>'" ) == XLAL_SUCCESS, XLAL_EFUNC );
90 XLAL_CHECK_MAIN( XLALRegisterNamedUvar( &IFO, "IFO", STRING, 'I', REQUIRED, "Detector (e.g., H1)" ) == XLAL_SUCCESS, XLAL_EFUNC );
91 XLAL_CHECK_MAIN( XLALRegisterNamedUvar( &startGPS, "startGPS", INT4, 's', REQUIRED, "Starting GPS time (SFT timestamps must be >= this time)" ) == XLAL_SUCCESS, XLAL_EFUNC );
92 XLAL_CHECK_MAIN( XLALRegisterNamedUvar( &endGPS, "endGPS", INT4, 'e', REQUIRED, "Ending GPS time (SFT timestamps must be < this time)" ) == XLAL_SUCCESS, XLAL_EFUNC );
93 XLAL_CHECK_MAIN( XLALRegisterNamedUvar( &f_min, "fMin", REAL8, 'f', REQUIRED, "Minimum frequency" ) == XLAL_SUCCESS, XLAL_EFUNC );
94 XLAL_CHECK_MAIN( XLALRegisterNamedUvar( &f_max, "fMax", REAL8, 'F', REQUIRED, "Maximum frequency" ) == XLAL_SUCCESS, XLAL_EFUNC );
95 XLAL_CHECK_MAIN( XLALRegisterNamedUvar( &blocksRngMean, "blocksRngMean", INT4, 'w', OPTIONAL, "Running Median window size" ) == XLAL_SUCCESS, XLAL_EFUNC );
96 XLAL_CHECK_MAIN( XLALRegisterNamedUvar( &outputDir, "outputDir", STRING, 'd', OPTIONAL, "Output directory for data files" ) == XLAL_SUCCESS, XLAL_EFUNC );
97 XLAL_CHECK_MAIN( XLALRegisterNamedUvar( &outputBname, "outputBname", STRING, 'o', OPTIONAL, "Base name of output files" ) == XLAL_SUCCESS, XLAL_EFUNC );
98 XLAL_CHECK_MAIN( XLALRegisterNamedUvar( &timebaseline, "timeBaseline", REAL8, 't', REQUIRED, "The time baseline of sfts" ) == XLAL_SUCCESS, XLAL_EFUNC );
99 XLAL_CHECK_MAIN( XLALRegisterNamedUvar( &persistAvgSeconds, "persistAvgSeconds", INT4, 'T', OPTIONAL, "Time baseline in seconds for averaging SFTs to measure the persistency, must be >= timeBaseline (cannot also specify --persistAveOption)" ) == XLAL_SUCCESS, XLAL_EFUNC );
100 XLAL_CHECK_MAIN( XLALRegisterNamedUvar( &persistAvgOpt, "persistAvgOption", INT4, 'E', OPTIONAL, "Choose one of 1 = day, 2 = week, or 3 = month averaging for measuring the persistency (cannot also specify --persistAvgSeconds)" ) == XLAL_SUCCESS, XLAL_EFUNC );
101 XLAL_CHECK_MAIN( XLALRegisterNamedUvar( &persistSNRthresh, "persistSNRthresh", REAL8, 'z', OPTIONAL, "SNR of lines for being present in the data" ) == XLAL_SUCCESS, XLAL_EFUNC );
102 XLAL_CHECK_MAIN( XLALRegisterNamedUvar( &line_freq, "lineFreq", STRINGVector, 0, OPTIONAL, "CSV list of line frequencies (e.g., --lineFreq=21.5,22.0). If set, then an output file with all GPS start times of SFTs with float values of number of standard deviations above the mean (>0 indicates above mean). Be careful that the CSV list of values are interpreted as floating point values" ) == XLAL_SUCCESS, XLAL_EFUNC );
103 XLAL_CHECK_MAIN( XLALRegisterNamedUvar( &auto_track, "autoTrack", REAL8, 'a', OPTIONAL, "If specified, also track any frequency whose persistency is >= this threshold within range [0,1]" ) == XLAL_SUCCESS, XLAL_EFUNC );
104 XLAL_CHECK_MAIN( XLALRegisterNamedUvar( &allow_skipping, "allow_skipping", BOOLEAN, 'x', OPTIONAL, "Allow to exit without an error if no SFTs are found" ) == XLAL_SUCCESS, XLAL_EFUNC );
105 XLAL_CHECK_MAIN( XLALRegisterNamedUvar( &header, "header", STRING, 'H', OPTIONAL, "Header line in the output file; if not provided then no header line will be made" ) == XLAL_SUCCESS, XLAL_EFUNC );
106
107 BOOLEAN should_exit = 0;
109 if ( should_exit ) {
110 return ( 1 );
111 }
112
113 printf( "Starting spec_avg_long...\n" );
114
115 XLAL_CHECK_MAIN( blocksRngMean % 2 == 1, XLAL_EINVAL, "Need to provide an odd value for blocksRngMean" );
116 XLAL_CHECK_MAIN( blocksRngMean > 2, XLAL_EINVAL, "Need to provide value larger than 2 blocksRngMean" );
117 INT4 nside = ( blocksRngMean - 1 ) / 2;
118
119 // Make some checks to be sure the persistency options for averaging are set correctly
120 XLAL_CHECK_MAIN( !( XLALUserVarWasSet( &persistAvgSeconds ) && XLALUserVarWasSet( &persistAvgOpt ) ), XLAL_EINVAL, "Provide only one of --persistAvgSeconds or --persistAvgOption" );
121 if ( XLALUserVarWasSet( &persistAvgSeconds ) ) {
122 XLAL_CHECK_MAIN( persistAvgSeconds >= timebaseline, XLAL_EINVAL, "--persistAvgSeconds must be >= --timebaseline" );
123 }
124 if ( XLALUserVarWasSet( &persistAvgOpt ) ) {
125 XLAL_CHECK_MAIN( persistAvgOpt > 0 && persistAvgOpt < 4, XLAL_EINVAL, "--persistAvgOption can only take a value of 1, 2, or 3" );
126 }
127 if ( !XLALUserVarWasSet( &persistAvgSeconds ) && !XLALUserVarWasSet( &persistAvgOpt ) ) {
128 persistAvgSeconds = timebaseline;
129 }
130 if ( XLALUserVarWasSet( &auto_track ) ) {
131 XLAL_CHECK_MAIN( auto_track >= 0 && auto_track <= 1, XLAL_EINVAL, "--autoTrack must be within range [0,1]" );
132 }
133
134 //Provide the constraints to the catalog
135 startTime.gpsSeconds = startGPS;
136 startTime.gpsNanoSeconds = 0;
137 constraints.minStartTime = &startTime;
138 endTime.gpsSeconds = endGPS;
139 endTime.gpsNanoSeconds = 0;
140 constraints.maxStartTime = &endTime;
141 constraints.detector = IFO;
142
143 printf( "Calling XLALSFTdataFind with SFTpatt=%s\n", SFTpatt );
144
145 int errnum;
146 XLAL_TRY( catalog = XLALSFTdataFind( SFTpatt, &constraints ), errnum );
147
148 // Ensure that some SFTs were found given the start and end time and IFO constraints
149 // unless --allow_skipping is true
150 if ( errnum != 0 ) {
151 if ( allow_skipping ) {
152 LogPrintf( LOG_CRITICAL, "No SFTs were found, exiting with code %d due to --allow_skipping=true\n", XLAL_EUSR0 );
154 exit( XLAL_EUSR0 );
155 } else {
156 XLAL_ERROR_MAIN( errnum );
157 }
158 }
159
160 XLAL_CHECK_MAIN( catalog->length > 0, XLAL_EFAILED, "No SFTs found, please examine start time, end time, frequency range, etc." );
161
162 LogPrintf( LOG_NORMAL, "%s has length of %u SFT files\n", SFTpatt, catalog->length );
163
164 // Count the number of epochs [either the persistAvgSeconds, or the persistAvgOpt (day, week, or month)]
165 XLAL_CHECK_MAIN( ( epoch_gps_times = setup_epochs( catalog, persistAvgOpt, XLALUserVarWasSet( &persistAvgOpt ), persistAvgSeconds ) ) != NULL, XLAL_EFUNC );
166
167 /* Output files */
168 if ( XLALUserVarWasSet( &outputBname ) ) {
169 snprintf( outbase, sizeof( outbase ), "%s/%s", outputDir, outputBname );
170 } else {
171 snprintf( outbase, sizeof( outbase ), "%s/spec_%.2f_%.2f_%s_%d_%d", outputDir, f_min, f_max, constraints.detector, startTime.gpsSeconds, endTime.gpsSeconds );
172 }
173
174 snprintf( outfile0, sizeof( outfile0 ), "%s.txt", outbase );
175 snprintf( outfile1, sizeof( outfile1 ), "%s_PWA.txt", outbase );
176 snprintf( outfile2, sizeof( outfile2 ), "%s_line_times.csv", outbase );
177
178 UINT4 epoch_index = 0;
179
180 printf( "Looping over SFTs to compute average spectra\n" );
181 for ( UINT4 j = 0; j < catalog->length; j++ ) {
182 fprintf( stderr, "Extracting SFT %d...\n", j );
183
184 //Extract one SFT at a time from the catalog
185 //we do this by using a catalog timeslice to get just the current SFT
186 SFTVector *sft_vect = NULL;
187 XLAL_CHECK_MAIN( ( sft_vect = extract_one_sft( catalog, catalog->data[j].header.epoch, f_min, f_max ) ) != NULL, XLAL_EFUNC );
188 XLAL_CHECK_MAIN( sft_vect->length == 1, XLAL_EINVAL, "Extracted zero SFTs but should have extracted one" );
189
190 //Make sure the SFTs are the same length as what we're expecting from user input
191 XLAL_CHECK_MAIN( fabs( timebaseline * sft_vect->data->deltaF - 1.0 ) <= 10.*LAL_REAL8_EPS, XLAL_EINVAL, "Expected SFTs with length %f but got %f", timebaseline, 1 / sft_vect->data->deltaF );
192
193 //For the first time through the loop, we allocate some vectors
194 if ( j == 0 ) {
195 UINT4 numBins = sft_vect->data->data->length;
196 f0 = sft_vect->data->f0;
197 deltaF = sft_vect->data->deltaF;
198 printf( "numBins=%d, f0=%f, deltaF=%f\n", numBins, f0, deltaF );
199
200 if ( line_freq != NULL ) {
202 XLAL_CHECK_MAIN( ( freq_vect = line_freq_str2dbl( line_freq ) ) != NULL, XLAL_EFUNC );
203 }
204
205 XLAL_CHECK_MAIN( ( timeavg = XLALCreateREAL8Vector( numBins ) ) != NULL, XLAL_EFUNC );
206 XLAL_CHECK_MAIN( ( timeavgwt = XLALCreateREAL8Vector( numBins ) ) != NULL, XLAL_EFUNC );
207 XLAL_CHECK_MAIN( ( sumweight = XLALCreateREAL8Vector( numBins ) ) != NULL, XLAL_EFUNC );
208 XLAL_CHECK_MAIN( ( persistency = XLALCreateREAL8Vector( numBins ) ) != NULL, XLAL_EFUNC );
209 memset( persistency->data, 0, sizeof( REAL8 )*persistency->length );
210
211 // Allocate vectors for this epoch average and weights as well as if we need to make a new epoch
212 XLAL_CHECK_MAIN( ( this_epoch_avg = XLALCreateREAL8Vector( numBins ) ) != NULL, XLAL_EFUNC );
213 XLAL_CHECK_MAIN( ( this_epoch_avg_wt = XLALCreateREAL8Vector( numBins ) ) != NULL, XLAL_EFUNC );
214 XLAL_CHECK_MAIN( ( new_epoch_avg = XLALCreateREAL8Vector( numBins ) ) != NULL, XLAL_EFUNC );
215 memset( new_epoch_avg->data, 0, sizeof( REAL8 )*new_epoch_avg->length );
216 XLAL_CHECK_MAIN( ( new_epoch_wt = XLALCreateREAL8Vector( numBins ) ) != NULL, XLAL_EFUNC );
217 XLAL_CHECK_MAIN( ( epoch_avg = XLALCreateREAL8VectorSequence( epoch_gps_times->length, numBins ) ) != NULL, XLAL_EFUNC );
218
219 // Check that epoch_avg has been fully allocated. This can be problematic over many SFTs
220 XLAL_CHECK_MAIN( epoch_avg->data != NULL, XLAL_ENOMEM, "Persistency calculation failed to allocate epoch_avg. Try using a longer epoch averaging with the -E flag or longer -T" );
221 XLAL_CHECK_MAIN( ( epoch_avg->length * epoch_avg->vectorLength ) / epoch_gps_times->length == numBins, XLAL_ENOMEM, "Persistency calculation failed to allocate epoch_avg. Try using a longer epoch averaging with the -E flag or longer -T" );
222 }
223
224 //Loop over the SFT bins
225 for ( UINT4 i = 0; i < sft_vect->data->data->length; i++ ) {
226 REAL8 thispower = POWER( sft_vect->data[0].data->data[i] );
227 REAL8 thisavepower = 0.;
228 UINT4 count = 0;
229 for ( INT4 ii = -nside; ii <= nside; ii++ ) {
230 //Only add to the cumulative average power if the variables are in range
231 if ( ( INT4 )i + ii >= 0 && ( INT4 )i + ii < ( INT4 )sft_vect->data->data->length ) {
232 thisavepower += POWER( sft_vect->data[0].data->data[i + ii] );
233 count++;
234 }
235 }
236 thisavepower /= count;
237 REAL8 weight = 1. / thisavepower;
238
239 //For the first SFT, just assign the values to the vector, otherwise accumulate
240 if ( j == 0 ) {
241 timeavg->data[i] = thispower;
242 timeavgwt->data[i] = thispower * weight;
243 sumweight->data[i] = weight;
244
245 this_epoch_avg->data[i] = thispower * weight;
246 this_epoch_avg_wt->data[i] = weight;
247 } else {
248 timeavg->data[i] += thispower;
249 timeavgwt->data[i] += thispower * weight;
250 sumweight->data[i] += weight;
251
252 // Only accumulate in the epoch average if this SFT is within the current epoch
253 // Otherwise put the values in the new epoch average and weight vector.
254 if ( ( epoch_index < ( epoch_gps_times->length - 1 ) && XLALGPSCmp( &sft_vect->data->epoch, &epoch_gps_times->data[epoch_index] ) >= 0 && XLALGPSCmp( &sft_vect->data->epoch, &epoch_gps_times->data[epoch_index + 1] ) < 0 ) || epoch_index == ( epoch_gps_times->length - 1 ) ) {
255 this_epoch_avg->data[i] += thispower * weight;
256 this_epoch_avg_wt->data[i] += weight;
257 } else {
258 new_epoch_avg->data[i] = thispower * weight;
259 new_epoch_wt->data[i] = weight;
260 }
261 }
262 } // end loop over this SFT frequency bins
263
264 // If we've started putting new values into the new epoch average, then we should conclude the
265 // last epoch and load the values from the new epoch into the current epoch
266 if ( new_epoch_avg->data[0] != 0.0 ) {
267 // Compute noise weighted power in this epoch average
268 for ( UINT4 i = 0; i < this_epoch_avg->length; i++ ) {
269 this_epoch_avg->data[i] *= 2.0 / this_epoch_avg_wt->data[i] / timebaseline;
270 }
271
272 // Copy to the vector sequence of epoch averages
273 memcpy( &( epoch_avg->data[epoch_index * this_epoch_avg->length] ), this_epoch_avg->data, sizeof( REAL8 )*this_epoch_avg->length );
274 epoch_index++;
275
276 // Copy over the new epoch data into this epoch's average
277 memcpy( this_epoch_avg->data, new_epoch_avg->data, sizeof( REAL8 )*new_epoch_avg->length );
278 memcpy( this_epoch_avg_wt->data, new_epoch_wt->data, sizeof( REAL8 )*new_epoch_wt->length );
279
280 // Set the new epoch data to be zero again
281 memset( new_epoch_avg->data, 0, sizeof( REAL8 )*new_epoch_avg->length );
282 }
283 // This just repeats the above if we are in the very last SFT
284 if ( j == catalog->length - 1 ) {
285 for ( UINT4 i = 0; i < this_epoch_avg->length; i++ ) {
286 this_epoch_avg->data[i] = 2.*this_epoch_avg->data[i] / this_epoch_avg_wt->data[i] / timebaseline;
287 }
288
289 memcpy( &( epoch_avg->data[epoch_index * this_epoch_avg->length] ), this_epoch_avg->data, sizeof( REAL8 )*this_epoch_avg->length );
290 }
291
292 // Destroys current SFT Vector
293 XLALDestroySFTVector( sft_vect );
294 sft_vect = NULL;
295 } // end loop over all SFTs
296
297 XLALDestroyREAL8Vector( this_epoch_avg_wt );
298 XLALDestroyREAL8Vector( new_epoch_avg );
299 XLALDestroyREAL8Vector( new_epoch_wt );
300
301 // Allocate vectors for running mean and standard deviation of each chunk
302 REAL8Vector *means = NULL, *stds = NULL;
303 XLAL_CHECK_MAIN( ( means = XLALCreateREAL8Vector( epoch_avg->vectorLength - 2 * nside ) ) != NULL, XLAL_EFUNC );
304 XLAL_CHECK_MAIN( ( stds = XLALCreateREAL8Vector( epoch_avg->vectorLength - 2 * nside ) ) != NULL, XLAL_EFUNC );
305
306 //Loop over epochs for persistency calculation
307 for ( UINT4 j = 0; j < epoch_gps_times->length; j++ ) {
308 // Use the mean and standard deviation of data for this epoch
309 memcpy( this_epoch_avg->data, &( epoch_avg->data[j * epoch_avg->vectorLength] ), sizeof( REAL8 )*epoch_avg->vectorLength );
310 XLAL_CHECK_MAIN( rngmean( this_epoch_avg, means, blocksRngMean ) == XLAL_SUCCESS, XLAL_EFUNC );
311 XLAL_CHECK_MAIN( rngstd( this_epoch_avg, means, stds, blocksRngMean ) == XLAL_SUCCESS, XLAL_EFUNC );
312
313 // At the end points of the running mean, we need to re-use the end values
314 // This is slightly sub-optimal
315 for ( UINT4 i = 0; i < epoch_avg->vectorLength; i++ ) {
316 REAL8 mean, std;
317 XLAL_CHECK_MAIN( select_mean_std_from_vect( &mean, &std, means, stds, i, ( UINT4 )nside ) == XLAL_SUCCESS, XLAL_EFUNC );
318 // Compare this SFT frequency data point with the running mean and standard deviation
319 if ( ( epoch_avg->data[j * epoch_avg->vectorLength + i] - mean ) / std > persistSNRthresh ) {
320 persistency->data[i] += 1.0;
321 }
322 } // end loop over frequencies
323 } // end loop over epochs
324
325 // Normalize persistency to be in range 0 - 1 based on the number of epochs
326 for ( UINT4 i = 0; i < persistency->length; i++ ) {
327 persistency->data[i] /= ( REAL8 )epoch_gps_times->length;
328
329 // if auto tracking, append any frequencies to the list
330 if ( XLALUserVarWasSet( &auto_track ) && ( persistency->data[i] >= auto_track ) ) {
331 if ( freq_vect != NULL ) {
332 XLAL_CHECK_MAIN( ( freq_vect = XLALResizeREAL8Vector( freq_vect, freq_vect->length + 1 ) ) != NULL, XLAL_EFUNC );
333 } else {
334 XLAL_CHECK_MAIN( ( freq_vect = XLALCreateREAL8Vector( 1 ) ) != NULL, XLAL_EFUNC );
335 }
336 freq_vect->data[freq_vect->length - 1] = f0 + deltaF * i;
337 }
338 } // end loop over frequency bins
339
340 // allocate arrays for monitoring specific line frequencies
341 REAL8VectorSequence *line_excess_in_epochs = NULL;
342 if ( freq_vect != NULL ) {
343 INT4Vector *line_freq_bin_in_sft = NULL;
344 XLAL_CHECK_MAIN( ( line_freq_bin_in_sft = XLALCreateINT4Vector( freq_vect->length ) ) != NULL, XLAL_EFUNC );
345 XLAL_CHECK_MAIN( ( line_excess_in_epochs = XLALCreateREAL8VectorSequence( freq_vect->length, epoch_gps_times->length ) ) != NULL, XLAL_EFUNC );
346 memset( line_excess_in_epochs->data, 0, sizeof( REAL8 )*line_excess_in_epochs->length * line_excess_in_epochs->vectorLength );
347
348 // Set line_freq_array as the REAL8 values of the line_freq string vector
349 // Set line_freq_bin_in_sft as the nearest INT4 values of the line frequencies to track
350 for ( UINT4 n = 0; n < freq_vect->length; n++ ) {
351 line_freq_bin_in_sft->data[n] = ( INT4 )round( ( freq_vect->data[n] - f0 ) / deltaF );
352 }
353
354 // Loop over chunks checking if the line frequencies to track are above threshold in each chunk
355 for ( UINT4 j = 0; j < epoch_gps_times->length; j++ ) {
356 // Use the standard deviation of data for this epoch
357 memcpy( this_epoch_avg->data, &( epoch_avg->data[j * epoch_avg->vectorLength] ), sizeof( REAL8 )*epoch_avg->vectorLength );
358 XLAL_CHECK_MAIN( rngmean( this_epoch_avg, means, blocksRngMean ) == XLAL_SUCCESS, XLAL_EFUNC );
359 XLAL_CHECK_MAIN( rngstd( this_epoch_avg, means, stds, blocksRngMean ) == XLAL_SUCCESS, XLAL_EFUNC );
360
361 // Check each line frequency
362 for ( UINT4 i = 0; i < line_freq_bin_in_sft->length; i++ ) {
363 REAL8 mean, std;
364 XLAL_CHECK_MAIN( select_mean_std_from_vect( &mean, &std, means, stds, line_freq_bin_in_sft->data[i], ( UINT4 )nside ) == XLAL_SUCCESS, XLAL_EFUNC );
365
366 // assign the value of the number of standard devaiations above the mean for this chunk
367 line_excess_in_epochs->data[i * line_excess_in_epochs->vectorLength + j] = ( epoch_avg->data[j * epoch_avg->vectorLength + line_freq_bin_in_sft->data[i]] - mean ) / std;
368 } // end loop over lines to track
369 } // end loop over chunks of SFT averages
370
371 XLALDestroyINT4Vector( line_freq_bin_in_sft );
372 } // end if line tracking
373
374 XLALDestroyREAL8Vector( means );
376 XLALDestroyREAL8Vector( this_epoch_avg );
378
379 /* Print to files */
380 SPECOUT = fopen( outfile0, "w" );
381 fopenerr = errno;
382 XLAL_CHECK_MAIN( SPECOUT != NULL, XLAL_EIO, "Failed to open '%s' for writing: %s", outfile0, strerror( fopenerr ) );
383 WTOUT = fopen( outfile1, "w" );
384 fopenerr = errno;
385 XLAL_CHECK_MAIN( WTOUT != NULL, XLAL_EIO, "Failed to open '%s' for writing: %s", outfile1, strerror( fopenerr ) );
386 // Write header line to files, if provided
387 if ( XLALUserVarWasSet( &header ) ) {
388 fprintf( SPECOUT, "# %s\n", header );
389 fprintf( WTOUT, "# %s\n", header );
390 }
391 for ( UINT4 i = 0; i < timeavg->length; i++ ) {
392 REAL8 f = f0 + ( ( REAL4 )i ) * deltaF;
393 REAL8 PSD = 2.*timeavg->data[i] / ( ( REAL4 )catalog->length ) / timebaseline;
394 REAL8 PSDWT = 2.*timeavgwt->data[i] / sumweight->data[i] / timebaseline;
395 REAL8 AMPPSD = pow( PSD, 0.5 );
396 REAL8 AMPPSDWT = pow( PSDWT, 0.5 );
397 REAL8 persist = persistency->data[i];
398 fprintf( SPECOUT, "%16.8f %g %g %g %g %g\n", f, PSD, AMPPSD, PSDWT, AMPPSDWT, persist );
399
400 REAL8 PWA_TAVGWT = timeavgwt->data[i];
401 REAL8 PWA_SUMWT = sumweight->data[i];
402 fprintf( WTOUT, "%16.8f %g %g\n", f, PWA_TAVGWT, PWA_SUMWT );
403 }
404 fclose( SPECOUT );
405 fclose( WTOUT );
406
407 // If user specified a list of line frequencies to monitor then print those data to a file
408 if ( freq_vect != NULL ) {
409 // open the line tracking output file for writing
410 LINEOUT = fopen( outfile2, "w" );
411 fopenerr = errno;
412 XLAL_CHECK_MAIN( LINEOUT != NULL, XLAL_EIO, "Failed to open '%s' for writing: %s", outfile2, strerror( fopenerr ) );
413 if ( XLALUserVarWasSet( &header ) ) {
414 fprintf( LINEOUT, "# %s\n", header );
415 }
416 if ( !XLALUserVarWasSet( &persistAvgOpt ) ) {
417 fprintf( LINEOUT, "# GPS Epoch (len = %d s)", persistAvgSeconds );
418 } else {
419 fprintf( LINEOUT, "# GPS Epoch (option = %d)", persistAvgOpt );
420 }
421 for ( UINT4 n = 0; n < freq_vect->length; n++ ) {
422 fprintf( LINEOUT, ",%16.8f Hz", freq_vect->data[n] );
423 }
424 fprintf( LINEOUT, "\n" );
425 for ( UINT4 i = 0; i < epoch_gps_times->length; i++ ) {
426 fprintf( LINEOUT, "%d", epoch_gps_times->data[i].gpsSeconds );
427 for ( UINT4 n = 0; n < freq_vect->length; n++ ) {
428 fprintf( LINEOUT, ",%.4f", line_excess_in_epochs->data[n * line_excess_in_epochs->vectorLength + i] );
429 }
430 fprintf( LINEOUT, "\n" );
431 }
432 fclose( LINEOUT );
433 XLALDestroyREAL8VectorSequence( line_excess_in_epochs );
434 XLALDestroyREAL8Vector( freq_vect );
435 }
436
437 /*------------------------------------------------------------------------------------------------------------------------*/
438
439 fprintf( stderr, "Destroying Variables\n" );
440
441 XLALDestroyTimestampVector( epoch_gps_times );
442 XLALDestroySFTCatalog( catalog );
443 XLALDestroyREAL8Vector( timeavg );
444 XLALDestroyREAL8Vector( timeavgwt );
445 XLALDestroyREAL8Vector( sumweight );
446 XLALDestroyREAL8Vector( persistency );
447
449 fprintf( stderr, "Done Destroying Variables\n" );
450 fprintf( stderr, "end of spec_avg_long\n" );
451
452 return ( 0 );
453
454}
455/* END main */
456
457/* Set up epochs:
458 This counts the number of epochs that would be set;
459 allocates a LIGOTimeGPSVector for the number of epochs;
460 populates the elements with the GPS times of the epochs */
461LIGOTimeGPSVector *setup_epochs( const SFTCatalog *catalog, const INT4 persistAvgOpt, const BOOLEAN persistAvgOptWasSet, const INT4 persistAvgSeconds )
462{
463 UINT4 epoch_index = 0;
465 LIGOTimeGPS XLAL_INIT_DECL( test_epoch );
466 struct tm epoch_utc;
467
468 // First just figure out how many epochs there are
469 for ( UINT4 j = 0; j < catalog->length; j++ ) {
470 if ( j == 0 ) {
471 XLAL_CHECK_NULL( set_sft_avg_epoch( &epoch_utc, &epoch, catalog->data[j].header.epoch, persistAvgOpt, persistAvgOptWasSet ) == XLAL_SUCCESS, XLAL_EFUNC );
472 epoch_index++;
473 } else {
474 XLAL_CHECK_NULL( set_sft_avg_epoch( &epoch_utc, &test_epoch, catalog->data[j].header.epoch, persistAvgOpt, persistAvgOptWasSet ) == XLAL_SUCCESS, XLAL_EFUNC );
475 if ( ( persistAvgOptWasSet && XLALGPSDiff( &test_epoch, &epoch ) != 0 ) || ( !persistAvgOptWasSet && XLALGPSDiff( &test_epoch, &epoch ) >= persistAvgSeconds ) ) {
476 epoch = test_epoch;
477 epoch_index++;
478 }
479 }
480 }
481
482 // Now allocate a timestamp vector
483 LIGOTimeGPSVector *epoch_gps_times = NULL;
484 XLAL_CHECK_NULL( ( epoch_gps_times = XLALCreateTimestampVector( epoch_index ) ) != NULL, XLAL_EFUNC );
485 epoch_index = 0;
486
487 // Now assign the GPS times
488 for ( UINT4 j = 0; j < catalog->length; j++ ) {
489 if ( j == 0 ) {
490 XLAL_CHECK_NULL( set_sft_avg_epoch( &epoch_utc, &epoch_gps_times->data[epoch_index], catalog->data[j].header.epoch, persistAvgOpt, persistAvgOptWasSet ) == XLAL_SUCCESS, XLAL_EFUNC );
491 epoch_index++;
492 } else {
493 XLAL_CHECK_NULL( set_sft_avg_epoch( &epoch_utc, &test_epoch, catalog->data[j].header.epoch, persistAvgOpt, persistAvgOptWasSet ) == XLAL_SUCCESS, XLAL_EFUNC );
494 if ( ( persistAvgOptWasSet && XLALGPSDiff( &test_epoch, &epoch_gps_times->data[epoch_index - 1] ) != 0 ) || ( !persistAvgOptWasSet && XLALGPSDiff( &test_epoch, &epoch_gps_times->data[epoch_index - 1] ) >= persistAvgSeconds ) ) {
495 XLAL_CHECK_NULL( set_sft_avg_epoch( &epoch_utc, &epoch_gps_times->data[epoch_index], catalog->data[j].header.epoch, persistAvgOpt, persistAvgOptWasSet ) == XLAL_SUCCESS, XLAL_EFUNC );
496 epoch_index++;
497 }
498 }
499 }
500
501 return epoch_gps_times;
502}
503
504/* Set the GPS time of each epoch, depending on if the --persistAvgOpt was set.
505 If it was set (meaning persistAvgOptWasSet is true and persistAvgOpt=[1,3]),
506 then the utc and epoch_start values are determined based on the GPS time of
507 first SFT epoch.
508 persistAvgOpt = 1: utc and epoch_start are set to the most recent UTC midnight
509 persistAvgOpt = 2: utc and epoch_start are set to the most recent UTC midnight Sunday
510 persistAvgOpt = 3: utc and epoch_start are set to the most recent UTC midnight first day of the month
511 otherwise, set utc and epoch_start to the first_sft_epoch */
512int set_sft_avg_epoch( struct tm *utc, LIGOTimeGPS *epoch_start, const LIGOTimeGPS first_sft_epoch, const INT4 persistAvgOpt, const BOOLEAN persistAvgOptWasSet )
513{
514 //Figure out the UTC time of the SFT epoch
515 XLAL_CHECK( ( XLALGPSToUTC( utc, first_sft_epoch.gpsSeconds ) ) != NULL, XLAL_EFUNC );
516
517 // If using the persistAvgOpt method 1, 2, or 3
518 if ( persistAvgOptWasSet && persistAvgOpt == 1 ) {
519 utc->tm_sec = utc->tm_min = utc->tm_hour = 0;
520 epoch_start->gpsSeconds = XLALUTCToGPS( utc );
521 } else if ( persistAvgOptWasSet && persistAvgOpt == 2 ) {
522 utc->tm_sec = utc->tm_min = utc->tm_hour = 0;
523 epoch_start->gpsSeconds = XLALUTCToGPS( utc ) - ( utc->tm_wday * 24 * 3600 );
524 } else if ( persistAvgOptWasSet && persistAvgOpt == 3 ) {
525 utc->tm_sec = utc->tm_min = utc->tm_hour = 0;
526 utc->tm_mday = 1;
527 XLAL_CHECK( ( XLALFillUTC( utc ) ) != NULL, XLAL_EFUNC );
528 epoch_start->gpsSeconds = XLALUTCToGPS( utc );
529 } else {
530 //Otherwise, the epoch is just the GPS time
531 epoch_start->gpsSeconds = first_sft_epoch.gpsSeconds;
532 }
533
534 //We again set the UTC time from the GPS to make sure that the UTC and epoch time return are synchronized
535 XLAL_CHECK( ( XLALGPSToUTC( utc, epoch_start->gpsSeconds ) ) != NULL, XLAL_EFUNC );
536
537 return XLAL_SUCCESS;
538}
539
540/* Validate that the line frequency given is within the range of f_min to f_max.
541 If there are any lines outside the range specified, the function will remove those lines from
542 the list by making a new vector with the valid lines in range, destroying the old list, and
543 returning a pointer to the new list */
544int validate_line_freq( LALStringVector **line_freq, const REAL8 f0, const REAL8 deltaF, const UINT4 numBins )
545{
546 UINT4Vector *valid = NULL;
547 XLAL_CHECK( ( valid = XLALCreateUINT4Vector( ( *line_freq )->length ) ) != NULL, XLAL_EFUNC );
548 UINT4 removeLength = 0;
549 for ( UINT4 i = 0; i < ( *line_freq )->length; i++ ) {
550 REAL8 freq = atof( ( *line_freq )->data[i] );
551 INT4 bin = ( INT4 )round( ( freq - f0 ) / deltaF );
552 if ( bin >= 0 && bin < ( INT4 )numBins ) {
553 valid->data[i] = 1;
554 } else {
555 valid->data[i] = 0;
556 removeLength++;
557 }
558 }
559 if ( removeLength > 0 ) {
560 LALStringVector *new_line_freq = NULL;
561 for ( UINT4 i = 0; i < valid->length; i++ ) {
562 if ( valid->data[i] == 1 ) {
563 XLAL_CHECK( ( new_line_freq = XLALAppendString2Vector( new_line_freq, ( *line_freq )->data[i] ) ) != NULL, XLAL_EFUNC );
564 } else {
565 fprintf( stderr, "NOTE: requested frequency to monitor %s Hz is outside of requested band and will not be included in output\n", ( *line_freq )->data[i] );
566 }
567 }
568 XLALDestroyStringVector( *line_freq );
569 *line_freq = new_line_freq;
570 }
571
572 XLALDestroyUINT4Vector( valid );
573
574 return XLAL_SUCCESS;
575}
576
578{
579 REAL8Vector *freq_vect = NULL;
580 XLAL_CHECK_NULL( ( freq_vect = XLALCreateREAL8Vector( line_freq->length ) ) != NULL, XLAL_EFUNC );
581 for ( UINT4 i = 0; i < line_freq->length; i++ ) {
582 freq_vect->data[i] = atof( line_freq->data[i] );
583 }
584 return freq_vect;
585}
586
587/* Compute the running mean of a REAL8Vector */
588int rngmean( const REAL8Vector *input, const REAL8Vector *output, const INT4 blocksRngMean )
589{
590 REAL8Vector *win = NULL;
591 XLAL_CHECK( ( win = XLALCreateREAL8Vector( blocksRngMean ) ) != NULL, XLAL_EFUNC );
592 memcpy( win->data, input->data, sizeof( REAL8 )*blocksRngMean );
593 output->data[0] = 0.0;
594 for ( UINT4 i = 0; i < win->length; i++ ) {
595 output->data[0] += win->data[i];
596 }
597 output->data[0] /= ( REAL8 )blocksRngMean;
598 for ( UINT4 i = 1; i < output->length; i++ ) {
599 output->data[i] = output->data[i - 1] - win->data[0] / ( REAL8 )blocksRngMean;
600 memmove( win->data, &win->data[1], sizeof( REAL8 ) * ( blocksRngMean - 1 ) );
601 win->data[win->length - 1] = input->data[i + ( blocksRngMean - 1 )];
602 output->data[i] += win->data[win->length - 1] / ( REAL8 )blocksRngMean;
603 }
605 return XLAL_SUCCESS;
606}
607
608/* Compute the running standard deviation of a REAL8Vector using a vector of
609 pre-computed mean values (use rngmean() above) */
610int rngstd( const REAL8Vector *input, const REAL8Vector *means, const REAL8Vector *output, const INT4 blocksRngMean )
611{
612 REAL8Vector *win = NULL;
613 XLAL_CHECK( ( win = XLALCreateREAL8Vector( blocksRngMean ) ) != NULL, XLAL_EFUNC );
614 for ( UINT4 i = 0; i < output->length; i++ ) {
615 memcpy( win->data, &input->data[i], sizeof( REAL8 )*blocksRngMean );
616 output->data[i] = 0.0;
617 for ( UINT4 j = 0; j < win->length; j++ ) {
618 output->data[i] += ( win->data[j] - means->data[i] ) * ( win->data[j] - means->data[i] );
619 }
620 }
621 for ( UINT4 i = 0; i < output->length; i++ ) {
622 output->data[i] = sqrt( output->data[i] / ( REAL8 )( blocksRngMean - 1 ) );
623 }
625 return XLAL_SUCCESS;
626}
627
628/* Select the specific mean and standard deviation from the running means and standard deviations.
629 Need to know the size of a "side" of the block size, so that is passed as well as the index. */
630int select_mean_std_from_vect( REAL8 *mean, REAL8 *std, const REAL8Vector *means, const REAL8Vector *stds, const UINT4 idx, const UINT4 nside )
631{
632 // At the end points, we need to re-use the 0-th or end values
633 // This is slightly sub-optimal but is simple
634 if ( idx < nside ) {
635 *mean = means->data[0];
636 *std = stds->data[0];
637 } else if ( idx >= means->length ) {
638 *mean = means->data[means->length - 1];
639 *std = stds->data[stds->length - 1];
640 } else {
641 *mean = means->data[idx - nside];
642 *std = stds->data[idx - nside];
643 }
644
645 return XLAL_SUCCESS;
646}
#define IFO
int j
const LALVCSInfoList lalPulsarVCSInfoList
NULL-terminated list of VCS and build information for LALPulsar and its dependencies
#define STRING(a)
#define fprintf
SFTVector * extract_one_sft(const SFTCatalog *full_catalog, const LIGOTimeGPS starttime, const REAL8 f_min, const REAL8 f_max)
Definition: fscanutils.c:31
REAL8VectorSequence * XLALCreateREAL8VectorSequence(UINT4 length, UINT4 veclen)
void XLALDestroyREAL8VectorSequence(REAL8VectorSequence *vecseq)
#define LAL_REAL8_EPS
unsigned char BOOLEAN
double REAL8
#define XLAL_INIT_DECL(var,...)
char CHAR
uint32_t UINT4
int32_t INT4
float REAL4
char char * XLALStringDuplicate(const char *s)
void LogPrintf(LogLevel_t, const char *format,...) _LAL_GCC_PRINTF_FORMAT_(2
LOG_CRITICAL
LOG_NORMAL
void XLALDestroySFTVector(SFTVector *vect)
XLAL interface to destroy an SFTVector.
Definition: SFTtypes.c:300
void XLALDestroySFTCatalog(SFTCatalog *catalog)
Free an 'SFT-catalogue'.
Definition: SFTcatalog.c:329
LIGOTimeGPSVector * XLALCreateTimestampVector(UINT4 len)
Allocate a LIGOTimeGPSVector.
Definition: SFTtimestamps.c:47
SFTCatalog * XLALSFTdataFind(const CHAR *file_pattern, const SFTConstraints *constraints)
Find the list of SFTs matching the file_pattern and satisfying the given constraints,...
Definition: SFTcatalog.c:71
void XLALDestroyTimestampVector(LIGOTimeGPSVector *vect)
De-allocate a LIGOTimeGPSVector.
Definition: SFTtimestamps.c:69
void XLALDestroyStringVector(LALStringVector *vect)
LALStringVector * XLALAppendString2Vector(LALStringVector *vect, const CHAR *string)
const char * lalUserVarHelpBrief
int XLALUserVarReadAllInput(BOOLEAN *should_exit, int argc, char *argv[], const LALVCSInfoList vcs_list)
void XLALDestroyUserVars(void)
const char * lalUserVarHelpDescription
#define XLALRegisterNamedUvar(cvar, name, type, option, category,...)
int XLALUserVarWasSet(const void *cvar)
REAL8Vector * XLALResizeREAL8Vector(REAL8Vector *vector, UINT4 length)
void XLALDestroyUINT4Vector(UINT4Vector *vector)
INT4Vector * XLALCreateINT4Vector(UINT4 length)
void XLALDestroyINT4Vector(INT4Vector *vector)
REAL8Vector * XLALCreateREAL8Vector(UINT4 length)
void XLALDestroyREAL8Vector(REAL8Vector *vector)
UINT4Vector * XLALCreateUINT4Vector(UINT4 length)
INT4 XLALUTCToGPS(const struct tm *utc)
struct tm * XLALFillUTC(struct tm *utc)
struct tm * XLALGPSToUTC(struct tm *utc, INT4 gpssec)
#define XLAL_CHECK(assertion,...)
#define XLAL_CHECK_MAIN(assertion,...)
#define XLAL_ERROR_MAIN(...)
#define XLAL_TRY(statement, errnum)
#define XLAL_CHECK_NULL(assertion,...)
XLAL_ENOMEM
XLAL_SUCCESS
XLAL_EUSR0
XLAL_EFUNC
XLAL_EIO
XLAL_EINVAL
XLAL_EFAILED
int XLALGPSCmp(const LIGOTimeGPS *t0, const LIGOTimeGPS *t1)
REAL8 XLALGPSDiff(const LIGOTimeGPS *t1, const LIGOTimeGPS *t0)
long long count
Definition: hwinject.c:371
n
int deltaF
REAL8Vector * line_freq_str2dbl(const LALStringVector *line_freq)
int set_sft_avg_epoch(struct tm *utc, LIGOTimeGPS *epoch_start, const LIGOTimeGPS first_sft_epoch, const INT4 persistAvgOpt, const BOOLEAN persistAvgOptWasSet)
int main(int argc, char **argv)
Definition: spec_avg_long.c:56
int rngstd(const REAL8Vector *input, const REAL8Vector *means, const REAL8Vector *output, const INT4 blocksRngMean)
int validate_line_freq(LALStringVector **line_freq, const REAL8 f0, const REAL8 deltaF, const UINT4 numBins)
#define POWER(x)
Definition: spec_avg_long.c:41
int rngmean(const REAL8Vector *input, const REAL8Vector *output, const INT4 blocksRngMean)
LIGOTimeGPSVector * setup_epochs(const SFTCatalog *catalog, const INT4 persistAvgOpt, const BOOLEAN persistAvgOptWasSet, const INT4 persistAvgSeconds)
int select_mean_std_from_vect(REAL8 *mean, REAL8 *std, const REAL8Vector *means, const REAL8Vector *stds, const UINT4 idx, const UINT4 nside)
COMPLEX8Sequence * data
A vector of COMPLEX8FrequencySeries.
COMPLEX8FrequencySeries * data
Pointer to the data array.
UINT4 length
Number of elements in array.
COMPLEX8 * data
INT4 * data
UINT4 length
INT4 gpsNanoSeconds
A vector of 'timestamps' of type LIGOTimeGPS.
Definition: SFTfileIO.h:188
LIGOTimeGPS * data
array of timestamps
Definition: SFTfileIO.h:193
UINT4 length
number of timestamps
Definition: SFTfileIO.h:192
REAL8 * data
An "SFT-catalogue": a vector of SFTdescriptors, as returned by XLALSFTdataFind()
Definition: SFTfileIO.h:238
SFTDescriptor * data
array of data-entries describing matched SFTs
Definition: SFTfileIO.h:243
UINT4 length
number of SFTs in catalog
Definition: SFTfileIO.h:242
'Constraints' for SFT-matching: which detector, within which time-stretch and which timestamps exactl...
Definition: SFTfileIO.h:212
SFTtype header
SFT-header info.
Definition: SFTfileIO.h:228
UINT4 * data
enum @1 epoch
double f_min
double f_max