LALPulsar 7.1.2.1-bf6a62b
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 SFTtype *sft = NULL;
187 XLAL_CHECK_MAIN( ( sft = extract_one_sft( catalog, catalog->data[j].header.epoch, f_min, f_max ) ) != NULL, XLAL_EFUNC );
188
189 //Make sure the SFTs are the same length as what we're expecting from user input
190 XLAL_CHECK_MAIN( fabs( timebaseline * sft->deltaF - 1.0 ) <= 10.*LAL_REAL8_EPS, XLAL_EINVAL, "Expected SFTs with length %f but got %f", timebaseline, 1 / sft->deltaF );
191
192 //For the first time through the loop, we allocate some vectors
193 if ( j == 0 ) {
194 UINT4 numBins = sft->data->length;
195 f0 = sft->f0;
196 deltaF = sft->deltaF;
197 printf( "numBins=%d, f0=%f, deltaF=%f\n", numBins, f0, deltaF );
198
199 if ( line_freq != NULL ) {
201 XLAL_CHECK_MAIN( ( freq_vect = line_freq_str2dbl( line_freq ) ) != NULL, XLAL_EFUNC );
202 }
203
204 XLAL_CHECK_MAIN( ( timeavg = XLALCreateREAL8Vector( numBins ) ) != NULL, XLAL_EFUNC );
205 XLAL_CHECK_MAIN( ( timeavgwt = XLALCreateREAL8Vector( numBins ) ) != NULL, XLAL_EFUNC );
206 XLAL_CHECK_MAIN( ( sumweight = XLALCreateREAL8Vector( numBins ) ) != NULL, XLAL_EFUNC );
207 XLAL_CHECK_MAIN( ( persistency = XLALCreateREAL8Vector( numBins ) ) != NULL, XLAL_EFUNC );
208 memset( persistency->data, 0, sizeof( REAL8 )*persistency->length );
209
210 // Allocate vectors for this epoch average and weights as well as if we need to make a new epoch
211 XLAL_CHECK_MAIN( ( this_epoch_avg = XLALCreateREAL8Vector( numBins ) ) != NULL, XLAL_EFUNC );
212 XLAL_CHECK_MAIN( ( this_epoch_avg_wt = XLALCreateREAL8Vector( numBins ) ) != NULL, XLAL_EFUNC );
213 XLAL_CHECK_MAIN( ( new_epoch_avg = XLALCreateREAL8Vector( numBins ) ) != NULL, XLAL_EFUNC );
214 memset( new_epoch_avg->data, 0, sizeof( REAL8 )*new_epoch_avg->length );
215 XLAL_CHECK_MAIN( ( new_epoch_wt = XLALCreateREAL8Vector( numBins ) ) != NULL, XLAL_EFUNC );
216 XLAL_CHECK_MAIN( ( epoch_avg = XLALCreateREAL8VectorSequence( epoch_gps_times->length, numBins ) ) != NULL, XLAL_EFUNC );
217
218 // Check that epoch_avg has been fully allocated. This can be problematic over many SFTs
219 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" );
220 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" );
221 }
222
223 //Loop over the SFT bins
224 for ( UINT4 i = 0; i < sft->data->length; i++ ) {
225 REAL8 thispower = POWER( sft->data->data[i] );
226 REAL8 thisavepower = 0.;
227 UINT4 count = 0;
228 for ( INT4 ii = -nside; ii <= nside; ii++ ) {
229 //Only add to the cumulative average power if the variables are in range
230 if ( ( INT4 )i + ii >= 0 && ( INT4 )i + ii < ( INT4 )sft->data->length ) {
231 thisavepower += POWER( sft->data->data[i + ii] );
232 count++;
233 }
234 }
235 thisavepower /= count;
236 REAL8 weight = 1. / thisavepower;
237
238 //For the first SFT, just assign the values to the vector, otherwise accumulate
239 if ( j == 0 ) {
240 timeavg->data[i] = thispower;
241 timeavgwt->data[i] = thispower * weight;
242 sumweight->data[i] = weight;
243
244 this_epoch_avg->data[i] = thispower * weight;
245 this_epoch_avg_wt->data[i] = weight;
246 } else {
247 timeavg->data[i] += thispower;
248 timeavgwt->data[i] += thispower * weight;
249 sumweight->data[i] += weight;
250
251 // Only accumulate in the epoch average if this SFT is within the current epoch
252 // Otherwise put the values in the new epoch average and weight vector.
253 if ( ( epoch_index < ( epoch_gps_times->length - 1 ) && XLALGPSCmp( &sft->epoch, &epoch_gps_times->data[epoch_index] ) >= 0 && XLALGPSCmp( &sft->epoch, &epoch_gps_times->data[epoch_index + 1] ) < 0 ) || epoch_index == ( epoch_gps_times->length - 1 ) ) {
254 this_epoch_avg->data[i] += thispower * weight;
255 this_epoch_avg_wt->data[i] += weight;
256 } else {
257 new_epoch_avg->data[i] = thispower * weight;
258 new_epoch_wt->data[i] = weight;
259 }
260 }
261 } // end loop over this SFT frequency bins
262
263 // If we've started putting new values into the new epoch average, then we should conclude the
264 // last epoch and load the values from the new epoch into the current epoch
265 if ( new_epoch_avg->data[0] != 0.0 ) {
266 // Compute noise weighted power in this epoch average
267 for ( UINT4 i = 0; i < this_epoch_avg->length; i++ ) {
268 this_epoch_avg->data[i] *= 2.0 / this_epoch_avg_wt->data[i] / timebaseline;
269 }
270
271 // Copy to the vector sequence of epoch averages
272 memcpy( &( epoch_avg->data[epoch_index * this_epoch_avg->length] ), this_epoch_avg->data, sizeof( REAL8 )*this_epoch_avg->length );
273 epoch_index++;
274
275 // Copy over the new epoch data into this epoch's average
276 memcpy( this_epoch_avg->data, new_epoch_avg->data, sizeof( REAL8 )*new_epoch_avg->length );
277 memcpy( this_epoch_avg_wt->data, new_epoch_wt->data, sizeof( REAL8 )*new_epoch_wt->length );
278
279 // Set the new epoch data to be zero again
280 memset( new_epoch_avg->data, 0, sizeof( REAL8 )*new_epoch_avg->length );
281 }
282 // This just repeats the above if we are in the very last SFT
283 if ( j == catalog->length - 1 ) {
284 for ( UINT4 i = 0; i < this_epoch_avg->length; i++ ) {
285 this_epoch_avg->data[i] = 2.*this_epoch_avg->data[i] / this_epoch_avg_wt->data[i] / timebaseline;
286 }
287
288 memcpy( &( epoch_avg->data[epoch_index * this_epoch_avg->length] ), this_epoch_avg->data, sizeof( REAL8 )*this_epoch_avg->length );
289 }
290
291 // Destroys current SFT Vector
292 XLALDestroySFT( sft );
293 sft = NULL;
294 } // end loop over all SFTs
295
296 XLALDestroyREAL8Vector( this_epoch_avg_wt );
297 XLALDestroyREAL8Vector( new_epoch_avg );
298 XLALDestroyREAL8Vector( new_epoch_wt );
299
300 // Allocate vectors for running mean and standard deviation of each chunk
301 REAL8Vector *means = NULL, *stds = NULL;
302 XLAL_CHECK_MAIN( ( means = XLALCreateREAL8Vector( epoch_avg->vectorLength - 2 * nside ) ) != NULL, XLAL_EFUNC );
303 XLAL_CHECK_MAIN( ( stds = XLALCreateREAL8Vector( epoch_avg->vectorLength - 2 * nside ) ) != NULL, XLAL_EFUNC );
304
305 //Loop over epochs for persistency calculation
306 for ( UINT4 j = 0; j < epoch_gps_times->length; j++ ) {
307 // Use the mean and standard deviation of data for this epoch
308 memcpy( this_epoch_avg->data, &( epoch_avg->data[j * epoch_avg->vectorLength] ), sizeof( REAL8 )*epoch_avg->vectorLength );
309 XLAL_CHECK_MAIN( rngmean( this_epoch_avg, means, blocksRngMean ) == XLAL_SUCCESS, XLAL_EFUNC );
310 XLAL_CHECK_MAIN( rngstd( this_epoch_avg, means, stds, blocksRngMean ) == XLAL_SUCCESS, XLAL_EFUNC );
311
312 // At the end points of the running mean, we need to re-use the end values
313 // This is slightly sub-optimal
314 for ( UINT4 i = 0; i < epoch_avg->vectorLength; i++ ) {
315 REAL8 mean, std;
316 XLAL_CHECK_MAIN( select_mean_std_from_vect( &mean, &std, means, stds, i, ( UINT4 )nside ) == XLAL_SUCCESS, XLAL_EFUNC );
317 // Compare this SFT frequency data point with the running mean and standard deviation
318 if ( ( epoch_avg->data[j * epoch_avg->vectorLength + i] - mean ) / std > persistSNRthresh ) {
319 persistency->data[i] += 1.0;
320 }
321 } // end loop over frequencies
322 } // end loop over epochs
323
324 // Normalize persistency to be in range 0 - 1 based on the number of epochs
325 for ( UINT4 i = 0; i < persistency->length; i++ ) {
326 persistency->data[i] /= ( REAL8 )epoch_gps_times->length;
327
328 // if auto tracking, append any frequencies to the list
329 if ( XLALUserVarWasSet( &auto_track ) && ( persistency->data[i] >= auto_track ) ) {
330 if ( freq_vect != NULL ) {
331 XLAL_CHECK_MAIN( ( freq_vect = XLALResizeREAL8Vector( freq_vect, freq_vect->length + 1 ) ) != NULL, XLAL_EFUNC );
332 } else {
333 XLAL_CHECK_MAIN( ( freq_vect = XLALCreateREAL8Vector( 1 ) ) != NULL, XLAL_EFUNC );
334 }
335 freq_vect->data[freq_vect->length - 1] = f0 + deltaF * i;
336 }
337 } // end loop over frequency bins
338
339 // allocate arrays for monitoring specific line frequencies
340 REAL8VectorSequence *line_excess_in_epochs = NULL;
341 if ( freq_vect != NULL ) {
342 INT4Vector *line_freq_bin_in_sft = NULL;
343 XLAL_CHECK_MAIN( ( line_freq_bin_in_sft = XLALCreateINT4Vector( freq_vect->length ) ) != NULL, XLAL_EFUNC );
344 XLAL_CHECK_MAIN( ( line_excess_in_epochs = XLALCreateREAL8VectorSequence( freq_vect->length, epoch_gps_times->length ) ) != NULL, XLAL_EFUNC );
345 memset( line_excess_in_epochs->data, 0, sizeof( REAL8 )*line_excess_in_epochs->length * line_excess_in_epochs->vectorLength );
346
347 // Set line_freq_array as the REAL8 values of the line_freq string vector
348 // Set line_freq_bin_in_sft as the nearest INT4 values of the line frequencies to track
349 for ( UINT4 n = 0; n < freq_vect->length; n++ ) {
350 line_freq_bin_in_sft->data[n] = ( INT4 )round( ( freq_vect->data[n] - f0 ) / deltaF );
351 }
352
353 // Loop over chunks checking if the line frequencies to track are above threshold in each chunk
354 for ( UINT4 j = 0; j < epoch_gps_times->length; j++ ) {
355 // Use the standard deviation of data for this epoch
356 memcpy( this_epoch_avg->data, &( epoch_avg->data[j * epoch_avg->vectorLength] ), sizeof( REAL8 )*epoch_avg->vectorLength );
357 XLAL_CHECK_MAIN( rngmean( this_epoch_avg, means, blocksRngMean ) == XLAL_SUCCESS, XLAL_EFUNC );
358 XLAL_CHECK_MAIN( rngstd( this_epoch_avg, means, stds, blocksRngMean ) == XLAL_SUCCESS, XLAL_EFUNC );
359
360 // Check each line frequency
361 for ( UINT4 i = 0; i < line_freq_bin_in_sft->length; i++ ) {
362 REAL8 mean, std;
363 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 );
364
365 // assign the value of the number of standard devaiations above the mean for this chunk
366 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;
367 } // end loop over lines to track
368 } // end loop over chunks of SFT averages
369
370 XLALDestroyINT4Vector( line_freq_bin_in_sft );
371 } // end if line tracking
372
373 XLALDestroyREAL8Vector( means );
375 XLALDestroyREAL8Vector( this_epoch_avg );
377
378 /* Print to files */
379 SPECOUT = fopen( outfile0, "w" );
380 fopenerr = errno;
381 XLAL_CHECK_MAIN( SPECOUT != NULL, XLAL_EIO, "Failed to open '%s' for writing: %s", outfile0, strerror( fopenerr ) );
382 WTOUT = fopen( outfile1, "w" );
383 fopenerr = errno;
384 XLAL_CHECK_MAIN( WTOUT != NULL, XLAL_EIO, "Failed to open '%s' for writing: %s", outfile1, strerror( fopenerr ) );
385 // Write header line to files, if provided
386 if ( XLALUserVarWasSet( &header ) ) {
387 fprintf( SPECOUT, "# %s\n", header );
388 fprintf( WTOUT, "# %s\n", header );
389 }
390 for ( UINT4 i = 0; i < timeavg->length; i++ ) {
391 REAL8 f = f0 + ( ( REAL4 )i ) * deltaF;
392 REAL8 PSD = 2.*timeavg->data[i] / ( ( REAL4 )catalog->length ) / timebaseline;
393 REAL8 PSDWT = 2.*timeavgwt->data[i] / sumweight->data[i] / timebaseline;
394 REAL8 AMPPSD = pow( PSD, 0.5 );
395 REAL8 AMPPSDWT = pow( PSDWT, 0.5 );
396 REAL8 persist = persistency->data[i];
397 fprintf( SPECOUT, "%16.8f %g %g %g %g %g\n", f, PSD, AMPPSD, PSDWT, AMPPSDWT, persist );
398
399 REAL8 PWA_TAVGWT = timeavgwt->data[i];
400 REAL8 PWA_SUMWT = sumweight->data[i];
401 fprintf( WTOUT, "%16.8f %g %g\n", f, PWA_TAVGWT, PWA_SUMWT );
402 }
403 fclose( SPECOUT );
404 fclose( WTOUT );
405
406 // If user specified a list of line frequencies to monitor then print those data to a file
407 if ( freq_vect != NULL ) {
408 // open the line tracking output file for writing
409 LINEOUT = fopen( outfile2, "w" );
410 fopenerr = errno;
411 XLAL_CHECK_MAIN( LINEOUT != NULL, XLAL_EIO, "Failed to open '%s' for writing: %s", outfile2, strerror( fopenerr ) );
412 if ( XLALUserVarWasSet( &header ) ) {
413 fprintf( LINEOUT, "# %s\n", header );
414 }
415 if ( !XLALUserVarWasSet( &persistAvgOpt ) ) {
416 fprintf( LINEOUT, "# GPS Epoch (len = %d s)", persistAvgSeconds );
417 } else {
418 fprintf( LINEOUT, "# GPS Epoch (option = %d)", persistAvgOpt );
419 }
420 for ( UINT4 n = 0; n < freq_vect->length; n++ ) {
421 fprintf( LINEOUT, ",%16.8f Hz", freq_vect->data[n] );
422 }
423 fprintf( LINEOUT, "\n" );
424 for ( UINT4 i = 0; i < epoch_gps_times->length; i++ ) {
425 fprintf( LINEOUT, "%d", epoch_gps_times->data[i].gpsSeconds );
426 for ( UINT4 n = 0; n < freq_vect->length; n++ ) {
427 fprintf( LINEOUT, ",%.4f", line_excess_in_epochs->data[n * line_excess_in_epochs->vectorLength + i] );
428 }
429 fprintf( LINEOUT, "\n" );
430 }
431 fclose( LINEOUT );
432 XLALDestroyREAL8VectorSequence( line_excess_in_epochs );
433 XLALDestroyREAL8Vector( freq_vect );
434 }
435
436 /*------------------------------------------------------------------------------------------------------------------------*/
437
438 fprintf( stderr, "Destroying Variables\n" );
439
440 XLALDestroyTimestampVector( epoch_gps_times );
441 XLALDestroySFTCatalog( catalog );
442 XLALDestroyREAL8Vector( timeavg );
443 XLALDestroyREAL8Vector( timeavgwt );
444 XLALDestroyREAL8Vector( sumweight );
445 XLALDestroyREAL8Vector( persistency );
446
448 fprintf( stderr, "Done Destroying Variables\n" );
449 fprintf( stderr, "end of spec_avg_long\n" );
450
451 return ( 0 );
452
453}
454/* END main */
455
456/* Set up epochs:
457 This counts the number of epochs that would be set;
458 allocates a LIGOTimeGPSVector for the number of epochs;
459 populates the elements with the GPS times of the epochs */
460LIGOTimeGPSVector *setup_epochs( const SFTCatalog *catalog, const INT4 persistAvgOpt, const BOOLEAN persistAvgOptWasSet, const INT4 persistAvgSeconds )
461{
462 UINT4 epoch_index = 0;
464 LIGOTimeGPS XLAL_INIT_DECL( test_epoch );
465 struct tm epoch_utc;
466
467 // First just figure out how many epochs there are
468 for ( UINT4 j = 0; j < catalog->length; j++ ) {
469 if ( j == 0 ) {
470 XLAL_CHECK_NULL( set_sft_avg_epoch( &epoch_utc, &epoch, catalog->data[j].header.epoch, persistAvgOpt, persistAvgOptWasSet ) == XLAL_SUCCESS, XLAL_EFUNC );
471 epoch_index++;
472 } else {
473 XLAL_CHECK_NULL( set_sft_avg_epoch( &epoch_utc, &test_epoch, catalog->data[j].header.epoch, persistAvgOpt, persistAvgOptWasSet ) == XLAL_SUCCESS, XLAL_EFUNC );
474 if ( ( persistAvgOptWasSet && XLALGPSDiff( &test_epoch, &epoch ) != 0 ) || ( !persistAvgOptWasSet && XLALGPSDiff( &test_epoch, &epoch ) >= persistAvgSeconds ) ) {
475 epoch = test_epoch;
476 epoch_index++;
477 }
478 }
479 }
480
481 // Now allocate a timestamp vector
482 LIGOTimeGPSVector *epoch_gps_times = NULL;
483 XLAL_CHECK_NULL( ( epoch_gps_times = XLALCreateTimestampVector( epoch_index ) ) != NULL, XLAL_EFUNC );
484 epoch_index = 0;
485
486 // Now assign the GPS times
487 for ( UINT4 j = 0; j < catalog->length; j++ ) {
488 if ( j == 0 ) {
489 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 );
490 epoch_index++;
491 } else {
492 XLAL_CHECK_NULL( set_sft_avg_epoch( &epoch_utc, &test_epoch, catalog->data[j].header.epoch, persistAvgOpt, persistAvgOptWasSet ) == XLAL_SUCCESS, XLAL_EFUNC );
493 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 ) ) {
494 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 );
495 epoch_index++;
496 }
497 }
498 }
499
500 return epoch_gps_times;
501}
502
503/* Set the GPS time of each epoch, depending on if the --persistAvgOpt was set.
504 If it was set (meaning persistAvgOptWasSet is true and persistAvgOpt=[1,3]),
505 then the utc and epoch_start values are determined based on the GPS time of
506 first SFT epoch.
507 persistAvgOpt = 1: utc and epoch_start are set to the most recent UTC midnight
508 persistAvgOpt = 2: utc and epoch_start are set to the most recent UTC midnight Sunday
509 persistAvgOpt = 3: utc and epoch_start are set to the most recent UTC midnight first day of the month
510 otherwise, set utc and epoch_start to the first_sft_epoch */
511int set_sft_avg_epoch( struct tm *utc, LIGOTimeGPS *epoch_start, const LIGOTimeGPS first_sft_epoch, const INT4 persistAvgOpt, const BOOLEAN persistAvgOptWasSet )
512{
513 //Figure out the UTC time of the SFT epoch
514 XLAL_CHECK( ( XLALGPSToUTC( utc, first_sft_epoch.gpsSeconds ) ) != NULL, XLAL_EFUNC );
515
516 // If using the persistAvgOpt method 1, 2, or 3
517 if ( persistAvgOptWasSet && persistAvgOpt == 1 ) {
518 utc->tm_sec = utc->tm_min = utc->tm_hour = 0;
519 epoch_start->gpsSeconds = XLALUTCToGPS( utc );
520 } else if ( persistAvgOptWasSet && persistAvgOpt == 2 ) {
521 utc->tm_sec = utc->tm_min = utc->tm_hour = 0;
522 epoch_start->gpsSeconds = XLALUTCToGPS( utc ) - ( utc->tm_wday * 24 * 3600 );
523 } else if ( persistAvgOptWasSet && persistAvgOpt == 3 ) {
524 utc->tm_sec = utc->tm_min = utc->tm_hour = 0;
525 utc->tm_mday = 1;
526 XLAL_CHECK( ( XLALFillUTC( utc ) ) != NULL, XLAL_EFUNC );
527 epoch_start->gpsSeconds = XLALUTCToGPS( utc );
528 } else {
529 //Otherwise, the epoch is just the GPS time
530 epoch_start->gpsSeconds = first_sft_epoch.gpsSeconds;
531 }
532
533 //We again set the UTC time from the GPS to make sure that the UTC and epoch time return are synchronized
534 XLAL_CHECK( ( XLALGPSToUTC( utc, epoch_start->gpsSeconds ) ) != NULL, XLAL_EFUNC );
535
536 return XLAL_SUCCESS;
537}
538
539/* Validate that the line frequency given is within the range of f_min to f_max.
540 If there are any lines outside the range specified, the function will remove those lines from
541 the list by making a new vector with the valid lines in range, destroying the old list, and
542 returning a pointer to the new list */
543int validate_line_freq( LALStringVector **line_freq, const REAL8 f0, const REAL8 deltaF, const UINT4 numBins )
544{
545 UINT4Vector *valid = NULL;
546 XLAL_CHECK( ( valid = XLALCreateUINT4Vector( ( *line_freq )->length ) ) != NULL, XLAL_EFUNC );
547 UINT4 removeLength = 0;
548 for ( UINT4 i = 0; i < ( *line_freq )->length; i++ ) {
549 REAL8 freq = atof( ( *line_freq )->data[i] );
550 INT4 bin = ( INT4 )round( ( freq - f0 ) / deltaF );
551 if ( bin >= 0 && bin < ( INT4 )numBins ) {
552 valid->data[i] = 1;
553 } else {
554 valid->data[i] = 0;
555 removeLength++;
556 }
557 }
558 if ( removeLength > 0 ) {
559 LALStringVector *new_line_freq = NULL;
560 for ( UINT4 i = 0; i < valid->length; i++ ) {
561 if ( valid->data[i] == 1 ) {
562 XLAL_CHECK( ( new_line_freq = XLALAppendString2Vector( new_line_freq, ( *line_freq )->data[i] ) ) != NULL, XLAL_EFUNC );
563 } else {
564 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] );
565 }
566 }
567 XLALDestroyStringVector( *line_freq );
568 *line_freq = new_line_freq;
569 }
570
571 XLALDestroyUINT4Vector( valid );
572
573 return XLAL_SUCCESS;
574}
575
577{
578 REAL8Vector *freq_vect = NULL;
579 XLAL_CHECK_NULL( ( freq_vect = XLALCreateREAL8Vector( line_freq->length ) ) != NULL, XLAL_EFUNC );
580 for ( UINT4 i = 0; i < line_freq->length; i++ ) {
581 freq_vect->data[i] = atof( line_freq->data[i] );
582 }
583 return freq_vect;
584}
585
586/* Compute the running mean of a REAL8Vector */
587int rngmean( const REAL8Vector *input, const REAL8Vector *output, const INT4 blocksRngMean )
588{
589 REAL8Vector *win = NULL;
590 XLAL_CHECK( ( win = XLALCreateREAL8Vector( blocksRngMean ) ) != NULL, XLAL_EFUNC );
591 memcpy( win->data, input->data, sizeof( REAL8 )*blocksRngMean );
592 output->data[0] = 0.0;
593 for ( UINT4 i = 0; i < win->length; i++ ) {
594 output->data[0] += win->data[i];
595 }
596 output->data[0] /= ( REAL8 )blocksRngMean;
597 for ( UINT4 i = 1; i < output->length; i++ ) {
598 output->data[i] = output->data[i - 1] - win->data[0] / ( REAL8 )blocksRngMean;
599 memmove( win->data, &win->data[1], sizeof( REAL8 ) * ( blocksRngMean - 1 ) );
600 win->data[win->length - 1] = input->data[i + ( blocksRngMean - 1 )];
601 output->data[i] += win->data[win->length - 1] / ( REAL8 )blocksRngMean;
602 }
604 return XLAL_SUCCESS;
605}
606
607/* Compute the running standard deviation of a REAL8Vector using a vector of
608 pre-computed mean values (use rngmean() above) */
609int rngstd( const REAL8Vector *input, const REAL8Vector *means, const REAL8Vector *output, const INT4 blocksRngMean )
610{
611 REAL8Vector *win = NULL;
612 XLAL_CHECK( ( win = XLALCreateREAL8Vector( blocksRngMean ) ) != NULL, XLAL_EFUNC );
613 for ( UINT4 i = 0; i < output->length; i++ ) {
614 memcpy( win->data, &input->data[i], sizeof( REAL8 )*blocksRngMean );
615 output->data[i] = 0.0;
616 for ( UINT4 j = 0; j < win->length; j++ ) {
617 output->data[i] += ( win->data[j] - means->data[i] ) * ( win->data[j] - means->data[i] );
618 }
619 }
620 for ( UINT4 i = 0; i < output->length; i++ ) {
621 output->data[i] = sqrt( output->data[i] / ( REAL8 )( blocksRngMean - 1 ) );
622 }
624 return XLAL_SUCCESS;
625}
626
627/* Select the specific mean and standard deviation from the running means and standard deviations.
628 Need to know the size of a "side" of the block size, so that is passed as well as the index. */
629int select_mean_std_from_vect( REAL8 *mean, REAL8 *std, const REAL8Vector *means, const REAL8Vector *stds, const UINT4 idx, const UINT4 nside )
630{
631 // At the end points, we need to re-use the 0-th or end values
632 // This is slightly sub-optimal but is simple
633 if ( idx < nside ) {
634 *mean = means->data[0];
635 *std = stds->data[0];
636 } else if ( idx >= means->length ) {
637 *mean = means->data[means->length - 1];
638 *std = stds->data[stds->length - 1];
639 } else {
640 *mean = means->data[idx - nside];
641 *std = stds->data[idx - nside];
642 }
643
644 return XLAL_SUCCESS;
645}
#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
SFTtype * 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 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 XLALDestroySFT(SFTtype *sft)
Destructor for one SFT.
Definition: SFTtypes.c:176
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
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