ViewVC Help
View File | Revision Log | Show Annotations | Root Listing
root/JSOC/proj/rings/apps/pspec3.c
Revision: 1.4
Committed: Mon Apr 8 22:27:55 2013 UTC (10 years, 5 months ago) by rick
Content type: text/plain
Branch: MAIN
CVS Tags: Ver_9-1, Ver_9-3, Ver_9-2, Ver_8-8, Ver_8-2, Ver_8-3, Ver_8-0, Ver_8-1, Ver_8-6, Ver_8-7, Ver_8-4, Ver_8-5, Ver_8-10, Ver_8-11, Ver_8-12, Ver_9-0
Changes since 1.3: +25 -40 lines
Log Message:
modified for JSOC release 8.0

File Contents

# Content
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, ',', &copykeylist);
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 */