1 |
/* |
2 |
* pspec3.c ~rick/src/pspec |
3 |
* |
4 |
* Calculate the 3-dimensional power spectrum of an input dataset |
5 |
* The module expects a 3-dimensional real dataset |
6 |
* |
7 |
* Responsible: |
8 |
* Rick Bogart RBogart@solar.stanford.edu |
9 |
* |
10 |
* Usage: |
11 |
* pspec3 [-lvx] in= pspec= ... |
12 |
* |
13 |
* Arguments: (type default description) |
14 |
* in DataSet none Input dataset |
15 |
* A series of records containing 3-d data cubes as one |
16 |
* of their segments. It is assumed that all records in |
17 |
* the dataset are from the same dataseries, or at least |
18 |
* share a common segment structure |
19 |
* segment string - Name of the input data segment (only |
20 |
* required if the input series has multiple 3-dimensional |
21 |
* segments) |
22 |
* pspec DataSeries - Output data series; must |
23 |
* contain at least one 3-dimensional segment |
24 |
* mask_in Float 0.9375 Inner apodization radius |
25 |
* mask_ex Float 1.0 Outer apodization radius |
26 |
* apodize Float 0.96875 Temporal apodization edge |
27 |
* fbin int 0 output frequency binning |
28 |
* |
29 |
* Flags |
30 |
* -l output direct tpower spectrum rather than scaled log |
31 |
* -n do not save results (diagnostic only) |
32 |
* -v run verbose |
33 |
* -x use double-precision calculation |
34 |
* |
35 |
* Bugs: |
36 |
* For large input data cubes (~1 Gpxl) the results may be garbage, |
37 |
* for larger ones (~2 Gpxl) the input may fail altogether. The exact |
38 |
* causes of these problems and consequently the exact limits of |
39 |
* validity are not known, but the code has been verified to work with |
40 |
* "normal" input spectra (Dopplergrams as compressed scaled shorts) |
41 |
* of up to 800 Mpxl. |
42 |
* No checking that input data series corresponds with link in output |
43 |
* series |
44 |
* The value of CDELT3 in the input set overrides the value of Cadence |
45 |
* if propagated, but is not checked for units |
46 |
* |
47 |
* Future Updates |
48 |
* Use drms_keyword_lookup() |
49 |
* Create new data series as needed |
50 |
* Parallelize over multiple records |
51 |
* Add recreation option for target output records |
52 |
* Add parameters for overriding essential input keywords |
53 |
* Add parameter for overriding keyword list for propagation |
54 |
* Modify to also work with a series of two-dimensional images - maybe |
55 |
* not such a good idea |
56 |
* |
57 |
* Revision history is at end of file. |
58 |
*/ |
59 |
#include <jsoc_main.h> |
60 |
#include <fftw3.h> |
61 |
|
62 |
char *module_name = "pspec3"; |
63 |
char *module_desc = "3-d power spectrum"; |
64 |
char *version_id = "1.1"; |
65 |
|
66 |
ModuleArgs_t module_args[] = { |
67 |
{ARG_DATASET, "in", "", "Input data set"}, |
68 |
{ARG_STRING, "segment", "Not Specified", |
69 |
"input data series segment; ignored if series only has one 3-d segment"}, |
70 |
{ARG_DATASERIES, "pspec", "", "Ouput data series"}, |
71 |
{ARG_FLOAT, "mask_in", "0.9375", "inner radial apodization edge", "[0.0,)"}, |
72 |
{ARG_FLOAT, "mask_ex", "1.0", "outer radial apodization edge", "[0.0,)"}, |
73 |
{ARG_FLOAT, "apodize", "0.96875", "temporal apodization edge", |
74 |
"[0.0,1.0]"}, |
75 |
{ARG_INT, "fbin", "0", "output frequency fbins (0-> none)"}, |
76 |
{ARG_STRING, "copy", "+", |
77 |
"comma separated list of keys to propagate forward"}, |
78 |
{ARG_FLAG, "l", "", |
79 |
"output direct power spectrum rather than scaled log"}, |
80 |
{ARG_FLAG, "n", "0", "do not save output record (diagnostics only)"}, |
81 |
{ARG_FLAG, "x", "", "use double-precision calculation"}, |
82 |
{ARG_FLAG, "v", "", "verbose mode"}, |
83 |
{} |
84 |
}; |
85 |
/* list of keywords to propagate (if possible) from input to output */ |
86 |
char *propagate[] = {"CarrTime", "CarrRot", "CMLon", "LonHG", "LatHG", "LonCM", |
87 |
"MidTime", "Duration", "LonSpan", "T_START", "T_STOP", "Coverage", |
88 |
"ZonalTrk", "ZonalVel", "MeridTrk", "MeridVel", "MapScale", "MAI", "Ident", |
89 |
"Width", "Height", "Size", "MapProj", "Map_PA", "PosAng", "RSunRef"}; |
90 |
|
91 |
#include "keystuff.c" |
92 |
|
93 |
static int cleanup (int error, DRMS_RecordSet_t *irecs, DRMS_Record_t *orec, |
94 |
DRMS_Array_t *orig, DRMS_Array_t *pspec, int dispose) { |
95 |
if (orig) drms_free_array (orig); |
96 |
if (pspec) drms_free_array (pspec); |
97 |
if (irecs) drms_close_records (irecs, DRMS_FREE_RECORD); |
98 |
if (orec) { |
99 |
if (error) drms_close_record (orec, DRMS_FREE_RECORD); |
100 |
else drms_close_record (orec, dispose); |
101 |
} |
102 |
return error; |
103 |
} |
104 |
|
105 |
int read_from_big_cube (DRMS_Segment_t *seg, int dp_calc, void *rdata, |
106 |
double *avg, double *var, double apode_edge, double *apodization, |
107 |
int xcols) { |
108 |
DRMS_Array_t *tmp; |
109 |
DRMS_Type_t type; |
110 |
void *data; |
111 |
double *wdata; |
112 |
double dval, dataavg, datavar, weight; |
113 |
float *xdata; |
114 |
float fval; |
115 |
long long n; |
116 |
int *start, *stop; |
117 |
int m, col, cols, row, rows, area, plane, planes, rank, size; |
118 |
int status; |
119 |
|
120 |
if (dp_calc) { |
121 |
size = sizeof (double); |
122 |
type = DRMS_TYPE_DOUBLE; |
123 |
wdata = (double *)rdata; |
124 |
} else { |
125 |
size = sizeof (float); |
126 |
type = DRMS_TYPE_FLOAT; |
127 |
xdata = (float *)rdata; |
128 |
} |
129 |
dataavg = datavar = 0.0; |
130 |
|
131 |
rank = seg->info->naxis; |
132 |
cols = seg->axis[0]; |
133 |
rows = seg->axis[1]; |
134 |
planes = seg->axis[rank-1]; |
135 |
start = (int *)malloc (rank * sizeof (int)); |
136 |
stop = (int *)malloc (rank * sizeof (int)); |
137 |
area = 1; |
138 |
for (n = 0; n < rank-1; n++) { |
139 |
start[n] = 0; |
140 |
stop[n] = seg->axis[n] - 1; |
141 |
area *= seg->axis[n]; |
142 |
} |
143 |
size *= area; |
144 |
n = 0; |
145 |
for (plane = 0; plane < planes; plane++) { |
146 |
m = 0; |
147 |
start[rank-1] = stop[rank-1] = plane; |
148 |
tmp = drms_segment_readslice (seg, type, start, stop, &status); |
149 |
if (status) { |
150 |
fprintf (stderr, "Error reading data plane %d\n", plane); |
151 |
return 1; |
152 |
} |
153 |
data = tmp->data; |
154 |
if (apode_edge < 1.0) { |
155 |
double t = (2.0 * plane) / (planes - 1.0); |
156 |
if (t > 1.0) t = 2.0 - t; |
157 |
t = 1.0 - t; |
158 |
if (t > apode_edge) { |
159 |
t = (t - apode_edge) / (1.0 - apode_edge); |
160 |
t *= t; |
161 |
weight = (1.0 - t); |
162 |
weight *= weight; |
163 |
} else weight = 1.0; |
164 |
} else weight = 1.0; |
165 |
if (dp_calc) { |
166 |
for (row = 0; row < rows; row++) { |
167 |
for (col = 0; col < cols; col++) { |
168 |
dval = ((double *)data)[m]; |
169 |
if (isnan (dval)) dval = 0.0; |
170 |
dval *= weight * apodization[m++]; |
171 |
dataavg += dval; |
172 |
datavar += dval * dval; |
173 |
wdata[n++] = dval; |
174 |
} |
175 |
n += xcols - cols; |
176 |
} |
177 |
} else { |
178 |
for (row = 0; row < rows; row++) { |
179 |
for (col = 0; col < cols; col++) { |
180 |
fval = ((float *)data)[m]; |
181 |
if (isnan (fval)) fval = 0.0; |
182 |
fval *= weight * apodization[m++]; |
183 |
dataavg += fval; |
184 |
datavar += fval * fval; |
185 |
xdata[n++] = fval; |
186 |
} |
187 |
n += xcols - cols; |
188 |
} |
189 |
} |
190 |
drms_free_array (tmp); |
191 |
} |
192 |
return 0; |
193 |
} |
194 |
|
195 |
DRMS_Array_t *read_big_cube (DRMS_Segment_t *seg, DRMS_Type_t type, int *status) { |
196 |
DRMS_Array_t *arr, *tmp; |
197 |
int *start, *stop; |
198 |
int n, plane, pln, plen, rank, size; |
199 |
void *data; |
200 |
|
201 |
size = drms_sizeof (type); |
202 |
rank = seg->info->naxis; |
203 |
plen = seg->axis[rank-1]; |
204 |
arr = drms_array_create (type, rank, seg->axis, NULL, status); |
205 |
if (*status) return NULL; |
206 |
|
207 |
start = (int *)malloc (rank * sizeof (int)); |
208 |
stop = (int *)malloc (rank * sizeof (int)); |
209 |
plane = 1; |
210 |
for (n = 0; n < rank-1; n++) { |
211 |
start[n] = 0; |
212 |
stop[n] = seg->axis[n] - 1; |
213 |
plane *= seg->axis[n]; |
214 |
} |
215 |
size *= plane; |
216 |
data = arr->data; |
217 |
for (pln = 0; pln < plen; pln++) { |
218 |
start[rank-1] = stop[rank-1] = pln; |
219 |
tmp = drms_segment_readslice (seg, type, start, stop, status); |
220 |
if (*status) return NULL; |
221 |
memcpy (data, tmp->data, size); |
222 |
drms_free_array (tmp); |
223 |
(char *)data += size; |
224 |
} |
225 |
if (*status) return NULL; |
226 |
return arr; |
227 |
} |
228 |
|
229 |
int DoIt (void) { |
230 |
CmdParams_t *params = &cmdparams; |
231 |
DRMS_RecordSet_t *irecs = NULL; |
232 |
DRMS_Record_t *irec, *orec = NULL; |
233 |
DRMS_Segment_t *iseg, *oseg; |
234 |
DRMS_Array_t *orig = NULL, *pspec = NULL; |
235 |
|
236 |
double *apodization; |
237 |
double *wdata; |
238 |
double crpix, crval = 0.0; |
239 |
double dnu, domega, dval, r, r2, ra, ra2, rx, ry, r0x, r0y, t, tstep; |
240 |
double dataavg, datavar, powrint, normal, weight; |
241 |
double bzero, bscale, scale_range; |
242 |
float *data, *xdata; |
243 |
float ftrb, ftib, fval, vmin, vmax, vmin2; |
244 |
long long cube, ntot, l, m, n; |
245 |
int axes[3]; |
246 |
int rank, col, cols, row, rows, plane, planes, area; |
247 |
int hcols, hrows, hplanes, opln, xcols, cols_even, rows_even; |
248 |
int rgn, rgnct, segs, isegnum, osegnum, found; |
249 |
int bin, is, js; |
250 |
int key_n, kstat, propct, status; |
251 |
int bigcube; |
252 |
char **copykeylist; |
253 |
char *inser; |
254 |
char module_ident[64]; |
255 |
char pathname[2*DRMS_MAXPATHLEN+1]; |
256 |
char source[DRMS_MAXQUERYLEN], recid[DRMS_MAXQUERYLEN]; |
257 |
void *val; |
258 |
|
259 |
int keyct = sizeof (propagate) / sizeof (char *); |
260 |
|
261 |
char *inds = strdup (params_get_str (params, "in")); |
262 |
char *out_series = strdup (params_get_str (params, "pspec")); |
263 |
double apode_edge = params_get_double (params, "apodize"); |
264 |
double edge_inner = params_get_double (params, "mask_in"); |
265 |
double edge_outer = params_get_double (params, "mask_ex"); |
266 |
int fbins = params_get_int (params, "fbin"); |
267 |
char *seg_name = strdup (params_get_str (params, "segment")); |
268 |
char *propagate_req = strdup (params_get_str (params, "copy")); |
269 |
int log_out = params_isflagset (params, "l") ? 0 : 1; |
270 |
int dp_calc = params_isflagset (params, "x"); |
271 |
int verbose = params_isflagset (params, "v"); |
272 |
int no_save = params_isflagset (params, "n"); |
273 |
int dispose = (no_save) ? DRMS_FREE_RECORD : DRMS_INSERT_RECORD; |
274 |
/* Declaration for FFTW library call */ |
275 |
fftwf_plan fplan; |
276 |
fftw_plan plan; |
277 |
|
278 |
snprintf (module_ident, 64, "%s v %s", module_name, version_id); |
279 |
if (verbose) { |
280 |
printf ("%s:\n", module_ident); |
281 |
if (fbins > 1) |
282 |
printf (" output binned by %d frequencies per plane\n", fbins); |
283 |
if (no_save) |
284 |
printf ("(diagnostic run only, no records will be written to DRMS)\n"); |
285 |
} |
286 |
/* check the output series */ |
287 |
orec = drms_create_record (drms_env, out_series, DRMS_TRANSIENT, &status); |
288 |
if (status) { |
289 |
fprintf (stderr, |
290 |
"Error: drms_create_record returned %d for data series:\n", status); |
291 |
fprintf (stderr, " %s\n", out_series); |
292 |
return cleanup (1, irecs, orec, orig, pspec, dispose); |
293 |
} |
294 |
if ((segs = orec->segments.num_total) < 1) { |
295 |
fprintf (stderr, "Error: no data segments in output data series:\n"); |
296 |
fprintf (stderr, " %s\n", out_series); |
297 |
return cleanup (1, irecs, orec, orig, pspec, dispose); |
298 |
} |
299 |
found = 0; |
300 |
for (n = 0; n < segs; n++) { |
301 |
oseg = drms_segment_lookupnum (orec, n); |
302 |
if (oseg->info->naxis != 3) continue; |
303 |
if (!found) osegnum = n; |
304 |
found++; |
305 |
} |
306 |
if (!found) { |
307 |
fprintf (stderr, "Error: no segment of rank 3 in output data series:\n"); |
308 |
fprintf (stderr, " %s\n", out_series); |
309 |
return cleanup (1, irecs, orec, orig, pspec, dispose); |
310 |
} |
311 |
oseg = drms_segment_lookupnum (orec, osegnum); |
312 |
if (found > 1) { |
313 |
fprintf (stderr, |
314 |
"Warning: multiple segments of rank 3 in output data series:\n"); |
315 |
fprintf (stderr, " %s\n", out_series); |
316 |
fprintf (stderr, " using %s\n", oseg->info->name); |
317 |
} |
318 |
switch (oseg->info->type) { |
319 |
case DRMS_TYPE_CHAR: |
320 |
scale_range = 250.0; |
321 |
break; |
322 |
case DRMS_TYPE_SHORT: |
323 |
scale_range = 65000.0; |
324 |
break; |
325 |
case DRMS_TYPE_INT: |
326 |
scale_range = 4.2e9; |
327 |
break; |
328 |
case DRMS_TYPE_LONGLONG: |
329 |
scale_range = 1.8e19; |
330 |
break; |
331 |
default: |
332 |
scale_range = 1.0; |
333 |
} |
334 |
drms_close_record (orec, DRMS_FREE_RECORD); |
335 |
/* check input */ |
336 |
irecs = drms_open_records (drms_env, inds, &status); |
337 |
if (status) { |
338 |
fprintf (stderr, "Error (%s): drms_open_records() returned %d for dataset:\n", |
339 |
module_ident, status); |
340 |
fprintf (stderr, " %s\n", inds); |
341 |
return cleanup (1, irecs, orec, orig, pspec, dispose); |
342 |
} |
343 |
|
344 |
rgnct = irecs->n; |
345 |
if (rgnct < 1) { |
346 |
fprintf (stderr, "No records found in input data set %s\n", inds); |
347 |
return cleanup (1, irecs, orec, orig, pspec, dispose); |
348 |
} |
349 |
irec = irecs->records[0]; |
350 |
inser = strdup (inds); |
351 |
if ((segs = drms_record_numsegments (irec)) < 1) { |
352 |
fprintf (stderr, "Error: no data segments in input data series:\n"); |
353 |
fprintf (stderr, " %s\n", inser); |
354 |
return cleanup (1, irecs, orec, orig, pspec, dispose); |
355 |
} |
356 |
found = 0; |
357 |
for (n = 0; n < segs; n++) { |
358 |
iseg = drms_segment_lookupnum (irec, n); |
359 |
if (iseg->info->naxis != 3) continue; |
360 |
if (!found) isegnum = n; |
361 |
found++; |
362 |
} |
363 |
if (!found) { |
364 |
fprintf (stderr, "Error: no segment of rank 3 in input data series:\n"); |
365 |
fprintf (stderr, " %s\n", inser); |
366 |
return cleanup (1, irecs, orec, orig, pspec, dispose); |
367 |
} |
368 |
if (found > 1) { |
369 |
if (strcmp (seg_name, "Not Specified")) { |
370 |
iseg = drms_segment_lookup (irec, seg_name); |
371 |
if (!iseg) { |
372 |
fprintf (stderr, |
373 |
"Warning: requested segment %s not found in input data series:\n", |
374 |
seg_name); |
375 |
fprintf (stderr, " %s\n", inser); |
376 |
iseg = drms_segment_lookupnum (irec, isegnum); |
377 |
fprintf (stderr, " using segement %s\n", iseg->info->name); |
378 |
} else if (iseg->info->naxis != 3) { |
379 |
fprintf (stderr, |
380 |
"Warning: requested segment %s in input data series:\n", seg_name); |
381 |
fprintf (stderr, " %s is not 3-dimensional", inser); |
382 |
iseg = drms_segment_lookupnum (irec, isegnum); |
383 |
fprintf (stderr, " using segment %s\n", iseg->info->name); |
384 |
} else isegnum = iseg->info->segnum; |
385 |
} else { |
386 |
fprintf (stderr, |
387 |
"Warning: multiple segments of rank 3 in input data series:\n"); |
388 |
fprintf (stderr, " %s\n", inser); |
389 |
fprintf (stderr, " using %s\n", iseg->info->name); |
390 |
} |
391 |
} |
392 |
propct = construct_stringlist (propagate_req, ',', ©keylist); |
393 |
if (verbose) { |
394 |
printf ("propagating %d key(s):\n", propct); |
395 |
for (key_n = 0; key_n < propct; key_n++) printf (" %s\n", |
396 |
copykeylist[key_n]); |
397 |
printf ("\nprocessing %d record(s) in series %s:\n", rgnct, inser); |
398 |
} |
399 |
|
400 |
/* process records */ |
401 |
for (rgn = 0; rgn < rgnct; rgn++) { |
402 |
irec = irecs->records[rgn]; |
403 |
drms_sprint_rec_query (source, irec); |
404 |
|
405 |
if (!(iseg = drms_segment_lookupnum (irec, isegnum))) { |
406 |
fprintf (stderr, "Warning: could not find segment \"V\" or \"Vtrack\"\n"); |
407 |
fprintf (stderr, " in %s; skipped\n", source); |
408 |
continue; |
409 |
} |
410 |
if (iseg->info->naxis != 3) { |
411 |
fprintf (stderr, "Error: rank of data cube (%d) != 3\n", iseg->info->naxis); |
412 |
return cleanup (1, irecs, orec, orig, pspec, dispose); |
413 |
} |
414 |
if (drms_wcs_timestep (irec, 3, &tstep)) { |
415 |
dval = (double)drms_getkey_time (irec, "T_STOP", &status); |
416 |
tstep = dval - (double)drms_getkey_time (irec, "T_START", &status); |
417 |
if (tstep <= 0.0) { |
418 |
fprintf (stderr, |
419 |
"Error: insufficient key information for frequency determination\n"); |
420 |
fprintf (stderr, |
421 |
" in record %s; skipped\n", source); |
422 |
continue; |
423 |
} |
424 |
tstep /= planes - 1.0; |
425 |
} |
426 |
/* the input looks okay, open the output record */ |
427 |
orec = drms_create_record (drms_env, out_series, DRMS_PERMANENT, &status); |
428 |
if (status) { |
429 |
fprintf (stderr, |
430 |
"Error: drms_create_record returned %d for data series:\n", status); |
431 |
fprintf (stderr, " %s\n", out_series); |
432 |
return cleanup (1, irecs, orec, orig, pspec, dispose); |
433 |
} |
434 |
cols = iseg->axis[0]; |
435 |
rows = iseg->axis[1]; |
436 |
planes = iseg->axis[2]; |
437 |
area = cols * rows; |
438 |
cube = planes * area; |
439 |
xcols = 2 * ((cols + 2) / 2); |
440 |
hcols = cols / 2; |
441 |
hrows = rows / 2; |
442 |
cols_even = (cols % 2) ? 0 : 1; |
443 |
rows_even = (rows % 2) ? 0 : 1; |
444 |
hplanes = planes / 2; /* possible bug if planes odd */ |
445 |
if (planes % 2) hplanes++; |
446 |
|
447 |
apodization = (double *)malloc (area * sizeof (double)); |
448 |
if (edge_outer == 0.0) { |
449 |
for (n = 0; n < area; n++) apodization[n] = 1.0; |
450 |
} else { |
451 |
r0x = hcols + 0.5 * cols_even; |
452 |
r0y = hrows + 0.5 * rows_even; |
453 |
for (row=0, n=0; row<rows; row++) { |
454 |
ry = (row - hrows + 0.5 * rows_even) / r0y; |
455 |
for (col=0; col<cols; col++) { |
456 |
rx = (col - hcols + 0.5 * cols_even) / r0x; |
457 |
r2 = rx * rx + ry * ry; |
458 |
r = sqrt (r2); |
459 |
if (edge_inner >= edge_outer) |
460 |
ra = (r < edge_outer) ? 0.0 : 1.0; |
461 |
else |
462 |
ra = (r - edge_inner) / (edge_outer - edge_inner); |
463 |
ra2 = 1.0 - ra * ra; |
464 |
apodization[n++] = (ra >= 1.0) ? 0.0 : (ra <= 0.0) ? 1.0 : ra2 * ra2; |
465 |
} |
466 |
} |
467 |
} |
468 |
/* Initialize FFT working space */ |
469 |
if (dp_calc) { |
470 |
wdata = (double *)malloc (planes * rows * xcols * sizeof (double)); |
471 |
plan = fftw_plan_dft_r2c_3d (planes, rows, cols, wdata, |
472 |
(fftw_complex *)wdata, FFTW_ESTIMATE); |
473 |
} else { |
474 |
xdata = (float *)malloc (planes * rows * xcols * sizeof (float)); |
475 |
fplan = fftwf_plan_dft_r2c_3d (planes, rows, cols, xdata, |
476 |
(fftwf_complex *)xdata, FFTW_ESTIMATE); |
477 |
} |
478 |
/* add the argument values to header */ |
479 |
if (planes < 2) apode_edge = 2.0; |
480 |
bigcube = 0; |
481 |
if (cube > 838860800) { |
482 |
fprintf (stderr, |
483 |
"Warning: call to drms_segment_read() may fail for %lld values\n", |
484 |
cube); |
485 |
fprintf (stderr, " or results may be garbage\n"); |
486 |
bigcube = 1; |
487 |
/* |
488 |
orig = read_big_cube (iseg, DRMS_TYPE_FLOAT, &status); |
489 |
*/ |
490 |
if (dp_calc) |
491 |
read_from_big_cube (iseg, dp_calc, wdata, &dataavg, &datavar, |
492 |
apode_edge, apodization, xcols); |
493 |
else |
494 |
read_from_big_cube (iseg, dp_calc, xdata, &dataavg, &datavar, |
495 |
apode_edge, apodization, xcols); |
496 |
} else { |
497 |
orig = drms_segment_read (iseg, DRMS_TYPE_FLOAT, &status); |
498 |
if (status) { |
499 |
fprintf (stderr, "Error on drms_segment_read in\n"); |
500 |
fprintf (stderr, " %s\n", source); |
501 |
return cleanup (1, irecs, orec, orig, pspec, dispose); |
502 |
} |
503 |
l = m = n = 0; |
504 |
dataavg = datavar = 0.0; |
505 |
data = (float *)orig->data; |
506 |
for (plane = 0; plane < planes; plane++) { |
507 |
if (apode_edge < 1.0) { |
508 |
t = (2.0 * plane) / (planes - 1.0); |
509 |
if (t > 1.0) t = 2.0 - t; |
510 |
t = 1.0 - t; |
511 |
if (t > apode_edge) { |
512 |
t = (t - apode_edge) / (1.0 - apode_edge); |
513 |
t *= t; |
514 |
weight = (1.0 - t); |
515 |
weight *= weight; |
516 |
} else weight = 1.0; |
517 |
} else weight = 1.0; |
518 |
if (dp_calc) { |
519 |
for (row = 0; row < rows; row++) { |
520 |
for (col = 0; col < cols; col++) { |
521 |
dval = data[m++]; |
522 |
if (isnan (dval)) dval = 0.0; |
523 |
dval *= weight * apodization[l++]; |
524 |
dataavg += dval; |
525 |
datavar += dval * dval; |
526 |
wdata[n++] = dval; |
527 |
} |
528 |
n += xcols - cols; |
529 |
} |
530 |
} else { |
531 |
for (row = 0; row < rows; row++) { |
532 |
for (col = 0; col < cols; col++) { |
533 |
fval = data[m++]; |
534 |
if (isnan (fval)) fval = 0.0; |
535 |
fval *= weight * apodization[l++]; |
536 |
dataavg += fval; |
537 |
datavar += fval * fval; |
538 |
xdata[n++] = fval; |
539 |
} |
540 |
n += xcols - cols; |
541 |
} |
542 |
} |
543 |
l = 0; |
544 |
} |
545 |
drms_free_array (orig); |
546 |
} |
547 |
/* necessary for cleanup */ |
548 |
orig = NULL; |
549 |
dataavg /= m; |
550 |
datavar /= m; |
551 |
datavar -= dataavg * dataavg; |
552 |
/* forward Fourier transform */ |
553 |
if (dp_calc) fftw_execute (plan); |
554 |
else fftwf_execute (fplan); |
555 |
/* Create output data set */ |
556 |
axes[0] = cols; |
557 |
axes[1] = rows; |
558 |
opln = (fbins > 1) ? hplanes / fbins : hplanes; |
559 |
if (fbins > 1 && hplanes % fbins) opln++; |
560 |
axes[2] = opln; /* possible bug if planes odd */ |
561 |
ntot = cols * rows * opln; |
562 |
data = (float *)malloc (ntot * sizeof (float)); |
563 |
/* copy designated keywords from input */ |
564 |
kstat = 0; |
565 |
for (key_n = 0; key_n < propct; key_n++) { |
566 |
if (strcmp (copykeylist[key_n], "+")) |
567 |
kstat += check_and_copy_key (orec, irec, copykeylist[key_n]); |
568 |
else kstat += propagate_keys (orec, irec, propagate, keyct); |
569 |
} |
570 |
/* |
571 |
kstat = propagate_keys (orec, irec, propagate, keyct); |
572 |
*/ |
573 |
dval = drms_getkey_double (irec, "CDELT3", &status); |
574 |
if (!status) kstat += check_and_set_key_float (orec, "Cadence", dval); |
575 |
/* and set new ones */ |
576 |
crpix = 0.5 * (cols + 1); |
577 |
kstat += check_and_set_key_float (orec, "CRPIX1", crpix); |
578 |
if (cols != rows) crpix = 0.5 * (rows + 1); |
579 |
kstat += check_and_set_key_float (orec, "CRPIX2", crpix); |
580 |
crpix = 1.0; |
581 |
kstat += check_and_set_key_float (orec, "CRPIX3", crpix); |
582 |
kstat += check_and_set_key_float (orec, "CRVAL1", crval); |
583 |
kstat += check_and_set_key_float (orec, "CRVAL2", crval); |
584 |
kstat += check_and_set_key_float (orec, "CRVAL3", crval); |
585 |
kstat += check_and_set_key_str (orec, "CTYPE1", "WAVE-NUM"); |
586 |
kstat += check_and_set_key_str (orec, "CTYPE2", "WAVE-NUM"); |
587 |
kstat += check_and_set_key_str (orec, "CTYPE3", "FREQ-ANG"); |
588 |
kstat += check_and_set_key_float (orec, "Apode_k_min", edge_inner); |
589 |
kstat += check_and_set_key_float (orec, "APOD_MIN", edge_inner); |
590 |
kstat += check_and_set_key_float (orec, "Apode_k_max", edge_outer); |
591 |
kstat += check_and_set_key_float (orec, "APOD_MAX", edge_outer); |
592 |
kstat += check_and_set_key_float (orec, "Apode_f", apode_edge); |
593 |
if (kstat) { |
594 |
fprintf (stderr, "Error writing key value(s) to record in series %s:\n", |
595 |
out_series); |
596 |
fprintf (stderr, " series may not have appropriate structure;\n"); |
597 |
fprintf (stderr, " record %d skipped\n", rgn); |
598 |
continue; |
599 |
} |
600 |
|
601 |
dval = drms_getkey_double (irec, "MapScale", &status); |
602 |
if (!status) { |
603 |
/* assume cols = rows! */ |
604 |
dval = 360.0 / dval / cols; /* k (inv radian) */ |
605 |
dval /= 696.0; /* k (inv Mm) */ |
606 |
kstat += check_and_set_key_double (orec, "CDELT1", dval); |
607 |
if (cols == rows) { |
608 |
kstat += check_and_set_key_double (orec, "CDELT2", dval); |
609 |
kstat += check_and_set_key_double (orec, "Delta_k", dval); |
610 |
} else { |
611 |
kstat += check_and_set_key_double (orec, "Delta_kx", dval); |
612 |
dval *= (double)cols / (double)rows; |
613 |
kstat += check_and_set_key_double (orec, "CDELT2", dval); |
614 |
kstat += check_and_set_key_double (orec, "Delta_ky", dval); |
615 |
} |
616 |
if (kstat) { |
617 |
fprintf (stderr, "Error writing key value(s) to record in series %s\n", |
618 |
out_series); |
619 |
fprintf (stderr, " series may not have appropriate structure\n"); |
620 |
fprintf (stderr, " record %d skipped\n", rgn); |
621 |
continue; |
622 |
} |
623 |
} |
624 |
dnu = 1.0e6 / planes / tstep; |
625 |
if (fbins > 1) dnu *= fbins; |
626 |
kstat += check_and_set_key_double (orec, "Delta_nu", dnu); |
627 |
domega = dnu * 2.0e-6 * M_PI; |
628 |
kstat += check_and_set_key_double (orec, "D_OMEGA", domega); |
629 |
kstat += check_and_set_key_double (orec, "CDELT3", domega); |
630 |
if (kstat) { |
631 |
fprintf (stderr, "Error writing key value(s) to record in series %s\n", |
632 |
out_series); |
633 |
fprintf (stderr, " series may not have appropriate structure\n"); |
634 |
fprintf (stderr, " record %d skipped\n", rgn); |
635 |
continue; |
636 |
} |
637 |
/* convert complex transform to power spectrum and reorder */ |
638 |
normal = 1.0 / ntot; |
639 |
normal *= normal; |
640 |
powrint = 0.0; |
641 |
if (fbins > 1) { |
642 |
double nfac = normal / fbins / fbins; |
643 |
for (plane = 0, n = 0; plane < hplanes; plane += fbins) { |
644 |
for (row = 0; row < rows; row++) { |
645 |
for (col = 0; col < cols; col++, n++) { |
646 |
js = (row == row % hrows) ? row + hrows : row - hrows; |
647 |
is = (col == col % hcols) ? col + hcols : col - hcols; |
648 |
ftrb = ftib = 0.0; |
649 |
for (bin = 0; bin < fbins; bin++) { |
650 |
m = (plane + bin) * xcols * rows + js * xcols + 2 * is; |
651 |
if (is >= hcols) { |
652 |
m = 2 * (cols - is); |
653 |
if (js != 0) m += (rows - js) * xcols; |
654 |
if ((plane + bin) != 0) |
655 |
m += (planes - plane - bin) * xcols * rows; |
656 |
} |
657 |
if (dp_calc) { |
658 |
ftrb += wdata[m]; |
659 |
ftib += wdata[m+1]; |
660 |
} else { |
661 |
ftrb += xdata[m]; |
662 |
ftib += xdata[m+1]; |
663 |
} |
664 |
} |
665 |
data[n] = nfac * (ftrb*ftrb + ftib*ftib); |
666 |
if (n == 0) vmax = vmin = vmin2 = data[n]; |
667 |
if (data[n] > vmax) vmax = data[n]; |
668 |
if (data[n] < vmin) { |
669 |
vmin2 = vmin; |
670 |
vmin = data[n]; |
671 |
} |
672 |
powrint += data[n]; |
673 |
} |
674 |
} |
675 |
} |
676 |
if (n > ntot) { |
677 |
fprintf (stderr, "Error: data written beyond output array bounds\n"); |
678 |
return cleanup (1, irecs, orec, orig, pspec, dispose); |
679 |
} |
680 |
} else { |
681 |
for (plane = 0, n = 0; plane < hplanes; plane++) { |
682 |
for (row = 0; row < rows; row++) { |
683 |
for (col = 0; col < cols; col++, n++) { |
684 |
js = (row == row % hrows) ? row + hrows : row - hrows; |
685 |
is = (col == col % hcols) ? col + hcols : col - hcols; |
686 |
m = plane * xcols * rows + js * xcols + 2 * is; |
687 |
if (is >= hcols) { |
688 |
m = 2 * (cols - is); |
689 |
if (js != 0) m += (rows - js) * xcols; |
690 |
if (plane != 0) m += (planes - plane) * xcols * rows; |
691 |
} |
692 |
data[n] = (dp_calc) ? |
693 |
wdata[m]*wdata[m] + wdata[m+1]*wdata[m+1] : |
694 |
xdata[m]*xdata[m] + xdata[m+1]*xdata[m+1]; |
695 |
data[n] *= normal; |
696 |
if (n == 0) vmax = vmin = vmin2 = data[n]; |
697 |
if (data[n] > vmax) vmax = data[n]; |
698 |
if (data[n] < vmin) { |
699 |
vmin2 = vmin; |
700 |
vmin = data[n]; |
701 |
} |
702 |
powrint += data[n]; |
703 |
} |
704 |
} |
705 |
} |
706 |
} |
707 |
if (dp_calc) free (wdata); |
708 |
else free (xdata); |
709 |
|
710 |
if (verbose) { |
711 |
printf (" P[0] = %11.4e (cf. apodized data mean = %11.4e)\n", |
712 |
data[cols * hrows + hcols], dataavg); |
713 |
printf (" S(P) = %11.4e (cf. apodized data var. = %11.4e)\n", powrint, datavar); |
714 |
} |
715 |
|
716 |
oseg = drms_segment_lookupnum (orec, osegnum); |
717 |
if (verbose) printf (" values range from %.3e to %.3e\n", vmin, vmax); |
718 |
if (log_out) { |
719 |
/* |
720 |
double target_min = vmax / exp (scale_range); |
721 |
printf ("vmin = %.4e <? target_min = %.4e / %.4e = %.4e\n", vmin, vmax, |
722 |
exp(scale_range), target_min); |
723 |
*/ |
724 |
if (vmin < 0.1 * vmin2) { |
725 |
fprintf (stderr, |
726 |
"** Warning: minimum value = %.2e; value = log (%.2e + data)\n", |
727 |
vmin, vmin2); |
728 |
for (n = 0; n < ntot; n++) data[n] = log (vmin2 + data[n]); |
729 |
vmin = log (vmin2 + vmin); |
730 |
vmax = log (vmin2 + vmax); |
731 |
} else { |
732 |
for (n = 0; n < ntot; n++) data[n] = log (data[n]); |
733 |
vmin = log (vmin); |
734 |
vmax = log (vmax); |
735 |
} |
736 |
if (verbose) printf (" logs scaled between %f and %f\n", vmin, vmax); |
737 |
kstat += check_and_set_key_double (orec, "LOG_BASE", exp (1.0)); |
738 |
} |
739 |
|
740 |
kstat += check_and_set_key_float (orec, "DataMin", vmin); |
741 |
kstat += check_and_set_key_float (orec, "DataMax", vmax); |
742 |
kstat += check_and_set_key_str (orec, "Module", module_ident); |
743 |
kstat += check_and_set_key_str (orec, "BLD_VERS", jsoc_version); |
744 |
kstat += check_and_set_key_str (orec, "Source", source); |
745 |
kstat += check_and_set_key_str (orec, "Input", inser); |
746 |
kstat += check_and_set_key_time (orec, "Created", CURRENT_SYSTEM_TIME); |
747 |
if (kstat) { |
748 |
fprintf (stderr, "Error writing key value(s) to record in series %s\n", |
749 |
out_series); |
750 |
fprintf (stderr, " series may not have appropriate structure\n"); |
751 |
fprintf (stderr, " record %d skipped\n", rgn); |
752 |
continue; |
753 |
} |
754 |
bscale = (vmax - vmin) / scale_range; |
755 |
bzero = 0.5 * (vmax + vmin); |
756 |
pspec = drms_array_create (DRMS_TYPE_FLOAT, 3, axes, data, &status); |
757 |
if (status) { |
758 |
fprintf (stderr, "Error: couldn't create output array\n"); |
759 |
return cleanup (1, irecs, orec, orig, pspec, dispose); |
760 |
} |
761 |
pspec->bscale = bscale; |
762 |
pspec->bzero = bzero; |
763 |
if (bigcube) { |
764 |
fprintf (stderr, |
765 |
"Warning: call to drms_segment_write() may fail for %lld values\n", |
766 |
ntot); |
767 |
fprintf (stderr, " or results may be garbage\n"); |
768 |
} |
769 |
status = drms_segment_write (oseg, pspec, 0); |
770 |
if (status) { |
771 |
drms_sprint_rec_query (recid, orec); |
772 |
fprintf (stderr, "Error writing data to record %s\n", recid); |
773 |
fprintf (stderr, " series may not have appropriate structure\n"); |
774 |
return cleanup (1, irecs, orec, orig, pspec, dispose); |
775 |
} |
776 |
drms_free_array (pspec); |
777 |
pspec = NULL; |
778 |
|
779 |
if (verbose) { |
780 |
drms_sprint_rec_query (recid, orec); |
781 |
if (no_save) |
782 |
printf ("output data record would be %s\n", recid); |
783 |
else { |
784 |
drms_segment_filename (oseg, pathname); |
785 |
printf ("output data record is %s\n", recid); |
786 |
printf ("output data cube at %s\n", pathname); |
787 |
} |
788 |
} |
789 |
drms_close_record (orec, dispose); |
790 |
} |
791 |
/* Clean up FFTW stuff */ |
792 |
fftwf_destroy_plan (fplan); |
793 |
/* this is kind of silly, why not just remove error argument from cleanup? */ |
794 |
return cleanup (0, irecs, NULL, orig, pspec, dispose); |
795 |
} |
796 |
|
797 |
/* |
798 |
* Revision History (all mods by Rick Bogart unless otherwise noted) |
799 |
* |
800 |
* 08.03.24 created this file, based on SOI powrspec3_v20 |
801 |
* v 0.6 frozen 2009.07.14 |
802 |
* v 0.7: fix to run with NetDRMS 2.0 (09.07.14); |
803 |
* Modify and add to list of keywords copied from input |
804 |
* v 0.7 frozen 2009.09.08.05 |
805 |
* v 0.8: general code cleanup; added copying of all standard (and |
806 |
* additional "standard") keys; |
807 |
* removed defaults for I/O; |
808 |
* removed CGI output and special processing for exports; |
809 |
* fixed bug in setting of CDELT3 and associated keywords; |
810 |
* modified key copying to use list and to be more careful; |
811 |
* added setting of Cadence keywords from input CDELT3; |
812 |
* put in (approximately) correct normalization; |
813 |
* generalized scaling of logs (and direct values) for output |
814 |
* precision |
815 |
* added looping over multiple input and output records |
816 |
* added no_save option for diagnostics |
817 |
* v 0.8 frozen 2010.01.18 |
818 |
* v 0.9: fixed use of params_get_str |
819 |
* added setting of several keys: bld_vers, created |
820 |
* added setting of keys APOD_MIN, APOD_MAX |
821 |
* added Width & Height to and removed Cadence from default |
822 |
* propagation list |
823 |
* added optional segment argument and removed restriction on |
824 |
* its name |
825 |
* added warning about large input cubes |
826 |
* v 0.9 frozen 2010.04.23 |
827 |
* v 1.0 Added code for reading and apodizing large cubes by slices; |
828 |
* however, there is still a problem with the memory required for the |
829 |
* output array at the same time the complex array is in place |
830 |
* Removed an extraneous keyword propagation |
831 |
* Added Ident to list of default propagated keywords; added option |
832 |
* for providing alternate or additional list of keywords for propagation |
833 |
* v 1.0 frozen 2010.08.19 |
834 |
* v 1.1 Removed some old commented out code |
835 |
* Fixed bug in test for minimum values out of scaling range (zero) |
836 |
* v 1.1 frozen 2012.12.24 |
837 |
* |
838 |
*/ |