/*! \brief Print chi-squared value and the parameters */ static void print_chi2_params(FILE *fp, const int eFitFn, const double fitparms[], const char *label, const int nfitpnts, const double x[], const double y[]) { int i; double chi2 = 0; for (i = 0; (i < nfitpnts); i++) { double yfit = lmcurves[eFitFn](x[i], fitparms); chi2 += gmx::square(y[i] - yfit); } fprintf(fp, "There are %d data points, %d parameters, %s chi2 = %g\nparams:", nfitpnts, effnNparams(eFitFn), label, chi2); for (i = 0; (i < effnNparams(eFitFn)); i++) { fprintf(fp, " %10g", fitparms[i]); } fprintf(fp, "\n"); }
bool lmfit_exp(int nfit, const double x[], const double y[], const double dy[], double parm[], // NOLINT(readability-non-const-parameter) bool bVerbose, int eFitFn, int nfix) { if ((eFitFn < 0) || (eFitFn >= effnNR)) { fprintf(stderr, "fitfn = %d, should be in the range 0..%d\n", eFitFn, effnNR-1); return false; } #if HAVE_LMFIT double chisq, ochisq; gmx_bool bCont; int j; int maxiter = 100; lm_control_struct control; lm_status_struct *status; int nparam = effnNparams(eFitFn); int p2; gmx_bool bSkipLast; /* Using default control structure for double precision fitting that * comes with the lmfit package (i.e. from the include file). */ control = lm_control_double; control.verbosity = (bVerbose ? 1 : 0); control.n_maxpri = 0; control.m_maxpri = 0; snew(status, 1); /* Initial params */ chisq = 1e12; j = 0; if (bVerbose) { printf("%4s %10s Parameters\n", "Step", "chi^2"); } /* Check whether we have to skip some params */ if (nfix > 0) { do { p2 = 1 << (nparam-1); bSkipLast = ((p2 & nfix) == p2); if (bSkipLast) { nparam--; nfix -= p2; } } while ((nparam > 0) && (bSkipLast)); if (bVerbose) { printf("Using %d out of %d parameters\n", nparam, effnNparams(eFitFn)); } } do { ochisq = chisq; gmx_lmcurve(nparam, parm, nfit, x, y, dy, lmcurves[eFitFn], &control, status); chisq = gmx::square(status->fnorm); if (bVerbose) { printf("status: fnorm = %g, nfev = %d, userbreak = %d\noutcome = %s\n", status->fnorm, status->nfev, status->userbreak, lm_infmsg[status->outcome]); } if (bVerbose) { int mmm; printf("%4d %8g", j, chisq); for (mmm = 0; (mmm < effnNparams(eFitFn)); mmm++) { printf(" %8g", parm[mmm]); } printf("\n"); } j++; bCont = (fabs(ochisq - chisq) > fabs(control.ftol*chisq)); } while (bCont && (j < maxiter)); sfree(status); #else gmx_fatal(FARGS, "This build of GROMACS was not configured with support " "for lmfit, so the requested fitting cannot be performed. " "See the install guide for instructions on how to build " "GROMACS with lmfit supported."); GMX_UNUSED_VALUE(nfit); GMX_UNUSED_VALUE(x); GMX_UNUSED_VALUE(y); GMX_UNUSED_VALUE(dy); GMX_UNUSED_VALUE(parm); GMX_UNUSED_VALUE(bVerbose); GMX_UNUSED_VALUE(eFitFn); GMX_UNUSED_VALUE(nfix); #endif return true; }
real fit_acf(int ncorr, int fitfn, const gmx_output_env_t *oenv, gmx_bool bVerbose, real tbeginfit, real tendfit, real dt, real c1[], real *fit) { double fitparm[3]; double tStart, tail_corr, sum, sumtot = 0, c_start, ct_estimate; real *sig; int i, j, jmax, nf_int; gmx_bool bPrint; bPrint = bVerbose || bDebugMode(); if (bPrint) { printf("COR:\n"); } if (tendfit <= 0) { tendfit = ncorr*dt; } nf_int = std::min(ncorr, (int)(tendfit/dt)); sum = print_and_integrate(debug, nf_int, dt, c1, NULL, 1); if (bPrint) { printf("COR: Correlation time (plain integral from %6.3f to %6.3f ps) = %8.5f ps\n", 0.0, dt*nf_int, sum); printf("COR: Relaxation times are computed as fit to an exponential:\n"); printf("COR: %s\n", effnDescription(fitfn)); printf("COR: Fit to correlation function from %6.3f ps to %6.3f ps, results in a\n", tbeginfit, std::min(ncorr*dt, tendfit)); } tStart = 0; if (bPrint) { printf("COR:%11s%11s%11s%11s%11s%11s%11s\n", "Fit from", "Integral", "Tail Value", "Sum (ps)", " a1 (ps)", (effnNparams(fitfn) >= 2) ? " a2 ()" : "", (effnNparams(fitfn) >= 3) ? " a3 (ps)" : ""); } snew(sig, ncorr); if (tbeginfit > 0) { jmax = 3; } else { jmax = 1; } for (j = 0; ((j < jmax) && (tStart < tendfit) && (tStart < ncorr*dt)); j++) { /* Estimate the correlation time for better fitting */ c_start = -1; ct_estimate = 0; for (i = 0; (i < ncorr) && (dt*i < tStart || c1[i] > 0); i++) { if (c_start < 0) { if (dt*i >= tStart) { c_start = c1[i]; ct_estimate = 0.5*c1[i]; } } else { ct_estimate += c1[i]; } } if (c_start > 0) { ct_estimate *= dt/c_start; } else { /* The data is strange, so we need to choose somehting */ ct_estimate = tendfit; } if (debug) { fprintf(debug, "tStart %g ct_estimate: %g\n", tStart, ct_estimate); } if (fitfn == effnEXPEXP) { fitparm[0] = 0.002*ncorr*dt; fitparm[1] = 0.95; fitparm[2] = 0.2*ncorr*dt; } else { /* Good initial guess, this increases the probability of convergence */ fitparm[0] = ct_estimate; fitparm[1] = 1.0; fitparm[2] = 1.0; } /* Generate more or less appropriate sigma's */ for (i = 0; i < ncorr; i++) { sig[i] = sqrt(ct_estimate+dt*i); } nf_int = std::min(ncorr, (int)((tStart+1e-4)/dt)); sum = print_and_integrate(debug, nf_int, dt, c1, NULL, 1); tail_corr = do_lmfit(ncorr, c1, sig, dt, NULL, tStart, tendfit, oenv, bDebugMode(), fitfn, fitparm, 0, NULL); sumtot = sum+tail_corr; if (fit && ((jmax == 1) || (j == 1))) { double mfp[3]; for (i = 0; (i < 3); i++) { mfp[i] = fitparm[i]; } for (i = 0; (i < ncorr); i++) { fit[i] = lmcurves[fitfn](i*dt, mfp); } } if (bPrint) { printf("COR:%11.4e%11.4e%11.4e%11.4e", tStart, sum, tail_corr, sumtot); for (i = 0; (i < effnNparams(fitfn)); i++) { printf(" %11.4e", fitparm[i]); } printf("\n"); } tStart += tbeginfit; } sfree(sig); return sumtot; }
real do_lmfit(int ndata, real c1[], real sig[], real dt, real *x0, real begintimefit, real endtimefit, const gmx_output_env_t *oenv, gmx_bool bVerbose, int eFitFn, double fitparms[], int fix, const char *fn_fitted) { FILE *fp; int i, j, nfitpnts; double integral, ttt; double *x, *y, *dy; if (0 != fix) { fprintf(stderr, "Using fixed parameters in curve fitting is temporarily not working.\n"); } if (debug) { fprintf(debug, "There are %d points to fit %d vars!\n", ndata, effnNparams(eFitFn)); fprintf(debug, "Fit to function %d from %g through %g, dt=%g\n", eFitFn, begintimefit, endtimefit, dt); } snew(x, ndata); snew(y, ndata); snew(dy, ndata); j = 0; for (i = 0; i < ndata; i++) { ttt = x0 ? x0[i] : dt*i; if (ttt >= begintimefit && ttt <= endtimefit) { x[j] = ttt; y[j] = c1[i]; if (NULL == sig) { // No weighting if all values are divided by 1. dy[j] = 1; } else { dy[j] = std::max(1.0e-7, (double)sig[i]); } if (debug) { fprintf(debug, "j= %d, i= %d, x= %g, y= %g, dy=%g, ttt=%g\n", j, i, x[j], y[j], dy[j], ttt); } j++; } } nfitpnts = j; integral = 0; if (nfitpnts < effnNparams(eFitFn)) { fprintf(stderr, "Not enough (%d) data points for fitting, dt = %g!\n", nfitpnts, dt); } else { gmx_bool bSuccess; if (bVerbose) { print_chi2_params(stdout, eFitFn, fitparms, "initial", nfitpnts, x, y); } initiate_fit_params(eFitFn, fitparms); bSuccess = lmfit_exp(nfitpnts, x, y, dy, fitparms, bVerbose, eFitFn, fix); extract_fit_params(eFitFn, fitparms); if (!bSuccess) { fprintf(stderr, "Fit failed!\n"); } else { if (bVerbose) { print_chi2_params(stdout, eFitFn, fitparms, "final", nfitpnts, x, y); } switch (eFitFn) { case effnEXP1: integral = fitparms[0]*myexp(begintimefit, 1, fitparms[0]); break; case effnEXP2: integral = fitparms[0]*myexp(begintimefit, fitparms[1], fitparms[0]); break; case effnEXPEXP: integral = (fitparms[0]*myexp(begintimefit, fitparms[1], fitparms[0]) + fitparms[2]*myexp(begintimefit, 1-fitparms[1], fitparms[2])); break; case effnEXP5: case effnEXP7: case effnEXP9: integral = 0; for (i = 0; (i < (effnNparams(eFitFn)-1)/2); i++) { integral += fitparms[2*i]*myexp(begintimefit, fitparms[2*i+1], fitparms[2*i]); } break; default: /* Do numerical integration */ integral = 0; for (i = 0; (i < nfitpnts-1); i++) { double y0 = lmcurves[eFitFn](x[i], fitparms); double y1 = lmcurves[eFitFn](x[i+1], fitparms); integral += (x[i+1]-x[i])*(y1+y0)*0.5; } break; } if (bVerbose) { printf("FIT: Integral of fitted function: %g\n", integral); if ((effnEXP5 == eFitFn) || (effnEXP7 == eFitFn) || (effnEXP9 == eFitFn)) { printf("FIT: Note that the constant term is not taken into account when computing integral.\n"); } } /* Generate debug output */ if (NULL != fn_fitted) { fp = xvgropen(fn_fitted, "Data + Fit", "Time (ps)", "Data (t)", oenv); for (i = 0; (i < effnNparams(eFitFn)); i++) { fprintf(fp, "# fitparms[%d] = %g\n", i, fitparms[i]); } for (j = 0; (j < nfitpnts); j++) { real ttt = x0 ? x0[j] : dt*j; fprintf(fp, "%10.5e %10.5e %10.5e\n", x[j], y[j], (lmcurves[eFitFn])(ttt, fitparms)); } xvgrclose(fp); } } } sfree(x); sfree(y); sfree(dy); return integral; }
/*! \brief Process the fitting parameters to get output parameters. * * See comment at the previous function. */ static void extract_fit_params(int eFitFn, double params[]) { int i, nparm; nparm = effnNparams(eFitFn); switch (eFitFn) { case effnVAC: params[0] = fabs(params[0]); break; case effnEXP1: case effnEXP2: case effnEXPEXP: params[0] = fabs(params[0]); if (nparm > 2) { /* Back conversion of parameters from the fitted difference * to the absolute value. */ params[2] = fabs(params[2])+params[0]; } break; case effnEXP5: case effnEXP7: case effnEXP9: params[1] = fabs(params[1]); if (nparm > 3) { /* See comment under effnEXPEXP */ params[3] = fabs(params[3])+params[1]; if (nparm > 5) { /* See comment under effnEXPEXP */ params[5] = fabs(params[5])+params[3]; if (nparm > 7) { /* See comment under effnEXPEXP */ params[7] = fabs(params[7])+params[5]; } } } break; case effnERREST: params[0] = fabs(params[0]); if (params[1] < 0) { params[1] = 0; } else if (params[1] > 1) { params[1] = 1; } /* See comment under effnEXPEXP */ params[2] = params[0]+fabs(params[2]); break; case effnPRES: for (i = 1; (i < nparm); i++) { params[i] = fabs(params[i]); } break; default: break; } }
/*! \brief Ensure the fitting parameters are well-behaved. * * In order to make sure that fitting behaves according to the * constraint that time constants are positive and increasing * we enforce this here by setting all time constants to their * absolute value and by adding e.g. |a_0| to |a_2|. This is * done in conjunction with the fitting functions themselves. * When there are multiple time constants we make sure that * the successive time constants are at least double the * previous ones and during fitting we enforce the they remain larger. * It may very well help the convergence of the fitting routine. */ static void initiate_fit_params(int eFitFn, double params[]) { int i, nparm; nparm = effnNparams(eFitFn); switch (eFitFn) { case effnVAC: GMX_ASSERT(params[0] >= 0, "parameters should be >= 0"); break; case effnEXP1: case effnEXP2: case effnEXPEXP: GMX_ASSERT(params[0] >= 0, "parameters should be >= 0"); if (nparm > 2) { GMX_ASSERT(params[2] >= 0, "parameters should be >= 0"); /* In order to maintain params[2] >= params[0] in the final * result, we fit the difference between the two, that is * params[2]-params[0] and in the add add in params[0] * again. */ params[2] = std::max(fabs(params[2])-params[0], params[0]); } break; case effnEXP5: case effnEXP7: case effnEXP9: GMX_ASSERT(params[1] >= 0, "parameters should be >= 0"); params[1] = fabs(params[1]); if (nparm > 3) { GMX_ASSERT(params[3] >= 0, "parameters should be >= 0"); /* See comment under effnEXPEXP */ params[3] = std::max(fabs(params[3])-params[1], params[1]); if (nparm > 5) { GMX_ASSERT(params[5] >= 0, "parameters should be >= 0"); /* See comment under effnEXPEXP */ params[5] = std::max(fabs(params[5])-params[3], params[3]); if (nparm > 7) { GMX_ASSERT(params[7] >= 0, "parameters should be >= 0"); /* See comment under effnEXPEXP */ params[7] = std::max(fabs(params[7])-params[5], params[5]); } } } break; case effnERREST: GMX_ASSERT(params[0] >= 0, "parameters should be >= 0"); GMX_ASSERT(params[1] >= 0 && params[1] <= 1, "parameter 1 should in 0 .. 1"); GMX_ASSERT(params[2] >= 0, "parameters should be >= 0"); /* See comment under effnEXPEXP */ params[2] = fabs(params[2])-params[0]; break; case effnPRES: for (i = 1; (i < nparm); i++) { GMX_ASSERT(params[i] >= 0, "parameters should be >= 0"); } break; default: break; } }
/*! \brief lmfit_exp supports fitting of different functions * * This routine calls the Levenberg-Marquardt non-linear fitting * routine for fitting a data set with errors to a target function. * Fitting routines included in gromacs in src/external/lmfit. */ static gmx_bool lmfit_exp(int nfit, const double x[], const double y[], const double dy[], double parm[], gmx_bool bVerbose, int eFitFn, int nfix) { double chisq, ochisq; gmx_bool bCont; int j; int maxiter = 100; lm_control_struct control; lm_status_struct *status; int nparam = effnNparams(eFitFn); int p2; gmx_bool bSkipLast; if ((eFitFn < 0) || (eFitFn >= effnNR)) { fprintf(stderr, "fitfn = %d, should be in the range 0..%d\n", eFitFn, effnNR-1); return FALSE; } /* Using default control structure for double precision fitting that * comes with the lmfit package (i.e. from the include file). */ control = lm_control_double; control.verbosity = (bVerbose ? 1 : 0); control.n_maxpri = 0; control.m_maxpri = 0; snew(status, 1); /* Initial params */ chisq = 1e12; j = 0; if (bVerbose) { printf("%4s %10s Parameters\n", "Step", "chi^2"); } /* Check whether we have to skip some params */ if (nfix > 0) { do { p2 = 1 << (nparam-1); bSkipLast = ((p2 & nfix) == p2); if (bSkipLast) { nparam--; nfix -= p2; } } while ((nparam > 0) && (bSkipLast)); if (bVerbose) { printf("Using %d out of %d parameters\n", nparam, effnNparams(eFitFn)); } } do { ochisq = chisq; gmx_lmcurve(nparam, parm, nfit, x, y, dy, lmcurves[eFitFn], &control, status); chisq = gmx::square(status->fnorm); if (bVerbose) { printf("status: fnorm = %g, nfev = %d, userbreak = %d\noutcome = %s\n", status->fnorm, status->nfev, status->userbreak, lm_infmsg[status->outcome]); } if (bVerbose) { int mmm; printf("%4d %8g", j, chisq); for (mmm = 0; (mmm < effnNparams(eFitFn)); mmm++) { printf(" %8g", parm[mmm]); } printf("\n"); } j++; bCont = (fabs(ochisq - chisq) > fabs(control.ftol*chisq)); } while (bCont && (j < maxiter)); sfree(status); return TRUE; }
int gmx_dielectric(int argc, char *argv[]) { const char *desc[] = { "[THISMODULE] calculates frequency dependent dielectric constants", "from the autocorrelation function of the total dipole moment in", "your simulation. This ACF can be generated by [gmx-dipoles].", "The functional forms of the available functions are:[PAR]", "One parameter: y = [EXP]-a[SUB]1[sub] x[exp],[BR]", "Two parameters: y = a[SUB]2[sub] [EXP]-a[SUB]1[sub] x[exp],[BR]", "Three parameters: y = a[SUB]2[sub] [EXP]-a[SUB]1[sub] x[exp] + (1 - a[SUB]2[sub]) [EXP]-a[SUB]3[sub] x[exp].[BR]", "Start values for the fit procedure can be given on the command line.", "It is also possible to fix parameters at their start value, use [TT]-fix[tt]", "with the number of the parameter you want to fix.", "[PAR]", "Three output files are generated, the first contains the ACF,", "an exponential fit to it with 1, 2 or 3 parameters, and the", "numerical derivative of the combination data/fit.", "The second file contains the real and imaginary parts of the", "frequency-dependent dielectric constant, the last gives a plot", "known as the Cole-Cole plot, in which the imaginary", "component is plotted as a function of the real component.", "For a pure exponential relaxation (Debye relaxation) the latter", "plot should be one half of a circle." }; t_filenm fnm[] = { { efXVG, "-f", "dipcorr", ffREAD }, { efXVG, "-d", "deriv", ffWRITE }, { efXVG, "-o", "epsw", ffWRITE }, { efXVG, "-c", "cole", ffWRITE } }; #define NFILE asize(fnm) output_env_t oenv; int i, j, nx, ny, nxtail, eFitFn, nfitparm; real dt, integral, fitintegral, fac, rffac; double *fitparms; double **yd; real **y; const char *legend[] = { "Correlation", "Std. Dev.", "Fit", "Combined", "Derivative" }; static int fix = 0, bX = 1, nsmooth = 3; static real tendInt = 5.0, tbegin = 5.0, tend = 500.0; static real A = 0.5, tau1 = 10.0, tau2 = 1.0, eps0 = 80, epsRF = 78.5, tail = 500.0; real lambda; t_pargs pa[] = { { "-x1", FALSE, etBOOL, {&bX}, "use first column as [IT]x[it]-axis rather than first data set" }, { "-eint", FALSE, etREAL, {&tendInt}, "Time to end the integration of the data and start to use the fit"}, { "-bfit", FALSE, etREAL, {&tbegin}, "Begin time of fit" }, { "-efit", FALSE, etREAL, {&tend}, "End time of fit" }, { "-tail", FALSE, etREAL, {&tail}, "Length of function including data and tail from fit" }, { "-A", FALSE, etREAL, {&A}, "Start value for fit parameter A" }, { "-tau1", FALSE, etREAL, {&tau1}, "Start value for fit parameter [GRK]tau[grk]1" }, { "-tau2", FALSE, etREAL, {&tau2}, "Start value for fit parameter [GRK]tau[grk]2" }, { "-eps0", FALSE, etREAL, {&eps0}, "[GRK]epsilon[grk]0 of your liquid" }, { "-epsRF", FALSE, etREAL, {&epsRF}, "[GRK]epsilon[grk] of the reaction field used in your simulation. A value of 0 means infinity." }, { "-fix", FALSE, etINT, {&fix}, "Fix parameters at their start values, A (2), tau1 (1), or tau2 (4)" }, { "-ffn", FALSE, etENUM, {s_ffn}, "Fit function" }, { "-nsmooth", FALSE, etINT, {&nsmooth}, "Number of points for smoothing" } }; if (!parse_common_args(&argc, argv, PCA_CAN_TIME | PCA_CAN_VIEW, NFILE, fnm, asize(pa), pa, asize(desc), desc, 0, NULL, &oenv)) { return 0; } please_cite(stdout, "Spoel98a"); printf("WARNING: non-polarizable models can never yield an infinite\n" "dielectric constant that is different from 1. This is incorrect\n" "in the reference given above (Spoel98a).\n\n"); nx = read_xvg(opt2fn("-f", NFILE, fnm), &yd, &ny); dt = yd[0][1] - yd[0][0]; nxtail = min(tail/dt, nx); printf("Read data set containing %d colums and %d rows\n", ny, nx); printf("Assuming (from data) that timestep is %g, nxtail = %d\n", dt, nxtail); snew(y, 6); for (i = 0; (i < ny); i++) { snew(y[i], max(nx, nxtail)); } for (i = 0; (i < nx); i++) { y[0][i] = yd[0][i]; for (j = 1; (j < ny); j++) { y[j][i] = yd[j][i]; } } if (nxtail > nx) { for (i = nx; (i < nxtail); i++) { y[0][i] = dt*i+y[0][0]; for (j = 1; (j < ny); j++) { y[j][i] = 0.0; } } nx = nxtail; } /* We have read a file WITHOUT standard deviations, so we make our own... */ if (ny == 2) { printf("Creating standard deviation numbers ...\n"); srenew(y, 3); snew(y[2], nx); fac = 1.0/((real)nx); for (i = 0; (i < nx); i++) { y[2][i] = fac; } } eFitFn = sffn2effn(s_ffn); nfitparm = effnNparams(eFitFn); snew(fitparms, 4); fitparms[0] = tau1; if (nfitparm > 1) { fitparms[1] = A; } if (nfitparm > 2) { fitparms[2] = tau2; } snew(y[3], nx); snew(y[4], nx); snew(y[5], nx); integral = print_and_integrate(NULL, calc_nbegin(nx, y[0], tbegin), dt, y[1], NULL, 1); integral += do_lmfit(nx, y[1], y[2], dt, y[0], tbegin, tend, oenv, TRUE, eFitFn, fitparms, fix); for (i = 0; i < nx; i++) { y[3][i] = fit_function(eFitFn, fitparms, y[0][i]); } if (epsRF == 0) { /* This means infinity! */ lambda = 0; rffac = 1; } else { lambda = (eps0 - 1.0)/(2*epsRF - 1.0); rffac = (2*epsRF+eps0)/(2*epsRF+1); } printf("DATA INTEGRAL: %5.1f, tauD(old) = %5.1f ps, " "tau_slope = %5.1f, tau_slope,D = %5.1f ps\n", integral, integral*rffac, fitparms[0], fitparms[0]*rffac); printf("tau_D from tau1 = %8.3g , eps(Infty) = %8.3f\n", fitparms[0]*(1 + fitparms[1]*lambda), 1 + ((1 - fitparms[1])*(eps0 - 1))/(1 + fitparms[1]*lambda)); fitintegral = numerical_deriv(nx, y[0], y[1], y[3], y[4], y[5], tendInt, nsmooth); printf("FIT INTEGRAL (tau_M): %5.1f, tau_D = %5.1f\n", fitintegral, fitintegral*rffac); /* Now we have the negative gradient of <Phi(0) Phi(t)> */ write_xvg(opt2fn("-d", NFILE, fnm), "Data", nx-1, 6, y, legend, oenv); /* Do FFT and analysis */ do_four(opt2fn("-o", NFILE, fnm), opt2fn("-c", NFILE, fnm), nx-1, y[0], y[5], eps0, epsRF, oenv); do_view(oenv, opt2fn("-o", NFILE, fnm), "-nxy"); do_view(oenv, opt2fn("-c", NFILE, fnm), NULL); do_view(oenv, opt2fn("-d", NFILE, fnm), "-nxy"); return 0; }
static void do_fit(FILE *out, int n, gmx_bool bYdy, int ny, real *x0, real **val, int npargs, t_pargs *ppa, const gmx_output_env_t *oenv, const char *fn_fitted) { real *c1 = NULL, *sig = NULL; double *fitparm; real tendfit, tbeginfit; int i, efitfn, nparm; efitfn = get_acffitfn(); nparm = effnNparams(efitfn); fprintf(out, "Will fit to the following function:\n"); fprintf(out, "%s\n", effnDescription(efitfn)); c1 = val[n]; if (bYdy) { c1 = val[n]; sig = val[n+1]; fprintf(out, "Using two columns as y and sigma values\n"); } else { snew(sig, ny); } if (opt2parg_bSet("-beginfit", npargs, ppa)) { tbeginfit = opt2parg_real("-beginfit", npargs, ppa); } else { tbeginfit = x0[0]; } if (opt2parg_bSet("-endfit", npargs, ppa)) { tendfit = opt2parg_real("-endfit", npargs, ppa); } else { tendfit = x0[ny-1]; } snew(fitparm, nparm); switch (efitfn) { case effnEXP1: fitparm[0] = 0.5; break; case effnEXP2: fitparm[0] = 0.5; fitparm[1] = c1[0]; break; case effnEXPEXP: fitparm[0] = 1.0; fitparm[1] = 0.5*c1[0]; fitparm[2] = 10.0; break; case effnEXP5: fitparm[0] = fitparm[2] = 0.5*c1[0]; fitparm[1] = 10; fitparm[3] = 40; fitparm[4] = 0; break; case effnEXP7: fitparm[0] = fitparm[2] = fitparm[4] = 0.33*c1[0]; fitparm[1] = 1; fitparm[3] = 10; fitparm[5] = 100; fitparm[6] = 0; break; case effnEXP9: fitparm[0] = fitparm[2] = fitparm[4] = fitparm[6] = 0.25*c1[0]; fitparm[1] = 0.1; fitparm[3] = 1; fitparm[5] = 10; fitparm[7] = 100; fitparm[8] = 0; break; default: fprintf(out, "Warning: don't know how to initialize the parameters\n"); for (i = 0; (i < nparm); i++) { fitparm[i] = 1; } } fprintf(out, "Starting parameters:\n"); for (i = 0; (i < nparm); i++) { fprintf(out, "a%-2d = %12.5e\n", i+1, fitparm[i]); } if (do_lmfit(ny, c1, sig, 0, x0, tbeginfit, tendfit, oenv, bDebugMode(), efitfn, fitparm, 0, fn_fitted) > 0) { for (i = 0; (i < nparm); i++) { fprintf(out, "a%-2d = %12.5e\n", i+1, fitparm[i]); } } else { fprintf(out, "No solution was found\n"); } }