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; }
/*! \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; }