Move symtab.* to topology/
[gromacs.git] / src / gromacs / gmxana / expfit.c
blobee125c8b8e3f95aa6faf2aded1ab51b113b83de1
1 /*
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.
37 #ifdef HAVE_CONFIG_H
38 #include <config.h>
39 #endif
41 #include <math.h>
42 #include <string.h>
44 #include "typedefs.h"
45 #include "gromacs/utility/smalloc.h"
46 #include "gromacs/fileio/xvgr.h"
47 #include "gromacs/utility/futil.h"
48 #include "gstat.h"
49 #include "gromacs/math/vec.h"
50 #include "index.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] = {
63 "no fit",
64 "y = exp(-x/a1)",
65 "y = a2 exp(-x/a1)",
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 []),
78 real *alamda);
80 static real myexp(real x, real A, real tau)
82 if ((A == 0) || (tau == 0))
84 return 0;
86 return A*exp(-x/tau);
89 void erffit (real x, real a[], real *y, real dyda[])
91 /* Fuction
92 * y=(a1+a2)/2-(a1-a2)/2*erf((x-a3)/a4^2)
95 real erfarg;
96 real erfval;
97 real erfarg2;
98 real derf;
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;
107 dyda[3] = derf;
108 dyda[4] = 2*derf*erfarg;
113 static void exp_one_parm(real x, real a[], real *y, real dyda[])
115 /* Fit to function
117 * y = exp(-x/a1)
121 real e1;
123 e1 = exp(-x/a[1]);
124 *y = e1;
125 dyda[1] = x*e1/sqr(a[1]);
128 static void exp_two_parm(real x, real a[], real *y, real dyda[])
130 /* Fit to function
132 * y = a2 exp(-x/a1)
136 real e1;
138 e1 = exp(-x/a[1]);
139 *y = a[2]*e1;
140 dyda[1] = x*a[2]*e1/sqr(a[1]);
141 dyda[2] = e1;
144 static void exp_3_parm(real x, real a[], real *y, real dyda[])
146 /* Fit to function
148 * y = a2 exp(-x/a1) + (1-a2) exp(-x/a3)
152 real e1, e2;
154 e1 = exp(-x/a[1]);
155 e2 = exp(-x/a[3]);
156 *y = a[2]*e1 + (1-a[2])*e2;
157 dyda[1] = x*a[2]*e1/sqr(a[1]);
158 dyda[2] = e1-e2;
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[])
164 /* Fit to function
166 * y = a1 exp(-x/a2) + a3 exp(-x/a4) + a5
170 real e1, e2;
172 e1 = exp(-x/a[2]);
173 e2 = exp(-x/a[4]);
174 *y = a[1]*e1 + a[3]*e2 + a[5];
176 if (debug)
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]);
182 dyda[1] = e1;
183 dyda[2] = x*e1/sqr(a[2]);
184 dyda[3] = e2;
185 dyda[4] = x*e2/sqr(a[4]);
186 dyda[5] = 0;
189 static void exp_7_parm(real x, real a[], real *y, real dyda[])
191 /* Fit to function
193 * y = a1 exp(-x/a2) + a3 exp(-x/a4) + a5 exp(-x/a6) + a7
197 real e1, e2, e3;
199 e1 = exp(-x/a[2]);
200 e2 = exp(-x/a[4]);
201 e3 = exp(-x/a[6]);
202 *y = a[1]*e1 + a[3]*e2 + a[5]*e3 + a[7];
204 dyda[1] = e1;
205 dyda[2] = x*e1/sqr(a[2]);
206 dyda[3] = e2;
207 dyda[4] = x*e2/sqr(a[4]);
208 dyda[5] = e3;
209 dyda[6] = x*e3/sqr(a[6]);
210 dyda[7] = 0;
213 static void exp_9_parm(real x, real a[], real *y, real dyda[])
215 /* Fit to function
217 * y = a1 exp(-x/a2) + a3 exp(-x/a4) + a5 exp(-x/a6) + a7
221 real e1, e2, e3, e4;
223 e1 = exp(-x/a[2]);
224 e2 = exp(-x/a[4]);
225 e3 = exp(-x/a[6]);
226 e4 = exp(-x/a[8]);
227 *y = a[1]*e1 + a[3]*e2 + a[5]*e3 + a[7]*e4 + a[9];
229 dyda[1] = e1;
230 dyda[2] = x*e1/sqr(a[2]);
231 dyda[3] = e2;
232 dyda[4] = x*e2/sqr(a[4]);
233 dyda[5] = e3;
234 dyda[6] = x*e3/sqr(a[6]);
235 dyda[7] = e4;
236 dyda[8] = x*e4/sqr(a[8]);
237 dyda[9] = 0;
240 static void vac_2_parm(real x, real a[], real *y, real dyda[])
242 /* Fit to function
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))
248 * v = x/(2 a1)
249 * w = sqrt(1 - a2)
251 * For tranverse current autocorrelation functions:
252 * a1 = tau
253 * a2 = 4 tau (eta/rho) k^2
257 double v, det, omega, omega2, em, ec, es;
259 v = x/(2*a[1]);
260 det = 1 - a[2];
261 em = exp(-v);
262 if (det != 0)
264 omega2 = fabs(det);
265 omega = sqrt(omega2);
266 if (det > 0)
268 ec = em*0.5*(exp(omega*v)+exp(-omega*v));
269 es = em*0.5*(exp(omega*v)-exp(-omega*v))/omega;
271 else
273 ec = em*cos(omega*v);
274 es = em*sin(omega*v)/omega;
276 *y = ec + es;
277 dyda[2] = (v/det*ec+(v-1/det)*es)/(-2.0);
278 dyda[1] = (1-det)*v/a[1]*es;
280 else
282 *y = (1+v)*em;
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[])
290 real e1, e2, v1, v2;
292 if (a[1])
294 e1 = exp(-x/a[1]) - 1;
296 else
298 e1 = 0;
300 if (a[3])
302 e2 = exp(-x/a[3]) - 1;
304 else
306 e2 = 0;
309 if (x > 0)
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);
316 dyda[2] = (v1 - v2);
318 else
320 *y = 0;
321 dyda[1] = 0;
322 dyda[3] = 0;
323 dyda[2] = 0;
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);
339 return y;
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,
345 int eFitFn, int fix)
347 real chisq, ochisq, alamda;
348 real *a, **covar, **alpha, *dum;
349 gmx_bool bCont;
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 */
359 snew(a, ma+1);
360 snew(covar, ma+1);
361 snew(alpha, ma+1);
362 snew(lista, ma+1);
363 snew(ia, ma+1);
364 snew(dum, ma+1);
365 for (i = 1; (i < ma+1); i++)
367 lista[i] = i;
368 ia[i] = 1; /* fixed bug B.S.S 19/11 */
369 snew(covar[i], ma+1);
370 snew(alpha[i], ma+1);
372 if (fix)
374 if (bVerbose)
376 fprintf(stderr, "Will keep parameters fixed during fit procedure: %d\n",
377 fix);
379 for (i = 0; i < ma; i++)
381 if (fix & 1<<i)
383 ia[i+1] = 0;
387 if (debug)
389 fprintf(debug, "%d parameter fit\n", mfit);
392 /* Initial params */
393 alamda = -1; /* Starting value */
394 chisq = 1e12;
395 for (i = 0; (i < mfit); i++)
397 a[i+1] = parm[i];
400 j = 0;
401 if (bVerbose)
403 fprintf(stderr, "%4s %10s %10s %10s %10s %10s %10s\n",
404 "Step", "chi^2", "Lambda", "A1", "A2", "A3", "A4");
408 ochisq = chisq;
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))
415 return FALSE;
418 if (bVerbose)
420 fprintf(stderr, "%4d %10.5e %10.5e %10.5e",
421 j, chisq, alamda, a[1]);
422 if (mfit > 1)
424 fprintf(stderr, " %10.5e", a[2]);
426 if (mfit > 2)
428 fprintf(stderr, " %10.5e", a[3]);
430 if (mfit > 3)
432 fprintf(stderr, " %10.5e", a[4]);
434 fprintf(stderr, "\n");
436 j++;
437 bCont = ((fabs(ochisq - chisq) > fabs(ftol*chisq)) ||
438 ((ochisq == chisq)));
440 while (bCont && (alamda != 0.0) && (j < 50));
441 if (bVerbose)
443 fprintf(stderr, "\n");
446 /* Now get the covariance matrix out */
447 alamda = 0;
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))
455 return FALSE;
458 for (j = 0; (j < mfit); j++)
460 parm[j] = a[j+1];
461 dparm[j] = covar[j+1][j+1];
464 for (i = 0; (i < ma+1); i++)
466 sfree(covar[i]);
467 sfree(alpha[i]);
469 sfree(a);
470 sfree(covar);
471 sfree(alpha);
472 sfree(lista);
473 sfree(dum);
475 return TRUE;
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)
482 FILE *fp;
483 char buf[32];
485 int i, j, nparm, nfitpnts;
486 real integral, ttt;
487 real *parm, *dparm;
488 real *x, *y, *dy;
489 real ftol = 1e-4;
491 nparm = nfp_ffn[eFitFn];
492 if (debug)
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);
499 snew(x, ndata);
500 snew(y, ndata);
501 snew(dy, ndata);
503 j = 0;
504 for (i = 0; i < ndata; i++)
506 ttt = x0 ? x0[i] : dt*i;
507 if (ttt >= begintimefit && ttt <= endtimefit)
509 x[j] = ttt;
510 y[j] = c1[i];
512 /* mrqmin does not like sig to be zero */
513 if (sig[i] < 1.0e-7)
515 dy[j] = 1.0e-7;
517 else
519 dy[j] = sig[i];
521 if (debug)
523 fprintf(debug, "j= %d, i= %d, x= %g, y= %g, dy= %g\n",
524 j, i, x[j], y[j], dy[j]);
526 j++;
529 nfitpnts = j;
530 integral = 0;
531 if (nfitpnts < nparm)
533 fprintf(stderr, "Not enough data points for fitting!\n");
535 else
537 snew(parm, nparm);
538 snew(dparm, nparm);
539 if (fitparms)
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");
551 else if (nparm <= 3)
553 /* Compute the integral from begintimefit */
554 if (nparm == 3)
556 integral = (parm[0]*myexp(begintimefit, parm[1], parm[0]) +
557 parm[2]*myexp(begintimefit, 1-parm[1], parm[2]));
559 else if (nparm == 2)
561 integral = parm[0]*myexp(begintimefit, parm[1], parm[0]);
563 else if (nparm == 1)
565 integral = parm[0]*myexp(begintimefit, 1, parm[0]);
567 else
569 gmx_fatal(FARGS, "nparm = %d in file %s, line %d",
570 nparm, __FILE__, __LINE__);
573 /* Generate THE output */
574 if (bVerbose)
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));
595 xvgrclose(fp);
598 if (fitparms)
600 for (i = 0; (i < nparm); i++)
602 fitparms[i] = parm[i];
605 sfree(parm);
606 sfree(dparm);
609 sfree(x);
610 sfree(y);
611 sfree(dy);
613 return integral;
616 void do_expfit(int ndata, real c1[], real dt, real begintimefit, real endtimefit)
618 int i, n;
619 real *x, *y, *Dy;
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 */
626 snew(y, ndata);
627 snew(Dy, ndata);
628 n = 0;
630 for (i = 0; (i < ndata); i++)
632 if ( (dt*i >= begintimefit) && (dt*i <= endtimefit) )
634 x[n] = dt*i;
635 y[n] = c1[i];
636 Dy[n] = 0.5;
637 fprintf(stderr, "n= %d, i= %d, x= %g, y= %g\n", n, i, x[n], y[n]);
638 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);
644 A = exp(aa);
645 dA = exp(aa)*saa;
646 tau = -1.0/bb;
647 dtau = sbb/sqr(bb);
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,
658 real *b, real *sb)
660 real *w, *ly, A, SA, B, SB;
661 int i;
662 real sum, xbar, ybar, Sxx, Sxy, wr2, chi2, gamma, Db;
664 #define ZERO 0.0
665 #define ONE 1.0
666 #define ONEP5 1.5
667 #define TWO 2.0
669 #define sqr(x) ((x)*(x))
671 /*allocate memory */
672 snew(w, n);
673 snew(ly, n);
675 /* Calculate weights and values of ln(y). */
676 for (i = 0; (i < n); i++)
678 w[i] = sqr(y[i]/Dy[i]);
679 ly[i] = log(y[i]);
682 /* The weighted averages of x and y: xbar and ybar. */
683 sum = ZERO;
684 xbar = ZERO;
685 ybar = ZERO;
686 for (i = 0; (i < n); i++)
688 sum += w[i];
689 xbar += w[i]*x[i];
690 ybar += w[i]*ly[i];
692 xbar /= sum;
693 ybar /= sum;
695 /* The centered product sums Sxx and Sxy, and hence A and B. */
696 Sxx = ZERO;
697 Sxy = ZERO;
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);
703 B = Sxy/Sxx;
704 A = ybar-B*xbar;
706 /* Chi-squared (chi2) and gamma. */
707 chi2 = ZERO;
708 gamma = ZERO;
709 for (i = 0; (i < n); i++)
711 wr2 = w[i]*sqr(ly[i]-A-B*x[i]);
712 chi2 += wr2;
713 gamma += wr2*(x[i]-xbar);
716 /* Refined values of A and B. Also SA and SB. */
717 Db = -ONEP5*gamma/Sxx;
718 B += Db;
719 A -= ONEP5*chi2/sum-xbar*Db;
720 SB = sqrt((chi2/(n-2))/Sxx);
721 SA = SB*sqrt(Sxx/sum+sqr(xbar));
722 *a = A;
723 *b = B;
724 *sa = SA;
725 *sb = SB;