|
Packit |
67cb25 |
#include <stdlib.h>
|
|
Packit |
67cb25 |
#include <stdio.h>
|
|
Packit |
67cb25 |
#include <gsl/gsl_vector.h>
|
|
Packit |
67cb25 |
#include <gsl/gsl_matrix.h>
|
|
Packit |
67cb25 |
#include <gsl/gsl_blas.h>
|
|
Packit |
67cb25 |
#include <gsl/gsl_multifit_nlinear.h>
|
|
Packit |
67cb25 |
#include <gsl/gsl_rng.h>
|
|
Packit |
67cb25 |
#include <gsl/gsl_randist.h>
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
struct data
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
double *t;
|
|
Packit |
67cb25 |
double *y;
|
|
Packit |
67cb25 |
size_t n;
|
|
Packit |
67cb25 |
};
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* model function: a * exp( -1/2 * [ (t - b) / c ]^2 ) */
|
|
Packit |
67cb25 |
double
|
|
Packit |
67cb25 |
gaussian(const double a, const double b, const double c, const double t)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
const double z = (t - b) / c;
|
|
Packit |
67cb25 |
return (a * exp(-0.5 * z * z));
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
int
|
|
Packit |
67cb25 |
func_f (const gsl_vector * x, void *params, gsl_vector * f)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
struct data *d = (struct data *) params;
|
|
Packit |
67cb25 |
double a = gsl_vector_get(x, 0);
|
|
Packit |
67cb25 |
double b = gsl_vector_get(x, 1);
|
|
Packit |
67cb25 |
double c = gsl_vector_get(x, 2);
|
|
Packit |
67cb25 |
size_t i;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
for (i = 0; i < d->n; ++i)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
double ti = d->t[i];
|
|
Packit |
67cb25 |
double yi = d->y[i];
|
|
Packit |
67cb25 |
double y = gaussian(a, b, c, ti);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
gsl_vector_set(f, i, yi - y);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
return GSL_SUCCESS;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
int
|
|
Packit |
67cb25 |
func_df (const gsl_vector * x, void *params, gsl_matrix * J)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
struct data *d = (struct data *) params;
|
|
Packit |
67cb25 |
double a = gsl_vector_get(x, 0);
|
|
Packit |
67cb25 |
double b = gsl_vector_get(x, 1);
|
|
Packit |
67cb25 |
double c = gsl_vector_get(x, 2);
|
|
Packit |
67cb25 |
size_t i;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
for (i = 0; i < d->n; ++i)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
double ti = d->t[i];
|
|
Packit |
67cb25 |
double zi = (ti - b) / c;
|
|
Packit |
67cb25 |
double ei = exp(-0.5 * zi * zi);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
gsl_matrix_set(J, i, 0, -ei);
|
|
Packit |
67cb25 |
gsl_matrix_set(J, i, 1, -(a / c) * ei * zi);
|
|
Packit |
67cb25 |
gsl_matrix_set(J, i, 2, -(a / c) * ei * zi * zi);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
return GSL_SUCCESS;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
int
|
|
Packit |
67cb25 |
func_fvv (const gsl_vector * x, const gsl_vector * v,
|
|
Packit |
67cb25 |
void *params, gsl_vector * fvv)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
struct data *d = (struct data *) params;
|
|
Packit |
67cb25 |
double a = gsl_vector_get(x, 0);
|
|
Packit |
67cb25 |
double b = gsl_vector_get(x, 1);
|
|
Packit |
67cb25 |
double c = gsl_vector_get(x, 2);
|
|
Packit |
67cb25 |
double va = gsl_vector_get(v, 0);
|
|
Packit |
67cb25 |
double vb = gsl_vector_get(v, 1);
|
|
Packit |
67cb25 |
double vc = gsl_vector_get(v, 2);
|
|
Packit |
67cb25 |
size_t i;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
for (i = 0; i < d->n; ++i)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
double ti = d->t[i];
|
|
Packit |
67cb25 |
double zi = (ti - b) / c;
|
|
Packit |
67cb25 |
double ei = exp(-0.5 * zi * zi);
|
|
Packit |
67cb25 |
double Dab = -zi * ei / c;
|
|
Packit |
67cb25 |
double Dac = -zi * zi * ei / c;
|
|
Packit |
67cb25 |
double Dbb = a * ei / (c * c) * (1.0 - zi*zi);
|
|
Packit |
67cb25 |
double Dbc = a * zi * ei / (c * c) * (2.0 - zi*zi);
|
|
Packit |
67cb25 |
double Dcc = a * zi * zi * ei / (c * c) * (3.0 - zi*zi);
|
|
Packit |
67cb25 |
double sum;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
sum = 2.0 * va * vb * Dab +
|
|
Packit |
67cb25 |
2.0 * va * vc * Dac +
|
|
Packit |
67cb25 |
vb * vb * Dbb +
|
|
Packit |
67cb25 |
2.0 * vb * vc * Dbc +
|
|
Packit |
67cb25 |
vc * vc * Dcc;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
gsl_vector_set(fvv, i, sum);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
return GSL_SUCCESS;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
void
|
|
Packit |
67cb25 |
callback(const size_t iter, void *params,
|
|
Packit |
67cb25 |
const gsl_multifit_nlinear_workspace *w)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
gsl_vector *f = gsl_multifit_nlinear_residual(w);
|
|
Packit |
67cb25 |
gsl_vector *x = gsl_multifit_nlinear_position(w);
|
|
Packit |
67cb25 |
double avratio = gsl_multifit_nlinear_avratio(w);
|
|
Packit |
67cb25 |
double rcond;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
(void) params; /* not used */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* compute reciprocal condition number of J(x) */
|
|
Packit |
67cb25 |
gsl_multifit_nlinear_rcond(&rcond, w);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
fprintf(stderr, "iter %2zu: a = %.4f, b = %.4f, c = %.4f, |a|/|v| = %.4f cond(J) = %8.4f, |f(x)| = %.4f\n",
|
|
Packit |
67cb25 |
iter,
|
|
Packit |
67cb25 |
gsl_vector_get(x, 0),
|
|
Packit |
67cb25 |
gsl_vector_get(x, 1),
|
|
Packit |
67cb25 |
gsl_vector_get(x, 2),
|
|
Packit |
67cb25 |
avratio,
|
|
Packit |
67cb25 |
1.0 / rcond,
|
|
Packit |
67cb25 |
gsl_blas_dnrm2(f));
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
void
|
|
Packit |
67cb25 |
solve_system(gsl_vector *x, gsl_multifit_nlinear_fdf *fdf,
|
|
Packit |
67cb25 |
gsl_multifit_nlinear_parameters *params)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
const gsl_multifit_nlinear_type *T = gsl_multifit_nlinear_trust;
|
|
Packit |
67cb25 |
const size_t max_iter = 200;
|
|
Packit |
67cb25 |
const double xtol = 1.0e-8;
|
|
Packit |
67cb25 |
const double gtol = 1.0e-8;
|
|
Packit |
67cb25 |
const double ftol = 1.0e-8;
|
|
Packit |
67cb25 |
const size_t n = fdf->n;
|
|
Packit |
67cb25 |
const size_t p = fdf->p;
|
|
Packit |
67cb25 |
gsl_multifit_nlinear_workspace *work =
|
|
Packit |
67cb25 |
gsl_multifit_nlinear_alloc(T, params, n, p);
|
|
Packit |
67cb25 |
gsl_vector * f = gsl_multifit_nlinear_residual(work);
|
|
Packit |
67cb25 |
gsl_vector * y = gsl_multifit_nlinear_position(work);
|
|
Packit |
67cb25 |
int info;
|
|
Packit |
67cb25 |
double chisq0, chisq, rcond;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* initialize solver */
|
|
Packit |
67cb25 |
gsl_multifit_nlinear_init(x, fdf, work);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* store initial cost */
|
|
Packit |
67cb25 |
gsl_blas_ddot(f, f, &chisq0);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* iterate until convergence */
|
|
Packit |
67cb25 |
gsl_multifit_nlinear_driver(max_iter, xtol, gtol, ftol,
|
|
Packit |
67cb25 |
callback, NULL, &info, work);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* store final cost */
|
|
Packit |
67cb25 |
gsl_blas_ddot(f, f, &chisq);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* store cond(J(x)) */
|
|
Packit |
67cb25 |
gsl_multifit_nlinear_rcond(&rcond, work);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
gsl_vector_memcpy(x, y);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* print summary */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
fprintf(stderr, "NITER = %zu\n", gsl_multifit_nlinear_niter(work));
|
|
Packit |
67cb25 |
fprintf(stderr, "NFEV = %zu\n", fdf->nevalf);
|
|
Packit |
67cb25 |
fprintf(stderr, "NJEV = %zu\n", fdf->nevaldf);
|
|
Packit |
67cb25 |
fprintf(stderr, "NAEV = %zu\n", fdf->nevalfvv);
|
|
Packit |
67cb25 |
fprintf(stderr, "initial cost = %.12e\n", chisq0);
|
|
Packit |
67cb25 |
fprintf(stderr, "final cost = %.12e\n", chisq);
|
|
Packit |
67cb25 |
fprintf(stderr, "final x = (%.12e, %.12e, %12e)\n",
|
|
Packit |
67cb25 |
gsl_vector_get(x, 0), gsl_vector_get(x, 1), gsl_vector_get(x, 2));
|
|
Packit |
67cb25 |
fprintf(stderr, "final cond(J) = %.12e\n", 1.0 / rcond);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
gsl_multifit_nlinear_free(work);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
int
|
|
Packit |
67cb25 |
main (void)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
const size_t n = 300; /* number of data points to fit */
|
|
Packit |
67cb25 |
const size_t p = 3; /* number of model parameters */
|
|
Packit |
67cb25 |
const double a = 5.0; /* amplitude */
|
|
Packit |
67cb25 |
const double b = 0.4; /* center */
|
|
Packit |
67cb25 |
const double c = 0.15; /* width */
|
|
Packit |
67cb25 |
const gsl_rng_type * T = gsl_rng_default;
|
|
Packit |
67cb25 |
gsl_vector *f = gsl_vector_alloc(n);
|
|
Packit |
67cb25 |
gsl_vector *x = gsl_vector_alloc(p);
|
|
Packit |
67cb25 |
gsl_multifit_nlinear_fdf fdf;
|
|
Packit |
67cb25 |
gsl_multifit_nlinear_parameters fdf_params =
|
|
Packit |
67cb25 |
gsl_multifit_nlinear_default_parameters();
|
|
Packit |
67cb25 |
struct data fit_data;
|
|
Packit |
67cb25 |
gsl_rng * r;
|
|
Packit |
67cb25 |
size_t i;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
gsl_rng_env_setup ();
|
|
Packit |
67cb25 |
r = gsl_rng_alloc (T);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
fit_data.t = malloc(n * sizeof(double));
|
|
Packit |
67cb25 |
fit_data.y = malloc(n * sizeof(double));
|
|
Packit |
67cb25 |
fit_data.n = n;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* generate synthetic data with noise */
|
|
Packit |
67cb25 |
for (i = 0; i < n; ++i)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
double t = (double)i / (double) n;
|
|
Packit |
67cb25 |
double y0 = gaussian(a, b, c, t);
|
|
Packit |
67cb25 |
double dy = gsl_ran_gaussian (r, 0.1 * y0);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
fit_data.t[i] = t;
|
|
Packit |
67cb25 |
fit_data.y[i] = y0 + dy;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* define function to be minimized */
|
|
Packit |
67cb25 |
fdf.f = func_f;
|
|
Packit |
67cb25 |
fdf.df = func_df;
|
|
Packit |
67cb25 |
fdf.fvv = func_fvv;
|
|
Packit |
67cb25 |
fdf.n = n;
|
|
Packit |
67cb25 |
fdf.p = p;
|
|
Packit |
67cb25 |
fdf.params = &fit_data;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* starting point */
|
|
Packit |
67cb25 |
gsl_vector_set(x, 0, 1.0);
|
|
Packit |
67cb25 |
gsl_vector_set(x, 1, 0.0);
|
|
Packit |
67cb25 |
gsl_vector_set(x, 2, 1.0);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
fdf_params.trs = gsl_multifit_nlinear_trs_lmaccel;
|
|
Packit |
67cb25 |
solve_system(x, &fdf, &fdf_params);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* print data and model */
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
double A = gsl_vector_get(x, 0);
|
|
Packit |
67cb25 |
double B = gsl_vector_get(x, 1);
|
|
Packit |
67cb25 |
double C = gsl_vector_get(x, 2);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
for (i = 0; i < n; ++i)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
double ti = fit_data.t[i];
|
|
Packit |
67cb25 |
double yi = fit_data.y[i];
|
|
Packit |
67cb25 |
double fi = gaussian(A, B, C, ti);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
printf("%f %f %f\n", ti, yi, fi);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
gsl_vector_free(f);
|
|
Packit |
67cb25 |
gsl_vector_free(x);
|
|
Packit |
67cb25 |
gsl_rng_free(r);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
return 0;
|
|
Packit |
67cb25 |
}
|