diff options
Diffstat (limited to 'main.c')
-rw-r--r-- | main.c | 334 |
1 files changed, 334 insertions, 0 deletions
@@ -0,0 +1,334 @@ +/* + * main.c + * + * The Top Level Source File + * + * (c) 2009 Thomas White <taw27@cam.ac.uk> + * + * Triclinator - solve nasty triclinic unit cells + * + */ + + +#include <stdlib.h> +#include <stdio.h> +#include <gsl/gsl_rng.h> +#include <gsl/gsl_randist.h> +#include <gsl/gsl_vector.h> +#include <gsl/gsl_blas.h> +#include <gsl/gsl_multifit_nlin.h> +#include <math.h> + +#include "crystal.h" +#include "util.h" + +#define DSTEP 0.0001 +#define ASTEP 0.00001 + +struct data { + size_t n; /* Number of measurements */ + MVal *vals; /* The measurements themselves */ +}; + + +int expb_f(const gsl_vector *x, void *data, gsl_vector *f) +{ + size_t n = ((struct data *)data)->n; + MVal *vals = ((struct data *) data)->vals; + Cell cell; + size_t i; + + cell.a = gsl_vector_get(x, 0); + cell.b = gsl_vector_get(x, 1); + cell.c = gsl_vector_get(x, 2); + cell.al = gsl_vector_get(x, 3); + cell.be = gsl_vector_get(x, 4); + cell.ga = gsl_vector_get(x, 5); + + for ( i=0; i<n; i++ ) { + double calc = crystal_calc(vals[i], cell); + gsl_vector_set(f, i, (calc - vals[i].meas)/vals[i].esd); + } + + return GSL_SUCCESS; +} + + +int expb_df(const gsl_vector *x, void *data, gsl_matrix *J) +{ + size_t n = ((struct data *)data)->n; + MVal *vals = ((struct data *) data)->vals; + Cell cell; + size_t i; + + cell.a = gsl_vector_get(x, 0); + cell.b = gsl_vector_get(x, 1); + cell.c = gsl_vector_get(x, 2); + cell.al = gsl_vector_get(x, 3); + cell.be = gsl_vector_get(x, 4); + cell.ga = gsl_vector_get(x, 5); + + for ( i=0; i<n; i++ ) { + + double calc, calc2, s; + Cell cell2; + MVal val; + + val = vals[i]; + + calc = crystal_calc(vals[i], cell); + s = vals[i].esd; + + cell2 = cell; cell2.a += DSTEP; calc2 = crystal_calc(val, cell2); + gsl_matrix_set(J, i, 0, (calc2 - calc)/(DSTEP*s)); /* df/da */ + + cell2 = cell; cell2.b += DSTEP; calc2 = crystal_calc(val, cell2); + gsl_matrix_set(J, i, 1, (calc2 - calc)/(DSTEP*s)); /* df/db */ + + cell2 = cell; cell2.c += DSTEP; calc2 = crystal_calc(val, cell2); + gsl_matrix_set(J, i, 2, (calc2 - calc)/(DSTEP*s)); /* df/dc */ + + cell2 = cell; cell2.al += ASTEP; calc2 = crystal_calc(val, cell2); + gsl_matrix_set(J, i, 3, (calc2 - calc)/(ASTEP*s)); /* df/dal */ + + cell2 = cell; cell2.be += ASTEP; calc2 = crystal_calc(val, cell2); + gsl_matrix_set(J, i, 4, (calc2 - calc)/(ASTEP*s)); /* df/dbe */ + + cell2 = cell; cell2.ga += ASTEP; calc2 = crystal_calc(val, cell2); + gsl_matrix_set(J, i, 5, (calc2 - calc)/(ASTEP*s)); /* df/dga */ + + } + + return GSL_SUCCESS; +} + + +int expb_fdf(const gsl_vector *x, void *data, gsl_vector *f, gsl_matrix *J) +{ + expb_f(x, data, f); + expb_df(x, data, J); + return GSL_SUCCESS; +} + + +void print_state (size_t iter, gsl_multifit_fdfsolver *s) +{ + printf ("%3u %8.5f %8.5f %8.5f %8.5f %8.5f %8.5f", iter, + gsl_vector_get(s->x, 0), + gsl_vector_get(s->x, 1), + gsl_vector_get(s->x, 2), + gsl_vector_get(s->x, 3), + gsl_vector_get(s->x, 4), + gsl_vector_get(s->x, 5)); + +} + + +int main(void) +{ + const gsl_multifit_fdfsolver_type *T; + gsl_multifit_fdfsolver *s; + int status; + unsigned int i, iter, done; + size_t n; + gsl_matrix *covar; + MVal *vals; + struct data d; + gsl_multifit_function_fdf f; + double x_init[6]; + gsl_vector_view x = gsl_vector_view_array(x_init, 6); + Cell cell; + + /* Get the data to be fitted */ + done = 0; n = 0; + vals = NULL; + while ( !done ) { + + signed int h, k, l; + char buf[64]; + int dspacing = 0; + +// printf("Enter the indicies of the first set of planes, " +// " in the format 'h k l'.\n"); +// if ( n != 0 ) printf("If you have no further planes, " +// "just hit enter.\n"); + printf(" First plane indicies: "); + if ( fgets(buf, 63, stdin) != buf ) { + fprintf(stderr, "Error reading from input\n"); + } + if ( sscanf(buf, "%i %i %i", &h, &k, &l) != 3 ) { + if ( buf[0] == '\n' ) { + done = 1; + continue; + } else { + printf("Invalid input, try again.\n"); + } + } + + /* Allocate space for the new reading, + now that we know it exists */ + vals = realloc(vals, (n+1)*sizeof(MVal)); + vals[n].h1 = h; + vals[n].k1 = k; + vals[n].l1 = l; + +// printf("Enter the indicies of the second set of planes in the " +// "same format.\n"); +// if ( n != 0 ) printf("If you are trying to give a d-spacing " +// "only, just hit enter here.\n"); + printf(" Second plane indicies: "); + if ( fgets(buf, 63, stdin) != buf ) { + fprintf(stderr, "Error reading from input\n"); + } + if ( sscanf(buf, "%i %i %i", &h, &k, &l) != 3 ) { + if ( buf[0] == '\n' ) { + dspacing = 1; + } else { + printf("Invalid input, try again.\n"); + } + } + + if ( dspacing ) { + vals[n].h2 = 0; + vals[n].k2 = 0; + vals[n].l2 = 0; + vals[n].meas = read_value(" D-spacing: "); + } else { + vals[n].h2 = h; + vals[n].k2 = k; + vals[n].l2 = l; + vals[n].meas = DEG2RAD(read_value(" Angle between planes: ")); + } + + vals[n].esd = read_value("Estimated standard deviation: "); + + printf("--------------------------------------\n"); + n++; + + } + + x_init[0] = read_value(" Initial guess for a: "); + x_init[1] = read_value(" Initial guess for b: "); + x_init[2] = read_value(" Initial guess for c: "); + x_init[3] = read_value("Initial guess for alpha: "); + x_init[4] = read_value(" Initial guess for beta: "); + x_init[5] = read_value("Initial guess for gamma: "); + + printf("-----------------------------------------\n\n"); + + printf("Inputted values:\n"); + printf("--------------------------------------------------------------\n"); + printf(" h1 k1 l1 h2 k2 l2 Spacing Angle ESD\n"); + printf("--------------------------------------------------------------\n"); + for ( i=0; i<n; i++ ) { + printf("%3i %3i %3i ", vals[i].h1, vals[i].k1, vals[i].l1); + if ( is_dspacing(vals[i]) ) { + printf(" - - - %8.5f - ", vals[i].meas); + } else { + printf("%3i %3i %3i - %8.5f", vals[i].h2, + vals[i].k2, vals[i].l2, RAD2DEG(vals[i].meas)); + } + printf(" +/- %8.5f", vals[i].esd); + if ( !is_dspacing(vals[i]) ) { + printf(" deg\n"); + } else { + printf(" nm\n"); + } + } + printf("--------------------------------------------------------------\n"); + + d.vals = vals; + d.n = n; + + f.f = &expb_f; + f.df = &expb_df; + f.fdf = &expb_fdf; + f.n = n; + f.p = 6; + f.params = &d; + + T = gsl_multifit_fdfsolver_lmsder; + s = gsl_multifit_fdfsolver_alloc(T, n, 6); + gsl_multifit_fdfsolver_set(s, &f, &x.vector); + + iter = 0; + printf("\n"); + printf("iter a b c alpha beta gamma\n"); + printf("---------------------------------------------------------\n"); + print_state(iter, s); + + do { + + iter++; + status = gsl_multifit_fdfsolver_iterate(s); + + printf(" status = %s\n", gsl_strerror(status)); + print_state(iter, s); + if ( status ) break; + + status = gsl_multifit_test_delta(s->dx, s->x, 1e-6, 1e-6); + + } while ( (status == GSL_CONTINUE) && (iter < 500) ); + + covar = gsl_matrix_alloc(6, 6); + gsl_multifit_covar(s->J, 0.0, covar); + + #define FIT(i) gsl_vector_get(s->x, i) + #define ERR(i) sqrt(gsl_matrix_get(covar,i,i)) + + printf("\n---------------------------------------------------------\n"); + + { + double chi = gsl_blas_dnrm2(s->f); + double dof = n - 6; + double c = GSL_MAX_DBL(1, chi / sqrt(dof)); + + printf("chisq/dof = %g / %g = %g\n", pow(chi, 2.0), dof, + pow(chi, 2.0) / dof); + + printf ("a = %8.5f +/- %8.5f\n", FIT(0), c*ERR(0)); + printf ("b = %8.5f +/- %8.5f\n", FIT(1), c*ERR(1)); + printf ("c = %8.5f +/- %8.5f\n", FIT(2), c*ERR(2)); + printf ("alpha = %8.5f +/- %8.5f\n", FIT(3), c*ERR(3)); + printf (" beta = %8.5f +/- %8.5f\n", FIT(4), c*ERR(4)); + printf ("gamma = %8.5f +/- %8.5f\n", FIT(5), c*ERR(5)); + } + + printf ("status = %s\n", gsl_strerror (status)); + + gsl_multifit_fdfsolver_free(s); + gsl_matrix_free(covar); + + cell.a = FIT(0); + cell.b = FIT(1); + cell.c = FIT(2); + cell.al = FIT(3); + cell.be = FIT(4); + cell.ga = FIT(5); + + printf("\nValues given by fitted cell:\n"); + printf("--------------------------------------------------------------\n"); + printf(" h1 k1 l1 h2 k2 l2 Spacing Angle ESD\n"); + printf("--------------------------------------------------------------\n"); + for ( i=0; i<n; i++ ) { + printf("%3i %3i %3i ", vals[i].h1, vals[i].k1, vals[i].l1); + if ( is_dspacing(vals[i]) ) { + printf(" - - - %8.5f - ", + crystal_calc(vals[i], cell)); + } else { + printf("%3i %3i %3i - %8.5f", vals[i].h2, + vals[i].k2, vals[i].l2, + RAD2DEG(crystal_calc(vals[i], cell))); + } + printf(" +/- %8.5f", vals[i].esd); + if ( !is_dspacing(vals[i]) ) { + printf(" deg\n"); + } else { + printf(" nm\n"); + } + } + printf("--------------------------------------------------------------\n"); + + + return 0; +} |