1 |
/* |
2 |
* hmib2ptr.c |
3 |
* |
4 |
* This module takes hmi.B_720s and convert into three field components (Bp, Bt, Br) |
5 |
* and optionally Stony Hurst longitude, latitude |
6 |
* and three error images (Bp_err, Bt_err, Br_err) |
7 |
* Potentially to be used in export system |
8 |
* |
9 |
* Author: |
10 |
* Xudong Sun |
11 |
* |
12 |
* Version: |
13 |
* v0.0 Aug 28 2015 |
14 |
* |
15 |
* Notes: |
16 |
* v0.0 |
17 |
* Need to check externally that the input is hmi.B_720s |
18 |
* |
19 |
* Example Calls: |
20 |
* hmib2ptr "in=hmi.B_720s[2011.02.15_00:00]" "out=hmi_test.Bptr_720s" "requestid=test" -e -l |
21 |
* |
22 |
*/ |
23 |
|
24 |
#include <stdio.h> |
25 |
#include <stdlib.h> |
26 |
#include <time.h> |
27 |
#include <sys/time.h> |
28 |
#include <math.h> |
29 |
#include <string.h> |
30 |
#include "jsoc_main.h" |
31 |
#include "astro.h" |
32 |
#include "fstats.h" |
33 |
//#include "cartography.c" |
34 |
//#include "img2helioVector.c" |
35 |
//#include "vecErrProp.c" // new version of errorprop |
36 |
|
37 |
#define PI (M_PI) |
38 |
#define TWOPI (2*M_PI) |
39 |
#define RADSINDEG (PI/180.) |
40 |
#define RAD2ARCSEC (648000./M_PI) |
41 |
#define SECINDAY (86400.) |
42 |
#define FOURK (4096) |
43 |
#define FOURK2 (16777216) |
44 |
|
45 |
#define ARRLENGTH(ARR) (sizeof(ARR) / sizeof(ARR[0])) |
46 |
|
47 |
// Some other things |
48 |
#ifndef MIN |
49 |
#define MIN(a,b) (((a)<(b)) ? (a) : (b)) |
50 |
#endif |
51 |
#ifndef MAX |
52 |
#define MAX(a,b) (((a)>(b)) ? (a) : (b)) |
53 |
#endif |
54 |
|
55 |
#define DIE(msg) {fflush(stdout); fprintf(stderr,"%s, status=%d\n", msg, status); return(status);} |
56 |
#define SHOW(msg) {printf("%s", msg); fflush(stdout);} |
57 |
|
58 |
#define FREE_ARR(arr) {if (arr) {free(arr);}} |
59 |
#define DRMS_FREE_ARR(arr) {if (arr && (arr->data)) {drms_free_array(arr);}} |
60 |
|
61 |
#define kNotSpecified "Not Specified" |
62 |
|
63 |
// Macros for WCS transformations. assume crpix1, crpix2 = CRPIX1, CRPIX2, sina,cosa = sin and cos of CROTA2 resp. |
64 |
// and crvalx and crvaly are CRVAL1 and CRVAL2, cdelt = CDELT1 == CDELT2, then |
65 |
// PIX_X and PIX_Y are CCD pixel addresses, WX and WY are arc-sec W and N on the Sun from disk center. |
66 |
#define PIX_X(wx,wy) ((((wx-crvalx)*cosa + (wy-crvaly)*sina)/cdelt)+crpix1) |
67 |
#define PIX_Y(wx,wy) ((((wy-crvaly)*cosa - (wx-crvalx)*sina)/cdelt)+crpix2) |
68 |
#define WX(pix_x,pix_y) (((pix_x-crpix1)*cosa - (pix_y-crpix2)*sina)*cdelt+crvalx) |
69 |
#define WY(pix_x,pix_y) (((pix_y-crpix2)*cosa + (pix_x-crpix1)*sina)*cdelt+crvaly) |
70 |
|
71 |
// Ephemeris information |
72 |
struct ephemeris { |
73 |
double disk_lonc, disk_latc; |
74 |
double disk_xc, disk_yc; |
75 |
double rSun, asd, pa; |
76 |
}; |
77 |
|
78 |
//================================================================================================= |
79 |
|
80 |
/* Get ephemeris information */ |
81 |
int getEphemeris(DRMS_Record_t *inRec, struct ephemeris *ephem); |
82 |
|
83 |
/* Convert field vector, calls img2helioVector */ |
84 |
void get_bptr(struct ephemeris *ephem, int *dims, float *fld, float *inc, float *azi, |
85 |
float *bp, float *bt, float *br, float *lon, float *lat); |
86 |
|
87 |
/* Compute error, calls errprop_rad */ |
88 |
void get_bptr_err(struct ephemeris *ephem, int *dims, float *fld, float *inc, float *azi, |
89 |
float *lon, float *lat, |
90 |
float *err_fld, float *err_inc, float *err_azi, float *cc_fi, float *cc_fa, float *cc_ia, |
91 |
float *err_bp, float *err_bt, float *err_br); |
92 |
|
93 |
/* Vector transformation */ |
94 |
int img2helioVector (double bxImg, double byImg, double bzImg, double *bxHelio, |
95 |
double *byHelio, double *bzHelio, double lon, double lat, |
96 |
double lonc, double latc, double pAng); |
97 |
|
98 |
/* Error propagation */ |
99 |
void vecErrProp(float fld, float inc, float azi, |
100 |
float var_fld, float var_inc, float var_azi, float cov_fi, float cov_fa, float cov_ia, |
101 |
double lon, double lat, double lonc, double latc, double pa, |
102 |
double *var_bp, double *var_bt, double *var_br); |
103 |
|
104 |
/* From Cartography.c */ |
105 |
int img2sphere (double x, double y, double ang_r, double latc, double lonc, |
106 |
double pa, double *rho, double *lat, double *lon, double *sinlat, |
107 |
double *coslat, double *sig, double *mu, double *chi); |
108 |
|
109 |
//================================================================================================= |
110 |
|
111 |
char *module_name = "sharp"; |
112 |
|
113 |
ModuleArgs_t module_args[] = |
114 |
{ |
115 |
{ARG_STRING, "in", kNotSpecified, "Input B series."}, |
116 |
{ARG_STRING, "out", kNotSpecified, "Input Bptr series."}, |
117 |
{ARG_STRING, "requestid", kNotSpecified, "Request ID."}, |
118 |
{ARG_INT, "ambweak", "2", "Disambiguation method. 0: potential acute, 1: random, 2: radial acute"}, |
119 |
{ARG_FLAG, "l", "0", "Flag for lat/lon output."}, |
120 |
{ARG_FLAG, "e", "0", "Flag for error output."}, |
121 |
{ARG_END} |
122 |
}; |
123 |
|
124 |
int DoIt(void) |
125 |
{ |
126 |
|
127 |
int status = DRMS_SUCCESS; |
128 |
|
129 |
/* Get parameters */ |
130 |
|
131 |
char *inQuery = (char *) params_get_str(&cmdparams, "in"); |
132 |
char *outQuery = (char *) params_get_str(&cmdparams, "out"); |
133 |
char *requestid = (char *) params_get_str(&cmdparams, "requestid"); |
134 |
int ambweak = params_get_int(&cmdparams, "ambweak"); |
135 |
int do_lonlat = params_isflagset(&cmdparams, "l"); |
136 |
int do_error = params_isflagset(&cmdparams, "e"); |
137 |
|
138 |
if (ambweak < 0 || ambweak > 2) ambweak = 2; |
139 |
|
140 |
/* Input and output data */ |
141 |
|
142 |
DRMS_RecordSet_t *inRS = drms_open_records(drms_env, inQuery, &status); |
143 |
|
144 |
if (!inRS) |
145 |
{ |
146 |
DIE("No records specified by record-set specification.\n"); |
147 |
} |
148 |
|
149 |
int nrecs = inRS->n; |
150 |
if (status || nrecs == 0) DIE("Input records error."); |
151 |
|
152 |
DRMS_RecordSet_t *outRS = drms_create_records(drms_env, nrecs, outQuery, DRMS_PERMANENT, &status); |
153 |
if (status) { |
154 |
drms_close_records(inRS, DRMS_FREE_RECORD); |
155 |
DIE("Output records not created."); |
156 |
} |
157 |
|
158 |
/* Work */ |
159 |
|
160 |
printf("Processing %d records:\n", nrecs); |
161 |
|
162 |
for (int irec = 0; irec < nrecs; irec++) { |
163 |
|
164 |
// Input record |
165 |
DRMS_Record_t *inRec = inRS->records[irec]; |
166 |
|
167 |
if (!inRec) |
168 |
{ |
169 |
fprintf(stderr, "No record with index %d in record set.\n", irec); |
170 |
continue; |
171 |
} |
172 |
|
173 |
TIME t_rec = drms_getkey_time(inRec, "T_REC", &status); |
174 |
|
175 |
if (status != DRMS_SUCCESS) |
176 |
{ |
177 |
fprintf(stderr, "Unable to obtain keyword value for T_REC.\n"); |
178 |
continue; |
179 |
} |
180 |
|
181 |
char t_rec_str[100]; |
182 |
sprint_time(t_rec_str, t_rec, "TAI", 0); |
183 |
printf("Processing record #%d, T_REC=%s\n", irec, t_rec_str); |
184 |
|
185 |
// Ephemeris |
186 |
|
187 |
struct ephemeris ephem; |
188 |
status = getEphemeris(inRec, &ephem); // can never return anything but 'success'. |
189 |
|
190 |
// Input images |
191 |
|
192 |
DRMS_Segment_t *inSeg_fld = drms_segment_lookup(inRec, "field"); |
193 |
if (!inSeg_fld) |
194 |
{ |
195 |
fprintf(stderr, "Missing required segment 'field'.\n"); |
196 |
continue; |
197 |
} |
198 |
|
199 |
DRMS_Segment_t *inSeg_inc = drms_segment_lookup(inRec, "inclination"); |
200 |
if (!inSeg_inc) |
201 |
{ |
202 |
fprintf(stderr, "Missing required segment 'inclination'.\n"); |
203 |
continue; |
204 |
} |
205 |
|
206 |
DRMS_Segment_t *inSeg_azi = drms_segment_lookup(inRec, "azimuth"); |
207 |
if (!inSeg_azi) |
208 |
{ |
209 |
fprintf(stderr, "Missing required segment 'azimuth'.\n"); |
210 |
continue; |
211 |
} |
212 |
|
213 |
DRMS_Segment_t *inSeg_amb = drms_segment_lookup(inRec, "disambig"); |
214 |
if (!inSeg_amb) |
215 |
{ |
216 |
fprintf(stderr, "Missing required segment 'disambig'.\n"); |
217 |
continue; |
218 |
} |
219 |
|
220 |
int status_fld = 0, status_inc = 0, status_azi = 0, status_amb = 0; |
221 |
DRMS_Array_t *inArray_fld = NULL, *inArray_inc = NULL, *inArray_azi = NULL, *inArray_amb = NULL; |
222 |
inArray_fld = drms_segment_read(inSeg_fld, DRMS_TYPE_FLOAT, &status_fld); |
223 |
inArray_inc = drms_segment_read(inSeg_inc, DRMS_TYPE_FLOAT, &status_inc); |
224 |
inArray_azi = drms_segment_read(inSeg_azi, DRMS_TYPE_FLOAT, &status_azi); |
225 |
inArray_amb = drms_segment_read(inSeg_amb, DRMS_TYPE_CHAR, &status_amb); |
226 |
if (status_fld || status_inc || status_azi || status_amb) { |
227 |
printf("Reading input arrays error, record skipped\n"); |
228 |
DRMS_FREE_ARR(inArray_fld); DRMS_FREE_ARR(inArray_inc); |
229 |
DRMS_FREE_ARR(inArray_azi); DRMS_FREE_ARR(inArray_amb); |
230 |
continue; |
231 |
} |
232 |
|
233 |
// Input error images if needed |
234 |
|
235 |
DRMS_Array_t *inArray_err_fld = NULL, *inArray_err_inc = NULL, *inArray_err_azi = NULL; |
236 |
DRMS_Array_t *inArray_cc_fi = NULL, *inArray_cc_fa = NULL, *inArray_cc_ia = NULL; |
237 |
if (do_error) { |
238 |
DRMS_Segment_t *inSeg_err_fld = drms_segment_lookup(inRec, "field_err"); |
239 |
DRMS_Segment_t *inSeg_err_inc = drms_segment_lookup(inRec, "inclination_err"); |
240 |
DRMS_Segment_t *inSeg_err_azi = drms_segment_lookup(inRec, "azimuth_err"); |
241 |
DRMS_Segment_t *inSeg_cc_fi = drms_segment_lookup(inRec, "field_inclination_err"); |
242 |
DRMS_Segment_t *inSeg_cc_fa = drms_segment_lookup(inRec, "field_az_err"); |
243 |
DRMS_Segment_t *inSeg_cc_ia = drms_segment_lookup(inRec, "inclin_azimuth_err"); |
244 |
|
245 |
if (!inSeg_err_fld || !inSeg_err_inc || !inSeg_err_azi || !inSeg_cc_fi || !inSeg_cc_fa || !inSeg_cc_ia) |
246 |
{ |
247 |
fprintf(stderr, "Missing one or more required error segments.\n"); |
248 |
continue; |
249 |
} |
250 |
|
251 |
int status_err_fld = 0, status_err_inc = 0, status_err_azi = 0; |
252 |
int status_cc_fi = 0, status_cc_fa = 0, status_cc_ia = 0; |
253 |
|
254 |
inArray_err_fld = drms_segment_read(inSeg_err_fld, DRMS_TYPE_FLOAT, &status_err_fld); |
255 |
inArray_err_inc = drms_segment_read(inSeg_err_inc, DRMS_TYPE_FLOAT, &status_err_inc); |
256 |
inArray_err_azi = drms_segment_read(inSeg_err_azi, DRMS_TYPE_FLOAT, &status_err_azi); |
257 |
inArray_cc_fi = drms_segment_read(inSeg_cc_fi, DRMS_TYPE_FLOAT, &status_cc_fi); |
258 |
inArray_cc_fa = drms_segment_read(inSeg_cc_fa, DRMS_TYPE_FLOAT, &status_cc_fa); |
259 |
inArray_cc_ia = drms_segment_read(inSeg_cc_ia, DRMS_TYPE_FLOAT, &status_cc_ia); |
260 |
if (status_err_fld || status_err_inc || status_err_azi || |
261 |
status_cc_fi || status_cc_fa || status_cc_ia) { |
262 |
printf("Reading input uncertainty arrays error, record skipped\n"); |
263 |
DRMS_FREE_ARR(inArray_err_fld); DRMS_FREE_ARR(inArray_err_inc); DRMS_FREE_ARR(inArray_err_azi); |
264 |
DRMS_FREE_ARR(inArray_cc_fi); DRMS_FREE_ARR(inArray_cc_fa); DRMS_FREE_ARR(inArray_cc_ia); |
265 |
DRMS_FREE_ARR(inArray_fld); DRMS_FREE_ARR(inArray_inc); |
266 |
DRMS_FREE_ARR(inArray_azi); DRMS_FREE_ARR(inArray_amb); |
267 |
continue; |
268 |
} |
269 |
} |
270 |
|
271 |
// Some pre-processing |
272 |
|
273 |
int ncols = inArray_fld->axis[0], nrows = inArray_fld->axis[1]; // FOURK |
274 |
int npix = ncols * nrows; |
275 |
int dims[2] = {ncols, nrows}; |
276 |
|
277 |
float *fld = (float *) (inArray_fld->data); |
278 |
float *inc = (float *) (inArray_inc->data); |
279 |
float *azi = (float *) (inArray_azi->data); |
280 |
char *amb = (char *) (inArray_amb->data); |
281 |
for (int ipix = 0; ipix < npix; ipix++) { |
282 |
inc[ipix] *= RADSINDEG; |
283 |
if (amb[ipix] >> ambweak) azi[ipix] += 180.; // bitwise operator |
284 |
azi[ipix] *= RADSINDEG; |
285 |
} |
286 |
|
287 |
float *err_fld = NULL, *err_inc = NULL, *err_azi = NULL; |
288 |
float *cc_fi = NULL, *cc_fa = NULL, *cc_ia = NULL; |
289 |
if (do_error) { |
290 |
err_fld = (float *) (inArray_err_fld->data); |
291 |
err_inc = (float *) (inArray_err_inc->data); |
292 |
err_azi = (float *) (inArray_err_azi->data); |
293 |
cc_fi = (float *) (inArray_cc_fi->data); |
294 |
cc_fa = (float *) (inArray_cc_fa->data); |
295 |
cc_ia = (float *) (inArray_cc_ia->data); |
296 |
for (int ipix = 0; ipix < npix; ipix++) { |
297 |
err_inc[ipix] *= RADSINDEG; |
298 |
err_azi[ipix] *= RADSINDEG; // conver to radian |
299 |
} |
300 |
} |
301 |
|
302 |
// Bptr, also calculate lon/lat |
303 |
|
304 |
float *bp = (float *) (malloc(npix * sizeof(float))); |
305 |
float *bt = (float *) (malloc(npix * sizeof(float))); |
306 |
float *br = (float *) (malloc(npix * sizeof(float))); |
307 |
float *lon = (float *) (malloc(npix * sizeof(float))); // lon/lat in rad |
308 |
float *lat = (float *) (malloc(npix * sizeof(float))); |
309 |
get_bptr(&ephem, dims, fld, inc, azi, bp, bt, br, lon, lat); // working function |
310 |
|
311 |
// Error if requested |
312 |
|
313 |
float *err_bp = NULL, *err_bt = NULL, *err_br = NULL; |
314 |
if (do_error) { |
315 |
err_bp = (float *) (malloc(npix * sizeof(float))); |
316 |
err_bt = (float *) (malloc(npix * sizeof(float))); |
317 |
err_br = (float *) (malloc(npix * sizeof(float))); |
318 |
get_bptr_err(&ephem, dims, fld, inc, azi, lon, lat, |
319 |
err_fld, err_inc, err_azi, cc_fi, cc_fa, cc_ia, |
320 |
err_bp, err_bt, err_br); // working function, all input in rad |
321 |
} |
322 |
|
323 |
// Convert lon/lat to deg if needed |
324 |
|
325 |
if (do_lonlat) { |
326 |
for (int ipix = 0; ipix < npix; ipix++) { |
327 |
lon[ipix] /= RADSINDEG; |
328 |
lat[ipix] /= RADSINDEG; |
329 |
} |
330 |
} |
331 |
|
332 |
// Some clean up |
333 |
|
334 |
DRMS_FREE_ARR(inArray_fld); DRMS_FREE_ARR(inArray_inc); |
335 |
DRMS_FREE_ARR(inArray_azi); DRMS_FREE_ARR(inArray_amb); |
336 |
if (do_error) { |
337 |
DRMS_FREE_ARR(inArray_err_fld); DRMS_FREE_ARR(inArray_err_inc); DRMS_FREE_ARR(inArray_err_azi); |
338 |
DRMS_FREE_ARR(inArray_cc_fi); DRMS_FREE_ARR(inArray_cc_fa); DRMS_FREE_ARR(inArray_cc_ia); |
339 |
} |
340 |
if (!do_lonlat) { |
341 |
FREE_ARR(lon); FREE_ARR(lat); |
342 |
} |
343 |
|
344 |
// Output |
345 |
|
346 |
DRMS_Record_t *outRec = outRS->records[irec]; |
347 |
if (!outRec) |
348 |
{ |
349 |
fprintf(stderr, "No output record with index %d in record set.\n", irec); |
350 |
continue; |
351 |
} |
352 |
|
353 |
DRMS_Segment_t *outSeg_bp = drms_segment_lookup(outRec, "Bp"); |
354 |
if (!outSeg_bp) |
355 |
{ |
356 |
fprintf(stderr, "Missing required output segment 'Bp'.\n"); |
357 |
continue; |
358 |
} |
359 |
|
360 |
DRMS_Segment_t *outSeg_bt = drms_segment_lookup(outRec, "Bt"); |
361 |
if (!outSeg_bt) |
362 |
{ |
363 |
fprintf(stderr, "Missing required output segment 'Bt'.\n"); |
364 |
continue; |
365 |
} |
366 |
|
367 |
DRMS_Segment_t *outSeg_br = drms_segment_lookup(outRec, "Br"); |
368 |
if (!outSeg_br) |
369 |
{ |
370 |
fprintf(stderr, "Missing required output segment 'Br'.\n"); |
371 |
continue; |
372 |
} |
373 |
|
374 |
int status_bp = 0, status_bt = 0, status_br = 0; |
375 |
DRMS_Array_t *outArray_bp = NULL, *outArray_bt = NULL, *outArray_br = NULL; |
376 |
outArray_bp = drms_array_create(DRMS_TYPE_FLOAT, 2, dims, bp, &status_bp); |
377 |
outArray_bt = drms_array_create(DRMS_TYPE_FLOAT, 2, dims, bt, &status_bt); |
378 |
outArray_br = drms_array_create(DRMS_TYPE_FLOAT, 2, dims, br, &status_br); |
379 |
if (status_bp || status_bt || status_br) { |
380 |
printf("Writing output arrays error, record skipped\n"); |
381 |
DRMS_FREE_ARR(outArray_bp); DRMS_FREE_ARR(outArray_bt); DRMS_FREE_ARR(outArray_br); |
382 |
continue; |
383 |
} |
384 |
outArray_bp->israw = outArray_bt->israw = outArray_br->israw = 0; // always compressed |
385 |
outArray_bp->bzero = outSeg_bp->bzero; outArray_bp->bscale = outSeg_bp->bscale; |
386 |
outArray_bt->bzero = outSeg_bt->bzero; outArray_bt->bscale = outSeg_bt->bscale; |
387 |
outArray_br->bzero = outSeg_br->bzero; outArray_br->bscale = outSeg_br->bscale; |
388 |
|
389 |
status_bp = drms_segment_write(outSeg_bp, outArray_bp, 0); |
390 |
status_bt = drms_segment_write(outSeg_bt, outArray_bt, 0); |
391 |
status_br = drms_segment_write(outSeg_br, outArray_br, 0); |
392 |
DRMS_FREE_ARR(outArray_bp); DRMS_FREE_ARR(outArray_bt); DRMS_FREE_ARR(outArray_br); |
393 |
|
394 |
if (status_bp || status_bt || status_br) { |
395 |
printf("Writing output arrays error, record skipped\n"); |
396 |
continue; |
397 |
} |
398 |
|
399 |
// Optional output |
400 |
|
401 |
if (do_error) { |
402 |
DRMS_Segment_t *outSeg_err_bp = drms_segment_lookup(outRec, "Bp_err"); |
403 |
if (!outSeg_err_bp) |
404 |
{ |
405 |
fprintf(stderr, "Missing required output segment 'Bp_err'.\n"); |
406 |
continue; |
407 |
} |
408 |
|
409 |
DRMS_Segment_t *outSeg_err_bt = drms_segment_lookup(outRec, "Bt_err"); |
410 |
if (!outSeg_err_bt) |
411 |
{ |
412 |
fprintf(stderr, "Missing required output segment 'Bt_err'.\n"); |
413 |
continue; |
414 |
} |
415 |
|
416 |
DRMS_Segment_t *outSeg_err_br = drms_segment_lookup(outRec, "Br_err"); |
417 |
if (!outSeg_err_br) |
418 |
{ |
419 |
fprintf(stderr, "Missing required output segment 'Br_err'.\n"); |
420 |
continue; |
421 |
} |
422 |
|
423 |
int status_err_bp = 0, status_err_bt = 0, status_err_br = 0; |
424 |
DRMS_Array_t *outArray_err_bp = NULL, *outArray_err_bt = NULL, *outArray_err_br = NULL; |
425 |
outArray_err_bp = drms_array_create(DRMS_TYPE_FLOAT, 2, dims, err_bp, &status_err_bp); |
426 |
outArray_err_bt = drms_array_create(DRMS_TYPE_FLOAT, 2, dims, err_bt, &status_err_bt); |
427 |
outArray_err_br = drms_array_create(DRMS_TYPE_FLOAT, 2, dims, err_br, &status_err_br); |
428 |
if (status_err_bp || status_err_bt || status_err_br) { |
429 |
printf("Writing error output arrays error, record skipped\n"); |
430 |
DRMS_FREE_ARR(outArray_err_bp); DRMS_FREE_ARR(outArray_err_bt); DRMS_FREE_ARR(outArray_err_br); |
431 |
continue; |
432 |
} |
433 |
outArray_err_bp->israw = outArray_err_bt->israw = outArray_err_br->israw = 0; // always compressed, fixed Dec 23 2015 |
434 |
outArray_err_bp->bzero = outSeg_err_bp->bzero; outArray_err_bp->bscale = outSeg_err_bp->bscale; |
435 |
outArray_err_bt->bzero = outSeg_err_bt->bzero; outArray_err_bt->bscale = outSeg_err_bt->bscale; |
436 |
outArray_err_br->bzero = outSeg_err_br->bzero; outArray_err_br->bscale = outSeg_err_br->bscale; |
437 |
|
438 |
status_err_bp = drms_segment_write(outSeg_err_bp, outArray_err_bp, 0); |
439 |
status_err_bt = drms_segment_write(outSeg_err_bt, outArray_err_bt, 0); |
440 |
status_err_br = drms_segment_write(outSeg_err_br, outArray_err_br, 0); |
441 |
DRMS_FREE_ARR(outArray_err_bp); DRMS_FREE_ARR(outArray_err_bt); DRMS_FREE_ARR(outArray_err_br); |
442 |
|
443 |
if (status_err_bp || status_err_bt || status_err_br) { |
444 |
printf("Writing error output arrays error, record skipped\n"); |
445 |
continue; |
446 |
} |
447 |
} |
448 |
|
449 |
if (do_lonlat) { |
450 |
DRMS_Segment_t *outSeg_lon = drms_segment_lookup(outRec, "lon"); |
451 |
if (!outSeg_lon) |
452 |
{ |
453 |
fprintf(stderr, "Missing required output segment 'lon'.\n"); |
454 |
continue; |
455 |
} |
456 |
|
457 |
DRMS_Segment_t *outSeg_lat = drms_segment_lookup(outRec, "lat"); |
458 |
if (!outSeg_lon) |
459 |
{ |
460 |
fprintf(stderr, "Missing required output segment 'lat'.\n"); |
461 |
continue; |
462 |
} |
463 |
|
464 |
int status_lon = 0, status_lat = 0; |
465 |
DRMS_Array_t *outArray_lon = NULL, *outArray_lat = NULL; |
466 |
outArray_lon = drms_array_create(DRMS_TYPE_FLOAT, 2, dims, lon, &status_lon); |
467 |
outArray_lat = drms_array_create(DRMS_TYPE_FLOAT, 2, dims, lat, &status_lat); |
468 |
if (status_lon || status_lat) { |
469 |
printf("Writing lon/lat arrays error, record skipped\n"); |
470 |
DRMS_FREE_ARR(outArray_lon); DRMS_FREE_ARR(outArray_lat); |
471 |
continue; |
472 |
} |
473 |
outArray_lon->israw = outArray_lat->israw = 0; // always compressed |
474 |
outArray_lon->bzero = outSeg_lon->bzero; outArray_lon->bscale = outSeg_lon->bscale; |
475 |
outArray_lat->bzero = outSeg_lat->bzero; outArray_lat->bscale = outSeg_lat->bscale; |
476 |
|
477 |
status_lon = drms_segment_write(outSeg_lon, outArray_lon, 0); |
478 |
status_lat = drms_segment_write(outSeg_lat, outArray_lat, 0); |
479 |
DRMS_FREE_ARR(outArray_lon); DRMS_FREE_ARR(outArray_lat); |
480 |
|
481 |
if (status_lon || status_lat) { |
482 |
printf("Writing lon/lat arrays error, record skipped\n"); |
483 |
continue; |
484 |
} |
485 |
} |
486 |
|
487 |
// Keywords |
488 |
|
489 |
drms_copykeys(outRec, inRec, 0, 0); // copy all keys |
490 |
|
491 |
TIME val, trec, tnow, UNIX_epoch = -220924792.000; /* 1970.01.01_00:00:00_UTC */ |
492 |
tnow = (double)time(NULL); |
493 |
tnow += UNIX_epoch; |
494 |
drms_setkey_time(outRec, "DATE", tnow); |
495 |
drms_setkey_int(outRec, "AMBWEAK", ambweak); |
496 |
drms_setkey_string(outRec, "RequestID", requestid); |
497 |
drms_setkey_string(outRec, "BUNIT_000", "Mx/cm^2"); |
498 |
drms_setkey_string(outRec, "BUNIT_001", "Mx/cm^2"); |
499 |
drms_setkey_string(outRec, "BUNIT_002", "Mx/cm^2"); |
500 |
drms_setkey_string(outRec, "BUNIT_003", "Mx/cm^2"); |
501 |
drms_setkey_string(outRec, "BUNIT_004", "Mx/cm^2"); |
502 |
drms_setkey_string(outRec, "BUNIT_005", "Mx/cm^2"); |
503 |
drms_setkey_string(outRec, "BUNIT_006", "degree"); |
504 |
drms_setkey_string(outRec, "BUNIT_007", "degree"); |
505 |
|
506 |
} // irec |
507 |
|
508 |
drms_close_records(inRS, DRMS_FREE_RECORD); |
509 |
drms_close_records(outRS, DRMS_INSERT_RECORD); |
510 |
|
511 |
return 0; |
512 |
|
513 |
} // DoIt |
514 |
|
515 |
|
516 |
//================================================================================================= |
517 |
|
518 |
/* |
519 |
* Fetch ephemeris info from a DRMS record |
520 |
* No error checking for now |
521 |
* |
522 |
*/ |
523 |
|
524 |
int getEphemeris(DRMS_Record_t *inRec, struct ephemeris *ephem) |
525 |
{ |
526 |
|
527 |
int status = 0; |
528 |
|
529 |
float crota2 = drms_getkey_float(inRec, "CROTA2", &status); // rotation |
530 |
double sina = sin(crota2 * RADSINDEG); |
531 |
double cosa = cos(crota2 * RADSINDEG); |
532 |
|
533 |
ephem->pa = - crota2 * RADSINDEG; |
534 |
ephem->disk_latc = drms_getkey_float(inRec, "CRLT_OBS", &status) * RADSINDEG; |
535 |
ephem->disk_lonc = drms_getkey_float(inRec, "CRLN_OBS", &status) * RADSINDEG; |
536 |
|
537 |
float crvalx = 0.0; |
538 |
float crvaly = 0.0; |
539 |
float crpix1 = drms_getkey_float(inRec, "CRPIX1", &status); |
540 |
float crpix2 = drms_getkey_float(inRec, "CRPIX2", &status); |
541 |
float cdelt = drms_getkey_float(inRec, "CDELT1", &status); // in arcsec, assumimg dx=dy |
542 |
ephem->disk_xc = PIX_X(0.0,0.0) - 1.0; // Center of disk in pixel, starting at 0 |
543 |
ephem->disk_yc = PIX_Y(0.0,0.0) - 1.0; |
544 |
|
545 |
float dSun = drms_getkey_float(inRec, "DSUN_OBS", &status); |
546 |
float rSun_ref = drms_getkey_float(inRec, "RSUN_REF", &status); |
547 |
if (status) rSun_ref = 6.96e8; |
548 |
|
549 |
ephem->asd = asin(rSun_ref/dSun); |
550 |
ephem->rSun = asin(rSun_ref / dSun) * RAD2ARCSEC / cdelt; // in pixel |
551 |
|
552 |
return 0; |
553 |
|
554 |
} |
555 |
|
556 |
/* Convert field vector, calls img2helioVector */ |
557 |
void get_bptr(struct ephemeris *ephem, int *dims, float *fld, float *inc, float *azi, |
558 |
float *bp, float *bt, float *br, float *lon, float *lat) |
559 |
{ |
560 |
int ncols = dims[0], nrows = dims[1]; |
561 |
int ipix = 0; |
562 |
|
563 |
double lonc = 0., latc = ephem->disk_latc; // iput |
564 |
double xc = ephem->disk_xc, yc = ephem->disk_yc; |
565 |
double asd = ephem->asd, pa = ephem->pa, rSun = ephem->rSun; |
566 |
double x, y, b_xi, b_eta, b_zeta; |
567 |
double rho, lat_t, lon_t, sinlat_t, coslat_t, sig, mu, chi; // output |
568 |
double bx_t, by_t, bz_t; |
569 |
// printf("xc=%f, yc=%f, rSun=%f\n", xc, yc, rSun); |
570 |
|
571 |
for (int row = 0; row < nrows; row++) { |
572 |
for (int col = 0; col < ncols; col++) { |
573 |
ipix = row * ncols + col; |
574 |
|
575 |
// lon/lat |
576 |
x = (col - xc) / rSun; y = (row - yc) / rSun; |
577 |
if (img2sphere(x, y, asd, latc, lonc, pa, |
578 |
&rho, &lat_t, &lon_t, &sinlat_t, &coslat_t, |
579 |
&sig, &mu, &chi)) { // fail |
580 |
lon[ipix] = lat[ipix] = DRMS_MISSING_FLOAT; |
581 |
bp[ipix] = bt[ipix] = br[ipix] = DRMS_MISSING_FLOAT; |
582 |
continue; |
583 |
} |
584 |
if (lon_t > PI) lon_t -= TWOPI; |
585 |
lon[ipix] = lon_t; lat[ipix] = lat_t; |
586 |
|
587 |
// Bvec |
588 |
b_xi = - fld[ipix] * sin(inc[ipix]) * sin(azi[ipix]); |
589 |
b_eta = fld[ipix] * sin(inc[ipix]) * cos(azi[ipix]); |
590 |
b_zeta = fld[ipix] * cos(inc[ipix]); |
591 |
img2helioVector(b_xi, b_eta, b_zeta, &bx_t, &by_t, &bz_t, |
592 |
lon_t, lat_t, lonc, latc, pa); |
593 |
bp[ipix] = bx_t; |
594 |
bt[ipix] = by_t * (-1); |
595 |
br[ipix] = bz_t; |
596 |
} |
597 |
} |
598 |
} |
599 |
|
600 |
/* Compute error, calls errprop_rad */ |
601 |
void get_bptr_err(struct ephemeris *ephem, int *dims, float *fld, float *inc, float *azi, |
602 |
float *lon, float *lat, |
603 |
float *err_fld, float *err_inc, float *err_azi, float *cc_fi, float *cc_fa, float *cc_ia, |
604 |
float *err_bp, float *err_bt, float *err_br) |
605 |
{ |
606 |
int ncols = dims[0], nrows = dims[1]; |
607 |
int npix = ncols * nrows; |
608 |
|
609 |
double lonc = 0., latc = ephem->disk_latc, pa = ephem->pa; // Dec 23 2015, changed lonc from disc_lonc to 0. |
610 |
|
611 |
float var_fld, var_inc, var_azi; // variance |
612 |
float cov_fi, cov_fa, cov_ia; // covariance |
613 |
|
614 |
double var_bp, var_bt, var_br; |
615 |
|
616 |
for (int ipix = 0; ipix < npix; ipix++) { |
617 |
if (isnan(lon[ipix])) { |
618 |
err_bp[ipix] = err_bt[ipix] = err_br[ipix] = DRMS_MISSING_FLOAT; |
619 |
continue; |
620 |
} |
621 |
|
622 |
// variance & covariance |
623 |
var_fld = err_fld[ipix] * err_fld[ipix]; |
624 |
var_inc = err_inc[ipix] * err_inc[ipix]; |
625 |
var_azi = err_azi[ipix] * err_azi[ipix]; |
626 |
cov_fi = cc_fi[ipix] * err_fld[ipix] * err_inc[ipix]; |
627 |
cov_fa = cc_fa[ipix] * err_fld[ipix] * err_azi[ipix]; |
628 |
cov_ia = cc_ia[ipix] * err_inc[ipix] * err_azi[ipix]; |
629 |
|
630 |
// Do it |
631 |
vecErrProp(fld[ipix], inc[ipix], azi[ipix], var_fld, var_inc, var_azi, cov_fi, cov_fa, cov_ia, |
632 |
lon[ipix], lat[ipix], lonc, latc, pa, &var_bp, &var_bt, &var_br); |
633 |
err_bp[ipix] = sqrt(var_bp); |
634 |
err_bt[ipix] = sqrt(var_bt); |
635 |
err_br[ipix] = sqrt(var_br); |
636 |
} |
637 |
} |
638 |
|
639 |
// From img2helioVector.c |
640 |
int img2helioVector (double bxImg, double byImg, double bzImg, double *bxHelio, |
641 |
double *byHelio, double *bzHelio, double lon, double lat, |
642 |
double lonc, double latc, double pAng) { |
643 |
/* |
644 |
* perform tramsformation of a vector from image location (lon, lat) to |
645 |
* heliographic center. The formula is from Hagyard (1987), and further |
646 |
* developed by Gary & Hagyard (1990). |
647 |
* |
648 |
* Arguments: |
649 |
* |
650 |
* bxImg, byImg, bzImg: three components of vector magnetic field on image |
651 |
* coordinates. |
652 |
* lon, lat: heliographic coordinates of the location where the vector field |
653 |
* measured. They are in radians. |
654 |
* lonc, latc: heliographic coordinates of the image disk center. They are in |
655 |
* radians. |
656 |
* pAng: position angle of the heliographic north pole, measured eastward |
657 |
* from the north. It's in radians. |
658 |
*/ |
659 |
|
660 |
static double raddeg = M_PI / 180.; |
661 |
double a11, a12, a13, a21, a22, a23, a31, a32, a33; |
662 |
|
663 |
a11 = -sin(latc) * sin(pAng) * sin(lon - lonc) + cos(pAng) * cos(lon - lonc); |
664 |
a12 = sin(latc) * cos(pAng) * sin(lon - lonc) + sin(pAng) * cos(lon - lonc); |
665 |
a13 = -cos(latc) * sin(lon - lonc); |
666 |
a21 = -sin(lat) * (sin(latc) * sin(pAng) * cos(lon - lonc) + cos(pAng) * sin(lon - lonc)) |
667 |
- cos(lat) * cos(latc) * sin(pAng); |
668 |
a22 = sin(lat) * (sin(latc) * cos(pAng) * cos(lon - lonc) - sin(pAng) * sin(lon - lonc)) |
669 |
+ cos(lat) * cos(latc) * cos(pAng); |
670 |
a23 = -cos(latc) * sin(lat) * cos(lon - lonc) + sin(latc) * cos(lat); |
671 |
a31 = cos(lat) * (sin(latc) * sin(pAng) * cos(lon - lonc) + cos(pAng) * sin(lon - lonc)) |
672 |
- sin(lat) * cos(latc) * sin(pAng); |
673 |
a32 = -cos(lat) * (sin(latc) * cos(pAng) * cos(lon - lonc) - sin(pAng) * sin(lon - lonc)) |
674 |
+ sin(lat) * cos(latc) * cos(pAng); |
675 |
a33 = cos(lat) * cos(latc) * cos(lon - lonc) + sin(lat) * sin(latc); |
676 |
|
677 |
*bxHelio = a11 * bxImg + a12 * byImg + a13 * bzImg; |
678 |
*byHelio = a21 * bxImg + a22 * byImg + a23 * bzImg; |
679 |
*bzHelio = a31 * bxImg + a32 * byImg + a33 * bzImg; |
680 |
|
681 |
return 0; |
682 |
} |
683 |
|
684 |
|
685 |
// Error propagation for vector field |
686 |
// Adapted from Yang's errorprop.c |
687 |
// All angles in radian |
688 |
// By or Bt=-By doesn't matter (all terms are squared) |
689 |
|
690 |
void vecErrProp(float fld, float inc, float azi, |
691 |
float var_fld, float var_inc, float var_azi, float cov_fi, float cov_fa, float cov_ia, |
692 |
double lon, double lat, double lonc, double latc, double pa, |
693 |
double *var_bp, double *var_bt, double *var_br) |
694 |
|
695 |
{ |
696 |
|
697 |
// Coefficients |
698 |
|
699 |
double a11, a12, a13, a21, a22, a23, a31, a32, a33; |
700 |
a11 = - sin(latc) * sin(pa) * sin(lon - lonc) + cos(pa) * cos(lon - lonc); |
701 |
a12 = sin(latc) * cos(pa) * sin(lon - lonc) + sin(pa) * cos(lon - lonc); |
702 |
a13 = - cos(latc) * sin(lon - lonc); |
703 |
a21 = - sin(lat) * (sin(latc) * sin(pa) * cos(lon - lonc) + cos(pa) * sin(lon - lonc)) |
704 |
- cos(lat) * cos(latc) * sin(pa); |
705 |
a22 = sin(lat) * (sin(latc) * cos(pa) * cos(lon - lonc) - sin(pa) * sin(lon - lonc)) |
706 |
+ cos(lat) * cos(latc) * cos(pa); |
707 |
a23 = - cos(latc) * sin(lat) * cos(lon - lonc) + sin(latc) * cos(lat); |
708 |
a31 = cos(lat) * (sin(latc) * sin(pa) * cos(lon - lonc) + cos(pa) * sin(lon - lonc)) |
709 |
- sin(lat) * cos(latc) * sin(pa); |
710 |
a32 = - cos(lat) * (sin(latc) * cos(pa) * cos(lon - lonc) - sin(pa) * sin(lon - lonc)) |
711 |
+ sin(lat) * cos(latc) * cos(pa); |
712 |
a33 = cos(lat) * cos(latc) * cos(lon - lonc) + sin(lat) * sin(latc); |
713 |
|
714 |
// Derivative |
715 |
|
716 |
double dBpdfld, dBpdinc, dBpdazi; |
717 |
double dBtdfld, dBtdinc, dBtdazi; |
718 |
double dBrdfld, dBrdinc, dBrdazi; |
719 |
|
720 |
dBpdfld = (- a11 * sin(inc) * sin(azi) + a12 * sin(inc) * cos(azi) + a13 * cos(inc)); |
721 |
dBpdinc = fld * (- a11 * cos(inc) * sin(azi) + a12 * cos(inc) * cos(azi) - a13 * sin(inc)); |
722 |
dBpdazi = fld * (- a11 * sin(inc) * cos(azi) - a12 * sin(inc) * sin(azi)); |
723 |
|
724 |
dBtdfld = (- a21 * sin(inc) * sin(azi) + a22 * sin(inc) * cos(azi) + a23 * cos(inc)); |
725 |
dBtdinc = fld * (- a21 * cos(inc) * sin(azi) + a22 * cos(inc) * cos(azi) - a23 * sin(inc)); |
726 |
dBtdazi = fld * (- a21 * sin(inc) * cos(azi) - a22 * sin(inc) * sin(azi)); |
727 |
|
728 |
dBrdfld = (- a31 * sin(inc) * sin(azi) + a32 * sin(inc) * cos(azi) + a33 * cos(inc)); |
729 |
dBrdinc = fld * (- a31 * cos(inc) * sin(azi) + a32 * cos(inc) * cos(azi) - a33 * sin(inc)); |
730 |
dBrdazi = fld * (- a31 * sin(inc) * cos(azi) - a32 * sin(inc) * sin(azi)); |
731 |
|
732 |
// Sum |
733 |
|
734 |
*var_bp = dBpdfld * dBpdfld * var_fld + dBpdinc * dBpdinc * var_inc + dBpdazi * dBpdazi * var_azi + |
735 |
2.0 * dBpdfld * dBpdinc * cov_fi + 2.0 * dBpdfld * dBpdazi * cov_fa + 2.0 * dBpdinc * dBpdazi * cov_ia; |
736 |
|
737 |
*var_bt = dBtdfld * dBtdfld * var_fld + dBtdinc * dBtdinc * var_inc + dBtdazi * dBtdazi * var_azi + |
738 |
2.0 * dBtdfld * dBtdinc * cov_fi + 2.0 * dBtdfld * dBtdazi * cov_fa + 2.0 * dBtdinc * dBtdazi * cov_ia; |
739 |
|
740 |
*var_br = dBrdfld * dBrdfld * var_fld + dBrdinc * dBrdinc * var_inc + dBrdazi * dBrdazi * var_azi + |
741 |
2.0 * dBrdfld * dBrdinc * cov_fi + 2.0 * dBrdfld * dBrdazi * cov_fa + 2.0 * dBrdinc * dBrdazi * cov_ia; |
742 |
|
743 |
} |
744 |
|
745 |
// from Cartography.c |
746 |
int img2sphere (double x, double y, double ang_r, double latc, double lonc, |
747 |
double pa, double *rho, double *lat, double *lon, double *sinlat, |
748 |
double *coslat, double *sig, double *mu, double *chi) { |
749 |
/* |
750 |
* Map projected coordinates (x, y) to (lon, lat) and (rho | sig, chi) |
751 |
* |
752 |
* Arguments: |
753 |
* x } Plate locations, in units of the image radius, relative |
754 |
* y } to the image center |
755 |
* ang_r Apparent semi-diameter of sun (angular radius of sun at |
756 |
* the observer's tangent line) |
757 |
* latc Latitude of disc center, uncorrected for light travel time |
758 |
* lonc Longitude of disc center |
759 |
* pa Position angle of solar north on image, measured eastward |
760 |
* from north (sky coordinates) |
761 |
* Return values: |
762 |
* rho Angle point:sun_center:observer |
763 |
* lon Heliographic longitude |
764 |
* lat Heliographic latitude |
765 |
* sinlat sine of heliographic latitude |
766 |
* coslat cosine of heliographic latitude |
767 |
* sig Angle point:observer:sun_center |
768 |
* mu cosine of angle between the point:observer line and the |
769 |
* local normal |
770 |
* chi Position angle on image measured westward from solar |
771 |
* north |
772 |
* |
773 |
* All angles are in radians. |
774 |
* Return value is 1 if point is outside solar radius (in which case the |
775 |
* heliographic coordinates and mu are meaningless), 0 otherwise. |
776 |
* It is assumed that the image is direct; the x or y coordinates require a |
777 |
* sign change if the image is inverted. |
778 |
* |
779 |
*/ |
780 |
static double ang_r0 = 0.0, sinang_r = 0.0, tanang_r = 0.0; |
781 |
static double latc0 = 0.0, coslatc = 1.0, sinlatc = 0.0; |
782 |
double cosr, sinr, sinlon, sinsig; |
783 |
|
784 |
if (ang_r != ang_r0) { |
785 |
sinang_r = sin (ang_r); |
786 |
tanang_r = tan (ang_r); |
787 |
ang_r0 = ang_r; |
788 |
} |
789 |
if (latc != latc0) { |
790 |
sinlatc = sin (latc); |
791 |
coslatc = cos (latc); |
792 |
latc0 = latc; |
793 |
} |
794 |
*chi = atan2 (x, y) + pa; |
795 |
while (*chi > 2 * M_PI) *chi -= 2 * M_PI; |
796 |
while (*chi < 0.0) *chi += 2 * M_PI; |
797 |
/* Camera curvature correction, no small angle approximations */ |
798 |
*sig = atan (hypot (x, y) * tanang_r); |
799 |
sinsig = sin (*sig); |
800 |
*rho = asin (sinsig / sinang_r) - *sig; |
801 |
if (*sig > ang_r) return (-1); |
802 |
*mu = cos (*rho + *sig); |
803 |
sinr = sin (*rho); |
804 |
cosr = cos (*rho); |
805 |
|
806 |
*sinlat = sinlatc * cos (*rho) + coslatc * sinr * cos (*chi); |
807 |
*coslat = sqrt (1.0 - *sinlat * *sinlat); |
808 |
*lat = asin (*sinlat); |
809 |
sinlon = sinr * sin (*chi) / *coslat; |
810 |
*lon = asin (sinlon); |
811 |
if (cosr < (*sinlat * sinlatc)) *lon = M_PI - *lon; |
812 |
*lon += lonc; |
813 |
while (*lon < 0.0) *lon += 2 * M_PI; |
814 |
while (*lon >= 2 * M_PI) *lon -= 2 * M_PI; |
815 |
return (0); |
816 |
} |