ViewVC Help
View File | Revision Log | Show Annotations | Root Listing
root/JSOC/proj/util/apps/jsoc_rebin.c
Revision: 1.21
Committed: Mon Jul 17 16:45:23 2017 UTC (6 years, 2 months ago) by kehcheng
Content type: text/plain
Branch: MAIN
CVS Tags: Ver_9-1, Ver_LATEST, Ver_9-3, Ver_9-41, Ver_9-2, Ver_9-5, Ver_9-4
Changes since 1.20: +10 -1 lines
Log Message:
fix upNcenter() for images with odd number of rows

File Contents

# Content
1 /**
2 @defgroup jsoc_rebin jsoc_rebin reduce/increase image size by integer multiples
3 @ingroup su_util
4
5 @brief Reduce (increase) the dimension of the input data by an integer factor.
6
7 @par Synopsis:
8 @code
9 jsoc_rebin in=input_data out=output_data scale=<scale> method={boxcar,gaussian}
10 where scale is <1 for size reduction and >1 for size increase. The output image scale
11 will be the nearest integer to "scale" or its reciprocal for scale < 1.0.
12 @endcode
13
14 This is a general purpose module that takes a series of input
15 data and modifies its spatial size by a factor
16 specified by "scale".
17 The method for avaraging (interpolation) can be specified
18 through the input "method". The current version handles a simple
19 boxcar average and Gaussian filtered sampling. If 'scale' < 1 then the input is reduced in size.
20
21 The image is not registered to solar center by this module. The image will be rotated by
22 a flip-flip procedure is the CROTA2 parameter is near +-180.0 unless the -u flag (unchanged) is
23 present. If the -c flag is present the image will be cropped at the solar limb before scaling.
24 If the -h flag or requestid parameter is present the output segments will have full headers.
25
26 If gaussian smoothing is specified (via method) then the FWHM and nvector parameters should also
27 be provided. These define the Gaussian smoothing vector. nvector is the full width of the
28 smoothing function. nvector will be adjusted such that nvector is odd if 1/scale rounds to an odd integer.
29
30 @par Flags:
31 @c
32 -A Process all segments
33 -c Crop before scaling. Use rsun_obs/cdelt1 for limb radius.
34 -h Write full FITS headers.
35 -u Leave unchanged, do NOT rotate by 180 degrees if CROTA2 is near 180. default is to do flip-flip method so
36 image is norths up and no pixel values are changed.
37
38 @par GEN_FLAGS:
39 Ubiquitous flags present in every module.
40 @ref jsoc_main
41
42 @param in The input data series.
43 @param out The output series.
44
45 @par Exit_Status:
46
47 @par Example:
48 Takes a series of 1024 X 1024 MDI full disk magnetogram and
49 produces images with the resolution of HMI, 4096 X 4096.
50
51 @code
52 jsoc_rebin in='mdi.fd_M_96m_lev18[2003.10.20/1d]' out='su_phil.mdi_M_4k' scale=4 method='boxcar'
53 @endcode
54
55 @par Example:
56 Reduces the resolution of HMI images 4096 X 4096 to that of MDI,
57 1024 X 1024. Here the input is the HMI images and the output
58 is the lower resolution HMI images. Crop and rotate before rescaling.
59 @code
60 jsoc_rebin -c in=hmi.M_45s[2011.10.20/1d]' out='su_phil.hmi_M_1k_45s' scale=0.25 method='boxcar'
61 @endcode
62
63 @bug
64 None known so far.
65
66 */
67
68 #include "jsoc.h"
69 #include "jsoc_main.h"
70 #include "fstats.h"
71
72 char *module_name = "jsoc_rebin";
73
74 #define DIE(msg) {fflush(stdout);fprintf(stderr,"%s, status=%d\n",msg,status); return(status);}
75
76 ModuleArgs_t module_args[] =
77 {
78 {ARG_STRING, "in", "NOT SPECIFIED", "Input data series."},
79 {ARG_STRING, "out", "NOT SPECIFIED", "Output data series."},
80 {ARG_FLAG, "A", "0", "Process all segments in the input series"},
81 {ARG_FLAG, "c", "0", "Crop at rsun_obs."},
82 {ARG_FLAG, "h", "0", "Include full FITS header in output segment."},
83 {ARG_FLAG, "u", "0", "do not rotate by 180 if needed."},
84 {ARG_FLOAT, "scale", "1.0", "Scale factor."},
85 {ARG_FLOAT, "FWHM", "-1.0", "Smoothing Gaussian FWHM for method=gaussian."},
86 {ARG_INT, "nvector", "-1.0", "Smoothing Gaussian vector length for method=gaussian."},
87 {ARG_INT, "inseg", "-1", "Input segment number"},
88 {ARG_INT, "outseg", "-1", "Output segment number"},
89 {ARG_STRING, "method", "boxcar", "conversion type, one of: boxcar, gaussian."},
90 {ARG_STRING, "requestid", "NA", "RequestID if called as an export processing step."},
91 {ARG_END}
92 };
93
94 #define Deg2Rad (M_PI/180.0)
95 #define Rad2arcsec (3600.0/Deg2Rad)
96 #define arcsec2Rad (Deg2Rad/3600.0)
97 #define Rad2Deg (180.0/M_PI)
98
99 struct ObsInfo_struct
100 {
101 // from observation info
102 TIME t_obs;
103 double rsun_obs, obs_vr, obs_vw, obs_vn;
104 double crpix1, crpix2, cdelt1, cdelt2, crota2;
105 double crval1, crval2;
106 double cosa, sina;
107 double obs_b0;
108 // observed point
109 int i,j;
110 // parameters for observed point
111 double x,y,r;
112 double rho;
113 double lon;
114 double lat;
115 double sinlat, coslat;
116 double sig;
117 double mu;
118 double chi;
119 double obs_v;
120 };
121
122 typedef struct ObsInfo_struct ObsInfo_t;
123
124 void rebinArraySF(DRMS_Array_t *out, DRMS_Array_t *in);
125 int upNcenter(DRMS_Array_t *arr, ObsInfo_t *ObsLoc);
126 int crop_image(DRMS_Array_t *arr, ObsInfo_t *ObsLoc);
127 const char *get_input_recset(DRMS_Env_t *drms_env, const char *in);
128
129 ObsInfo_t *GetObsInfo(DRMS_Segment_t *seg, ObsInfo_t *pObsLoc, int *rstatus);
130 ObsInfo_t *GetMinObsInfo(DRMS_Segment_t *seg, ObsInfo_t *pObsLoc, int *rstatus);
131
132 int DoIt(void)
133 {
134 int status = DRMS_SUCCESS;
135 DRMS_RecordSet_t *inRS, *outRS;
136 int irec, nrecs;
137 const char *inQuery = params_get_str(&cmdparams, "in");
138 char *inStr;
139 const char *outSeries = params_get_str(&cmdparams, "out");
140 const char *method = params_get_str(&cmdparams, "method");
141 const char *requestid = params_get_str(&cmdparams, "requestid");
142 int nvector = params_get_int(&cmdparams, "nvector");
143 float fscale = params_get_float(&cmdparams, "scale");
144 float fwhm = params_get_float(&cmdparams, "FWHM");
145 int crop = params_get_int(&cmdparams, "c");
146 int as_is = params_get_int(&cmdparams, "u");
147 int wantAllSegs = params_get_int(&cmdparams, "A");
148 int inseg = params_get_int(&cmdparams, "inseg");
149 int outseg = params_get_int(&cmdparams, "outseg");
150 int full_header = params_get_int(&cmdparams, "h") || strcmp(requestid, "NA");
151 char *in_filename = NULL;
152 DRMS_Record_t *template = NULL;
153 int firstNx = 0, firstNy = 0, firstNaxis = 0;
154 int wantSeg = 1;
155
156 int iscale, ivec, vec_half;
157 double *vector;
158 char history[4096];
159
160 if (fscale < 1.0) // shrinking
161 iscale = 1.0/fscale + 0.5;
162 else // enlarging
163 iscale = fscale + 0.5;
164 if (nvector < 0)
165 nvector = iscale;
166 // Both 1/scale and nvector must be odd or both even so add 1 to nvector if needed
167 if (((iscale & 1) && !(nvector & 1)) || ((!(iscale & 1) && (nvector & 1) )))
168 nvector += 1;
169 vector = (double *)malloc(nvector * sizeof(double));
170 vec_half = nvector/2; // counts on truncate to int if nvector is odd.
171
172 if (strcasecmp(method, "boxcar")==0 && fscale < 1)
173 {
174 for (ivec = 0; ivec < nvector; ivec++)
175 vector[ivec] = 1.0;
176 sprintf(history, "Boxcar bin by %d%s%s",
177 iscale,
178 (crop ? ", Cropped at rsun_obs" : ""),
179 (!as_is ? ", North is up" : "") );
180 }
181 else if (strcasecmp(method, "boxcar")==0 && fscale >= 1)
182 {
183 if (nvector != iscale)
184 DIE("For fscale>=1 nvector must be fscale");
185 for (ivec = 0; ivec < nvector; ivec++)
186 vector[ivec] = 1.0;
187 sprintf(history, "Replicate to expand by %d%s%s",
188 iscale,
189 (crop ? ", Cropped at rsun_obs" : ""),
190 (!as_is ? ", North is up" : "") );
191 }
192 else if (strcasecmp(method, "gaussian")==0) // do 2-D vector weights calculated as Gaussian
193 {
194 if (fwhm < 0)
195 DIE("Need FWHM parameter");
196 for (ivec = 0; ivec < nvector; ivec++)
197 {
198 double arg = (ivec - (nvector-1)/2.0) * (ivec - (nvector-1)/2.0);
199 vector[ivec] = exp(-arg/(fwhm*fwhm*0.52034));
200 }
201 sprintf(history, "Scale by %f with Gasussian smoothing FWHM=%f, nvector=%d%s%s",
202 fscale, fwhm, nvector,
203 (crop ? ", Cropped at rsun_obs" : ""),
204 (!as_is ? ", North is up" : "") );
205 }
206 else
207 DIE("invalid conversion method");
208
209 printf(history);
210
211 inStr = strdup(get_input_recset(drms_env, (char *)inQuery));
212 if (!inStr || *inStr=='\0') DIE("Cant make special cadence recordset list file");
213 inRS = drms_open_records(drms_env, inStr, &status);
214 if (strcmp(inStr, inQuery) && *inStr == '@')
215 unlink(inStr+1);
216 if (status || inRS->n == 0)
217 DIE("No input data found");
218
219 nrecs = inRS->n;
220 if (nrecs == 0)
221 DIE("No records found");
222 drms_stage_records(inRS, 1, 1);
223
224 outRS = drms_create_records(drms_env, nrecs, (char *)outSeries, DRMS_PERMANENT, &status);
225 if (status)
226 DIE("Output recordset not created");
227
228 int iSet;
229 int iSubRec;
230 int nSubRecs = 0;
231
232 /* We need the record-set specfication for each record, so loop by recordset subset. */
233 for (iSet = 0, irec = 0; iSet < inRS->ss_n; iSet++)
234 {
235 int hasSeglist = wantAllSegs ? 1 : 0;
236
237 /* For each record, we need to know if the segments it contains came from a record-set specification that had a segment list.
238 * To do that, we have to search for '{' in the specification that resolved to this record. So we need the spec for this record,
239 * which is in inRS->ss_queries[iSet]. */
240 if (strchr(inRS->ss_queries[iSet], '{'))
241 {
242 hasSeglist = 1;
243 }
244
245 nSubRecs = drms_recordset_getssnrecs(inRS, iSet, &status);
246
247 for (iSubRec = 0; iSubRec < nSubRecs; iSubRec++, irec++)
248 {
249 ObsInfo_t *ObsLoc;
250 DRMS_Record_t *outRec, *inRec;
251 DRMS_Segment_t *outSeg, *inSeg;
252 DRMS_Segment_t *orig = NULL;
253 DRMS_Array_t *inArray, *outArray;
254 float *inData, *outData;
255 float val;
256 int quality=0;
257
258 inRec = inRS->records[(inRS->ss_starts)[iSet] + iSubRec];
259
260 quality = drms_getkey_int(inRec, "QUALITY", &status);
261 if (status || (!status && quality >= 0))
262 {
263 /* Segment loop. */
264 HIterator_t *segIter = NULL;
265
266 while ((inSeg = drms_record_nextseg2(inRec, &segIter, 1, &orig)) != NULL)
267 {
268 /* A segment can only be processed if it is dimension 2 and if not first segment has same dimension
269 * as first segment.
270 */
271 if (inseg >= 0)
272 {
273 /* This module was called with the inseg argument (which is the input series' segment number).
274 * Process only that segment. But inSeg could be a linked segment, so we have to obtain the
275 * segment struct in the original series. There is no pointer from the linked segment to
276 * the original segment. And we do not have the name or number of the original segment. Or we
277 * didn't, so I made drms_record_nextseg2(). */
278 if (orig->info->segnum != inseg)
279 {
280 /* Skip this segment. It isn't the one the caller has requested. */
281 continue;
282 }
283 }
284 wantSeg = 1; // start by assuming OK
285
286 inArray = drms_segment_read(inSeg, DRMS_TYPE_FLOAT, &status);
287 if (status)
288 {
289 printf(" No data file found but QUALITY not bad, status=%d\n", status);
290 drms_free_array(inArray);
291 continue;
292 }
293 int inx, iny, outx, outy, i, j;
294 int in_nx = inArray->axis[0];
295 int in_ny = inArray->axis[1];
296 int out_nx = in_nx * fscale + 0.5;
297 int out_ny = in_ny * fscale + 0.5;
298 int outDims[2] = {out_nx, out_ny};
299 if (firstNaxis == 0)
300 {
301 if (inArray->naxis != 2)
302 wantSeg = 0; // Skip segment if not 2 axes. mark for skip below
303 else
304 {
305 firstNaxis = inArray->naxis;
306 firstNx = in_nx;
307 firstNy = in_ny;
308 }
309 }
310 if (inArray->naxis != firstNaxis || in_nx != firstNx || in_ny != firstNy)
311 { // this segment now wanted, if no segment list provided, copy this segment as-is
312 wantSeg = 0;
313 }
314
315 if (wantSeg && (crop || !as_is))
316 {
317 ObsLoc = GetObsInfo(inSeg, NULL, &status);
318 if (!as_is) upNcenter(inArray, ObsLoc);
319 if (crop) crop_image(inArray, ObsLoc);
320 }
321 else if (wantSeg)
322 {
323 ObsLoc = GetMinObsInfo(inSeg, NULL, &status);
324 }
325
326 if (wantSeg)
327 {
328 inData = (float *)inArray->data;
329 outArray = drms_array_create(DRMS_TYPE_FLOAT, 2, outDims, NULL, &status);
330 outData = (float *)outArray->data;
331 }
332
333 if (wantSeg && fscale > 1.0)
334 {
335 int out_go = (iscale-1)/2.0 + 0.5;
336 for (iny = 0; iny < in_ny; iny += 1)
337 for (inx = 0; inx < in_nx; inx += 1)
338 {
339 val = inData[in_nx*iny + inx];
340 for (j = 0; j < nvector; j += 1)
341 {
342 outy = iny*iscale + out_go + j - vec_half;
343 for (i = 0; i < nvector; i += 1)
344 {
345 outx = inx*iscale + out_go + i - vec_half;
346 if (outx >= 0 && outx < out_nx && outy >= 0 && outy < out_ny)
347 outData[out_nx*outy + outx] = val;
348 }
349 }
350 }
351 }
352 else if (wantSeg)
353 {
354 int in_go = (iscale-1)/2.0 + 0.5;
355 for (outy = 0; outy < out_ny; outy += 1)
356 for (outx = 0; outx < out_nx; outx += 1)
357 {
358 double total = 0.0;
359 double weight = 0.0;
360 int nn = 0;
361 for (j = 0; j < nvector; j += 1)
362 {
363 iny = outy*iscale + in_go + j - vec_half;
364 for (i = 0; i < nvector; i += 1)
365 {
366 inx = outx*iscale + in_go + i - vec_half;
367 if (inx >= 0 && inx < in_nx && iny >=0 && iny < in_ny)
368 {
369 val = inData[in_nx*(iny) + inx];
370 if (!drms_ismissing_float(val))
371 {
372 double w = vector[i]*vector[j];
373 total += w*val;
374 weight += w;
375 nn++;
376 }
377 }
378 }
379 }
380 outData[out_nx*outy + outx] = (nn > 0 ? total/weight : DRMS_MISSING_FLOAT);
381 }
382 }
383
384
385 // write data file
386 outRec = outRS->records[irec];
387
388 /* The original intent was for the output series' segments to parallel the input series' segments.
389 * However, the names were allowed to vary. So the segment descriptions match, and they are in the
390 * same order. However, the names given to these descriptions might vary. Therefore, we need to
391 * look-up output segments by segment number, not name.
392 *
393 * If outseg was provided in the arguments, use that. Otherwise, use the segment number of the input
394 * segment (the original input segment, in case a link was followed).
395 */
396 outSeg = drms_segment_lookupnum(outRec, (outseg >= 0) ? outseg : orig->info->segnum);
397
398 if (!outSeg)
399 {
400 DIE("Unable to look-up output segment.");
401 }
402
403 // copy all keywords
404 drms_copykeys(outRec, inRec, 0, kDRMS_KeyClass_Explicit);
405
406 // Now fixup coordinate keywords
407 // Only CRPIX1,2 and CDELT1,2 and CROTA2 should need repair.
408 drms_setkey_double(outRec, "CDELT1", ObsLoc->cdelt1/fscale);
409 drms_setkey_double(outRec, "CDELT2", ObsLoc->cdelt2/fscale);
410 drms_setkey_double(outRec, "CRPIX1", (ObsLoc->crpix1-0.5) * fscale + 0.5);
411 drms_setkey_double(outRec, "CRPIX2", (ObsLoc->crpix2-0.5) * fscale + 0.5);
412 drms_setkey_double(outRec, "CROTA2", ObsLoc->crota2);
413
414 if (strcasecmp(method, "gaussian")==0)
415 drms_setkey_double(outRec, "FWHM", fwhm);
416 drms_appendhistory(outRec, history, 1);
417 drms_setkey_time(outRec, "DATE", CURRENT_SYSTEM_TIME);
418 if (strcmp(requestid, "NA") != 0)
419 drms_setkey_string(outRec, "RequestID", requestid);
420
421
422 if (!wantSeg)
423 {
424 drms_free_array(inArray);
425 inArray = drms_segment_read(inSeg,DRMS_TYPE_RAW,&status);
426 if (!inArray || status)
427 DIE("Problem reading ancillary array");
428 status = drms_segment_write(outSeg, inArray, 0);
429 if (status)
430 DIE("Problem writing ancillary array");
431 drms_free_array(inArray);
432 }
433 else
434 {
435 // get info for array from input segment
436 outArray->parent_segment = outSeg;
437
438 drms_setkey_int(outRec, "TOTVALS", out_nx*out_ny);
439 set_statistics(outSeg, outArray, 1);
440
441 // Use the input array as the best guess for scale and zero
442 outArray->bzero = inArray->bzero;
443 outArray->bscale = inArray->bscale;
444
445 drms_free_array(inArray);
446 if (full_header)
447 status = drms_segment_writewithkeys(outSeg, outArray, 0);
448 else
449 status = drms_segment_write(outSeg, outArray, 0);
450 if (status)
451 DIE("problem writing file");
452 drms_free_array(outArray);
453 }
454
455 if (inseg >= 0)
456 {
457 /* The caller requested the processing of a single segment. Exit loop. */
458 break;
459 }
460
461 /* If the user did not provide a segment specifier (which means that all segment structs are in the rec->segments container,
462 * and there was no seglist), then process only the first segment. */
463 if (inRec->seriesinfo && *inRec->seriesinfo->seriesname)
464 {
465 template = drms_template_record(drms_env, inRec->seriesinfo->seriesname, &status);
466 }
467 else
468 {
469 template = NULL;
470 }
471
472 if (status || !template)
473 {
474 DIE("Cannot obtain DRMS-record template.");
475 }
476
477 if (drms_record_numsegments(inRec) == drms_record_numsegments(template) && !hasSeglist)
478 {
479 break;
480 }
481 } // end of segment loop
482
483 if (segIter)
484 {
485 hiter_destroy(&segIter);
486 }
487 } // record quality check
488 }
489 } //end of "irec" loop
490
491 drms_close_records(inRS, DRMS_FREE_RECORD);
492 drms_close_records(outRS, DRMS_INSERT_RECORD);
493 return (DRMS_SUCCESS);
494 } // end of DoIt
495
496 // ----------------------------------------------------------------------
497
498 /* center whith whole pixel shifts and rotate by 180 if needed */
499 /* Only apply center if it will not result in an image crop. I.e. not ever
500 for AIA, and not for HMI or MDI or other if a shift of more than 20 arcsec
501 is implied */
502 int upNcenter(DRMS_Array_t *arr, ObsInfo_t *ObsLoc)
503 {
504 int nx, ny, ix, iy, i, j, xoff, yoff, max_off;
505 double rot, x0, y0, midx, midy;
506 float *data;
507 float *data2;
508 if (!arr || !ObsLoc)
509 return(1);
510 data = arr->data;
511 nx = arr->axis[0];
512 ny = arr->axis[1];
513 x0 = ObsLoc->crpix1 - 1;
514 y0 = ObsLoc->crpix2 - 1;
515 midx = (nx-1.0)/2.0;
516 midy = (ny-1.0)/2.0;
517 if ((rot = fabs(ObsLoc->crota2)) > 179 && rot < 181)
518 {
519 // rotate image by 180 degrees by a flip flip
520 float val;
521 int half = ny / 2;
522 int odd = ny & 1;
523 for (iy=0; iy<half; iy++)
524 {
525 for (ix=0; ix<nx; ix++)
526 {
527 i = iy*nx + ix;
528 j = (ny - 1 - iy)*nx + (nx - 1 - ix);
529 val = data[i];
530 data[i] = data[j];
531 data[j] = val;
532 }
533 }
534 // reverse middle row if ny is odd
535 if (odd) {
536 for (ix=0; ix<nx/2; ++ix) {
537 i = nx*half + ix;
538 j = nx*half + nx - ix - 1;
539 val = data[i];
540 data[i] = data[j];
541 data[j] = val;
542 }
543 }
544 x0 = nx - 1 - x0;
545 y0 = ny - 1 - y0;
546 rot = ObsLoc->crota2 - 180.0;
547 if (rot < -90.0) rot += 360.0;
548 ObsLoc->crota2 = rot;
549 }
550 // Center to nearest pixel - if OK to do so
551 xoff = round(x0 - midx);
552 yoff = round(y0 - midy);
553 max_off = 20.0 / ObsLoc->cdelt1;
554 if (arr->parent_segment &&
555 arr->parent_segment->record &&
556 arr->parent_segment->record->seriesinfo &&
557 arr->parent_segment->record->seriesinfo->seriesname &&
558 strncasecmp(arr->parent_segment->record->seriesinfo->seriesname, "aia", 3) &&
559 abs(xoff) < max_off && abs(yoff) < max_off)
560 {
561 if (abs(xoff) >= 1 || abs(yoff) >= 1)
562 {
563 data2 = malloc(4*nx*ny);
564 for (iy=0; iy<ny; iy++)
565 {
566 int jy = iy + yoff;
567 for (ix=0; ix<nx; ix++)
568 {
569 int jx = ix + xoff;
570 int idx = jy*nx + jx;
571 int idx2 = iy*nx + ix;
572 if (jx<0 || jx>=nx || jy<0 || jy>=ny)
573 data2[idx2] = DRMS_MISSING_FLOAT;
574 else
575 data2[idx2] = data[idx];
576 }
577 }
578 x0 -= xoff;
579 y0 -= yoff;
580 free(data);
581 arr->data = data2;
582 }
583 }
584 // update center location
585 ObsLoc->crpix1 = x0 + 1;
586 ObsLoc->crpix2 = y0 + 1;
587 return(0);
588 }
589
590 // ----------------------------------------------------------------------
591
592 int crop_image(DRMS_Array_t *arr, ObsInfo_t *ObsLoc)
593 {
594 int nx, ny, ix, iy, i, j, xoff, yoff;
595 double x0, y0;
596 double rsun = ObsLoc->rsun_obs/ObsLoc->cdelt1;
597 double scale, crop_limit2;
598 float *data;
599 if (!arr || !ObsLoc)
600 return(1);
601 data = arr->data;
602 nx = arr->axis[0];
603 ny = arr->axis[1];
604 x0 = ObsLoc->crpix1 - 1;
605 y0 = ObsLoc->crpix2 - 1;
606 scale = 1.0/rsun;
607 // crop_limit = 0.99975; // 1 - 1/4000, 1/2 HMI pixel.
608 crop_limit2 = 0.99950; // square of 1 - 1/4000, 1/2 HMI pixel.
609 for (iy=0; iy<ny; iy++)
610 for (ix=0; ix<nx; ix++)
611 {
612 double x, y, R2;
613 float *Ip = data + iy*nx + ix;
614 if (drms_ismissing_float(*Ip))
615 continue;
616 x = ((double)ix - x0) * scale; /* x,y in pixel coords */
617 y = ((double)iy - y0) * scale;
618 R2 = x*x + y*y;
619 if (R2 > crop_limit2)
620 *Ip = DRMS_MISSING_FLOAT;
621 }
622 return(0);
623 }
624
625 // ----------------------------------------------------------------------
626
627 #define CHECK(keyname) {if (status) {fprintf(stderr,"Keyword failure to find: %s, status=%d\n",keyname,status); *rstatus=status; return(NULL);}}
628
629 ObsInfo_t *GetObsInfo(DRMS_Segment_t *seg, ObsInfo_t *pObsLoc, int *rstatus)
630 {
631 TIME t_prev;
632 DRMS_Record_t *rec;
633 TIME t_obs;
634 double dv;
635 ObsInfo_t *ObsLoc;
636 int status;
637
638 if (!seg || !(rec = seg->record))
639 { *rstatus = 1; return(NULL); }
640
641 ObsLoc = (pObsLoc ? pObsLoc : (ObsInfo_t *)malloc(sizeof(ObsInfo_t)));
642 if (!pObsLoc)
643 memset(ObsLoc, 0, sizeof(ObsInfo_t));
644
645 t_prev = ObsLoc->t_obs;
646 t_obs = drms_getkey_time(rec, "T_OBS", &status); CHECK("T_OBS");
647
648 if (t_obs <= 0.0)
649 { *rstatus = 2; return(NULL); }
650
651 if (t_obs != t_prev)
652 {
653 ObsLoc->crpix1 = drms_getkey_double(rec, "CRPIX1", &status); CHECK("CRPIX1");
654 ObsLoc->crpix2 = drms_getkey_double(rec, "CRPIX2", &status); CHECK("CRPIX2");
655 ObsLoc->crval1 = drms_getkey_double(rec, "CRVAL1", &status); CHECK("CRVAL1");
656 ObsLoc->crval2 = drms_getkey_double(rec, "CRVAL2", &status); CHECK("CRVAL2");
657 ObsLoc->cdelt1 = drms_getkey_double(rec, "CDELT1", &status); CHECK("CDELT1");
658 ObsLoc->cdelt2 = drms_getkey_double(rec, "CDELT2", &status); CHECK("CDELT1");
659 ObsLoc->crota2 = drms_getkey_double(rec, "CROTA2", &status); if (status) ObsLoc->crota2 = 0.0; // WCS default
660 ObsLoc->sina = sin(ObsLoc->crota2*Deg2Rad);
661 ObsLoc->cosa = sqrt (1.0 - ObsLoc->sina*ObsLoc->sina);
662 ObsLoc->rsun_obs = drms_getkey_double(rec, "RSUN_OBS", &status);
663 if (status)
664 {
665 double dsun_obs = drms_getkey_double(rec, "DSUN_OBS", &status); CHECK("DSUN_OBS");
666 ObsLoc->rsun_obs = asin(696000000.0/dsun_obs)/arcsec2Rad;
667 }
668 ObsLoc->obs_vr = drms_getkey_double(rec, "OBS_VR", &status); CHECK("OBS_VR");
669 ObsLoc->obs_vw = drms_getkey_double(rec, "OBS_VW", &status); CHECK("OBS_VW");
670 ObsLoc->obs_vn = drms_getkey_double(rec, "OBS_VN", &status); CHECK("OBS_VN");
671 ObsLoc->obs_b0 = drms_getkey_double(rec, "CRLT_OBS", &status); CHECK("CRLT_OBS");
672 ObsLoc->t_obs = t_obs;
673 }
674 *rstatus = 0;
675 return(ObsLoc);
676 }
677
678 /* GetMinObsInfo - gets minimum standard WCS keywords for e.g. heliographic mapped data */
679 ObsInfo_t *GetMinObsInfo(DRMS_Segment_t *seg, ObsInfo_t *pObsLoc, int *rstatus)
680 {
681 TIME t_prev;
682 DRMS_Record_t *rec;
683 TIME t_obs;
684 double dv;
685 ObsInfo_t *ObsLoc;
686 int status;
687
688 if (!seg || !(rec = seg->record))
689 { *rstatus = 1; return(NULL); }
690
691 ObsLoc = (pObsLoc ? pObsLoc : (ObsInfo_t *)malloc(sizeof(ObsInfo_t)));
692 if (!pObsLoc)
693 memset(ObsLoc, 0, sizeof(ObsInfo_t));
694
695 t_prev = ObsLoc->t_obs;
696 t_obs = drms_getkey_time(rec, "T_OBS", &status); CHECK("T_OBS");
697
698 if (t_obs <= 0.0)
699 { *rstatus = 2; return(NULL); }
700
701 if (t_obs != t_prev)
702 {
703 ObsLoc->crpix1 = drms_getkey_double(rec, "CRPIX1", &status); CHECK("CRPIX1");
704 ObsLoc->crpix2 = drms_getkey_double(rec, "CRPIX2", &status); CHECK("CRPIX2");
705 ObsLoc->crval1 = drms_getkey_double(rec, "CRVAL1", &status); CHECK("CRVAL1");
706 ObsLoc->crval2 = drms_getkey_double(rec, "CRVAL2", &status); CHECK("CRVAL2");
707 ObsLoc->cdelt1 = drms_getkey_double(rec, "CDELT1", &status); CHECK("CDELT1");
708 ObsLoc->cdelt2 = drms_getkey_double(rec, "CDELT2", &status); CHECK("CDELT1");
709 ObsLoc->crota2 = drms_getkey_double(rec, "CROTA2", &status); if (status) ObsLoc->crota2 = 0.0; // WCS default
710 ObsLoc->sina = sin(ObsLoc->crota2*Deg2Rad);
711 ObsLoc->cosa = sqrt (1.0 - ObsLoc->sina*ObsLoc->sina);
712 ObsLoc->rsun_obs = drms_getkey_double(rec, "RSUN_OBS", &status);
713 ObsLoc->obs_vr = drms_getkey_double(rec, "OBS_VR", &status);
714 ObsLoc->obs_vw = drms_getkey_double(rec, "OBS_VW", &status);
715 ObsLoc->obs_vn = drms_getkey_double(rec, "OBS_VN", &status);
716 ObsLoc->obs_b0 = drms_getkey_double(rec, "CRLT_OBS", &status);
717 ObsLoc->t_obs = t_obs;
718 }
719 *rstatus = 0;
720 return(ObsLoc);
721 }
722
723 // ----------------------------------------------------------------------
724
725 // In cases known to not have compact slotted series and cadence is specified
726 // generate explicit recordset list of closest good record to desired grid
727 // First get vector of times and quality
728 // Then if vector is not OK, quit.
729 // then: make temp file to hold recordset list
730 // start with first time to define desired grid,
731 // make array of desired times.
732 // make empty array of recnums
733 // search vector for good images nearest desired times
734 // for each found time, write record query
735
736
737 const char *get_input_recset(DRMS_Env_t *drms_env, const char *inQuery)
738 {
739 static char newInQuery[102];
740 TIME epoch = (cmdparams_exists(&cmdparams, "epoch")) ? params_get_time(&cmdparams, "epoch") : 0;
741 DRMS_Array_t *data;
742 TIME t_start, t_stop, t_now, t_want, t_diff, this_t_diff;
743 int status = 1;
744 int nrecs, irec;
745 int nslots, islot;
746 long long *recnums;
747 TIME *t_this, half;
748 TIME cadence;
749 double *drecnum, *dquality;
750 int quality;
751 long long recnum;
752 char keylist[DRMS_MAXQUERYLEN];
753 static char filename[100];
754 char *tmpdir;
755 FILE *tmpfile;
756 char newIn[DRMS_MAXQUERYLEN];
757 char seriesname[DRMS_MAXQUERYLEN];
758 char *lbracket;
759 char *at = index(inQuery, '@');
760
761 if (at && *at && (strncmp(inQuery,"aia.lev1[", 9)==0 ||
762 strncmp(inQuery,"hmi.lev1[", 9)==0 ||
763 strncmp(inQuery,"aia.lev1_nrt2[",14)==0 ||
764 strncmp(inQuery,"hmi.lev1_nrt[", 13)==0 ))
765 {
766 char *ip=(char *)inQuery, *op=newIn, *p;
767 long n, mul;
768
769 char *segSpec = NULL;
770 const char *psl = NULL;
771 char *pbracket = NULL;
772
773 psl = strchr(inQuery, '{');
774 if (psl)
775 {
776 segSpec = strdup(psl + 1);
777
778 if (!segSpec)
779 {
780 fprintf(stderr, "No memory.\n");
781 return NULL;
782 }
783
784 pbracket = strchr(segSpec, '}');
785
786 if (!pbracket)
787 {
788 fprintf(stderr, "Invalid segment specification.\n");
789 return NULL;
790 }
791
792 *pbracket = '\0';
793
794 if (!*segSpec)
795 {
796 fprintf(stderr, "Invalid segment specification.\n");
797 return NULL;
798 }
799 }
800
801 while ( *ip && ip<at )
802 *op++ = *ip++;
803 ip++; // skip the '@'
804 n = strtol(ip, &p, 10); // get digits only
805 if (*p == 's') mul = 1;
806 else if (*p == 'm') mul = 60;
807 else if (*p == 'h') mul = 3600;
808 else if (*p == 'd') mul = 86400;
809 else
810 {
811 fprintf(stderr,"cant make sense of @xx cadence spec for aia or hmi lev1 data");
812 return(NULL);
813 }
814 cadence = n * mul;
815 ip = ++p; // skip cadence multiplier
816 while ( *ip )
817 *op++ = *ip++;
818 *op = '\0';
819 half = cadence/2.0;
820 sprintf(keylist, "T_OBS,QUALITY,recnum");
821 data = drms_record_getvector(drms_env, newIn, keylist, DRMS_TYPE_DOUBLE, 0, &status);
822 if (!data || status)
823 {
824 fprintf(stderr,"getkey_vector failed status=%d\n", status);
825 return(NULL);
826 }
827 nrecs = data->axis[1];
828 irec = 0;
829 t_this = (TIME *)data->data;
830 dquality = (double *)data->data + 1*nrecs;
831 drecnum = (double *)data->data + 2*nrecs;
832 if (epoch > 0.0)
833 {
834 int s0 = (t_this[0] - epoch)/cadence;
835 TIME t0 = s0*cadence + epoch;
836 t_start = (t0 < t_this[0] ? t0 + cadence : t0);
837 }
838 else
839 t_start = t_this[0];
840 t_stop = t_this[nrecs-1];
841 nslots = (t_stop - t_start + cadence/2)/cadence;
842 recnums = (long long *)malloc(nslots*sizeof(long long));
843 for (islot=0; islot<nslots; islot++)
844 recnums[islot] = 0;
845 islot = 0;
846 t_want = t_start;
847 t_diff = 1.0e9;
848 for (irec = 0; irec<nrecs; irec++)
849 {
850 t_now = t_this[irec];
851 quality = (int)dquality[irec] & 0xFFFFFFFF;
852 recnum = (long long)drecnum[irec];
853 this_t_diff = fabs(t_now - t_want);
854 if (quality < 0)
855 continue;
856 if (t_now <= (t_want-half))
857 continue;
858 while (t_now > (t_want+half))
859 {
860 islot++;
861 if (islot >= nslots)
862 break;
863 t_want = t_start + cadence * islot;
864 this_t_diff = fabs(t_now - t_want);
865 t_diff = 1.0e8;
866 }
867 if (islot < nslots && this_t_diff <= t_diff)
868 recnums[islot] = recnum;
869 t_diff = fabs(t_now - t_want);
870 }
871 if (islot+1 < nslots)
872 nslots = islot+1; // take what we got.
873 strcpy(seriesname, inQuery);
874 lbracket = index(seriesname,'[');
875 if (lbracket) *lbracket = '\0';
876
877 tmpdir = getenv("TMPDIR");
878 if (!tmpdir) tmpdir = "/tmp";
879 sprintf(filename, "%s/hg_patchXXXXXX", tmpdir);
880 mkstemp(filename);
881 tmpfile = fopen(filename,"w");
882 for (islot=0; islot<nslots; islot++)
883 if (recnums[islot])
884 {
885 if (!segSpec)
886 {
887 fprintf(tmpfile, "%s[:#%lld]\n", seriesname, recnums[islot]);
888 }
889 else
890 {
891 fprintf(tmpfile, "%s[:#%lld]{%s}\n", seriesname, recnums[islot], segSpec);
892 }
893 }
894
895 if (segSpec)
896 {
897 free(segSpec);
898 }
899
900 fclose(tmpfile);
901 free(recnums);
902 drms_free_array(data);
903 sprintf(newInQuery,"@%s", filename);
904 return(newInQuery);
905 }
906 else
907 return(inQuery);
908 }