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,2013, 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.
43 #include <gsl/gsl_rng.h>
44 #include <gsl/gsl_randist.h>
45 #include <gsl/gsl_vector.h>
46 #include <gsl/gsl_blas.h>
47 #include <gsl/gsl_multimin.h>
48 #include <gsl/gsl_multifit_nlin.h>
49 #include <gsl/gsl_sf.h>
50 #include <gsl/gsl_version.h>
61 /* The first few sections of this file contain functions that were adopted,
62 * and to some extent modified, by Erik Marklund (erikm[aT]xray.bmc.uu.se,
63 * http://folding.bmc.uu.se) from code written by Omer Markovitch (email, url).
64 * This is also the case with the function eq10v2().
66 * The parts menetioned in the previous paragraph were contributed under the BSD license.
70 /* This first part is from complex.c which I recieved from Omer Markowitch.
73 * ------------- from complex.c ------------- */
75 /* Complexation of a paired number (r,i) */
76 static gem_complex gem_cmplx(double r, double i)
84 /* Complexation of a real number, x */
85 static gem_complex gem_c(double x)
93 /* Magnitude of a complex number z */
94 static double gem_cx_abs(gem_complex z) { return (sqrt(z.r*z.r+z.i*z.i)); }
96 /* Addition of two complex numbers z1 and z2 */
97 static gem_complex gem_cxadd(gem_complex z1, gem_complex z2)
105 /* Addition of a complex number z1 and a real number r */
106 static gem_complex gem_cxradd(gem_complex z, double r)
114 /* Subtraction of two complex numbers z1 and z2 */
115 static gem_complex gem_cxsub(gem_complex z1, gem_complex z2)
123 /* Multiplication of two complex numbers z1 and z2 */
124 static gem_complex gem_cxmul(gem_complex z1, gem_complex z2)
127 value.r = z1.r*z2.r-z1.i*z2.i;
128 value.i = z1.r*z2.i+z1.i*z2.r;
132 /* Square of a complex number z */
133 static gem_complex gem_cxsq(gem_complex z)
136 value.r = z.r*z.r-z.i*z.i;
137 value.i = z.r*z.i*2.;
141 /* multiplication of a complex number z and a real number r */
142 static gem_complex gem_cxrmul(gem_complex z, double r)
150 /* Division of two complex numbers z1 and z2 */
151 static gem_complex gem_cxdiv(gem_complex z1, gem_complex z2)
155 num = z2.r*z2.r+z2.i*z2.i;
158 fprintf(stderr, "ERROR in gem_cxdiv function\n");
160 value.r = (z1.r*z2.r+z1.i*z2.i)/num; value.i = (z1.i*z2.r-z1.r*z2.i)/num;
164 /* division of a complex z number by a real number x */
165 static gem_complex gem_cxrdiv(gem_complex z, double r)
173 /* division of a real number r by a complex number x */
174 static gem_complex gem_rxcdiv(double r, gem_complex z)
178 f = r/(z.r*z.r+z.i*z.i);
184 /* Exponential of a complex number-- exp (z)=|exp(z.r)|*{cos(z.i)+I*sin(z.i)}*/
185 static gem_complex gem_cxdexp(gem_complex z)
190 value.r = exp_z_r*cos(z.i);
191 value.i = exp_z_r*sin(z.i);
195 /* Logarithm of a complex number -- log(z)=log|z|+I*Arg(z), */
196 /* where -PI < Arg(z) < PI */
197 static gem_complex gem_cxlog(gem_complex z)
201 mag2 = z.r*z.r+z.i*z.i;
203 fprintf(stderr, "ERROR in gem_cxlog func\n");
205 value.r = log(sqrt(mag2));
212 value.i = atan2(z.i, z.r);
217 /* Square root of a complex number z = |z| exp(I*the) -- z^(1/2) */
218 /* z^(1/2)=|z|^(1/2)*[cos(the/2)+I*sin(the/2)] */
219 /* where 0 < the < 2*PI */
220 static gem_complex gem_cxdsqrt(gem_complex z)
225 value.r = sqrt(fabs((sq+z.r)*0.5)); /* z'.r={|z|*[1+cos(the)]/2}^(1/2) */
226 value.i = sqrt(fabs((sq-z.r)*0.5)); /* z'.i={|z|*[1-cos(the)]/2}^(1/2) */
233 /* Complex power of a complex number z1^z2 */
234 static gem_complex gem_cxdpow(gem_complex z1, gem_complex z2)
237 value=gem_cxdexp(gem_cxmul(gem_cxlog(z1),z2));
241 /* ------------ end of complex.c ------------ */
243 /* This next part was derived from cubic.c, also received from Omer Markovitch.
244 * ------------- from cubic.c ------------- */
246 /* Solver for a cubic equation: x^3-a*x^2+b*x-c=0 */
247 static void gem_solve(gem_complex *al, gem_complex *be, gem_complex *gam,
248 double a, double b, double c)
250 double t1, t2, two_3, temp;
251 gem_complex ctemp, ct3;
253 two_3=pow(2., 1./3.); t1 = -a*a+3.*b; t2 = 2.*a*a*a-9.*a*b+27.*c;
254 temp = 4.*t1*t1*t1+t2*t2;
256 ctemp = gem_cmplx(temp,0.); ctemp = gem_cxadd(gem_cmplx(t2,0.),gem_cxdsqrt(ctemp));
257 ct3 = gem_cxdpow(ctemp, gem_cmplx(1./3.,0.));
259 ctemp = gem_rxcdiv(-two_3*t1/3., ct3);
260 ctemp = gem_cxadd(ctemp, gem_cxrdiv(ct3, 3.*two_3));
262 *gam = gem_cxadd(gem_cmplx(a/3.,0.), ctemp);
264 ctemp=gem_cxmul(gem_cxsq(*gam), gem_cxsq(gem_cxsub(*gam, gem_cmplx(a,0.))));
265 ctemp=gem_cxadd(ctemp, gem_cxmul(gem_cmplx(-4.*c,0.), *gam));
266 ctemp = gem_cxdiv(gem_cxdsqrt(ctemp), *gam);
267 *al = gem_cxrmul(gem_cxsub(gem_cxsub(gem_cmplx(a,0.), *gam),ctemp),0.5);
268 *be = gem_cxrmul(gem_cxadd(gem_cxsub(gem_cmplx(a,0.), *gam),ctemp),0.5);
271 /* ------------ end of cubic.c ------------ */
273 /* This next part was derived from cerror.c and rerror.c, also received from Omer Markovitch.
274 * ------------- from [cr]error.c ------------- */
276 /************************************************************/
277 /* Real valued error function and related functions */
278 /* x, y : real variables */
279 /* erf(x) : error function */
280 /* erfc(x) : complementary error function */
281 /* omega(x) : exp(x*x)*erfc(x) */
282 /* W(x,y) : exp(-x*x)*omega(x+y)=exp(2*x*y+y^2)*erfc(x+y) */
283 /************************************************************/
285 /*---------------------------------------------------------------------------*/
286 /* Utilzed the series approximation of erf(x) */
287 /* Relative error=|err(x)|/erf(x)<EPS */
288 /* Handbook of Mathematical functions, Abramowitz, p 297 */
289 /* Note: When x>=6 series sum deteriorates -> Asymptotic series used instead */
290 /*---------------------------------------------------------------------------*/
291 /* This gives erfc(z) correctly only upto >10-15 */
293 static double gem_erf(double x)
295 double n,sum,temp,exp2,xm,x2,x4,x6,x8,x10,x12;
308 for(n=1.; n<=2000.; n+=1.){
309 temp *= 2.*x2/(2.*n+1.);
311 if(fabs(temp/sum)<1.E-16)
316 fprintf(stderr, "In Erf calc - iteration exceeds %lg\n",n);
321 /* from the asymptotic expansion of experfc(x) */
322 sum = (1. - 0.5/x2 + 0.75/x4
323 - 1.875/x6 + 6.5625/x8
324 - 29.53125/x10 + 162.421875/x12)
326 sum*=exp2; /* now sum is erfc(x) */
329 return x>=0.0 ? sum : -sum;
332 /* Result --> Alex's code for erfc and experfc behaves better than this */
333 /* complementray error function. Returns 1.-erf(x) */
334 static double gem_erfc(double x)
340 ans = t * exp(-z*z - 1.26551223 +
349 t*0.17087277)))))))));
351 return x>=0.0 ? ans : 2.0-ans;
354 /* omega(x)=exp(x^2)erfc(x) */
355 static double gem_omega(double x)
357 double xm, ans, xx, x4, x6, x8, x10, x12;
367 ans = exp(xx)*gem_erfc(x);
369 /* Asymptotic expansion */
370 ans = (1. - 0.5/xx + 0.75/x4 - 1.875/x6 + 6.5625/x8 - 29.53125/x10 + 162.421875/x12) / sPI/x;
375 /*---------------------------------------------------------------------------*/
376 /* Utilzed the series approximation of erf(z=x+iy) */
377 /* Relative error=|err(z)|/|erf(z)|<EPS */
378 /* Handbook of Mathematical functions, Abramowitz, p 299 */
379 /* comega(z=x+iy)=cexp(z^2)*cerfc(z) */
380 /*---------------------------------------------------------------------------*/
381 static gem_complex gem_comega(gem_complex z)
385 double sumr,sumi,n,n2,f,temp,temp1;
386 double x2, y2,cos_2xy,sin_2xy,cosh_2xy,sinh_2xy,cosh_ny,sinh_ny,exp_y2;
394 cos_2xy = cos(2.*x*y);
395 sin_2xy = sin(2.*x*y);
396 cosh_2xy = cosh(2.*x*y);
397 sinh_2xy = sinh(2.*x*y);
400 for(n=1.0, temp=0.; n<=2000.; n+=1.0){
404 f = exp(-n2/4.)/(n2+4.*x2);
405 /* if(f<1.E-200) break; */
406 sumr += (2.*x - 2.*x*cosh_ny*cos_2xy + n*sinh_ny*sin_2xy)*f;
407 sumi += (2.*x*cosh_ny*sin_2xy + n*sinh_ny*cos_2xy)*f;
408 temp1 = sqrt(sumr*sumr+sumi*sumi);
409 if(fabs((temp1-temp)/temp1)<1.E-16) {
415 fprintf(stderr, "iteration exceeds %lg\n",n);
425 value.r = gem_omega(x)-(f*(1.-cos_2xy)+sumr);
426 value.i = -(f*sin_2xy+sumi);
427 value = gem_cxmul(value,gem_cmplx(exp_y2*cos_2xy,exp_y2*sin_2xy));
431 /* ------------ end of [cr]error.c ------------ */
433 /*_ REVERSIBLE GEMINATE RECOMBINATION
435 * Here are the functions for reversible geminate recombination. */
437 /* Changes the unit from square cm per s to square Ångström per ps,
438 * since Omers code uses the latter units while g_mds outputs the former.
439 * g_hbond expects a diffusion coefficent given in square cm per s. */
440 static double sqcm_per_s_to_sqA_per_ps (real D) {
441 fprintf(stdout, "Diffusion coefficient is %f A^2/ps\n", D*1e4);
442 return (double)(D*1e4);
446 static double eq10v2(double theoryCt[], double time[], int manytimes,
447 double ka, double kd, t_gemParams *params)
449 /* Finding the 3 roots */
451 double kD, D, r, a, b, c, tsqrt, sumimaginary;
456 part1, part2, part3, part4;
461 a = (1.0 + ka/kD) * sqrt(D)/r;
465 gem_solve(&alpha, &beta, &gamma, a, b, c);
466 /* Finding the 3 roots */
469 part1 = gem_cxmul(alpha, gem_cxmul(gem_cxadd(beta, gamma), gem_cxsub(beta, gamma))); /* 1(2+3)(2-3) */
470 part2 = gem_cxmul(beta, gem_cxmul(gem_cxadd(gamma, alpha), gem_cxsub(gamma, alpha))); /* 2(3+1)(3-1) */
471 part3 = gem_cxmul(gamma, gem_cxmul(gem_cxadd(alpha, beta) , gem_cxsub(alpha, beta))); /* 3(1+2)(1-2) */
472 part4 = gem_cxmul(gem_cxsub(gamma, alpha), gem_cxmul(gem_cxsub(alpha, beta), gem_cxsub(beta, gamma))); /* (3-1)(1-2)(2-3) */
474 #pragma omp parallel for \
475 private(i, tsqrt, oma, omb, omc, c1, c2, c3, c4) \
476 reduction(+:sumimaginary) \
479 for (i=0; i<manytimes; i++){
480 tsqrt = sqrt(time[i]);
481 oma = gem_comega(gem_cxrmul(alpha, tsqrt));
482 c1 = gem_cxmul(oma, gem_cxdiv(part1, part4));
483 omb = gem_comega(gem_cxrmul(beta, tsqrt));
484 c2 = gem_cxmul(omb, gem_cxdiv(part2, part4));
485 omc = gem_comega(gem_cxrmul(gamma, tsqrt));
486 c3 = gem_cxmul(omc, gem_cxdiv(part3, part4));
487 c4.r = c1.r+c2.r+c3.r;
488 c4.i = c1.i+c2.i+c3.i;
490 sumimaginary += c4.i * c4.i;
497 /* This returns the real-valued index(!) to an ACF, equidistant on a log scale. */
498 static double getLogIndex(const int i, const t_gemParams *params)
500 return (exp(((double)(i)) * params->logQuota) -1);
503 extern t_gemParams *init_gemParams(const double sigma, const double D,
504 const real *t, const int len, const int nFitPoints,
505 const real begFit, const real endFit,
506 const real ballistic, const int nBalExp, const gmx_bool bDt)
513 /* A few hardcoded things here. For now anyway. */
515 /* p->ka_max = 100; */
523 /* p->lifetime = 0; */
524 p->sigma = sigma*10; /* Omer uses Ã…, not nm */
525 /* p->lsq_old = 99999; */
526 p->D = sqcm_per_s_to_sqA_per_ps(D);
527 p->kD = 4*acos(-1.0)*sigma*p->D;
530 /* Parameters used by calcsquare(). Better to calculate them
531 * here than in calcsquare every time it's called. */
533 /* p->logAfterTime = logAfterTime; */
534 tDelta = (t[len-1]-t[0]) / len;
536 gmx_fatal(FARGS, "Time between frames is non-positive!");
541 p->nExpFit = nBalExp;
542 /* p->nLin = logAfterTime / tDelta; */
543 p->nFitPoints = nFitPoints;
546 p->logQuota = (double)(log(p->len))/(p->nFitPoints-1);
547 /* if (p->nLin <= 0) { */
548 /* fprintf(stderr, "Number of data points in the linear regime is non-positive!\n"); */
552 /* We want the same number of data points in the log regime. Not crucial, but seems like a good idea. */
553 /* p->logDelta = log(((float)len)/p->nFitPoints) / p->nFitPoints;/\* log(((float)len)/p->nLin) / p->nLin; *\/ */
554 /* p->logPF = p->nFitPoints*p->nFitPoints/(float)len; /\* p->nLin*p->nLin/(float)len; *\/ */
555 /* logPF and logDelta are stitched together with the macro GETLOGINDEX defined in geminate.h */
557 /* p->logMult = pow((float)len, 1.0/nLin);/\* pow(t[len-1]-t[0], 1.0/p->nLin); *\/ */
558 p->ballistic = ballistic;
562 /* There was a misunderstanding regarding the fitting. From our
563 * recent correspondence it appears that Omer's code require
564 * the ACF data on a log-scale and does not operate on the raw data.
565 * This needs to be redone in gemFunc_residual() as well as in the
566 * t_gemParams structure. */
568 static double gemFunc_residual2(const gsl_vector *p, void *data)
571 int i, iLog, nLin, nFitPoints, nData;
572 double r, residual2, *ctTheory, *y;
574 GD = (gemFitData *)data;
575 nLin = GD->params->nLin;
576 nFitPoints = GD->params->nFitPoints;
579 ctTheory = GD->ctTheory;
582 /* Now, we'd save a lot of time by not calculating eq10v2 for all
583 * time points, but only those that we sample to calculate the mse.
586 eq10v2(GD->ctTheory, GD->doubleLogTime/* GD->time */, nFitPoints/* GD->nData */,
587 gsl_vector_get(p, 0), gsl_vector_get(p, 1),
590 fixGemACF(GD->ctTheory, nFitPoints);
592 /* Removing a bunch of points from the log-part. */
593 #pragma omp parallel for schedule(dynamic) \
594 firstprivate(nData, ctTheory, y, nFitPoints) \
595 private (i, iLog, r) \
596 reduction(+:residual2) \
598 for(i=0; i<nFitPoints; i++)
600 iLog = GD->logtime[i];
601 r = log(ctTheory[i /* iLog */]);
602 residual2 += sqr(r-log(y[iLog]));
604 residual2 /= nFitPoints; /* Not really necessary for the fitting, but gives more meaning to the returned data. */
605 /* printf("ka=%3.5f\tkd=%3.5f\trmse=%3.5f\n", gsl_vector_get(p,0), gsl_vector_get(p,1), residual2); */
608 /* for (i=0; i<nLin; i++) { */
609 /* /\* Linear part ----------*\/ */
610 /* r = ctTheory[i]; */
611 /* residual2 += sqr(r-y[i]); */
612 /* /\* Log part -------------*\/ */
613 /* iLog = GETLOGINDEX(i, GD->params); */
614 /* if (iLog >= nData) */
615 /* gmx_fatal(FARGS, "log index out of bounds: %i", iLog); */
616 /* r = ctTheory[iLog]; */
617 /* residual2 += sqr(r-y[iLog]); */
620 /* residual2 /= GD->n; */
621 /* return residual2; */
625 static real* d2r(const double *d, const int nn);
627 extern real fitGemRecomb(double *ct, double *time, double **ctFit,
628 const int nData, t_gemParams *params)
631 int nThreads, i, iter, status, maxiter;
632 real size, d2, tol, *dumpdata;
635 char *dumpstr, dumpname[128];
637 /* nmsimplex2 had convergence problems prior to gsl v1.14,
638 * but it's O(N) instead of O(N) operations, so let's use it if v >= 1.14 */
640 gsl_multimin_fminimizer *s;
641 gsl_vector *x,*dx; /* parameters and initial step size */
642 gsl_multimin_function fitFunc;
643 #ifdef GSL_MAJOR_VERSION
644 #ifdef GSL_MINOR_VERSION
645 #if ((GSL_MAJOR_VERSION == 1 && GSL_MINOR_VERSION >= 14) || \
646 (GSL_MAJOR_VERSION > 1))
647 const gsl_multimin_fminimizer_type *T = gsl_multimin_fminimizer_nmsimplex2;
649 const gsl_multimin_fminimizer_type *T = gsl_multimin_fminimizer_nmsimplex;
651 #endif /* GSL_MINOR_VERSION */
653 const gsl_multimin_fminimizer_type *T = gsl_multimin_fminimizer_nmsimplex;
654 #endif /* GSL_MAJOR_VERSION */
655 fprintf(stdout, "Will fit ka and kd to the ACF according to the reversible geminate recombination model.\n");
656 #else /* HAVE_LIBGSL */
657 fprintf(stderr, "Sorry, can't do reversible geminate recombination without gsl. "
658 "Recompile using --with-gsl.\n");
660 #endif /* HAVE_LIBGSL */
664 nThreads = gmx_omp_get_max_threads();
665 gmx_omp_set_num_threads(nThreads);
666 fprintf(stdout, "We will be using %i threads.\n", nThreads);
674 p = 2; /* Number of parameters to fit. ka and kd. */
675 n = params->nFitPoints; /* params->nLin*2 */; /* Number of points in the reduced dataset */
679 fprintf(stderr, "Fitting of D is not implemented yet. It must be provided on the command line.\n");
684 /* fprintf(stderr, "Reduced data set larger than the complete data set!\n"); */
687 snew(dumpdata, nData);
693 snew(GD->ctTheory, nData);
699 GD->tDelta = time[1]-time[0];
702 snew(GD->logtime,params->nFitPoints);
703 snew(GD->doubleLogTime,params->nFitPoints);
705 for (i=0; i<params->nFitPoints; i++)
707 GD->doubleLogTime[i] = (double)(getLogIndex(i, params));
708 GD->logtime[i] = (int)(GD->doubleLogTime[i]);
709 GD->doubleLogTime[i]*=GD->tDelta;
711 if (GD->logtime[i] >= nData)
713 fprintf(stderr, "Ayay. It seems we're indexing out of bounds.\n");
714 params->nFitPoints = i;
718 fitFunc.f = &gemFunc_residual2;
720 fitFunc.params = (void*)GD;
722 x = gsl_vector_alloc (fitFunc.n);
723 dx = gsl_vector_alloc (fitFunc.n);
724 gsl_vector_set (x, 0, 25);
725 gsl_vector_set (x, 1, 0.5);
726 gsl_vector_set (dx, 0, 0.1);
727 gsl_vector_set (dx, 1, 0.01);
730 s = gsl_multimin_fminimizer_alloc (T, fitFunc.n);
731 gsl_multimin_fminimizer_set (s, &fitFunc, x, dx);
733 gsl_vector_free (dx);
737 status = gsl_multimin_fminimizer_iterate (s);
740 gmx_fatal(FARGS,"Something went wrong in the iteration in minimizer %s:\n \"%s\"\n",
741 gsl_multimin_fminimizer_name(s), gsl_strerror(status));
743 d2 = gsl_multimin_fminimizer_minimum(s);
744 size = gsl_multimin_fminimizer_size(s);
745 params->ka = gsl_vector_get (s->x, 0);
746 params->kd = gsl_vector_get (s->x, 1);
750 fprintf(stderr, "%s\n", gsl_strerror(status));
754 status = gsl_multimin_test_size(size,tol);
756 if (status == GSL_SUCCESS) {
757 fprintf(stdout, "Converged to minimum at\n");
760 printf ("iter %5d: ka = %2.5f kd = %2.5f f() = %7.3f size = %.3f chi2 = %2.5f\n",
768 eq10v2(GD->ctTheory, time, nData, params->ka, params->kd, params);
769 /* fixGemACF(GD->ctTheory, nFitPoints); */
770 sprintf(dumpname, "Iter_%i.xvg", iter);
771 for(i=0; i<GD->nData; i++)
773 dumpdata[i] = (real)(GD->ctTheory[i]);
774 if (!gmx_isfinite(dumpdata[i]))
776 gmx_fatal(FARGS, "Non-finite value in acf.");
779 dumpN(dumpdata, GD->nData, dumpname);
782 while ((status == GSL_CONTINUE) && (iter < maxiter));
784 /* /\* Calculate the theoretical ACF from the parameters one last time. *\/ */
785 eq10v2(GD->ctTheory, time, nData, params->ka, params->kd, params);
786 *ctFit = GD->ctTheory;
789 gsl_multimin_fminimizer_free (s);
794 #endif /* HAVE_LIBGSL */
798 static int balFunc_f(const gsl_vector *x, void *data, gsl_vector *f)
800 /* C + sum{ A_i * exp(-B_i * t) }*/
804 double *y, *A, *B, C, /* There are the parameters to be optimized. */
807 BD = (balData *)data;
814 for (i = 0; i<nexp; i++)
816 A[i] = gsl_vector_get(x, i*2);
817 B[i] = gsl_vector_get(x, i*2+1);
819 C = gsl_vector_get(x, nexp*2);
825 for (j=0; j<nexp; j++) {
826 ct += A[j] * exp(B[j] * t);
829 gsl_vector_set (f, i, ct - y[i]);
834 /* The derivative stored in jacobian form (J)*/
835 static int balFunc_df(const gsl_vector *params, void *data, gsl_matrix *J)
839 double *y, *A, *B, C, /* There are the parameters. */
851 for (i=0; i<nexp; i++)
853 A[i] = gsl_vector_get(params, i*2);
854 B[i] = gsl_vector_get(params, i*2+1);
856 C = gsl_vector_get(params, nexp*2);
860 for (j=0; j<nexp; j++)
862 gsl_matrix_set (J, i, j*2, exp(B[j]*t)); /* df(t)/dA_j */
863 gsl_matrix_set (J, i, j*2+1, A[j]*t*exp(B[j]*t)); /* df(t)/dB_j */
865 gsl_matrix_set (J, i, nexp*2, 1); /* df(t)/dC */
870 /* Calculation of the function and its derivative */
871 static int balFunc_fdf(const gsl_vector *params, void *data,
872 gsl_vector *f, gsl_matrix *J)
874 balFunc_f(params, data, f);
875 balFunc_df(params, data, J);
878 #endif /* HAVE_LIBGSL */
880 /* Removes the ballistic term from the beginning of the ACF,
881 * just like in Omer's paper.
883 extern void takeAwayBallistic(double *ct, double *t, int len, real tMax, int nexp, gmx_bool bDerivative)
886 /* Use nonlinear regression with GSL instead.
887 * Fit with 4 exponentials and one constant term,
888 * subtract the fatest exponential. */
890 int nData,i,status, iter;
892 double *guess, /* Initial guess. */
893 *A, /* The fitted parameters. (A1, B1, A2, B2,... C) */
903 } while (t[nData]<tMax+t[0] && nData<len);
905 p = nexp*2+1; /* Number of parameters. */
908 const gsl_multifit_fdfsolver_type *T
909 = gsl_multifit_fdfsolver_lmsder;
911 gsl_multifit_fdfsolver *s; /* The solver itself. */
912 gsl_multifit_function_fdf fitFunction; /* The function to be fitted. */
913 gsl_matrix *covar; /* Covariance matrix for the parameters.
914 * We'll not use the result, though. */
915 gsl_vector_view theParams;
920 } while (t[nData]<tMax+t[0] && nData<len);
927 covar = gsl_matrix_alloc (p, p);
929 /* Set up an initial gess for the parameters.
930 * The solver is somewhat sensitive to the initial guess,
931 * but this worked fine for a TIP3P box with -geminate dd
932 * EDIT: In fact, this seems like a good starting pont for other watermodels too. */
933 for (i=0; i<nexp; i++)
936 guess[i*2+1] = -0.5 + (((double)i)/nexp - 0.5)*0.3;
938 guess[nexp * 2] = 0.01;
940 theParams = gsl_vector_view_array(guess, p);
945 BD->tDelta = t[1]-t[0];
948 fitFunction.f = &balFunc_f;
949 fitFunction.df = &balFunc_df;
950 fitFunction.fdf = &balFunc_fdf;
951 fitFunction.n = nData;
953 fitFunction.params = BD;
955 s = gsl_multifit_fdfsolver_alloc (T, nData, p);
957 gmx_fatal(FARGS, "Could not set up the nonlinear solver.");
959 gsl_multifit_fdfsolver_set(s, &fitFunction, &theParams.vector);
961 /* \=============================================/ */
967 status = gsl_multifit_fdfsolver_iterate (s);
971 status = gsl_multifit_test_delta (s->dx, s->x, 1e-4, 1e-4);
973 while (iter < 5000 && status == GSL_CONTINUE);
977 fprintf(stderr, "The non-linear fitting did not converge in 5000 steps.\n"
978 "Check the quality of the fit!\n");
982 fprintf(stderr, "Non-linear fitting of ballistic term converged in %d steps.\n\n", (int)iter);
984 for (i=0; i<nexp; i++) {
985 fprintf(stdout, "%c * exp(%c * t) + ", 'A'+(char)i*2, 'B'+(char)i*2);
988 fprintf(stdout, "%c\n", 'A'+(char)nexp*2);
989 fprintf(stdout, "Here are the actual numbers for A-%c:\n", 'A'+nexp*2);
991 for (i=0; i<nexp; i++)
993 A[i*2] = gsl_vector_get(s->x, i*2);
994 A[i*2+1] = gsl_vector_get(s->x, i*2+1);
995 fprintf(stdout, " %g*exp(%g * x) +", A[i*2], A[i*2+1]);
997 A[i*2] = gsl_vector_get(s->x, i*2); /* The last and constant term */
998 fprintf(stdout, " %g\n", A[i*2]);
1002 /* Implement some check for parameter quality */
1003 for (i=0; i<nexp; i++)
1005 if (A[i*2]<0 || A[i*2]>1) {
1006 fprintf(stderr, "WARNING: ----------------------------------\n"
1007 " | A coefficient does not lie within [0,1].\n"
1008 " | This may or may not be a problem.\n"
1009 " | Double check the quality of the fit!\n");
1012 fprintf(stderr, "WARNING: ----------------------------------\n"
1013 " | One factor in the exponent is positive.\n"
1014 " | This could be a problem if the coefficient\n"
1015 " | is large. Double check the quality of the fit!\n");
1018 if (A[i*2]<0 || A[i*2]>1) {
1019 fprintf(stderr, "WARNING: ----------------------------------\n"
1020 " | The constant term does not lie within [0,1].\n"
1021 " | This may or may not be a problem.\n"
1022 " | Double check the quality of the fit!\n");
1025 /* Sort the terms */
1026 sorted = (nexp > 1) ? FALSE : TRUE;
1030 for (i=0;i<nexp-1;i++)
1032 ddt[0] = A[i*2] * A[i*2+1];
1033 ddt[1] =A[i*2+2] * A[i*2+3];
1035 if ((bDerivative && (ddt[0]<0 && ddt[1]<0 && ddt[0]>ddt[1])) || /* Compare derivative at t=0... */
1036 (!bDerivative && (A[i*2+1] > A[i*2+3]))) /* Or just the coefficient in the exponent */
1039 a[0] = A[i*2]; /* coefficient */
1040 a[1] = A[i*2+1]; /* parameter in the exponent */
1043 A[i*2+1] = A[i*2+3];
1051 /* Subtract the fastest component */
1052 fprintf(stdout, "Fastest component is %g * exp(%g * t)\n"
1053 "Subtracting fastest component from ACF.\n", A[0], A[1]);
1055 for (i=0; i<len; i++) {
1056 ct[i] = (ct[i] - A[0] * exp(A[1] * i*BD->tDelta)) / (1-A[0]);
1062 gsl_multifit_fdfsolver_free(s);
1063 gsl_matrix_free(covar);
1067 /* We have no gsl. */
1068 fprintf(stderr, "Sorry, can't take away ballistic component without gsl. "
1069 "Recompile using --with-gsl.\n");
1071 #endif /* HAVE_LIBGSL */
1075 extern void dumpN(const real *e, const int nn, char *fn)
1077 /* For debugging only */
1080 char standardName[] = "Nt.xvg";
1088 "@ xaxis label \"Frame\"\n"
1089 "@ yaxis label \"N\"\n"
1090 "@ s0 line type 3\n");
1092 for (i=0; i<nn; i++) {
1093 fprintf(f, "%-10i %-g\n", i, e[i]);
1099 static real* d2r(const double *d, const int nn)
1105 for (i=0; i<nn; i++)
1111 static void _patchBad(double *ct, int n, double dy)
1113 /* Just do lin. interpolation for now. */
1122 static void patchBadPart(double *ct, int n)
1124 _patchBad(ct,n,(ct[n] - ct[0])/n);
1127 static void patchBadTail(double *ct, int n)
1129 _patchBad(ct+1,n-1,ct[1]-ct[0]);
1133 extern void fixGemACF(double *ct, int len)
1138 /* Let's separate two things:
1139 * - identification of bad parts
1140 * - patching of bad parts.
1143 b = 0; /* Start of a bad stretch */
1144 e = 0; /* End of a bad stretch */
1147 /* An acf of binary data must be one at t=0. */
1148 if (abs(ct[0]-1.0) > 1e-6)
1151 fprintf(stderr, "|ct[0]-1.0| = %1.6d. Setting ct[0] to 1.0.\n", abs(ct[0]-1.0));
1154 for (i=0; i<len; i++)
1158 if (isfinite(ct[i]))
1159 #elif defined(HAS__ISFINITE)
1160 if (_isfinite(ct[i]))
1167 /* Still on a good stretch. Proceed.*/
1171 /* Patch up preceding bad stretch. */
1177 gmx_fatal(FARGS, "The ACF is mostly NaN or Inf. Aborting.");
1179 patchBadTail(&(ct[b-2]), (len-b)+1);
1183 patchBadPart(&(ct[b-1]), (e-b)+1);