2 * $Id: expfit.c,v 1.33 2005/08/29 19:39:11 lindahl Exp $
4 * This source code is part of
8 * GROningen MAchine for Chemical Simulations
11 * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
12 * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
13 * Copyright (c) 2001-2004, The GROMACS development team,
14 * check out http://www.gromacs.org for more information.
16 * This program is free software; you can redistribute it and/or
17 * modify it under the terms of the GNU General Public License
18 * as published by the Free Software Foundation; either version 2
19 * of the License, or (at your option) any later version.
21 * If you want to redistribute modifications, please consider that
22 * scientific software is very special. Version control is crucial -
23 * bugs must be traceable. We will be happy to consider code for
24 * inclusion in the official distribution, but derived work must not
25 * be called official GROMACS. Details are found in the README & COPYING
26 * files - if they are missing, get the official version at www.gromacs.org.
28 * To help us fund GROMACS development, we humbly ask that you cite
29 * the papers on the package - you can find them in the top README file.
31 * For more info, check our website at http://www.gromacs.org
34 * Green Red Orange Magenta Azure Cyan Skyblue
53 const int nfp_ffn
[effnNR
] = { 0, 1, 2, 3, 2, 5, 7, 9, 4, 3};
55 const char *s_ffn
[effnNR
+2] = { NULL
, "none", "exp", "aexp", "exp_exp", "vac",
56 "exp5", "exp7", "exp9","erffit", NULL
, NULL
};
57 /* We don't allow errest as a choice on the command line */
59 const char *longs_ffn
[effnNR
] = {
63 "y = a2 exp(-x/a1) + (1-a2) exp(-x/a3)",
64 "y = exp(-v) (cosh(wv) + 1/w sinh(wv)), v = x/(2 a1), w = sqrt(1 - a2)",
65 "y = a1 exp(-x/a2) + a3 exp(-x/a4) + a5",
66 "y = a1 exp(-x/a2) + a3 exp(-x/a4) + a5 exp(-x/a6) + a7",
67 "y = a1 exp(-x/a2) + a3 exp(-x/a4) + a5 exp(-x/a6) + a7 exp(-x/a8) + a9",
68 "y = 1/2*(a1+a2) - 1/2*(a1-a2)*erf( (x-a3) /a4^2)",
69 "y = a2*ee(a1,x) + (1-a2)*ee(a2,x)"
72 extern gmx_bool
mrqmin(real x
[],real y
[],real sig
[],int ndata
,real a
[],
73 int ma
,int lista
[],int mfit
,real
**covar
,real
**alpha
,
75 void (*funcs
)(real x
,real a
[],real
*y
,real dyda
[]),
78 extern gmx_bool
mrqmin_new(real x
[],real y
[],real sig
[],int ndata
,real a
[],
79 int ia
[],int ma
,real
**covar
,real
**alpha
,real
*chisq
,
80 void (*funcs
)(real
, real
[], real
*, real
[]),
83 static real
myexp(real x
,real A
,real tau
)
85 if ((A
== 0) || (tau
== 0))
90 static real
signum(real num
){
101 void erffit (real x
, real a
[], real
*y
, real dyda
[])
104 * y=(a1+a2)/2-(a1-a2)/2*erf((x-a3)/a4^2)
112 erfarg
=(x
-a
[3])/(a
[4]*a
[4]);
113 erfarg2
=erfarg
*erfarg
;
114 erfval
=gmx_erf(erfarg
)/2;
115 derf
=M_2_SQRTPI
*(a
[1]-a
[2])/2*exp(-erfarg2
)/(a
[4]*a
[4]);
117 *y
=(a
[1]+a
[2])/2-(a
[1]-a
[2])*erfval
;
121 dyda
[4]=2*derf
*erfarg
;
126 static void exp_one_parm(real x
,real a
[],real
*y
,real dyda
[])
138 dyda
[1] = x
*e1
/sqr(a
[1]);
141 static void exp_two_parm(real x
,real a
[],real
*y
,real dyda
[])
153 dyda
[1] = x
*a
[2]*e1
/sqr(a
[1]);
157 static void exp_3_parm(real x
,real a
[],real
*y
,real dyda
[])
161 * y = a2 exp(-x/a1) + (1-a2) exp(-x/a3)
169 *y
= a
[2]*e1
+ (1-a
[2])*e2
;
170 dyda
[1] = x
*a
[2]*e1
/sqr(a
[1]);
172 dyda
[3] = x
*(1-a
[2])*e2
/sqr(a
[3]);
175 static void exp_5_parm(real x
,real a
[],real
*y
,real dyda
[])
179 * y = a1 exp(-x/a2) + a3 exp(-x/a4) + a5
187 *y
= a
[1]*e1
+ a
[3]*e2
+ a
[5];
190 fprintf(debug
,"exp_5_parm called: x = %10.3f y = %10.3f\n"
191 "a = ( %8.3f %8.3f %8.3f %8.3f %8.3f)\n",
192 x
,*y
,a
[1],a
[2],a
[3],a
[4],a
[5]);
194 dyda
[2] = x
*e1
/sqr(a
[2]);
196 dyda
[4] = x
*e2
/sqr(a
[4]);
200 static void exp_7_parm(real x
,real a
[],real
*y
,real dyda
[])
204 * y = a1 exp(-x/a2) + a3 exp(-x/a4) + a5 exp(-x/a6) + a7
213 *y
= a
[1]*e1
+ a
[3]*e2
+ a
[5]*e3
+ a
[7];
216 dyda
[2] = x
*e1
/sqr(a
[2]);
218 dyda
[4] = x
*e2
/sqr(a
[4]);
220 dyda
[6] = x
*e3
/sqr(a
[6]);
224 static void exp_9_parm(real x
,real a
[],real
*y
,real dyda
[])
228 * y = a1 exp(-x/a2) + a3 exp(-x/a4) + a5 exp(-x/a6) + a7
238 *y
= a
[1]*e1
+ a
[3]*e2
+ a
[5]*e3
+ a
[7]*e4
+ a
[9];
241 dyda
[2] = x
*e1
/sqr(a
[2]);
243 dyda
[4] = x
*e2
/sqr(a
[4]);
245 dyda
[6] = x
*e3
/sqr(a
[6]);
247 dyda
[8] = x
*e4
/sqr(a
[8]);
251 static void vac_2_parm(real x
,real a
[],real
*y
,real dyda
[])
255 * y = 1/2 (1 - 1/w) exp(-(1+w)v) + 1/2 (1 + 1/w) exp(-(1-w)v)
257 * = exp(-v) (cosh(wv) + 1/w sinh(wv))
262 * For tranverse current autocorrelation functions:
264 * a2 = 4 tau (eta/rho) k^2
268 double v
,det
,omega
,omega2
,em
,ec
,es
;
275 omega
= sqrt(omega2
);
277 ec
= em
*0.5*(exp(omega
*v
)+exp(-omega
*v
));
278 es
= em
*0.5*(exp(omega
*v
)-exp(-omega
*v
))/omega
;
280 ec
= em
*cos(omega
*v
);
281 es
= em
*sin(omega
*v
)/omega
;
284 dyda
[2] = (v
/det
*ec
+(v
-1/det
)*es
)/(-2.0);
285 dyda
[1] = (1-det
)*v
/a
[1]*es
;
288 dyda
[2] = -v
*v
*em
*(0.5+v
/6);
289 dyda
[1] = v
*v
/a
[1]*em
;
293 static void errest_3_parm(real x
,real a
[],real
*y
,real dyda
[])
298 e1
= exp(-x
/a
[1]) - 1;
302 e2
= exp(-x
/a
[3]) - 1;
307 v1
= 2*a
[1]*(e1
*a
[1]/x
+ 1);
308 v2
= 2*a
[3]*(e2
*a
[3]/x
+ 1);
309 *y
= a
[2]*v1
+ (1-a
[2])*v2
;
310 dyda
[1] = 2* a
[2] *(v1
/a
[1] + e1
);
311 dyda
[3] = 2*(1 - a
[2])*(v2
/a
[3] + e2
);
321 typedef void (*myfitfn
)(real x
,real a
[],real
*y
,real dyda
[]);
322 myfitfn mfitfn
[effnNR
] = {
323 exp_one_parm
, exp_one_parm
, exp_two_parm
, exp_3_parm
, vac_2_parm
,
324 exp_5_parm
, exp_7_parm
, exp_9_parm
, erffit
, errest_3_parm
327 real
fit_function(int eFitFn
,real
*parm
,real x
)
329 static real y
,dum
[8];
331 mfitfn
[eFitFn
](x
,parm
-1,&y
,dum
);
336 /* lmfit_exp supports up to 3 parameter fitting of exponential functions */
337 static gmx_bool
lmfit_exp(int nfit
,real x
[],real y
[],real dy
[],real ftol
,
338 real parm
[],real dparm
[],gmx_bool bVerbose
,
341 real chisq
,ochisq
,alamda
;
342 real
*a
,**covar
,**alpha
,*dum
;
344 int i
,j
,ma
,mfit
,*lista
,*ia
;
346 if ((eFitFn
< 0) || (eFitFn
>= effnNR
))
347 gmx_fatal(FARGS
,"fitfn = %d, should be in 0..%d (%s,%d)",
348 effnNR
-1,eFitFn
,__FILE__
,__LINE__
);
350 ma
=mfit
=nfp_ffn
[eFitFn
]; /* number of parameters to fit */
357 for(i
=1; (i
<ma
+1); i
++) {
359 ia
[i
] = 1; /* fixed bug B.S.S 19/11 */
365 fprintf(stderr
,"Will keep parameters fixed during fit procedure: %d\n",
372 fprintf(debug
,"%d parameter fit\n",mfit
);
375 alamda
= -1; /* Starting value */
377 for(i
=0; (i
<mfit
); i
++)
382 fprintf(stderr
,"%4s %10s %10s %10s %10s %10s %10s\n",
383 "Step","chi^2","Lambda","A1","A2","A3","A4");
386 /* mrqmin(x-1,y-1,dy-1,nfit,a,ma,lista,mfit,covar,alpha,
387 * &chisq,expfn[mfit-1],&alamda)
389 if (!mrqmin_new(x
-1,y
-1,dy
-1,nfit
,a
,ia
,ma
,covar
,alpha
,&chisq
,
390 mfitfn
[eFitFn
],&alamda
))
394 fprintf(stderr
,"%4d %10.5e %10.5e %10.5e",
395 j
,chisq
,alamda
,a
[1]);
397 fprintf(stderr
," %10.5e",a
[2]);
399 fprintf(stderr
," %10.5e",a
[3]);
401 fprintf(stderr
," %10.5e",a
[4]);
402 fprintf(stderr
,"\n");
405 bCont
= ((fabs(ochisq
- chisq
) > fabs(ftol
*chisq
)) ||
406 ((ochisq
== chisq
)));
407 } while (bCont
&& (alamda
!= 0.0) && (j
< 50));
409 fprintf(stderr
,"\n");
411 /* Now get the covariance matrix out */
414 /* mrqmin(x-1,y-1,dy-1,nfit,a,ma,lista,mfit,covar,alpha,
415 * &chisq,expfn[mfit-1],&alamda)
417 if ( !mrqmin_new(x
-1,y
-1,dy
-1,nfit
,a
,ia
,ma
,covar
,alpha
,&chisq
,
418 mfitfn
[eFitFn
],&alamda
))
421 for(j
=0; (j
<mfit
); j
++) {
423 dparm
[j
] = covar
[j
+1][j
+1];
426 for(i
=0; (i
<ma
+1); i
++) {
439 real
do_lmfit(int ndata
,real c1
[],real sig
[],real dt
,real x0
[],
440 real begintimefit
,real endtimefit
,const output_env_t oenv
,
441 gmx_bool bVerbose
, int eFitFn
,real fitparms
[],int fix
)
446 int i
,j
,nparm
,nfitpnts
;
452 nparm
= nfp_ffn
[eFitFn
];
454 fprintf(debug
,"There are %d points to fit %d vars!\n",ndata
,nparm
);
455 fprintf(debug
,"Fit to function %d from %g through %g, dt=%g\n",
456 eFitFn
,begintimefit
,endtimefit
,dt
);
464 for(i
=0; i
<ndata
; i
++) {
465 ttt
= x0
? x0
[i
] : dt
*i
;
466 if (ttt
>=begintimefit
&& ttt
<=endtimefit
) {
470 /* mrqmin does not like sig to be zero */
476 fprintf(debug
,"j= %d, i= %d, x= %g, y= %g, dy= %g\n",
477 j
,i
,x
[j
],y
[j
],dy
[j
]);
483 if (nfitpnts
< nparm
)
484 fprintf(stderr
,"Not enough data points for fitting!\n");
489 for(i
=0; (i
< nparm
); i
++)
492 if (!lmfit_exp(nfitpnts
,x
,y
,dy
,ftol
,parm
,dparm
,bVerbose
,eFitFn
,fix
))
493 fprintf(stderr
,"Fit failed!\n");
494 else if (nparm
<= 3) {
495 /* Compute the integral from begintimefit */
497 integral
=(parm
[0]*myexp(begintimefit
,parm
[1], parm
[0]) +
498 parm
[2]*myexp(begintimefit
,1-parm
[1],parm
[2]));
500 integral
=parm
[0]*myexp(begintimefit
,parm
[1], parm
[0]);
502 integral
=parm
[0]*myexp(begintimefit
,1, parm
[0]);
504 gmx_fatal(FARGS
,"nparm = %d in file %s, line %d",
505 nparm
,__FILE__
,__LINE__
);
507 /* Generate THE output */
509 fprintf(stderr
,"FIT: # points used in fit is: %d\n",nfitpnts
);
510 fprintf(stderr
,"FIT: %21s%21s%21s\n",
511 "parm0 ","parm1 (ps) ","parm2 (ps) ");
512 fprintf(stderr
,"FIT: ------------------------------------------------------------\n");
513 fprintf(stderr
,"FIT: %8.3g +/- %8.3g%9.4g +/- %8.3g%8.3g +/- %8.3g\n",
514 parm
[0],dparm
[0],parm
[1],dparm
[1],parm
[2],dparm
[2]);
515 fprintf(stderr
,"FIT: Integral (calc with fitted function) from %g ps to inf. is: %g\n",
516 begintimefit
,integral
);
518 sprintf(buf
,"test%d.xvg",nfitpnts
);
519 fp
= xvgropen(buf
,"C(t) + Fit to C(t)","Time (ps)","C(t)",oenv
);
520 fprintf(fp
,"# parm0 = %g, parm1 = %g, parm2 = %g\n",
521 parm
[0],parm
[1],parm
[2]);
522 for(j
=0; (j
<nfitpnts
); j
++) {
523 ttt
= x0
? x0
[j
] : dt
*j
;
524 fprintf(fp
,"%10.5e %10.5e %10.5e\n",
525 ttt
,c1
[j
],fit_function(eFitFn
,parm
,ttt
));
530 for(i
=0;(i
<nparm
);i
++)
531 fitparms
[i
] = parm
[i
];
543 void do_expfit(int ndata
,real c1
[],real dt
,real begintimefit
,real endtimefit
)
547 real aa
,bb
,saa
,sbb
,A
,tau
,dA
,dtau
;
549 fprintf(stderr
,"Will fit data from %g (ps) to %g (ps).\n",
550 begintimefit
,endtimefit
);
552 snew(x
,ndata
); /* allocate the maximum necessary space */
557 for(i
=0; (i
<ndata
); i
++) {
558 if ( (dt
*i
>= begintimefit
) && (dt
*i
<= endtimefit
) ) {
562 fprintf(stderr
,"n= %d, i= %d, x= %g, y= %g\n",n
,i
,x
[n
],y
[n
]);
566 fprintf(stderr
,"# of data points used in the fit is : %d\n\n",n
);
567 expfit(n
,x
,y
,Dy
,&aa
,&saa
,&bb
,&sbb
);
573 fprintf(stderr
,"Fitted to y=exp(a+bx):\n");
574 fprintf(stderr
,"a = %10.5f\t b = %10.5f",aa
,bb
);
575 fprintf(stderr
,"\n");
576 fprintf(stderr
,"Fitted to y=Aexp(-x/tau):\n");
577 fprintf(stderr
,"A = %10.5f\t tau = %10.5f\n",A
,tau
);
578 fprintf(stderr
,"dA = %10.5f\t dtau = %10.5f\n",dA
,dtau
);
582 void expfit(int n
, real
*x
, real
*y
, real
*Dy
, real
*a
, real
*sa
,
585 real
*w
,*ly
,A
,SA
,B
,SB
;
587 real sum
,xbar
,ybar
,Sxx
,Sxy
,wr2
,chi2
,gamma
,Db
;
594 #define sqr(x) ((x)*(x))
600 /* Calculate weights and values of ln(y). */
602 w
[i
]=sqr(y
[i
]/Dy
[i
]);
606 /* The weighted averages of x and y: xbar and ybar. */
618 /* The centered product sums Sxx and Sxy, and hence A and B. */
622 Sxx
+=w
[i
]*sqr(x
[i
]-xbar
);
623 Sxy
+=w
[i
]*(x
[i
]-xbar
)*(ly
[i
]-ybar
);
628 /* Chi-squared (chi2) and gamma. */
632 wr2
=w
[i
]*sqr(ly
[i
]-A
-B
*x
[i
]);
634 gamma
+=wr2
*(x
[i
]-xbar
);
637 /* Refined values of A and B. Also SA and SB. */
640 A
-=ONEP5
*chi2
/sum
-xbar
*Db
;
641 SB
=sqrt((chi2
/(n
-2))/Sxx
);
642 SA
=SB
*sqrt(Sxx
/sum
+sqr(xbar
));