Linuxpops  3.01.04
Spectral Anaysis Package for Single Dish Data
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
gaussfit.c
Go to the documentation of this file.
1 #include <stdio.h>
2 #include <strings.h>
3 #include <malloc.h>
4 #include <math.h>
5 
6 #include "global.h"
7 #include "linuxlib_proto.h"
8 
9 #define NPARM 100
10 #define ITMAX 100
11 #define EPS (3.0e-7)
12 #define CONV_CRIT (0.001)
13 
14 #define SWAP(a,b) {double temp=(a);(a)=(b);(b)=temp;}
15 
18 
19 int nrerror(error_text)
20 char *error_text;
21 {
22  printf("%s\n", error_text);
23 
24  return(0);
25 }
26 
27 
28 double *vector(nl, nh)
29 int nl, nh;
30 {
31  double *v;
32 
33  v = (double *)malloc((unsigned) (nh-nl+1) * sizeof(double));
34 
35  if(!v)
36  {
37  nrerror("allocation failure in vector()");
38  }
39 
40  return(v-nl);
41 }
42 
43 
44 static int *ivector(nl, nh)
45 int nl, nh;
46 {
47  int *v;
48 
49  v = (int *)malloc((unsigned) (nh-nl+1) * sizeof(int));
50 
51  if(!v)
52  {
53  nrerror("allocation failure in ivector()");
54  }
55 
56  return(v-nl);
57 }
58 
59 
60 double **matrix(nrl, nrh, ncl, nch)
61 int nrl, nrh, ncl, nch;
62 {
63  int i;
64  double **m;
65 
66  m = (double **)malloc((unsigned) (nrh-nrl+1) * sizeof(double*));
67 
68  if(!m)
69  {
70  nrerror("allocation failure 1 in matrix()");
71  }
72 
73  m -= nrl;
74 
75  for(i=nrl;i<=nrh;i++)
76  {
77  m[i] = (double *) malloc((unsigned) (nch-ncl+1) * sizeof(double));
78 
79  if(!m[i])
80  {
81  nrerror("allocation failure 2 in matrix()");
82  }
83 
84  m[i] -= ncl;
85  }
86 
87  return(m);
88 }
89 
90 
91 int free_vector(v, nl)
92 double *v;
93 int nl;
94 {
95  free((char *)(v+nl));
96 
97  return(0);
98 }
99 
100 
101 int free_ivector(v, nl)
102 int *v, nl;
103 {
104  free((char *)(v+nl));
105 
106  return(0);
107 }
108 
109 
110 
111 int free_matrix(m, nrl, nrh, ncl)
112 double **m;
113 int nrl, nrh, ncl;
114 {
115  int i;
116 
117  for(i=nrh;i>=nrl;i--)
118  {
119  free((char *)(m[i]+ncl));
120  }
121 
122  free((char *)(m+nrl));
123 
124  return(0);
125 }
126 
127 
128 
129 int gaussj(a, n, b, m)
130 double a[NPARM+1][NPARM+1], **b;
131 int n, m;
132 {
133  int *indxc, *indxr, *ipiv;
134  int i, icol, irow, j, k, l, ll;
135  double big, dum, pivinv;
136 
137  indxc = ivector(1, n);
138  indxr = ivector(1, n);
139  ipiv = ivector(1, n);
140 
141  for(j=1;j<=n;j++)
142  {
143  ipiv[j] = 0;
144  }
145 
146  for(i=1;i<=n;i++)
147  {
148  big = 0.0;
149 
150  for(j=1;j<=n;j++)
151  {
152  if(ipiv[j] != 1)
153  {
154  for(k=1;k<=n;k++)
155  {
156  if(ipiv[k] == 0)
157  {
158  if(fabs(a[j][k]) >= big)
159  {
160  big = fabs(a[j][k]);
161  irow = j;
162  icol = k;
163  }
164  }
165  else
166  if(ipiv[k] > 1)
167  {
168  nrerror("GAUSSJ: Singular Matrix-1");
169  }
170  }
171  }
172  }
173 
174  ++(ipiv[icol]);
175 
176  if(irow != icol)
177  {
178  for(l=1;l<=n;l++)
179  {
180  SWAP(a[irow][l], a[icol][l])
181  }
182  for(l=1;l<=m;l++)
183  {
184  SWAP(b[irow][l], b[icol][l])
185  }
186  }
187 
188  indxr[i] = irow;
189  indxc[i] = icol;
190 
191  if(a[icol][icol] == 0.0)
192  {
193  nrerror("GAUSSJ: Singular Matrix-2");
194  }
195 
196  pivinv = 1.0 / a[icol][icol];
197  a[icol][icol] = 1.0;
198 
199  for(l=1;l<=n;l++)
200  {
201  a[icol][l] *= pivinv;
202  }
203  for(l=1;l<=m;l++)
204  {
205  b[icol][l] *= pivinv;
206  }
207  for(ll=1;ll<=n;ll++)
208  {
209  if(ll != icol)
210  {
211  dum = a[ll][icol];
212  a[ll][icol] = 0.0;
213 
214  for(l=1;l<=n;l++)
215  {
216  a[ll][l] -= a[icol][l] * dum;
217  }
218  for(l=1;l<=m;l++)
219  {
220  b[ll][l] -= b[icol][l] * dum;
221  }
222  }
223  }
224  }
225 
226  for(l=n;l>=1;l--)
227  {
228  if(indxr[l] != indxc[l])
229  {
230  for(k=1;k<=n;k++)
231  {
232  SWAP(a[k][indxr[l]], a[k][indxc[l]]);
233  }
234  }
235  }
236 
237  free_ivector(ipiv, 1);
238  free_ivector(indxr, 1);
239  free_ivector(indxc, 1);
240 
241  return(0);
242 }
243 
244 #undef SWAP
245 
246 
247 int mrqmin(x,y,sig,ndata,a, ma, lista, mfit, covar, alpha, chisq, funcs, alamda)
248 double x[], y[], sig[], a[],
249  covar[NPARM+1][NPARM+1],
250  alpha[NPARM+1][NPARM+1],
251  *chisq, *alamda;
252 int ndata, ma, lista[], mfit;
253 void (*funcs)(double, double *, double *, double *);
254 {
255  int k, kk, j, ihit;
256  static double *da, *atry, **oneda, *beta, ochisq;
257 
258  if(*alamda < 0.0)
259  {
260  oneda = matrix(1, mfit, 1, 1);
261  atry = vector(1, ma);
262  da = vector(1, ma);
263  beta = vector(1, ma);
264  kk = mfit + 1;
265 
266  for(j=1;j<=ma;j++)
267  {
268  ihit = 0;
269 
270  for(k=1;k<=mfit;k++)
271  {
272  if(lista[k] == j)
273  {
274  ihit++;
275  }
276  }
277 
278  if(ihit == 0)
279  {
280  lista[kk++] = j;
281  }
282  else
283  if(ihit > 1)
284  {
285  nrerror("Bad LISTA permutation in MRQMIN-1");
286  }
287  }
288 
289  if(kk != ma+1)
290  {
291  nrerror("Bad LISTA permutation in MRQMIN-2");
292  }
293 
294  *alamda = CONV_CRIT;
295 
296  mrqcof(x, y, sig, ndata, a, ma, lista, mfit, alpha, beta, chisq, funcs);
297 
298  ochisq = (*chisq);
299  }
300 
301  for(j=1;j<=mfit;j++)
302  {
303  for(k=1;k<=mfit;k++)
304  {
305  covar[j][k] = alpha[j][k];
306  }
307 
308  covar[j][j] = alpha[j][j] * (1.0 + (*alamda));
309  oneda[j][1] = beta[j];
310  }
311 
312  gaussj(covar, mfit, oneda, 1);
313 
314  for(j=1;j<=mfit;j++)
315  {
316  da[j] = oneda[j][1];
317  }
318 
319  if(*alamda == 0.0)
320  {
321  covsrt(covar, ma, lista, mfit);
322  free_vector(beta, 1);
323  free_vector(da, 1);
324  free_vector(atry, 1);
325  free_matrix(oneda, 1, mfit, 1);
326 
327  return(0);
328  }
329 
330  for(j=1;j<=ma;j++)
331  {
332  atry[j]=a[j];
333  }
334 
335  for(j=1;j<=mfit;j++)
336  {
337  atry[lista[j]] = a[lista[j]] + da[j];
338  }
339 
340  mrqcof( x, y, sig, ndata, atry, ma, lista, mfit, covar, da, chisq, funcs);
341 
342  if(*chisq < ochisq)
343  {
344  *alamda *= 0.1;
345  ochisq = (*chisq);
346 
347  for(j=1;j<=mfit;j++)
348  {
349  for(k=1;k<=mfit;k++)
350  {
351  alpha[j][k] = covar[j][k];
352  }
353 
354  beta[j] = da[j];
355  a[lista[j]] = atry[lista[j]];
356  }
357  }
358  else
359  {
360  *alamda *= 10.0;
361  *chisq = ochisq;
362  }
363 
364  return(0);
365 }
366 
367 
368 int mrqcof(x, y, sig, ndata, a, ma, lista, mfit, alpha, beta, chisq, funcs)
369 double x[], y[], sig[], a[],
370  alpha[NPARM+1][NPARM+1],
371  beta[], *chisq;
372 int ndata, ma, lista[], mfit;
373 void (*funcs)(double, double *, double *, double *);
374 {
375  int k, j, i;
376  double ymod, wt, sig2i, dy, *dyda;
377 
378  dyda = vector(1, ma);
379 
380  for(j=1;j<=mfit;j++)
381  {
382  for(k=1;k<=j;k++)
383  {
384  alpha[j][k] = 0.0;
385  }
386 
387  beta[j] = 0.0;
388  }
389 
390  *chisq = 0.0;
391 
392 /* Old way: funcs(x[i],a,&ymod,dyda,ma); */
393 
394  for(i=1;i<=ndata;i++)
395  {
396  funcs(x[i], a, &ymod, dyda);
397 
398  sig2i = 1.0 / (sig[i] * sig[i]);
399  dy = y[i] - ymod;
400 
401  for(j=1;j<=mfit;j++)
402  {
403  wt=dyda[lista[j]]*sig2i;
404 
405  for(k=1;k<=j;k++)
406  {
407  alpha[j][k] += wt*dyda[lista[k]];
408  }
409 
410  beta[j] += dy*wt;
411  }
412 
413  (*chisq) += dy * dy * sig2i;
414  }
415 
416  for(j=2;j<=mfit;j++)
417  {
418  for(k=1;k<=j-1;k++)
419  {
420  alpha[k][j] = alpha[j][k];
421  }
422  }
423 
424  free_vector(dyda, 1);
425 
426  return(0);
427 }
428 
429 
430 
431 int covsrt(covar, ma,lista, mfit)
432 double covar[NPARM+1][NPARM+1];
433 int ma, lista[], mfit;
434 {
435  int i, j;
436  double swap;
437 
438  for(j=1;j<ma;j++)
439  {
440  for(i=j+1;i<=ma;i++)
441  {
442  covar[i][j] = 0.0;
443  }
444  }
445 
446  for(i=1;i<mfit;i++)
447  {
448  for(j=i+1;j<=mfit;j++)
449  {
450  if(lista[j] > lista[i])
451  {
452  covar[lista[j]][lista[i]] = covar[i][j];
453  }
454  else
455  {
456  covar[lista[i]][lista[j]] = covar[i][j];
457  }
458  }
459  }
460 
461  swap = covar[1][1];
462 
463  for(j=1;j<=ma;j++)
464  {
465  covar[1][j] = covar[j][j];
466  covar[j][j] = 0.0;
467  }
468 
469  covar[lista[1]][lista[1]] = swap;
470 
471  for(j=2;j<=mfit;j++)
472  {
473  covar[lista[j]][lista[j]] = covar[1][j];
474  }
475 
476  for(j=2;j<=ma;j++)
477  {
478  for(i=1;i<=j-1;i++)
479  {
480  covar[i][j] = covar[j][i];
481  }
482  }
483 
484  return(0);
485 }
486 
487 
488 double gammq(a, x)
489 double a, x;
490 {
491  double gamser, gammcf, gln;
492 
493  if(x < 0.0 || a <= 0.0)
494  {
495  nrerror("Invalid arguments in routine GAMMQ");
496 
497  return(0.0);
498  }
499 
500  if(x < (a + 1.0))
501  {
502  gser(&gamser, a, x, &gln);
503 
504  return(1.0 - gamser);
505  }
506  else
507  {
508  gcf(&gammcf, a, x, &gln);
509 
510  return(gammcf);
511  }
512 
513  return(0.0);
514 }
515 
516 
517 
518 
519 int gser(gamser,a, x, gln)
520 double *gamser, a, x, *gln;
521 {
522  int n;
523  double sum, del, ap;
524 
525  *gln = gammln(a);
526 
527  if(x <= 0.0)
528  {
529  if(x < 0.0)
530  {
531  nrerror("x less than 0 in routine GSER");
532  }
533 
534  *gamser = 0.0;
535 
536  return(0);
537  }
538  else
539  {
540  ap = a;
541  del = sum = 1.0 / a;
542 
543  for(n=1;n<=ITMAX;n++)
544  {
545  ap += 1.0;
546  del *= x / ap;
547  sum += del;
548 
549  if(fabs(del) < fabs(sum) * EPS)
550  {
551  *gamser = sum * exp(-x + a * log(x) - (*gln));
552 
553  return(0);
554  }
555  }
556 
557  nrerror("'a' too large, ITMAX too small in routine GSER");
558 
559  return(1);
560  }
561 
562  return(0);
563 }
564 
565 
566 int gcf(gammcf, a, x, gln)
567 double *gammcf, a, x, *gln;
568 {
569  int n;
570  double gold = 0.0, g, fac = 1.0, b1 = 1.0;
571  double b0 = 0.0, anf, ana, an, a1, a0 = 1.0;
572 
573  *gln = gammln(a);
574  a1 = x;
575 
576  for(n=1;n<=ITMAX;n++)
577  {
578  an = (double) n;
579  ana = an - a;
580  a0 = (a1 + a0 * ana) * fac;
581  b0 = (b1 + b0 * ana) * fac;
582  anf = an * fac;
583  a1 = x * a0 + anf * a1;
584  b1 = x * b0 + anf * b1;
585 
586  if(a1)
587  {
588  fac = 1.0 / a1;
589  g = b1 * fac;
590 
591  if(fabs((g - gold) / g) < EPS)
592  {
593  *gammcf = exp(-x + a * log(x) - (*gln)) * g;
594 
595  return(0);
596  }
597  gold = g;
598  }
599  }
600 
601  nrerror("a too large, ITMAX too small in routine GCF");
602 
603  return(1);
604 }
605 
606 
607 
608 double gammln(xx)
609 double xx;
610 {
611  double x, tmp, ser;
612  static double cof[6] = {76.18009173, -86.50532033, 24.01409822,
613  -1.231739516, 0.120858003e-2, -0.536382e-5 };
614  int j;
615 
616  x = xx - 1.0;
617  tmp = x + 5.5;
618  tmp -= (x + 0.5) * log(tmp);
619  ser = 1.0;
620 
621  for(j=0;j<=5;j++)
622  {
623  x += 1.0;
624  ser += cof[j]/x;
625  }
626 
627  return(-tmp + log(2.50662827465 * ser));
628 }
629 
630 
631 
632 /*
633 Tom:
634  What follows is a pitiful attempt at C programming. It has
635 little chance of running, although I hope it demonstrates the
636 logic of the fitting algorithm. You might try to compile it and
637 clean up the gross syntax errors, then I'll help you get it
638 running next Monday. I was particularly unsure about how to pass
639 multiple return parameters out of functions. I know you have to
640 do it with pointers, but that's all Greek to me.
641 
642  To run the function "gauss_fit", you'll need to pass it the x
643 and y data arrays, and a first guess at the peak a[0], the center
644 position a[1], and the FWHM a[NPARM+1]. The function will (should)
645 return new values of 'a'.
646 
647  It would be good to have a graphical display, at least during
648 the debugging stage, that shows the input data and the fitted
649 Gaussian. You can use the function 'fgauss' to generate the
650 computed gaussian.
651 
652  Good luck. You'll need it.
653 
654  Phil
655 
657 
658 */
659 
660 
661 /*
662  * Evaluate the Gaussian function y and its first partial
663  * derivatives dyda[] at a given x value, with supplied
664  * parameters a[].
665  */
666 void fgauss(x, a, y, dyda)
667 double x, *a, *y, *dyda;
668 {
669  double arg1, arg2, ex, fac;
670 
671  arg1 = -4. * log(2.0);
672  arg2 = (x - a[2]) / a[3];
673  ex = exp(arg1 * arg2 * arg2);
674  fac = a[1] * ex * arg1 * 2.0 * arg2;
675 
676  *y = a[1] * ex;
677 
678  dyda[1] = ex;
679  dyda[2] = -fac / a[3];
680  dyda[3] = -fac * arg2 / a[3];
681 }
682 
683 
684 /* Control the iterations of mrqmin. x and y are the input data array,
685  * sig is the array of standard deviations (if any), npts are the number
686  * of data points, and 'a' is the array of fitted parameters. When
687  * gauss_fit is first called, 'a' must contain the initial guesses for the
688  * parameters.
689  */
690 int gauss_fit(x, y, sig, npts, a, verbose)
691 double *x, *y, *sig, *a;
692 int npts, verbose;
693 {
694  double alamda= -1.0, chisq=0.0, chisq1=0.0, g, cvtest,
695  dyda[NPARM+1], resid[32768],
696  alpha[NPARM+1][NPARM+1],
697  covar[NPARM+1][NPARM+1];
698  int ma=3, mfit=3, converged =0, i, j=1, niter=50, lista[NPARM+1], ibase;
699 
700  double sumsq;
701  double height, center, hwidth;
702  double constant = 2.35482004504;
703  double diff, tsq;
704 
705  bzero((char *)&dyda[0], sizeof(dyda));
706  bzero((char *)&resid[0], sizeof(resid));
707  bzero((char *)&alpha[0], sizeof(alpha));
708  bzero((char *)&covar[0][0], sizeof(covar));
709  bzero((char *)&lista[0], sizeof(lista));
710 
711  lista[1] = 1;
712  lista[2] = 2;
713  lista[3] = 3;
714 
715  /* Calculate the CHI-SQUARED based on the initial-guess coefficients: */
716  for(i=1;i<=npts;++i)
717  {
718  fgauss(x[i], a, &g, dyda);
719  resid[i] = y[i] - g;
720  chisq = chisq + resid[i] * resid[i];
721  }
722 
723  if(verbose)
724  {
725  st_report("Chisq = %e", chisq);
726  }
727  /* Start the main iteration loop: */
728  while((j <= niter) && (converged == 0))
729  {
730  if(verbose)
731  {
732  st_report("(1): J = %2d: Calling mrqmin: alpha = %e, chisq1 = %e", j, alpha[j][j], chisq1);
733  }
734 
735  mrqmin(x, y, sig, npts, a, ma, lista, mfit, covar, alpha, &chisq1, fgauss, &alamda);
736 
737  if(verbose)
738  {
739  for(i=1;i<4;i++)
740  {
741  st_report("(1): COVAR[%d] = %e, %e, %e", i, covar[i][1], covar[i][2], covar[i][3]);
742  }
743 
744  st_report("(1): J = %2d: Testing chisq1 < chisq: %e < %e", j, chisq1, chisq);
745  }
746 
747  if((chisq1 < chisq) || (chisq1 < CONV_CRIT))
748  {
749  cvtest = fabs( (chisq1 - chisq) / chisq );
750 
751  if(verbose)
752  {
753  st_report("(1): J = %2d: cvtest = %e vs. %e", j, cvtest, CONV_CRIT);
754  }
755 
756  if(cvtest <= CONV_CRIT)
757  {
758  if(verbose)
759  {
760  st_report("Converged after %d interations", j);
761  }
762 
763  converged = 1;
764  }
765 
766  chisq = chisq1;
767  }
768 
769  j++;
770  } /* If converged, call mrqmin with alamda = 0
771  to get covariance and curvature matrices. */
772  if(converged)
773  {
774  alamda = 0.0;
775 
776  if(verbose)
777  {
778  st_report("(2): J = %2d: Calling mrqmin: alpha = %e, chisq1 = %e", j, alpha[j][j], chisq1);
779  }
780 
781  mrqmin(x, y, sig, npts, a, ma, lista, mfit, covar, alpha, &chisq1, fgauss, &alamda);
782 
783  if(verbose)
784  {
785  for(i=1;i<4;i++)
786  {
787  st_report("(2): COVAR[%d] = %e, %e, %e", i, covar[i][1], covar[i][2], covar[i][3]);
788  }
789  }
790 
791  /* Compute how many actuall channels have data */
792  ibase = 1;
793  tsq = 0.0;
794  for(j=0;j<npts;j++)
795  {
796  fgauss(x[j], a, &g, dyda);
797 
798  if(g > 0.0)
799  {
800  ibase++;
801 
802  diff = y[j]-g;
803 
804  tsq += (diff*diff);
805  }
806  }
807 
808  tsq = sqrt(tsq);
809 
810  sumsq = sqrt(chisq1 / (double)(ibase-mfit));
811 
812  sumsq /= 3.0;
813 
814  height = a[1];
815  center = a[2];
816  hwidth = a[3] * constant;
817 
818  hghterr = height * sqrt( covar[1][1] / (a[1]*a[1])) * sumsq;
819  cnterr = sqrt( covar[2][2]) * sumsq;
820  hwerr = hwidth * sqrt( covar[3][3] / (a[3]*a[3])) * sumsq;
821 
822  if(verbose)
823  {
824  hghtdiff = hghterr - 8.24424e-3;
825  cntdiff = cnterr - 0.1169328;
826  hwdiff = hwerr - 0.2863190;
827 
828  st_report("npts = %d", npts);
829  st_report("ibase = %d", ibase);
830  st_report("constant = %f", constant);
831  st_report("chisq1 = %f", chisq1);
832  st_report("sumsq = %f", sumsq);
833  st_report("tsq = %f", tsq);
834  st_report("height = %f", height);
835  st_report("center = %f", center);
836  st_report("hwidth = %f", hwidth);
837  st_report("hghterr = %f", hghterr);
838  st_report("cnterr = %f", cnterr);
839  st_report("hwerr = %f", hwerr);
840  st_report("hghtdiff = %f", hghtdiff);
841  st_report("cntdiff = %f", cntdiff);
842  st_report("hwdiff = %f", hwdiff);
843  }
844 
845  return(1);
846  }
847 
848  return(0);
849 }
850 
851 /*
852  height = a[j] * a[1];
853  center = a[j+1] + a[2];
854  hwidth = a[j+2] * a[3] * constant;
855 
856  hghterr = height * sqrt( covar[1][1]/(a[1]*a[1]) + covar[j][j]/(a[j]*a[j]) + 2.0 * covar[1][j] / (a[1]*a[j])) * sumsq;
857  cnterr = center * sqrt( covar[2][2] + covar[j+1][j+1] + 2.0 * covar[2][j+1]) * sumsq;
858  hwerr = hwidth * sqrt( covar[3][3] /(a[3]*a[3]) + covar[j+2][j+2]/(a[j+2]*a[j+2]) + 2.0 * covar[3][j+2]/(a[3]*a[j+2])) * sumsq;
859  */
int xx()
Definition: linuxpops.c:605
int nrerror()
double hghtdiff
Definition: gaussfit.c:17
void fgauss()
int gcf()
int gauss_fit()
int mrqmin()
int gaussj()
int free_vector()
int * ivector(int nl, int nh)
Definition: gaussfit.c:39
double gammln()
int mrqcof()
#define EPS
Definition: gaussfit.c:11
double sum
Definition: beam.h:5
#define dy(i)
#define NPARM
Definition: gaussfit.c:9
double * vector()
int free_ivector()
#define SWAP(a, b)
Definition: gaussfit.c:14
int gser()
double hwdiff
Definition: gaussfit.c:17
int covsrt()
int free_matrix()
double cnterr
Definition: gaussfit.c:16
void st_report()
double hghterr
Definition: gaussfit.c:16
double ** matrix()
double gammq()
#define CONV_CRIT
Definition: gaussfit.c:12
#define ITMAX
Definition: gaussfit.c:10
#define m(i)
double hwerr
Definition: gaussfit.c:16
double cntdiff
Definition: gaussfit.c:17