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 * Copyright (c) 2013,2014, by the GROMACS development team, led by
7 * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
8 * and including many others, as listed in the AUTHORS file in the
9 * top-level source directory and at http://www.gromacs.org.
11 * GROMACS is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public License
13 * as published by the Free Software Foundation; either version 2.1
14 * of the License, or (at your option) any later version.
16 * GROMACS is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with GROMACS; if not, see
23 * http://www.gnu.org/licenses, or write to the Free Software Foundation,
24 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26 * If you want to redistribute modifications to GROMACS, please
27 * consider that scientific software is very special. Version
28 * control is crucial - bugs must be traceable. We will be happy to
29 * consider code for inclusion in the official distribution, but
30 * derived work must not be called official GROMACS. Details are found
31 * in the README & COPYING files - if they are missing, get the
32 * official version at http://www.gromacs.org.
34 * To help us fund GROMACS development, we humbly ask that you cite
35 * the research papers on the package. Check out http://www.gromacs.org.
45 #include "gromacs/utility/smalloc.h"
46 #include "gromacs/fileio/xvgr.h"
47 #include "gromacs/utility/futil.h"
49 #include "gromacs/math/vec.h"
52 #include "gromacs/utility/fatalerror.h"
54 const int nfp_ffn
[effnNR
] = { 0, 1, 2, 3, 2, 5, 7, 9, 4, 3};
56 const char *s_ffn
[effnNR
+2] = {
57 NULL
, "none", "exp", "aexp", "exp_exp", "vac",
58 "exp5", "exp7", "exp9", "erffit", NULL
, NULL
60 /* We don't allow errest as a choice on the command line */
62 const char *longs_ffn
[effnNR
] = {
66 "y = a2 exp(-x/a1) + (1-a2) exp(-x/a3)",
67 "y = exp(-v) (cosh(wv) + 1/w sinh(wv)), v = x/(2 a1), w = sqrt(1 - a2)",
68 "y = a1 exp(-x/a2) + a3 exp(-x/a4) + a5",
69 "y = a1 exp(-x/a2) + a3 exp(-x/a4) + a5 exp(-x/a6) + a7",
70 "y = a1 exp(-x/a2) + a3 exp(-x/a4) + a5 exp(-x/a6) + a7 exp(-x/a8) + a9",
71 "y = 1/2*(a1+a2) - 1/2*(a1-a2)*erf( (x-a3) /a4^2)",
72 "y = a2*ee(a1,x) + (1-a2)*ee(a2,x)"
75 extern gmx_bool
mrqmin_new(real x
[], real y
[], real sig
[], int ndata
, real a
[],
76 int ia
[], int ma
, real
**covar
, real
**alpha
, real
*chisq
,
77 void (*funcs
)(real
, real
[], real
*, real
[]),
80 static real
myexp(real x
, real A
, real tau
)
82 if ((A
== 0) || (tau
== 0))
89 void erffit (real x
, real a
[], real
*y
, real dyda
[])
92 * y=(a1+a2)/2-(a1-a2)/2*erf((x-a3)/a4^2)
100 erfarg
= (x
-a
[3])/(a
[4]*a
[4]);
101 erfarg2
= erfarg
*erfarg
;
102 erfval
= gmx_erf(erfarg
)/2;
103 derf
= M_2_SQRTPI
*(a
[1]-a
[2])/2*exp(-erfarg2
)/(a
[4]*a
[4]);
104 *y
= (a
[1]+a
[2])/2-(a
[1]-a
[2])*erfval
;
105 dyda
[1] = 1/2-erfval
;
106 dyda
[2] = 1/2+erfval
;
108 dyda
[4] = 2*derf
*erfarg
;
113 static void exp_one_parm(real x
, real a
[], real
*y
, real dyda
[])
125 dyda
[1] = x
*e1
/sqr(a
[1]);
128 static void exp_two_parm(real x
, real a
[], real
*y
, real dyda
[])
140 dyda
[1] = x
*a
[2]*e1
/sqr(a
[1]);
144 static void exp_3_parm(real x
, real a
[], real
*y
, real dyda
[])
148 * y = a2 exp(-x/a1) + (1-a2) exp(-x/a3)
156 *y
= a
[2]*e1
+ (1-a
[2])*e2
;
157 dyda
[1] = x
*a
[2]*e1
/sqr(a
[1]);
159 dyda
[3] = x
*(1-a
[2])*e2
/sqr(a
[3]);
162 static void exp_5_parm(real x
, real a
[], real
*y
, real dyda
[])
166 * y = a1 exp(-x/a2) + a3 exp(-x/a4) + a5
174 *y
= a
[1]*e1
+ a
[3]*e2
+ a
[5];
178 fprintf(debug
, "exp_5_parm called: x = %10.3f y = %10.3f\n"
179 "a = ( %8.3f %8.3f %8.3f %8.3f %8.3f)\n",
180 x
, *y
, a
[1], a
[2], a
[3], a
[4], a
[5]);
183 dyda
[2] = x
*e1
/sqr(a
[2]);
185 dyda
[4] = x
*e2
/sqr(a
[4]);
189 static void exp_7_parm(real x
, real a
[], real
*y
, real dyda
[])
193 * y = a1 exp(-x/a2) + a3 exp(-x/a4) + a5 exp(-x/a6) + a7
202 *y
= a
[1]*e1
+ a
[3]*e2
+ a
[5]*e3
+ a
[7];
205 dyda
[2] = x
*e1
/sqr(a
[2]);
207 dyda
[4] = x
*e2
/sqr(a
[4]);
209 dyda
[6] = x
*e3
/sqr(a
[6]);
213 static void exp_9_parm(real x
, real a
[], real
*y
, real dyda
[])
217 * y = a1 exp(-x/a2) + a3 exp(-x/a4) + a5 exp(-x/a6) + a7
227 *y
= a
[1]*e1
+ a
[3]*e2
+ a
[5]*e3
+ a
[7]*e4
+ a
[9];
230 dyda
[2] = x
*e1
/sqr(a
[2]);
232 dyda
[4] = x
*e2
/sqr(a
[4]);
234 dyda
[6] = x
*e3
/sqr(a
[6]);
236 dyda
[8] = x
*e4
/sqr(a
[8]);
240 static void vac_2_parm(real x
, real a
[], real
*y
, real dyda
[])
244 * y = 1/2 (1 - 1/w) exp(-(1+w)v) + 1/2 (1 + 1/w) exp(-(1-w)v)
246 * = exp(-v) (cosh(wv) + 1/w sinh(wv))
251 * For tranverse current autocorrelation functions:
253 * a2 = 4 tau (eta/rho) k^2
257 double v
, det
, omega
, omega2
, em
, ec
, es
;
265 omega
= sqrt(omega2
);
268 ec
= em
*0.5*(exp(omega
*v
)+exp(-omega
*v
));
269 es
= em
*0.5*(exp(omega
*v
)-exp(-omega
*v
))/omega
;
273 ec
= em
*cos(omega
*v
);
274 es
= em
*sin(omega
*v
)/omega
;
277 dyda
[2] = (v
/det
*ec
+(v
-1/det
)*es
)/(-2.0);
278 dyda
[1] = (1-det
)*v
/a
[1]*es
;
283 dyda
[2] = -v
*v
*em
*(0.5+v
/6);
284 dyda
[1] = v
*v
/a
[1]*em
;
288 static void errest_3_parm(real x
, real a
[], real
*y
, real dyda
[])
294 e1
= exp(-x
/a
[1]) - 1;
302 e2
= exp(-x
/a
[3]) - 1;
311 v1
= 2*a
[1]*(e1
*a
[1]/x
+ 1);
312 v2
= 2*a
[3]*(e2
*a
[3]/x
+ 1);
313 *y
= a
[2]*v1
+ (1-a
[2])*v2
;
314 dyda
[1] = 2* a
[2] *(v1
/a
[1] + e1
);
315 dyda
[3] = 2*(1 - a
[2])*(v2
/a
[3] + e2
);
327 typedef void (*myfitfn
)(real x
, real a
[], real
*y
, real dyda
[]);
328 myfitfn mfitfn
[effnNR
] = {
329 exp_one_parm
, exp_one_parm
, exp_two_parm
, exp_3_parm
, vac_2_parm
,
330 exp_5_parm
, exp_7_parm
, exp_9_parm
, erffit
, errest_3_parm
333 real
fit_function(int eFitFn
, real
*parm
, real x
)
335 static real y
, dum
[8];
337 mfitfn
[eFitFn
](x
, parm
-1, &y
, dum
);
342 /* lmfit_exp supports up to 3 parameter fitting of exponential functions */
343 static gmx_bool
lmfit_exp(int nfit
, real x
[], real y
[], real dy
[], real ftol
,
344 real parm
[], real dparm
[], gmx_bool bVerbose
,
347 real chisq
, ochisq
, alamda
;
348 real
*a
, **covar
, **alpha
, *dum
;
350 int i
, j
, ma
, mfit
, *lista
, *ia
;
352 if ((eFitFn
< 0) || (eFitFn
>= effnNR
))
354 gmx_fatal(FARGS
, "fitfn = %d, should be in 0..%d (%s,%d)",
355 effnNR
-1, eFitFn
, __FILE__
, __LINE__
);
358 ma
= mfit
= nfp_ffn
[eFitFn
]; /* number of parameters to fit */
365 for (i
= 1; (i
< ma
+1); i
++)
368 ia
[i
] = 1; /* fixed bug B.S.S 19/11 */
369 snew(covar
[i
], ma
+1);
370 snew(alpha
[i
], ma
+1);
376 fprintf(stderr
, "Will keep parameters fixed during fit procedure: %d\n",
379 for (i
= 0; i
< ma
; i
++)
389 fprintf(debug
, "%d parameter fit\n", mfit
);
393 alamda
= -1; /* Starting value */
395 for (i
= 0; (i
< mfit
); i
++)
403 fprintf(stderr
, "%4s %10s %10s %10s %10s %10s %10s\n",
404 "Step", "chi^2", "Lambda", "A1", "A2", "A3", "A4");
409 /* mrqmin(x-1,y-1,dy-1,nfit,a,ma,lista,mfit,covar,alpha,
410 * &chisq,expfn[mfit-1],&alamda)
412 if (!mrqmin_new(x
-1, y
-1, dy
-1, nfit
, a
, ia
, ma
, covar
, alpha
, &chisq
,
413 mfitfn
[eFitFn
], &alamda
))
420 fprintf(stderr
, "%4d %10.5e %10.5e %10.5e",
421 j
, chisq
, alamda
, a
[1]);
424 fprintf(stderr
, " %10.5e", a
[2]);
428 fprintf(stderr
, " %10.5e", a
[3]);
432 fprintf(stderr
, " %10.5e", a
[4]);
434 fprintf(stderr
, "\n");
437 bCont
= ((fabs(ochisq
- chisq
) > fabs(ftol
*chisq
)) ||
438 ((ochisq
== chisq
)));
440 while (bCont
&& (alamda
!= 0.0) && (j
< 50));
443 fprintf(stderr
, "\n");
446 /* Now get the covariance matrix out */
449 /* mrqmin(x-1,y-1,dy-1,nfit,a,ma,lista,mfit,covar,alpha,
450 * &chisq,expfn[mfit-1],&alamda)
452 if (!mrqmin_new(x
-1, y
-1, dy
-1, nfit
, a
, ia
, ma
, covar
, alpha
, &chisq
,
453 mfitfn
[eFitFn
], &alamda
))
458 for (j
= 0; (j
< mfit
); j
++)
461 dparm
[j
] = covar
[j
+1][j
+1];
464 for (i
= 0; (i
< ma
+1); i
++)
478 real
do_lmfit(int ndata
, real c1
[], real sig
[], real dt
, real x0
[],
479 real begintimefit
, real endtimefit
, const output_env_t oenv
,
480 gmx_bool bVerbose
, int eFitFn
, real fitparms
[], int fix
)
485 int i
, j
, nparm
, nfitpnts
;
491 nparm
= nfp_ffn
[eFitFn
];
494 fprintf(debug
, "There are %d points to fit %d vars!\n", ndata
, nparm
);
495 fprintf(debug
, "Fit to function %d from %g through %g, dt=%g\n",
496 eFitFn
, begintimefit
, endtimefit
, dt
);
504 for (i
= 0; i
< ndata
; i
++)
506 ttt
= x0
? x0
[i
] : dt
*i
;
507 if (ttt
>= begintimefit
&& ttt
<= endtimefit
)
512 /* mrqmin does not like sig to be zero */
523 fprintf(debug
, "j= %d, i= %d, x= %g, y= %g, dy= %g\n",
524 j
, i
, x
[j
], y
[j
], dy
[j
]);
531 if (nfitpnts
< nparm
)
533 fprintf(stderr
, "Not enough data points for fitting!\n");
541 for (i
= 0; (i
< nparm
); i
++)
543 parm
[i
] = fitparms
[i
];
547 if (!lmfit_exp(nfitpnts
, x
, y
, dy
, ftol
, parm
, dparm
, bVerbose
, eFitFn
, fix
))
549 fprintf(stderr
, "Fit failed!\n");
553 /* Compute the integral from begintimefit */
556 integral
= (parm
[0]*myexp(begintimefit
, parm
[1], parm
[0]) +
557 parm
[2]*myexp(begintimefit
, 1-parm
[1], parm
[2]));
561 integral
= parm
[0]*myexp(begintimefit
, parm
[1], parm
[0]);
565 integral
= parm
[0]*myexp(begintimefit
, 1, parm
[0]);
569 gmx_fatal(FARGS
, "nparm = %d in file %s, line %d",
570 nparm
, __FILE__
, __LINE__
);
573 /* Generate THE output */
576 fprintf(stderr
, "FIT: # points used in fit is: %d\n", nfitpnts
);
577 fprintf(stderr
, "FIT: %21s%21s%21s\n",
578 "parm0 ", "parm1 (ps) ", "parm2 (ps) ");
579 fprintf(stderr
, "FIT: ------------------------------------------------------------\n");
580 fprintf(stderr
, "FIT: %8.3g +/- %8.3g%9.4g +/- %8.3g%8.3g +/- %8.3g\n",
581 parm
[0], dparm
[0], parm
[1], dparm
[1], parm
[2], dparm
[2]);
582 fprintf(stderr
, "FIT: Integral (calc with fitted function) from %g ps to inf. is: %g\n",
583 begintimefit
, integral
);
585 sprintf(buf
, "test%d.xvg", nfitpnts
);
586 fp
= xvgropen(buf
, "C(t) + Fit to C(t)", "Time (ps)", "C(t)", oenv
);
587 fprintf(fp
, "# parm0 = %g, parm1 = %g, parm2 = %g\n",
588 parm
[0], parm
[1], parm
[2]);
589 for (j
= 0; (j
< nfitpnts
); j
++)
591 ttt
= x0
? x0
[j
] : dt
*j
;
592 fprintf(fp
, "%10.5e %10.5e %10.5e\n",
593 ttt
, c1
[j
], fit_function(eFitFn
, parm
, ttt
));
600 for (i
= 0; (i
< nparm
); i
++)
602 fitparms
[i
] = parm
[i
];
616 void do_expfit(int ndata
, real c1
[], real dt
, real begintimefit
, real endtimefit
)
620 real aa
, bb
, saa
, sbb
, A
, tau
, dA
, dtau
;
622 fprintf(stderr
, "Will fit data from %g (ps) to %g (ps).\n",
623 begintimefit
, endtimefit
);
625 snew(x
, ndata
); /* allocate the maximum necessary space */
630 for (i
= 0; (i
< ndata
); i
++)
632 if ( (dt
*i
>= begintimefit
) && (dt
*i
<= endtimefit
) )
637 fprintf(stderr
, "n= %d, i= %d, x= %g, y= %g\n", n
, i
, x
[n
], y
[n
]);
641 fprintf(stderr
, "# of data points used in the fit is : %d\n\n", n
);
642 expfit(n
, x
, y
, Dy
, &aa
, &saa
, &bb
, &sbb
);
648 fprintf(stderr
, "Fitted to y=exp(a+bx):\n");
649 fprintf(stderr
, "a = %10.5f\t b = %10.5f", aa
, bb
);
650 fprintf(stderr
, "\n");
651 fprintf(stderr
, "Fitted to y=Aexp(-x/tau):\n");
652 fprintf(stderr
, "A = %10.5f\t tau = %10.5f\n", A
, tau
);
653 fprintf(stderr
, "dA = %10.5f\t dtau = %10.5f\n", dA
, dtau
);
657 void expfit(int n
, real
*x
, real
*y
, real
*Dy
, real
*a
, real
*sa
,
660 real
*w
, *ly
, A
, SA
, B
, SB
;
662 real sum
, xbar
, ybar
, Sxx
, Sxy
, wr2
, chi2
, gamma
, Db
;
669 #define sqr(x) ((x)*(x))
675 /* Calculate weights and values of ln(y). */
676 for (i
= 0; (i
< n
); i
++)
678 w
[i
] = sqr(y
[i
]/Dy
[i
]);
682 /* The weighted averages of x and y: xbar and ybar. */
686 for (i
= 0; (i
< n
); i
++)
695 /* The centered product sums Sxx and Sxy, and hence A and B. */
698 for (i
= 0; (i
< n
); i
++)
700 Sxx
+= w
[i
]*sqr(x
[i
]-xbar
);
701 Sxy
+= w
[i
]*(x
[i
]-xbar
)*(ly
[i
]-ybar
);
706 /* Chi-squared (chi2) and gamma. */
709 for (i
= 0; (i
< n
); i
++)
711 wr2
= w
[i
]*sqr(ly
[i
]-A
-B
*x
[i
]);
713 gamma
+= wr2
*(x
[i
]-xbar
);
716 /* Refined values of A and B. Also SA and SB. */
717 Db
= -ONEP5
*gamma
/Sxx
;
719 A
-= ONEP5
*chi2
/sum
-xbar
*Db
;
720 SB
= sqrt((chi2
/(n
-2))/Sxx
);
721 SA
= SB
*sqrt(Sxx
/sum
+sqr(xbar
));