ViewVC Help
View File | Revision Log | Show Annotations | Root Listing
root/JSOC/proj/util/apps/hmi_limbdark.c
Revision: 1.11
Committed: Mon Jul 17 16:56:21 2017 UTC (6 years, 2 months ago) by kehcheng
Content type: text/plain
Branch: MAIN
CVS Tags: Ver_9-1, Ver_LATEST, Ver_9-3, Ver_9-41, Ver_9-2, Ver_9-5, Ver_9-4, HEAD
Changes since 1.10: +3 -3 lines
Log Message:
fix typo nx->ny in upNcenter()

File Contents

# Content
1 #define CVSVERSION "$Id: hmi_limbdark.c,v 1.10 2017/07/17 16:45:23 kehcheng Exp $"
2 /**
3 @defgroup analysis
4 @ingroup su_util
5
6 @brief Compute solar limb darkening and remove.
7
8 @par
9 @code
10 hmi_limbdark - emoves limb darkening.
11
12 Input is expected to be hmi (or drms mdi) brightness image data with.
13 Output is the residual image after removing limb-darkening with
14 a polynomial fit. The fit order defaults to 2. The limb-darkening
15 profile comes from Tech Note SOI_TN_095 but the values in use here are from
16 an average of several runs with the -f flag set.
17 Modified from MDI DSDS program fitlimbdark.
18 Default is to rotate to solar north up, and center to nearest pixel.
19
20 Fit formula comes from Pierce, A.K. and C. Slaughter, "Solar Limb Darkening", Solar Physics 51, 25-41, 1977.
21
22 Parameters are:
23 in input recordset, expected to be an Ic product
24 out output seriesname
25 f FLAG: Compute limb-darkening fit parameters.
26 l FLAG: non-zero supresses limb darkening removal
27 c FLAG: Do not center or rotate from input data orientation
28 r FLAG: non-zero performs REVERSE limb darkening removal
29 n FLAG: normalize output by dividing by image mean
30 i.e. puts limb darkening back in
31 croplimit float crop limit for removing limb darkening, default 1.0
32 requestid optional string
33
34 @endcode
35
36 @par Synopsis:
37 @code
38 hmi_fitlimbdark in=input data out=output data
39 @endcode
40
41 */
42
43 #include "jsoc.h"
44 #include "jsoc_main.h"
45 #include "fstats.h"
46 #include <math.h>
47 #include <stdlib.h>
48 #include <time.h>
49
50 char *module_name = "hmi_limbdark";
51
52 #define DIE(msg) {fflush(stdout);fprintf(stderr,"%s, status=%d\n",msg,status); return(status);}
53
54 #define Deg2Rad (M_PI/180.0)
55 #define Rad2arcsec (3600.0/Deg2Rad)
56 #define arcsec2Rad (Deg2Rad/3600.0)
57 #define Rad2Deg (180.0/M_PI)
58
59 struct ObsInfo_struct
60 {
61 // from observation info
62 TIME t_obs;
63 double rsun_obs, obs_vr, obs_vw, obs_vn;
64 double crpix1, crpix2, cdelt1, cdelt2, crota2;
65 double crval1, crval2;
66 double cosa, sina;
67 double obs_b0;
68 // observed point
69 int i,j;
70 // parameters for observed point
71 double x,y,r;
72 double rho;
73 double lon;
74 double lat;
75 double sinlat, coslat;
76 double sig;
77 double mu;
78 double chi;
79 double obs_v;
80 };
81
82 typedef struct ObsInfo_struct ObsInfo_t;
83
84 ObsInfo_t *GetObsInfo(DRMS_Segment_t *seg, ObsInfo_t *ObsLoc, int *status);
85
86 int GetObsLocInfo(DRMS_Segment_t *seg, int i, int j, ObsInfo_t *ObsLoc);
87
88 int rm_limbdark(DRMS_Array_t *arr, DRMS_Array_t *outarr, ObsInfo_t *ObsLoc, double *coefs, int *ncrop, int do_reverse, int do_norm, double crop_limit2);
89
90 int fit_limbdark(DRMS_Array_t *arr, ObsInfo_t *ObsLoc, double* coefs);
91
92 int upNcenter(DRMS_Array_t *data, ObsInfo_t *ObsLoc);
93
94 // for lsqfit, also needs math.h
95 int lsqfitd(double y[],double x[],double a[],int n,int np);
96 double imprvd(double a[], double lu[], double x[], double b[], int n);
97 int ludcmpd(double a[], int n);
98 void bkslvd(double lu[], double b[], int n);
99 int matinvd(double a[], int n);
100 int matsold(double a[], double x[], double b[], int n);
101
102 ModuleArgs_t module_args[] =
103 {
104 {ARG_STRING, "in", "NOT SPECIFIED", "Input data series."},
105 {ARG_STRING, "out", "NOT SPECIFIED", "Output data series."},
106 {ARG_FLAG, "l", "0", "disable limb darkening removal, implied by -r"},
107 {ARG_FLAG, "r", "0", "Restore limb darkening"},
108 {ARG_FLAG, "f", "0", "Fit limb darkening before applying"},
109 {ARG_FLAG, "n", "0", "Normalize the final image by dividing by the mean"},
110 {ARG_FLAG, "c", "0", "Supress center and flip 180 degrees if CROTA~180."},
111 {ARG_FLAG, "x", "0", "Exclude pixels that deviate from the default LD, <0.875 or >1.25."},
112 {ARG_FLAG, "h", "0", "Include full headers, set when requestid is present"},
113 {ARG_DOUBLES, "coefs", "0.0", "Limb darkening coeficients, 5 needed"},
114 {ARG_FLOAT, "croplimit", "1.0", "crop limit for removing limbdarkening"},
115 {ARG_STRING, "requestid", "NA", "JSOC export identifier"},
116 {ARG_END}
117 };
118
119 int DoIt(void)
120 {
121 int noLD = cmdparams_isflagset(&cmdparams, "l");
122 int noFlip = cmdparams_isflagset(&cmdparams, "c");
123 int restoreLD = cmdparams_isflagset(&cmdparams, "r");
124 int do_fit = cmdparams_isflagset(&cmdparams, "f");
125 int do_normalize = cmdparams_isflagset(&cmdparams, "n");
126 int do_exclude = cmdparams_isflagset(&cmdparams, "x");
127 const char *inQuery = params_get_str(&cmdparams, "in");
128 const char *outSeries = params_get_str(&cmdparams, "out");
129 const char *requestid = params_get_str(&cmdparams, "requestid");
130 int full_headers = cmdparams_isflagset(&cmdparams, "h") || strcmp(requestid, "NA");
131 float crop_limit = params_get_float(&cmdparams, "croplimit");
132 double crop_limit2 = crop_limit*crop_limit;
133 char *p;
134 int status = 0;
135 ObsInfo_t *ObsLoc;
136 // Coef version 1
137 // static double defaultcoefs[] = {1.0, 0.443000, 0.139000, 0.041000, 0.012500, 0.001900};
138 // char *CoefVersion = "1";
139 // Coef version 2
140 static double defaultcoefs[] = {1.0, 0.459224, 0.132395, 0.019601, 0.000802, -4.31934E-05 };
141 char *CoefVersion = "2";
142
143 double use_coefs[6];
144 double n_user_coefs = cmdparams_get_int(&cmdparams, "coefs_nvals", &status);
145
146 int nrecs, irec;
147 DRMS_RecordSet_t *inRS, *outRS;
148
149 if (strcmp(inQuery, "NOT SPECIFIED") == 0)
150 DIE("Must have input series");;
151 if (strcmp(outSeries, "NOT SPECIFIED") == 0)
152 DIE("Must have output series");;
153
154 printf("FitLimbDark\n");
155 if (n_user_coefs == 6)
156 {
157 double *cmdcoefs;
158 int i;
159 CoefVersion = "user given";
160 cmdparams_get_dblarr(&cmdparams, "coefs", &cmdcoefs, &status);
161 for (i=0; i<6; i++)
162 {
163 use_coefs[i] = cmdcoefs[i];
164 printf(" Coef%d = %0.6f\n", i, use_coefs[i]);
165 }
166 }
167 else
168 {
169 int i;
170 for (i=0; i<6; i++)
171 use_coefs[i] = defaultcoefs[i];
172 printf(" Use default coefs\n");
173 }
174
175 if (restoreLD) noLD = 1;
176 if (noLD)
177 printf(" Supress limb darkening removal\n");
178
179 inRS = drms_open_records(drms_env, inQuery, &status);
180 if (status || !inRS || (nrecs = inRS->n) == 0)
181 DIE("No input records found");
182
183 outRS = drms_create_records(drms_env, nrecs, (char *)outSeries, DRMS_PERMANENT, &status);
184 if (status || !outRS)
185 DIE("Failed to create output recordset");
186
187 for (irec=0; irec<nrecs; irec++)
188 {
189 DRMS_Record_t *inRec = inRS->records[irec];
190 DRMS_Record_t *outRec;
191 int quality = drms_getkey_int(inRec, "QUALITY", NULL);
192 ObsInfo_t *ObsLoc;
193
194 outRec = outRS->records[irec];
195 drms_copykeys(outRec, inRec, 0, kDRMS_KeyClass_Explicit);
196 drms_copykey(outRec, inRec, "T_REC");
197 drms_copykey(outRec, inRec, "T_OBS");
198 drms_copykey(outRec, inRec, "QUALITY");
199 drms_setkey_time(outRec, "DATE", time(0) + UNIX_EPOCH);
200 drms_setkey_string(outRec, "RequestID", requestid);
201 drms_setkey_string(outRec, "CODEVER4", CVSVERSION);
202
203 if (quality >= 0)
204 {
205 double mean=1.0;
206 double coefs[6];
207 DRMS_Segment_t *inSeg, *outSeg;
208 DRMS_Array_t *inArray, *outArray;
209 int ncropped = 0;
210 inSeg = drms_segment_lookupnum(inRec, 0);
211 inArray = drms_segment_read(inSeg, DRMS_TYPE_FLOAT, &status);
212 if (status)
213 {
214 printf(" No data file found but QUALITY not bad, status=%d\n", status);
215 drms_free_array(inArray);
216 continue;
217 }
218
219 ObsLoc = GetObsInfo(inSeg, NULL, &status);
220 if (status)
221 DIE("Failed to get observatory location.");
222
223 // if (do_exclude && do_fit)
224 if (do_fit)
225 {
226 if (do_exclude )
227 {
228 DRMS_Array_t *xArray = drms_array_create(DRMS_TYPE_FLOAT, inArray->naxis, inArray->axis, NULL, &status);
229 DRMS_Array_t *inxArray = drms_array_create(DRMS_TYPE_FLOAT, inArray->naxis, inArray->axis, NULL, &status);
230 float *iv = (float*)inArray->data;
231 float *v = (float*)xArray->data;
232 float *nv = (float*)inxArray->data;
233 int i, n = inArray->axis[0] * inArray->axis[1];
234 int nskip = 0;
235 float missval = DRMS_MISSING_FLOAT;
236 rm_limbdark(inArray, xArray, ObsLoc, use_coefs, &ncropped, 0, 1, crop_limit2);
237 for (i=0; i<n; i++, v++, iv++)
238 if (!isnan(*v) && *v > 0.850 && *v < 1.150)
239 *nv++ = *iv;
240 else
241 {
242 *nv++ = missval;
243 if (!isnan(*v))
244 nskip++;
245 }
246 printf("exclude %d pixels\n", nskip);
247 fit_limbdark(inxArray, ObsLoc, coefs);
248 drms_free_array(xArray);
249 drms_free_array(inxArray);
250 }
251 else
252 fit_limbdark(inArray, ObsLoc, coefs);
253 }
254
255 outSeg = drms_segment_lookupnum(outRec, 0);
256 outArray = drms_array_create(DRMS_TYPE_FLOAT, inArray->naxis, inArray->axis, NULL, &status);
257
258 if (rm_limbdark(inArray, outArray, ObsLoc, (do_fit ? coefs : use_coefs), &ncropped, restoreLD, do_normalize, crop_limit2) == DRMS_SUCCESS)
259 {
260 int totvals, datavals;
261
262 if (drms_keyword_lookup(outRec, "COEF_VER", 0))
263 {
264 drms_setkey_string(outRec, "COEF_VER", CoefVersion);
265 drms_setkey_float(outRec, "LDCoef0", (float)(do_fit ? coefs[0] : use_coefs[0]));
266 drms_setkey_float(outRec, "LDCoef1", (float)(do_fit ? coefs[1] : use_coefs[1]));
267 drms_setkey_float(outRec, "LDCoef2", (float)(do_fit ? coefs[2] : use_coefs[2]));
268 drms_setkey_float(outRec, "LDCoef3", (float)(do_fit ? coefs[3] : use_coefs[3]));
269 drms_setkey_float(outRec, "LDCoef4", (float)(do_fit ? coefs[4] : use_coefs[4]));
270 drms_setkey_float(outRec, "LDCoef5", (float)(do_fit ? coefs[5] : use_coefs[5]));
271 }
272 else
273 {
274 char LDhistory[1000];
275 sprintf(LDhistory, "hmi_limbdark: COEF_VER=%s", CoefVersion);
276 drms_appendhistory(outRec, LDhistory, 0);
277 sprintf(LDhistory, "LDCoefs=%0.6f,%0.6f,%0.6f,%0.6f,%0.6f,%0.6f",
278 (float)(do_fit ? coefs[0] : use_coefs[0]),
279 (float)(do_fit ? coefs[1] : use_coefs[1]),
280 (float)(do_fit ? coefs[2] : use_coefs[2]),
281 (float)(do_fit ? coefs[3] : use_coefs[3]),
282 (float)(do_fit ? coefs[4] : use_coefs[4]),
283 (float)(do_fit ? coefs[5] : use_coefs[5]));
284 drms_appendhistory(outRec, LDhistory, 1);
285 }
286 if (!noFlip)
287 upNcenter(outArray, ObsLoc);
288 drms_setkey_double(outRec, "CRPIX1", ObsLoc->crpix1);
289 drms_setkey_double(outRec, "CRPIX2", ObsLoc->crpix2);
290 drms_setkey_double(outRec, "CROTA2", ObsLoc->crota2);
291
292 if (do_normalize)
293 {
294 outArray->bzero = 1.0;
295 outArray->bscale= 1.0/30000.0;
296 }
297 else
298 {
299 outArray->bzero = 32768.0;
300 outArray->bscale=1.5;
301 }
302
303 set_statistics(outSeg, outArray, 1);
304 totvals = drms_getkey_int(outRec, "TOTVALS", &status);
305 if (!status)
306 {
307 datavals = drms_getkey_int(outRec, "DATAVALS", &status);
308 totvals -= ncropped;
309 drms_setkey_int(outRec, "TOTVALS", totvals);
310 drms_setkey_int(outRec, "MISSVALS", totvals - datavals);
311 }
312
313 if (full_headers)
314 drms_segment_writewithkeys(outSeg, outArray, 0);
315 else
316 drms_segment_write(outSeg, outArray, 0);
317 drms_free_array(inArray);
318 drms_free_array(outArray);
319 }
320 // printf("Done with %s\n", drms_getkey_string(inRec, "T_OBS", NULL));
321 }
322 else
323 printf("Skip Rec %d, Quality=%#08x\n", irec, quality);
324 }
325 drms_close_records(outRS, DRMS_INSERT_RECORD);
326 drms_close_records(inRS, DRMS_FREE_RECORD);
327 return (DRMS_SUCCESS);
328 } // end of DoIt
329
330 int fit_limbdark(DRMS_Array_t *arr, ObsInfo_t *ObsLoc, double* coefs)
331 {
332 int status = 0;
333 double x0 = ObsLoc->crpix1 - 1;
334 double y0 = ObsLoc->crpix2 - 1;
335 double rsun = ObsLoc->rsun_obs/ObsLoc->cdelt1;
336
337 int ix, iy;
338 int nx = arr->axis[0];
339 int ny = arr->axis[1];
340 double scale;
341 double crop_limit2;
342 float *data = (float*)arr->data;
343 float missval = DRMS_MISSING_FLOAT;
344 int n;
345 int ord;
346 double *f = (double *)malloc(nx*ny*sizeof(double));
347 double *c = (double *)malloc(6*nx*ny*sizeof(double));
348 double fitcoefs[6];
349
350 if (!f || !c) DIE("malloc problem");
351
352 scale = 1.0/rsun;
353 crop_limit2 = 0.99975;
354
355 n = 0;
356 for (iy=0; iy<ny; iy++)
357 for (ix=0; ix<nx; ix++)
358 {
359 double costheta2;
360 double xi, mu, z, ld;
361 double x, y, R2;
362 float *Ip = data + iy*nx + ix;
363
364 if (drms_ismissing_float(*Ip))
365 continue;
366
367 /* get coordinates of point */
368 x = ((double)ix - x0) * scale; /* x,y in pixel coords */
369 y = ((double)iy - y0) * scale;
370
371 /* only fit points within limit radius */
372 R2 = x*x + y*y;
373
374 if (R2 >= crop_limit2)
375 continue;
376
377 costheta2 = 1.0 - R2;
378 mu = sqrt(costheta2);
379 xi = log(mu);
380 z = 1.0;
381 f[n] = *Ip;
382 c[6*n + 0] = 1.0;
383 for (ord=1; ord<6; ord++)
384 {
385 z *= xi;
386 c[6*n + ord] = z;
387 }
388 n++;
389 }
390 if (!lsqfitd(f, c, fitcoefs, 5, n))
391 {
392 fprintf(stderr,"lsqfit failure\n");
393 fitcoefs[0] = fitcoefs[1] = fitcoefs[2] = fitcoefs[3] = fitcoefs[4] = fitcoefs[5] = DRMS_MISSING_DOUBLE;
394 }
395 printf("Fit %d points, Coefs = %0.6f", n, fitcoefs[0]);
396 for (ord=0; ord<6; ord++)
397 {
398 coefs[ord] = fitcoefs[ord]/fitcoefs[0];
399 printf(", %8.6f", coefs[ord]);
400 }
401 printf("\n");
402 coefs[0] = fitcoefs[0];
403 free(f);
404 free(c);
405 return(0);
406 }
407
408 int rm_limbdark(DRMS_Array_t *arr, DRMS_Array_t *outarr, ObsInfo_t *ObsLoc, double *coefs, int *ncrop, int do_reverse, int do_norm, double crop_limit2)
409 {
410 double x0 = ObsLoc->crpix1 - 1;
411 double y0 = ObsLoc->crpix2 - 1;
412 double rsun = ObsLoc->rsun_obs/ObsLoc->cdelt1;
413
414 int ix, iy;
415 int nx = arr->axis[0];
416 int ny = arr->axis[1];
417 double scale;
418 float *data = (float *)arr->data;
419 float *odata = (float *)outarr->data;
420 float missval = DRMS_MISSING_FLOAT;
421 int ncropped = 0;
422
423 scale = 1.0/rsun;
424
425 for (iy=0; iy<ny; iy++)
426 for (ix=0; ix<nx; ix++)
427 {
428 double costheta2;
429 double xi, mu, z, ld;
430 double x, y, R2;
431 int ord;
432 float *Ip = data + iy*nx + ix;
433 float *Op = odata + iy*nx + ix;
434
435 if (drms_ismissing_float(*Ip))
436 {
437 *Op = missval;
438 continue;
439 }
440
441 /* get coordinates of point */
442 x = ((double)ix - x0) * scale; /* x,y in pixel coords */
443 y = ((double)iy - y0) * scale;
444
445 /* only fix points within limit radius */
446 R2 = x*x + y*y;
447
448 if (R2 >= crop_limit2)
449 {
450 *Op = missval;
451 ncropped++;
452 continue;
453 }
454
455 if (R2 < 0.99975)
456 costheta2 = 1.0 - R2;
457 else
458 costheta2 = 1.0 - 0.99975; /* 1/4 pixel from limb */
459
460 mu = sqrt(costheta2);
461 xi = log(mu);
462 z = 1.0;
463 ld = 1.0;
464 for (ord=1; ord<6; ord++)
465 {
466 z *= xi;
467 ld += coefs[ord] * z;
468 }
469 if (ld <= 0.0)
470 {
471 *Op = missval;
472 ncropped++;
473 }
474 else if (do_reverse)
475 *Op = *Ip * ld;
476 else
477 *Op = *Ip / ld;
478 }
479 *ncrop = ncropped;
480 if (do_norm)
481 {
482 double mean;
483 float *v = odata;
484 int i, n = outarr->axis[0] * outarr->axis[1];
485 if (coefs[0] == 1.0)
486 {
487 int nok=0;
488 v = odata;
489 for (i=0; i<n; i++, v++)
490 if (!isnan(*v))
491 { nok++; mean += *v; }
492 if (nok)
493 mean /= nok;
494 else
495 mean = 1.0;
496 }
497 else
498 mean = coefs[0];
499 v = odata;
500 for (i=0; i<n; i++, v++)
501 if (!isnan(*v))
502 *v /= mean;
503 }
504 return(0);
505 }
506
507 #define CHECK(keyname) {if (status) {fprintf(stderr,"Keyword failure to find: %s, status=%d\n",keyname,status); *rstatus=status; return(NULL);}}
508
509 ObsInfo_t *GetObsInfo(DRMS_Segment_t *seg, ObsInfo_t *pObsLoc, int *rstatus)
510 {
511 TIME t_prev;
512 DRMS_Record_t *rec;
513 TIME t_obs;
514 double dv;
515 ObsInfo_t *ObsLoc;
516 int status;
517
518 if (!seg || !(rec = seg->record))
519 { *rstatus = 1; return(NULL); }
520
521 ObsLoc = (pObsLoc ? pObsLoc : (ObsInfo_t *)malloc(sizeof(ObsInfo_t)));
522 if (!pObsLoc)
523 memset(ObsLoc, 0, sizeof(ObsInfo_t));
524
525 t_prev = ObsLoc->t_obs;
526 t_obs = drms_getkey_time(rec, "T_OBS", &status); CHECK("T_OBS");
527
528 if (t_obs <= 0.0)
529 { *rstatus = 2; return(NULL); }
530
531 if (t_obs != t_prev)
532 {
533 ObsLoc->crpix1 = drms_getkey_double(rec, "CRPIX1", &status); CHECK("CRPIX1");
534 ObsLoc->crpix2 = drms_getkey_double(rec, "CRPIX2", &status); CHECK("CRPIX2");
535 ObsLoc->crval1 = drms_getkey_double(rec, "CRVAL1", &status); CHECK("CRVAL1");
536 ObsLoc->crval2 = drms_getkey_double(rec, "CRVAL2", &status); CHECK("CRVAL2");
537 ObsLoc->cdelt1 = drms_getkey_double(rec, "CDELT1", &status); CHECK("CDELT1");
538 ObsLoc->cdelt2 = drms_getkey_double(rec, "CDELT2", &status); CHECK("CDELT1");
539 ObsLoc->crota2 = drms_getkey_double(rec, "CROTA2", &status); CHECK("CROTA2");
540 ObsLoc->sina = sin(ObsLoc->crota2*Deg2Rad);
541 ObsLoc->cosa = sqrt (1.0 - ObsLoc->sina*ObsLoc->sina);
542 ObsLoc->rsun_obs = drms_getkey_double(rec, "RSUN_OBS", &status);
543 if (status)
544 {
545 double dsun_obs = drms_getkey_double(rec, "DSUN_OBS", &status); CHECK("DSUN_OBS");
546 ObsLoc->rsun_obs = asin(696000000.0/dsun_obs)/arcsec2Rad;
547 }
548 ObsLoc->obs_vr = drms_getkey_double(rec, "OBS_VR", &status); CHECK("OBS_VR");
549 ObsLoc->obs_vw = drms_getkey_double(rec, "OBS_VW", &status); CHECK("OBS_VW");
550 ObsLoc->obs_vn = drms_getkey_double(rec, "OBS_VN", &status); CHECK("OBS_VN");
551 ObsLoc->obs_b0 = drms_getkey_double(rec, "CRLT_OBS", &status); CHECK("CRLT_OBS");
552 ObsLoc->t_obs = t_obs;
553 }
554 *rstatus = 0;
555 return(ObsLoc);
556 }
557
558 /* center whith whole pixel shifts and rotate by 180 if needed */
559 int upNcenter(DRMS_Array_t *arr, ObsInfo_t *ObsLoc)
560 {
561 int nx, ny, ix, iy, i, j, xoff, yoff;
562 double rot, x0, y0, mid;
563 float *data;
564 if (!arr || !ObsLoc)
565 return(1);
566 data = (float *)arr->data;
567 nx = arr->axis[0];
568 ny = arr->axis[1];
569 x0 = ObsLoc->crpix1 - 1;
570 y0 = ObsLoc->crpix2 - 1;
571 mid = (nx-1.0)/2.0;
572 if ((rot = fabs(ObsLoc->crota2)) > 179 && rot < 181)
573 {
574 // rotate image by 180 degrees by a flip flip
575 float val;
576 int half = ny / 2;
577 int odd = ny & 1;
578 for (iy=0; iy<half; iy++)
579 {
580 for (ix=0; ix<nx; ix++)
581 {
582 i = iy*nx + ix;
583 j = (ny - 1 - iy)*nx + (nx - 1 - ix);
584 val = data[i];
585 data[i] = data[j];
586 data[j] = val;
587 }
588 }
589 // reverse middle row if ny is odd
590 if (odd) {
591 for (ix=0; ix<nx/2; ++ix) {
592 i = nx*half + ix;
593 j = nx*half + nx - ix - 1;
594 val = data[i];
595 data[i] = data[j];
596 data[j] = val;
597 }
598 }
599 x0 = nx - x0;
600 y0 = ny - y0;
601 rot = ObsLoc->crota2 - 180.0;
602 if (rot < -90.0) rot += 360.0;
603 ObsLoc->crota2 = rot;
604 }
605 xoff = round(x0 - mid);
606 yoff = round(y0 - mid);
607 if (abs(xoff) > 1.0)
608 {
609 for (iy=0; iy<ny; iy++)
610 {
611 float valarr[nx];
612 for (ix=0; ix<nx; ix++)
613 {
614 int jx = ix - xoff;
615 if (jx >= nx) jx -= nx;
616 if (jx < 0) jx += nx;
617 valarr[jx] = data[iy*nx + ix];
618 }
619 for (ix=0; ix<nx; ix++)
620 data[iy*nx + ix] = valarr[ix];
621 }
622 x0 -= xoff;
623 }
624 if (abs(yoff) > 1.0)
625 {
626 for (ix=0; ix<nx; ix++)
627 {
628 float valarr[ny];
629 for (iy=0; iy<ny; iy++)
630 {
631 int jy = iy - yoff;
632 if (jy >= ny) jy -= ny;
633 if (jy < 0) jy += ny;
634 valarr[jy] = data[iy*nx + ix];
635 }
636 for (iy=0; iy<ny; iy++)
637 data[iy*nx + ix] = valarr[iy];
638 }
639 y0 -= yoff;
640 }
641 ObsLoc->crpix1 = x0 + 1;
642 ObsLoc->crpix2 = y0 + 1;
643 return(0);
644 }
645
646
647
648 #define ITMAX 7 /* max imprvd iterations */
649 #define EPS 2.8e-17 /* relative precision of arithmetic */
650
651 /*
652 * Solve the linear system a x = b for x, where b and x are
653 * n dimensional vectors and a is a n x n matrix of doubles,
654 * uses ludcmpd (lower/upper triangular decomposition), bkslvd
655 * (back solve lu system), imprvd (refine solution from ludcmpd
656 * and bkslvd - calls bkslvd itself)
657 */
658 int matsold(double a[], double x[], double b[], int n)
659 {
660 double *lu, err, wrk, wrk1;
661 extern double imprvd();
662 int k;
663
664 /*
665 * allocate storage for lu decomposition of a
666 */
667
668 lu = (double *)malloc( (n*n*8) );
669
670 /*
671 * copy a to lu
672 */
673
674 {
675 double *src = &a[0];
676 double *dest = lu;
677 int i = (n*n);
678
679 do
680 {
681 *(dest++) = *(src++);
682 } while(--i);
683 }
684
685 /*
686 * get lu decomposition in lu
687 */
688
689 if(ludcmpd(lu, n) == 0)
690 { /* singular matrix - give up */
691 free(lu);
692 return(0);
693 }
694
695 /*
696 * calculate the solution to the linear system
697 * using a maximum of ITMAX iterations of imprvd
698 */
699
700 {
701 int i;
702 double *dest = x;
703 double *src = b;
704
705 /*
706 * copy b to x
707 */
708
709 i = n;
710 do
711 {
712 *(dest++) = *(src++);
713 }while(--i);
714
715 /*
716 * backsolve and improve
717 */
718
719 bkslvd(lu, x, n);
720
721 for(k=0;k<ITMAX;k++)
722 {
723 err = imprvd(a,lu,x,b,n);
724 wrk = 0.0;
725 src = x;
726 i = n;
727 do
728 {
729 wrk1 = (*src < 0.0) ? -(*src++) : *(src++);
730 wrk = (wrk < wrk1) ? wrk1 : wrk;
731 }while(--i);
732 wrk1 = err/wrk;
733 if(wrk1 < EPS)break;
734 }
735
736 }
737
738 /*
739 * free temporary storage
740 */
741
742 free(lu);
743 return(1);
744 }
745
746 /*
747 * invert the n x n matrix of double precision numbers A,
748 * uses ludcmpd (lower/upper triangular decomposition), bkslvd
749 * (back solve lu system), imprvd (refine solution from ludcmpd
750 * and bkslvd - calls bkslvd itself)
751 */
752 int matinvd(double a[], int n)
753 {
754 double *ainv, *lu, *x, *b, err, wrk, wrk1;
755 extern double imprvd();
756 int j, k;
757
758 /*
759 * allocate storage for intermediate arrays and
760 * vectors
761 */
762
763 ainv = (double *)malloc( (n*n*8) );
764 lu = (double *)malloc( (n*n*8) );
765 x = (double *)malloc( (n*8) );
766 b = (double *)malloc( (n*8) );
767
768 /*
769 * copy a to lu
770 */
771
772 {
773 double *src = &a[0];
774 double *dest = lu;
775 int i = (n*n);
776
777 do
778 {
779 *(dest++) = *(src++);
780 } while(--i);
781 }
782
783 /*
784 * get lu decomposition in lu
785 */
786
787 if(ludcmpd(lu, n) == 0)
788 { /* singular matrix - give up */
789 free(ainv);
790 free(lu);
791 free(x);
792 free(b);
793 return(0);
794 }
795
796 /*
797 * calculate the columns of the inverse one at a time
798 * using a maximum of ITMAX iterations of imprvd
799 */
800
801 for(j = 0;j<n;j++)
802 {
803 int i;
804 double *dest = b;
805 double *src = x;
806
807 /*
808 * construct correct right hand sides for calculating
809 * the current column of inverse
810 */
811
812 i = n;
813 do
814 {
815 *(dest++) = 0.0;
816 *(src++) = 0.0;
817 }while(--i);
818 b[j] = x[j] = 1.0;
819
820 /*
821 * find column of inverse
822 */
823
824 bkslvd(lu, x, n);
825
826 for(k=0;k<ITMAX;k++)
827 {
828 err = imprvd(a,lu,x,b,n);
829 wrk = 0.0;
830 src = x;
831 i = n;
832 do
833 {
834 wrk1 = (*src < 0.0) ? -(*src++) : *(src++);
835 wrk = (wrk < wrk1) ? wrk1 : wrk;
836 }while(--i);
837 wrk1 = err/wrk;
838 if(wrk1 < EPS)break;
839 }
840
841 /*
842 * save column of inverse in ainv
843 */
844
845 src = x;
846 dest = &ainv[j];
847 i = n;
848 do
849 {
850 *dest = *(src++);
851 dest += n;
852 }while(--i);
853 }
854 {
855 int i = n*n;
856 double *src = ainv;
857 double *dest = &a[0];
858
859 /*
860 * copy inverse onto original a
861 */
862
863 do
864 {
865 *(dest++) = *(src++);
866 }while(--i);
867 }
868
869 /*
870 * free temporary storage
871 */
872
873 free(ainv);
874 free(lu);
875 free(x);
876 free(b);
877 return(1);
878 }
879
880 /*
881 * back solve for x in Ax = b, A an n x n matrix double prescison
882 * numbers and x and b are n dimensional vectors - given the LU
883 * decomposition of A. b is overwritten with x.
884 */
885 void bkslvd(double lu[], double b[], int n)
886 {
887 int i, k;
888
889 /*
890 * multiply by lower triangular
891 */
892
893 for(i=0;i<(n-1);i++)
894 {
895 int j = n-1-i;
896 double *lower = &lu[i*(n+1)+n];
897 double *current = &b[i+1];
898 double first = b[i];
899
900 do
901 {
902
903 *(current++) -= first*(*lower);
904 lower += n;
905 } while(--j);
906 }
907
908 /*
909 * backsolve upper triangular
910 */
911
912 for(i = n-1;i >= 0;i--)
913 {
914 double *factor = &lu[n*i + i + 1];
915 double *vector = &b[i+1];
916 double *current = &b[i];
917
918 for(k=i;k<n-1;k++)
919 {
920 *current -= *(factor++)*(*(vector++));
921 }
922 *current /= lu[n*i+i];
923 }
924 return;
925 }
926
927 /*
928 * LU decomposition of an n x n matrix of double precision
929 * numbers by Gaussian elimination in place - original
930 * matrix is overwritten - no pivoting
931 *
932 * clearer but slower version is in comments at the end - present
933 * version is optimized for PDP 11/45
934 */
935 int ludcmpd(double a[], int n)
936 {
937 double wrk; /* to save divides */
938 int i, j;
939
940 for(i=0;i<(n-1);i++)
941 {
942 if(a[i+n*i] != 0.0)wrk = 1.0/a[i+n*i];
943 else return(0); /* zero divide - give up */
944 for(j=i+1;j<n;j++)
945 {
946 double *first = &a[i+1+n*i];
947 double *row = &a[i+1+n*j];
948 int k = n-(i+1);
949 double elim = a[i+n*j]*wrk;
950
951 /* save lower triangular */
952 a[i+n*j] = elim;
953 /*
954 * generate upper triangular - optimized
955 * for fast innermost loop
956 *
957 * note that initialization time
958 * may dominate for small n - but
959 * then it doesn't take long anyway
960 */
961 do
962 {
963 *(row++) -= *(first++)*elim;
964 }while(--k);
965 }
966 }
967 return(1);
968 }
969
970 /*
971 * improve the solution, x, to the linear equation Ax = b, where A is a
972 * n x n matrix of double precision numbers, x is a provisional
973 * solution to the equation (most likely from bkslv), b is the
974 * original right hand side and lu is the decomposition of A into
975 * a product of a lower triangular and an upper triangular matrix
976 * (most likely from ludcmp). Returns the maximum absolute error
977 * of the error vector (Ax - b). The improved x overwrites the old x.
978 */
979 double imprvd(double a[], double lu[], double x[], double b[], int n)
980 {
981 double *berr, err;
982 int i;
983
984 berr = (double *)malloc( (n*8) );
985 err = 0.0;
986 /*
987 * calculate error vector and max absolute error
988 */
989
990 for(i=0;i<n;i++)
991 {
992 int j = n;
993 double *vector = &x[0];
994 double *row = &a[n*i];
995 double accum = 0.0;
996
997 do
998 {
999 accum += (*(vector++))*(*(row++));
1000 }while(--j);
1001 berr[i] = b[i] - accum;
1002
1003 accum = (berr[i] < 0) ? -berr[i] : berr[i];
1004 err = (err < accum) ? accum : err;
1005 }
1006
1007 bkslvd(lu, berr, n);
1008 for(i=0;i<n;i++)x[i] += berr[i];
1009 free(berr);
1010 return(err);
1011 }
1012
1013 /*
1014 * linear least squares fit to a vector y(i) of np vectors x(i,j), where
1015 * i runs from 1 to np, and j runs from 0 to n, the coeficients are returned
1016 * in the vector a(j). The weight of each y(i) is contained in x(i,0) -
1017 * patterned on the algol routine written by Leif Svalgaard in algol.
1018 * The usual "normal equations" for a least square fit are solved, with
1019 * the following modifications:
1020 *
1021 * 1) The sum of the weights is normalized to np, the number of data
1022 * points, forming adjusted weights, w(i).
1023 *
1024 * 2) The y(i) are normalized by subtracting the weighted mean,
1025 * ym = (sum of y(i)*w(i))/np, and dividing by an estimate of the
1026 * square root of the variance sqrt( (sum (y(i)-ym)**2)/(np-1)).
1027 *
1028 * 3) The fitting vectors x(i,j) are also normalized by subttracting
1029 * the weighted mean and dividing by the square root of the estimated
1030 * variance.
1031 *
1032 * 4) Both left and right sides of the linear equations are divided
1033 * by (np-1) so that the expected values of the elements of the matrix
1034 * and the right hand side are 1.
1035 *
1036 * 5) The resulting solutions to the linear equations must be transformed
1037 * to account for the above normalizations before being returned.
1038 *
1039 * Returns 1 on succesful completion, 0 on some error condition. From
1040 * C, &y[0] should point to np doubles, &x[0] should point to np*(n+1)
1041 * doubles and &a[0] should point to (n+1) doubles.
1042 */
1043 int lsqfitd(double y[],double x[],double a[],int n,int np)
1044 {
1045 double *ar, *lu, *sx, *xm, *r;
1046 int i, k;
1047 double f1, ym, sum, s, wmi;
1048 extern double sqrt(), imprvd();
1049 /*
1050 * first allocate and zero working arrays and zero sums.
1051 *
1052 * ym is the weighted mean of the y(i)'s
1053 *
1054 * s is the square root of the estimated variance of the y(i)'s
1055 *
1056 * wmi is the one over the sum of the weights
1057 *
1058 * xm(j) is the vector of the weighted means of the x(i,j)'s
1059 *
1060 * sx(j) is the vector of the square roots of the estimated
1061 * variances of the x(i,j)'s
1062 *
1063 */
1064
1065 if (np < 3)
1066 return(0);
1067 ar = (double *)malloc( n*n*8 );
1068 lu = (double *)malloc( n*n*8 );
1069 sx = (double *)malloc( n*8 );
1070 xm = (double *)malloc( n*8 );
1071 r = (double *)malloc( n*8 );
1072
1073 sum = ym = s = 0.0;
1074 /* zero r and ar */
1075 for(i=0;i<n;i++)
1076 {
1077 double *dp = &ar[i*n];
1078 int j = n;
1079
1080 r[i] = 0.0;
1081 do
1082 {
1083 *(dp)++ = 0.0;
1084 }while(--j);
1085 }
1086 {
1087 /* zero sx and xm */
1088 double *dp1 = &sx[0];
1089 double *dp2 = &xm[0];
1090 int j = n;
1091
1092 do
1093 {
1094 *(dp1++) = 0.0;
1095 *(dp2++) = 0.0;
1096 }while(--j);
1097 }
1098
1099 /* accumulate sum of weights, weighted sum of y's and
1100 * fitting vectors
1101 */
1102 for(i=0;i<np;i++)
1103 {
1104 double *dp1 = &xm[0];
1105 double *dp2 = &x[(n+1)*i];
1106 int j = n;
1107 double wi;
1108
1109 wi = *(dp2++);
1110 sum += wi;
1111 ym += wi*y[i];
1112 do
1113 {
1114 *(dp1++) += wi*(*(dp2++));
1115 }while(--j);
1116 }
1117 /* if the sum of the weights is 0, return 0 */
1118 if(sum == 0.0)
1119 {
1120 free(ar);
1121 free(lu);
1122 free(sx);
1123 free(xm);
1124 free(r);
1125 return(0);
1126 }
1127
1128 /* divide to get weighted averages from weighted sums */
1129 ym /= sum;
1130 wmi = ((double)np)/sum;
1131 for(i=0;i<n;i++)xm[i] /= sum;
1132
1133 /* accumulate weighted square of differences from weighted means,
1134 * matrix elements and right hand side of linear equation
1135 */
1136 for(i=0;i<np;i++)
1137 {
1138 double fy, wi;
1139
1140 wi = x[i*(n+1)]*wmi;
1141 fy = y[i] - ym;
1142 s += wi*fy*fy;
1143 for(k=0;k<n;k++)
1144 {
1145 double *dp1 = &ar[k];
1146 double *dp2 = &ar[n*k];
1147 double *dp3 = &xm[0];
1148 double *dp4 = &x[i*(n+1)+1];
1149 int j;
1150 double fx;
1151
1152 fx = *(dp4+k) - *(dp3+k);
1153 sx[k]+= wi*fx*fx;
1154 r[k] += wi*fx*fy;
1155
1156 for(j=0;j<=k;j++)
1157 {
1158 *dp2 += wi*fx*(*(dp4++) - *(dp3++));
1159 *dp1 = *(dp2++);
1160 dp1 += n;
1161 }
1162 }
1163 }
1164
1165 /* normalize equations so all matrix elements have
1166 * expectation value 1
1167 */
1168
1169 f1 = np - 1.0;
1170 s = sqrt(s/f1);
1171 for(i=0;i<n;i++)
1172 {
1173 double *dp1 = &ar[i];
1174 double *dp2 = &ar[i*n];
1175 double *dp3 = &sx[i];
1176 int j;
1177 double sxj;
1178
1179 *dp3 = sqrt(*dp3/f1);
1180 sxj = *dp3;
1181 r[i] /= f1*(*dp3)*s;
1182 dp3 = &sx[0];
1183
1184 for(j=0;j<=i;j++)
1185 {
1186 if (*dp3 == 0.0)
1187 return(0);
1188 *dp2 /= f1*(*(dp3++))*sxj;
1189 *dp1 = *(dp2++);
1190 dp1 += n;
1191 }
1192 }
1193
1194 /*
1195 * solve linear system - using ludcmpd, bkslvd, and imprvd
1196 * first make a copy of ar in lu
1197 */
1198
1199 {
1200 double *dp1 = &ar[0];
1201 double *dp2 = &lu[0];
1202 int j = n*n;
1203
1204 do
1205 {
1206 *(dp2++) = *(dp1++);
1207 }while(--j);
1208 }
1209
1210 if(ludcmpd(lu, n) == 0)
1211 { /* singular matrix - give up */
1212 free(ar);
1213 free(lu);
1214 free(sx);
1215 free(xm);
1216 free(r);
1217 return(0);
1218 }
1219
1220 /* copy r to a offset for the constant term */
1221
1222 {
1223 double *dp1 = &a[1];
1224 double *dp2 = &r[0];
1225 int j = n;
1226
1227 do
1228 {
1229 *(dp1++) = *(dp2++);
1230 }while(--j);
1231 }
1232
1233 /* back solve equations */
1234
1235 bkslvd(lu, &a[1], n);
1236
1237 /* do a maximum of ITMAX imprvd refinements */
1238
1239 for(i=0;i<ITMAX;i++)
1240 if(imprvd(ar, lu, &a[1], r, n) < EPS)break;
1241
1242 /* transform calculated fits back to original variables */
1243
1244 {
1245 double *dp1 = &a[0];
1246 double *dp2 = &sx[0];
1247 double *dp3 = &xm[0];
1248 int j;
1249
1250 *(dp1++) = ym;
1251 for(j=0;j<n;j++)
1252 {
1253 *dp1 *= s;
1254 *dp1 /= *(dp2++);
1255 a[0] -= (*(dp1++))*(*(dp3++));
1256 }
1257 }
1258
1259 /* free allocated storage */
1260 free(ar);
1261 free(lu);
1262 free(sx);
1263 free(xm);
1264 free(r);
1265
1266 return(1);
1267 }
1268
1269 /* Algol routine after which this routine is patterned
1270
1271 .
1272 external
1273 procedure lsqfit(y,x,a,n,np); value n,np;
1274 real array y,x,a; integer n,np;
1275 begin
1276 comment: Computes the least-squares fit to
1277 y(i) = a(0) + a(1)*x(i,1) + ... + a(n)*x(i,n)
1278 the weight for y(i) is stored in x(i,0).
1279 The number of points is 'np' ;
1280 integer yl,yh,yn,al,ah;
1281 yl:= 1; yh:= np; yn:= yh-yl+1; ah:= n; al:= 1;
1282
1283 begin real array ar(1:ah,1:ah), xm,r,sx(1:ah);
1284 real s,sum,ym,f1,wm,fx,fy,wi,sxj,aj;
1285 integer i,j,k;
1286
1287 sum:= ym:= s:= 0.0;
1288 for j:= 1 step 1 until ah do
1289 begin xm(j):= sx(j):= a(j):= r(j):= 0;
1290 for k:= 1 step 1 until ah do ar(j,k):= 0;
1291 end;
1292
1293 for i:= yl step 1 until yh do
1294 begin wi:= x(i,0);
1295 sum:= sum + wi; ym:= ym + wi*y(i);
1296 for j:= 1 step 1 until ah do xm(j):= xm(j) + wi*x(i,j);
1297 end;
1298
1299 if sum=0 then a(0):= missing
1300 else
1301 begin
1302 ym:= ym/sum; wm:= sum/yn;
1303 for j:= 1 step 1 until ah do xm(j):= xm(j)/sum;
1304
1305 for i:= yl step 1 until yh do
1306 begin wi:= x(i,0)/wm; fy:= y(i) - ym;
1307 s:= s + wi*fy**2;
1308 for j:= 1 step 1 until ah do
1309 begin fx:= x(i,j) - xm(j);
1310 sx(j):= sx(j) + wi*fx**2; r(j):= r(j) + wi*fx*fy;
1311 for k:= 1 step 1 until j do
1312 ar(j,k):= ar(j,k) + wi*fx*(x(i,k) - xm(k));
1313 end j;
1314 end i;
1315
1316 f1:= yn - 1; s:= sqrt(s/f1);
1317 for j:= 1 step 1 until ah do
1318 begin sxj:= sx(j):= sqrt(sx(j)/f1); r(j):= r(j)/(f1*sxj*s);
1319 for k:= 1 step 1 until j do
1320 begin ar(j,k):= ar(j,k)/(f1*sxj*sx(k));
1321 ar(k,j):= ar(j,k);
1322 end;
1323 end;
1324
1325 if syminv(ar) = 0 then a(0):= missing else
1326 begin comment: normal case; a(0):= ym;
1327 for j:= 1 step 1 until ah do
1328 begin for k:= 1 step 1 until ah do a(j):= a(j)+r(k)*ar(j,k);
1329 aj:= a(j):= a(j)*s/sx(j); a(0):= a(0) - aj*xm(j);
1330 end;
1331 end;
1332
1333 end;
1334 end;
1335
1336 end;
1337 end
1338 */