1 |
/** |
2 |
@defgroup im_patch im_patch (image_patch) extracts a rectangular |
3 |
region or patch from an input series. The patch is tracked across |
4 |
the solar disk from time t_start to t_stop. The patch size in pixels is defined by either its |
5 |
Carrington rotation, longitude, latitude and size when it crosses central meridian or |
6 |
by its location in arcsec at a reference time. If defined by Carrington coordinates the |
7 |
bounding box size is specified in degrees of longitude and latitude at disk center. Else the box is |
8 |
specified by its reference image time and location in locunits. No reprojection is done, the patch is |
9 |
a simple cutout of the original image. |
10 |
|
11 |
@ingroup a_programs |
12 |
|
13 |
@brief im_patch extracts a rectangular |
14 |
image from an input series. The patch is tracked across |
15 |
the solar disk from t_start to t_stop times. The patch may be defined by Carrington or Syonyhurst coordinates or |
16 |
in arcsec or pixels. The extracted patch is rectangular in original image pixels. |
17 |
|
18 |
|
19 |
@par Synopsis: |
20 |
|
21 |
@code |
22 |
im_patch in=<recordset> out=<series_out> \ |
23 |
log=<logfile> \ |
24 |
t_start=<start time> \ |
25 |
t_stop=<end time> \ |
26 |
cadence=<step time> \ |
27 |
car_rot=<Carrington Rotation> \ |
28 |
t_ref=<ref_time> \ |
29 |
locunits=<location units> \ |
30 |
x=<ew location> \ |
31 |
y=<ns location> \ |
32 |
boxunits= <patch spec units> \ |
33 |
height=<height> \ |
34 |
width=<width> \ |
35 |
requestid=<RequestID> \ |
36 |
[-t] \ |
37 |
|
38 |
@endcode |
39 |
|
40 |
Cadence is the desired time between extracted frames. It will be modified to be a multiple of the dataset's step size. |
41 |
The extracted region location may be specified by position at a reference time or by Carrington coordinates. |
42 |
If by position at a reference time, the position may be specified in ipixels, arcsec, or Stonyhurst coordinates. |
43 |
If the car_rot parameter is required if the Carrington location method is used. |
44 |
If the t_ref parameter is present, location is specified by a method given in <locunits>. |
45 |
The location is given in the "x" and "y" arguments where the units of x and y are determined by locunits. |
46 |
The choices for locunits are: "arcsec", "pixels", "stony", "carrlong". |
47 |
For "stony" (Stonyhurst) x is the CM distance in degrees, for "carrlong" x is Carrington longitude. |
48 |
The y value is in degrees of latitude for either "stony" or "carrlong". |
49 |
Arcsec locations are measured from disk center, pixel locations are measured from the lower left corner of |
50 |
the image, with the first pixel labeled (1,1). |
51 |
|
52 |
The size of the patch, given in the width and height parameters can be expressed in "pixels", "arcsec", or "degrees" |
53 |
as determined by the "boxunits" parameter. |
54 |
|
55 |
If the logfile parameter is present, a RecordSet query will be written to logfile for each image created containing a query |
56 |
that will return that image. |
57 |
|
58 |
RequestID, if present, is the ID of an on-requst processing export request. |
59 |
|
60 |
If neither a limiting recordset specification nor t_start or t_stop are present, those values will be inferred from |
61 |
the on-disk time span for the center of the patch -90 degrees to +90 degrees from CM. |
62 |
If cadence is not specified explicitly on the command line or in the recordset spec, the full cadence of the dataset will be used. |
63 |
This module computes the beginning and ending time for tracking the |
64 |
region identified at time = t_ref, x and y or by the Carrington coordinates of the box center. |
65 |
In the Carrington case the module extracts a rectangular region |
66 |
with user defined size. the height and width of the box are specified in degrees |
67 |
of latitude and longitude with the pixel size of the box is computed from the |
68 |
projection of the box at CM. The pixel size of the rectangular box remains constant |
69 |
during tracking. The box height defaults to the width. The width defaults to 10 degrees. |
70 |
|
71 |
If the input recordset spec is exactly "[$]" that spec will be discarded and the time limits will be taken from t_start, t_stop, car_rot, and/or t_ref as appropriate. This is to allow exports via jsoc_fetch to not require a bounding recordset to be specified. |
72 |
|
73 |
If t_start and/or t_stop are specified the referecne time or disk center location need not be |
74 |
included. |
75 |
|
76 |
If the input is only a seriesname with [$], it must have a prime key of type time. |
77 |
|
78 |
If the t_ref parameter is specified, there must be a non-missing image within +- 2 hours of t_ref. |
79 |
|
80 |
The output seriesname defaults to the input seriesname with a suffix of "_mod". |
81 |
|
82 |
The -t, 'no tracking' flag casues the extracted region to remain fixed with respect to disc center. I.e. the Carrington |
83 |
tracking is disabled. If locunits are "stony" or "carrlong" the patch center must be on the disk. |
84 |
|
85 |
The -c, 'crop' flag causes the off-limb data to be replaced with MISSING (NaNs for floating types). |
86 |
|
87 |
The -h "header keywords" flag causes the metadata keywords to be included in all of the output FITS files. |
88 |
|
89 |
If -r or -R are specified, the images will be sub-pixel registered to the target location. If -r or -R are given |
90 |
along with -t (no tracking) then -r means register to the first frame and -R means register to Sun center. |
91 |
|
92 |
-f, -F flags and FDS are special rarely used parameters that allow tracking to a location given in |
93 |
a SDO flight dynamics system generated trajectory of e.g. a transitting moon or planet. The -f or -F flags |
94 |
in this case will generate a fake object with value either 0 or datamax. For example, the Venus transit |
95 |
locations are found in sdo.fds[2012.06.05_00:00:00_UTC][SOLAR_TRANSIT][S][2] |
96 |
|
97 |
If the input series is AIA lev1 or HMI lev1 where the time slots are not fully populated then special |
98 |
code is used to produce the requested cadence. In these cases the DRMS "time@cadence" recordset notation |
99 |
will fail so use the cadence parameter instead. |
100 |
|
101 |
@par Flags: |
102 |
-A Generate output for all segments. |
103 |
-t Disable tracking. |
104 |
-h Include header keywords |
105 |
-r register to first frame |
106 |
-R register to Sun center |
107 |
-f make black fake tracked object |
108 |
-F make light fake tracked object |
109 |
|
110 |
|
111 |
@par GEN_FLAGS: |
112 |
Ubiquitous flags present in every module. |
113 |
@ref jsoc_main |
114 |
|
115 |
@param in The input data series. |
116 |
@param out The output series. |
117 |
|
118 |
@par Exit_Status: |
119 |
|
120 |
@par Example: |
121 |
Extracts a rectangular region of size 20 x 10 degrees and tracks it from |
122 |
when the region is just appearing at the E-limb to t_stop. |
123 |
|
124 |
@code |
125 |
im_patch in='hmi.M_45s' locunits=carrlong boxunits=pixels car_rot=2009 x=295 y=5 width=30 height=20 |
126 |
|
127 |
@endcode |
128 |
|
129 |
@par Example: |
130 |
|
131 |
@code |
132 |
|
133 |
@endcode |
134 |
|
135 |
@bug |
136 |
No doubt some bugs. |
137 |
|
138 |
|
139 |
*/ |
140 |
#include "jsoc.h" |
141 |
#include "jsoc_main.h" |
142 |
#include "astro.h" |
143 |
#include "fstats.h" |
144 |
#include "atoinc.h" |
145 |
#include <math.h> |
146 |
|
147 |
int get_tracking_xy(char *FDSfile, TIME want, double *xp, double *yp, double *radius); |
148 |
void HeliographicLocation(TIME t, int *crot, double *L, double *B); |
149 |
TIME HeliographicTime(int crot, double L); |
150 |
|
151 |
char *module_name = "im_patch"; |
152 |
|
153 |
#define DIE(msg) {fprintf(stderr,"%s Status=%d\n",msg, status); return(status?status:1);} |
154 |
#define DIE2(msg,val) {fprintf(stderr,"%s %s, Status=%d\n",msg, val, status); return(status?status:1);} |
155 |
#define TEST_PARAM(param) {if (status) DIE2("Required keyword missing: ", param);} |
156 |
|
157 |
#define Deg2Rad (M_PI/180.0) |
158 |
#define Rad2arcsec (3600.0/Deg2Rad) |
159 |
#define Rad2Deg (180.0/M_PI) |
160 |
#define VERBOSE 0 |
161 |
|
162 |
ModuleArgs_t module_args[] = |
163 |
{ |
164 |
{ARG_STRING, "in", "NOTSPECIFIED", "input series. e.g 'hmi.M_720s'"}, |
165 |
{ARG_STRING, "out", "NOTSPECIFIED", "output seies. e.g. 'su_phil.hmi_cutout'"}, |
166 |
{ARG_STRING, "log", "NOTSPECIFIED", "output log file of records made"}, |
167 |
{ARG_STRING, "requestid", "NOTSPECIFIED", "RequestID if im_patch call originated in an export request."}, |
168 |
{ARG_INT, "car_rot", "-1", "Carrington Rotation when the region crosses CM"}, |
169 |
{ARG_FLOAT, "width", "0", "width of box in boxunits (conversion to pixels made when at CM)"}, |
170 |
{ARG_FLOAT, "height", "0", "height of box in boxunits (conversion to pixels made when at CM)"}, |
171 |
{ARG_STRING, "boxunits", "NOTSPECIFIED", "units of patch, 'pixels', 'arcsecs', or 'degrees'"}, |
172 |
{ARG_TIME, "t_start", "JD_0", "Start time, defaults to time at 90E"}, |
173 |
{ARG_TIME, "t_stop", "JD_0", "End time, defauolts to 90W"}, |
174 |
{ARG_TIME, "cadence", "NOTSPECIFIED", "Cadence of product, defaults to input cadence."}, |
175 |
{ARG_TIME, "t_ref", "JD_0", "Time for which x and y apply, selects reference image for tracking."}, |
176 |
{ARG_STRING, "locunits", "NOTSPECIFIED", "Location units in 'pixels', 'arcsec', 'stony', or 'carrlong'"}, |
177 |
{ARG_STRING, "where", "NOTSPECIFIED", "Additional 'where' clause if needed"}, |
178 |
{ARG_FLOAT, "x", "0", "Location of extract box center in pixels in locunits: arcsec from Sun center, degrees from Sun center, or Carrington longitude"}, |
179 |
{ARG_FLOAT, "y", "0", "Location of extract box center, same units as x"}, |
180 |
{ARG_FLAG, "A", NULL, "Generate output for all input segments"}, |
181 |
{ARG_FLAG, "t", "0", "Disable Carrington rate tracking"}, |
182 |
{ARG_FLAG, "h", "0", "Export keywords, i.e. include full metadata in FITS files"}, |
183 |
{ARG_FLAG, "c", "0", "Crop at limb, useful for HMI M data."}, |
184 |
{ARG_FLAG, "f", "0", "FAKE tracking target added for transits, val=0"}, |
185 |
{ARG_FLAG, "F", "0", "FAKE tracking target added for transits, val=datamax"}, |
186 |
{ARG_FLAG, "r", "0", "Register to fractional CRPIXi, all frames to first frame round(crpix)"}, |
187 |
{ARG_STRING, "FDS", "NOTSPECIFIED", "FDS file for tracking transit objects"}, |
188 |
{ARG_END} |
189 |
}; |
190 |
|
191 |
int img2sphere (double x, double y, double ang_r, double latc, double lonc, |
192 |
double pa, double *rho, double *lat, double *lon, double *sinlat, |
193 |
double *coslat, double *sig, double *mu, double *chi); |
194 |
int sphere2img (double lat, double lon, double latc, double lonc, |
195 |
double *x, double *y, double xcenter, double ycenter, |
196 |
double rsun, double peff, double ecc, double chi, |
197 |
int xinvrt, int yinvrt); |
198 |
int image_magrotate(void *, int nin, int min, int data_type_input, float theta, float mag, |
199 |
float dx, float dy, void **outarray, int *nx, int *ny, int regridtype_input, int stretch_lines); |
200 |
|
201 |
// experimental make recordset list at cadence |
202 |
// OLD VERSION char *get_input_recset(DRMS_Env_t *env, char *in, TIME cadence, char *timekeyname); |
203 |
char *get_input_recset(DRMS_Env_t *drms_env, char *inQuery); |
204 |
|
205 |
// Macros for WCS transformations. assume crpix1, crpix2 = CRPIX1, CRPIX2, sina,cosa = sin and cos of CROTA2 resp. |
206 |
// and crvalx and crvaly are CRVAL1 and CRVAL2, cdelt = CDELT1 == CDELT2, then |
207 |
// PIX_X and PIX_Y are CCD pixel addresses, WX and WY are arc-sec W and N on the Sun from disk center. |
208 |
// These are in units where the first pixel is 1 not 0. |
209 |
#define PIX_X(wx,wy) ((((wx-crvalx)*cosa + (wy-crvaly)*sina)/cdelt)+crpix1) |
210 |
#define PIX_Y(wx,wy) ((((wy-crvaly)*cosa - (wx-crvalx)*sina)/cdelt)+crpix2) |
211 |
#define WX(pix_x,pix_y) (((pix_x-crpix1)*cosa - (pix_y-crpix2)*sina)*cdelt+crvalx) |
212 |
#define WY(pix_x,pix_y) (((pix_y-crpix2)*cosa + (pix_x-crpix1)*sina)*cdelt+crvaly) |
213 |
|
214 |
#define BOXBAD 0 |
215 |
#define BOXARCSEC 1 |
216 |
#define BOXPIXELS 2 |
217 |
#define BOXDEGREE 3 |
218 |
|
219 |
#define LOCBAD 0 |
220 |
#define LOCARCSEC 1 |
221 |
#define LOCPIXELS 2 |
222 |
#define LOCSTONY 3 |
223 |
#define LOCCARR 4 |
224 |
|
225 |
#define TIMES_RECSET 0 // recordset spec contains time range |
226 |
#define TIMES_GIVEN 1 // explicit t_start and t_stop provided |
227 |
#define TIMES_IMPLICIT 2 // times to be deduced for disk transit of specified box |
228 |
|
229 |
// Two functions to get CRLN_OBS corrected and to store new CALVERxx value. |
230 |
// Use update_CALVERxx to fetch CALVERxx and or it with e.g. 1<<28 to indicate new CRLN_OBS |
231 |
// CALVERxx may be either of CALVER64 or CALVER32. |
232 |
int update_CALVERxx(DRMS_Record_t *inrec, DRMS_Record_t *outrec, int calver) |
233 |
{ |
234 |
int status; |
235 |
DRMS_Keyword_t *calver_kw; |
236 |
if (calver_kw = drms_keyword_lookup(inrec, "CALVER64", 1)) |
237 |
{ |
238 |
long long calver64 = calver_kw->value.longlong_val; |
239 |
if (((long long)1<<63) & calver64) calver64 = 0; |
240 |
drms_setkey_longlong(outrec, "CALVER64", calver64 | calver); |
241 |
} |
242 |
else |
243 |
{ |
244 |
if (calver_kw = drms_keyword_lookup(inrec, "CALVER32", 1)) |
245 |
{ |
246 |
int calver32 = calver_kw->value.int_val; |
247 |
if ((1<<31) & calver32) calver32 = 0; |
248 |
drms_setkey_int(outrec, "CALVER32", calver32 | calver); |
249 |
} |
250 |
} |
251 |
} |
252 |
|
253 |
// Use get_new_CRLN_OBS as a direct replacement for drms_getkey_double or drms_getkey_float. |
254 |
// If there is a CALVERxx keyword present, it will check the bit #28 and if not set then |
255 |
// the correction to CRLN_OBS will be made. |
256 |
double get_new_CRLN_OBS(DRMS_Record_t *inrec, int *status) |
257 |
{ |
258 |
int this_status; |
259 |
double CRLN_CORRECTION = -0.0818941; |
260 |
long long calver64; |
261 |
int calver32; |
262 |
DRMS_Keyword_t *calver_kw; |
263 |
calver32 = 1<<31; |
264 |
double crln_obs = drms_getkey_double(inrec, "CRLN_OBS", &this_status); |
265 |
if (this_status || isnan(crln_obs)) |
266 |
*status = this_status; |
267 |
else // CRLN_OBS exists and is not missing, check for one of CALVER keywords. |
268 |
{ |
269 |
if (calver_kw = drms_keyword_lookup(inrec, "CALVER64", 1)) |
270 |
{ |
271 |
calver64 = calver_kw->value.longlong_val; |
272 |
if (calver64 >= 0) |
273 |
calver32 = calver64 & 0xFFFFFFFF; |
274 |
} |
275 |
else |
276 |
{ |
277 |
if (calver_kw = drms_keyword_lookup(inrec, "CALVER32", 1)) |
278 |
calver32 = calver_kw->value.int_val; |
279 |
} |
280 |
if (!((calver32>>31) & 1) && !((calver32>>28) & 1)) // good CALVER but new CRLN_OBS is not present |
281 |
{ |
282 |
crln_obs += CRLN_CORRECTION; |
283 |
} |
284 |
} |
285 |
return(crln_obs); |
286 |
} |
287 |
|
288 |
|
289 |
int DoIt(void) |
290 |
{ |
291 |
CmdParams_t *params = &cmdparams; |
292 |
DRMS_RecordSet_t *inRS = NULL; |
293 |
DRMS_RecordSet_t *outRS = NULL; |
294 |
DRMS_Record_t *inRec = NULL; |
295 |
DRMS_Record_t *outRec = NULL; |
296 |
DRMS_Record_t *inTemplate = NULL; |
297 |
DRMS_Record_t *outTemplate = NULL; |
298 |
DRMS_Segment_t *inSeg = NULL; |
299 |
DRMS_Segment_t *outSeg = NULL; |
300 |
DRMS_Array_t *inArray = NULL; |
301 |
DRMS_Array_t *outArray = NULL; |
302 |
int i, ii, status = DRMS_SUCCESS, nrecs; |
303 |
int irec; |
304 |
int OK_recs = 0; |
305 |
double center_x, center_y, crpix1, crpix2, x0, y0; |
306 |
double rsun_ref, dsun_obs, rsun, rsun_rad, rsunpix; |
307 |
double r2; |
308 |
double this_x0; |
309 |
double this_y0; |
310 |
double crln_obs, crlt_obs; |
311 |
double crln_obs_rad, crlt_obs_rad; |
312 |
double crln_rad, crlt_rad; |
313 |
double pa_rad; |
314 |
double cdelt; |
315 |
double llx, lly; |
316 |
int inAxis[2]; |
317 |
int this_car_rot; |
318 |
char *ctype1, *ctype2; |
319 |
TIME t_rec; |
320 |
double box_x, box_y; |
321 |
double crln, crlt; |
322 |
char outseries[DRMS_MAXSERIESNAMELEN]; |
323 |
char inseries[DRMS_MAXSERIESNAMELEN]; |
324 |
char extractedSeries[DRMS_MAXSERIESNAMELEN]; |
325 |
int is_mod; |
326 |
char testseries[DRMS_MAXSERIESNAMELEN]; |
327 |
char inQuery[DRMS_MAXQUERYLEN]; |
328 |
char in[DRMS_MAXQUERYLEN]; |
329 |
|
330 |
const char *ingiven = params_get_str(params, "in"); |
331 |
char *inparam; |
332 |
char *lbracket, *rbracket; |
333 |
char *moreQuery = NULL; |
334 |
const char *outparam = params_get_str(params, "out"); |
335 |
const char *logfile = params_get_str(params, "log"); |
336 |
const char *requestid = params_get_str(params, "requestid"); |
337 |
const char *where = params_get_str(params, "where"); |
338 |
const char *FDSfile = params_get_str(params, "FDS"); |
339 |
TIME t_start = params_get_time(params, "t_start"); |
340 |
TIME t_stop = params_get_time(params, "t_stop"); |
341 |
const char *cadence_str = params_get_str(params, "cadence"); |
342 |
double cadence; |
343 |
TIME t_ref = params_get_time(params, "t_ref"); |
344 |
double width = params_get_double(params, "width"); |
345 |
double height = params_get_double(params, "height"); |
346 |
int pixwidth, pixheight; |
347 |
double midx, midy; |
348 |
int car_rot = params_get_int(params, "car_rot"); |
349 |
double x = params_get_double(params, "x"); |
350 |
double y = params_get_double(params, "y"); |
351 |
const char *boxunits = params_get_str(params, "boxunits"); |
352 |
const char *locunits = params_get_str(params, "locunits"); |
353 |
int NoTrack = params_isflagset(params, "t"); |
354 |
int wantFAKEwhite = params_isflagset(params, "F"); |
355 |
int wantFAKE = params_isflagset(params, "f") || wantFAKEwhite; |
356 |
int do_register = params_isflagset(params, "r"); |
357 |
int export_keys = params_isflagset(params, "h"); |
358 |
int do_crop = params_isflagset(params, "c"); |
359 |
TIME tNotSpecified = sscan_time("JD_0"); |
360 |
int do_reftime = 0; // Target specified by reftime vs Carr rotation mode. |
361 |
double crvalx = 0.0; |
362 |
double crvaly = 0.0; |
363 |
double crota, sina, cosa; |
364 |
double pa, deltlong; |
365 |
double target_x, target_y; // used for NoTrack option |
366 |
int firstimage = 1; |
367 |
int boxtype, loctype; |
368 |
char *timekeyname; |
369 |
TIME t_step, t_epoch; |
370 |
int npkeys; |
371 |
int times_source = TIMES_RECSET; |
372 |
char timebuf[20]; |
373 |
char *in_filename = NULL; |
374 |
double trackx, tracky; |
375 |
double track_radius; |
376 |
double crpix1_0, crpix2_0; |
377 |
int register_padding = 60; // later this should be based on crota2 and box size. |
378 |
char *tmpstr = NULL; |
379 |
int hasSegList = 0; |
380 |
int doingAllSegs = params_isflagset(params, "A"); |
381 |
int calver; |
382 |
|
383 |
FILE *log = NULL; |
384 |
|
385 |
if (strcmp(FDSfile,"NOTSPECIFIED")==0) |
386 |
FDSfile = NULL; |
387 |
|
388 |
if (strncasecmp(locunits, "arcsec", 6) == 0) loctype = LOCARCSEC; |
389 |
else if (strncasecmp(locunits, "pixels", 3) == 0) loctype = LOCPIXELS; |
390 |
else if (strncasecmp(locunits, "stony", 5) == 0) loctype = LOCSTONY; |
391 |
else if (strncasecmp(locunits, "carrlong", 4) == 0) loctype = LOCCARR; |
392 |
else loctype = LOCBAD; |
393 |
|
394 |
if (strncasecmp(boxunits, "arcsec", 6) == 0) boxtype = BOXARCSEC; |
395 |
else if (strncasecmp(boxunits, "pixels", 3) == 0) boxtype = BOXPIXELS; |
396 |
else if (strncasecmp(boxunits, "degrees", 3) == 0) boxtype = BOXDEGREE; |
397 |
else loctype = BOXBAD; |
398 |
|
399 |
if (loctype == LOCCARR) |
400 |
{ |
401 |
if (car_rot < 0) DIE("Carrington rotation number must be provided for locunits=carrlong"); |
402 |
// if (NoTrack) DIE("Can not use locunits=carrlong for no-tracking mode"); |
403 |
do_reftime = 0; |
404 |
} |
405 |
else |
406 |
{ |
407 |
if (t_ref < 0) |
408 |
DIE("t_ref must be provided for locunits!=carrlong"); |
409 |
do_reftime = 1; |
410 |
} |
411 |
|
412 |
if (loctype==LOCBAD) |
413 |
DIE2("Location units not detected, locunits", locunits) |
414 |
if (boxtype==BOXBAD) |
415 |
DIE2("patch dimensions not understood,", boxunits); |
416 |
|
417 |
if (strcasecmp(logfile, "NOTSPECIFIED") != 0) |
418 |
{ |
419 |
log = fopen(logfile, "w"); |
420 |
if (!log) DIE2("Can not create log file.",logfile); |
421 |
} |
422 |
|
423 |
if (strcasecmp(where, "NOTSPECIFIED") == 0 || *where == '\0') |
424 |
{ |
425 |
where = ""; |
426 |
} |
427 |
else |
428 |
{ |
429 |
char wherework[4096]; |
430 |
sprintf(wherework,"[? %s ?]", where); |
431 |
where = strdup(wherework); |
432 |
} |
433 |
|
434 |
/* We need to extract the series name from the input record-set specification. There */ |
435 |
|
436 |
/* Determine if there is a segment list specifier. I believe this is true if the last non-ws char of the specification is a '}'. |
437 |
* Of course, the specification could be invalid, but in that event the drms_open_records() call will fail and catch the error and |
438 |
* the module run will abort. */ |
439 |
char *testSegList = NULL; |
440 |
char *pCh = NULL; |
441 |
|
442 |
testSegList = rindex(ingiven, '}'); |
443 |
if (testSegList) |
444 |
{ |
445 |
for (pCh = testSegList + 1, hasSegList = 1; *pCh; pCh++) |
446 |
{ |
447 |
if (!isspace(*pCh)) |
448 |
{ |
449 |
/* There is a non-ws char after '}' - this is not a valid seglist. */ |
450 |
hasSegList = 0; |
451 |
break; |
452 |
} |
453 |
} |
454 |
} |
455 |
|
456 |
inparam = strdup(ingiven); |
457 |
if (strcasecmp(inparam, "NOTSPECIFIED") == 0) DIE("Input series must be specified."); |
458 |
|
459 |
/* This program works only if the series' first prime-key constituent is a time keyword. Then, we want to |
460 |
* ignore the first prime key and use the t_start/t_stop argument to select records instead. |
461 |
* I believe the program will not work with record-set specifications that contain more than one |
462 |
* subset either. So... |
463 |
* 1. Extract the series from the record-set specification. |
464 |
* 2. Bail if there is more than one record-set subset. |
465 |
* 3. Obtain the first keyword from the prime-key set. |
466 |
* 4. Bail if the first keyword is not a time keyword. |
467 |
* 5. Remove the time filter provided by the user in the record-set specification. |
468 |
*/ |
469 |
|
470 |
/* Use drms_record_parserecsetspec() to extract the series and filter strings. The previous |
471 |
* code wasn't quite working 100% . */ |
472 |
char *allvers = NULL; |
473 |
char **sets = NULL; |
474 |
DRMS_RecordSetType_t *settypes = NULL; /* a maximum doesn't make sense */ |
475 |
char **snames = NULL; |
476 |
char **filts = NULL; |
477 |
int nsets = 0; |
478 |
DRMS_RecQueryInfo_t rsinfo; /* Filled in by parser as it encounters elements. */ |
479 |
DRMS_Keyword_t *firstPKey = NULL; |
480 |
|
481 |
if (drms_record_parserecsetspec(inparam, &allvers, &sets, &settypes, &snames, &filts, &nsets, &rsinfo) == DRMS_SUCCESS) |
482 |
{ |
483 |
if (nsets > 1) |
484 |
{ |
485 |
status = DRMS_ERROR_INVALIDDATA; |
486 |
DIE("im_patch supports single-set record-set specifications only."); |
487 |
} |
488 |
} |
489 |
else |
490 |
{ |
491 |
status = DRMS_ERROR_INVALIDDATA; |
492 |
DIE("Invalid record-set specification provided."); |
493 |
} |
494 |
|
495 |
snprintf(inseries, sizeof(inseries), "%s", snames[0]); |
496 |
lbracket = index(inparam, '['); |
497 |
|
498 |
inTemplate = drms_template_record(drms_env, inseries, &status); |
499 |
if (status || !inTemplate) DIE2("Input series can not be found: ", inseries); |
500 |
|
501 |
if (drms_keyword_isindex(inTemplate->seriesinfo->pidx_keywords[0])) |
502 |
{ |
503 |
firstPKey = drms_keyword_slotfromindex(inTemplate->seriesinfo->pidx_keywords[0]); |
504 |
} |
505 |
else |
506 |
{ |
507 |
firstPKey = inTemplate->seriesinfo->pidx_keywords[0]; |
508 |
} |
509 |
|
510 |
if (firstPKey->info->type != DRMS_TYPE_TIME) |
511 |
{ |
512 |
status = DRMS_ERROR_INVALIDDATA; |
513 |
DIE("The first prime-key constituent keyword must be of type TIME."); |
514 |
} |
515 |
|
516 |
if (filts && filts[0]) |
517 |
{ |
518 |
if (strlen(filts[0]) == 3 && filts[0][1] == '$') |
519 |
{ |
520 |
/* The user specified the last (according to time) record. Remove that filter. */ |
521 |
moreQuery = lbracket + 3; |
522 |
*lbracket = '\0'; |
523 |
lbracket = NULL; |
524 |
|
525 |
if (t_start == tNotSpecified || t_stop == tNotSpecified) |
526 |
times_source = TIMES_IMPLICIT; |
527 |
else |
528 |
times_source = TIMES_GIVEN; |
529 |
} |
530 |
else |
531 |
{ |
532 |
rbracket = index(lbracket, ']'); |
533 |
moreQuery = rbracket ? rbracket + 1 : lbracket; |
534 |
} |
535 |
} |
536 |
else |
537 |
{ |
538 |
/* No filter provided at all. */ |
539 |
if (t_start == tNotSpecified || t_stop == tNotSpecified) |
540 |
times_source = TIMES_IMPLICIT; |
541 |
else |
542 |
times_source = TIMES_GIVEN; |
543 |
} |
544 |
|
545 |
drms_record_freerecsetspecarr(&allvers, &sets, &settypes, &snames, &filts, nsets); |
546 |
|
547 |
// XXXXX Get box location in Carrington Coords for all location types, also initial center_X, center_y in NoTrack case XXXXX |
548 |
if (do_reftime) // Arc-sec, pixel, or Stonyhurst specification, get ref image information |
549 |
{ // the image for ref_time is supposed to be present in the series. |
550 |
if (VERBOSE) fprintf(stderr,"doing reftime\n"); |
551 |
int okrec = -1; |
552 |
char t_ref_pre[100]; |
553 |
char t_ref_post[100]; |
554 |
TIME search_width = 15; |
555 |
while (search_width < 10000) |
556 |
{ |
557 |
sprint_at(t_ref_pre, t_ref-search_width); |
558 |
sprint_at(t_ref_post, t_ref+search_width); |
559 |
sprintf(in, "%s[%s-%s][? QUALITY >= 0 ?]%s%s", inseries, t_ref_pre, t_ref_post, moreQuery, where); |
560 |
if (VERBOSE) fprintf(stderr,"searchwidth=%f, t_ref query is: %s\n",search_width,in); |
561 |
inRS = drms_open_records(drms_env, in, &status); |
562 |
if (!status && inRS->n > 0) |
563 |
{ |
564 |
int irec, nrecs = inRS->n; |
565 |
TIME tdiff = 100000; |
566 |
for (irec=0, okrec=-1; irec<nrecs; irec++) // find record close to t_ref |
567 |
{ |
568 |
TIME newdiff; |
569 |
inRec = inRS->records[irec]; |
570 |
if (VERBOSE) fprintf(stderr,"irec=%d, tdiff=%lf\n",irec,tdiff); |
571 |
if ((newdiff=(fabs(drms_getkey_time(inRec,"T_OBS",NULL) - t_ref))) > tdiff) |
572 |
break; |
573 |
okrec = irec; |
574 |
tdiff = newdiff; |
575 |
} |
576 |
} |
577 |
if (okrec >= 0) |
578 |
break; |
579 |
search_width *= 2; |
580 |
drms_close_records(inRS, DRMS_FREE_RECORD); |
581 |
} |
582 |
if (search_width >= 10000) |
583 |
DIE2("No input data found within 2-hours of t_ref",in); |
584 |
inRec = inRS->records[okrec]; |
585 |
this_car_rot = drms_getkey_int(inRec, "CAR_ROT", &status); TEST_PARAM("CAR_ROT"); |
586 |
crlt_obs = drms_getkey_double(inRec, "CRLT_OBS", &status); TEST_PARAM("CRLT_OBS"); |
587 |
// crln_obs = drms_getkey_double(inRec, "CRLN_OBS", &status); TEST_PARAM("CRLN_OBS"); |
588 |
crln_obs = get_new_CRLN_OBS(inRec, &status); TEST_PARAM("CRLN_OBS"); |
589 |
crpix1 = drms_getkey_double(inRec, "CRPIX1", &status); TEST_PARAM("CRPIX1"); |
590 |
x0 = crpix1 - 1; |
591 |
crpix2 = drms_getkey_double(inRec, "CRPIX2", &status); TEST_PARAM("CRPIX2"); |
592 |
y0 = crpix2 - 1; |
593 |
crvalx = drms_getkey_double(inRec, "CRVAL1", &status); TEST_PARAM("CRVAL1"); |
594 |
crvaly = drms_getkey_double(inRec, "CRVAL2", &status); TEST_PARAM("CRVAL2"); |
595 |
crota = drms_getkey_double(inRec, "CROTA2", &status); if (status) crota = 0.0; // WCS default |
596 |
pa = -crota; |
597 |
crlt_obs_rad = Deg2Rad * crlt_obs; |
598 |
crln_obs_rad = Deg2Rad * crln_obs; |
599 |
pa_rad = Deg2Rad * pa; |
600 |
sina = sin(crota*Deg2Rad); |
601 |
cosa = cos(crota*Deg2Rad); |
602 |
tmpstr = drms_getkey_string(inRec, "CTYPE1", &status); |
603 |
ctype1 = strdup(tmpstr); TEST_PARAM("CTYPE1"); |
604 |
if (tmpstr) |
605 |
{ |
606 |
free(tmpstr); |
607 |
} |
608 |
if (strcmp(ctype1, "HPLN-TAN") != 0) |
609 |
DIE2("CTYPE1 not HPLN-TAN as required, is: ", ctype1); |
610 |
if (ctype1) |
611 |
{ |
612 |
free(ctype1); |
613 |
ctype1 = NULL; |
614 |
} |
615 |
tmpstr = drms_getkey_string(inRec, "CTYPE2", &status); |
616 |
ctype2 = strdup(tmpstr); TEST_PARAM("CTYPE2"); |
617 |
if (tmpstr) |
618 |
{ |
619 |
free(tmpstr); |
620 |
} |
621 |
if (strcmp(ctype2, "HPLT-TAN") != 0) |
622 |
DIE2("CTYPE2 not HPLT-TAN as required, is: ", ctype2); |
623 |
if (ctype2) |
624 |
{ |
625 |
free(ctype2); |
626 |
ctype2 = NULL; |
627 |
} |
628 |
rsun_ref = drms_getkey_double(inRec, "RSUN_REF", &status); |
629 |
if (status) |
630 |
rsun_ref = 6.96e8; |
631 |
dsun_obs = drms_getkey_double(inRec, "DSUN_OBS", &status); TEST_PARAM("DSUN_OBS"); |
632 |
rsun_rad = asin(rsun_ref/dsun_obs); |
633 |
rsun = rsun_rad*Rad2arcsec; |
634 |
cdelt = drms_getkey_double(inRec, "CDELT1", &status); TEST_PARAM("CDELT1"); |
635 |
rsunpix = rsun/cdelt; |
636 |
if (loctype == LOCPIXELS || loctype==LOCARCSEC) |
637 |
{ /* box ref location is in arcsec - find Carrington equivalent */ |
638 |
// Note x and y and PIX_X and PIX_Y have first pixel at (1,1) |
639 |
// center_x and center_y are center of target box where first pixel is (0,0) |
640 |
if (loctype==LOCARCSEC) |
641 |
{ |
642 |
center_x = PIX_X(x,y) - 1; |
643 |
center_y = PIX_Y(x,y) - 1; |
644 |
} |
645 |
else |
646 |
{ |
647 |
center_x = x - 1; |
648 |
center_y = y - 1; |
649 |
} |
650 |
// center_x and center_y are box center in pixels, first pixel at (0,0) |
651 |
inSeg = drms_segment_lookupnum(inRec, 0); |
652 |
inAxis[0] = inSeg->axis[0]; |
653 |
inAxis[1] = inSeg->axis[1]; |
654 |
if ( img2sphere((center_x - x0)/rsunpix, (center_y -y0)/rsunpix, rsun_rad, crlt_obs_rad, crln_obs_rad, pa_rad, |
655 |
NULL, &crlt_rad, &crln_rad, NULL, NULL, NULL, NULL, NULL) < 0) |
656 |
fprintf(stderr, "Starting location is off the solar disk."); |
657 |
crln = crln_rad * Rad2Deg; |
658 |
crlt = crlt_rad * Rad2Deg; |
659 |
fprintf(stderr,"at do reftime, center_x=%f\n", center_x); |
660 |
} |
661 |
else /* loctype==LOCSTONY */ |
662 |
{ |
663 |
crlt = y; |
664 |
crln = crln_obs + x; |
665 |
sphere2img(crlt/Rad2Deg, crln/Rad2Deg, crlt_obs_rad, crln_obs_rad, ¢er_x, ¢er_y, x0, y0, rsunpix, pa_rad, 0, 0, 0, 0); |
666 |
} |
667 |
deltlong = crln - crln_obs; |
668 |
car_rot = this_car_rot; |
669 |
if (crln >= 360.0) |
670 |
{ car_rot--; crln -= 360.0; } |
671 |
else if (crln < 0) |
672 |
{ car_rot++; crln += 360.0; } |
673 |
drms_close_records(inRS, DRMS_FREE_RECORD); |
674 |
} |
675 |
else // Carrington specification |
676 |
{ |
677 |
crln = x; |
678 |
crlt = y; |
679 |
if (crln < 0) DIE("Box longitude must be specified."); |
680 |
if (crlt < -990) DIE("box latitude must be specified."); |
681 |
sphere2img(crlt/Rad2Deg, crln/Rad2Deg, crlt_obs_rad, crln_obs_rad, ¢er_x, ¢er_y, x0, y0, rsunpix, pa_rad, 0, 0, 0, 0); |
682 |
} |
683 |
crln_rad = crln * Deg2Rad; |
684 |
crlt_rad = crlt * Deg2Rad; |
685 |
|
686 |
// Now we have crln, crlt, crln_rad, crlt_rad, car_rot for the target box. |
687 |
// unless the box center is off the disk. |
688 |
// For NoTrack case we have center_x and center_y in pixels |
689 |
|
690 |
// Get implied time limits from car_rot and crln |
691 |
t_ref = HeliographicTime(car_rot, crln); |
692 |
if (times_source == TIMES_IMPLICIT) |
693 |
{ |
694 |
if (t_start == tNotSpecified) |
695 |
{ |
696 |
if (NoTrack) DIE("Must have t_start or explicit times for NoTrack"); |
697 |
t_start = HeliographicTime(car_rot, crln + 90); |
698 |
} |
699 |
if (t_stop == tNotSpecified) |
700 |
{ |
701 |
if (NoTrack) DIE("Must have t_stop or explicit times for NoTrack"); |
702 |
t_stop = HeliographicTime(car_rot, crln - 90); |
703 |
} |
704 |
} |
705 |
// XXXXXXXXXXXXXXXXX End of get target box location |
706 |
|
707 |
// XXXXXXXXXXXXXXXX get input seriesname and output seriesname |
708 |
// first, get input and output series names. |
709 |
is_mod = 0; |
710 |
if (strcasecmp(outparam, "NOTSPECIFIED") == 0) |
711 |
{ |
712 |
strncpy(outseries, inseries, DRMS_MAXSERIESNAMELEN); |
713 |
strncat(outseries, "_mod", DRMS_MAXSERIESNAMELEN); |
714 |
is_mod = 1; |
715 |
} |
716 |
else |
717 |
{ |
718 |
strncpy(outseries, outparam, DRMS_MAXSERIESNAMELEN); |
719 |
strncpy(testseries, inseries, DRMS_MAXSERIESNAMELEN); |
720 |
strcat(testseries, "_mod"); |
721 |
if (strcmp(testseries, outseries) == 0) |
722 |
is_mod = 1; |
723 |
} |
724 |
|
725 |
// Now, make sure output series exists and get template record. |
726 |
outTemplate = drms_template_record(drms_env, outseries, &status); |
727 |
if (status || !outTemplate) DIE2("Output series can not be found: ", outseries); |
728 |
|
729 |
// Now find the prime time keyword name |
730 |
npkeys = inTemplate->seriesinfo->pidx_num; |
731 |
timekeyname = NULL; |
732 |
if (npkeys > 0) |
733 |
{ |
734 |
int i; |
735 |
for (i=0; i<npkeys; i++) |
736 |
{ |
737 |
DRMS_Keyword_t *pkey, *skey; |
738 |
pkey = inTemplate->seriesinfo->pidx_keywords[i]; |
739 |
if (pkey->info->recscope > 1) |
740 |
pkey = drms_keyword_slotfromindex(pkey); |
741 |
if (pkey->info->type != DRMS_TYPE_TIME) |
742 |
continue; |
743 |
if(i > 0) DIE("Input series must have TIME keyword first, for now..."); |
744 |
timekeyname = pkey->info->name; |
745 |
t_step = drms_keyword_getdouble(drms_keyword_stepfromslot(pkey), &status); |
746 |
if (status) DIE("problem getting t_step"); |
747 |
t_epoch = drms_keyword_getdouble(drms_keyword_epochfromslot(pkey), &status); |
748 |
if (status) DIE("problem getting t_epoch"); |
749 |
} |
750 |
} |
751 |
else |
752 |
DIE("Must have time prime key"); |
753 |
|
754 |
// Get cadence for output data. The output series should be slotted on a multiple of |
755 |
// the input series, multiple may be 1. |
756 |
|
757 |
if (strcasecmp(cadence_str, "NOTSPECIFIED") == 0) |
758 |
cadence = t_step; |
759 |
else |
760 |
{ |
761 |
int ratio; |
762 |
double initial_cadence; |
763 |
initial_cadence = atoinc((char *)cadence_str); |
764 |
ratio = round(initial_cadence/t_step); |
765 |
cadence = ratio * t_step; |
766 |
if (cadence != initial_cadence) |
767 |
fprintf(stderr,"Cadence rounded from %f to %f, since t_step == %f\n", initial_cadence, cadence, t_step); |
768 |
} |
769 |
|
770 |
// Finally, get input recordset spec |
771 |
if (lbracket && times_source == TIMES_RECSET) // RecordSet query specified |
772 |
strncpy(in, inparam, DRMS_MAXQUERYLEN); |
773 |
else // need to generate query from limit times |
774 |
{ |
775 |
char t_start_text[100], t_stop_text[100], cadence_text[100]; |
776 |
if (cadence > t_step) |
777 |
{ |
778 |
sprintf(cadence_text,"@%0.0fs", cadence); |
779 |
if (times_source == TIMES_IMPLICIT) // round start and stop to cadence slots for auto limits |
780 |
{ |
781 |
int nsteps; |
782 |
nsteps = round((t_start - t_epoch)/cadence); |
783 |
t_start = t_epoch + nsteps * cadence; |
784 |
nsteps = round((t_stop - t_epoch)/cadence); |
785 |
t_stop = t_epoch + nsteps * cadence; |
786 |
} |
787 |
} |
788 |
else |
789 |
cadence_text[0] = '\0'; |
790 |
sprint_at(t_start_text, t_start); |
791 |
sprint_at(t_stop_text, t_stop); |
792 |
sprintf(in, "%s[%s-%s%s]%s%s", inseries, t_start_text, t_stop_text, cadence_text, where, (moreQuery ? moreQuery : "")); |
793 |
} |
794 |
|
795 |
if (inparam) |
796 |
{ |
797 |
free(inparam); |
798 |
inparam = NULL; |
799 |
} |
800 |
|
801 |
// Check for specified epoch or cadence specified and not compact slotted series, replace query if needed |
802 |
if (cmdparams_exists(&cmdparams, "epoch") || (cadence > 1.0 && |
803 |
(strncmp(inseries, "aia.lev1", 8)==0 || strncmp(inseries, "hmi.lev1", 8)==0 ))) |
804 |
{ // special case for AIA and HMI lev1 slots |
805 |
char *new_in; |
806 |
new_in = get_input_recset(drms_env, in); |
807 |
if (new_in != in) |
808 |
{ |
809 |
strcpy(in, new_in); |
810 |
in_filename = new_in+1; |
811 |
} |
812 |
} |
813 |
|
814 |
// XXXXXXXXXXXXX End of get input and output series information |
815 |
|
816 |
// XXXXXXXXXXXXX Now read data and extract boxes. |
817 |
|
818 |
inRS = drms_open_records(drms_env, in, &status); |
819 |
if (status || inRS->n == 0) |
820 |
{ |
821 |
fprintf(stderr,"Query is: %s\n",in); |
822 |
DIE("No input data found"); |
823 |
} |
824 |
nrecs = inRS->n; |
825 |
|
826 |
// extract patches from each record |
827 |
int nextRec = 0; |
828 |
for (irec = 0; irec < nrecs; irec ++) |
829 |
{ |
830 |
double use_bzero, use_bscale; |
831 |
char history[4096]; |
832 |
|
833 |
nextRec = 0; |
834 |
|
835 |
*history = '\0'; |
836 |
inRec = inRS->records[irec]; |
837 |
if (status || !inRec) DIE("Record read failed."); |
838 |
|
839 |
|
840 |
TIME trec = drms_getkey_time(inRec, timekeyname, &status); TEST_PARAM(timekeyname); |
841 |
if (t_start != tNotSpecified && trec < t_start) |
842 |
{ |
843 |
continue; |
844 |
} |
845 |
if (t_stop != tNotSpecified && trec > t_stop) |
846 |
break; |
847 |
// skip records without images. |
848 |
if (drms_keyword_lookup(inRec, "QUALITY", 1)) |
849 |
{ |
850 |
int quality = drms_getkey_int(inRec, "QUALITY", &status); |
851 |
if (quality < 0) |
852 |
{ |
853 |
continue; |
854 |
} |
855 |
} |
856 |
|
857 |
// get venus or other transit object location |
858 |
if (FDSfile) |
859 |
{ |
860 |
TIME t_obs = drms_getkey_time(inRec, "T_OBS", NULL); |
861 |
if(get_tracking_xy((char *)FDSfile, t_obs, &trackx, &tracky, &track_radius)) |
862 |
DIE("Failed to open FDS file"); |
863 |
if (VERBOSE) fprintf(stderr,"xxxx called get_tracking, trackx=%f, tracky=%f, radius=%f\n",trackx,tracky,track_radius); |
864 |
} |
865 |
|
866 |
// get coordinate information for this image |
867 |
this_car_rot = drms_getkey_int(inRec, "CAR_ROT", &status); TEST_PARAM("CAR_ROT"); |
868 |
crlt_obs = drms_getkey_double(inRec, "CRLT_OBS", &status); TEST_PARAM("CRLT_OBS"); |
869 |
// crln_obs = drms_getkey_double(inRec, "CRLN_OBS", &status); TEST_PARAM("CRLN_OBS"); |
870 |
crln_obs = get_new_CRLN_OBS(inRec, &status); TEST_PARAM("CRLN_OBS"); |
871 |
crpix1 = drms_getkey_double(inRec, "CRPIX1", &status); TEST_PARAM("CRPIX1"); |
872 |
x0 = crpix1 - 1; |
873 |
crpix2 = drms_getkey_double(inRec, "CRPIX2", &status); TEST_PARAM("CRPIX2"); |
874 |
y0 = crpix2 - 1; |
875 |
crota = drms_getkey_double(inRec, "CROTA2", &status); TEST_PARAM("CROTA2"); |
876 |
cdelt = drms_getkey_double(inRec, "CDELT1", &status); TEST_PARAM("CDELT1"); |
877 |
pa = -crota; |
878 |
|
879 |
int paIs180 = 0; |
880 |
if (fabs(fabs(pa)-180.0) < 1.0) |
881 |
{ |
882 |
paIs180 = 1; |
883 |
} |
884 |
|
885 |
crlt_obs_rad = Deg2Rad * crlt_obs; |
886 |
crln_obs_rad = Deg2Rad * crln_obs; |
887 |
pa_rad = Deg2Rad * pa; |
888 |
sina = sin(crota*Deg2Rad); |
889 |
cosa = cos(crota*Deg2Rad); |
890 |
|
891 |
if (VERBOSE) fprintf(stderr,"T_OBS=%s, crpix1=%f, crpix2=%f\n", drms_getkey_string(inRec,"T_OBS", NULL), crpix1, crpix2); |
892 |
|
893 |
// XXXXXXXXXXXXXXXXX get coordinate mapping info using keywords from first record |
894 |
if (firstimage) |
895 |
{ |
896 |
firstimage = 0; |
897 |
// firstimage values for register to first image option. |
898 |
int idx, idy; |
899 |
idx = crpix1 + 0.5; |
900 |
idy = crpix2 + 0.5; |
901 |
crpix1_0 = idx; |
902 |
crpix2_0 = idy; |
903 |
|
904 |
if (loctype==LOCCARR) |
905 |
{ |
906 |
tmpstr = drms_getkey_string(inRec, "CTYPE1", &status); |
907 |
ctype1 = strdup(tmpstr); TEST_PARAM("CTYPE1"); |
908 |
if (tmpstr) |
909 |
{ |
910 |
free(tmpstr); |
911 |
} |
912 |
|
913 |
tmpstr = drms_getkey_string(inRec, "CTYPE2", &status); |
914 |
if (strcmp(ctype1, "HPLN-TAN") != 0) DIE2("CTYPE1 not HPLN-TAN as required, is: ", ctype1); |
915 |
if (ctype1) |
916 |
{ |
917 |
free(ctype1); |
918 |
ctype1 = NULL; |
919 |
} |
920 |
ctype2 = strdup(tmpstr); TEST_PARAM("CTYPE2"); |
921 |
if (tmpstr) |
922 |
{ |
923 |
free(tmpstr); |
924 |
} |
925 |
|
926 |
if (strcmp(ctype2, "HPLT-TAN") != 0) DIE2("CTYPE2 not HPLT-TAN as required, is: ", ctype2); |
927 |
if (ctype2) |
928 |
{ |
929 |
free(ctype2); |
930 |
ctype2 = NULL; |
931 |
} |
932 |
rsun_ref = drms_getkey_double(inRec, "RSUN_REF", &status); |
933 |
if (status) rsun_ref = 6.96e8; |
934 |
dsun_obs = drms_getkey_double(inRec, "DSUN_OBS", &status); TEST_PARAM("DSUN_OBS"); |
935 |
rsun_rad = asin(rsun_ref/dsun_obs); |
936 |
rsun = rsun_rad*Rad2arcsec; |
937 |
cdelt = drms_getkey_double(inRec, "CDELT1", &status); TEST_PARAM("CDELT1"); |
938 |
// in principle use deltlong to get time to use for correcting crlt_obs, ignore for now |
939 |
// get ur, ll coords of box at CM. |
940 |
rsunpix = rsun/cdelt; |
941 |
} |
942 |
|
943 |
if (boxtype == BOXDEGREE) |
944 |
{ |
945 |
int nx, ny; |
946 |
double urx, ury; |
947 |
// get corners of sample box at zero longitude wrt center. |
948 |
sphere2img(Deg2Rad*(crlt+height/2), Deg2Rad*(width/2), crlt_obs_rad, 0.0, |
949 |
&urx, &ury, 0.0, 0.0, rsunpix, pa_rad, 0, 0, 0, 0); |
950 |
sphere2img(Deg2Rad*(crlt-height/2), -Deg2Rad*(width/2), crlt_obs_rad, 0.0, |
951 |
&llx, &lly, 0.0, 0.0, rsunpix, pa_rad, 0, 0, 0, 0); |
952 |
// llx, urx, lly, ury are image coordinates for Sun, want llx and lly |
953 |
// on plate so need to swap if image rotated. |
954 |
nx = urx - llx ; |
955 |
ny = ury - lly ; |
956 |
if (nx < 0) { nx = -nx; llx = urx; } |
957 |
if (ny < 0) { ny = -ny; lly = ury; } |
958 |
pixwidth = nx + 1; |
959 |
pixheight = ny + 1; |
960 |
} |
961 |
else if (boxtype==BOXARCSEC) |
962 |
{ |
963 |
int nx, ny; |
964 |
llx = -width/(2.0*cdelt); |
965 |
lly = -height/(2.0*cdelt); |
966 |
pixwidth = 1 - 2 * llx; |
967 |
pixheight = 1 - 2 * lly; |
968 |
} |
969 |
else /* boxtype == BOXPIXELS */ |
970 |
{ |
971 |
pixwidth = round(width); |
972 |
pixheight = round(height); |
973 |
llx = -pixwidth / 2.0; |
974 |
lly = -pixheight / 2.0; |
975 |
} |
976 |
} |
977 |
|
978 |
if (!NoTrack) |
979 |
{ |
980 |
if (FDSfile) |
981 |
{ |
982 |
center_x = PIX_X(trackx,tracky) - 1; |
983 |
center_y = PIX_Y(trackx,tracky) - 1; |
984 |
sprintf(history+strlen(history), "Image center tracked as per %s\n", FDSfile); |
985 |
fprintf(stderr,"center_x=%f,center_y=%f\n",center_x,center_y); |
986 |
} |
987 |
else |
988 |
sphere2img(crlt_rad, crln_rad, crlt_obs_rad, crln_obs_rad, ¢er_x, ¢er_y, x0, y0, rsunpix, pa_rad, 0, 0, 0, 0); |
989 |
} |
990 |
// center_x and center_y are target locations for the center of the desired patch, pixels from 0 of as-is image. |
991 |
// note HMI has not been flipped at this point |
992 |
|
993 |
target_x = center_x; |
994 |
target_y = center_y; |
995 |
int x1Orig; |
996 |
int y1Orig; |
997 |
|
998 |
int x1 = round(target_x + llx); |
999 |
int y1 = round(target_y + lly); |
1000 |
int x2 = x1 + pixwidth - 1; |
1001 |
int y2 = y1 + pixheight - 1; |
1002 |
if (do_register) |
1003 |
{ |
1004 |
x1 -= register_padding; |
1005 |
y1 -= register_padding; |
1006 |
x2 += register_padding; |
1007 |
y2 += register_padding; |
1008 |
} |
1009 |
crpix1 = 1 + x0 - x1; |
1010 |
crpix2 = 1 + y0 - y1; |
1011 |
if (VERBOSE) fprintf(stderr,"at box define, crpix1=%f, x0=%f, x1=%d\n",crpix1,x0,x1); |
1012 |
|
1013 |
int start1[2] = {x1, y1}; |
1014 |
int end1[2] = {x2, y2}; |
1015 |
|
1016 |
outRS = drms_create_records(drms_env, 1, outseries, DRMS_PERMANENT, &status); |
1017 |
if (status) {fprintf(stderr,"Output series is %s, ",outseries); DIE("Cant make outout record");} |
1018 |
outRec = outRS->records[0]; |
1019 |
|
1020 |
|
1021 |
if (do_crop) |
1022 |
{ |
1023 |
/* BEFORE SEG LOOP */ |
1024 |
int retStat; |
1025 |
dsun_obs = drms_getkey_double(inRec, "DSUN_OBS", &retStat); |
1026 |
rsun_rad = asin(rsun_ref/dsun_obs); |
1027 |
rsun = rsun_rad*Rad2arcsec/cdelt; |
1028 |
r2 = rsun*rsun; |
1029 |
r2 *= 0.9995; |
1030 |
|
1031 |
/* WE HAVE TO CALCULATE this_x0 and this_y0 now, before paIs180 modifies crpix1 and crpix2. */ |
1032 |
this_x0 = crpix1 - 1; |
1033 |
this_y0 = crpix2 - 1; |
1034 |
} |
1035 |
|
1036 |
/* We need to adjust pa and crota if |pa| == 180. Originally, this was done in code that was mixed with |
1037 |
* per-segment code. But now that we made a per-segment loop, we do not want to execute this code more than |
1038 |
* once. So I moved it here, right before the segment loop. */ |
1039 |
|
1040 |
/* These might be modified in the paIs180 block of code, but we need to use the original values |
1041 |
* later. */ |
1042 |
x1Orig = x1; |
1043 |
y1Orig = y1; |
1044 |
|
1045 |
if (paIs180) |
1046 |
{ |
1047 |
pa -= 180.0; /* This actually does not get used again during the rest of the record loop, and is not used by the segment loop. */ |
1048 |
crota -= 180.0; |
1049 |
|
1050 |
crpix1 = 1 + x2 - x0; |
1051 |
crpix2 = 1 + y2 - y0; |
1052 |
if (VERBOSE) fprintf(stderr,"after rotate, crpix1=%f\n",crpix1); |
1053 |
|
1054 |
// adjust internal quantities for after the flip, may be needed by do_register. |
1055 |
/* But we will need the original values of x1 and y1 in the code that handles the patch-image intersection. |
1056 |
* These quantities are saved in x1orig and y1orig. |
1057 |
*/ |
1058 |
x1 = inAxis[0] - 1 - x2; |
1059 |
y1 = inAxis[1] - 1 - y2; |
1060 |
target_x = inAxis[0] - 1 - center_x; |
1061 |
target_y = inAxis[1] - 1 - center_y; |
1062 |
// cosa = 1.0; sina = 0.0; |
1063 |
strcat(history, "Image rotated 180 degrees."); |
1064 |
if (VERBOSE) fprintf(stderr,"after flip x1=%d, target_x=%lf, y1=%d, target_y=%lf\n",x1,target_x,y1,target_y); |
1065 |
} |
1066 |
|
1067 |
/* At this point, all the modifications to x1, y1, target_x, and target_y have been performed, |
1068 |
* so it is safe to calculate dx and dy. target_x, target_y are the pixel address of the part of |
1069 |
* the image that we want to be in the center of the output array. */ |
1070 |
|
1071 |
/* |
1072 |
* To simplify things, error-out if the input segment's patches dimensions are not equivalent. |
1073 |
* Also, we need to calculate dx and dy, which require that we know the intersection of the |
1074 |
* patch box with the image. |
1075 |
*/ |
1076 |
DRMS_Segment_t *firstSeg = NULL; |
1077 |
HIterator_t *segIter = NULL; |
1078 |
DRMS_Segment_t *orig = NULL; |
1079 |
|
1080 |
float regShiftX = 0; |
1081 |
float regShiftY = 0; |
1082 |
char patchIntersection; |
1083 |
|
1084 |
while ((inSeg = drms_record_nextseg2(inRec, &segIter, 1, &orig)) != NULL) |
1085 |
{ |
1086 |
if (!firstSeg) |
1087 |
{ |
1088 |
firstSeg = inSeg; |
1089 |
|
1090 |
/* Calculate the ultimate patch dimensions. */ |
1091 |
/* We need to use the original x1 and y1, not the ones modified by paIs180. */ |
1092 |
if (x1Orig >= inSeg->axis[0] || y1Orig >= inSeg->axis[1] || x2 < 0 || y2 < 0) |
1093 |
{ |
1094 |
// patch completely outside image |
1095 |
patchIntersection = 'N'; |
1096 |
/* The record needs to be skipped. Downstream code will handle this. */ |
1097 |
} |
1098 |
else if (x1Orig >= 0 && y1Orig >= 0 && x2 < inSeg->axis[0] && y2 < inSeg->axis[1]) |
1099 |
{ |
1100 |
// patch entirely in image. |
1101 |
patchIntersection = 'F'; |
1102 |
} |
1103 |
else |
1104 |
{ |
1105 |
// patch partly outside image. |
1106 |
patchIntersection = 'P'; |
1107 |
} |
1108 |
} |
1109 |
else |
1110 |
{ |
1111 |
if (!hasSegList && !doingAllSegs) |
1112 |
{ |
1113 |
/* No need to ensure post-first segment matches the first segment since we are processing only the first segment. */ |
1114 |
break; |
1115 |
} |
1116 |
|
1117 |
/* Ensure that both segments are of the same dimensions (both in number and size of each dimension). */ |
1118 |
int iSeg; |
1119 |
int mismatch; |
1120 |
|
1121 |
mismatch = 0; |
1122 |
if (firstSeg->info->naxis == inSeg->info->naxis) |
1123 |
{ |
1124 |
for (iSeg = 0; iSeg < firstSeg->info->naxis; iSeg++) |
1125 |
{ |
1126 |
if (firstSeg->axis[iSeg] != inSeg->axis[iSeg]) |
1127 |
{ |
1128 |
mismatch = 1; |
1129 |
break; |
1130 |
} |
1131 |
} |
1132 |
} |
1133 |
else |
1134 |
{ |
1135 |
mismatch = 1; |
1136 |
} |
1137 |
|
1138 |
if (!mismatch) |
1139 |
{ |
1140 |
if (firstSeg->info->protocol == DRMS_TAS && inSeg->info->protocol == DRMS_TAS) |
1141 |
{ |
1142 |
for (iSeg = 0; iSeg < firstSeg->info->protocol; iSeg++) |
1143 |
{ |
1144 |
if (firstSeg->blocksize[iSeg] != inSeg->blocksize[iSeg]) |
1145 |
{ |
1146 |
mismatch = 1; |
1147 |
break; |
1148 |
} |
1149 |
} |
1150 |
} |
1151 |
} |
1152 |
|
1153 |
if (mismatch) |
1154 |
{ |
1155 |
DIE("When processing more than one segment, all segments' dimensions must match."); |
1156 |
} |
1157 |
} |
1158 |
} /* Not the real segment loop. */ |
1159 |
|
1160 |
if (segIter) |
1161 |
{ |
1162 |
hiter_destroy(&segIter); |
1163 |
} |
1164 |
|
1165 |
drms_copykeys(outRec, inRec, 0, kDRMS_KeyClass_Explicit); |
1166 |
drms_sprint_rec_query(inQuery, inRec); |
1167 |
drms_setkey_string(outRec, "SOURCE", inQuery); |
1168 |
drms_appendhistory(outRec, inQuery, 1); |
1169 |
drms_setkey_time(outRec, "T_REC", trec); |
1170 |
drms_setkey_double(outRec, "CRVAL1", 0.0); |
1171 |
drms_setkey_double(outRec, "CRVAL2", 0.0); |
1172 |
drms_setkey_double(outRec, "CRDELT1", cdelt); |
1173 |
drms_setkey_double(outRec, "CRDELT2", cdelt); |
1174 |
|
1175 |
if (do_register) |
1176 |
{ |
1177 |
/* It used to be the case that in the per-segment code, if do_register was set, then |
1178 |
* crota got set to 0.0, and they the crota2 keyword got assigned that value. |
1179 |
* But now that we have a segment loop, we cannot set crota to 0.0 in the per-segment |
1180 |
* code, otherwise we lose the value of crota needed by the second and greater |
1181 |
* segment. */ |
1182 |
drms_setkey_double(outRec, "CROTA2", 0.0); |
1183 |
} |
1184 |
else |
1185 |
{ |
1186 |
drms_setkey_double(outRec, "CROTA2", crota); |
1187 |
} |
1188 |
|
1189 |
drms_setkey_string(outRec, "CONTENT", "Tracked Extracted Patches, made by im_patch"); |
1190 |
drms_appendcomment(outRec, "Patches", 1); |
1191 |
drms_setkey_string(outRec, "RequestID", requestid); |
1192 |
drms_setkey_string(outRec, "HGBOXUNITS", boxunits); |
1193 |
drms_setkey_string(outRec, "HGLOCUNITS", locunits); |
1194 |
drms_setkey_float(outRec, "HGWIDE", width); |
1195 |
drms_setkey_float(outRec, "HGHIGH", height); |
1196 |
drms_setkey_float(outRec, "HGCRLN", crln); |
1197 |
drms_setkey_float(outRec, "HGCRLT", crlt); |
1198 |
drms_setkey_int(outRec, "HGCARROT", car_rot); |
1199 |
drms_setkey_time(outRec, "HGTSTART", t_start); |
1200 |
drms_setkey_time(outRec, "HGTSTOP", t_stop); |
1201 |
drms_setkey_time(outRec, "DATE", time(0) + UNIX_EPOCH); |
1202 |
drms_setkey_string(outRec, "HGQUERY", in); |
1203 |
drms_setkey_double(outRec, "CRLN_OBS", crln_obs); |
1204 |
update_CALVERxx(inRec, outRec, 1<<28); |
1205 |
if (VERBOSE) fprintf(stderr,"DATAMIN=%f, DATAMAX=%f\n",drms_getkey_float(outRec,"DATAMIN",NULL),drms_getkey_float(outRec,"DATAMAX",NULL)); |
1206 |
|
1207 |
/* |
1208 |
* writing the extracted region data file |
1209 |
*/ |
1210 |
/* Make sure the output series is compatible with the input series. |
1211 |
* The input series and output series must have the same-named segments in |
1212 |
* the same order, with one exception. If there is only a single segment in |
1213 |
* the input series and only a single segment in the output segment, then |
1214 |
* the names can differ. In that case, this code will assume that the output |
1215 |
* patch will go in the single output series. |
1216 |
*/ |
1217 |
int numInSegs = hcon_size(&(inTemplate->segments)); |
1218 |
int numOutSegs = hcon_size(&(outTemplate->segments)); |
1219 |
|
1220 |
if (numInSegs != numOutSegs) |
1221 |
{ |
1222 |
DIE("Input and output series are incompatible (the number of segments differs).\n"); |
1223 |
} |
1224 |
|
1225 |
if (numInSegs < 1) |
1226 |
{ |
1227 |
DIE("The input series must have at least one segment.\n"); |
1228 |
} |
1229 |
|
1230 |
/* inSeg - |
1231 |
* The third argument to drms_record_nextseg2() indicates that a link should be followed. |
1232 |
* |
1233 |
*/ |
1234 |
int iSeg = 0; |
1235 |
char msgBuf[512]; |
1236 |
|
1237 |
while ((inSeg = drms_record_nextseg2(inRec, &segIter, 1, &orig)) != NULL) |
1238 |
{ |
1239 |
/* THIS IS THE REAL SEGMENT LOOP. */ |
1240 |
if (!hasSegList && !doingAllSegs && iSeg > 0) |
1241 |
{ |
1242 |
/* We've already processed the first segment, and there is no seglist specifier, so we are not processing segments other |
1243 |
* than the first one. */ |
1244 |
break; |
1245 |
} |
1246 |
|
1247 |
/* Pin the first segment that meets these conditions: |
1248 |
* + The segment protocol is either FITS or TAS. |
1249 |
* + NAXIS == 2. |
1250 |
* + CTYPE1 == CTYPE2 == 'HPLN-TAN' (but the keyword-reading code |
1251 |
* already rejects records for which this isn't true). |
1252 |
* + The existence of these keywords for the segment: |
1253 |
* CAR_ROT |
1254 |
* CRLT_OBS |
1255 |
* CRLN_OBS |
1256 |
* CRPIX1 |
1257 |
* CRPIX2 |
1258 |
* CRVAL1 |
1259 |
* CRVAL2 |
1260 |
* CROTA2 |
1261 |
* CTYPE1 |
1262 |
* CTYPE2 |
1263 |
* DSUN_OBS |
1264 |
* CDELT1 |
1265 |
* T_REC or T_OBS |
1266 |
* (but the keyword-reading code already rejects records for which |
1267 |
* this isn't true). |
1268 |
* |
1269 |
* Once a segment is pinned, then all following segments must have WCS |
1270 |
* keyword values that match the WCS keyword values of the pinned segment. |
1271 |
* However, since this module rejects series with per-segment WCS keywords, |
1272 |
* this will also already be true. |
1273 |
* |
1274 |
* So as long as the current segment has NAXIS == 2 and is a FITS or TAS segment, |
1275 |
* then we can process it, even if it is a linked segment. |
1276 |
*/ |
1277 |
|
1278 |
/* The input series and output series must have the same-named segments in |
1279 |
* the same order, with one exception. If there is only a single segment in |
1280 |
* the input series and only a single segment in the output segment, then |
1281 |
* the names can differ. In that case, this code will assume that the output |
1282 |
* patch will go in the single output series. |
1283 |
* |
1284 |
* A check for the two series having the same number of segments was already performed, |
1285 |
* before the segment loop. |
1286 |
* |
1287 |
* Must use orig, not inSeg, since inSeg could be a followed link. |
1288 |
*/ |
1289 |
outSeg = drms_segment_lookupnum(outRec, orig->info->segnum); |
1290 |
|
1291 |
if (outSeg == NULL || (numInSegs != 1 && strncasecmp(orig->info->name, outSeg->info->name, DRMS_MAXSEGNAMELEN - 1) != 0)) |
1292 |
{ |
1293 |
/* Incompatible output series. */ |
1294 |
snprintf(msgBuf, sizeof(msgBuf), "Input and output series are incompatible (there is no segment named %s in the output series).\n", orig->info->name); |
1295 |
DIE(msgBuf); |
1296 |
} |
1297 |
|
1298 |
if (inSeg->info->naxis != 2 || (inSeg->info->protocol != DRMS_FITZ && inSeg->info->protocol != DRMS_FITS && inSeg->info->protocol != DRMS_TAS)) |
1299 |
{ |
1300 |
/* The input series' segment must be a 2D FITS-type of segment. */ |
1301 |
snprintf(msgBuf, sizeof(msgBuf), "Input segment %s is not a 2D FITS segment.\n", orig->info->name); |
1302 |
} |
1303 |
|
1304 |
inAxis[0] = inSeg->axis[0]; |
1305 |
inAxis[1] = inSeg->axis[1]; |
1306 |
|
1307 |
/* We need to use the original x1 and y1, not the ones modified in paIs180. */ |
1308 |
if (patchIntersection == 'N') |
1309 |
{ // patch completely outside image |
1310 |
fprintf(stderr, "patch completely outside image, x1=%d, y1=%d, x2=%d, y2=%d\n", x1Orig, y1Orig, x2, y2); |
1311 |
/* If the patch is completely outside of one image, it is completely outside all images |
1312 |
* since all images must be of the same dimensions. So break out of segment loop. */ |
1313 |
nextRec = 1; |
1314 |
break; |
1315 |
} |
1316 |
else if (patchIntersection == 'F') |
1317 |
{ // patch entirely in image. |
1318 |
status = 0; |
1319 |
outArray = drms_segment_readslice(inSeg, DRMS_TYPE_FLOAT, start1, end1, &status); |
1320 |
if (status) DIE("Cant read input record"); |
1321 |
if (VERBOSE) fprintf(stderr,"$$$$$$$ outArray bzero, bscale are %f, %f\n", outArray->bzero, outArray->bscale); |
1322 |
} |
1323 |
else |
1324 |
{ // patch partly outside image. |
1325 |
int dims[2] = {x2-x1Orig+1,y2-y1Orig+1}; |
1326 |
int start2[2], end2[2]; |
1327 |
|
1328 |
int x,y; |
1329 |
outArray = drms_array_create(DRMS_TYPE_FLOAT, 2, dims, NULL, &status); |
1330 |
drms_array2missing(outArray); |
1331 |
|
1332 |
start2[0] = x1Orig < 0 ? 0 : x1Orig; |
1333 |
start2[1] = y1Orig < 0 ? 0 : y1Orig; |
1334 |
end2[0] = x2 >= inAxis[0] ? inAxis[0]-1 : x2; |
1335 |
end2[1] = y2 >= inAxis[1] ? inAxis[1]-1 : y2; |
1336 |
|
1337 |
status = 0; |
1338 |
inArray = drms_segment_readslice(inSeg, DRMS_TYPE_FLOAT, start2, end2, &status); |
1339 |
if (status || !inArray) DIE("Cant read input record"); |
1340 |
|
1341 |
//fprintf(stderr,"$$$$$$$ inArray bzero, bscale are %f, %f\n",inArray->bzero, inArray->bscale); |
1342 |
outArray->bzero = inArray->bzero; |
1343 |
outArray->bscale = inArray->bscale; |
1344 |
|
1345 |
int start3[2] = {start2[0]-start1[0],start2[1]-start1[1]}; // fetched slice offset in outarray |
1346 |
int end3[2] = {end2[0]-end1[0],end2[1]-end1[1]}; // fetched slice offset in outarray |
1347 |
int n3x = end2[0] - start2[0] + 1; |
1348 |
int n3y = end2[1] - start2[1] + 1; |
1349 |
|
1350 |
for (y=0; y< n3y; y++) |
1351 |
{ |
1352 |
for (x=0; x < n3x; x++) |
1353 |
{ |
1354 |
*((float *)outArray->data + ((start3[1]+y)*dims[0] + x + start3[0])) = |
1355 |
*((float *)inArray->data + (y*n3x + x)); |
1356 |
} |
1357 |
} |
1358 |
|
1359 |
drms_free_array(inArray); |
1360 |
} |
1361 |
|
1362 |
use_bzero = outArray->bzero; |
1363 |
use_bscale = outArray->bscale; |
1364 |
|
1365 |
// Handle crop if wanted |
1366 |
if (do_crop) |
1367 |
{ |
1368 |
int stat; |
1369 |
// rsun_ref and cdelt defined above |
1370 |
float *data = (float *)outArray->data; |
1371 |
int i,j; |
1372 |
int nx = outArray->axis[0]; |
1373 |
int ny = outArray->axis[1]; |
1374 |
|
1375 |
for (j=0; j<ny; j++) |
1376 |
{ |
1377 |
for (i=0; i<nx; i++) |
1378 |
{ |
1379 |
double x = i - this_x0; |
1380 |
double y = j - this_y0; |
1381 |
|
1382 |
if ((x*x + y*y) >= r2) |
1383 |
{ |
1384 |
data[j*nx + i] = DRMS_MISSING_FLOAT; |
1385 |
} |
1386 |
} |
1387 |
} |
1388 |
} |
1389 |
|
1390 |
// Always handle special case where |pa| == 180 |
1391 |
if (paIs180) |
1392 |
{ |
1393 |
// Tracking should be OK for center, but patch rotated. Flip on both axes. |
1394 |
float *data = (float *)outArray->data; |
1395 |
int i,j; |
1396 |
int nx = outArray->axis[0]; |
1397 |
int ny = outArray->axis[1]; |
1398 |
int midrow = (ny)/2; |
1399 |
int midcol = (nx)/2; |
1400 |
float val; |
1401 |
|
1402 |
for (j=0; j<midrow; j++) |
1403 |
{ |
1404 |
for (i=0; i<nx; i++) |
1405 |
{ |
1406 |
val = data[j*nx + i]; |
1407 |
data[j*nx + i] = data[(ny - 1 - j)*nx + nx - 1 - i]; |
1408 |
data[(ny - 1 - j)*nx + nx - 1 - i] = val; |
1409 |
} |
1410 |
} |
1411 |
|
1412 |
if ((ny & 1) != 0) |
1413 |
{ |
1414 |
for (i=0; i<midcol; i++) |
1415 |
{ |
1416 |
val = data[midrow*nx + i]; |
1417 |
data[midrow*nx + i] = data[midrow*nx + nx - 1 - i]; |
1418 |
data[midrow*nx + nx - 1 - i] = val; |
1419 |
} |
1420 |
} |
1421 |
} |
1422 |
|
1423 |
/* |
1424 |
* Register fraction of pixel to target location, if desired |
1425 |
*/ |
1426 |
if (do_register) |
1427 |
{ |
1428 |
/* IN SEG LOOP */ |
1429 |
DRMS_Array_t *tmpArray; |
1430 |
int status; |
1431 |
int i,j; |
1432 |
float *data = (float *)outArray->data; |
1433 |
float *newdata = NULL; |
1434 |
int newnx, newny; |
1435 |
int nx = outArray->axis[0]; |
1436 |
int ny = outArray->axis[1]; |
1437 |
float midx = (nx-1)/2.0; |
1438 |
float midy = (ny-1)/2.0; |
1439 |
// x1+midx is the data pixel that was just placed at the center of the output array. |
1440 |
// target_x is the pixel that contains the data we want to have in the center of the output array. |
1441 |
float dx = (x1 + midx) - target_x; |
1442 |
float dy = (y1 + midy) - target_y; |
1443 |
|
1444 |
/* We do not want to adjust crpix1 and crpix2 more than once per record. */ |
1445 |
if (iSeg == 0) |
1446 |
{ |
1447 |
sprintf(history+strlen(history), "\nImage registered by shift of (%0.3f,%0.3f) pixels.", dx, dy); |
1448 |
crpix1 += dx - register_padding; |
1449 |
crpix2 += dy - register_padding; |
1450 |
} |
1451 |
|
1452 |
regShiftX = dx; |
1453 |
regShiftY = dy; |
1454 |
|
1455 |
int dtyp = 3; |
1456 |
|
1457 |
if (status=image_magrotate((void *)data, nx, ny, dtyp, crota, 1.0, regShiftX, regShiftY, &(void *)newdata, &newnx, &newny, 1, 0)) |
1458 |
{ |
1459 |
DIE("XXXX Failure in call to image_magrotate. Either malloc error or nx or ny too large. Must quit.\n"); |
1460 |
} |
1461 |
|
1462 |
if (newnx != nx || newny != ny) |
1463 |
{ |
1464 |
fprintf(stderr,"image_magrotate changed dimensions: nx want %d got %d, ny want %d got %d\n",nx,newnx,ny,newny); |
1465 |
} |
1466 |
|
1467 |
drms_free_array(outArray); |
1468 |
int outdims[2] = {pixwidth, pixheight}; |
1469 |
outArray = drms_array_create(DRMS_TYPE_FLOAT, 2, outdims, NULL, &status); |
1470 |
data = (float *)outArray->data; |
1471 |
for (j=0; j<pixheight; j++) |
1472 |
{ |
1473 |
for (i=0; i< pixwidth; i++) |
1474 |
{ |
1475 |
data[j*pixwidth + i] = newdata[(j+register_padding)*nx + i+register_padding]; |
1476 |
} |
1477 |
} |
1478 |
|
1479 |
/* This was being leaked - over 4MB per call. */ |
1480 |
if (newdata) |
1481 |
{ |
1482 |
free(newdata); |
1483 |
newdata = NULL; |
1484 |
} |
1485 |
|
1486 |
outArray->bzero = use_bzero; |
1487 |
outArray->bscale = use_bscale; |
1488 |
} |
1489 |
|
1490 |
set_statistics(outSeg, outArray, 1); // do this before adding possible FAKE image |
1491 |
|
1492 |
if (wantFAKE && FDSfile) |
1493 |
{ |
1494 |
// fprintf(stderr,"XXXX in wantFAKE and FDSfile\n"); |
1495 |
double r; |
1496 |
int ix0, iy0; |
1497 |
int nx = outArray->axis[0]; |
1498 |
int ny = outArray->axis[1]; |
1499 |
double x0, y0, r2; |
1500 |
float *data = (float *)outArray->data; |
1501 |
float datamax = drms_getkey_float(outRec, "DATAMAX", NULL); |
1502 |
int ix,iy,ir,ir2; |
1503 |
|
1504 |
if (NoTrack) |
1505 |
{ |
1506 |
x0 = trackx/cdelt + crpix1; |
1507 |
y0 = tracky/cdelt + crpix2; |
1508 |
} |
1509 |
else |
1510 |
{ |
1511 |
x0 = nx/2.0; |
1512 |
y0 = ny/2.0; |
1513 |
} |
1514 |
|
1515 |
if (VERBOSE) fprintf(stderr,"XXXXx x0=%f, yo=%f\n",x0,y0); |
1516 |
ix0 = x0+0.5; |
1517 |
iy0 = y0+0.5; |
1518 |
// r = 28.9/cdelt; // venus radius in pixels |
1519 |
r = track_radius/cdelt; // venus radius in pixels |
1520 |
ir = r + 0.5; |
1521 |
r2 = r*r; |
1522 |
|
1523 |
for (ix = -ir; ix <= ir; ix++) |
1524 |
{ |
1525 |
for (iy = -ir; iy <= ir; iy++) |
1526 |
{ |
1527 |
x = x0 - ix0 + ix; |
1528 |
y = y0 - iy0 + iy; |
1529 |
if (x*x + y*y < r2 && ix0+ix >=0 && ix0+ix < nx && iy0+iy >=0 && iy0+iy < ny) |
1530 |
{ |
1531 |
if (wantFAKEwhite) |
1532 |
{ |
1533 |
data[(iy+iy0)*nx + (ix+ix0)] = datamax; |
1534 |
} |
1535 |
else |
1536 |
{ |
1537 |
if (ix==0 || iy==0) |
1538 |
{ |
1539 |
data[(iy+iy0)*nx + (ix+ix0)] = datamax; |
1540 |
} |
1541 |
else |
1542 |
{ |
1543 |
data[(iy+iy0)*nx + (ix+ix0)] = 0.0; |
1544 |
} |
1545 |
} |
1546 |
} |
1547 |
} |
1548 |
} |
1549 |
} |
1550 |
|
1551 |
if (iSeg == 0) |
1552 |
{ |
1553 |
drms_setkey_double(outRec, "CRPIX1", crpix1); |
1554 |
drms_setkey_double(outRec, "CRPIX2", crpix2); |
1555 |
} |
1556 |
|
1557 |
if (export_keys) |
1558 |
{ |
1559 |
status = drms_segment_writewithkeys(outSeg, outArray, 0); |
1560 |
} |
1561 |
else |
1562 |
{ |
1563 |
status = drms_segment_write(outSeg, outArray, 0); |
1564 |
} |
1565 |
|
1566 |
if (status) |
1567 |
{ |
1568 |
DIE("problem writing file"); |
1569 |
} |
1570 |
|
1571 |
if (outArray) |
1572 |
{ |
1573 |
drms_free_array(outArray); |
1574 |
outArray = NULL; |
1575 |
} |
1576 |
|
1577 |
iSeg++; |
1578 |
} /* end segment loop */ |
1579 |
|
1580 |
if (segIter) |
1581 |
{ |
1582 |
hiter_destroy(&segIter); |
1583 |
} |
1584 |
|
1585 |
if (log) |
1586 |
{ |
1587 |
drms_fprint_rec_query(log, outRec); |
1588 |
fprintf(log, "\n"); |
1589 |
} |
1590 |
|
1591 |
if (*history) |
1592 |
drms_appendhistory(outRec, history, 1); |
1593 |
|
1594 |
if (nextRec) |
1595 |
{ |
1596 |
drms_close_records(outRS, DRMS_FREE_RECORD); |
1597 |
continue; |
1598 |
} |
1599 |
else |
1600 |
{ |
1601 |
drms_close_records(outRS, DRMS_INSERT_RECORD); |
1602 |
drms_free_array(outArray); |
1603 |
} |
1604 |
|
1605 |
OK_recs += 1; |
1606 |
} /* end record loop */ |
1607 |
|
1608 |
drms_close_records(inRS, DRMS_FREE_RECORD); |
1609 |
if (in_filename) |
1610 |
{ |
1611 |
unlink(in_filename); |
1612 |
} |
1613 |
|
1614 |
if (OK_recs) |
1615 |
printf(" DONE, %d records made! \n \n",OK_recs); |
1616 |
else |
1617 |
printf(" DONE but no useful records created! \n \n"); |
1618 |
|
1619 |
if (log) |
1620 |
fclose(log); |
1621 |
return DRMS_SUCCESS; |
1622 |
} // |
1623 |
|
1624 |
/* |
1625 |
* |
1626 |
* FUNCTIONS |
1627 |
* |
1628 |
* img2sphere() |
1629 |
* |
1630 |
* Written: Rick Bogart |
1631 |
* |
1632 |
*/ |
1633 |
int img2sphere (double x, double y, double ang_r, double latc, double lonc, |
1634 |
double pa, double *p_rho, double *p_lat, double *p_lon, double *p_sinlat, |
1635 |
double *p_coslat, double *p_sig, double *p_mu, double *p_chi) |
1636 |
{ |
1637 |
/* |
1638 |
* Taken from cartography.c, written by Rick Bogart |
1639 |
* Map projected coordinates (x, y) to (lon, lat) and (rho | sig, chi) |
1640 |
* |
1641 |
* Arguments: |
1642 |
* x } Plate locations, in same units as the image radius, relative |
1643 |
* y } to the image center |
1644 |
* ang_r Apparent semi-diameter of sun (angular radius of sun at |
1645 |
* the observer's tangent line) |
1646 |
* latc Latitude of disc center, uncorrected for light travel time |
1647 |
* lonc Longitude of disc center |
1648 |
* pa Position angle of solar north on image, measured eastward |
1649 |
* from north (sky coordinates) |
1650 |
* Return values: |
1651 |
* rho Angle point:sun_center:observer |
1652 |
* lon Heliographic longitude |
1653 |
* lat Heliographic latitude |
1654 |
* sinlat sine of heliographic latitude |
1655 |
* coslat cosine of heliographic latitude |
1656 |
* sig Angle point:observer:sun_center |
1657 |
* mu cosine of angle between the point:observer line and the |
1658 |
* local normal |
1659 |
* chi Position angle on image measured westward from solar |
1660 |
* north |
1661 |
* |
1662 |
* All angles are in radians. |
1663 |
* Return value is 1 if point is outside solar radius (in which case the |
1664 |
* heliographic coordinates and mu are meaningless), 0 otherwise. |
1665 |
* It is assumed that the image is direct; the x or y coordinates require a |
1666 |
* sign change if the image is inverted. |
1667 |
* |
1668 |
* modified to ignore setting return values for NULL pointers. |
1669 |
* |
1670 |
*/ |
1671 |
|
1672 |
|
1673 |
double w_rho, w_lat, w_lon, w_sinlat, w_coslat, w_sig, w_mu, w_chi; |
1674 |
double *rho= &w_rho, *lat= &w_lat, *lon= &w_lon, *sinlat= &w_sinlat, *coslat= &w_coslat, *sig= &w_sig, *mu= &w_mu, *chi= &w_chi; |
1675 |
static double ang_r0 = 0.0, sinang_r = 0.0, tanang_r = 0.0; |
1676 |
static double latc0 = 0.0, coslatc = 1.0, sinlatc = 0.0; |
1677 |
double cosr, sinr, sinlon, sinsig; |
1678 |
|
1679 |
if (p_rho) rho=p_rho; |
1680 |
if (p_lat) lat=p_lat; |
1681 |
if (p_lon) lon=p_lon; |
1682 |
if (p_sinlat) sinlat=p_sinlat; |
1683 |
if (p_coslat) coslat=p_coslat; |
1684 |
if (p_sig) sig=p_sig; |
1685 |
if (p_mu) mu=p_mu; |
1686 |
if (p_chi) chi=p_chi; |
1687 |
|
1688 |
if (ang_r != ang_r0) { |
1689 |
sinang_r = sin(ang_r); |
1690 |
tanang_r = tan(ang_r); |
1691 |
ang_r0 = ang_r; |
1692 |
} |
1693 |
|
1694 |
if (latc != latc0) { |
1695 |
sinlatc = sin(latc); |
1696 |
coslatc = cos(latc); |
1697 |
latc0 = latc; |
1698 |
} |
1699 |
|
1700 |
// position angle |
1701 |
*chi = atan2 (x, y) + pa; |
1702 |
while (*chi > 2 * M_PI) *chi -= 2 * M_PI; |
1703 |
while (*chi < 0.0) *chi += 2 * M_PI; |
1704 |
/* Camera curvature correction, no small angle approximations */ |
1705 |
*sig = atan (hypot (x, y) * tanang_r); |
1706 |
sinsig = sin (*sig); |
1707 |
*rho = asin (sinsig / sinang_r) - *sig; |
1708 |
if (*sig > ang_r) return (-1); |
1709 |
*mu = cos (*rho + *sig); |
1710 |
sinr = sin (*rho); |
1711 |
cosr = cos (*rho); |
1712 |
*sinlat = sinlatc * cosr + coslatc * sinr * cos (*chi); |
1713 |
*coslat = sqrt (1.0 - *sinlat * *sinlat); |
1714 |
*lat = asin (*sinlat); |
1715 |
|
1716 |
sinlon = sinr * sin (*chi) / *coslat; |
1717 |
*lon = asin (sinlon); |
1718 |
if (cosr < (*sinlat * sinlatc)) *lon = M_PI - *lon; |
1719 |
*lon += lonc; |
1720 |
while (*lon < 0.0) *lon += 2 * M_PI; |
1721 |
while (*lon >= 2 * M_PI) *lon -= 2 * M_PI; |
1722 |
return (0); |
1723 |
} |
1724 |
/* |
1725 |
* |
1726 |
* sphere2img() |
1727 |
* |
1728 |
* Written: Rick Bogart |
1729 |
* |
1730 |
*/ |
1731 |
|
1732 |
int sphere2img (double lat, double lon, double latc, double lonc, |
1733 |
double *x, double *y, double xcenter, double ycenter, |
1734 |
double rsun, double peff, double ecc, double chi, |
1735 |
int xinvrt, int yinvrt) { |
1736 |
/* |
1737 |
* Taken from cartography.c, written by Rick Bogart |
1738 |
* Perform a mapping from heliographic coordinates latitude and longitude |
1739 |
* (in radians) to plate location on an image of the sun. The plate |
1740 |
* location is in units of the image radius and is given relative to |
1741 |
* the image center. The function returns 1 if the requested point is |
1742 |
* on the far side (>90 deg from disc center), 0 otherwise. |
1743 |
* |
1744 |
* Arguments: |
1745 |
* lat Latitude (in radians) |
1746 |
* lon Longitude (in radians) |
1747 |
* latc Heliographic latitude of the disc center (in radians) |
1748 |
* lonc Heliographic longitude of the disc center (in radians) |
1749 |
* *x } Plate locations, in same units as the image radius, NOT relative |
1750 |
* *y } to the image center |
1751 |
* xcenter } Plate locations of the image center, in units of the |
1752 |
* ycenter } image radius, and measured from an arbitrary origin |
1753 |
* (presumably the plate center or a corner) |
1754 |
* rsun Apparent semi-diameter of the solar disc, in plate |
1755 |
* coordinates |
1756 |
* peff Position angle of the heliographic pole, measured |
1757 |
* eastward from north, relative to the north direction |
1758 |
* on the plate, in radians |
1759 |
* ecc Eccentricity of the fit ellipse presumed due to image |
1760 |
* distortion (no distortion in direction of major axis) |
1761 |
* chi Position angle of the major axis of the fit ellipse, |
1762 |
* measure eastward from north, relative to the north |
1763 |
* direction on the plate, in radians (ignored if ecc = 0) |
1764 |
* xinvrt} Flag parameters: if not equal to 0, the respective |
1765 |
* yinvrt} coordinates on the image x and y are inverted |
1766 |
* |
1767 |
* The heliographic coordinates are first mapped into the polar coordinates |
1768 |
* in an orthographic projection centered at the appropriate location and |
1769 |
* oriented with north in direction of increasing y and west in direction |
1770 |
* of increasing x. The radial coordinate is corrected for foreshortening |
1771 |
* due to the finite distance to the Sun. If the eccentricity of the fit |
1772 |
* ellipse is non-zero the coordinate of the mapped point is proportionately |
1773 |
* reduced in the direction parallel to the minor axis. |
1774 |
* |
1775 |
* Bugs: |
1776 |
* The finite distance correction uses a fixed apparent semi-diameter |
1777 |
* of 16'01'' appropriate to 1.0 AU. In principle the plate radius could |
1778 |
* be used, but this would require the plate scale to be supplied and the |
1779 |
* correction would probably be erroneous and in any case negligible. |
1780 |
* |
1781 |
* The ellipsoidal correction has not been tested very thoroughly. |
1782 |
* |
1783 |
* The return value is based on a test which does not take foreshortening |
1784 |
* into account. |
1785 |
*/ |
1786 |
static double sin_asd = 0.004660, cos_asd = 0.99998914; |
1787 |
/* appropriate to 1 AU */ |
1788 |
static double last_latc = 0.0, cos_latc = 1.0, sin_latc = 0.0; |
1789 |
double r, cos_cang, xr, yr; |
1790 |
double sin_lat, cos_lat, cos_lat_lon, cospa, sinpa; |
1791 |
double squash, cchi, schi, c2chi, s2chi, xp, yp; |
1792 |
int hemisphere; |
1793 |
|
1794 |
if (latc != last_latc) { |
1795 |
sin_latc = sin (latc); |
1796 |
cos_latc = cos (latc); |
1797 |
last_latc = latc; |
1798 |
} |
1799 |
sin_lat = sin (lat); |
1800 |
cos_lat = cos (lat); |
1801 |
cos_lat_lon = cos_lat * cos (lon - lonc); |
1802 |
|
1803 |
cos_cang = sin_lat * sin_latc + cos_latc * cos_lat_lon; |
1804 |
hemisphere = (cos_cang < 0.0) ? 1 : 0; |
1805 |
r = rsun * cos_asd / (1.0 - cos_cang * sin_asd); |
1806 |
xr = r * cos_lat * sin (lon - lonc); |
1807 |
yr = r * (sin_lat * cos_latc - sin_latc * cos_lat_lon); |
1808 |
/* Change sign for inverted images */ |
1809 |
if (xinvrt) xr *= -1.0; |
1810 |
if (yinvrt) yr *= -1.0; |
1811 |
/* Correction for ellipsoidal squashing of image */ |
1812 |
if (ecc > 0.0 && ecc < 1.0) { |
1813 |
squash = sqrt (1.0 - ecc * ecc); |
1814 |
cchi = cos (chi); |
1815 |
schi = sin (chi); |
1816 |
s2chi = schi * schi; |
1817 |
c2chi = 1.0 - s2chi; |
1818 |
xp = xr * (s2chi + squash * c2chi) - yr * (1.0 - squash) * schi * cchi; |
1819 |
yp = yr * (c2chi + squash * s2chi) - xr * (1.0 - squash) * schi * cchi; |
1820 |
xr = xp; |
1821 |
yr = yp; |
1822 |
} |
1823 |
|
1824 |
cospa = cos (peff); |
1825 |
sinpa = sin (peff); |
1826 |
*x = xr * cospa - yr * sinpa; |
1827 |
*y = xr * sinpa + yr * cospa; |
1828 |
|
1829 |
*y += ycenter; |
1830 |
*x += xcenter; |
1831 |
|
1832 |
return (hemisphere); |
1833 |
} |
1834 |
|
1835 |
// In cases known to not have compact slotted series and cadence is specified |
1836 |
// generate explicit recordset list of closest good record to desired grid |
1837 |
// First get vector of times and quality |
1838 |
// Then if vector is not OK, quit. |
1839 |
// then: make temp file to hold recordset list |
1840 |
// start with first time to define desired grid, |
1841 |
// make array of desired times. |
1842 |
// make empty array of recnums |
1843 |
// search vector for good images nearest desired times |
1844 |
// for each found time, write record query |
1845 |
|
1846 |
|
1847 |
#define DIE_get_recset(msg) {fprintf(stderr,"$$$$ %s: %s\n", module_name, msg); return NULL;} |
1848 |
char *get_input_recset(DRMS_Env_t *drms_env, char *inQuery) |
1849 |
{ |
1850 |
static char newInQuery[DRMS_MAXSERIESNAMELEN+2]; |
1851 |
int epoch_given = cmdparams_exists(&cmdparams, "epoch"); |
1852 |
TIME epoch, t_epoch; |
1853 |
DRMS_Array_t *data; |
1854 |
DRMS_Record_t *inTemplate; |
1855 |
TIME t_start, t_stop, t_now, t_want, t_diff, this_t_diff; |
1856 |
int status = 1; |
1857 |
int nrecs, irec; |
1858 |
int nslots, islot; |
1859 |
long long *recnums; |
1860 |
TIME *t_this, half; |
1861 |
TIME cadence; |
1862 |
double *drecnum, *dquality; |
1863 |
int quality; |
1864 |
long long recnum; |
1865 |
char keylist[DRMS_MAXQUERYLEN]; |
1866 |
char filename[DRMS_MAXSERIESNAMELEN]; |
1867 |
char *tmpdir; |
1868 |
FILE *tmpfile; |
1869 |
char newIn[DRMS_MAXQUERYLEN]; |
1870 |
char seriesname[DRMS_MAXQUERYLEN]; |
1871 |
char *lbracket; |
1872 |
char *at = index(inQuery, '@'); |
1873 |
int npkeys; |
1874 |
char *timekeyname; |
1875 |
double t_step; |
1876 |
|
1877 |
strcpy(seriesname, inQuery); |
1878 |
lbracket = index(seriesname,'['); |
1879 |
if (lbracket) *lbracket = '\0'; |
1880 |
inTemplate = drms_template_record(drms_env, seriesname, &status); |
1881 |
if (status || !inTemplate) DIE_get_recset("Input series can not be found"); |
1882 |
|
1883 |
// Now find the prime time keyword name |
1884 |
npkeys = inTemplate->seriesinfo->pidx_num; |
1885 |
timekeyname = NULL; |
1886 |
if (npkeys > 0) |
1887 |
{ |
1888 |
int i; |
1889 |
for (i=0; i<npkeys; i++) |
1890 |
{ |
1891 |
DRMS_Keyword_t *pkey, *skey; |
1892 |
pkey = inTemplate->seriesinfo->pidx_keywords[i]; |
1893 |
if (pkey->info->recscope > 1) |
1894 |
pkey = drms_keyword_slotfromindex(pkey); |
1895 |
if (pkey->info->type != DRMS_TYPE_TIME) |
1896 |
continue; |
1897 |
if(i > 0) DIE_get_recset("Input series must have TIME keyword first, for now..."); |
1898 |
timekeyname = pkey->info->name; |
1899 |
t_step = drms_keyword_getdouble(drms_keyword_stepfromslot(pkey), &status); |
1900 |
if (status) DIE_get_recset("problem getting t_step"); |
1901 |
t_epoch = drms_keyword_getdouble(drms_keyword_epochfromslot(pkey), &status); |
1902 |
if (status) DIE_get_recset("problem getting t_epoch"); |
1903 |
} |
1904 |
} |
1905 |
else |
1906 |
DIE_get_recset("Must have time prime key"); |
1907 |
epoch = epoch_given ? params_get_time(&cmdparams, "epoch") : t_epoch; |
1908 |
|
1909 |
if (at && *at && ((strncmp(inQuery,"aia.lev1[", 9)==0 || |
1910 |
strncmp(inQuery,"hmi.lev1[", 9)==0 || |
1911 |
strncmp(inQuery,"aia.lev1_nrt2[",14)==0 || |
1912 |
strncmp(inQuery,"hmi.lev1_nrt[", 13)==0 ) || |
1913 |
epoch_given)) |
1914 |
{ |
1915 |
char *ip=(char *)inQuery, *op=newIn, *p; |
1916 |
long n, mul; |
1917 |
while ( *ip && ip<at ) |
1918 |
*op++ = *ip++; |
1919 |
ip++; // skip the '@' |
1920 |
n = strtol(ip, &p, 10); // get digits only |
1921 |
if (*p == 's') mul = 1; |
1922 |
else if (*p == 'm') mul = 60; |
1923 |
else if (*p == 'h') mul = 3600; |
1924 |
else if (*p == 'd') mul = 86400; |
1925 |
else |
1926 |
DIE_get_recset("cant make sense of @xx cadence spec"); |
1927 |
cadence = n * mul; |
1928 |
ip = ++p; // skip cadence multiplier |
1929 |
while ( *ip ) |
1930 |
*op++ = *ip++; |
1931 |
*op = '\0'; |
1932 |
half = cadence/2.0; |
1933 |
sprintf(keylist, "%s,QUALITY,recnum", timekeyname); |
1934 |
data = drms_record_getvector(drms_env, newIn, keylist, DRMS_TYPE_DOUBLE, 0, &status); |
1935 |
if (!data || status) |
1936 |
{ |
1937 |
fprintf(stderr, "status=%d\n", status); |
1938 |
DIE_get_recset("getkey_vector failed\n"); |
1939 |
} |
1940 |
nrecs = data->axis[1]; |
1941 |
irec = 0; |
1942 |
t_this = (TIME *)data->data; |
1943 |
dquality = (double *)data->data + 1*nrecs; |
1944 |
drecnum = (double *)data->data + 2*nrecs; |
1945 |
if (epoch_given) |
1946 |
{ |
1947 |
int s0 = (t_this[0] - epoch)/cadence; |
1948 |
TIME t0 = s0*cadence + epoch; |
1949 |
t_start = (t0 < t_this[0] ? t0 + cadence : t0); |
1950 |
} |
1951 |
else |
1952 |
t_start = t_this[0]; |
1953 |
t_stop = t_this[nrecs-1]; |
1954 |
nslots = (t_stop - t_start + cadence/2)/cadence; |
1955 |
recnums = (long long *)malloc(nslots*sizeof(long long)); |
1956 |
for (islot=0; islot<nslots; islot++) |
1957 |
recnums[islot] = 0; |
1958 |
islot = 0; |
1959 |
t_want = t_start; |
1960 |
t_diff = 1.0e9; |
1961 |
for (irec = 0; irec<nrecs; irec++) |
1962 |
{ |
1963 |
t_now = t_this[irec]; |
1964 |
quality = (int)dquality[irec] & 0xFFFFFFFF; |
1965 |
recnum = (long long)drecnum[irec]; |
1966 |
this_t_diff = fabs(t_now - t_want); |
1967 |
if (quality < 0) |
1968 |
continue; |
1969 |
if (t_now <= (t_want-half)) |
1970 |
continue; |
1971 |
while (t_now > (t_want+half)) |
1972 |
{ |
1973 |
islot++; |
1974 |
if (islot >= nslots) |
1975 |
break; |
1976 |
t_want = t_start + cadence * islot; |
1977 |
this_t_diff = fabs(t_now - t_want); |
1978 |
t_diff = 1.0e8; |
1979 |
} |
1980 |
if (islot < nslots && this_t_diff <= t_diff) |
1981 |
recnums[islot] = recnum; |
1982 |
t_diff = fabs(t_now - t_want); |
1983 |
} |
1984 |
if (islot+1 < nslots) |
1985 |
nslots = islot+1; // take what we got. |
1986 |
tmpdir = getenv("TMPDIR"); |
1987 |
if (!tmpdir) tmpdir = "/tmp"; |
1988 |
sprintf(filename, "%s/%sXXXXXX", tmpdir, module_name); |
1989 |
mkstemp(filename); |
1990 |
tmpfile = fopen(filename,"w"); |
1991 |
for (islot=0; islot<nslots; islot++) |
1992 |
if (recnums[islot]) |
1993 |
fprintf(tmpfile, "%s[:#%lld]\n", seriesname, recnums[islot]); |
1994 |
fclose(tmpfile); |
1995 |
free(recnums); |
1996 |
drms_free_array(data); |
1997 |
sprintf(newInQuery,"@%s", filename); |
1998 |
return(newInQuery); |
1999 |
} |
2000 |
else |
2001 |
return(inQuery); |
2002 |
} |
2003 |
|
2004 |
// FDS file is in format of SDO FDS "transit" files. |
2005 |
// returns xp, yp, and radius of target all in arcsec |
2006 |
int get_tracking_xy(char *FDSfile, TIME want, double *xp, double *yp, double *radius) |
2007 |
{ |
2008 |
int iline; |
2009 |
char buf[200]; |
2010 |
TIME now0; |
2011 |
FILE *data = fopen(FDSfile,"r"); |
2012 |
double lambda, phi, x, y, dist, obj_radius; |
2013 |
double frac, x0, y0, obj_radius0; |
2014 |
char object[100], now_txt[100]; |
2015 |
if (!data) |
2016 |
return(1); |
2017 |
|
2018 |
// skip first 13 lines, for lunar transit data, was 14 lines |
2019 |
for (iline=0; iline<13; iline++) |
2020 |
fgets(buf, 200, data); |
2021 |
// fprintf(stderr,"line before using: %s\n",buf); |
2022 |
// read info until end, stop at first time after want |
2023 |
while (fscanf(data, "%s %s %lf %lf %lf %lf %lf %lf", object, now_txt, &lambda, &phi, &x, &y, &dist, &obj_radius) == 8) |
2024 |
{ |
2025 |
char tmp_txt[100]; |
2026 |
int yyyy, doy, hh, mm, ss; |
2027 |
int m,d; |
2028 |
int dim[] = {31,28,31,30,31,30,31,31,30,31,30,31}; |
2029 |
double distance; |
2030 |
TIME now; |
2031 |
// fix coordinate system to match HMI view |
2032 |
// not for ISON |
2033 |
x = -x; |
2034 |
y = -y; |
2035 |
obj_radius *= 3600; |
2036 |
// extract time |
2037 |
sscanf(tmp_txt,"%4d%3d.%2d%2d%2d", &yyyy, &doy, &hh, &mm, &ss); |
2038 |
if (yyyy % 4 == 0) dim[1] = 29; else dim[1] = 28; |
2039 |
for (m=1; m<=12; m++) |
2040 |
{ |
2041 |
if (doy > dim[m-1]) |
2042 |
doy -= dim[m-1]; |
2043 |
else |
2044 |
break; |
2045 |
} |
2046 |
d = doy; |
2047 |
|
2048 |
sprintf(tmp_txt, "%4d.%02d.%02d_%02d:%02d:%02d_UTC", yyyy, m, d, hh, mm, ss); |
2049 |
now = sscan_time(tmp_txt); |
2050 |
// report closest x,y for time want |
2051 |
if (now < want) |
2052 |
{ |
2053 |
now0 = now; |
2054 |
x0 = x; |
2055 |
y0 = y; |
2056 |
obj_radius0 = obj_radius; |
2057 |
} |
2058 |
else |
2059 |
{ |
2060 |
if (fabs(now-want) >= fabs(now0-want)) |
2061 |
{ |
2062 |
obj_radius = obj_radius0; |
2063 |
if (now == want) |
2064 |
{ |
2065 |
x = x0; |
2066 |
y = y0; |
2067 |
} |
2068 |
else |
2069 |
{ |
2070 |
frac = (want-now0)/(now-now0); |
2071 |
x = x0 + (x-x0)*frac; |
2072 |
y = y0 + (y-y0)*frac; |
2073 |
} |
2074 |
} |
2075 |
break; |
2076 |
} |
2077 |
} |
2078 |
fclose(data); |
2079 |
fprintf(stderr,"Found %s, x=%f, y=%f, radius=%f (all arcsecs)\n",now_txt,x,y,obj_radius); |
2080 |
*xp = x; |
2081 |
*yp = y; |
2082 |
*radius = obj_radius; |
2083 |
return(0); |
2084 |
} |