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 |
*/ |