1 |
/* |
2 |
this module creates power spectra out of slices of timeseries |
3 |
based on jtsfiddle, but no detrending or gapfilling |
4 |
*/ |
5 |
|
6 |
/* |
7 |
* Detrending/gapfilling/differencing module |
8 |
* ts_fiddle_rml upgrades ts_fiddle |
9 |
*/ |
10 |
|
11 |
#include <stdio.h> |
12 |
#include <stdlib.h> |
13 |
#include <strings.h> |
14 |
#include <time.h> |
15 |
#include <sys/time.h> |
16 |
#include <sys/resource.h> |
17 |
#include <math.h> |
18 |
#include <assert.h> |
19 |
#include <fftw3.h> |
20 |
|
21 |
#include "jsoc_main.h" |
22 |
#include "fitsio.h" |
23 |
|
24 |
#define ARRLENGTH(ARR) (sizeof(ARR)/sizeof(ARR[0])) |
25 |
#define kNOTSPECIFIED "not specified" |
26 |
|
27 |
char *module_name = "jtsslice"; |
28 |
char *cvsinfo_jtsslice = "cvsinfo: $Header: /home/cvsuser/cvsroot/JSOC/proj/globalhs/apps/jtsslice.c,v 1.11 2012/09/24 20:06:23 tplarson Exp $"; |
29 |
|
30 |
/* Command line arguments: */ |
31 |
ModuleArgs_t module_args[] = |
32 |
{ |
33 |
{ARG_STRING, "in", "", "input data records"}, |
34 |
{ARG_STRING, "out", "", "output data series"}, |
35 |
{ARG_STRING, "segin" , kNOTSPECIFIED, "name of input segment if not using segment 0"}, |
36 |
{ARG_STRING, "segout", kNOTSPECIFIED, "name of output segment if not using segment 0"}, |
37 |
{ARG_STRING, "histlink", "HISTORY", "name of link to ancillary dataseries for processing metadata"}, |
38 |
{ARG_STRING, "srclink", "SRCDATA", "name of link to source data"}, |
39 |
{ARG_INT, "PERM", "1", "set to 0 for transient records, nonzero for permanent records"}, |
40 |
{ARG_INT, "VERB", "1", "option for level of verbosity: 0=only error and warning messages; >0=print messages outside of loop; >1=print messages inside loop; >2=debugging output", NULL}, |
41 |
{ARG_STRING, "GAPFILE", "", "record or file containing window function"}, |
42 |
|
43 |
{ARG_INT, "NDT", "-1", "", ""}, |
44 |
{ARG_STRING, "TTOTAL", NULL, "total length of time in output"}, |
45 |
|
46 |
{ARG_INT, "IFIRST", "0", "", ""}, |
47 |
// {ARG_INT, "FLIPM", "0", "", ""}, |
48 |
|
49 |
{ARG_INT, "TSOUT", "0", "", ""}, |
50 |
{ARG_INT, "FFTOUT", "0", "", ""}, |
51 |
{ARG_INT, "FFT1OUT", "0", "", ""}, |
52 |
{ARG_INT, "POWOUT", "0", "", ""}, |
53 |
{ARG_INT, "MAVGOUT", "0", "", ""}, |
54 |
{ARG_INT, "NAVG", "0", "", ""}, |
55 |
{ARG_INT, "NSKIP", "0", "", ""}, |
56 |
{ARG_INT, "NOFF", "0", "", ""}, |
57 |
{ARG_INT, "IMIN", "0", "", ""}, |
58 |
{ARG_INT, "IMAX", "-1", "", ""}, |
59 |
{ARG_END}, |
60 |
}; |
61 |
|
62 |
#include "saveparm.c" |
63 |
#include "timing.c" |
64 |
#include "set_history.c" |
65 |
|
66 |
#define DIE(code) { fprintf(stderr,"jtsslice died with error code %d\n",(code)); return 0;} |
67 |
|
68 |
/* global variables holding the values of the command line variables. */ |
69 |
static char *gapfile; |
70 |
static int lmode, n_sampled_out, flipm; |
71 |
static float tsample; |
72 |
static int ifirst, tsout,fftout, fft1out, powout, mavgout; |
73 |
static int navg, nskip, noff, imin, imax; |
74 |
|
75 |
|
76 |
/* Prototypes for local functions. */ |
77 |
static double splitting(int l, int m); |
78 |
|
79 |
/* Prototypes for external functions */ |
80 |
extern void cffti_(int *, float *); |
81 |
extern void cfftb_(int *, float *, float *); |
82 |
static int extract_gaps(int n_in, int *gaps_in, int *n_out, int *gaps_out, |
83 |
float tsample_in, float *tsample_out, |
84 |
int *num_sections, int *sections); |
85 |
static void extract_data(int n_in, int *gaps, float *data_in, float *data_out); |
86 |
|
87 |
/************ Here begins the main module **************/ |
88 |
int DoIt(void) |
89 |
{ |
90 |
int i; |
91 |
int start_index[2], counts[2], intervals[2]; |
92 |
int m, n_in, n_sampled_in; |
93 |
TIME epoch, step, start, stop; |
94 |
int gapsize, istart, istop, data_dim, detrend_order; |
95 |
int npow, mshift; |
96 |
float tsamplex, df1, c; |
97 |
int *agaps; |
98 |
int *gaps; |
99 |
float *msum, *pow; |
100 |
float *data, *out_data, *in_data; |
101 |
fftwf_plan plan; |
102 |
int num_sections, *sections; |
103 |
char tstartstr[100]; |
104 |
|
105 |
int fstatus = 0; |
106 |
fitsfile *fitsptr; |
107 |
long fdims[1]; |
108 |
long fpixel[]={1}; |
109 |
int *anynul=0; |
110 |
|
111 |
int length[2], startind[2], endind[2]; |
112 |
float *datarr; |
113 |
int status=DRMS_SUCCESS; |
114 |
int newstat=0; |
115 |
char *ttotal; |
116 |
double nseconds; |
117 |
|
118 |
DRMS_Segment_t *segin = NULL; |
119 |
DRMS_Segment_t *segout = NULL; |
120 |
DRMS_Array_t *inarr = NULL; |
121 |
DRMS_Array_t *outarr = NULL; |
122 |
DRMS_Record_t *inrec = NULL; |
123 |
DRMS_Record_t *outrec = NULL; |
124 |
DRMS_Type_t usetype = DRMS_TYPE_FLOAT; |
125 |
DRMS_RecLifetime_t lifetime; |
126 |
long long histrecnum = -1; |
127 |
DRMS_Segment_t *gapseg = NULL; |
128 |
DRMS_Array_t *gaparr = NULL; |
129 |
|
130 |
HIterator_t outKey_list; |
131 |
DRMS_Keyword_t *outKey; |
132 |
TIME tnow, UNIX_epoch = -220924792.000; /* 1970.01.01_00:00:00_UTC */ |
133 |
|
134 |
int errbufstat=setvbuf(stderr, NULL, _IONBF, BUFSIZ); |
135 |
int outbufstat=setvbuf(stdout, NULL, _IONBF, BUFSIZ); |
136 |
|
137 |
double tstart, tstartsave, tstop, tstopsave, cadence, tstartout, tstopout; |
138 |
double wt0, wt1, wt2, wt3, wt; |
139 |
double ut0, ut1, ut2, ut3, ut; |
140 |
double st0, st1, st2, st3, st; |
141 |
double ct0, ct1, ct2, ct3, ct; |
142 |
|
143 |
wt0=getwalltime(); |
144 |
ct0=getcputime(&ut0, &st0); |
145 |
|
146 |
/* Read input parameters. */ |
147 |
gapfile = (char *)cmdparams_save_str (&cmdparams, "GAPFILE", &newstat); |
148 |
n_sampled_out = cmdparams_save_int (&cmdparams, "NDT", &newstat); |
149 |
ifirst = cmdparams_save_int (&cmdparams, "IFIRST", &newstat); |
150 |
// flipm = cmdparams_save_int (&cmdparams, "FLIPM", &newstat); |
151 |
tsout = cmdparams_save_int (&cmdparams, "TSOUT", &newstat); |
152 |
fftout = cmdparams_save_int (&cmdparams, "FFTOUT", &newstat); |
153 |
fft1out = cmdparams_save_int (&cmdparams, "FFT1OUT", &newstat); |
154 |
powout = cmdparams_save_int (&cmdparams, "POWOUT", &newstat); |
155 |
mavgout = cmdparams_save_int (&cmdparams, "MAVGOUT", &newstat); |
156 |
navg = cmdparams_save_int (&cmdparams, "NAVG", &newstat); |
157 |
nskip = cmdparams_save_int (&cmdparams, "NSKIP", &newstat); |
158 |
noff = cmdparams_save_int (&cmdparams, "NOFF", &newstat); |
159 |
imin = cmdparams_save_int (&cmdparams, "IMIN", &newstat); |
160 |
imax = cmdparams_save_int (&cmdparams, "IMAX", &newstat); |
161 |
|
162 |
char *inrecquery = (char *)cmdparams_save_str(&cmdparams, "in", &newstat); |
163 |
char *outseries = (char *)cmdparams_save_str(&cmdparams, "out", &newstat); |
164 |
char *segnamein = (char *)cmdparams_save_str(&cmdparams, "segin", &newstat); |
165 |
char *segnameout = (char *)cmdparams_save_str(&cmdparams, "segout", &newstat); |
166 |
int seginflag = strcmp(kNOTSPECIFIED, segnamein); |
167 |
int segoutflag = strcmp(kNOTSPECIFIED, segnameout); |
168 |
char *histlinkname = (char *)cmdparams_save_str(&cmdparams, "histlink", &newstat); |
169 |
char *srclinkname = (char *)cmdparams_save_str(&cmdparams, "srclink", &newstat); |
170 |
int verbflag = cmdparams_save_int(&cmdparams, "VERB", &newstat); |
171 |
int permflag = cmdparams_save_int(&cmdparams, "PERM", &newstat); |
172 |
if (permflag) |
173 |
lifetime = DRMS_PERMANENT; |
174 |
else |
175 |
lifetime = DRMS_TRANSIENT; |
176 |
|
177 |
ttotal=(char *)cmdparams_save_str(&cmdparams, "TTOTAL", &newstat); |
178 |
status=drms_names_parseduration(&ttotal, &nseconds, 1); |
179 |
if (status != DRMS_SUCCESS) |
180 |
{ |
181 |
fprintf(stderr, "ERROR: problem parsing TTOTAL, = %s\n", ttotal); |
182 |
return 1; |
183 |
} |
184 |
|
185 |
if (newstat) |
186 |
{ |
187 |
fprintf(stderr, "ERROR: problem with input arguments, status = %d, diagnosis follows\n", newstat); |
188 |
cpsave_decode_error(newstat); |
189 |
return 1; |
190 |
} |
191 |
else if (savestrlen != strlen(savestr)) |
192 |
{ |
193 |
fprintf(stderr, "ERROR: problem with savestr, savestrlen = %d, strlen(savestr) = %d\n", savestrlen, (int)strlen(savestr)); |
194 |
return 1; |
195 |
} |
196 |
|
197 |
|
198 |
/**** Sanity check of input parameters. ****/ |
199 |
|
200 |
/* Default is to just output the timeseries. */ |
201 |
if ((tsout == 0) && (fftout == 0) && (fft1out == 0) && (powout == 0) && (mavgout == 0)) |
202 |
tsout=1; |
203 |
/* Only one type of output allowed at a time */ |
204 |
if ((tsout+fftout+fft1out+powout+mavgout) !=1) |
205 |
{ |
206 |
fprintf(stderr, "ERROR: only one type of output allowed at a time\n"); |
207 |
return 1; |
208 |
} |
209 |
if (navg <= 0) |
210 |
navg=1; |
211 |
if (nskip <= 0) |
212 |
nskip=1; |
213 |
if ((navg != 1) && (nskip != 1)) |
214 |
{ |
215 |
fprintf(stderr, "ERROR: one of navg and nskip must equal 1\n"); |
216 |
return 1; |
217 |
} |
218 |
if (noff < 0 || noff >= nskip) |
219 |
{ |
220 |
fprintf(stderr, "ERROR: noff must be >= 0 and < nskip\n"); |
221 |
return 1; |
222 |
} |
223 |
|
224 |
|
225 |
DRMS_Record_t *tempoutrec = drms_create_record(drms_env, |
226 |
outseries, |
227 |
DRMS_TRANSIENT, |
228 |
&status); |
229 |
|
230 |
if (status != DRMS_SUCCESS) |
231 |
{ |
232 |
fprintf(stderr,"ERROR: couldn't open a record in output dataseries %s, status = %d\n", outseries, status); |
233 |
return 1; |
234 |
} |
235 |
|
236 |
DRMS_Link_t *histlink = hcon_lookup_lower(&tempoutrec->links, histlinkname); |
237 |
DRMS_Link_t *srclink = hcon_lookup_lower(&tempoutrec->links, srclinkname); |
238 |
|
239 |
// char *cvsinfo = strdup("$Header: /home/cvsuser/cvsroot/JSOC/proj/globalhs/apps/jtsslice.c,v 1.11 2012/09/24 20:06:23 tplarson Exp $"); |
240 |
if (histlink != NULL) |
241 |
{ |
242 |
histrecnum=set_history(histlink); |
243 |
if (histrecnum < 0) |
244 |
{ |
245 |
drms_close_record(tempoutrec, DRMS_FREE_RECORD); |
246 |
return 1; |
247 |
} |
248 |
} |
249 |
else |
250 |
{ |
251 |
fprintf(stderr,"WARNING: could not find history link in output dataseries\n"); |
252 |
} |
253 |
|
254 |
// these must be present in the output dataseries and variable, not links or constants |
255 |
char *outchecklist[] = {"T_START", "QUALITY", "LMIN", "LMAX", "NDT"}; |
256 |
|
257 |
int itest; |
258 |
for (itest=0; itest < ARRLENGTH(outchecklist); itest++) |
259 |
{ |
260 |
DRMS_Keyword_t *outkeytest = hcon_lookup_lower(&tempoutrec->keywords, outchecklist[itest]); |
261 |
if (outkeytest == NULL || outkeytest->info->islink || outkeytest->info->recscope == 1) |
262 |
{ |
263 |
fprintf(stderr, "ERROR: output keyword %s is either missing, constant, or a link\n", outchecklist[itest]); |
264 |
drms_close_record(tempoutrec, DRMS_FREE_RECORD); |
265 |
return 1; |
266 |
} |
267 |
} |
268 |
|
269 |
cadence=drms_getkey_float(tempoutrec, "T_STEP", &status); |
270 |
double chunksecs = n_sampled_out*cadence; |
271 |
if (fmod(nseconds,chunksecs) != 0.0) |
272 |
{ |
273 |
fprintf(stderr, "ERROR: input parameters seem incompatible (chunksecs must divide nseconds): nseconds = %f, chunksecs = %f\n", nseconds, chunksecs); |
274 |
drms_close_record(tempoutrec, DRMS_FREE_RECORD); |
275 |
return 1; |
276 |
} |
277 |
int ntimechunks = nseconds/chunksecs; |
278 |
tsample=cadence; |
279 |
|
280 |
int mflipout = drms_getkey_int(tempoutrec, "MFLIPPED", &status); |
281 |
if (status != DRMS_SUCCESS) mflipout=0; |
282 |
|
283 |
drms_close_record(tempoutrec, DRMS_FREE_RECORD); |
284 |
|
285 |
|
286 |
if (fits_open_file(&fitsptr, gapfile, READONLY, &fstatus)) |
287 |
{ |
288 |
DRMS_RecordSet_t *gaprecset = drms_open_records(drms_env, gapfile, &status); |
289 |
if (status != DRMS_SUCCESS || gaprecset == NULL) |
290 |
{ |
291 |
fprintf(stderr,"ERROR: problem reading gaps: file status = %d, DRMS status = %d\n",fstatus,status); |
292 |
return 1; |
293 |
} |
294 |
if (gaprecset->n == 0) |
295 |
{ |
296 |
fprintf(stderr,"ERROR: gapfile recordset contains no records\n"); |
297 |
return 1; |
298 |
} |
299 |
if (gaprecset->n > 1) |
300 |
{ |
301 |
fprintf(stderr,"ERROR: gapfile recordset with more than 1 record not yet supported.\n"); |
302 |
return 1; |
303 |
} |
304 |
gapseg = drms_segment_lookupnum(gaprecset->records[0], 0); |
305 |
if (gapseg != NULL) |
306 |
gaparr = drms_segment_read(gapseg, DRMS_TYPE_INT, &status); |
307 |
if (status != DRMS_SUCCESS || gaparr == NULL || gapseg == NULL) |
308 |
{ |
309 |
fprintf(stderr, "ERROR: problem reading gaps segment: status = %d\n", status); |
310 |
return 1; |
311 |
} |
312 |
agaps=(int *)(gaparr->data); |
313 |
gapsize=gaparr->axis[0]; |
314 |
} |
315 |
else |
316 |
{ |
317 |
fits_get_img_size(fitsptr, 1, fdims, &fstatus); |
318 |
gapsize=fdims[0]; |
319 |
agaps=(int *)(malloc(gapsize*sizeof(int))); |
320 |
fits_read_pix(fitsptr, TINT, fpixel, gapsize, NULL, agaps, anynul, &fstatus); |
321 |
fits_close_file(fitsptr, &fstatus); |
322 |
if (fstatus) |
323 |
{ |
324 |
fprintf(stderr, "ERROR: "); |
325 |
fits_report_error(stderr, fstatus); |
326 |
return 1; |
327 |
} |
328 |
} |
329 |
|
330 |
if (verbflag) |
331 |
printf("gapfile read, gapsize = %d\n",gapsize); |
332 |
|
333 |
data_dim=gapsize; |
334 |
if (n_sampled_out>gapsize) |
335 |
data_dim=n_sampled_out; |
336 |
|
337 |
num_sections=1; |
338 |
sections = malloc(2*sizeof(int)); |
339 |
sections[0] = 0; |
340 |
sections[1] = data_dim-1; |
341 |
|
342 |
/* allocate temporary storage */ |
343 |
gaps=(int *)(malloc(gapsize*sizeof(int))); |
344 |
data=(float *)(fftwf_malloc(2*data_dim*sizeof(float))); |
345 |
|
346 |
DRMS_RecordSet_t *inrecset = drms_open_records(drms_env, inrecquery, &status); |
347 |
|
348 |
if (status != DRMS_SUCCESS || inrecset == NULL) |
349 |
{ |
350 |
fprintf(stderr,"ERROR: problem opening input recordset: status = %d\n",status); |
351 |
return 1; |
352 |
} |
353 |
|
354 |
if (inrecset->n == 0) |
355 |
{ |
356 |
fprintf(stderr, "ERROR: input recordset contains no records\n"); |
357 |
return 1; |
358 |
} |
359 |
|
360 |
inrec=inrecset->records[0]; |
361 |
char *inchecklist[] = {"T_START", "QUALITY", "LMIN", "LMAX", "T_STEP"}; |
362 |
|
363 |
for (itest=0; itest < ARRLENGTH(inchecklist); itest++) |
364 |
{ |
365 |
DRMS_Keyword_t *inkeytest = hcon_lookup_lower(&inrec->keywords, inchecklist[itest]); |
366 |
if (inkeytest == NULL) |
367 |
{ |
368 |
fprintf(stderr, "ERROR: required input keyword %s is missing\n", inchecklist[itest]); |
369 |
drms_close_records(inrecset, DRMS_FREE_RECORD); |
370 |
return 1; |
371 |
} |
372 |
} |
373 |
|
374 |
tstartsave=drms_getkey_time(inrec, "T_START", NULL); //must be constant across all input records unless GAPFILE is implemented differently |
375 |
|
376 |
int mflipin = drms_getkey_int(inrec, "MFLIPPED", &status); |
377 |
if (status != DRMS_SUCCESS) mflipin=0; |
378 |
|
379 |
if (mflipout != mflipin) |
380 |
flipm=1; |
381 |
else |
382 |
flipm=0; |
383 |
|
384 |
// changed n_in to gapsize in following call |
385 |
if (extract_gaps(gapsize, agaps, &n_sampled_in, gaps, tsample, &tsamplex, &num_sections, sections)) |
386 |
{ |
387 |
fprintf(stderr, "ERROR: problem in extract_gaps\n"); |
388 |
return 0; |
389 |
} |
390 |
|
391 |
if (n_sampled_out == -1) |
392 |
n_sampled_out = n_sampled_in; |
393 |
df1 = tsamplex*n_sampled_out; |
394 |
|
395 |
if (fftout || fft1out || powout || mavgout) |
396 |
plan = fftwf_plan_dft_1d(n_sampled_out, (fftwf_complex *)data, |
397 |
(fftwf_complex *)data, FFTW_BACKWARD, FFTW_MEASURE); |
398 |
|
399 |
/* Set sum to zero before starting */ |
400 |
if (mavgout) |
401 |
msum = (float *)calloc(n_sampled_out/2,sizeof(float)); |
402 |
|
403 |
if (fft1out || powout || mavgout) |
404 |
{ |
405 |
/* Set first and last output index if not set as a parameter. */ |
406 |
if (imax < imin) |
407 |
{ |
408 |
imin=0; |
409 |
imax=n_sampled_out/2-1; |
410 |
} |
411 |
npow=imax-imin+1; |
412 |
pow=(float *)(malloc(n_sampled_out*sizeof(float))); |
413 |
} |
414 |
|
415 |
|
416 |
status=drms_stage_records(inrecset, 1, 0); |
417 |
if (status != DRMS_SUCCESS) |
418 |
{ |
419 |
fprintf(stderr, "ERROR: drms_stage_records returned status = %d\n", status); |
420 |
return 1; |
421 |
} |
422 |
|
423 |
int nrecsout = ntimechunks * inrecset->n; |
424 |
DRMS_RecordSet_t *outrecset = drms_create_records(drms_env, nrecsout, outseries, DRMS_PERMANENT, &status); |
425 |
if (status != DRMS_SUCCESS || outrecset == NULL) |
426 |
{ |
427 |
fprintf(stderr,"ERROR: couldn't open a record in output dataseries %s, status = %d\n", outseries, status); |
428 |
return 1; |
429 |
} |
430 |
|
431 |
int gapoffset, gapoffset0 = ifirst; |
432 |
double tstart0 = tstartsave+ifirst*tsample; |
433 |
int irec; |
434 |
for (irec=0;irec<inrecset->n;irec++) |
435 |
{ |
436 |
|
437 |
inrec = inrecset->records[irec]; |
438 |
|
439 |
int lmin=drms_getkey_int(inrec, "LMIN", NULL); |
440 |
int lmax=drms_getkey_int(inrec, "LMAX", NULL); |
441 |
if (lmin != lmax) |
442 |
{ |
443 |
fprintf(stderr, "ERROR: lmin != lmax not yet supported.\n"); |
444 |
return 0; |
445 |
} |
446 |
lmode=lmin; |
447 |
|
448 |
if (verbflag) |
449 |
printf("starting l=%d\n",lmode); |
450 |
|
451 |
tstart=drms_getkey_time(inrec, "T_START", NULL); |
452 |
tstop =drms_getkey_time(inrec, "T_STOP", NULL); |
453 |
cadence=drms_getkey_float(inrec, "T_STEP", NULL); |
454 |
if (tstart != tstartsave) |
455 |
{ |
456 |
// to lift this restriction must be able to specify multiple gap files/records as input |
457 |
sprint_time(tstartstr, tstart, "TAI", 0); |
458 |
fprintf(stderr, "ERROR: all input records must have same T_START, record %d has %s\n", irec, tstartstr); |
459 |
return 0; |
460 |
} |
461 |
|
462 |
n_in=(tstop-tstart)/cadence; |
463 |
if (n_in != gapsize) |
464 |
{ |
465 |
fprintf(stderr, "ERROR: gaps seem incompatible with time-series, gapsize=%d, n_in=%d\n", gapsize, n_in); |
466 |
return 0; |
467 |
} |
468 |
|
469 |
/* Create output data set. */ |
470 |
if (tsout || fftout) |
471 |
{ |
472 |
length[0]=2*n_sampled_out; |
473 |
length[1]=lmode+1; |
474 |
} |
475 |
else |
476 |
{ |
477 |
if (fft1out) |
478 |
length[0]=2*npow; |
479 |
else |
480 |
length[0]=npow; |
481 |
if (powout || fft1out) |
482 |
length[1]=2*lmode+1; |
483 |
else |
484 |
length[1]=1; |
485 |
} |
486 |
|
487 |
startind[1]=0; |
488 |
endind[1]=lmode; |
489 |
|
490 |
if (seginflag) |
491 |
segin = drms_segment_lookup(inrec, segnamein); |
492 |
else |
493 |
segin = drms_segment_lookupnum(inrec, 0); |
494 |
if (segin == NULL) |
495 |
{ |
496 |
fprintf(stderr, "ERROR: problem reading input segment: recnum = %ld\n", inrec->recnum); |
497 |
return 0; |
498 |
} |
499 |
|
500 |
int iset; |
501 |
for (iset=0; iset < ntimechunks; iset++) |
502 |
{ |
503 |
tstartout=tstart0 + iset * chunksecs; |
504 |
tstopout=tstartout+chunksecs; |
505 |
sprint_time(tstartstr, tstartout, "TAI", 0); |
506 |
gapoffset = gapoffset0 + iset*n_sampled_out; |
507 |
|
508 |
if (verbflag>1) |
509 |
{ |
510 |
printf(" starting tstart = %s, ",tstartstr); |
511 |
if (irec == 0) |
512 |
{ |
513 |
int ig, gtotal=0; |
514 |
for (ig=0;ig<n_sampled_out;ig++) |
515 |
gtotal+=gaps[gapoffset+ig]; |
516 |
float dutycycle = (float)gtotal/n_sampled_out; |
517 |
printf("dutycycle = %f\n", dutycycle); |
518 |
} |
519 |
} |
520 |
|
521 |
// set ifirst to gapoffset for reading slice |
522 |
ifirst=gapoffset; |
523 |
startind[0]=2*(ifirst); |
524 |
endind[0]=2*(ifirst + n_sampled_out) - 1; |
525 |
// set ifirst=0 because data is read starting at ifirst by drms_segment_readslice |
526 |
ifirst=0; |
527 |
|
528 |
inarr = drms_segment_readslice(segin, usetype, startind, endind, &status); |
529 |
if (status != DRMS_SUCCESS || inarr == NULL) |
530 |
{ |
531 |
fprintf(stderr, "ERROR: problem reading input segment: recnum = %ld, status = %d\n", inrec->recnum, status); |
532 |
return 0; |
533 |
} |
534 |
datarr=(float *)(inarr->data); |
535 |
|
536 |
/* |
537 |
outrec = drms_create_record(drms_env, outseries, lifetime, &status); |
538 |
if (status != DRMS_SUCCESS || outrec==NULL) |
539 |
{ |
540 |
fprintf(stderr,"ERROR: unable to open record in output dataseries, status = %d\n", status); |
541 |
return 0; |
542 |
} |
543 |
*/ |
544 |
// outrec = outrecset->records[ntimechunks*irec+iset]; |
545 |
outrec = outrecset->records[iset*inrecset->n + irec]; |
546 |
|
547 |
if (histlink != NULL) |
548 |
drms_setlink_static(outrec, histlinkname, histrecnum); |
549 |
if (srclink != NULL) |
550 |
drms_setlink_static(outrec, srclinkname, inrec->recnum); |
551 |
|
552 |
if (segoutflag) |
553 |
segout = drms_segment_lookup(outrec, segnameout); |
554 |
else |
555 |
segout = drms_segment_lookupnum(outrec, 0); |
556 |
outarr = drms_array_create(usetype, 2, length, NULL, &status); |
557 |
if (status != DRMS_SUCCESS || outarr == NULL || segout == NULL) |
558 |
{ |
559 |
fprintf(stderr,"ERROR: problem creating output array or segment: length = [%d, %d], status = %d", length[0], length[1], status); |
560 |
return 0; |
561 |
} |
562 |
out_data = outarr->data; |
563 |
|
564 |
/***** Main Loop over m: Detrend, gapfill and/or compute FFT/power spectrum *******/ |
565 |
for (m=0; m<=lmode; m++) |
566 |
{ |
567 |
|
568 |
if (verbflag>2) |
569 |
printf(" starting m=%d\n",m); |
570 |
|
571 |
in_data=datarr + m*2*n_sampled_out; |
572 |
|
573 |
/* Extracts data copy */ |
574 |
extract_data(n_sampled_out, gaps+gapoffset, in_data, data); |
575 |
|
576 |
/* pad with zeros if the last point output (n_sampled_out+ifirst) |
577 |
is after the last data points read in (nread). */ |
578 |
memmove(data, &data[2*ifirst], 2*(n_sampled_in-ifirst)*sizeof(float)); |
579 |
if ((ifirst+n_sampled_out) >= n_sampled_in) |
580 |
memset(&data[2*n_sampled_in], 0, 2*(n_sampled_out+ifirst-n_sampled_in)*sizeof(float)); |
581 |
|
582 |
if (fftout || fft1out || powout || mavgout) |
583 |
fftwf_execute(plan); |
584 |
|
585 |
if (tsout || fftout) |
586 |
memcpy(&out_data[2*m*n_sampled_out], &data[2*ifirst], 2*n_sampled_out*sizeof(float)); |
587 |
|
588 |
else if (fft1out) |
589 |
{ |
590 |
/* Do positive m */ |
591 |
memcpy(&out_data[2*(lmode+m)*npow], &data[2*imin], 2*npow*sizeof(float)); |
592 |
if (m > 0) |
593 |
{ |
594 |
/* Do negative m */ |
595 |
for (i=0; i<npow; i++) |
596 |
{ |
597 |
/* Conjugate for negative m */ |
598 |
out_data[2*((lmode-m)*npow+i)] = data[2*(n_sampled_out-imin-i)]; |
599 |
out_data[2*((lmode-m)*npow+i)+1] = -data[2*(n_sampled_out-imin-i)+1]; |
600 |
} |
601 |
} |
602 |
} |
603 |
else |
604 |
{ |
605 |
/* Compute power spectrum from complex FFT. */ |
606 |
for (i = 0; i < n_sampled_out; i++) |
607 |
pow[i] = data[2*i]*data[2*i] + data[2*i+1]*data[2*i+1]; |
608 |
if (powout) |
609 |
{ |
610 |
/* Do positive m */ |
611 |
memcpy(&out_data[(lmode+m)*npow], &pow[imin], npow*sizeof(float)); |
612 |
if (m > 0) |
613 |
{ |
614 |
/* Do negative m */ |
615 |
if (imin) |
616 |
out_data[(lmode-m)*npow] = pow[n_sampled_out-imin]; |
617 |
else |
618 |
out_data[(lmode-m)*npow] = pow[0]; |
619 |
for (i=1; i<npow;i++) |
620 |
out_data[(lmode-m)*npow+i] = pow[n_sampled_out-imin-i]; |
621 |
} |
622 |
} |
623 |
else |
624 |
{ |
625 |
/* m-averaged output */ |
626 |
/* Sum all freqs, not only those in output. Should be fixed. */ |
627 |
/* Maybe should allow for wrapping around Nyquist. */ |
628 |
/* Do positive m */ |
629 |
mshift = floor(df1*splitting(lmode,m)+0.5f); |
630 |
if (mshift >= 0) |
631 |
for (i=0; i<n_sampled_out/2-mshift; i++) |
632 |
msum[i] += pow[mshift+i]; |
633 |
else |
634 |
for (i=0; i<n_sampled_out/2+mshift; i++) |
635 |
msum[i-mshift] += pow[i]; |
636 |
if (m > 0) |
637 |
{ |
638 |
/* Do negative m */ |
639 |
mshift = floor(df1*splitting(lmode,-m)+0.5f); |
640 |
if (mshift >=0) |
641 |
for (i=1; i<n_sampled_out/2-mshift;i++) |
642 |
msum[i] += pow[n_sampled_out-mshift-i]; |
643 |
else |
644 |
for (i=1; i<n_sampled_out/2+mshift; i++) |
645 |
msum[i-mshift] += pow[n_sampled_out-i]; |
646 |
} |
647 |
} |
648 |
} |
649 |
|
650 |
} /* End of m loop */ |
651 |
|
652 |
drms_copykeys(outrec, inrec, 0, kDRMS_KeyClass_Explicit); |
653 |
drms_setkey_int(outrec, "QUALITY", 0); |
654 |
drms_setkey_time(outrec, "T_START", tstartout); |
655 |
drms_setkey_time(outrec, "T_STOP", tstopout); |
656 |
drms_setkey_time(outrec, "T_OBS", (tstartout + tstopout)/2); |
657 |
drms_setkey_float(outrec, "T_STEP", tsamplex); |
658 |
drms_setkey_int(outrec, "NDT", n_sampled_out); |
659 |
|
660 |
tnow = (double)time(NULL); |
661 |
tnow += UNIX_epoch; |
662 |
drms_setkey_time(outrec, "DATE", tnow); |
663 |
|
664 |
if (mavgout) |
665 |
{ |
666 |
c=1.0f/(2*lmode+1); |
667 |
for (i=0; i<npow; i++) |
668 |
out_data[i] = msum[imin+i] * c; |
669 |
} |
670 |
|
671 |
outarr->bzero=segout->bzero; |
672 |
outarr->bscale=segout->bscale; |
673 |
status=drms_segment_write(segout, outarr, 0); |
674 |
if (status != DRMS_SUCCESS) |
675 |
{ |
676 |
fprintf(stderr, "ERROR: problem writing output segment: status = %d, T_START = %s, LMODE = %d, histrecnum = %lld\n", status, tstartstr, lmode, histrecnum); |
677 |
return 0; |
678 |
} |
679 |
drms_free_array(outarr); |
680 |
drms_free_array(inarr); |
681 |
// drms_close_record(outrec, DRMS_INSERT_RECORD); |
682 |
|
683 |
} |
684 |
|
685 |
} |
686 |
|
687 |
drms_close_records(inrecset, DRMS_FREE_RECORD); |
688 |
drms_close_records(outrecset, DRMS_INSERT_RECORD); |
689 |
|
690 |
if (fftout || fft1out || powout || mavgout) |
691 |
fftwf_destroy_plan(plan); |
692 |
|
693 |
wt=getwalltime(); |
694 |
ct=getcputime(&ut, &st); |
695 |
if (verbflag) |
696 |
{ |
697 |
fprintf(stdout, "total time spent: %.2f ms wall time, %.2f ms cpu time\n", |
698 |
wt-wt0, ct-ct0); |
699 |
} |
700 |
|
701 |
printf("module %s successful completion\n", cmdparams.argv[0]); |
702 |
return 0; |
703 |
} |
704 |
|
705 |
|
706 |
static double splitting(int l, int m) |
707 |
{ |
708 |
double a1x[] = {406.0,407.0,408.0,410.5,412.0,411.5,409.0,406.0,406.0}; |
709 |
double a3x[] = {10.0,10.0,15.0,19.5,21.0,21.3,21.3,21.3,21.8}; |
710 |
double a5x[] = {0.0,0.0,0.0,-1.5,-2.5,-3.5,-4.0,-4.0,-4.5}; |
711 |
/* f0 is the frequency used for generating the above a-coeff */ |
712 |
double f0 = 1500.0; |
713 |
/* fcol is the frequency for which to optimize the collaps */ |
714 |
double fcol = 800.0; |
715 |
|
716 |
double ll,x,x3,x5,a1,a2,a3,a5,frac,lx; |
717 |
int ix; |
718 |
|
719 |
if (l == 0) |
720 |
ll = 1; |
721 |
else |
722 |
ll = sqrt(l*(l+1.)); |
723 |
x = m/ll; |
724 |
x3 = x*x*x; |
725 |
x5 = x3*x*x; |
726 |
lx = 5*log10(l*f0/fcol)-4; |
727 |
ix = floor(lx); |
728 |
frac = lx-ix; |
729 |
if (lx <= 0) { |
730 |
ix = 0; |
731 |
frac = 0.0; |
732 |
} |
733 |
if (lx >=8) { |
734 |
ix = 7; |
735 |
frac = 1.0; |
736 |
} |
737 |
a1 = (1.0-frac)*a1x[ix]+frac*a1x[ix+1]; |
738 |
a2 = 0.0; |
739 |
a3 = (1.0-frac)*a3x[ix]+frac*a3x[ix+1]; |
740 |
a5 = (1.0-frac)*a5x[ix]+frac*a5x[ix+1]; |
741 |
|
742 |
return ll*(a1*x+a2*(1.5*x*x-0.5)+a3*(2.5*x3-1.5*x)+a5*(63./8.*x5-70./8.*x3+15./8.*x))/1e9; |
743 |
} |
744 |
|
745 |
|
746 |
|
747 |
/* Extract the data samples actually used by skipping or averaging |
748 |
data. Replace missing data that are not marked as gaps with zero. */ |
749 |
void extract_data(int n_in, int *gaps, float *data_in, float *data_out) |
750 |
{ |
751 |
int i,j, nmiss = 0; |
752 |
// the following check will be skipped in production executables since they will be built with NDEBUG defined. |
753 |
// it doesn't matter because the check is already done in DoIt(). |
754 |
assert(nskip==1 || navg==1); |
755 |
if ((navg == 1) && (nskip == 1)) |
756 |
{ |
757 |
for (i=0; i<n_in; i++) |
758 |
{ |
759 |
if (gaps[i]==0 ) |
760 |
{ |
761 |
data_out[2*i] = 0.0f; |
762 |
data_out[2*i+1] = 0.0f; |
763 |
} |
764 |
else |
765 |
{ |
766 |
if (isnan(data_in[2*i]) || isnan(data_in[2*i+1])) |
767 |
{ |
768 |
data_out[2*i] = 0.0f; |
769 |
data_out[2*i+1] = 0.0f; |
770 |
gaps[i] = 0; |
771 |
nmiss++; |
772 |
} |
773 |
else |
774 |
{ |
775 |
data_out[2*i] = data_in[2*i]; |
776 |
data_out[2*i+1] = flipm ? -data_in[2*i+1] : data_in[2*i+1]; |
777 |
} |
778 |
} |
779 |
} |
780 |
} |
781 |
else if (nskip != 1) |
782 |
{ |
783 |
for (i = 0; i<n_in; i++) |
784 |
{ |
785 |
if (gaps[i]==0 ) |
786 |
{ |
787 |
data_out[2*i] = 0.0f; |
788 |
data_out[2*i+1] = 0.0f; |
789 |
} |
790 |
else |
791 |
{ |
792 |
int ix = nskip*i+noff; |
793 |
if (isnan(data_in[2*ix]) || isnan(data_in[2*ix+1])) |
794 |
{ |
795 |
data_out[2*i] = 0.0f; |
796 |
data_out[2*i+1] = 0.0f; |
797 |
gaps[i] = 0; |
798 |
nmiss++; |
799 |
} |
800 |
else |
801 |
{ |
802 |
data_out[2*i] = data_in[2*ix]; |
803 |
data_out[2*i+1] = flipm ? -data_in[2*ix+1] : data_in[2*ix+1]; |
804 |
} |
805 |
} |
806 |
} |
807 |
} |
808 |
else if (navg != 1) |
809 |
{ |
810 |
for (i = 0; i<n_in; i++) |
811 |
{ |
812 |
if (gaps[i]==0 ) |
813 |
{ |
814 |
data_out[2*i] = 0.0f; |
815 |
data_out[2*i+1] = 0.0f; |
816 |
} |
817 |
else |
818 |
{ |
819 |
float avgr = 0.0f; |
820 |
float avgi = 0.0f; |
821 |
for (j=0; j<navg; j++) |
822 |
{ |
823 |
int ix = navg*i+j; |
824 |
if (isnan(data_in[2*ix]) || isnan(data_in[2*ix+1])) |
825 |
{ |
826 |
data_out[2*i] = 0.0f; |
827 |
data_out[2*i+1] = 0.0f; |
828 |
gaps[i] = 0; |
829 |
nmiss++; |
830 |
break; |
831 |
} |
832 |
else |
833 |
{ |
834 |
avgr += data_in[2*ix]; |
835 |
avgi += data_in[2*ix+1]; |
836 |
} |
837 |
} |
838 |
if (j == navg) |
839 |
{ |
840 |
data_out[2*i] = avgr/navg; |
841 |
data_out[2*i+1] = avgi/navg; |
842 |
} |
843 |
} |
844 |
} |
845 |
} |
846 |
} |
847 |
|
848 |
/* Extract the windows function for the samples actually used after |
849 |
subsampling or averaging. Modify the list of continous sections |
850 |
accordingly, and make sure we do not average across section boundaries. */ |
851 |
static int extract_gaps(int n_in, int *gaps_in, int *n_out, int *gaps_out, |
852 |
float tsample_in, float *tsample_out, |
853 |
int *num_sections, int *sections) |
854 |
{ |
855 |
// the following check will be skipped in production executables since they will be built with NDEBUG defined. |
856 |
// it doesn't matter because the check is already done in DoIt(). |
857 |
assert(nskip==1 || navg==1); |
858 |
int i,j,sect, start,stop; |
859 |
|
860 |
|
861 |
if (*num_sections<1) |
862 |
{ |
863 |
fprintf(stderr,"Apparantly no sections of data available."); |
864 |
return 1; |
865 |
} |
866 |
/* Mask out data that in between sections if this hasn't already been |
867 |
done in gapfile. */ |
868 |
for (i=0; i<sections[0] && i<n_in; i++) |
869 |
gaps_in[i] = 0; |
870 |
for (sect=1; sect<(*num_sections); sect++) |
871 |
{ |
872 |
for (i=sections[2*sect-1]+1; i<sections[2*sect] && i<n_in; i++) |
873 |
gaps_in[i] = 0; |
874 |
} |
875 |
for (i=sections[2*(*num_sections-1)+1]+1; i<n_in; i++) |
876 |
gaps_in[i] = 0; |
877 |
|
878 |
|
879 |
if ((navg == 1) && (nskip == 1)) |
880 |
{ |
881 |
*n_out = n_in; |
882 |
*tsample_out = tsample_in; |
883 |
for (i=0; i<*n_out; i++) |
884 |
gaps_out[i] = gaps_in[i]; |
885 |
} |
886 |
else if (nskip != 1) |
887 |
{ |
888 |
*n_out = n_in/nskip; |
889 |
*tsample_out = nskip*tsample_in; |
890 |
for (i=0; i<*n_out; i++) |
891 |
{ |
892 |
gaps_out[i] = gaps_in[nskip*i+noff]; |
893 |
} |
894 |
for (i=0; i<2*(*num_sections); i+=2) |
895 |
{ |
896 |
start = (int)ceilf(((float)(sections[i]-noff))/nskip); |
897 |
stop = (int)floorf(((float)(sections[i+1]-noff))/nskip); |
898 |
if (start <= stop) |
899 |
{ |
900 |
sections[i] = start; |
901 |
sections[i+1] = stop; |
902 |
} |
903 |
else |
904 |
{ |
905 |
/* This section was skipped entirely. */ |
906 |
for (j=i; j< 2*(*num_sections-1); j+=2) |
907 |
{ |
908 |
sections[j] = sections[j+2]; |
909 |
sections[j+1] = sections[j+3]; |
910 |
} |
911 |
*num_sections -= 1; |
912 |
} |
913 |
} |
914 |
} |
915 |
else if (navg != 1) |
916 |
{ |
917 |
sect = 0; |
918 |
*n_out = n_in/navg; |
919 |
*tsample_out = tsample*navg; |
920 |
for (i=0; i<*n_out; i++) |
921 |
{ |
922 |
int igx = 1; |
923 |
while (sect < *num_sections && |
924 |
!(navg*i >= sections[2*sect] && navg*i >= sections[2*sect+1])) |
925 |
sect++; |
926 |
|
927 |
/* Don't allow averaging of data from different sections. */ |
928 |
if (navg*i >= sections[2*sect] && (navg*i+navg-1)<=sections[2*sect+1]) |
929 |
{ |
930 |
for (j=0; j<navg; j++) |
931 |
igx *= gaps_in[navg*i+j]; |
932 |
gaps_out[i] = igx; |
933 |
} |
934 |
else |
935 |
gaps_out[i] = 0; |
936 |
} |
937 |
for (i=0; i<2*(*num_sections); i+=2) |
938 |
{ |
939 |
start = (int)ceilf(((float)sections[i])/navg); |
940 |
stop = (int)floorf(((float)sections[i+1])/navg); |
941 |
if (start <= stop) |
942 |
{ |
943 |
sections[i] = start; |
944 |
sections[i+1] = stop; |
945 |
} |
946 |
else |
947 |
{ |
948 |
/* This section was skipped entirely. */ |
949 |
for (j=i; j< 2*(*num_sections-1); j+=2) |
950 |
{ |
951 |
sections[j] = sections[j+2]; |
952 |
sections[j+1] = sections[j+3]; |
953 |
} |
954 |
*num_sections -= 1; |
955 |
} |
956 |
} |
957 |
} |
958 |
return 0; |
959 |
} |
960 |
|