2 * This file is part of the GROMACS molecular simulation package.
4 * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
5 * Copyright (c) 2001-2004, The GROMACS development team,
6 * check out http://www.gromacs.org for more information.
7 * Copyright (c) 2012, by the GROMACS development team, led by
8 * David van der Spoel, Berk Hess, Erik Lindahl, and including many
9 * others, as listed in the AUTHORS file in the top-level source
10 * directory and at http://www.gromacs.org.
12 * GROMACS is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public License
14 * as published by the Free Software Foundation; either version 2.1
15 * of the License, or (at your option) any later version.
17 * GROMACS is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with GROMACS; if not, see
24 * http://www.gnu.org/licenses, or write to the Free Software Foundation,
25 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
27 * If you want to redistribute modifications to GROMACS, please
28 * consider that scientific software is very special. Version
29 * control is crucial - bugs must be traceable. We will be happy to
30 * consider code for inclusion in the official distribution, but
31 * derived work must not be called official GROMACS. Details are found
32 * in the README & COPYING files - if they are missing, get the
33 * official version at http://www.gromacs.org.
35 * To help us fund GROMACS development, we humbly ask that you cite
36 * the research papers on the package. Check out http://www.gromacs.org.
55 const int nfp_ffn[effnNR] = { 0, 1, 2, 3, 2, 5, 7, 9, 4, 3};
57 const char *s_ffn[effnNR+2] = { NULL, "none", "exp", "aexp", "exp_exp", "vac",
58 "exp5", "exp7", "exp9","erffit", NULL, NULL };
59 /* We don't allow errest as a choice on the command line */
61 const char *longs_ffn[effnNR] = {
65 "y = a2 exp(-x/a1) + (1-a2) exp(-x/a3)",
66 "y = exp(-v) (cosh(wv) + 1/w sinh(wv)), v = x/(2 a1), w = sqrt(1 - a2)",
67 "y = a1 exp(-x/a2) + a3 exp(-x/a4) + a5",
68 "y = a1 exp(-x/a2) + a3 exp(-x/a4) + a5 exp(-x/a6) + a7",
69 "y = a1 exp(-x/a2) + a3 exp(-x/a4) + a5 exp(-x/a6) + a7 exp(-x/a8) + a9",
70 "y = 1/2*(a1+a2) - 1/2*(a1-a2)*erf( (x-a3) /a4^2)",
71 "y = a2*ee(a1,x) + (1-a2)*ee(a2,x)"
74 extern gmx_bool mrqmin_new(real x[],real y[],real sig[],int ndata,real a[],
75 int ia[],int ma,real **covar,real **alpha,real *chisq,
76 void (*funcs)(real, real [], real *, real []),
79 static real myexp(real x,real A,real tau)
81 if ((A == 0) || (tau == 0))
86 void erffit (real x, real a[], real *y, real dyda[])
89 * y=(a1+a2)/2-(a1-a2)/2*erf((x-a3)/a4^2)
97 erfarg=(x-a[3])/(a[4]*a[4]);
98 erfarg2=erfarg*erfarg;
99 erfval=gmx_erf(erfarg)/2;
100 derf=M_2_SQRTPI*(a[1]-a[2])/2*exp(-erfarg2)/(a[4]*a[4]);
101 *y=(a[1]+a[2])/2-(a[1]-a[2])*erfval;
105 dyda[4]=2*derf*erfarg;
110 static void exp_one_parm(real x,real a[],real *y,real dyda[])
122 dyda[1] = x*e1/sqr(a[1]);
125 static void exp_two_parm(real x,real a[],real *y,real dyda[])
137 dyda[1] = x*a[2]*e1/sqr(a[1]);
141 static void exp_3_parm(real x,real a[],real *y,real dyda[])
145 * y = a2 exp(-x/a1) + (1-a2) exp(-x/a3)
153 *y = a[2]*e1 + (1-a[2])*e2;
154 dyda[1] = x*a[2]*e1/sqr(a[1]);
156 dyda[3] = x*(1-a[2])*e2/sqr(a[3]);
159 static void exp_5_parm(real x,real a[],real *y,real dyda[])
163 * y = a1 exp(-x/a2) + a3 exp(-x/a4) + a5
171 *y = a[1]*e1 + a[3]*e2 + a[5];
174 fprintf(debug,"exp_5_parm called: x = %10.3f y = %10.3f\n"
175 "a = ( %8.3f %8.3f %8.3f %8.3f %8.3f)\n",
176 x,*y,a[1],a[2],a[3],a[4],a[5]);
178 dyda[2] = x*e1/sqr(a[2]);
180 dyda[4] = x*e2/sqr(a[4]);
184 static void exp_7_parm(real x,real a[],real *y,real dyda[])
188 * y = a1 exp(-x/a2) + a3 exp(-x/a4) + a5 exp(-x/a6) + a7
197 *y = a[1]*e1 + a[3]*e2 + a[5]*e3 + a[7];
200 dyda[2] = x*e1/sqr(a[2]);
202 dyda[4] = x*e2/sqr(a[4]);
204 dyda[6] = x*e3/sqr(a[6]);
208 static void exp_9_parm(real x,real a[],real *y,real dyda[])
212 * y = a1 exp(-x/a2) + a3 exp(-x/a4) + a5 exp(-x/a6) + a7
222 *y = a[1]*e1 + a[3]*e2 + a[5]*e3 + a[7]*e4 + a[9];
225 dyda[2] = x*e1/sqr(a[2]);
227 dyda[4] = x*e2/sqr(a[4]);
229 dyda[6] = x*e3/sqr(a[6]);
231 dyda[8] = x*e4/sqr(a[8]);
235 static void vac_2_parm(real x,real a[],real *y,real dyda[])
239 * y = 1/2 (1 - 1/w) exp(-(1+w)v) + 1/2 (1 + 1/w) exp(-(1-w)v)
241 * = exp(-v) (cosh(wv) + 1/w sinh(wv))
246 * For tranverse current autocorrelation functions:
248 * a2 = 4 tau (eta/rho) k^2
252 double v,det,omega,omega2,em,ec,es;
259 omega = sqrt(omega2);
261 ec = em*0.5*(exp(omega*v)+exp(-omega*v));
262 es = em*0.5*(exp(omega*v)-exp(-omega*v))/omega;
264 ec = em*cos(omega*v);
265 es = em*sin(omega*v)/omega;
268 dyda[2] = (v/det*ec+(v-1/det)*es)/(-2.0);
269 dyda[1] = (1-det)*v/a[1]*es;
272 dyda[2] = -v*v*em*(0.5+v/6);
273 dyda[1] = v*v/a[1]*em;
277 static void errest_3_parm(real x,real a[],real *y,real dyda[])
282 e1 = exp(-x/a[1]) - 1;
286 e2 = exp(-x/a[3]) - 1;
291 v1 = 2*a[1]*(e1*a[1]/x + 1);
292 v2 = 2*a[3]*(e2*a[3]/x + 1);
293 *y = a[2]*v1 + (1-a[2])*v2;
294 dyda[1] = 2* a[2] *(v1/a[1] + e1);
295 dyda[3] = 2*(1 - a[2])*(v2/a[3] + e2);
305 typedef void (*myfitfn)(real x,real a[],real *y,real dyda[]);
306 myfitfn mfitfn[effnNR] = {
307 exp_one_parm, exp_one_parm, exp_two_parm, exp_3_parm, vac_2_parm,
308 exp_5_parm, exp_7_parm, exp_9_parm, erffit, errest_3_parm
311 real fit_function(int eFitFn,real *parm,real x)
313 static real y,dum[8];
315 mfitfn[eFitFn](x,parm-1,&y,dum);
320 /* lmfit_exp supports up to 3 parameter fitting of exponential functions */
321 static gmx_bool lmfit_exp(int nfit,real x[],real y[],real dy[],real ftol,
322 real parm[],real dparm[],gmx_bool bVerbose,
325 real chisq,ochisq,alamda;
326 real *a,**covar,**alpha,*dum;
328 int i,j,ma,mfit,*lista,*ia;
330 if ((eFitFn < 0) || (eFitFn >= effnNR))
331 gmx_fatal(FARGS,"fitfn = %d, should be in 0..%d (%s,%d)",
332 effnNR-1,eFitFn,__FILE__,__LINE__);
334 ma=mfit=nfp_ffn[eFitFn]; /* number of parameters to fit */
341 for(i=1; (i<ma+1); i++) {
343 ia[i] = 1; /* fixed bug B.S.S 19/11 */
349 fprintf(stderr,"Will keep parameters fixed during fit procedure: %d\n",
356 fprintf(debug,"%d parameter fit\n",mfit);
359 alamda = -1; /* Starting value */
361 for(i=0; (i<mfit); i++)
366 fprintf(stderr,"%4s %10s %10s %10s %10s %10s %10s\n",
367 "Step","chi^2","Lambda","A1","A2","A3","A4");
370 /* mrqmin(x-1,y-1,dy-1,nfit,a,ma,lista,mfit,covar,alpha,
371 * &chisq,expfn[mfit-1],&alamda)
373 if (!mrqmin_new(x-1,y-1,dy-1,nfit,a,ia,ma,covar,alpha,&chisq,
374 mfitfn[eFitFn],&alamda))
378 fprintf(stderr,"%4d %10.5e %10.5e %10.5e",
379 j,chisq,alamda,a[1]);
381 fprintf(stderr," %10.5e",a[2]);
383 fprintf(stderr," %10.5e",a[3]);
385 fprintf(stderr," %10.5e",a[4]);
386 fprintf(stderr,"\n");
389 bCont = ((fabs(ochisq - chisq) > fabs(ftol*chisq)) ||
390 ((ochisq == chisq)));
391 } while (bCont && (alamda != 0.0) && (j < 50));
393 fprintf(stderr,"\n");
395 /* Now get the covariance matrix out */
398 /* mrqmin(x-1,y-1,dy-1,nfit,a,ma,lista,mfit,covar,alpha,
399 * &chisq,expfn[mfit-1],&alamda)
401 if ( !mrqmin_new(x-1,y-1,dy-1,nfit,a,ia,ma,covar,alpha,&chisq,
402 mfitfn[eFitFn],&alamda))
405 for(j=0; (j<mfit); j++) {
407 dparm[j] = covar[j+1][j+1];
410 for(i=0; (i<ma+1); i++) {
423 real do_lmfit(int ndata,real c1[],real sig[],real dt,real x0[],
424 real begintimefit,real endtimefit,const output_env_t oenv,
425 gmx_bool bVerbose, int eFitFn,real fitparms[],int fix)
430 int i,j,nparm,nfitpnts;
436 nparm = nfp_ffn[eFitFn];
438 fprintf(debug,"There are %d points to fit %d vars!\n",ndata,nparm);
439 fprintf(debug,"Fit to function %d from %g through %g, dt=%g\n",
440 eFitFn,begintimefit,endtimefit,dt);
448 for(i=0; i<ndata; i++) {
449 ttt = x0 ? x0[i] : dt*i;
450 if (ttt>=begintimefit && ttt<=endtimefit) {
454 /* mrqmin does not like sig to be zero */
460 fprintf(debug,"j= %d, i= %d, x= %g, y= %g, dy= %g\n",
461 j,i,x[j],y[j],dy[j]);
467 if (nfitpnts < nparm)
468 fprintf(stderr,"Not enough data points for fitting!\n");
473 for(i=0; (i < nparm); i++)
476 if (!lmfit_exp(nfitpnts,x,y,dy,ftol,parm,dparm,bVerbose,eFitFn,fix))
477 fprintf(stderr,"Fit failed!\n");
478 else if (nparm <= 3) {
479 /* Compute the integral from begintimefit */
481 integral=(parm[0]*myexp(begintimefit,parm[1], parm[0]) +
482 parm[2]*myexp(begintimefit,1-parm[1],parm[2]));
484 integral=parm[0]*myexp(begintimefit,parm[1], parm[0]);
486 integral=parm[0]*myexp(begintimefit,1, parm[0]);
488 gmx_fatal(FARGS,"nparm = %d in file %s, line %d",
489 nparm,__FILE__,__LINE__);
491 /* Generate THE output */
493 fprintf(stderr,"FIT: # points used in fit is: %d\n",nfitpnts);
494 fprintf(stderr,"FIT: %21s%21s%21s\n",
495 "parm0 ","parm1 (ps) ","parm2 (ps) ");
496 fprintf(stderr,"FIT: ------------------------------------------------------------\n");
497 fprintf(stderr,"FIT: %8.3g +/- %8.3g%9.4g +/- %8.3g%8.3g +/- %8.3g\n",
498 parm[0],dparm[0],parm[1],dparm[1],parm[2],dparm[2]);
499 fprintf(stderr,"FIT: Integral (calc with fitted function) from %g ps to inf. is: %g\n",
500 begintimefit,integral);
502 sprintf(buf,"test%d.xvg",nfitpnts);
503 fp = xvgropen(buf,"C(t) + Fit to C(t)","Time (ps)","C(t)",oenv);
504 fprintf(fp,"# parm0 = %g, parm1 = %g, parm2 = %g\n",
505 parm[0],parm[1],parm[2]);
506 for(j=0; (j<nfitpnts); j++) {
507 ttt = x0 ? x0[j] : dt*j;
508 fprintf(fp,"%10.5e %10.5e %10.5e\n",
509 ttt,c1[j],fit_function(eFitFn,parm,ttt));
516 for(i=0;(i<nparm);i++)
518 fitparms[i] = parm[i];
532 void do_expfit(int ndata,real c1[],real dt,real begintimefit,real endtimefit)
536 real aa,bb,saa,sbb,A,tau,dA,dtau;
538 fprintf(stderr,"Will fit data from %g (ps) to %g (ps).\n",
539 begintimefit,endtimefit);
541 snew(x,ndata); /* allocate the maximum necessary space */
546 for(i=0; (i<ndata); i++) {
547 if ( (dt*i >= begintimefit) && (dt*i <= endtimefit) ) {
551 fprintf(stderr,"n= %d, i= %d, x= %g, y= %g\n",n,i,x[n],y[n]);
555 fprintf(stderr,"# of data points used in the fit is : %d\n\n",n);
556 expfit(n,x,y,Dy,&aa,&saa,&bb,&sbb);
562 fprintf(stderr,"Fitted to y=exp(a+bx):\n");
563 fprintf(stderr,"a = %10.5f\t b = %10.5f",aa,bb);
564 fprintf(stderr,"\n");
565 fprintf(stderr,"Fitted to y=Aexp(-x/tau):\n");
566 fprintf(stderr,"A = %10.5f\t tau = %10.5f\n",A,tau);
567 fprintf(stderr,"dA = %10.5f\t dtau = %10.5f\n",dA,dtau);
571 void expfit(int n, real *x, real *y, real *Dy, real *a, real *sa,
574 real *w,*ly,A,SA,B,SB;
576 real sum,xbar,ybar,Sxx,Sxy,wr2,chi2,gamma,Db;
583 #define sqr(x) ((x)*(x))
589 /* Calculate weights and values of ln(y). */
591 w[i]=sqr(y[i]/Dy[i]);
595 /* The weighted averages of x and y: xbar and ybar. */
607 /* The centered product sums Sxx and Sxy, and hence A and B. */
611 Sxx+=w[i]*sqr(x[i]-xbar);
612 Sxy+=w[i]*(x[i]-xbar)*(ly[i]-ybar);
617 /* Chi-squared (chi2) and gamma. */
621 wr2=w[i]*sqr(ly[i]-A-B*x[i]);
623 gamma+=wr2*(x[i]-xbar);
626 /* Refined values of A and B. Also SA and SB. */
629 A-=ONEP5*chi2/sum-xbar*Db;
630 SB=sqrt((chi2/(n-2))/Sxx);
631 SA=SB*sqrt(Sxx/sum+sqr(xbar));